cgv
Loading...
Searching...
No Matches
image.h
1#pragma once
2
3#include <algorithm>
4#include "image_reader.h"
5#include "image_writer.h"
6#include <cgv/math/functions.h>
7
8#include "lib_begin.h"
9
10namespace cgv {
11 namespace media {
12 namespace image {
13
15 {
16 protected:
18 public:
19 image() : dv() {}
20 image(const image &I) : dv()
21 {
22 copy(I);
23 }
24 template <typename T> T* get_ptr() { return dv.get_ptr<T>(); }
25 template <typename T> const T* get_ptr() const { return dv.get_ptr<T>(); }
26 bool read(const std::string& file_name)
27 {
28 image_reader ir(*this);
29 if (ir.open(file_name)) {
30 if (ir.read_image(dv)) {
31 return true;
32 }
33 }
34 return false;
35 }
36 bool write(const std::string& file_name) {
37 image_writer iw(file_name);
38 if(iw.write_image(dv)) {
39 return true;
40 }
41 return false;
42 }
43 void hflip()
44 {
45 // swap order of rows
46 size_t row_size = get_entry_size() * get_width();
47 unsigned h = (unsigned)get_height();
48 for (unsigned y = 0; y < (h - 1) / 2; ++y) {
49 std::swap_ranges(dv.get_ptr<char>() + y*row_size, dv.get_ptr<char>() + (y + 1)*row_size, dv.get_ptr<char>() + (h - y - 1)*row_size);
50 }
51 }
53 void combine(const cgv::type::uint8_type* src_ptr, unsigned n_x, unsigned entry_size, unsigned n_y, unsigned row_size, cgv::type::uint8_type* dst_ptr)
54 {
55 double c[4] = { 0,0,0,0 };
56 unsigned n_c = get_nr_components();
57 for (unsigned y = 0; y < n_y; ++y) {
58 for (unsigned x = 0; x < n_x; ++x) {
59 for (unsigned ci = 0; ci < n_c; ++ci)
60 c[ci] += get<double>(ci, src_ptr + entry_size*x + row_size*y);
61 }
62 }
63 double scale = 1.0 / (n_x*n_y);
64 for (unsigned ci = 0; ci < n_c; ++ci)
65 set<double>(ci, dst_ptr, scale*c[ci]);
66 }
68 void copy(const image& I)
69 {
70 int w = (int)I.get_width();
71 int h = (int)I.get_height();
72
73 // copy format and set dimensions
74 *static_cast<cgv::data::data_format*>(this) = I;
75 set_width(w);
76 set_height(h);
77
78 // allocate data
79 new(&dv) cgv::data::data_view(this);
80
81 const cgv::type::uint8_type* src_ptr = I.get_ptr<cgv::type::uint8_type>();
82 cgv::type::uint8_type* dst_ptr = get_ptr<cgv::type::uint8_type>();
83
84 unsigned entry_size = get_entry_size();
85
86 size_t size = entry_size * w * h;
87 memcpy(dst_ptr, src_ptr, size);
88 }
90 void downscale(unsigned int size_x, unsigned int size_y, const image& I)
91 {
92 int w = (int)I.get_width();
93 int h = (int)I.get_height();
94 float wf = float(w);
95 float hf = float(h);
96 float x_scale = float(size_x) / wf;
97 float y_scale = float(size_y) / hf;
98 float y_end = 0.0f;
99
100 // copy format and set downscaled dimensions
101 *static_cast<cgv::data::data_format*>(this) = I;
102 set_width(size_x);
103 set_height(size_y);
104
105 // allocate data
106 new(&dv) cgv::data::data_view(this);
107
108 const cgv::type::uint8_type* src_ptr = I.get_ptr<cgv::type::uint8_type>();
109 cgv::type::uint8_type* dst_ptr = get_ptr<cgv::type::uint8_type>();
110
111 unsigned n_c = get_nr_components();
112 unsigned entry_size = get_entry_size();
113
114 for(unsigned j = 0; j < size_y; ++j) {
115 float y_start = y_end;
116 y_end = (j + 1) / y_scale;
117
118 if(y_end >= hf) y_end = hf - 0.000001f;
119
120 float x_end = 0.0f;
121
122 for(unsigned i = 0; i < size_x; ++i) {
123 float x_start = x_end;
124 x_end = (i + 1) / x_scale;
125
126 if(x_end >= wf) x_end = wf - 0.000001f;
127
128 double sum = 0.0;
129 double c[4] = { 0.0, 0.0, 0.0, 0.0 };
130
131 for(int y = (int)y_start; y <= (int)y_end; ++y) {
132 float y_portion = 1.0f;
133
134 if(y == (int)y_start) y_portion -= y_start - y;
135 if(y == (int)y_end) y_portion -= y + 1.0f - y_end;
136
137 for(int x = (int)x_start; x <= (int)x_end; ++x) {
138 float x_portion = 1.0f;
139 if(x == (int)x_start) x_portion -= x_start - x;
140 if(x == (int)x_end) x_portion -= x + 1.0f - x_end;
141
142 double scaling = y_portion * x_portion;
143 sum += scaling;
144
145 for(unsigned ci = 0; ci < n_c; ++ci)
146 c[ci] += get<double>(ci, src_ptr + entry_size * (x + w * y)) * scaling;
147 }
148 }
149 for(unsigned ci = 0; ci < n_c; ++ci)
150 set<double>(ci, dst_ptr + entry_size * (i + (unsigned)size_x*j), c[ci] / sum);
151 }
152 }
153 }
155 void downsample(unsigned fx, unsigned fy, const image& I)
156 {
157 downscale((unsigned)I.get_width() / fx, (unsigned)I.get_height() / fy, I);
158 }
160 void upscale(unsigned int size_x, unsigned int size_y, const image& I)
161 {
162 int w = (int)I.get_width();
163 int h = (int)I.get_height();
164
165 // copy format and set upscaled dimensions
166 *static_cast<cgv::data::data_format*>(this) = I;
167 set_width(size_x);
168 set_height(size_y);
169
170 // allocate data
171 new(&dv) cgv::data::data_view(this);
172
173 const cgv::type::uint8_type* src_ptr = I.get_ptr<cgv::type::uint8_type>();
174 cgv::type::uint8_type* dst_ptr = get_ptr<cgv::type::uint8_type>();
175
176 unsigned n_c = get_nr_components();
177 unsigned entry_size = get_entry_size();
178
179
180
181 unsigned n = 8;
182 unsigned m = 4;
183 float step_x = 1.0f / float(size_x);
184 float step_y = 1.0f / float(size_y);
185
186 for(unsigned j = 0; j < size_y; ++j) {
187 float ty = (float(j) + 0.5f) * step_y;
188 float fiy = ty * float(h) - 0.5f;
189 unsigned iy = unsigned(fiy);
190 ty = cgv::math::clamp(fiy - iy, 0.0f, 1.0f);
191
192 if(iy == h - 1) {
193 iy = h - 2;
194 ty = 1.0f;
195 }
196
197 for(unsigned i = 0; i < size_x; ++i) {
198 float tx = (float(i) + 0.5f) * step_x;
199 float fix = tx * float(w) - 0.5f;
200 unsigned ix = unsigned(fix);
201 tx = cgv::math::clamp(fix - ix, 0.0f, 1.0f);
202
203 if(ix == w - 1) {
204 ix = w - 2;
205 tx = 1.0f;
206 }
207
208 unsigned idx00 = entry_size * (ix + w * iy);
209 unsigned idx10 = entry_size * (ix + 1 + w * iy);
210 unsigned idx01 = entry_size * (ix + w * (iy + 1));
211 unsigned idx11 = entry_size * (ix + 1 + w * (iy + 1));
212
213 double c[4] = { 0.0, 0.0, 0.0, 0.0 };
214
215 for(unsigned ci = 0; ci < n_c; ++ci) {
216 double y0 = (1.0f - tx) * get<double>(ci, src_ptr + idx00) + tx * get<double>(ci, src_ptr + idx10);
217 double y1 = (1.0f - tx) * get<double>(ci, src_ptr + idx01) + tx * get<double>(ci, src_ptr + idx11);
218
219 c[ci] = (1.0f - ty) * y0 + ty * y1;
220 }
221
222 for(unsigned ci = 0; ci < n_c; ++ci)
223 set<double>(ci, dst_ptr + entry_size * (i + (unsigned)size_x*j), c[ci]);
224 }
225 }
226 }
228 void resize(unsigned size_x, unsigned size_y, const image& I)
229 {
230 unsigned w = (int)I.get_width();
231 unsigned h = (int)I.get_height();
232
233 // cannot produce an image with resolution of zero in either dimension
234 assert(size_x != 0);
235 assert(size_y != 0);
236
237 bool shrink_x = size_x <= w;
238 bool shrink_y = size_y <= h;
239
240 if(w == size_x && h == size_y) {
241 // copy the image if the same size is requested
242 copy(I);
243 } else {
244 // choose an optimal resize scheme depending on the requested size
245 if(shrink_x && shrink_y) {
246 downscale(size_x, size_y, I);
247 } else if(!shrink_x && !shrink_y) {
248 upscale(size_x, size_y, I);
249 } else {// if(shrink_x && !shrink_y) {
250 image temp;
251 temp.downscale(shrink_x ? size_x : w, shrink_y ? size_y : h, I);
252 upscale(size_x, size_y, temp);
253 }
254 }
255 }
256 };
257 }
258 }
259}
260
261#include <cgv/config/lib_end.h>
complete implementation of method actions that only call one method when entering a node
Definition action.h:113
unsigned int get_entry_size() const
return the size of one entry of components in bytes
unsigned int get_nr_components() const
return the number of components
A data_format describes a multidimensional data block of data entries.
Definition data_format.h:17
void set_height(size_t _height)
set the resolution in the second dimension, add dimensions if necessary
void set_width(size_t _width)
set the resolution in the first dimension, add dimensions if necessary
size_t get_width() const
return the resolution in the first dimension, or 1 if not defined
size_t get_height() const
return the resolution in the second dimension, or 1 if not defined
cgv::type::func::transfer_const< P, S * >::type get_ptr() const
return a data pointer to type S
Definition data_view.h:61
the data view gives access to a data array of one, two, three or four dimensions.
Definition data_view.h:153
the image reader chooses a specific reader automatically based on the extension of the given file nam...
bool read_image(const std::string &file_name, cgv::data::data_view &dv, std::vector< cgv::data::data_view > *palettes=0)
read the whole image into the given data view.
bool open(const std::string &file_name)
open the file and read the image header in order to determine the data format of the file,...
the image writer chooses a specific writer automatically based on the extension of the given file nam...
bool write_image(const cgv::data::const_data_view &dv, const std::vector< cgv::data::const_data_view > *palettes=0, double duration=0)
write the data stored in the data view to a file with the file name given in the constructor.
void upscale(unsigned int size_x, unsigned int size_y, const image &I)
construct a resized larger version of given image using bilinear interpolation
Definition image.h:160
void downscale(unsigned int size_x, unsigned int size_y, const image &I)
construct a resized smaller version of given image using area averaging
Definition image.h:90
void combine(const cgv::type::uint8_type *src_ptr, unsigned n_x, unsigned entry_size, unsigned n_y, unsigned row_size, cgv::type::uint8_type *dst_ptr)
combine a rectangular image region into a single pixel
Definition image.h:53
void downsample(unsigned fx, unsigned fy, const image &I)
downsample image in x and y direction by given downsampling factors fx and fy
Definition image.h:155
void resize(unsigned size_x, unsigned size_y, const image &I)
construct a resized version of given image using the down- and upscale methods
Definition image.h:228
void copy(const image &I)
constructs a copy of given image
Definition image.h:68
the cgv namespace
Definition print.h:11