Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
ExampleHomographyMapping.cpp
1 /*
2 This file is part of the BIAS library (Basic ImageAlgorithmS).
3 
4 Copyright (C) 2003-2009 (see file CONTACT for details)
5  Multimediale Systeme der Informationsverarbeitung
6  Institut fuer Informatik
7  Christian-Albrechts-Universitaet Kiel
8 
9 
10 BIAS is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
14 
15 BIAS is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Lesser General Public License for more details.
19 
20 You should have received a copy of the GNU Lesser General Public License
21 along with BIAS; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24 
25 /**
26  * @example ExampleHomographyMapping.cpp
27  @relates HomographyMapping
28  @brief Example for HomographyMapping usage.
29  @ingroup g_examples
30  @author MIP
31 */
32 
33 #include <Image/HomographyMapping.hh>
34 #include <Image/AffineMapping.hh>
35 #include <Image/DisplacementMapping.hh>
36 #include <Base/Image/ImageIO.hh>
37 #include <Base/Debug/TimeMeasure.hh>
38 #include <Base/Math/Random.hh>
39 
40 using namespace BIAS;
41 using namespace std;
42 
43 // #define AFFINE
44 
45 int main(int argc, char *argv[])
46 {
47  cout<<endl<<"Usage: "<<argv[0]
48  <<" [testimage [ width height [homography.mat]]]"<<endl<<endl;
49  cout<<"If you dont provide a test image, I will generate one :-)"
50  <<endl<<endl;
51  Image<unsigned char> im(640, 480, 1);
52  if (argc>=2) {
53  if (ImageIO::Load(argv[1], im)!=0){
54  BIASERR("error loading "<<argv[1]);
55  return -2;
56  }
57 
58  }
59  HMatrix H(MatrixIdentity), tmp;
60  if (argc>4) {
61  cout<<"Reading HMatrix "<<argv[4]<<endl;
62  H.Load(argv[4]);
63  cout<<"H is "<<H<<endl;
64  H.GetInverse(tmp);
65  H = tmp;
66  } else {
67  /*
68  H[0][0]= 4.5 ; H[0][1]= -0.08; H[0][2] = 0;
69  H[1][0]= 0.08; H[1][1]= 4.5; H[1][2] = 0;
70  */
71 
72  // direction of enlargement
73  double angle = -45.0 / 180.0 * M_PI;
74  // outpuit direction
75  double angle2 = 3.0 / 180.0 * M_PI;
77  HRot[0][0]= cos(angle); HRot[0][1] = sin(angle);
78  HRot[1][0]= -sin(angle); HRot[1][1]= cos(angle);
79 
80 
81  HRot2[0][0]= cos(angle2); HRot2[0][1] = sin(angle2);
82  HRot2[1][0]= -sin(angle2); HRot2[1][1]= cos(angle2);
83 
84 
85 
86  HMatrix HScale(MatrixIdentity);
87  HScale[0][0] = 4.0; HScale[1][1] = 1.0;
88  //HScale[0][0] = 2.0; HScale[1][1] = 2.0;
89  // HScale[1][2] = -400;
90  H = HRot2 * HRot.Transpose() * HScale * HRot;
91  //H = HMatrix(MatrixIdentity);
92 
93  cout<<"Using default homography "<<H<<endl;
94  }
95 
96  if (argc<2){
97  cout<<"Generating test image orig.mip"<<endl;
98  bool highFreqCross = true;
99  HomgPoint2D point(0.0, 0.0, 1.0);
100  HMatrix Hinv;
101  H.GetInverse(Hinv);
102  Hinv *= 1.0 / H[2][2];
103  Random R;
104  if (!im.IsEmpty()) im.Release();
105 
106 
108  GenerateTestImage(im,highFreqCross,5,245,Hinv);
109 
110  ImageIO::Save("orig.mip", im);
111 
112 
113 
114 
115 
116  } else {
117  if (ImageIO::Load(argv[1], im)!=0){
118  BIASERR("error loading "<<argv[1]);
119  return -2;
120  }
121  }
122  int width = im.GetWidth()/2;
123  int height = im.GetHeight()/2;
124 
125  if (argc>3) {
126  width = atoi(argv[2]);
127  height = atoi(argv[3]);
128  cout<<"Using imagesize "<<width<<" x "<<height<<endl;
129  } else {
130  cout<<"Using input image size "<<width<<" x "<<height<<endl;
131  }
132 
133  HMatrix HMove(MatrixIdentity), HMove2(MatrixIdentity), HMoveInv;
134  HMove[0][2]= double(im.GetWidth())/-2.0;
135  HMove[1][2] =double(im.GetHeight())/-2.0;
136  HMove2[0][2]= double(width)/-2.0; HMove2[1][2] = double(height)/-2.0;
137  HMove.GetInverse(HMoveInv);
138  H = HMoveInv * H * HMove2;
139  cout<<"ROI of source image is "<<*im.GetROI()
140  <<" while image size is "<<width<<" x "<<height<<endl;
141 
142 
143 #ifdef AFFINE
145 #else
147 #endif
149 
150  // Mapper.SetPyramidSize(1);
151 
152 
154  imresnearest (width, height, im.GetChannelCount()),
155  imresbilinear (width, height, im.GetChannelCount()),
156  imrestrilinear (width, height, im.GetChannelCount()),
157 
158  imresnearest_dismap (width, height, im.GetChannelCount()),
159 
160  imresnearest_lookup (width, height, im.GetChannelCount()),
161  imresbilinear_lookup (width, height, im.GetChannelCount()),
162  imrestrilinear_lookup (width, height, im.GetChannelCount()),
163 
164  imresbicubic (width, height, im.GetChannelCount()),
165  imresanisotropic (width, height, im.GetChannelCount()),
166  imresdirect (width, height, im.GetChannelCount());
167 
168  unsigned char *color = new unsigned char[im.GetChannelCount()];
169  for(unsigned int i=0;i<im.GetChannelCount();i++) color[i]=(unsigned char)255;
170 
171  imresnearest.FillImageWithConstValue(color);
172  imresbilinear.FillImageWithConstValue(color);
173  imrestrilinear.FillImageWithConstValue(color);
174  imresnearest_dismap.FillImageWithConstValue(color);
175  imresnearest_lookup.FillImageWithConstValue(color);
176  imresbilinear_lookup.FillImageWithConstValue(color);
177  imrestrilinear_lookup.FillImageWithConstValue(color);
178  imresbicubic.FillImageWithConstValue(color);
179  imresanisotropic.FillImageWithConstValue(color);
180  imresdirect.FillImageWithConstValue(color);
181 
182  delete[] color;
183  //Nearest-Neigbour Displacement Map
185  NN_dismap (width, height, 3);
186 
187 #ifdef AFFINE
188  Mapper.SetAffineTransformation(H[0][0],H[0][1],H[1][0], H[1][1],
189  H[0][2],H[1][2]);
190 #else
191  // trilinear mapping with automatic scale and pyramid size selection
192  Mapper.SetHomography(H);
193 
194 #endif
195 
196 
197 #ifdef AFFINE
198  Mapper.MapDirect(im, imresdirect);
199 #endif
200 
201 
202  //Mapper.GetDisplacementMap(NN_dismap, im);
203  Mapper.GetDisplacementMap(NN_dismap, im.GetWidth(), im.GetHeight());
204  Mapper_dis.SetDisplacementMap(NN_dismap);
205 
206  unsigned char* Data = imresnearest_dismap.GetImageData();
207 
208  int counter = 0;
209  int counter_index = 0;
210  double bias_x, bias_y;
211 
212  for(unsigned int j = 0; j < imresnearest_dismap.GetHeight(); j++){
213  for(unsigned int i = 0; i < imresnearest_dismap.GetWidth(); i++){
214  HomgPoint2D p_sink, p_src;
215  p_sink[0] = i;
216  p_sink[1] = j;
217  p_sink[2] = 1.0;
218 
219  if(Mapper_dis.GetSourceCoordinates_(p_sink, p_src) != -1){
220 
221 
222  im.TextureToBIASCoordinates(p_src[0], p_src[1], bias_x, bias_y);
223 
224  //BIG DEBUG CHECKING IF BIAS2TEXTURE and TEXTURE2BIAS work correctly
225  /**
226  HomgPoint2D p_src_p, p_bias;
227  im.BIASToTextureCoordinates(bias_x, bias_y, p_src_p[0], p_src_p[1]);
228  im.TextureToBIASCoordinates(p_src_p[0], p_src_p[1],
229  p_bias[0], p_bias[1]);
230 
231  if(p_src[0] != p_src_p[0] || p_src[1] != p_src_p[1] ||
232  bias_x != p_bias[0] || bias_y != p_bias[1]
233  ){
234  cout << endl;
235  cout << "TEXT coords: " << p_src[0] << ", " << p_src[1] << endl;
236  cout << "BIAS coords: " << bias_x << ", " << bias_y << endl;
237  cout << "TEXT coords: " << p_src_p[0] << ", " << p_src_p[1] << endl;
238  cout << "BIAS coords: " << p_bias[0] << ", " << p_bias[1] << endl;
239  }
240  **/
241 
242  int p_x = (int)rint(bias_x);
243  int p_y = (int)rint(bias_y);
244  int p_z = (int)(p_src[2]);
245 
246  if(p_z != -1 &&
247  p_x >= 0 &&
248  p_x < (int)im.GetWidth() &&
249  p_y >= 0 &&
250  p_y < (int)im.GetHeight()){
251  counter_index = im.GetWidth()*p_y + p_x;
252  *Data++ =(unsigned char)im.GetImageData()[counter_index];
253  }
254  else
255  *Data++ = (unsigned char)(0);
256  }
257  counter++;
258  }
259  }
260 
261 
262  cout<<"timing ..."<<endl<<flush;
263  unsigned int numbermeasurements = 1;
264  TimeMeasure t1, t2, t3, t4, t5, t6;
265  TimeMeasure t1l_init, t2l_init, t4l_init;//, t4l, t5l;
266  TimeMeasure t1l, t2l, t4l;//, t4l, t5l;
267  for (unsigned int i=0; i<numbermeasurements; i++) {
268 
269  //---NEAREST NEIGHBOUR---
270  t1.Start();
271  // NN mapping
272  Mapper.Map(im, imresnearest, MapNearestNeighbor);
273  t1.Stop();
274 
275  t1l_init.Start();
276  Mapper.PrepareLookupTableMapping(im, imresnearest_lookup,
278  t1l_init.Stop();
279  t1l.Start();
280  // NN mapping
281  Mapper.MapWithLookupTable(im, imresnearest_lookup, MapNearestNeighbor);
282  t1l.Stop();
283 
284  //-----------------------
285 
286  //--------BILINEAR-------
287  t2.Start();
288  // fast backward mapping (bilinaer) disregarding sampling theroem
289  Mapper.Map(im, imresbilinear, MapBilinear);
290  t2.Stop();
291 
292  t2l_init.Start();
293  Mapper.PrepareLookupTableMapping(im, imresbilinear_lookup,
294  MapBilinear);
295 
296  t2l_init.Stop();
297  t2l.Start();
298  // trilinear mapping with automatic scale and pyramid size selection
299  Mapper.MapWithLookupTable(im, imresbilinear_lookup, MapBilinear);
300  t2l.Stop();
301  //-----------------------
302 #ifdef TIMING
303  BIASWARN("Anisoptropic filtering causes double free or corruption error.")
304  t3.Start();
305  // anisotropic
306  Mapper.Map(im, imresanisotropic, MapAnisotropic);
307  t3.Stop();
308 #endif //TIMING
309  //-------TRILINEAR-------
310  t4.Start();
311  // trilinear mapping with automatic scale and pyramid size selection
312  Mapper.Map(im, imrestrilinear, MapTrilinear, false,2.0);
313  t4.Stop();
314 
315  t4l_init.Start();
316  Mapper.PrepareLookupTableMapping(im, imrestrilinear_lookup,
317  MapTrilinear);
318  t4l_init.Stop();
319  t4l.Start();
320  // trilinear mapping with automatic scale and pyramid size selection
321  Mapper.MapWithLookupTable(im, imrestrilinear_lookup, MapTrilinear);
322  t4l.Stop();
323  //-----------------------
324 
325  t5.Start();
326  // bicubic mapping with automatic scale and pyramid size selection
327  Mapper.Map(im, imresbicubic, MapBicubic);
328  t5.Stop();
329 #ifdef AFFINE
330  t6.Start();
331  // direct affine mapping with automatic scale and pyramid size selection
332  Mapper.MapDirect(im, imresdirect);
333  t6.Stop();
334 
335 #endif
336 
337  }
338  cout <<"Anisotropic mapping took "
339  <<t3.GetUserTime()/double(numbermeasurements)
340  <<" ms, "<<endl
341 
342  <<"Bicubic mapping took "
343  <<t5.GetUserTime()/double(numbermeasurements)
344  <<" ms,"<<endl
345 
346  <<"NN-mapping (no lookups) took "
347  <<t1.GetUserTime()/double(numbermeasurements)
348  <<" ms"<< endl
349  <<"NN-mapping (wt lookups) init took "
350  <<t1l_init.GetUserTime()/double(numbermeasurements)
351  <<" ms," << endl
352  <<"NN-mapping (wt lookups) took "
353  <<t1l.GetUserTime()/double(numbermeasurements)
354  <<" ms," << endl
355 
356  <<"Bilinear mapping (no lookups) took "
357  <<t2.GetUserTime()/double(numbermeasurements)
358  <<" ms,"<<endl
359  <<"Bilinear mapping (wt lookups) init took "
360  <<t2l_init.GetUserTime()/double(numbermeasurements)
361  <<" ms,"<<endl
362  <<"Bilinear mapping (wt lookups) took "
363  <<t2l.GetUserTime()/double(numbermeasurements)
364  <<" ms,"<<endl
365 
366  <<"Trilinear mapping (no lookups) took "
367  <<t4.GetUserTime()/double(numbermeasurements)
368  <<" ms,"<<endl
369  <<"Trilinear mapping (wt lookups) init took "
370  <<t4l_init.GetUserTime()/double(numbermeasurements)
371  <<" ms,"<<endl
372  <<"Trilinear mapping (wt lookups) took "
373  <<t4l.GetUserTime()/double(numbermeasurements)
374  <<" ms,"<<endl
375 #ifdef AFFINE
376  <<"Direct affine took "
377  <<t6.GetUserTime()/double(numbermeasurements)<<" ms"
378 #endif
379  <<endl;
380 
381  //if (ImageIO::Save("image_homography_anisotropic.mip", imresanisotropic)!=0){
382  if (ImageIO::Save("image_homography_anisotropic.mip", imresanisotropic)!=0){
383  BIASERR("error image");
384  return -3;
385  }
386  //if (ImageIO::Save("image_homography_trilinear.mip", imrestrilinear)!=0){
387  if (ImageIO::Save("image_homography_trilinear.mip", imrestrilinear)!=0){
388  BIASERR("error image");
389  return -3;
390  }
391  //if (ImageIO::Save("image_homography_trilinear_lookup.mip",
392  // imrestrilinear_lookup)!=0){
393  if (ImageIO::Save("image_homography_trilinear_lookup.mip",
394  imrestrilinear_lookup)!=0){
395  BIASERR("error image");
396  return -3;
397  }
398  //if (ImageIO::Save("image_homography_bicubic.mip", imresbicubic)!=0){
399  if (ImageIO::Save("image_homography_bicubic.mip", imresbicubic)!=0){
400  BIASERR("error image");
401  return -3;
402  }
403  //if (ImageIO::Save("image_homography_bilinear.mip", imresbilinear)!=0){
404  if (ImageIO::Save("image_homography_bilinear.mip", imresbilinear)!=0){
405  BIASERR("error image");
406  return -3;
407  }
408  //if (ImageIO::Save("image_homography_bilinear_lookup.mip",
409  // imresbilinear_lookup)!=0){
410  if (ImageIO::Save("image_homography_bilinear_lookup.mip",
411  imresbilinear_lookup)!=0){
412  BIASERR("error image");
413  return -3;
414  }
415  //if (ImageIO::Save("image_homography_nearest.mip", imresnearest)!=0){
416  if (ImageIO::Save("image_homography_nearest.mip", imresnearest)!=0){
417  BIASERR("error image");
418  return -3;
419  }
420  //if (ImageIO::Save("image_homography_nearest_lookup.mip",
421  // imresnearest_lookup)!=0){
422  if (ImageIO::Save("image_homography_nearest_lookup.mip",
423  imresnearest_lookup)!=0){
424  BIASERR("error image");
425  return -3;
426  }
427  //if (ImageIO::Save("image_homography_nearest_dismap.mip",
428  // imresnearest_dismap)!=0){
429  if (ImageIO::Save("image_homography_nearest_dismap.mip",
430  imresnearest_dismap)!=0){
431  BIASERR("error image");
432  return -3;
433  }
434 #ifdef AFFINE
435  if (ImageIO::Save("image_direct.mip", imresdirect)!=0){
436  BIASERR("error image");
437  return -3;
438  }
439 #endif
440  return 0;
441 }
class HomgPoint2D describes a point with 2 degrees of freedom in projective coordinates.
Definition: HomgPoint2D.hh:67
a 3x3 Matrix describing projective transformations between planes
Definition: HMatrix.hh:39
Maps image src to image sink with homography H (software implementation)
int SetDisplacementMap(Image< float > &dismap)
virtual int GetSourceCoordinates_(const HomgPoint2D &sink, HomgPoint2D &source) const
reimplementation for homography, takes sink and computes coords in source taking the values from disp...
Maps image src to image sink with displacement mapl generated by backwardmapping method.
int GetInverse(Matrix3x3< T > &inv) const
Matrix inversion: inverts this and stores resulty in argument inv.
Definition: Matrix3x3.cpp:373
int Map(const Image< InputStorageType > &src, Image< OutputStorageType > &sink, InterpolationMethod=MapTrilinear, bool newSink=false, double SuperSampling=1.0)
backward mapping with various interpolations
int PrepareLookupTableMapping(const Image< InputStorageType > &src, Image< OutputStorageType > &sink, InterpolationMethod method, bool newSink=false)
precomputes lookup coordinates for accessing src
bool Load(const std::string &fname)
Definition: Matrix3x3.cpp:546
Maps image src to image sink with affine transformation.
static void GenerateTestImage(Image< InputStorageType > &testimage, bool highFrequencyCross=true, InputStorageType dark=5, InputStorageType bright=127, const Matrix3x3< double > &Hinv=Matrix3x3< double >(MatrixIdentity))
generates a siemens star like test image with lots of different frequencies to test backward mapping ...
void FillImageWithConstValue(StorageType Value)
fill grey images
Definition: Image.cpp:456
static int Save(const std::string &filename, const ImageBase &img, const enum TFileFormat FileFormat=FF_auto, const bool sync=BIAS_DEFAULT_SYNC, const int c_jpeg_quality=BIAS_DEFAULT_IMAGE_QUALITY, const bool forceNewID=BIAS_DEFAULT_FORCENEWID, const bool &writeMetaData=true)
Export image as file using extrnal libs.
Definition: ImageIO.cpp:725
int MapWithLookupTable(const Image< InputStorageType > &src, Image< OutputStorageType > &sink, InterpolationMethod method)
applies precomputed coordinates in src, fast for repeated usages of same mapping function ...
static int Load(const std::string &FileName, ImageBase &img)
first tries a call to Read MIP image and if that fails, tries to Import Image with all other availabl...
Definition: ImageIO.cpp:141
int GetDisplacementMap(Image< float > &dismap, int width, int height)
precomputes lookup coordinates and computes displacement map int TEXTURE coordinates, according to the size of src (or width,height)
void SetHomography(const HMatrix &H)
set your homography H (source = H * sink) before calling Map()
double GetUserTime() const
return user time (=system usage time) in msec JW For Win32: user-time is the sum over all processes o...
class for producing random numbers from different distributions
Definition: Random.hh:51
class TimeMeasure contains functions for timing real time and cpu time.
Definition: TimeMeasure.hh:111