浏览代码

Initial commit :>

started 2017-05-12
Johannes Hofmann 8 年前
当前提交
29793e9594
共有 8 个文件被更改,包括 7720 次插入0 次删除
  1. 3
    0
      .gitignore
  2. 17
    0
      Makefile
  3. 146
    0
      haader.cpp
  4. 34
    0
      haader.h
  5. 275
    0
      image.cpp
  6. 35
    0
      image.h
  7. 33
    0
      main.cpp
  8. 7177
    0
      stb_image.h

+ 3
- 0
.gitignore 查看文件

@@ -0,0 +1,3 @@
1
+haader
2
+.*.swp
3
+*.o

+ 17
- 0
Makefile 查看文件

@@ -0,0 +1,17 @@
1
+CXXFLAGS= -std=c++98 -pedantic -Wall -O3
2
+LIBS= -ljpeg
3
+OBJS= haader.o image.o
4
+
5
+run: haader
6
+	./haader
7
+
8
+haader: main.cpp $(OBJS)
9
+	$(CXX) main.cpp -o haader $(OBJS) $(CXXFLAGS) $(LIBS)
10
+
11
+%.o: %.c %.h
12
+	gcc $< -c -o $@ $(CFLAGS)
13
+
14
+clean:
15
+	rm -f haader $(OBJS)
16
+
17
+.PHONY: run clean

+ 146
- 0
haader.cpp 查看文件

@@ -0,0 +1,146 @@
1
+#include <iostream>
2
+#include <fstream>
3
+#include <stdlib.h>
4
+#include <time.h>
5
+
6
+#include "haader.h"
7
+
8
+using namespace std;
9
+using namespace haader;
10
+
11
+HdrImageStack::HdrImageStack() {
12
+}
13
+
14
+bool HdrImageStack::read_from_files(char * const* file_paths, int number_of_paths) {
15
+    m_images.clear();
16
+
17
+    if (number_of_paths < 0) {
18
+        cerr << "HdrImageStack::read_from_files: number_of_paths is negative" << endl;
19
+        return false;
20
+    }
21
+
22
+    for (int i = 0; i < number_of_paths; i++) {
23
+        m_images.push_back(Image());
24
+        if (m_images[i].read_from_file(file_paths[i])) {
25
+            cout << "Read \"" << file_paths[i] << "\"" << endl;
26
+            if (!m_images[0].has_equal_dimensions(m_images[i])) {
27
+                cerr << "HdrImageStack::read_from_files: Dimensions do not match (\""
28
+                     << file_paths[i]
29
+                     << "\")"
30
+                     << endl;
31
+                return false;
32
+            }
33
+        } else {
34
+            return false;
35
+        }
36
+    }
37
+
38
+    return true;
39
+}
40
+
41
+bool HdrImageStack::get_average_image_slow(Image &output) {
42
+    if (m_images.size() == 0) {
43
+        return false;
44
+    }
45
+
46
+    output.m_image_data.resize(m_images[0].m_image_data.size());
47
+    output.m_width = m_images[0].m_width;
48
+    output.m_height = m_images[0].m_height;
49
+    output.m_components = m_images[0].m_components;
50
+
51
+    unsigned int bytes_size = m_images[0].m_image_data.size();
52
+    unsigned int images_size = m_images.size();
53
+    for (unsigned int i = 0; i < bytes_size; i++) {
54
+        int v = 0;
55
+        for (unsigned int k = 0; k < images_size; k++) {
56
+            v += m_images[k].m_image_data[i];
57
+        }
58
+        output.m_image_data[i] = v / (int)images_size;
59
+    }
60
+
61
+    return true;
62
+}
63
+
64
+bool HdrImageStack::get_average_image(Image &output) {
65
+    if (m_images.size() == 0) {
66
+        return false;
67
+    }
68
+
69
+    output.m_image_data.resize(m_images[0].m_image_data.size());
70
+    output.m_width = m_images[0].m_width;
71
+    output.m_height = m_images[0].m_height;
72
+    output.m_components = m_images[0].m_components;
73
+
74
+    unsigned int bytes_size = m_images[0].m_image_data.size();
75
+    unsigned int images_size = m_images.size();
76
+
77
+    const unsigned int buf_size = 128;
78
+    int buf[buf_size];
79
+
80
+    for (unsigned int i = 0; i + buf_size <= bytes_size; i += buf_size) {
81
+        for (unsigned int m = 0; m < buf_size; m++) {
82
+            buf[m] = m_images[0].m_image_data[i + m];
83
+        }
84
+        for (unsigned int k = 1; k < images_size; k++) {
85
+            for (unsigned int m = 0; m < buf_size; m++) {
86
+                buf[m] += m_images[k].m_image_data[i + m];
87
+            }
88
+        }
89
+        for (unsigned int m = 0; m < buf_size; m++) {
90
+            output.m_image_data[i + m] = buf[m] / images_size;
91
+        }
92
+    }
93
+
94
+    // TODO test this with an image that is prime numbered dimensions
95
+    unsigned int rest = bytes_size % buf_size;
96
+    for (unsigned int i = bytes_size - rest; i < bytes_size; i++) {
97
+        int v = 0;
98
+        for (unsigned int k = 0; k < images_size; k++) {
99
+            v += m_images[k].m_image_data[i];
100
+        }
101
+        output.m_image_data[i] = v / (int)images_size;
102
+    }
103
+
104
+    return true;
105
+}
106
+
107
+bool HdrImageStack::samples_to_csv(const char *file_path) {
108
+    if (m_images.size() == 0) {
109
+        return false;
110
+    }
111
+
112
+    srand(time(0));
113
+    ofstream output(file_path);
114
+
115
+    if (output.is_open()) {
116
+        unsigned int images_size = m_images.size();
117
+        unsigned int c = m_images[0].m_components;
118
+        unsigned int width = m_images[0].m_width;
119
+        unsigned int height = m_images[0].m_height;
120
+
121
+        for (unsigned int i = 0; i < 100; i++) {
122
+            unsigned int x = rand() % width;
123
+            unsigned int y = rand() % height;
124
+            unsigned int index = (y * width + x) * c;
125
+            for (unsigned int k = 0; k < images_size; k++) {
126
+                int val = m_images[k].m_image_data[index];
127
+                output << val;
128
+                if (k + 1 < images_size) {
129
+                    output << ',';
130
+                } else {
131
+                    output << '\n';
132
+                }
133
+            }
134
+        }
135
+
136
+        return true;
137
+    } else {
138
+        return false;
139
+    }
140
+}
141
+
142
+bool HdrImageStack::recover_response_function(ResponseFunction &respFunc) {
143
+    //TODO implement
144
+
145
+    return false;
146
+}

+ 34
- 0
haader.h 查看文件

@@ -0,0 +1,34 @@
1
+#ifndef HAADER_ILUCF4Z0
2
+#define HAADER_ILUCF4Z0
3
+
4
+#include <vector>
5
+
6
+#include "image.h"
7
+
8
+namespace haader {
9
+    class ResponseFunction {
10
+        private:
11
+            std::vector<double> m_lookup_table;
12
+    };
13
+
14
+    class HdrImageStack {
15
+        friend class ResponseFunction;
16
+
17
+        public:
18
+            HdrImageStack();
19
+
20
+            bool read_from_files(char * const* file_paths, int number_of_paths);
21
+
22
+            bool get_average_image(Image &output);
23
+            bool get_average_image_slow(Image &output);
24
+
25
+            bool samples_to_csv(const char *file_path);
26
+
27
+            bool recover_response_function(ResponseFunction &respFunc);
28
+
29
+        private:
30
+            std::vector<Image> m_images;
31
+    };
32
+}
33
+
34
+#endif // HAADER_ILUCF4Z0

+ 275
- 0
image.cpp 查看文件

@@ -0,0 +1,275 @@
1
+#include <stdio.h>
2
+
3
+// for error recovery
4
+#include <setjmp.h>
5
+
6
+#include <iostream>
7
+#include <fstream>
8
+#include <sstream>
9
+#include <vector>
10
+
11
+#include "jpeglib.h"
12
+
13
+#define STB_IMAGE_IMPLEMENTATION
14
+#include "stb_image.h"
15
+
16
+#include "image.h"
17
+
18
+using namespace std;
19
+using namespace haader;
20
+
21
+
22
+Image::Image():
23
+    m_width(0),
24
+    m_height(0),
25
+    m_components(0)
26
+{
27
+}
28
+
29
+void Image::to_string(string &s) {
30
+    stringstream ss;
31
+    ss << "Image(";
32
+    ss << m_width << 'x' << m_height << 'x' << m_components << ")";
33
+    s = ss.str();
34
+}
35
+
36
+bool Image::read_from_file(const char *file_path) {
37
+    int x = 0;
38
+    int y = 0;
39
+    int components = 0;
40
+
41
+    unsigned char *data = stbi_load(file_path, &x, &y, &components, 0);
42
+
43
+    if (data) {
44
+        m_width = x;
45
+        m_height = y;
46
+        m_components = components;
47
+        size_t size = (size_t)x * (size_t)y * (size_t)components;
48
+        m_image_data.assign(data, data + size);
49
+
50
+        return true;
51
+    } else {
52
+        cerr << "Can not read \"" << file_path << "\" as an image." << endl;
53
+        return false;
54
+    }
55
+    
56
+    stbi_image_free(data);
57
+}
58
+
59
+struct my_error_mgr {
60
+  struct jpeg_error_mgr pub;	/* "public" fields */
61
+
62
+  jmp_buf setjmp_buffer;	/* for return to caller */
63
+};
64
+
65
+typedef struct my_error_mgr * my_error_ptr;
66
+
67
+/*
68
+ * Here's the routine that will replace the standard error_exit method:
69
+ */
70
+
71
+METHODDEF(void)
72
+my_error_exit (j_common_ptr cinfo)
73
+{
74
+  /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
75
+  my_error_ptr myerr = (my_error_ptr) cinfo->err;
76
+
77
+  /* Always display the message. */
78
+  /* We could postpone this until after returning, if we chose. */
79
+  (*cinfo->err->output_message) (cinfo);
80
+
81
+  /* Return control to the setjmp point */
82
+  longjmp(myerr->setjmp_buffer, 1);
83
+}
84
+
85
+bool Image::read_from_jpeg_file(const char *file_path) {
86
+    /* This struct contains the JPEG decompression parameters and pointers to
87
+    * working space (which is allocated as needed by the JPEG library).
88
+    */
89
+    struct jpeg_decompress_struct cinfo;
90
+
91
+    /* We use our private extension JPEG error handler.
92
+    * Note that this struct must live as long as the main JPEG parameter
93
+    * struct, to avoid dangling-pointer problems.
94
+    */
95
+    struct my_error_mgr jerr;
96
+
97
+    /* More stuff */
98
+    FILE * infile;		/* source file */
99
+    JSAMPARRAY buffer;		/* Output row buffer */
100
+    int row_stride;		/* physical row width in output buffer */
101
+
102
+    /* In this example we want to open the input file before doing anything else,
103
+    * so that the setjmp() error recovery below can assume the file is open.
104
+    * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
105
+    * requires it in order to read binary files.
106
+    */
107
+
108
+    if ((infile = fopen(file_path, "rb")) == NULL) {
109
+        cerr << "Can not open \"" << file_path << "\"" << endl;
110
+        return false;
111
+    }
112
+
113
+    /* Step 1: allocate and initialize JPEG decompression object */
114
+
115
+    /* We set up the normal JPEG error routines, then override error_exit. */
116
+    cinfo.err = jpeg_std_error(&jerr.pub);
117
+    jerr.pub.error_exit = my_error_exit;
118
+    /* Establish the setjmp return context for my_error_exit to use. */
119
+    if (setjmp(jerr.setjmp_buffer)) {
120
+        /* If we get here, the JPEG code has signaled an error.
121
+         * We need to clean up the JPEG object, close the input file, and return.
122
+         */
123
+        jpeg_destroy_decompress(&cinfo);
124
+        fclose(infile);
125
+        return false;
126
+    }
127
+    /* Now we can initialize the JPEG decompression object. */
128
+    jpeg_create_decompress(&cinfo);
129
+
130
+    /* Step 2: specify data source (eg, a file) */
131
+
132
+    jpeg_stdio_src(&cinfo, infile);
133
+
134
+    /* Step 3: read file parameters with jpeg_read_header() */
135
+
136
+    (void) jpeg_read_header(&cinfo, TRUE);
137
+    /* We can ignore the return value from jpeg_read_header since
138
+    *   (a) suspension is not possible with the stdio data source, and
139
+    *   (b) we passed TRUE to reject a tables-only JPEG file as an error.
140
+    * See libjpeg.txt for more info.
141
+    */
142
+
143
+    /* Step 4: set parameters for decompression */
144
+
145
+    /* In this example, we don't need to change any of the defaults set by
146
+    * jpeg_read_header(), so we do nothing here.
147
+    */
148
+
149
+    /* Step 5: Start decompressor */
150
+
151
+    (void) jpeg_start_decompress(&cinfo);
152
+    /* We can ignore the return value since suspension is not possible
153
+    * with the stdio data source.
154
+    */
155
+
156
+    m_image_data.reserve(cinfo.output_width * cinfo.output_height * cinfo.output_components);
157
+
158
+    m_width = cinfo.output_width;
159
+    m_height = cinfo.output_height;
160
+    m_components = cinfo.output_components;
161
+
162
+    /* We may need to do some setup of our own at this point before reading
163
+    * the data.  After jpeg_start_decompress() we have the correct scaled
164
+    * output image dimensions available, as well as the output colormap
165
+    * if we asked for color quantization.
166
+    * In this example, we need to make an output work buffer of the right size.
167
+    */ 
168
+    /* JSAMPLEs per row in output buffer */
169
+    row_stride = cinfo.output_width * cinfo.output_components;
170
+    /* Make a one-row-high sample array that will go away when done with image */
171
+    buffer = (*cinfo.mem->alloc_sarray)
172
+        ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
173
+
174
+    /* Step 6: while (scan lines remain to be read) */
175
+    /*           jpeg_read_scanlines(...); */
176
+
177
+    /* Here we use the library's state variable cinfo.output_scanline as the
178
+    * loop counter, so that we don't have to keep track ourselves.
179
+    */
180
+    while (cinfo.output_scanline < cinfo.output_height) {
181
+        /* jpeg_read_scanlines expects an array of pointers to scanlines.
182
+         * Here the array is only one element long, but you could ask for
183
+         * more than one scanline at a time if that's more convenient.
184
+         */
185
+        (void) jpeg_read_scanlines(&cinfo, buffer, 1);
186
+        /* Assume put_scanline_someplace wants a pointer and sample count. */
187
+        //put_scanline_someplace(buffer[0], row_stride);
188
+
189
+        for (int i = 0; i < row_stride; i++) {
190
+            m_image_data.push_back(buffer[0][i]);
191
+        }
192
+    }
193
+
194
+    /* Step 7: Finish decompression */
195
+
196
+    (void) jpeg_finish_decompress(&cinfo);
197
+    /* We can ignore the return value since suspension is not possible
198
+    * with the stdio data source.
199
+    */
200
+
201
+    /* Step 8: Release JPEG decompression object */
202
+
203
+    /* This is an important step since it will release a good deal of memory. */
204
+    jpeg_destroy_decompress(&cinfo);
205
+
206
+    /* After finish_decompress, we can close the input file.
207
+    * Here we postpone it until after no more JPEG errors are possible,
208
+    * so as to simplify the setjmp error logic above.  (Actually, I don't
209
+    * think that jpeg_destroy can do an error exit, but why assume anything...)
210
+    */
211
+    fclose(infile);
212
+
213
+    if (jerr.pub.num_warnings != 0) {
214
+        cout << jerr.pub.num_warnings << " errors occured." << endl;
215
+        return false;
216
+    } else {
217
+        return true;
218
+    }
219
+}
220
+
221
+bool Image::save_as_ppm_file(const char *file_path, bool ascii) {
222
+    if (ascii) {
223
+        // ASCII
224
+
225
+        ofstream out(file_path);
226
+        out << "P3\n";
227
+        out << m_width << ' ' << m_height << '\n';
228
+        out << "255\n";
229
+
230
+        unsigned int pixels = m_width * m_height;
231
+        unsigned int index = 0;
232
+        for (unsigned int i = 0; i < pixels; i++) {
233
+            out << (int)m_image_data[index] << ' ' << (int)m_image_data[index + 1] << ' ' << (int)m_image_data[index + 2] << '\n';
234
+            index += 3;
235
+        }
236
+
237
+        out.close();
238
+        return true;
239
+    } else {
240
+        // binary
241
+
242
+        ofstream out(file_path);
243
+        out << "P6\n";
244
+        out << m_width << ' ' << m_height << '\n';
245
+        out << "255\n";
246
+
247
+        unsigned int pixels = m_width * m_height;
248
+        unsigned int index = 0;
249
+        for (unsigned int i = 0; i < pixels; i++) {
250
+            out << m_image_data[index] << m_image_data[index + 1] << m_image_data[index + 2];
251
+            index += 3;
252
+        }
253
+
254
+        out.close();
255
+        return true;
256
+    }
257
+}
258
+
259
+unsigned int Image::get_width() {
260
+    return m_width;
261
+}
262
+
263
+unsigned int Image::get_height() {
264
+    return m_height;
265
+}
266
+
267
+unsigned int Image::get_components() {
268
+    return m_components;
269
+}
270
+
271
+bool Image::has_equal_dimensions(const Image &other) {
272
+    return (m_width == other.m_width &&
273
+            m_height == other.m_height &&
274
+            m_components == other.m_components);
275
+}

+ 35
- 0
image.h 查看文件

@@ -0,0 +1,35 @@
1
+#ifndef IMAGE_AF9FV02C
2
+#define IMAGE_AF9FV02C
3
+
4
+#include <vector>
5
+#include <string>
6
+
7
+namespace haader {
8
+
9
+    class Image {
10
+        friend class HdrImageStack;
11
+
12
+        public:
13
+            Image();
14
+
15
+            void to_string(std::string &s);
16
+
17
+            bool read_from_file(const char *file_path);
18
+            bool read_from_jpeg_file(const char *file_path);
19
+            bool save_as_ppm_file(const char *file_path, bool ascii=false);
20
+
21
+            unsigned int get_width();
22
+            unsigned int get_height();
23
+            unsigned int get_components();
24
+            bool has_equal_dimensions(const Image &other);
25
+
26
+        private:
27
+            std::vector<unsigned char> m_image_data;
28
+            unsigned int m_width;
29
+            unsigned int m_height;
30
+            unsigned int m_components;
31
+    };
32
+
33
+}
34
+
35
+#endif // IMAGE_AF9FV02C

+ 33
- 0
main.cpp 查看文件

@@ -0,0 +1,33 @@
1
+#include "haader.h"
2
+
3
+#include <time.h>
4
+
5
+#include <iostream>
6
+
7
+using namespace std;
8
+
9
+
10
+int main(int argc, char *argv[])
11
+{
12
+    if (argc >= 2) {
13
+        haader::HdrImageStack stack;
14
+
15
+        if (stack.read_from_files(argv + 1, argc - 1)) {
16
+            haader::Image img;
17
+
18
+            {
19
+                clock_t start = clock();
20
+                stack.get_average_image(img);
21
+                clock_t end = clock();
22
+                double seconds = (end - start) / (double)CLOCKS_PER_SEC;
23
+                cout << "secs: " << seconds << endl;
24
+            }
25
+
26
+            img.save_as_ppm_file("average.ppm");
27
+            stack.samples_to_csv("samples.csv");
28
+        }
29
+
30
+    }
31
+
32
+    return 0;
33
+}

+ 7177
- 0
stb_image.h
文件差异内容过多而无法显示
查看文件