Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
ExampleFMT2D.cpp
1 /* This file is part of the BIAS library (Basic ImageAlgorithmS).
2 
3  Copyright (C) 2003-2009 (see file CONTACT for details)
4  Multimediale Systeme der Informationsverarbeitung
5  Institut fuer Informatik
6  Christian-Albrechts-Universitaet Kiel
7 
8 
9  BIAS is free software; you can redistribute it and/or modify
10  it under the terms of the GNU Lesser General Public License as published by
11  the Free Software Foundation; either version 2.1 of the License, or
12  (at your option) any later version.
13 
14  BIAS is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  GNU Lesser General Public License for more details.
18 
19  You should have received a copy of the GNU Lesser General Public License
20  along with BIAS; if not, write to the Free Software
21  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/
22 
23 
24 /**
25  * @example ExampleFMT2D.cpp
26  @relates FFT2D
27  @brief Example for using the fast fourier Transform (FFT) 2D
28  @ingroup g_examples
29  @author MIP
30 */
31 
32 #include <Image/FFT2D.hh>
33 #include <Base/Image/Image.hh>
34 #include <Base/Image/ImageIO.hh>
35 #include <Base/Image/ImageConvert.hh>
36 #include <Image/LogPolarMapping.hh>
37 #include <Image/HomographyMapping.hh>
38 #include <Base/Debug/TimeMeasure.hh>
39 #include <Geometry/RMatrix.hh>
40 
41 
42 using namespace std;
43 using namespace BIAS;
44 
45 int cut(const Image<float>& src, Image<float>& dst){
46  int width = src.GetWidth();
47  int height = src.GetHeight();
48 
49  dst.Init(width-1,src.GetHeight(),1);
50  const float *simgp = src.GetImageData();
51  float *dimgp = dst.GetImageData();
52 
53  for(int i=0;i<height;i++){
54  for(int j=1;j<width;j++){
55  dimgp[(j-1)+i*(width-1)] = simgp[j+i*width];
56  }
57  }
58  return 0;
59 }
60 
61 int mirror(const Image<float>& src, Image<float>& dst){
62 
63  int width = src.GetWidth();
64  int height = src.GetHeight();
65  int qsize = width*height/2;
66  if (!dst.IsEmpty()) dst.Release();
67  //dst.Init(2*width,height,1);
68  dst.Init(width,height,1);
69  const float *simgp = src.GetImageData();
70  float *oimgp = dst.GetImageData();
71  for(int i=0;i<qsize;i++){
72 
73  oimgp[qsize+i] = log(simgp[i]);
74  oimgp[i] = log(simgp[qsize+i]);
75  }
76 //Highpass Filter ??
77 /*
78  for(int y =0; y<height;y++){
79  for(int x=0;x<width;x++){
80  oimgp[y*width+x] -= (10.0 * cos(0.5*M_PI*(double)x/(double)width) * cos(0.5*M_PI*(double)(y-height/2)/(double)(height/2)));
81  }
82  }
83 */
84 /*
85  oimgp[qsize] -= 8;
86  oimgp[qsize+1] -= 6;
87  oimgp[qsize+2] -= 4;
88  oimgp[qsize+3] -= 2;
89  oimgp[qsize-width] -= 6;
90  oimgp[qsize-width+1] -= 4;
91  oimgp[qsize-width+2] -= 2;
92  oimgp[qsize+width] -= 6;
93  oimgp[qsize+width+1] -= 4;
94  oimgp[qsize+width+2] -= 2;
95  oimgp[qsize-2*width] -= 4;
96  oimgp[qsize-2*width+1] -= 2;
97  oimgp[qsize-3*width] -= 2;
98  oimgp[qsize+2*width] -= 4;
99  oimgp[qsize+2*width+1] -= 2;
100  oimgp[qsize+3*width] -= 2;
101 */
102 
103  return 0;
104 }
105 
106 int castfloat(const Image<unsigned char>& src, Image<float>& dst){
107  int width = src.GetWidth();
108  int height = src.GetHeight();
109  int size = width*height;
110  dst.Init( width,height,src.GetChannelCount());
111  const unsigned char *imgp1 = src.GetImageData();
112  float *oimgp1 = dst.GetImageData();
113  for(int i=0;i<size;i++){
114  oimgp1[i] = (float) imgp1[i];
115  }
116  return 0;
117 }
118 
119 int castchar(const Image<float>& src, Image<unsigned char>& dst){
120  int width = src.GetWidth();
121  int height = src.GetHeight();
122  int size = width*height;
123  dst.Init( width,height,src.GetChannelCount());
124  const float *imgp1 = src.GetImageData();
125  unsigned char *oimgp1 = dst.GetImageData();
126  for(int i=0;i<size;i++){
127  oimgp1[i] = (unsigned char) imgp1[i];
128  }
129  return 0;
130 }
131 
132 int main(int argc, char *argv[])
133 {
134 
135  TimeMeasure t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11;
136 
137  //load input images and initialize components
138  t1.Start();
139  if (argc != 3){
140  cerr << argv[0] << " <image> <image2>\n";
141  return -1;
142  }
143 
144  Image<unsigned char> im1, im2,im1grey,im2grey, resuc;
145  Image<float> im1greyfloat, im2correctedfloat, im2greyfloat, mag1, mag1cut, mag1mirrored, mag2, mag2cut, mag2mirrored, cps, res;
146  float max, max2;
147  double angle,scale;
148  unsigned int* coords = (unsigned int*) calloc(2,sizeof(unsigned int));
149  unsigned int* coords2 = (unsigned int*) calloc(2,sizeof(unsigned int));
152  HMatrix H(MatrixIdentity);
153  HMatrix HTrans(MatrixIdentity);
154  HMatrix HTransInv(MatrixIdentity);
155  HMatrix HRot(MatrixIdentity);
156  HMatrix HScale(MatrixIdentity);
157 
158  if (ImageIO::Load(argv[1], im1)!=0){
159  BIASERR("error loading image "<<argv[1]);
160  return -2;
161  }
162  if (ImageIO::Load(argv[2], im2)!=0){
163  BIASERR("error loading image "<<argv[2]);
164  return -2;
165  }
166 
167  int width = im1.GetWidth();
168  int height = im1.GetHeight();
169 
170  if((width != (int)im2.GetWidth()) ||
171  (height != (int)im2.GetHeight())){
172  BIASERR("images must have same size!");
173  return -2;
174  }
175 
177  mapperlp.SetImageCenter(width/2,height/2);
178  Image<float> im1lp(width,height, 1);
179  Image<float> im2lp(width,height, 1);
180  Image<unsigned char>imgcorrected(width, height, 1);
181  Image<unsigned char>imgcorrected2(width, height, 1);
182 
183  t10.Start();
184  fft.Init(width,height);
185  t10.Stop();
186 
187  ImageConvert::ToGrey(im1,im1grey);
188  //ImageIO::Save("0_Grey1",im1grey);
189  ImageIO::Save("0_Grey1",im1grey);
190  ImageConvert::ToGrey(im2,im2grey);
191  //ImageIO::Save("0_Grey2",im2grey);
192  ImageIO::Save("0_Grey2",im2grey);
193  im1lp.SetColorModel(im1grey.GetColorModel());
194  im2lp.SetColorModel(im2grey.GetColorModel());
195  t1.Stop();
196 
197  //cast image to float
198  t2.Start();
199  castfloat(im1grey,im1greyfloat);
200  castfloat(im2grey,im2greyfloat);
201  t2.Stop();
202 
203  //calculate magnitude for grey float input images
204  t3.Start();
205  fft.TransformAbs(im1greyfloat,mag1);
206  //ImageIO::Save("1_mag1",mag1);
207  ImageIO::Save("1_mag1",mag1);
208  fft.TransformAbs(im2greyfloat,mag2);
209  //ImageIO::Save("1_mag2",mag2);
210  ImageIO::Save("1_mag2",mag2);
211  t3.Stop();
212 
213  //cut image if too large and mirror magnitude to have CT at left border center position and width exactly half the original images width
214  t4.Start();
215  if(mag1.GetWidth()%2 != 0){
216  cut(mag1,mag1cut);
217  cut(mag2,mag2cut);
218  }
219  mirror(mag1cut,mag1mirrored);
220  mirror(mag2cut,mag2mirrored);
221  //ImageIO::Save("2_mag1mirrored",mag1mirrored);
222  //ImageIO::Save("2_mag2mirrored",mag2mirrored);
223  ImageIO::Save("2_mag1mirrored",mag1mirrored);
224  ImageIO::Save("2_mag2mirrored",mag2mirrored);
225  t4.Stop();
226 
227  //calculate Log-Polar spectrum for prepared magnitude
228  t5.Start();
229  mapperlp.Map(mag1mirrored, im1lp, MapBilinear);
230  //if (ImageIO::Save("ImgLogPolar.mip", im1lp)!=0){
231  if (ImageIO::Save("ImgLogPolar.mip", im1lp)!=0){
232  BIASERR("error image");
233  }
234 
235  mapperlp.Map(mag2mirrored, im2lp, MapBilinear);
236  //if (ImageIO::Save("ImgLogPolar2.mip", im2lp)!=0){
237  if (ImageIO::Save("ImgLogPolar2.mip", im2lp)!=0){
238  BIASERR("error image");
239  }
240  t5.Stop();
241 
242  //calculate the Cross Power Spectrum for Log-Polar images
243  t6.Start();
244  fft.CrossPowerSpectrum(im1lp,im2lp,cps);
245  //ImageIO::Save("3_CPS",cps);
246  ImageIO::Save("3_CPS",cps);
247  t6.Stop();
248 
249  //Transform reverse to find rotation and scale
250  t7.Start();
251  fft.TransformReverse(cps,res);
252  //ImageIO::Save("4_Resolution",res);
253  ImageIO::Save("4_Resolution",res);
254  t7.Stop();
255 
256  //find the peak
257  t8.Start();
258  max = res.GetMaxPixelValue(0,coords);
259  t8.Stop();
260 
261  //Correct the 2. source image with calculated rotation and scale
262  t9.Start();
263  angle = (double)coords[1] / (double) height * M_PI;
264  if (angle > (0.5*M_PI)) angle -= M_PI;
265  if(coords[0] > (unsigned int)(width/2))
266  scale = pow((double)(width/2),((double)coords[0]-(double)width)/(double)width);
267  else
268  scale = pow((double)(width/2),(double)coords[0]/(double) width);
269 
270  HTrans[0][2] = (double)(width/2);
271  HTrans[1][2] = (double)(height/2);
272  HTransInv[0][2] = (double)-(width/2);
273  HTransInv[1][2] = (double)-(height/2);
274  HRot[0][0]= cos(angle);
275  HRot[0][1]= -sin(angle);
276  HRot[1][0]= sin(angle);
277  HRot[1][1]= cos(angle);
278  HScale[0][0] = scale;
279  HScale[1][1] = scale;
280  HScale[1][2] = 1.0;
281 
282  H = HTrans * HScale * HRot * HTransInv;
283  MapperHM.SetHomography(H);
284  MapperHM.Map(im2grey, imgcorrected, MapBilinear);
285  //ImageIO::Save("5_Corrected",imgcorrected);
286  ImageIO::Save("5_Corrected",imgcorrected);
287  t9.Stop();
288 
289  //Find the translation with the rotation and scale corrected image
290  t11.Start();
291  castfloat(imgcorrected,im2correctedfloat);
292  fft.CrossPowerSpectrum(im1greyfloat,im2correctedfloat,cps);
293  fft.TransformReverse(cps,res);
294  //ImageIO::Save("6_Resolution2",res);
295  ImageIO::Save("6_Resolution2",res);
296 
297  //Correct the image with the calculated translation
298  max2 = res.GetMaxPixelValue(0,coords2);
299  if(coords2[0] > (unsigned int)(width/2))
300  HTrans[0][2] = width - (int)coords2[0];
301  else
302  HTrans[0][2] = -(int)coords2[0];
303  if(coords2[1] > (unsigned int)(height/2))
304  HTrans[1][2] = height - (int)coords2[1];
305  else
306  HTrans[1][2] = -(int)coords2[1];
307 
308  MapperHM.SetHomography(HTrans);
309  MapperHM.Map(imgcorrected, imgcorrected2, MapBilinear);
310  //ImageIO::Save("7_Corrected2",imgcorrected2);
311  ImageIO::Save("7_Corrected2",imgcorrected2);
312  t11.Stop();
313 
314 
315 
316 
317  cout<<endl<<endl;
318  cout <<"Loading Image and converting to grey took "<<t1.GetUserTime()<<" ms, "<<endl;
319  cout <<"Floating took "<<t2.GetUserTime()<<" ms, "<<endl;
320  cout <<"Init FFT took "<<t10.GetUserTime()<<" ms, "<<endl;
321  cout <<"FFT took "<<t3.GetUserTime()<<" ms, "<<endl;
322  cout <<"Mirror took "<<t4.GetUserTime()<<" ms, "<<endl;
323  cout <<"LogPolar took: "<<t5.GetUserTime()<<" ms, "<<endl;
324  cout <<"CPS took "<<t6.GetUserTime()<<" ms, "<<endl;
325  cout <<"IFT took "<<t7.GetUserTime()<<" ms, "<<endl;
326  cout <<"Finding Max took "<<t8.GetUserTime()<<" ms, "<<endl;
327  cout <<"Correcting rotation and scale took "<<t9.GetUserTime()<<" ms, "<<endl;
328  cout <<"Finding and correcting translation took "<<t11.GetUserTime()<<" ms, "<<endl;
329 
330  cout<<endl;
331 
332  cout<<"Max at: "<<coords[0]<<"/"<<coords[1]<<" value: "<<max<<endl<<endl;
333  cout<<"Max2 at: "<<coords2[0]<<"/"<<coords2[1]<<" value: "<<max2<<endl<<endl;
334  cout<<"Das entspricht (fuer ein 512x512 Bild):"<<endl;
335  if(coords[0] > (unsigned int)(width/2))
336  cout<<"Skalierungsfaktor: "<<pow(256.0,((double)coords[0]-width)/512.0)<<endl;
337  else
338  cout<<"Skalierungsfaktor: "<<pow(256.0,(double)coords[0]/512.0)<<endl;
339  cout<<"Rotation: "<<180.0*angle/M_PI<<" Grad"<<endl;
340 
341  cout<<"Verschiebung: (";
342  if(coords2[0] > (unsigned int)(width/2))
343  cout<<width - (int)coords2[0];
344  else
345  cout<<-(int)coords2[0];
346  cout<<",";
347  if(coords2[1] > (unsigned int)(height/2))
348  cout<<height - (int)coords2[1];
349  else
350  cout<<-(int)coords2[1];
351  cout<<")"<<endl;
352  return 0;
353 }
354 
Maps cartesian source coordinates to log-polar sink coordinates.
void Release()
reimplemented from ImageBase
Definition: Image.cpp:1579
StorageType GetMaxPixelValue(unsigned short int channel=0, unsigned int *coo=NULL) const
Get the maximal pixel value if coo!=NULL the coo[0]=x of max and coo[1]=y of max. ...
Definition: Image.cpp:995
a 3x3 Matrix describing projective transformations between planes
Definition: HMatrix.hh:39
Maps image src to image sink with homography H (software implementation)
bool IsEmpty() const
check if ImageData_ points to allocated image buffer or not
Definition: ImageBase.hh:245
void SetImageCenter(const int &x, const int &y)
set your image center before calling Map().
unsigned int GetWidth() const
Definition: ImageBase.hh:312
virtual int TransformAbs(const Image< InputStorageType > &src, Image< OutputStorageType > &dst)
Transform forward and get absolute value from complex result The result is not normalized! ...
Definition: FFT2D.cpp:202
unsigned int GetChannelCount() const
returns the number of Color channels, e.g.
Definition: ImageBase.hh:382
unsigned int GetHeight() const
Definition: ImageBase.hh:319
int Map(const Image< InputStorageType > &src, Image< OutputStorageType > &sink, InterpolationMethod=MapTrilinear, bool newSink=false, double SuperSampling=1.0)
backward mapping with various interpolations
void Init(unsigned int Width, unsigned int Height, unsigned int channels=1, enum EStorageType storageType=ST_unsignedchar, const bool interleaved=true)
calls Init from ImageBase storageType is ignored, just dummy argument
Definition: Image.cpp:421
const StorageType * GetImageData() const
overloaded GetImageData() from ImageBase
Definition: Image.hh:137
void Init(int width, int height)
initializes for forward transformation on complete image.
Definition: FFT2D.cpp:57
enum EColorModel GetColorModel() const
Definition: ImageBase.hh:407
virtual int CrossPowerSpectrum(const Image< InputStorageType > &src1, const Image< InputStorageType > &src2, Image< OutputStorageType > &dst1)
Definition: FFT2D.cpp:273
Wrapper to the fftw3 library adapted for 2D image filtering.
Definition: FFT2D.hh:50
void SetHomography(const HMatrix &H)
set your homography H (source = H * sink) before calling Map()
virtual int TransformReverse(const Image< OutputStorageType > &src, Image< InputStorageType > &dst)
Transform reverse, src must be of _SizeX,_OutSizeY,2.
Definition: FFT2D.cpp:311
double GetUserTime() const
return user time (=system usage time) in msec JW For Win32: user-time is the sum over all processes o...
class TimeMeasure contains functions for timing real time and cpu time.
Definition: TimeMeasure.hh:111