Roussos-Maragos Tensor-Driven Diffusion Interpolation
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
finterp.c
Go to the documentation of this file.
1 
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <math.h>
10 #include <fftw3.h>
11 
12 #include "basic.h"
13 #include "finterp.h"
14 
15 
22 static int ConstExtension(int N, int i)
23 {
24  if(i < 0)
25  return 0;
26  else if(i >= N)
27  return N - 1;
28  else
29  return i;
30 }
31 
32 
39 static int HSymExtension(int N, int i)
40 {
41  while(1)
42  {
43  if(i < 0)
44  i = -1 - i;
45  else if(i >= N)
46  i = (2*N - 1) - i;
47  else
48  return i;
49  }
50 }
51 
52 
59 static int WSymExtension(int N, int i)
60 {
61  while(1)
62  {
63  if(i < 0)
64  i = -i;
65  else if(i >= N)
66  i = (2*N - 2) - i;
67  else
68  return i;
69  }
70 }
71 
72 
73 int (*ExtensionMethod[3])(int, int) =
74  {ConstExtension, HSymExtension, WSymExtension};
75 
76 
77 static int FourierScaleScan(float *Dest,
78  int DestStride, int DestScanStride, int DestChannelStride, int DestScanSize,
79  const float *Src,
80  int SrcStride, int SrcScanStride, int SrcChannelStride, int SrcScanSize,
81  int NumScans, int NumChannels, float XStart, double PsfSigma,
82  boundaryhandling Boundary)
83 {
84  const int SrcPadScanSize = 2*(SrcScanSize
85  - ((Boundary == BOUNDARY_WSYMMETRIC) ? 1:0));
86  const int DestPadScanSize = (Boundary == BOUNDARY_HSYMMETRIC) ?
87  (2*DestScanSize)
88  : (2*DestScanSize - (int)floor((2.0f*DestScanSize)/SrcScanSize + 0.5f));
89  const int ReflectOffset = SrcPadScanSize
90  - ((Boundary == BOUNDARY_HSYMMETRIC) ? 1:0);
91  const int SrcDftSize = SrcPadScanSize/2 + 1;
92  const int DestDftSize = DestPadScanSize/2 + 1;
93  const int BufSpatialNumEl = DestPadScanSize*NumScans*NumChannels;
94  const int BufDftNumEl = 2*DestDftSize*NumScans*NumChannels;
95  float *BufSpatial = NULL, *BufDft = NULL, *Modulation = NULL, *Ptr;
96  fftwf_plan Plan = 0;
97  fftwf_iodim Dims[1], HowManyDims[1];
98  float Temp, Denom;
99  int i, Scan, Channel, Success = 0;
100 
101 
102  if((Boundary != BOUNDARY_HSYMMETRIC && Boundary != BOUNDARY_WSYMMETRIC)
103  || !(BufSpatial = (float *)fftwf_malloc(sizeof(float)*BufSpatialNumEl))
104  || !(BufDft = (float *)fftwf_malloc(sizeof(float)*BufDftNumEl)))
105  goto Catch;
106 
107  if(XStart != 0)
108  {
109  if(!(Modulation = (float *)Malloc(sizeof(float)*2*DestDftSize)))
110  goto Catch;
111 
112  for(i = 0; i < DestDftSize; i++)
113  {
114  Temp = (float)(M_2PI*XStart*i/SrcPadScanSize);
115  Modulation[2*i + 0] = (float)cos(Temp);
116  Modulation[2*i + 1] = (float)sin(Temp);
117  }
118  }
119 
120  /* Fill BufSpatial with the input and symmetrize */
121  for(Channel = 0; Channel < NumChannels; Channel++)
122  {
123  for(Scan = 0; Scan < NumScans; Scan++)
124  {
125  for(i = 0; i < SrcScanSize; i++)
126  BufSpatial[i + SrcPadScanSize*(Scan + NumScans*Channel)]
127  = Src[SrcStride*i + SrcScanStride*Scan + SrcChannelStride*Channel];
128 
129  for(; i < SrcPadScanSize; i++)
130  BufSpatial[i + SrcPadScanSize*(Scan + NumScans*Channel)]
131  = Src[SrcStride*(ReflectOffset - i)
132  + SrcScanStride*Scan + SrcChannelStride*Channel];
133  }
134  }
135 
136  /* Initialize DFT buffer to zeros (there is no "fftwf_calloc"). Note that
137  it is not safely portable to use memset for this purpose.
138  http://c-faq.com/malloc/calloc.html */
139  for(i = 0; i < BufDftNumEl; i++)
140  BufDft[i] = 0.0f;
141 
142  /* Perform DFT real-to-complex transform */
143  Dims[0].n = SrcPadScanSize;
144  Dims[0].is = 1;
145  Dims[0].os = 1;
146  HowManyDims[0].n = NumScans*NumChannels;
147  HowManyDims[0].is = SrcPadScanSize;
148  HowManyDims[0].os = DestDftSize;
149 
150  if(!(Plan = fftwf_plan_guru_dft_r2c(1, Dims, 1, HowManyDims, BufSpatial,
151  (fftwf_complex *)BufDft, FFTW_ESTIMATE | FFTW_DESTROY_INPUT)))
152  goto Catch;
153 
154  fftwf_execute(Plan);
155  fftwf_destroy_plan(Plan);
156 
157  if(PsfSigma == 0)
158  for(Channel = 0, Ptr = BufDft; Channel < NumChannels; Channel++)
159  for(Scan = 0; Scan < NumScans; Scan++, Ptr += 2*DestDftSize)
160  for(i = 0; i < SrcDftSize; i++)
161  {
162  Ptr[2*i + 0] /= SrcPadScanSize;
163  Ptr[2*i + 1] /= SrcPadScanSize;
164  }
165  else
166  {
167  /* Also divide by the Gaussian point spread function in this case */
168  Temp = (float)(SrcPadScanSize / (M_2PI * PsfSigma));
169  Temp = 2*Temp*Temp;
170 
171  for(i = 0; i < SrcDftSize; i++)
172  {
173  if(i <= DestScanSize)
174  Denom = (float)exp(-(i*i)/Temp);
175  else
176  Denom = (float)exp(
177  -((DestPadScanSize - i)*(DestPadScanSize - i))/Temp);
178 
179  Denom *= SrcPadScanSize;
180 
181  for(Channel = 0; Channel < NumChannels; Channel++)
182  for(Scan = 0; Scan < NumScans; Scan++)
183  {
184  BufDft[2*(i + DestDftSize*(Scan + NumScans*Channel)) + 0] /= Denom;
185  BufDft[2*(i + DestDftSize*(Scan + NumScans*Channel)) + 1] /= Denom;
186  }
187  }
188  }
189 
190  /* If XStart is nonzero, modulate the DFT to translate the result */
191  if(XStart != 0)
192  for(Channel = 0, Ptr = BufDft; Channel < NumChannels; Channel++)
193  for(Scan = 0; Scan < NumScans; Scan++, Ptr += 2*DestDftSize)
194  for(i = 0; i < SrcDftSize; i++)
195  {
196  /* Complex multiply */
197  Temp = Ptr[2*i + 0]*Modulation[2*i + 0]
198  - Ptr[2*i + 1]*Modulation[2*i + 1];
199  Ptr[2*i + 1] = Ptr[2*i + 0]*Modulation[2*i + 1]
200  + Ptr[2*i + 1]*Modulation[2*i + 0];
201  Ptr[2*i + 0] = Temp;
202  }
203 
204  /* Perform inverse DFT complex-to-real transform */
205  Dims[0].n = DestPadScanSize;
206  Dims[0].is = 1;
207  Dims[0].os = 1;
208  HowManyDims[0].n = NumScans*NumChannels;
209  HowManyDims[0].is = DestDftSize;
210  HowManyDims[0].os = DestPadScanSize;
211 
212  if(!(Plan = fftwf_plan_guru_dft_c2r(1, Dims, 1, HowManyDims,
213  (fftwf_complex *)BufDft, BufSpatial,
214  FFTW_ESTIMATE | FFTW_DESTROY_INPUT)))
215  goto Catch;
216 
217  fftwf_execute(Plan);
218  fftwf_destroy_plan(Plan);
219 
220  /* Fill Dest with the result (and trim padding) */
221  for(Channel = 0; Channel < NumChannels; Channel++)
222  {
223  for(Scan = 0; Scan < NumScans; Scan++)
224  {
225  for(i = 0; i < DestScanSize; i++)
226  Dest[DestStride*i + DestScanStride*Scan + DestChannelStride*Channel]
227  = BufSpatial[i + DestPadScanSize*(Scan + NumScans*Channel)];
228  }
229  }
230 
231  Success = 1;
232 Catch:
233  Free(Modulation);
234  if(BufDft)
235  fftwf_free(BufDft);
236  if(BufSpatial)
237  fftwf_free(BufSpatial);
238  fftwf_cleanup();
239  return Success;
240 }
241 
242 
266 int FourierScale2d(float *Dest, int DestWidth, float XStart,
267  int DestHeight, float YStart,
268  const float *Src, int SrcWidth, int SrcHeight, int NumChannels,
269  double PsfSigma, boundaryhandling Boundary)
270 {
271  float *Buf = NULL;
272  unsigned long StartTime, StopTime;
273  int Success = 0;
274 
275 
276  if(!Dest || DestWidth < SrcWidth || DestHeight < SrcHeight || !Src
277  || SrcWidth <= 0 || SrcHeight <= 0 || NumChannels <= 0 || PsfSigma < 0
278  || !(Buf = (float *)Malloc(sizeof(float)*SrcWidth*DestHeight*3)))
279  return 0;
280 
281  StartTime = Clock();
282 
283  /* Scale the image vertically */
284  if(!FourierScaleScan(Buf, SrcWidth, 1, SrcWidth*DestHeight, DestHeight,
285  Src, SrcWidth, 1, SrcWidth*SrcHeight, SrcHeight,
286  SrcWidth, 3, YStart, PsfSigma, Boundary))
287  goto Catch;
288 
289  /* Scale the image horizontally */
290  if(!FourierScaleScan(Dest, 1, DestWidth, DestWidth*DestHeight, DestWidth,
291  Buf, 1, SrcWidth, SrcWidth*DestHeight, SrcWidth,
292  DestHeight, 3, XStart, PsfSigma, Boundary))
293  goto Catch;
294 
295  StopTime = Clock();
296  printf("CPU Time: %.3f s\n\n", 0.001*(StopTime - StartTime));
297 
298  Success = 1;
299 Catch:
300  Free(Buf);
301  return Success;
302 }