]> granicus.if.org Git - imagemagick/blob - MagickCore/fourier.c
Add RobidouxSharp filter depreciate Bessel Filter and Static Gravity
[imagemagick] / MagickCore / fourier.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %               FFFFF   OOO   U   U  RRRR   IIIII  EEEEE  RRRR                %
7 %               F      O   O  U   U  R   R    I    E      R   R               %
8 %               FFF    O   O  U   U  RRRR     I    EEE    RRRR                %
9 %               F      O   O  U   U  R R      I    E      R R                 %
10 %               F       OOO    UUU   R  R   IIIII  EEEEE  R  R                %
11 %                                                                             %
12 %                                                                             %
13 %                MagickCore Discrete Fourier Transform Methods                %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                Sean Burke                                   %
17 %                               Fred Weinhaus                                 %
18 %                                John Cristy                                  %
19 %                                 July 2009                                   %
20 %                                                                             %
21 %                                                                             %
22 %  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
23 %  dedicated to making software imaging solutions freely available.           %
24 %                                                                             %
25 %  You may not use this file except in compliance with the License.  You may  %
26 %  obtain a copy of the License at                                            %
27 %                                                                             %
28 %    http://www.imagemagick.org/script/license.php                            %
29 %                                                                             %
30 %  Unless required by applicable law or agreed to in writing, software        %
31 %  distributed under the License is distributed on an "AS IS" BASIS,          %
32 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
33 %  See the License for the specific language governing permissions and        %
34 %  limitations under the License.                                             %
35 %                                                                             %
36 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
37 %
38 %
39 %
40 */
41 \f
42 /*
43   Include declarations.
44 */
45 #include "MagickCore/studio.h"
46 #include "MagickCore/attribute.h"
47 #include "MagickCore/cache.h"
48 #include "MagickCore/image.h"
49 #include "MagickCore/image-private.h"
50 #include "MagickCore/list.h"
51 #include "MagickCore/fourier.h"
52 #include "MagickCore/log.h"
53 #include "MagickCore/memory_.h"
54 #include "MagickCore/monitor.h"
55 #include "MagickCore/pixel-accessor.h"
56 #include "MagickCore/property.h"
57 #include "MagickCore/quantum-private.h"
58 #include "MagickCore/thread-private.h"
59 #if defined(MAGICKCORE_FFTW_DELEGATE)
60 #if defined(MAGICKCORE_HAVE_COMPLEX_H)
61 #include <complex.h>
62 #endif
63 #include <fftw3.h>
64 #if !defined(MAGICKCORE_HAVE_CABS)
65 #define cabs(z)  (sqrt(z[0]*z[0]+z[1]*z[1]))
66 #endif
67 #if !defined(MAGICKCORE_HAVE_CARG)
68 #define carg(z)  (atan2(cimag(z),creal(z)))
69 #endif
70 #if !defined(MAGICKCORE_HAVE_CIMAG)
71 #define cimag(z)  (z[1])
72 #endif
73 #if !defined(MAGICKCORE_HAVE_CREAL)
74 #define creal(z)  (z[0])
75 #endif
76 #endif
77 \f
78 /*
79   Typedef declarations.
80 */
81 typedef struct _FourierInfo
82 {
83   PixelChannel
84     channel;
85
86   MagickBooleanType
87     modulus;
88
89   size_t
90     width,
91     height;
92
93   ssize_t
94     center;
95 } FourierInfo;
96 \f
97 /*
98 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
99 %                                                                             %
100 %                                                                             %
101 %                                                                             %
102 %     F o r w a r d F o u r i e r T r a n s f o r m I m a g e                 %
103 %                                                                             %
104 %                                                                             %
105 %                                                                             %
106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
107 %
108 %  ForwardFourierTransformImage() implements the discrete Fourier transform
109 %  (DFT) of the image either as a magnitude / phase or real / imaginary image
110 %  pair.
111 %
112 %  The format of the ForwadFourierTransformImage method is:
113 %
114 %      Image *ForwardFourierTransformImage(const Image *image,
115 %        const MagickBooleanType modulus,ExceptionInfo *exception)
116 %
117 %  A description of each parameter follows:
118 %
119 %    o image: the image.
120 %
121 %    o modulus: if true, return as transform as a magnitude / phase pair
122 %      otherwise a real / imaginary image pair.
123 %
124 %    o exception: return any errors or warnings in this structure.
125 %
126 */
127
128 #if defined(MAGICKCORE_FFTW_DELEGATE)
129
130 static MagickBooleanType RollFourier(const size_t width,const size_t height,
131   const ssize_t x_offset,const ssize_t y_offset,double *fourier)
132 {
133   double
134     *roll;
135
136   register ssize_t
137     i,
138     x;
139
140   ssize_t
141     u,
142     v,
143     y;
144
145   /*
146     Move zero frequency (DC, average color) from (0,0) to (width/2,height/2).
147   */
148   roll=(double *) AcquireQuantumMemory((size_t) height,width*sizeof(*roll));
149   if (roll == (double *) NULL)
150     return(MagickFalse);
151   i=0L;
152   for (y=0L; y < (ssize_t) height; y++)
153   {
154     if (y_offset < 0L)
155       v=((y+y_offset) < 0L) ? y+y_offset+(ssize_t) height : y+y_offset;
156     else
157       v=((y+y_offset) > ((ssize_t) height-1L)) ? y+y_offset-(ssize_t) height :
158         y+y_offset;
159     for (x=0L; x < (ssize_t) width; x++)
160     {
161       if (x_offset < 0L)
162         u=((x+x_offset) < 0L) ? x+x_offset+(ssize_t) width : x+x_offset;
163       else
164         u=((x+x_offset) > ((ssize_t) width-1L)) ? x+x_offset-(ssize_t) width :
165           x+x_offset;
166       roll[v*width+u]=fourier[i++];
167     }
168   }
169   (void) CopyMagickMemory(fourier,roll,height*width*sizeof(*roll));
170   roll=(double *) RelinquishMagickMemory(roll);
171   return(MagickTrue);
172 }
173
174 static MagickBooleanType ForwardQuadrantSwap(const size_t width,
175   const size_t height,double *source,double *destination)
176 {
177   MagickBooleanType
178     status;
179
180   register ssize_t
181     x;
182
183   ssize_t
184     center,
185     y;
186
187   /*
188     Swap quadrants.
189   */
190   center=(ssize_t) floor((double) width/2L)+1L;
191   status=RollFourier((size_t) center,height,0L,(ssize_t) height/2L,source);
192   if (status == MagickFalse)
193     return(MagickFalse);
194   for (y=0L; y < (ssize_t) height; y++)
195     for (x=0L; x < (ssize_t) (width/2L-1L); x++)
196       destination[width*y+x+width/2L]=source[center*y+x];
197   for (y=1; y < (ssize_t) height; y++)
198     for (x=0L; x < (ssize_t) (width/2L-1L); x++)
199       destination[width*(height-y)+width/2L-x-1L]=source[center*y+x+1L];
200   for (x=0L; x < (ssize_t) (width/2L); x++)
201     destination[-x+width/2L-1L]=destination[x+width/2L+1L];
202   return(MagickTrue);
203 }
204
205 static void CorrectPhaseLHS(const size_t width,const size_t height,
206   double *fourier)
207 {
208   register ssize_t
209     x;
210
211   ssize_t
212     y;
213
214   for (y=0L; y < (ssize_t) height; y++)
215     for (x=0L; x < (ssize_t) (width/2L); x++)
216       fourier[y*width+x]*=(-1.0);
217 }
218
219 static MagickBooleanType ForwardFourier(const FourierInfo *fourier_info,
220   Image *image,double *magnitude,double *phase,ExceptionInfo *exception)
221 {
222   CacheView
223     *magnitude_view,
224     *phase_view;
225
226   double
227     *magnitude_source,
228     *phase_source;
229
230   Image
231     *magnitude_image,
232     *phase_image;
233
234   MagickBooleanType
235     status;
236
237   register ssize_t
238     x;
239
240   register Quantum
241     *q;
242
243   ssize_t
244     i,
245     y;
246
247   magnitude_image=GetFirstImageInList(image);
248   phase_image=GetNextImageInList(image);
249   if (phase_image == (Image *) NULL)
250     {
251       (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
252         "TwoOrMoreImagesRequired","'%s'",image->filename);
253       return(MagickFalse);
254     }
255   /*
256     Create "Fourier Transform" image from constituent arrays.
257   */
258   magnitude_source=(double *) AcquireQuantumMemory((size_t)
259     fourier_info->height,fourier_info->width*sizeof(*magnitude_source));
260   if (magnitude_source == (double *) NULL)
261     return(MagickFalse);
262   (void) ResetMagickMemory(magnitude_source,0,fourier_info->height*
263     fourier_info->width*sizeof(*magnitude_source));
264   phase_source=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
265     fourier_info->width*sizeof(*phase_source));
266   if (phase_source == (double *) NULL)
267     {
268       (void) ThrowMagickException(exception,GetMagickModule(),
269         ResourceLimitError,"MemoryAllocationFailed","'%s'",image->filename);
270       magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
271       return(MagickFalse);
272     }
273   status=ForwardQuadrantSwap(fourier_info->height,fourier_info->height,
274     magnitude,magnitude_source);
275   if (status != MagickFalse)
276     status=ForwardQuadrantSwap(fourier_info->height,fourier_info->height,phase,
277       phase_source);
278   CorrectPhaseLHS(fourier_info->height,fourier_info->height,phase_source);
279   if (fourier_info->modulus != MagickFalse)
280     {
281       i=0L;
282       for (y=0L; y < (ssize_t) fourier_info->height; y++)
283         for (x=0L; x < (ssize_t) fourier_info->width; x++)
284         {
285           phase_source[i]/=(2.0*MagickPI);
286           phase_source[i]+=0.5;
287           i++;
288         }
289     }
290   magnitude_view=AcquireAuthenticCacheView(magnitude_image,exception);
291   i=0L;
292   for (y=0L; y < (ssize_t) fourier_info->height; y++)
293   {
294     q=GetCacheViewAuthenticPixels(magnitude_view,0L,y,fourier_info->height,1UL,
295       exception);
296     if (q == (Quantum *) NULL)
297       break;
298     for (x=0L; x < (ssize_t) fourier_info->width; x++)
299     {
300       switch (fourier_info->channel)
301       {
302         case RedPixelChannel:
303         default:
304         {
305           SetPixelRed(magnitude_image,ClampToQuantum(QuantumRange*
306             magnitude_source[i]),q);
307           break;
308         }
309         case GreenPixelChannel:
310         {
311           SetPixelGreen(magnitude_image,ClampToQuantum(QuantumRange*
312             magnitude_source[i]),q);
313           break;
314         }
315         case BluePixelChannel:
316         {
317           SetPixelBlue(magnitude_image,ClampToQuantum(QuantumRange*
318             magnitude_source[i]),q);
319           break;
320         }
321         case BlackPixelChannel:
322         {
323           SetPixelBlack(magnitude_image,ClampToQuantum(QuantumRange*
324             magnitude_source[i]),q);
325           break;
326         }
327         case AlphaPixelChannel:
328         {
329           SetPixelAlpha(magnitude_image,ClampToQuantum(QuantumRange*
330             magnitude_source[i]),q);
331           break;
332         }
333       }
334       i++;
335       q+=GetPixelChannels(magnitude_image);
336     }
337     status=SyncCacheViewAuthenticPixels(magnitude_view,exception);
338     if (status == MagickFalse)
339       break;
340   }
341   magnitude_view=DestroyCacheView(magnitude_view);
342   i=0L;
343   phase_view=AcquireAuthenticCacheView(phase_image,exception);
344   for (y=0L; y < (ssize_t) fourier_info->height; y++)
345   {
346     q=GetCacheViewAuthenticPixels(phase_view,0L,y,fourier_info->height,1UL,
347       exception);
348     if (q == (Quantum *) NULL)
349       break;
350     for (x=0L; x < (ssize_t) fourier_info->width; x++)
351     {
352       switch (fourier_info->channel)
353       {
354         case RedPixelChannel:
355         default:
356         {
357           SetPixelRed(phase_image,ClampToQuantum(QuantumRange*
358             phase_source[i]),q);
359           break;
360         }
361         case GreenPixelChannel:
362         {
363           SetPixelGreen(phase_image,ClampToQuantum(QuantumRange*
364             phase_source[i]),q);
365           break;
366         }
367         case BluePixelChannel:
368         {
369           SetPixelBlue(phase_image,ClampToQuantum(QuantumRange*
370             phase_source[i]),q);
371           break;
372         }
373         case BlackPixelChannel:
374         {
375           SetPixelBlack(phase_image,ClampToQuantum(QuantumRange*
376             phase_source[i]),q);
377           break;
378         }
379         case AlphaPixelChannel:
380         {
381           SetPixelAlpha(phase_image,ClampToQuantum(QuantumRange*
382             phase_source[i]),q);
383           break;
384         }
385       }
386       i++;
387       q+=GetPixelChannels(phase_image);
388     }
389     status=SyncCacheViewAuthenticPixels(phase_view,exception);
390     if (status == MagickFalse)
391       break;
392    }
393   phase_view=DestroyCacheView(phase_view);
394   phase_source=(double *) RelinquishMagickMemory(phase_source);
395   magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
396   return(status);
397 }
398
399 static MagickBooleanType ForwardFourierTransform(FourierInfo *fourier_info,
400   const Image *image,double *magnitude,double *phase,ExceptionInfo *exception)
401 {
402   CacheView
403     *image_view;
404
405   double
406     n,
407     *source;
408
409   fftw_complex
410     *fourier;
411
412   fftw_plan
413     fftw_r2c_plan;
414
415   register const Quantum
416     *p;
417
418   register ssize_t
419     i,
420     x;
421
422   ssize_t
423     y;
424
425   /*
426     Generate the forward Fourier transform.
427   */
428   source=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
429     fourier_info->width*sizeof(*source));
430   if (source == (double *) NULL)
431     {
432       (void) ThrowMagickException(exception,GetMagickModule(),
433         ResourceLimitError,"MemoryAllocationFailed","'%s'",image->filename);
434       return(MagickFalse);
435     }
436   ResetMagickMemory(source,0,fourier_info->height*fourier_info->width*
437     sizeof(*source));
438   i=0L;
439   image_view=AcquireVirtualCacheView(image,exception);
440   for (y=0L; y < (ssize_t) fourier_info->height; y++)
441   {
442     p=GetCacheViewVirtualPixels(image_view,0L,y,fourier_info->width,1UL,
443       exception);
444     if (p == (const Quantum *) NULL)
445       break;
446     for (x=0L; x < (ssize_t) fourier_info->width; x++)
447     {
448       switch (fourier_info->channel)
449       {
450         case RedPixelChannel:
451         default:
452         {
453           source[i]=QuantumScale*GetPixelRed(image,p);
454           break;
455         }
456         case GreenPixelChannel:
457         {
458           source[i]=QuantumScale*GetPixelGreen(image,p);
459           break;
460         }
461         case BluePixelChannel:
462         {
463           source[i]=QuantumScale*GetPixelBlue(image,p);
464           break;
465         }
466         case BlackPixelChannel:
467         {
468           source[i]=QuantumScale*GetPixelBlack(image,p);
469           break;
470         }
471         case AlphaPixelChannel:
472         {
473           source[i]=QuantumScale*GetPixelAlpha(image,p);
474           break;
475         }
476       }
477       i++;
478       p+=GetPixelChannels(image);
479     }
480   }
481   image_view=DestroyCacheView(image_view);
482   fourier=(fftw_complex *) AcquireQuantumMemory((size_t) fourier_info->height,
483     fourier_info->center*sizeof(*fourier));
484   if (fourier == (fftw_complex *) NULL)
485     {
486       (void) ThrowMagickException(exception,GetMagickModule(),
487         ResourceLimitError,"MemoryAllocationFailed","'%s'",image->filename);
488       source=(double *) RelinquishMagickMemory(source);
489       return(MagickFalse);
490     }
491 #if defined(MAGICKCORE_OPENMP_SUPPORT)
492   #pragma omp critical (MagickCore_ForwardFourierTransform)
493 #endif
494   fftw_r2c_plan=fftw_plan_dft_r2c_2d(fourier_info->width,fourier_info->width,
495     source,fourier,FFTW_ESTIMATE);
496   fftw_execute(fftw_r2c_plan);
497   fftw_destroy_plan(fftw_r2c_plan);
498   source=(double *) RelinquishMagickMemory(source);
499   /*
500     Normalize Fourier transform.
501   */
502   n=(double) fourier_info->width*(double) fourier_info->width;
503   i=0L;
504   for (y=0L; y < (ssize_t) fourier_info->height; y++)
505     for (x=0L; x < (ssize_t) fourier_info->center; x++)
506     {
507 #if defined(MAGICKCORE_HAVE_COMPLEX_H)
508       fourier[i]/=n;
509 #else
510       fourier[i][0]/=n;
511       fourier[i][1]/=n;
512 #endif
513       i++;
514     }
515   /*
516     Generate magnitude and phase (or real and imaginary).
517   */
518   i=0L;
519   if (fourier_info->modulus != MagickFalse)
520     for (y=0L; y < (ssize_t) fourier_info->height; y++)
521       for (x=0L; x < (ssize_t) fourier_info->center; x++)
522       {
523         magnitude[i]=cabs(fourier[i]);
524         phase[i]=carg(fourier[i]);
525         i++;
526       }
527   else
528     for (y=0L; y < (ssize_t) fourier_info->height; y++)
529       for (x=0L; x < (ssize_t) fourier_info->center; x++)
530       {
531         magnitude[i]=creal(fourier[i]);
532         phase[i]=cimag(fourier[i]);
533         i++;
534       }
535   fourier=(fftw_complex *) RelinquishMagickMemory(fourier);
536   return(MagickTrue);
537 }
538
539 static MagickBooleanType ForwardFourierTransformChannel(const Image *image,
540   const PixelChannel channel,const MagickBooleanType modulus,
541   Image *fourier_image,ExceptionInfo *exception)
542 {
543   double
544     *magnitude,
545     *phase;
546
547   fftw_complex
548     *fourier;
549
550   FourierInfo
551     fourier_info;
552
553   MagickBooleanType
554     status;
555
556   size_t
557     extent;
558
559   fourier_info.width=image->columns;
560   if ((image->columns != image->rows) || ((image->columns % 2) != 0) ||
561       ((image->rows % 2) != 0))
562     {
563       extent=image->columns < image->rows ? image->rows : image->columns;
564       fourier_info.width=(extent & 0x01) == 1 ? extent+1UL : extent;
565     }
566   fourier_info.height=fourier_info.width;
567   fourier_info.center=(ssize_t) floor((double) fourier_info.width/2.0)+1L;
568   fourier_info.channel=channel;
569   fourier_info.modulus=modulus;
570   magnitude=(double *) AcquireQuantumMemory((size_t) fourier_info.height,
571     fourier_info.center*sizeof(*magnitude));
572   if (magnitude == (double *) NULL)
573     {
574       (void) ThrowMagickException(exception,GetMagickModule(),
575         ResourceLimitError,"MemoryAllocationFailed","'%s'",image->filename);
576       return(MagickFalse);
577     }
578   phase=(double *) AcquireQuantumMemory((size_t) fourier_info.height,
579     fourier_info.center*sizeof(*phase));
580   if (phase == (double *) NULL)
581     {
582       (void) ThrowMagickException(exception,GetMagickModule(),
583         ResourceLimitError,"MemoryAllocationFailed","'%s'",image->filename);
584       magnitude=(double *) RelinquishMagickMemory(magnitude);
585       return(MagickFalse);
586     }
587   fourier=(fftw_complex *) AcquireQuantumMemory((size_t) fourier_info.height,
588     fourier_info.center*sizeof(*fourier));
589   if (fourier == (fftw_complex *) NULL)
590     {
591       (void) ThrowMagickException(exception,GetMagickModule(),
592         ResourceLimitError,"MemoryAllocationFailed","'%s'",image->filename);
593       phase=(double *) RelinquishMagickMemory(phase);
594       magnitude=(double *) RelinquishMagickMemory(magnitude);
595       return(MagickFalse);
596     }
597   status=ForwardFourierTransform(&fourier_info,image,magnitude,phase,exception);
598   if (status != MagickFalse)
599     status=ForwardFourier(&fourier_info,fourier_image,magnitude,phase,
600       exception);
601   fourier=(fftw_complex *) RelinquishMagickMemory(fourier);
602   phase=(double *) RelinquishMagickMemory(phase);
603   magnitude=(double *) RelinquishMagickMemory(magnitude);
604   return(status);
605 }
606 #endif
607
608 MagickExport Image *ForwardFourierTransformImage(const Image *image,
609   const MagickBooleanType modulus,ExceptionInfo *exception)
610 {
611   Image
612     *fourier_image;
613
614   fourier_image=NewImageList();
615 #if !defined(MAGICKCORE_FFTW_DELEGATE)
616   (void) modulus;
617   (void) ThrowMagickException(exception,GetMagickModule(),
618     MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","'%s' (FFTW)",
619     image->filename);
620 #else
621   {
622     Image
623       *magnitude_image;
624
625     size_t
626       extent,
627       width;
628
629     width=image->columns;
630     if ((image->columns != image->rows) || ((image->columns % 2) != 0) ||
631         ((image->rows % 2) != 0))
632       {
633         extent=image->columns < image->rows ? image->rows : image->columns;
634         width=(extent & 0x01) == 1 ? extent+1UL : extent;
635       }
636     magnitude_image=CloneImage(image,width,width,MagickFalse,exception);
637     if (magnitude_image != (Image *) NULL)
638       {
639         Image
640           *phase_image;
641
642         magnitude_image->storage_class=DirectClass;
643         magnitude_image->depth=32UL;
644         phase_image=CloneImage(image,width,width,MagickFalse,exception);
645         if (phase_image == (Image *) NULL)
646           magnitude_image=DestroyImage(magnitude_image);
647         else
648           {
649             MagickBooleanType
650               is_gray,
651               status;
652
653             phase_image->storage_class=DirectClass;
654             phase_image->depth=32UL;
655             AppendImageToList(&fourier_image,magnitude_image);
656             AppendImageToList(&fourier_image,phase_image);
657             status=MagickTrue;
658             is_gray=IsImageGray(image,exception);
659 #if defined(MAGICKCORE_OPENMP_SUPPORT)
660             #pragma omp parallel sections
661 #endif
662             {
663 #if defined(MAGICKCORE_OPENMP_SUPPORT)
664               #pragma omp section
665 #endif
666               {
667                 MagickBooleanType
668                   thread_status;
669
670                 if (is_gray != MagickFalse)
671                   thread_status=ForwardFourierTransformChannel(image,
672                     GrayPixelChannel,modulus,fourier_image,exception);
673                 else
674                   thread_status=ForwardFourierTransformChannel(image,
675                     RedPixelChannel,modulus,fourier_image,exception);
676                 if (thread_status == MagickFalse)
677                   status=thread_status;
678               }
679 #if defined(MAGICKCORE_OPENMP_SUPPORT)
680               #pragma omp section
681 #endif
682               {
683                 MagickBooleanType
684                   thread_status;
685
686                 thread_status=MagickTrue;
687                 if (is_gray == MagickFalse)
688                   thread_status=ForwardFourierTransformChannel(image,
689                     GreenPixelChannel,modulus,fourier_image,exception);
690                 if (thread_status == MagickFalse)
691                   status=thread_status;
692               }
693 #if defined(MAGICKCORE_OPENMP_SUPPORT)
694               #pragma omp section
695 #endif
696               {
697                 MagickBooleanType
698                   thread_status;
699
700                 thread_status=MagickTrue;
701                 if (is_gray == MagickFalse)
702                   thread_status=ForwardFourierTransformChannel(image,
703                     BluePixelChannel,modulus,fourier_image,exception);
704                 if (thread_status == MagickFalse)
705                   status=thread_status;
706               }
707 #if defined(MAGICKCORE_OPENMP_SUPPORT)
708               #pragma omp section
709 #endif
710               {
711                 MagickBooleanType
712                   thread_status;
713
714                 thread_status=MagickTrue;
715                 if (image->colorspace == CMYKColorspace)
716                   thread_status=ForwardFourierTransformChannel(image,
717                     BlackPixelChannel,modulus,fourier_image,exception);
718                 if (thread_status == MagickFalse)
719                   status=thread_status;
720               }
721 #if defined(MAGICKCORE_OPENMP_SUPPORT)
722               #pragma omp section
723 #endif
724               {
725                 MagickBooleanType
726                   thread_status;
727
728                 thread_status=MagickTrue;
729                 if (image->matte != MagickFalse)
730                   thread_status=ForwardFourierTransformChannel(image,
731                     AlphaPixelChannel,modulus,fourier_image,exception);
732                 if (thread_status == MagickFalse)
733                   status=thread_status;
734               }
735             }
736             if (status == MagickFalse)
737               fourier_image=DestroyImageList(fourier_image);
738             fftw_cleanup();
739           }
740       }
741   }
742 #endif
743   return(fourier_image);
744 }
745 \f
746 /*
747 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
748 %                                                                             %
749 %                                                                             %
750 %                                                                             %
751 %     I n v e r s e F o u r i e r T r a n s f o r m I m a g e                 %
752 %                                                                             %
753 %                                                                             %
754 %                                                                             %
755 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
756 %
757 %  InverseFourierTransformImage() implements the inverse discrete Fourier
758 %  transform (DFT) of the image either as a magnitude / phase or real /
759 %  imaginary image pair.
760 %
761 %  The format of the InverseFourierTransformImage method is:
762 %
763 %      Image *InverseFourierTransformImage(const Image *magnitude_image,
764 %        const Image *phase_image,const MagickBooleanType modulus,
765 %        ExceptionInfo *exception)
766 %
767 %  A description of each parameter follows:
768 %
769 %    o magnitude_image: the magnitude or real image.
770 %
771 %    o phase_image: the phase or imaginary image.
772 %
773 %    o modulus: if true, return transform as a magnitude / phase pair
774 %      otherwise a real / imaginary image pair.
775 %
776 %    o exception: return any errors or warnings in this structure.
777 %
778 */
779
780 #if defined(MAGICKCORE_FFTW_DELEGATE)
781 static MagickBooleanType InverseQuadrantSwap(const size_t width,
782   const size_t height,const double *source,double *destination)
783 {
784   register ssize_t
785     x;
786
787   ssize_t
788     center,
789     y;
790
791   /*
792     Swap quadrants.
793   */
794   center=(ssize_t) floor((double) width/2.0)+1L;
795   for (y=1L; y < (ssize_t) height; y++)
796     for (x=0L; x < (ssize_t) (width/2L+1L); x++)
797       destination[center*(height-y)-x+width/2L]=source[y*width+x];
798   for (y=0L; y < (ssize_t) height; y++)
799     destination[center*y]=source[y*width+width/2L];
800   for (x=0L; x < center; x++)
801     destination[x]=source[center-x-1L];
802   return(RollFourier(center,height,0L,(ssize_t) height/-2L,destination));
803 }
804
805 static MagickBooleanType InverseFourier(FourierInfo *fourier_info,
806   const Image *magnitude_image,const Image *phase_image,fftw_complex *fourier,
807   ExceptionInfo *exception)
808 {
809   CacheView
810     *magnitude_view,
811     *phase_view;
812
813   double
814     *magnitude,
815     *phase,
816     *magnitude_source,
817     *phase_source;
818
819   MagickBooleanType
820     status;
821
822   register const Quantum
823     *p;
824
825   register ssize_t
826     i,
827     x;
828
829   ssize_t
830     y;
831
832   /*
833     Inverse fourier - read image and break down into a double array.
834   */
835   magnitude_source=(double *) AcquireQuantumMemory((size_t)
836     fourier_info->height,fourier_info->width*sizeof(*magnitude_source));
837   if (magnitude_source == (double *) NULL)
838     {
839       (void) ThrowMagickException(exception,GetMagickModule(),
840         ResourceLimitError,"MemoryAllocationFailed","'%s'",
841         magnitude_image->filename);
842       return(MagickFalse);
843     }
844   phase_source=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
845     fourier_info->width*sizeof(*phase_source));
846   if (phase_source == (double *) NULL)
847     {
848       (void) ThrowMagickException(exception,GetMagickModule(),
849         ResourceLimitError,"MemoryAllocationFailed","'%s'",
850         magnitude_image->filename);
851       magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
852       return(MagickFalse);
853     }
854   i=0L;
855   magnitude_view=AcquireVirtualCacheView(magnitude_image,exception);
856   for (y=0L; y < (ssize_t) fourier_info->height; y++)
857   {
858     p=GetCacheViewVirtualPixels(magnitude_view,0L,y,fourier_info->width,1UL,
859       exception);
860     if (p == (const Quantum *) NULL)
861       break;
862     for (x=0L; x < (ssize_t) fourier_info->width; x++)
863     {
864       switch (fourier_info->channel)
865       {
866         case RedPixelChannel:
867         default:
868         {
869           magnitude_source[i]=QuantumScale*GetPixelRed(magnitude_image,p);
870           break;
871         }
872         case GreenPixelChannel:
873         {
874           magnitude_source[i]=QuantumScale*GetPixelGreen(magnitude_image,p);
875           break;
876         }
877         case BluePixelChannel:
878         {
879           magnitude_source[i]=QuantumScale*GetPixelBlue(magnitude_image,p);
880           break;
881         }
882         case BlackPixelChannel:
883         {
884           magnitude_source[i]=QuantumScale*GetPixelBlack(magnitude_image,p);
885           break;
886         }
887         case AlphaPixelChannel:
888         {
889           magnitude_source[i]=QuantumScale*GetPixelAlpha(magnitude_image,p);
890           break;
891         }
892       }
893       i++;
894       p+=GetPixelChannels(magnitude_image);
895     }
896   }
897   i=0L;
898   phase_view=AcquireVirtualCacheView(phase_image,exception);
899   for (y=0L; y < (ssize_t) fourier_info->height; y++)
900   {
901     p=GetCacheViewVirtualPixels(phase_view,0,y,fourier_info->width,1,
902       exception);
903     if (p == (const Quantum *) NULL)
904       break;
905     for (x=0L; x < (ssize_t) fourier_info->width; x++)
906     {
907       switch (fourier_info->channel)
908       {
909         case RedPixelChannel:
910         default:
911         {
912           phase_source[i]=QuantumScale*GetPixelRed(phase_image,p);
913           break;
914         }
915         case GreenPixelChannel:
916         {
917           phase_source[i]=QuantumScale*GetPixelGreen(phase_image,p);
918           break;
919         }
920         case BluePixelChannel:
921         {
922           phase_source[i]=QuantumScale*GetPixelBlue(phase_image,p);
923           break;
924         }
925         case BlackPixelChannel:
926         {
927           phase_source[i]=QuantumScale*GetPixelBlack(phase_image,p);
928           break;
929         }
930         case AlphaPixelChannel:
931         {
932           phase_source[i]=QuantumScale*GetPixelAlpha(phase_image,p);
933           break;
934         }
935       }
936       i++;
937       p+=GetPixelChannels(phase_image);
938     }
939   }
940   if (fourier_info->modulus != MagickFalse)
941     {
942       i=0L;
943       for (y=0L; y < (ssize_t) fourier_info->height; y++)
944         for (x=0L; x < (ssize_t) fourier_info->width; x++)
945         {
946           phase_source[i]-=0.5;
947           phase_source[i]*=(2.0*MagickPI);
948           i++;
949         }
950     }
951   magnitude_view=DestroyCacheView(magnitude_view);
952   phase_view=DestroyCacheView(phase_view);
953   magnitude=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
954     fourier_info->center*sizeof(*magnitude));
955   if (magnitude == (double *) NULL)
956     {
957       (void) ThrowMagickException(exception,GetMagickModule(),
958         ResourceLimitError,"MemoryAllocationFailed","'%s'",
959         magnitude_image->filename);
960       magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
961       phase_source=(double *) RelinquishMagickMemory(phase_source);
962       return(MagickFalse);
963     }
964   status=InverseQuadrantSwap(fourier_info->width,fourier_info->height,
965     magnitude_source,magnitude);
966   magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
967   phase=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
968     fourier_info->width*sizeof(*phase));
969   if (phase == (double *) NULL)
970     {
971       (void) ThrowMagickException(exception,GetMagickModule(),
972         ResourceLimitError,"MemoryAllocationFailed","'%s'",
973         magnitude_image->filename);
974       phase_source=(double *) RelinquishMagickMemory(phase_source);
975       return(MagickFalse);
976     }
977   CorrectPhaseLHS(fourier_info->width,fourier_info->width,phase_source);
978   if (status != MagickFalse)
979     status=InverseQuadrantSwap(fourier_info->width,fourier_info->height,
980       phase_source,phase);
981   phase_source=(double *) RelinquishMagickMemory(phase_source);
982   /*
983     Merge two sets.
984   */
985   i=0L;
986   if (fourier_info->modulus != MagickFalse)
987     for (y=0L; y < (ssize_t) fourier_info->height; y++)
988        for (x=0L; x < (ssize_t) fourier_info->center; x++)
989        {
990 #if defined(MAGICKCORE_HAVE_COMPLEX_H)
991          fourier[i]=magnitude[i]*cos(phase[i])+I*magnitude[i]*sin(phase[i]);
992 #else
993          fourier[i][0]=magnitude[i]*cos(phase[i]);
994          fourier[i][1]=magnitude[i]*sin(phase[i]);
995 #endif
996          i++;
997       }
998   else
999     for (y=0L; y < (ssize_t) fourier_info->height; y++)
1000       for (x=0L; x < (ssize_t) fourier_info->center; x++)
1001       {
1002 #if defined(MAGICKCORE_HAVE_COMPLEX_H)
1003         fourier[i]=magnitude[i]+I*phase[i];
1004 #else
1005         fourier[i][0]=magnitude[i];
1006         fourier[i][1]=phase[i];
1007 #endif
1008         i++;
1009       }
1010   phase=(double *) RelinquishMagickMemory(phase);
1011   magnitude=(double *) RelinquishMagickMemory(magnitude);
1012   return(status);
1013 }
1014
1015 static MagickBooleanType InverseFourierTransform(FourierInfo *fourier_info,
1016   fftw_complex *fourier,Image *image,ExceptionInfo *exception)
1017 {
1018   CacheView
1019     *image_view;
1020
1021   double
1022     *source;
1023
1024   fftw_plan
1025     fftw_c2r_plan;
1026
1027   register Quantum
1028     *q;
1029
1030   register ssize_t
1031     i,
1032     x;
1033
1034   ssize_t
1035     y;
1036
1037   source=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
1038     fourier_info->width*sizeof(*source));
1039   if (source == (double *) NULL)
1040     {
1041       (void) ThrowMagickException(exception,GetMagickModule(),
1042         ResourceLimitError,"MemoryAllocationFailed","'%s'",image->filename);
1043       return(MagickFalse);
1044     }
1045 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1046   #pragma omp critical (MagickCore_InverseFourierTransform)
1047 #endif
1048   {
1049     fftw_c2r_plan=fftw_plan_dft_c2r_2d(fourier_info->width,fourier_info->height,
1050       fourier,source,FFTW_ESTIMATE);
1051     fftw_execute(fftw_c2r_plan);
1052     fftw_destroy_plan(fftw_c2r_plan);
1053   }
1054   i=0L;
1055   image_view=AcquireAuthenticCacheView(image,exception);
1056   for (y=0L; y < (ssize_t) fourier_info->height; y++)
1057   {
1058     if (y >= (ssize_t) image->rows)
1059       break;
1060     q=GetCacheViewAuthenticPixels(image_view,0L,y,fourier_info->width >
1061       image->columns ? image->columns : fourier_info->width,1UL,exception);
1062     if (q == (Quantum *) NULL)
1063       break;
1064     for (x=0L; x < (ssize_t) fourier_info->width; x++)
1065     {
1066       switch (fourier_info->channel)
1067       {
1068         case RedPixelChannel:
1069         default:
1070         {
1071           SetPixelRed(image,ClampToQuantum(QuantumRange*source[i]),q);
1072           break;
1073         }
1074         case GreenPixelChannel:
1075         {
1076           SetPixelGreen(image,ClampToQuantum(QuantumRange*source[i]),q);
1077           break;
1078         }
1079         case BluePixelChannel:
1080         {
1081           SetPixelBlue(image,ClampToQuantum(QuantumRange*source[i]),q);
1082           break;
1083         }
1084         case BlackPixelChannel:
1085         {
1086           SetPixelBlack(image,ClampToQuantum(QuantumRange*source[i]),q);
1087           break;
1088         }
1089         case AlphaPixelChannel:
1090         {
1091           SetPixelAlpha(image,ClampToQuantum(QuantumRange*source[i]),q);
1092           break;
1093         }
1094       }
1095       i++;
1096       q+=GetPixelChannels(image);
1097     }
1098     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1099       break;
1100   }
1101   image_view=DestroyCacheView(image_view);
1102   source=(double *) RelinquishMagickMemory(source);
1103   return(MagickTrue);
1104 }
1105
1106 static MagickBooleanType InverseFourierTransformChannel(
1107   const Image *magnitude_image,const Image *phase_image,
1108   const PixelChannel channel,const MagickBooleanType modulus,
1109   Image *fourier_image,ExceptionInfo *exception)
1110 {
1111   double
1112     *magnitude,
1113     *phase;
1114
1115   fftw_complex
1116     *fourier;
1117
1118   FourierInfo
1119     fourier_info;
1120
1121   MagickBooleanType
1122     status;
1123
1124   size_t
1125     extent;
1126
1127   fourier_info.width=magnitude_image->columns;
1128   if ((magnitude_image->columns != magnitude_image->rows) ||
1129       ((magnitude_image->columns % 2) != 0) ||
1130       ((magnitude_image->rows % 2) != 0))
1131     {
1132       extent=magnitude_image->columns < magnitude_image->rows ?
1133         magnitude_image->rows : magnitude_image->columns;
1134       fourier_info.width=(extent & 0x01) == 1 ? extent+1UL : extent;
1135     }
1136   fourier_info.height=fourier_info.width;
1137   fourier_info.center=(ssize_t) floor((double) fourier_info.width/2.0)+1L;
1138   fourier_info.channel=channel;
1139   fourier_info.modulus=modulus;
1140   magnitude=(double *) AcquireQuantumMemory((size_t) fourier_info.height,
1141     fourier_info.center*sizeof(*magnitude));
1142   if (magnitude == (double *) NULL)
1143     {
1144       (void) ThrowMagickException(exception,GetMagickModule(),
1145         ResourceLimitError,"MemoryAllocationFailed","'%s'",
1146         magnitude_image->filename);
1147       return(MagickFalse);
1148     }
1149   phase=(double *) AcquireQuantumMemory((size_t) fourier_info.height,
1150     fourier_info.center*sizeof(*phase));
1151   if (phase == (double *) NULL)
1152     {
1153       (void) ThrowMagickException(exception,GetMagickModule(),
1154         ResourceLimitError,"MemoryAllocationFailed","'%s'",
1155         magnitude_image->filename);
1156       magnitude=(double *) RelinquishMagickMemory(magnitude);
1157       return(MagickFalse);
1158     }
1159   fourier=(fftw_complex *) AcquireQuantumMemory((size_t) fourier_info.height,
1160     fourier_info.center*sizeof(*fourier));
1161   if (fourier == (fftw_complex *) NULL)
1162     {
1163       (void) ThrowMagickException(exception,GetMagickModule(),
1164         ResourceLimitError,"MemoryAllocationFailed","'%s'",
1165         magnitude_image->filename);
1166       phase=(double *) RelinquishMagickMemory(phase);
1167       magnitude=(double *) RelinquishMagickMemory(magnitude);
1168       return(MagickFalse);
1169     }
1170   status=InverseFourier(&fourier_info,magnitude_image,phase_image,fourier,
1171    exception);
1172   if (status != MagickFalse)
1173     status=InverseFourierTransform(&fourier_info,fourier,fourier_image,
1174       exception);
1175   fourier=(fftw_complex *) RelinquishMagickMemory(fourier);
1176   phase=(double *) RelinquishMagickMemory(phase);
1177   magnitude=(double *) RelinquishMagickMemory(magnitude);
1178   return(status);
1179 }
1180 #endif
1181
1182 MagickExport Image *InverseFourierTransformImage(const Image *magnitude_image,
1183   const Image *phase_image,const MagickBooleanType modulus,
1184   ExceptionInfo *exception)
1185 {
1186   Image
1187     *fourier_image;
1188
1189   assert(magnitude_image != (Image *) NULL);
1190   assert(magnitude_image->signature == MagickSignature);
1191   if (magnitude_image->debug != MagickFalse)
1192     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1193       magnitude_image->filename);
1194   if (phase_image == (Image *) NULL)
1195     {
1196       (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
1197         "TwoOrMoreImagesRequired","'%s'",magnitude_image->filename);
1198       return((Image *) NULL);
1199     }
1200 #if !defined(MAGICKCORE_FFTW_DELEGATE)
1201   fourier_image=(Image *) NULL;
1202   (void) modulus;
1203   (void) ThrowMagickException(exception,GetMagickModule(),
1204     MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","'%s' (FFTW)",
1205     magnitude_image->filename);
1206 #else
1207   {
1208     fourier_image=CloneImage(magnitude_image,magnitude_image->columns,
1209       magnitude_image->rows,MagickFalse,exception);
1210     if (fourier_image != (Image *) NULL)
1211       {
1212         MagickBooleanType
1213           is_gray,
1214           status;
1215
1216         status=MagickTrue;
1217         is_gray=IsImageGray(magnitude_image,exception);
1218         if (is_gray != MagickFalse)
1219           is_gray=IsImageGray(phase_image,exception);
1220 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1221         #pragma omp parallel sections
1222 #endif
1223         {
1224 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1225           #pragma omp section
1226 #endif
1227           {
1228             MagickBooleanType
1229               thread_status;
1230
1231             if (is_gray != MagickFalse)
1232               thread_status=InverseFourierTransformChannel(magnitude_image,
1233                 phase_image,GrayPixelChannel,modulus,fourier_image,exception);
1234             else
1235               thread_status=InverseFourierTransformChannel(magnitude_image,
1236                 phase_image,RedPixelChannel,modulus,fourier_image,exception);
1237             if (thread_status == MagickFalse)
1238               status=thread_status;
1239           }
1240 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1241           #pragma omp section
1242 #endif
1243           {
1244             MagickBooleanType
1245               thread_status;
1246
1247             thread_status=MagickTrue;
1248             if (is_gray == MagickFalse)
1249               thread_status=InverseFourierTransformChannel(magnitude_image,
1250                 phase_image,GreenPixelChannel,modulus,fourier_image,exception);
1251             if (thread_status == MagickFalse)
1252               status=thread_status;
1253           }
1254 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1255           #pragma omp section
1256 #endif
1257           {
1258             MagickBooleanType
1259               thread_status;
1260
1261             thread_status=MagickTrue;
1262             if (is_gray == MagickFalse)
1263               thread_status=InverseFourierTransformChannel(magnitude_image,
1264                 phase_image,BluePixelChannel,modulus,fourier_image,exception);
1265             if (thread_status == MagickFalse)
1266               status=thread_status;
1267           }
1268 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1269           #pragma omp section
1270 #endif
1271           {
1272             MagickBooleanType
1273               thread_status;
1274
1275             thread_status=MagickTrue;
1276             if (magnitude_image->colorspace == CMYKColorspace)
1277               thread_status=InverseFourierTransformChannel(magnitude_image,
1278                 phase_image,BlackPixelChannel,modulus,fourier_image,exception);
1279             if (thread_status == MagickFalse)
1280               status=thread_status;
1281           }
1282 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1283           #pragma omp section
1284 #endif
1285           {
1286             MagickBooleanType
1287               thread_status;
1288
1289             thread_status=MagickTrue;
1290             if (magnitude_image->matte != MagickFalse)
1291               thread_status=InverseFourierTransformChannel(magnitude_image,
1292                 phase_image,AlphaPixelChannel,modulus,fourier_image,exception);
1293             if (thread_status == MagickFalse)
1294               status=thread_status;
1295           }
1296         }
1297         if (status == MagickFalse)
1298           fourier_image=DestroyImage(fourier_image);
1299       }
1300     fftw_cleanup();
1301   }
1302 #endif
1303   return(fourier_image);
1304 }