2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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 %
13 % MagickCore Discrete Fourier Transform Methods %
22 % Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
23 % dedicated to making software imaging solutions freely available. %
25 % You may not use this file except in compliance with the License. You may %
26 % obtain a copy of the License at %
28 % http://www.imagemagick.org/script/license.php %
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. %
36 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
45 #include "magick/studio.h"
46 #include "magick/cache.h"
47 #include "magick/image.h"
48 #include "magick/image-private.h"
49 #include "magick/list.h"
50 #include "magick/fourier.h"
51 #include "magick/log.h"
52 #include "magick/memory_.h"
53 #include "magick/monitor.h"
54 #include "magick/property.h"
55 #include "magick/quantum-private.h"
56 #include "magick/thread-private.h"
57 #if defined(MAGICKCORE_FFTW_DELEGATE)
58 #if defined(MAGICKCORE_HAVE_COMPLEX_H)
62 #if !defined(MAGICKCORE_HAVE_CABS)
63 #define cabs(z) (sqrt(z[0]*z[0]+z[1]*z[1]))
65 #if !defined(MAGICKCORE_HAVE_CARG)
66 #define carg(z) (atan2(cimag(z),creal(z)))
68 #if !defined(MAGICKCORE_HAVE_CIMAG)
69 #define cimag(z) (z[1])
71 #if !defined(MAGICKCORE_HAVE_CREAL)
72 #define creal(z) (z[0])
79 typedef struct _FourierInfo
96 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
100 % 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 %
104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
106 % ForwardFourierTransformImage() implements the discrete Fourier transform
107 % (DFT) of the image either as a magnitude / phase or real / imaginary image
110 % The format of the ForwadFourierTransformImage method is:
112 % Image *ForwardFourierTransformImage(const Image *image,
113 % const MagickBooleanType modulus,ExceptionInfo *exception)
115 % A description of each parameter follows:
117 % o image: the image.
119 % o modulus: if true, return as transform as a magnitude / phase pair
120 % otherwise a real / imaginary image pair.
122 % o exception: return any errors or warnings in this structure.
126 #if defined(MAGICKCORE_FFTW_DELEGATE)
128 static MagickBooleanType RollFourier(const size_t width,const size_t height,
129 const ssize_t x_offset,const ssize_t y_offset,double *fourier)
144 Move zero frequency (DC, average color) from (0,0) to (width/2,height/2).
146 roll=(double *) AcquireQuantumMemory((size_t) height,width*sizeof(*roll));
147 if (roll == (double *) NULL)
150 for (y=0L; y < (ssize_t) height; y++)
153 v=((y+y_offset) < 0L) ? y+y_offset+(ssize_t) height : y+y_offset;
155 v=((y+y_offset) > ((ssize_t) height-1L)) ? y+y_offset-(ssize_t) height :
157 for (x=0L; x < (ssize_t) width; x++)
160 u=((x+x_offset) < 0L) ? x+x_offset+(ssize_t) width : x+x_offset;
162 u=((x+x_offset) > ((ssize_t) width-1L)) ? x+x_offset-(ssize_t) width :
164 roll[v*width+u]=fourier[i++];
167 (void) CopyMagickMemory(fourier,roll,height*width*sizeof(*roll));
168 roll=(double *) RelinquishMagickMemory(roll);
172 static MagickBooleanType ForwardQuadrantSwap(const size_t width,
173 const size_t height,double *source,double *destination)
188 center=(ssize_t) floor((double) width/2L)+1L;
189 status=RollFourier((size_t) center,height,0L,(ssize_t) height/2L,source);
190 if (status == MagickFalse)
192 for (y=0L; y < (ssize_t) height; y++)
193 for (x=0L; x < (ssize_t) (width/2L-1L); x++)
194 destination[width*y+x+width/2L]=source[center*y+x];
195 for (y=1; y < (ssize_t) height; y++)
196 for (x=0L; x < (ssize_t) (width/2L-1L); x++)
197 destination[width*(height-y)+width/2L-x-1L]=source[center*y+x+1L];
198 for (x=0L; x < (ssize_t) (width/2L); x++)
199 destination[-x+width/2L-1L]=destination[x+width/2L+1L];
203 static void CorrectPhaseLHS(const size_t width,const size_t height,
212 for (y=0L; y < (ssize_t) height; y++)
213 for (x=0L; x < (ssize_t) (width/2L); x++)
214 fourier[y*width+x]*=(-1.0);
217 static MagickBooleanType ForwardFourier(const FourierInfo *fourier_info,
218 Image *image,double *magnitude,double *phase,ExceptionInfo *exception)
248 magnitude_image=GetFirstImageInList(image);
249 phase_image=GetNextImageInList(image);
250 if (phase_image == (Image *) NULL)
252 (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
253 "ImageSequenceRequired","`%s'",image->filename);
257 Create "Fourier Transform" image from constituent arrays.
259 magnitude_source=(double *) AcquireQuantumMemory((size_t)
260 fourier_info->height,fourier_info->width*sizeof(*magnitude_source));
261 if (magnitude_source == (double *) NULL)
263 (void) ResetMagickMemory(magnitude_source,0,fourier_info->height*
264 fourier_info->width*sizeof(*magnitude_source));
265 phase_source=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
266 fourier_info->width*sizeof(*phase_source));
267 if (phase_source == (double *) NULL)
269 (void) ThrowMagickException(exception,GetMagickModule(),
270 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
271 magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
274 status=ForwardQuadrantSwap(fourier_info->height,fourier_info->height,
275 magnitude,magnitude_source);
276 if (status != MagickFalse)
277 status=ForwardQuadrantSwap(fourier_info->height,fourier_info->height,phase,
279 CorrectPhaseLHS(fourier_info->height,fourier_info->height,phase_source);
280 if (fourier_info->modulus != MagickFalse)
283 for (y=0L; y < (ssize_t) fourier_info->height; y++)
284 for (x=0L; x < (ssize_t) fourier_info->width; x++)
286 phase_source[i]/=(2.0*MagickPI);
287 phase_source[i]+=0.5;
291 magnitude_view=AcquireCacheView(magnitude_image);
292 phase_view=AcquireCacheView(phase_image);
294 for (y=0L; y < (ssize_t) fourier_info->height; y++)
296 q=GetCacheViewAuthenticPixels(magnitude_view,0L,y,fourier_info->height,1UL,
298 if (q == (PixelPacket *) NULL)
300 indexes=GetCacheViewAuthenticIndexQueue(magnitude_view);
301 for (x=0L; x < (ssize_t) fourier_info->width; x++)
303 switch (fourier_info->channel)
308 SetRedPixelComponent(q,ClampToQuantum(QuantumRange*
309 magnitude_source[i]));
314 SetGreenPixelComponent(q,ClampToQuantum(QuantumRange*
315 magnitude_source[i]));
320 SetBluePixelComponent(q,ClampToQuantum(QuantumRange*
321 magnitude_source[i]));
326 SetOpacityPixelComponent(q,ClampToQuantum(QuantumRange*
327 magnitude_source[i]));
332 SetIndexPixelComponent(indexes+x,ClampToQuantum(QuantumRange*
333 magnitude_source[i]));
338 SetGrayPixelComponent(q,ClampToQuantum(QuantumRange*
339 magnitude_source[i]));
346 status=SyncCacheViewAuthenticPixels(magnitude_view,exception);
347 if (status == MagickFalse)
351 for (y=0L; y < (ssize_t) fourier_info->height; y++)
353 q=GetCacheViewAuthenticPixels(phase_view,0L,y,fourier_info->height,1UL,
355 if (q == (PixelPacket *) NULL)
357 indexes=GetCacheViewAuthenticIndexQueue(phase_view);
358 for (x=0L; x < (ssize_t) fourier_info->width; x++)
360 switch (fourier_info->channel)
365 SetRedPixelComponent(q,ClampToQuantum(QuantumRange*
371 SetGreenPixelComponent(q,ClampToQuantum(QuantumRange*
377 SetBluePixelComponent(q,ClampToQuantum(QuantumRange*
383 SetOpacityPixelComponent(q,ClampToQuantum(QuantumRange*
389 SetIndexPixelComponent(indexes+x,ClampToQuantum(QuantumRange*
395 SetGrayPixelComponent(q,ClampToQuantum(QuantumRange*phase_source[i]));
402 status=SyncCacheViewAuthenticPixels(phase_view,exception);
403 if (status == MagickFalse)
406 phase_view=DestroyCacheView(phase_view);
407 magnitude_view=DestroyCacheView(magnitude_view);
408 phase_source=(double *) RelinquishMagickMemory(phase_source);
409 magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
413 static MagickBooleanType ForwardFourierTransform(FourierInfo *fourier_info,
414 const Image *image,double *magnitude,double *phase,ExceptionInfo *exception)
429 register const IndexPacket
432 register const PixelPacket
443 Generate the forward Fourier transform.
445 source=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
446 fourier_info->width*sizeof(*source));
447 if (source == (double *) NULL)
449 (void) ThrowMagickException(exception,GetMagickModule(),
450 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
453 ResetMagickMemory(source,0,fourier_info->height*fourier_info->width*
456 image_view=AcquireCacheView(image);
457 for (y=0L; y < (ssize_t) fourier_info->height; y++)
459 p=GetCacheViewVirtualPixels(image_view,0L,y,fourier_info->width,1UL,
461 if (p == (const PixelPacket *) NULL)
463 indexes=GetCacheViewVirtualIndexQueue(image_view);
464 for (x=0L; x < (ssize_t) fourier_info->width; x++)
466 switch (fourier_info->channel)
471 source[i]=QuantumScale*GetRedPixelComponent(p);
476 source[i]=QuantumScale*GetGreenPixelComponent(p);
481 source[i]=QuantumScale*GetBluePixelComponent(p);
486 source[i]=QuantumScale*GetOpacityPixelComponent(p);
491 source[i]=QuantumScale*GetIndexPixelComponent(indexes+x);
496 source[i]=QuantumScale*GetGrayPixelComponent(p);
504 image_view=DestroyCacheView(image_view);
505 fourier=(fftw_complex *) AcquireQuantumMemory((size_t) fourier_info->height,
506 fourier_info->center*sizeof(*fourier));
507 if (fourier == (fftw_complex *) NULL)
509 (void) ThrowMagickException(exception,GetMagickModule(),
510 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
511 source=(double *) RelinquishMagickMemory(source);
514 #if defined(MAGICKCORE_OPENMP_SUPPORT)
515 #pragma omp critical (MagickCore_ForwardFourierTransform)
517 fftw_r2c_plan=fftw_plan_dft_r2c_2d(fourier_info->width,fourier_info->width,
518 source,fourier,FFTW_ESTIMATE);
519 fftw_execute(fftw_r2c_plan);
520 fftw_destroy_plan(fftw_r2c_plan);
521 source=(double *) RelinquishMagickMemory(source);
523 Normalize Fourier transform.
525 n=(double) fourier_info->width*(double) fourier_info->width;
527 for (y=0L; y < (ssize_t) fourier_info->height; y++)
528 for (x=0L; x < (ssize_t) fourier_info->center; x++)
530 #if defined(MAGICKCORE_HAVE_COMPLEX_H)
539 Generate magnitude and phase (or real and imaginary).
542 if (fourier_info->modulus != MagickFalse)
543 for (y=0L; y < (ssize_t) fourier_info->height; y++)
544 for (x=0L; x < (ssize_t) fourier_info->center; x++)
546 magnitude[i]=cabs(fourier[i]);
547 phase[i]=carg(fourier[i]);
551 for (y=0L; y < (ssize_t) fourier_info->height; y++)
552 for (x=0L; x < (ssize_t) fourier_info->center; x++)
554 magnitude[i]=creal(fourier[i]);
555 phase[i]=cimag(fourier[i]);
558 fourier=(fftw_complex *) RelinquishMagickMemory(fourier);
562 static MagickBooleanType ForwardFourierTransformChannel(const Image *image,
563 const ChannelType channel,const MagickBooleanType modulus,
564 Image *fourier_image,ExceptionInfo *exception)
582 fourier_info.width=image->columns;
583 if ((image->columns != image->rows) || ((image->columns % 2) != 0) ||
584 ((image->rows % 2) != 0))
586 extent=image->columns < image->rows ? image->rows : image->columns;
587 fourier_info.width=(extent & 0x01) == 1 ? extent+1UL : extent;
589 fourier_info.height=fourier_info.width;
590 fourier_info.center=(ssize_t) floor((double) fourier_info.width/2.0)+1L;
591 fourier_info.channel=channel;
592 fourier_info.modulus=modulus;
593 magnitude=(double *) AcquireQuantumMemory((size_t) fourier_info.height,
594 fourier_info.center*sizeof(*magnitude));
595 if (magnitude == (double *) NULL)
597 (void) ThrowMagickException(exception,GetMagickModule(),
598 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
601 phase=(double *) AcquireQuantumMemory((size_t) fourier_info.height,
602 fourier_info.center*sizeof(*phase));
603 if (phase == (double *) NULL)
605 (void) ThrowMagickException(exception,GetMagickModule(),
606 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
607 magnitude=(double *) RelinquishMagickMemory(magnitude);
610 fourier=(fftw_complex *) AcquireQuantumMemory((size_t) fourier_info.height,
611 fourier_info.center*sizeof(*fourier));
612 if (fourier == (fftw_complex *) NULL)
614 (void) ThrowMagickException(exception,GetMagickModule(),
615 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
616 phase=(double *) RelinquishMagickMemory(phase);
617 magnitude=(double *) RelinquishMagickMemory(magnitude);
620 status=ForwardFourierTransform(&fourier_info,image,magnitude,phase,exception);
621 if (status != MagickFalse)
622 status=ForwardFourier(&fourier_info,fourier_image,magnitude,phase,
624 fourier=(fftw_complex *) RelinquishMagickMemory(fourier);
625 phase=(double *) RelinquishMagickMemory(phase);
626 magnitude=(double *) RelinquishMagickMemory(magnitude);
631 MagickExport Image *ForwardFourierTransformImage(const Image *image,
632 const MagickBooleanType modulus,ExceptionInfo *exception)
637 fourier_image=NewImageList();
638 #if !defined(MAGICKCORE_FFTW_DELEGATE)
640 (void) ThrowMagickException(exception,GetMagickModule(),
641 MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","`%s' (FFTW)",
652 width=image->columns;
653 if ((image->columns != image->rows) || ((image->columns % 2) != 0) ||
654 ((image->rows % 2) != 0))
656 extent=image->columns < image->rows ? image->rows : image->columns;
657 width=(extent & 0x01) == 1 ? extent+1UL : extent;
659 magnitude_image=CloneImage(image,width,width,MagickFalse,exception);
660 if (magnitude_image != (Image *) NULL)
665 magnitude_image->storage_class=DirectClass;
666 magnitude_image->depth=32UL;
667 phase_image=CloneImage(image,width,width,MagickFalse,exception);
668 if (phase_image == (Image *) NULL)
669 magnitude_image=DestroyImage(magnitude_image);
676 phase_image->storage_class=DirectClass;
677 phase_image->depth=32UL;
678 AppendImageToList(&fourier_image,magnitude_image);
679 AppendImageToList(&fourier_image,phase_image);
681 is_gray=IsGrayImage(image,exception);
682 #if defined(MAGICKCORE_OPENMP_SUPPORT)
683 #pragma omp parallel sections
686 #if defined(MAGICKCORE_OPENMP_SUPPORT)
693 if (is_gray != MagickFalse)
694 thread_status=ForwardFourierTransformChannel(image,
695 GrayChannels,modulus,fourier_image,exception);
697 thread_status=ForwardFourierTransformChannel(image,
698 RedChannel,modulus,fourier_image,exception);
699 if (thread_status == MagickFalse)
700 status=thread_status;
702 #if defined(MAGICKCORE_OPENMP_SUPPORT)
709 thread_status=MagickTrue;
710 if (is_gray == MagickFalse)
711 thread_status=ForwardFourierTransformChannel(image,
712 GreenChannel,modulus,fourier_image,exception);
713 if (thread_status == MagickFalse)
714 status=thread_status;
716 #if defined(MAGICKCORE_OPENMP_SUPPORT)
723 thread_status=MagickTrue;
724 if (is_gray == MagickFalse)
725 thread_status=ForwardFourierTransformChannel(image,
726 BlueChannel,modulus,fourier_image,exception);
727 if (thread_status == MagickFalse)
728 status=thread_status;
730 #if defined(MAGICKCORE_OPENMP_SUPPORT)
737 thread_status=MagickTrue;
738 if (image->matte != MagickFalse)
739 thread_status=ForwardFourierTransformChannel(image,
740 OpacityChannel,modulus,fourier_image,exception);
741 if (thread_status == MagickFalse)
742 status=thread_status;
744 #if defined(MAGICKCORE_OPENMP_SUPPORT)
751 thread_status=MagickTrue;
752 if (image->colorspace == CMYKColorspace)
753 thread_status=ForwardFourierTransformChannel(image,
754 IndexChannel,modulus,fourier_image,exception);
755 if (thread_status == MagickFalse)
756 status=thread_status;
759 if (status == MagickFalse)
760 fourier_image=DestroyImageList(fourier_image);
766 return(fourier_image);
770 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
774 % 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 %
778 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
780 % InverseFourierTransformImage() implements the inverse discrete Fourier
781 % transform (DFT) of the image either as a magnitude / phase or real /
782 % imaginary image pair.
784 % The format of the InverseFourierTransformImage method is:
786 % Image *InverseFourierTransformImage(const Image *magnitude_image,
787 % const Image *phase_image,const MagickBooleanType modulus,
788 % ExceptionInfo *exception)
790 % A description of each parameter follows:
792 % o magnitude_image: the magnitude or real image.
794 % o phase_image: the phase or imaginary image.
796 % o modulus: if true, return transform as a magnitude / phase pair
797 % otherwise a real / imaginary image pair.
799 % o exception: return any errors or warnings in this structure.
803 #if defined(MAGICKCORE_FFTW_DELEGATE)
804 static MagickBooleanType InverseQuadrantSwap(const size_t width,
805 const size_t height,const double *source,double *destination)
817 center=(ssize_t) floor((double) width/2.0)+1L;
818 for (y=1L; y < (ssize_t) height; y++)
819 for (x=0L; x < (ssize_t) (width/2L+1L); x++)
820 destination[center*(height-y)-x+width/2L]=source[y*width+x];
821 for (y=0L; y < (ssize_t) height; y++)
822 destination[center*y]=source[y*width+width/2L];
823 for (x=0L; x < center; x++)
824 destination[x]=source[center-x-1L];
825 return(RollFourier(center,height,0L,(ssize_t) height/-2L,destination));
828 static MagickBooleanType InverseFourier(FourierInfo *fourier_info,
829 const Image *magnitude_image,const Image *phase_image,fftw_complex *fourier,
830 ExceptionInfo *exception)
845 register const IndexPacket
848 register const PixelPacket
859 Inverse fourier - read image and break down into a double array.
861 magnitude_source=(double *) AcquireQuantumMemory((size_t)
862 fourier_info->height,fourier_info->width*sizeof(*magnitude_source));
863 if (magnitude_source == (double *) NULL)
865 (void) ThrowMagickException(exception,GetMagickModule(),
866 ResourceLimitError,"MemoryAllocationFailed","`%s'",
867 magnitude_image->filename);
870 phase_source=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
871 fourier_info->width*sizeof(*phase_source));
872 if (phase_source == (double *) NULL)
874 (void) ThrowMagickException(exception,GetMagickModule(),
875 ResourceLimitError,"MemoryAllocationFailed","`%s'",
876 magnitude_image->filename);
877 magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
881 magnitude_view=AcquireCacheView(magnitude_image);
882 for (y=0L; y < (ssize_t) fourier_info->height; y++)
884 p=GetCacheViewVirtualPixels(magnitude_view,0L,y,fourier_info->width,1UL,
886 if (p == (const PixelPacket *) NULL)
888 indexes=GetCacheViewAuthenticIndexQueue(magnitude_view);
889 for (x=0L; x < (ssize_t) fourier_info->width; x++)
891 switch (fourier_info->channel)
896 magnitude_source[i]=QuantumScale*GetRedPixelComponent(p);
901 magnitude_source[i]=QuantumScale*GetGreenPixelComponent(p);
906 magnitude_source[i]=QuantumScale*GetBluePixelComponent(p);
911 magnitude_source[i]=QuantumScale*GetOpacityPixelComponent(p);
916 magnitude_source[i]=QuantumScale*GetIndexPixelComponent(indexes+x);
921 magnitude_source[i]=QuantumScale*GetGrayPixelComponent(p);
930 phase_view=AcquireCacheView(phase_image);
931 for (y=0L; y < (ssize_t) fourier_info->height; y++)
933 p=GetCacheViewVirtualPixels(phase_view,0,y,fourier_info->width,1,
935 if (p == (const PixelPacket *) NULL)
937 indexes=GetCacheViewAuthenticIndexQueue(phase_view);
938 for (x=0L; x < (ssize_t) fourier_info->width; x++)
940 switch (fourier_info->channel)
945 phase_source[i]=QuantumScale*GetRedPixelComponent(p);
950 phase_source[i]=QuantumScale*GetGreenPixelComponent(p);
955 phase_source[i]=QuantumScale*GetBluePixelComponent(p);
960 phase_source[i]=QuantumScale*GetOpacityPixelComponent(p);
965 phase_source[i]=QuantumScale*GetIndexPixelComponent(indexes+x);
970 phase_source[i]=QuantumScale*GetGrayPixelComponent(p);
978 if (fourier_info->modulus != MagickFalse)
981 for (y=0L; y < (ssize_t) fourier_info->height; y++)
982 for (x=0L; x < (ssize_t) fourier_info->width; x++)
984 phase_source[i]-=0.5;
985 phase_source[i]*=(2.0*MagickPI);
989 magnitude_view=DestroyCacheView(magnitude_view);
990 phase_view=DestroyCacheView(phase_view);
991 magnitude=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
992 fourier_info->center*sizeof(*magnitude));
993 if (magnitude == (double *) NULL)
995 (void) ThrowMagickException(exception,GetMagickModule(),
996 ResourceLimitError,"MemoryAllocationFailed","`%s'",
997 magnitude_image->filename);
998 magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
999 phase_source=(double *) RelinquishMagickMemory(phase_source);
1000 return(MagickFalse);
1002 status=InverseQuadrantSwap(fourier_info->width,fourier_info->height,
1003 magnitude_source,magnitude);
1004 magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
1005 phase=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
1006 fourier_info->width*sizeof(*phase));
1007 if (phase == (double *) NULL)
1009 (void) ThrowMagickException(exception,GetMagickModule(),
1010 ResourceLimitError,"MemoryAllocationFailed","`%s'",
1011 magnitude_image->filename);
1012 phase_source=(double *) RelinquishMagickMemory(phase_source);
1013 return(MagickFalse);
1015 CorrectPhaseLHS(fourier_info->width,fourier_info->width,phase_source);
1016 if (status != MagickFalse)
1017 status=InverseQuadrantSwap(fourier_info->width,fourier_info->height,
1018 phase_source,phase);
1019 phase_source=(double *) RelinquishMagickMemory(phase_source);
1024 if (fourier_info->modulus != MagickFalse)
1025 for (y=0L; y < (ssize_t) fourier_info->height; y++)
1026 for (x=0L; x < (ssize_t) fourier_info->center; x++)
1028 #if defined(MAGICKCORE_HAVE_COMPLEX_H)
1029 fourier[i]=magnitude[i]*cos(phase[i])+I*magnitude[i]*sin(phase[i]);
1031 fourier[i][0]=magnitude[i]*cos(phase[i]);
1032 fourier[i][1]=magnitude[i]*sin(phase[i]);
1037 for (y=0L; y < (ssize_t) fourier_info->height; y++)
1038 for (x=0L; x < (ssize_t) fourier_info->center; x++)
1040 #if defined(MAGICKCORE_HAVE_COMPLEX_H)
1041 fourier[i]=magnitude[i]+I*phase[i];
1043 fourier[i][0]=magnitude[i];
1044 fourier[i][1]=phase[i];
1048 phase=(double *) RelinquishMagickMemory(phase);
1049 magnitude=(double *) RelinquishMagickMemory(magnitude);
1053 static MagickBooleanType InverseFourierTransform(FourierInfo *fourier_info,
1054 fftw_complex *fourier,Image *image,ExceptionInfo *exception)
1065 register IndexPacket
1068 register PixelPacket
1078 source=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
1079 fourier_info->width*sizeof(*source));
1080 if (source == (double *) NULL)
1082 (void) ThrowMagickException(exception,GetMagickModule(),
1083 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
1084 return(MagickFalse);
1086 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1087 #pragma omp critical (MagickCore_InverseFourierTransform)
1090 fftw_c2r_plan=fftw_plan_dft_c2r_2d(fourier_info->width,fourier_info->height,
1091 fourier,source,FFTW_ESTIMATE);
1092 fftw_execute(fftw_c2r_plan);
1093 fftw_destroy_plan(fftw_c2r_plan);
1096 image_view=AcquireCacheView(image);
1097 for (y=0L; y < (ssize_t) fourier_info->height; y++)
1099 if (y >= (ssize_t) image->rows)
1101 q=GetCacheViewAuthenticPixels(image_view,0L,y,fourier_info->width >
1102 image->columns ? image->columns : fourier_info->width,1UL,exception);
1103 if (q == (PixelPacket *) NULL)
1105 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1106 for (x=0L; x < (ssize_t) fourier_info->width; x++)
1108 switch (fourier_info->channel)
1113 SetRedPixelComponent(q,ClampToQuantum(QuantumRange*source[i]));
1118 SetGreenPixelComponent(q,ClampToQuantum(QuantumRange*source[i]));
1123 SetBluePixelComponent(q,ClampToQuantum(QuantumRange*source[i]));
1126 case OpacityChannel:
1128 SetOpacityPixelComponent(q,ClampToQuantum(QuantumRange*source[i]));
1133 SetIndexPixelComponent(indexes+x,ClampToQuantum(QuantumRange*
1139 SetGrayPixelComponent(q,ClampToQuantum(QuantumRange*source[i]));
1146 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1149 image_view=DestroyCacheView(image_view);
1150 source=(double *) RelinquishMagickMemory(source);
1154 static MagickBooleanType InverseFourierTransformChannel(
1155 const Image *magnitude_image,const Image *phase_image,
1156 const ChannelType channel,const MagickBooleanType modulus,
1157 Image *fourier_image,ExceptionInfo *exception)
1175 fourier_info.width=magnitude_image->columns;
1176 if ((magnitude_image->columns != magnitude_image->rows) ||
1177 ((magnitude_image->columns % 2) != 0) ||
1178 ((magnitude_image->rows % 2) != 0))
1180 extent=magnitude_image->columns < magnitude_image->rows ?
1181 magnitude_image->rows : magnitude_image->columns;
1182 fourier_info.width=(extent & 0x01) == 1 ? extent+1UL : extent;
1184 fourier_info.height=fourier_info.width;
1185 fourier_info.center=(ssize_t) floor((double) fourier_info.width/2.0)+1L;
1186 fourier_info.channel=channel;
1187 fourier_info.modulus=modulus;
1188 magnitude=(double *) AcquireQuantumMemory((size_t) fourier_info.height,
1189 fourier_info.center*sizeof(*magnitude));
1190 if (magnitude == (double *) NULL)
1192 (void) ThrowMagickException(exception,GetMagickModule(),
1193 ResourceLimitError,"MemoryAllocationFailed","`%s'",
1194 magnitude_image->filename);
1195 return(MagickFalse);
1197 phase=(double *) AcquireQuantumMemory((size_t) fourier_info.height,
1198 fourier_info.center*sizeof(*phase));
1199 if (phase == (double *) NULL)
1201 (void) ThrowMagickException(exception,GetMagickModule(),
1202 ResourceLimitError,"MemoryAllocationFailed","`%s'",
1203 magnitude_image->filename);
1204 magnitude=(double *) RelinquishMagickMemory(magnitude);
1205 return(MagickFalse);
1207 fourier=(fftw_complex *) AcquireQuantumMemory((size_t) fourier_info.height,
1208 fourier_info.center*sizeof(*fourier));
1209 if (fourier == (fftw_complex *) NULL)
1211 (void) ThrowMagickException(exception,GetMagickModule(),
1212 ResourceLimitError,"MemoryAllocationFailed","`%s'",
1213 magnitude_image->filename);
1214 phase=(double *) RelinquishMagickMemory(phase);
1215 magnitude=(double *) RelinquishMagickMemory(magnitude);
1216 return(MagickFalse);
1218 status=InverseFourier(&fourier_info,magnitude_image,phase_image,fourier,
1220 if (status != MagickFalse)
1221 status=InverseFourierTransform(&fourier_info,fourier,fourier_image,
1223 fourier=(fftw_complex *) RelinquishMagickMemory(fourier);
1224 phase=(double *) RelinquishMagickMemory(phase);
1225 magnitude=(double *) RelinquishMagickMemory(magnitude);
1230 MagickExport Image *InverseFourierTransformImage(const Image *magnitude_image,
1231 const Image *phase_image,const MagickBooleanType modulus,
1232 ExceptionInfo *exception)
1237 assert(magnitude_image != (Image *) NULL);
1238 assert(magnitude_image->signature == MagickSignature);
1239 if (magnitude_image->debug != MagickFalse)
1240 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1241 magnitude_image->filename);
1242 if (phase_image == (Image *) NULL)
1244 (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
1245 "ImageSequenceRequired","`%s'",magnitude_image->filename);
1246 return((Image *) NULL);
1248 #if !defined(MAGICKCORE_FFTW_DELEGATE)
1249 fourier_image=(Image *) NULL;
1251 (void) ThrowMagickException(exception,GetMagickModule(),
1252 MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","`%s' (FFTW)",
1253 magnitude_image->filename);
1256 fourier_image=CloneImage(magnitude_image,magnitude_image->columns,
1257 magnitude_image->rows,MagickFalse,exception);
1258 if (fourier_image != (Image *) NULL)
1265 is_gray=IsGrayImage(magnitude_image,exception);
1266 if (is_gray != MagickFalse)
1267 is_gray=IsGrayImage(phase_image,exception);
1268 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1269 #pragma omp parallel sections
1272 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1279 if (is_gray != MagickFalse)
1280 thread_status=InverseFourierTransformChannel(magnitude_image,
1281 phase_image,GrayChannels,modulus,fourier_image,exception);
1283 thread_status=InverseFourierTransformChannel(magnitude_image,
1284 phase_image,RedChannel,modulus,fourier_image,exception);
1285 if (thread_status == MagickFalse)
1286 status=thread_status;
1288 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1295 thread_status=MagickTrue;
1296 if (is_gray == MagickFalse)
1297 thread_status=InverseFourierTransformChannel(magnitude_image,
1298 phase_image,GreenChannel,modulus,fourier_image,exception);
1299 if (thread_status == MagickFalse)
1300 status=thread_status;
1302 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1309 thread_status=MagickTrue;
1310 if (is_gray == MagickFalse)
1311 thread_status=InverseFourierTransformChannel(magnitude_image,
1312 phase_image,BlueChannel,modulus,fourier_image,exception);
1313 if (thread_status == MagickFalse)
1314 status=thread_status;
1316 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1323 thread_status=MagickTrue;
1324 if (magnitude_image->matte != MagickFalse)
1325 thread_status=InverseFourierTransformChannel(magnitude_image,
1326 phase_image,OpacityChannel,modulus,fourier_image,exception);
1327 if (thread_status == MagickFalse)
1328 status=thread_status;
1330 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1337 thread_status=MagickTrue;
1338 if (magnitude_image->colorspace == CMYKColorspace)
1339 thread_status=InverseFourierTransformChannel(magnitude_image,
1340 phase_image,IndexChannel,modulus,fourier_image,exception);
1341 if (thread_status == MagickFalse)
1342 status=thread_status;
1345 if (status == MagickFalse)
1346 fourier_image=DestroyImage(fourier_image);
1351 return(fourier_image);