PICCANTE  0.4
The hottest HDR imaging library!
ward_alignment.hpp
Go to the documentation of this file.
1 /*
2 
3 PICCANTE
4 The hottest HDR imaging library!
5 http://vcg.isti.cnr.it/piccante
6 
7 Copyright (C) 2014
8 Visual Computing Laboratory - ISTI CNR
9 http://vcg.isti.cnr.it
10 First author: Francesco Banterle
11 
12 This Source Code Form is subject to the terms of the Mozilla Public
13 License, v. 2.0. If a copy of the MPL was not distributed with this
14 file, You can obtain one at http://mozilla.org/MPL/2.0/.
15 
16 */
17 
18 #ifndef PIC_FEATURES_MATCHING_WARD_ALIGNMENT_HPP
19 #define PIC_FEATURES_MATCHING_WARD_ALIGNMENT_HPP
20 
21 #include <vector>
22 
23 #include "../image.hpp"
24 #include "../util/vec.hpp"
25 #include "../util/string.hpp"
26 #include "../image_samplers/image_sampler_bilinear.hpp"
27 #include "../filtering/filter_downsampler_2d.hpp"
28 #include "../filtering/filter_luminance.hpp"
29 
30 namespace pic {
31 
36 {
37 protected:
39 
40 public:
42  std::vector< bool* > tb1_v, tb2_v, eb2_shifted_v, tb2_shifted_v;
43 
48  {
49  update(0.5f, 0.015625f);
50  }
51 
53  {
54  for(unsigned int i=0; i< luminance.size(); i++) {
55  delete luminance[i];
56  }
57 
58  for(unsigned int i=0; i< img1_v.size(); i++) {
59  delete img1_v[i];
60  }
61 
62  for(unsigned int i=0; i< img2_v.size(); i++) {
63  delete img2_v[i];
64  }
65 
66  for(unsigned int i=0; i< tb1_v.size(); i++) {
67  delete[] tb1_v[i];
68  }
69 
70  for(unsigned int i=0; i< tb2_v.size(); i++) {
71  delete[] tb2_v[i];
72  }
73 
74  for(unsigned int i=0; i< eb2_shifted_v.size(); i++) {
75  delete[] eb2_shifted_v[i];
76  }
77 
78  for(unsigned int i=0; i<tb2_shifted_v.size(); i++) {
79  delete[] tb2_shifted_v[i];
80  }
81  }
82 
88  void update(float percentile, float tolerance)
89  {
90  if(percentile < 0.0f && percentile > 1.0f) {
91  percentile = 0.5f;
92  }
93 
94  if(tolerance > 0.0625f) {
95  tolerance = 0.015625f;
96  }
97 
98  this->percentile = percentile;
99  this->tolerance = tolerance;
100  }
101 
108  bool *MTB(Image *img, Image *L)
109  {
110  bool bDelete = (L == NULL);
111 
112  if(img->channels == 1)
113  {
114  bDelete = false;
115  L = img;
116  } else {
118  }
119 
120  int n = L->nPixels();
121  bool *maskThr = new bool[n * 2];
122  bool *maskEb = &maskThr[n];
123 
124  float *ret = L->getPercentileVal(percentile, NULL, NULL);
125  float medVal = ret[0];
126 
127  float A = medVal - tolerance;
128  float B = medVal + tolerance;
129 
130  for(int i = 0; i < n; i++) {
131  maskThr[i] = L->data[i] > medVal;
132  maskEb[i] = !((L->data[i] >= A) && (L->data[i] <= B));
133  }
134 
135  if(bDelete) {
136  delete L;
137  }
138 
139  return maskThr;
140  }
141 
149  Vec2i getExpShift(Image *img1, Image *img2,
150  int shift_bits = 6)
151  {
152  if(img1 == NULL || img2 == NULL) {
153  return Vec2i(0, 0);
154  }
155 
156  if(!img1->isSimilarType(img2)) {
157  return Vec2i(0, 0);
158  }
159 
160  Image *L1, *L2;
161 
162  if(img1->channels == 1) {
163  L1 = img1;
164  } else {
166  luminance.push_back(L1);
167  }
168 
169  if(img2->channels == 1) {
170  L2 = img2;
171  } else {
173  luminance.push_back(L2);
174  }
175 
176  int min_coord = MIN(L1->width, L1->height);
177  if(min_coord < (1 << shift_bits)) {
178  shift_bits = MAX(log2(min_coord) - 1, 1);
179  }
180 
181  Vec2i cur_shift, ret_shift;
182 
183  cur_shift = Vec2i(0, 0);
184  ret_shift = Vec2i(0, 0);
185 
186  //downsample
187  Image *tmp_1 = L1;
188  Image *tmp_2 = L2;
189  for(int i = 0; i < shift_bits; i++) {
190  Image* sml_img1 = FilterDownSampler2D::execute(tmp_1, NULL, 0.5f);
191  Image* sml_img2 = FilterDownSampler2D::execute(tmp_2, NULL, 0.5f);
192 
193  img1_v.push_back(sml_img1);
194  img2_v.push_back(sml_img2);
195 
196  tmp_1 = sml_img1;
197  tmp_2 = sml_img2;
198  }
199 
200  //compute the shift
201  while(shift_bits > 0) {
202  Image* sml_img1 = img1_v[shift_bits - 1];
203  Image* sml_img2 = img2_v[shift_bits - 1];
204 
205  int width = sml_img1->width;
206  int height = sml_img1->height;
207  int n = width * height;
208 
209  //compute the median threshold mask
210  bool *tb1 = MTB(sml_img1, NULL);
211  bool *eb1 = &tb1[n];
212 
213  bool *tb2 = MTB(sml_img2, NULL);
214  bool *eb2 = &tb2[n];
215 
216  //track memory
217  tb1_v.push_back(tb1);
218  tb2_v.push_back(tb2);
219 
220  int min_err = n;
221 
222  bool *tb2_shifted = new bool[n];
223  bool *eb2_shifted = new bool[n];
224 
225  tb2_shifted_v.push_back(tb2_shifted);
226  eb2_shifted_v.push_back(eb2_shifted);
227 
228  for(int i = -1; i <= 1; i++) {
229 
230  for(int j = -1; j <= 1; j++) {
231 
232  int xs = cur_shift[0] + i;
233  int ys = cur_shift[1] + j;
234 
235  Buffer<bool>::shift(tb2_shifted, tb2, xs, ys, width, height, 1, 1);
236  Buffer<bool>::shift(eb2_shifted, eb2, xs, ys, width, height, 1, 1);
237 
238  int err = 0;
239  for(int k=0; k<n; k++) {
240  bool diff_b = tb1[k] ^ tb2_shifted[k];
241  diff_b = diff_b & eb1[k];
242  diff_b = diff_b & eb2_shifted[k];
243 
244  if(diff_b) {
245  err++;
246  }
247  }
248 
249  if(err < min_err) {
250  ret_shift[0] = xs;
251  ret_shift[1] = ys;
252  min_err = err;
253  }
254  }
255  }
256 
257  shift_bits--;
258 
259  cur_shift[0] = ret_shift[0] * 2;
260  cur_shift[1] = ret_shift[1] * 2;
261  }
262 
263  return cur_shift;
264  }
265 
266  static Vec2i execute(Image *imgTarget, Image *imgSource)
267  {
268  Vec2i shift;
269  WardAlignment wa;
270 
271  if(imgTarget == NULL || imgSource == NULL) {
272  return shift;
273  }
274 
275  if(!imgTarget->isSimilarType(imgSource)) {
276  return shift;
277  }
278 
279  shift = wa.getExpShift(imgTarget, imgSource);
280 
281  return shift;
282  }
283 
284  static Image *shiftImage(Image *img, Vec2i shift, Image *ret = NULL)
285  {
286  if(img == NULL) {
287  return ret;
288  }
289 
290  if(ret == NULL) {
291  ret = img->allocateSimilarOne();
292  } else {
293  if(!ret->isSimilarType(img)) {
294  ret = img->allocateSimilarOne();
295  }
296  }
297 
298  ret->setZero();
299  Buffer<float>::shift(ret->data, img->data,
300  shift[0], shift[1],
301  img->width, img->height,
302  img->channels, img->frames);
303 
304  return ret;
305  }
306 
307 
315  static Image *execute(Image *imgTarget, Image *imgSource, Vec2i &shift)
316  {
317  shift = execute(imgTarget, imgSource);
318 
319  if(shift[0] != 0 && shift[1] != 0) {
320  Image *ret = shiftImage(imgSource, shift, NULL);
321  return ret;
322  } else {
323  return imgSource;
324  }
325  }
326 };
327 
328 } // end namespace pic
329 
330 #endif /* PIC_FEATURES_MATCHING_WARD_ALIGNMENT_HPP */
331 
static Vec2i execute(Image *imgTarget, Image *imgSource)
Definition: ward_alignment.hpp:266
float percentile
Definition: ward_alignment.hpp:38
float * data
data is the main buffer where pixel values are stored.
Definition: image.hpp:91
PIC_INLINE int log2(int n)
log2 computes logarithm in base 2 for integers.
Definition: math.hpp:302
void setZero()
setZero sets data to 0.0f.
int channels
Definition: image.hpp:80
Definition: filter_luminance.hpp:28
std::vector< Image * > ImageVec
ImageVec an std::vector of pic::Image.
Definition: image_vec.hpp:29
bool isSimilarType(const Image *img)
isSimilarType checks if the current image is similar to img; i.e. if they have the same width...
int frames
Definition: image.hpp:80
static T * shift(T *bufferOut, T *bufferIn, int dx, int dy, int width, int height, int channels, int frames)
shift
Definition: buffer.hpp:566
std::vector< bool *> eb2_shifted_v
Definition: ward_alignment.hpp:42
Vec< 2, int > Vec2i
Vec2i.
Definition: vec.hpp:829
ImageVec img1_v
Definition: ward_alignment.hpp:41
WardAlignment()
WardAlignment.
Definition: ward_alignment.hpp:47
std::vector< bool *> tb2_v
Definition: ward_alignment.hpp:42
std::vector< bool *> tb2_shifted_v
Definition: ward_alignment.hpp:42
static Image * execute(Image *imgIn, Image *imgOut, int width, int height)
execute
Definition: filter_downsampler_2d.hpp:100
int nPixels() const
nPixels computes the number of pixels.
Definition: image.hpp:499
ImageVec luminance
Definition: ward_alignment.hpp:41
static Image * execute(Image *imgIn, Image *imgOut, LUMINANCE_TYPE type=LT_CIE_LUMINANCE)
execute
Definition: filter_luminance.hpp:166
std::vector< bool *> tb1_v
Definition: ward_alignment.hpp:42
static Image * execute(Image *imgTarget, Image *imgSource, Vec2i &shift)
execute aligns imgSource to imgTarget
Definition: ward_alignment.hpp:315
The WardAlignment class.
Definition: ward_alignment.hpp:35
#define MIN(a, b)
Definition: math.hpp:69
The Image class stores an image as buffer of float.
Definition: image.hpp:60
float tolerance
Definition: ward_alignment.hpp:38
Image * allocateSimilarOne()
allocateSimilarOne creates an Image with similar size of the calling instance.
float * getPercentileVal(float percentile, BBox *box, float *ret)
getPercentileVal computes the n-th value given a percentile.
Definition: bilateral_separation.hpp:25
ImageVec img2_v
Definition: ward_alignment.hpp:41
void update(float percentile, float tolerance)
update sets parameters up for MTB
Definition: ward_alignment.hpp:88
#define MAX(a, b)
Definition: math.hpp:73
static Image * shiftImage(Image *img, Vec2i shift, Image *ret=NULL)
Definition: ward_alignment.hpp:284
int width
Definition: image.hpp:80
int height
Definition: image.hpp:80
The Vec class.
Definition: vec.hpp:35
~WardAlignment()
Definition: ward_alignment.hpp:52
bool * MTB(Image *img, Image *L)
MTB computes the median threshold mask.
Definition: ward_alignment.hpp:108
Vec2i getExpShift(Image *img1, Image *img2, int shift_bits=6)
getExpShift computes the shift vector for moving an img1 onto img2
Definition: ward_alignment.hpp:149