Total Variation Deconvolution using Split Bregman
usolve_dft_inc.c
Go to the documentation of this file.
1 
14 #include <string.h>
15 #include "util_deconv.h"
16 
17 
27 static void SymmetricPadding(num *Dest, const num *Src,
28  int Width, int Height, int NumChannels)
29 {
30  const int InPlace = (Dest == Src);
31  const int PadWidth = 2*Width;
32  const long ChannelJump = ((long)PadWidth) * ((long)Height);
33  const int SrcStride = (InPlace) ? PadWidth : Width;
34  int x, y, k;
35 
36  for(k = 0; k < NumChannels; k++)
37  {
38  for(y = 0; y < Height; y++, Dest += PadWidth, Src += SrcStride)
39  {
40  if(!InPlace)
41  memcpy(Dest, Src, sizeof(num) * Width);
42 
43  for(x = 0; x < Width; x++)
44  Dest[Width + x] = Dest[Width - 1 - x];
45 
46  memcpy(Dest + ((long)(2*(Height - y) - 1)) * PadWidth,
47  Dest, sizeof(num) * PadWidth);
48  }
49 
50  Dest += ChannelJump;
51 
52  if(InPlace)
53  Src = Dest;
54  }
55 }
56 
57 
59 static void AdjBlurFourier(numcomplex *ATrans, num *A, FFT(plan) TransformA,
60  const numcomplex *KernelTrans, const num *ztilde,
61  int Width, int Height, int NumChannels, num Alpha)
62 {
63  const int PadWidth = 2*Width;
64  const int PadHeight = 2*Height;
65  const int TransWidth = PadWidth/2 + 1;
66  const long TransNumPixels = ((long)TransWidth) * ((long)PadHeight);
67  long i;
68  int k;
69 
70  /* Compute A as a symmetric padded version of ztilde */
71  SymmetricPadding(A, ztilde, Width, Height, NumChannels);
72 
73  /* Compute ATrans = DFT[A] */
74  FFT(execute)(TransformA);
75 
76  /* Compute ATrans = Alpha . conj(KernelTrans) . ATrans */
77  for(k = 0; k < NumChannels; k++, ATrans += TransNumPixels)
78  for(i = 0; i < TransNumPixels; i++)
79  {
80  num Temp = Alpha*(KernelTrans[i][0] * ATrans[i][1]
81  - KernelTrans[i][1] * ATrans[i][0]);
82  ATrans[i][0] = Alpha*(KernelTrans[i][0] * ATrans[i][0]
83  + KernelTrans[i][1] * ATrans[i][1]);
84  ATrans[i][1] = Temp;
85  }
86 }
87 
88 
95 {
96  num *B = S->B;
97  numcomplex *ATrans = (numcomplex *)S->ATrans;
98  numcomplex *BTrans = (numcomplex *)S->BTrans;
99  numcomplex *KernelTrans = (numcomplex *)S->KernelTrans;
100  num *DenomTrans = S->DenomTrans;
101  const num *Kernel = S->Opt.Kernel;
102  const int KernelWidth = S->Opt.KernelWidth;
103  const int KernelHeight = S->Opt.KernelHeight;
104  const int PadWidth = S->PadWidth;
105  const int PadHeight = S->PadHeight;
106  const num Alpha = S->Alpha;
107  const long PadNumPixels = ((long)PadWidth) * ((long)PadHeight);
108  const int TransWidth = PadWidth/2 + 1;
109  FFT(plan) Plan = NULL;
110  long i;
111  int PadSize[2], x0, y0, x, y, xi, yi;
112 
113  for(i = 0; i < PadNumPixels; i++)
114  B[i] = 0;
115 
116  x0 = -KernelWidth/2;
117  y0 = -KernelHeight/2;
118 
119  /* Pad Kernel to size PadWidth by PadHeight. If Kernel
120  happens to be larger, it is wrapped. */
121  for(y = y0, i = 0; y < y0 + KernelHeight; y++)
122  {
123  yi = PeriodicExtension(PadHeight, y);
124 
125  for(x = x0; x < x0 + KernelWidth; x++, i++)
126  {
127  xi = PeriodicExtension(PadWidth, x);
128  B[xi + PadWidth*yi] += Kernel[i];
129  }
130  }
131 
132  /* Compute the Fourier transform of the padded Kernel */
133  if(!(Plan = FFT(plan_dft_r2c_2d)(PadHeight, PadWidth, B,
134  KernelTrans, FFTW_ESTIMATE | FFTW_DESTROY_INPUT)))
135  return 0;
136 
137  FFT(execute)(Plan);
138  FFT(destroy_plan)(Plan);
139 
140  /* Precompute the denominator that will be used in the u-subproblem. */
141  for(y = 0, i = 0; y < PadHeight; y++)
142  for(x = 0; x < TransWidth; x++, i++)
143  DenomTrans[i] =
144  (num)(PadNumPixels*(Alpha*(KernelTrans[i][0]*KernelTrans[i][0]
145  + KernelTrans[i][1]*KernelTrans[i][1])
146  + 2*(2 - cos(x*M_2PI/PadWidth) - cos(y*M_2PI/PadHeight))));
147 
148  /* Plan Fourier transforms */
149  PadSize[1] = PadWidth;
150  PadSize[0] = PadHeight;
151 
152  if(!(S->TransformA = FFT(plan_many_dft_r2c)(2, PadSize, S->NumChannels,
153  S->A, NULL, 1, PadNumPixels, ATrans, NULL, 1,
154  TransWidth*PadHeight, FFTW_ESTIMATE | FFTW_DESTROY_INPUT))
155  || !(S->InvTransformA = FFT(plan_many_dft_c2r)(2, PadSize,
156  S->NumChannels, ATrans, NULL, 1, TransWidth*PadHeight, S->A,
157  NULL, 1, PadNumPixels, FFTW_ESTIMATE | FFTW_DESTROY_INPUT))
158  || !(S->TransformB = FFT(plan_many_dft_r2c)(2, PadSize,
159  S->NumChannels, S->B, NULL, 1, PadNumPixels, BTrans, NULL, 1,
160  TransWidth*PadHeight, FFTW_ESTIMATE | FFTW_DESTROY_INPUT))
161  || !(S->InvTransformB = FFT(plan_many_dft_c2r)(2, PadSize,
162  S->NumChannels, BTrans, NULL, 1, TransWidth*PadHeight, S->B,
163  NULL, 1, PadNumPixels, FFTW_ESTIMATE | FFTW_DESTROY_INPUT)))
164  return 0;
165 
166  /* Compute ATrans = Alpha . conj(KernelTrans) . DFT[f] */
167  if(!S->UseZ)
168  AdjBlurFourier(ATrans, S->A, S->TransformA,
169  (const numcomplex *)KernelTrans, S->f,
170  S->Width, S->Height, S->NumChannels, Alpha);
171 
172  S->Ku = S->A;
173  return 1;
174 }
175 
176 
183 static void UTransSolveFourier(numcomplex *BTrans, num *B, FFT(plan) TransformB,
184  numcomplex *ATrans, const numvec2 *dtilde,
185  const num *DenomTrans, int Width, int Height, int NumChannels)
186 {
187  const long PadWidth = 2*Width;
188  const long PadHeight = 2*Height;
189  const long TransWidth = PadWidth/2 + 1;
190  const long TransNumPixels = TransWidth * PadHeight;
191  long i;
192  int k;
193 
194  /* Compute B = div(dtilde) and pad with even half-sample symmetry */
195  Divergence(B, PadWidth, PadHeight, dtilde, Width, Height, NumChannels);
196  SymmetricPadding(B, B, Width, Height, NumChannels);
197 
198  /* Compute BTrans = DFT[B] */
199  FFT(execute)(TransformB);
200 
201  /* Compute BTrans = ( ATrans - BTrans ) / DenomTrans */
202  for(k = 0; k < NumChannels; k++,
203  ATrans += TransNumPixels, BTrans += TransNumPixels)
204  for(i = 0; i < TransNumPixels; i++)
205  {
206  BTrans[i][0] = (ATrans[i][0] - BTrans[i][0]) / DenomTrans[i];
207  BTrans[i][1] = (ATrans[i][1] - BTrans[i][1]) / DenomTrans[i];
208  }
209 }
210 
211 
228 {
229  /* BTrans = ( ATrans - DFT[div(dtilde)] ) / DenomTrans */
230  UTransSolveFourier((numcomplex *)S->BTrans, S->B, S->TransformB,
231  (numcomplex *)S->ATrans, S->dtilde, S->DenomTrans,
232  S->Width, S->Height, S->NumChannels);
233  /* B = IDFT[BTrans] */
234  FFT(execute)(S->InvTransformB);
235  /* Trim padding, compute ||B - u||, and assign u = B */
236  return UUpdate(S);
237 }
238 
239 
240 #if defined(TVREG_USEZ) || defined(DOXYGEN)
241 
250 {
251  numcomplex *ATrans = (numcomplex *)S->ATrans;
252  numcomplex *BTrans = (numcomplex *)S->BTrans;
253  const numcomplex *KernelTrans = (const numcomplex *)S->KernelTrans;
254  const int TransWidth = S->PadWidth/2 + 1;
255  const long TransNumPixels = ((long)TransWidth) * ((long)S->PadHeight);
256  long i;
257  int k;
258 
259  /* Compute ATrans = Alpha . conj(KernelTrans) . DFT[ztilde] */
260  AdjBlurFourier(ATrans, S->A, S->TransformA, KernelTrans, S->ztilde,
261  S->Width, S->Height, S->NumChannels, S->Alpha);
262  /* BTrans = ( ATrans - DFT[div(dtilde)] ) / DenomTrans */
263  UTransSolveFourier((numcomplex *)S->BTrans, S->B, S->TransformB,
264  ATrans, S->dtilde, S->DenomTrans,
265  S->Width, S->Height, S->NumChannels);
266 
267  /* Compute ATrans = KernelTrans . BTrans */
268  for(k = 0; k < S->NumChannels; k++,
269  ATrans += TransNumPixels, BTrans += TransNumPixels)
270  for(i = 0; i < TransNumPixels; i++)
271  {
272  ATrans[i][0] = KernelTrans[i][0] * BTrans[i][0]
273  - KernelTrans[i][1] * BTrans[i][1];
274  ATrans[i][1] = KernelTrans[i][0] * BTrans[i][1]
275  + KernelTrans[i][1] * BTrans[i][0];
276  }
277 
278  /* A = IDFT[ATrans] = new Ku */
279  FFT(execute)(S->InvTransformA);
280  /* B = IDFT[BTrans] = new u */
281  FFT(execute)(S->InvTransformB);
282 
283  /* Trim padding, compute ||B - u||, and assign u = B */
284  return UUpdate(S);
285 }
286 #endif