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-2010 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/thread-private.h"
56 #if defined(MAGICKCORE_FFTW_DELEGATE)
57 #if defined(MAGICKCORE_HAVE_COMPLEX_H)
60 #define cabs(z) (sqrt(z[0]*z[0]+z[1]*z[1]))
61 #define carg(z) (atan2(z[1],z[0]))
62 #define creal(z) (z[0])
63 #define cimag(z) (z[1])
71 typedef struct _FourierInfo
88 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
92 % 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 %
96 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
98 % ForwardFourierTransformImage() implements the discrete Fourier transform
99 % (DFT) of the image either as a magnitude / phase or real / imaginary image
102 % The format of the ForwadFourierTransformImage method is:
104 % Image *ForwardFourierTransformImage(const Image *image,
105 % const MagickBooleanType modulus,ExceptionInfo *exception)
107 % A description of each parameter follows:
109 % o image: the image.
111 % o modulus: if true, return as transform as a magnitude / phase pair
112 % otherwise a real / imaginary image pair.
114 % o exception: return any errors or warnings in this structure.
118 #if defined(MAGICKCORE_FFTW_DELEGATE)
120 static MagickBooleanType RollFourier(const unsigned long width,
121 const unsigned long height,const long x_offset,const long y_offset,
137 Move the zero frequency (DC) from (0,0) to (width/2,height/2).
139 roll=(double *) AcquireQuantumMemory((size_t) width,height*sizeof(*roll));
140 if (roll == (double *) NULL)
143 for (y=0L; y < (long) height; y++)
146 v=((y+y_offset) < 0L) ? y+y_offset+(long) height : y+y_offset;
148 v=((y+y_offset) > ((long) height-1L)) ? y+y_offset-(long) height :
150 for (x=0L; x < (long) width; x++)
153 u=((x+x_offset) < 0L) ? x+x_offset+(long) width : x+x_offset;
155 u=((x+x_offset) > ((long) width-1L)) ? x+x_offset-(long) width :
157 roll[v*width+u]=fourier[i++];
160 (void) CopyMagickMemory(fourier,roll,width*height*sizeof(*roll));
161 roll=(double *) RelinquishMagickMemory(roll);
165 static MagickBooleanType ForwardQuadrantSwap(const unsigned long width,
166 const unsigned long height,double *source,double *destination)
181 center=(long) floor((double) width/2L)+1L;
182 status=RollFourier((unsigned long) center,height,0L,(long) height/2L,source);
183 if (status == MagickFalse)
185 for (y=0L; y < (long) height; y++)
186 for (x=0L; x < (long) (width/2L-1L); x++)
187 destination[width*y+x+width/2L]=source[center*y+x];
188 for (y=1; y < (long) height; y++)
189 for (x=0L; x < (long) (width/2L-1L); x++)
190 destination[width*(height-y)+width/2L-x-1L]=source[center*y+x+1L];
191 for (x=0L; x < (long) (width/2L); x++)
192 destination[-x+width/2L-1L]=destination[x+width/2L+1L];
196 static void CorrectPhaseLHS(const unsigned long width,
197 const unsigned long height,double *fourier)
205 for (y=0L; y < (long) height; y++)
206 for (x=0L; x < (long) (width/2L); x++)
207 fourier[y*width+x]*=(-1.0);
210 static MagickBooleanType ForwardFourier(const FourierInfo *fourier_info,
211 Image *image,double *magnitude,double *phase,ExceptionInfo *exception)
241 magnitude_image=GetFirstImageInList(image);
242 phase_image=GetNextImageInList(image);
243 if (phase_image == (Image *) NULL)
245 (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
246 "ImageSequenceRequired","`%s'",image->filename);
250 Create "Fourier Transform" image from constituent arrays.
252 magnitude_source=(double *) AcquireQuantumMemory((size_t)
253 fourier_info->height,fourier_info->width*sizeof(*magnitude_source));
254 if (magnitude_source == (double *) NULL)
256 (void) ResetMagickMemory(magnitude_source,0,fourier_info->width*
257 fourier_info->height*sizeof(*magnitude_source));
258 phase_source=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
259 fourier_info->width*sizeof(*phase_source));
260 if (magnitude_source == (double *) NULL)
262 (void) ThrowMagickException(exception,GetMagickModule(),
263 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
264 magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
267 status=ForwardQuadrantSwap(fourier_info->height,fourier_info->height,
268 magnitude,magnitude_source);
269 if (status != MagickFalse)
270 status=ForwardQuadrantSwap(fourier_info->height,fourier_info->height,phase,
272 CorrectPhaseLHS(fourier_info->height,fourier_info->height,phase_source);
273 if (fourier_info->modulus != MagickFalse)
276 for (y=0L; y < (long) fourier_info->height; y++)
277 for (x=0L; x < (long) fourier_info->width; x++)
279 phase_source[i]/=(2.0*MagickPI);
280 phase_source[i]+=0.5;
284 magnitude_view=AcquireCacheView(magnitude_image);
285 phase_view=AcquireCacheView(phase_image);
287 for (y=0L; y < (long) fourier_info->height; y++)
289 q=GetCacheViewAuthenticPixels(magnitude_view,0L,y,fourier_info->height,1UL,
291 if (q == (PixelPacket *) NULL)
293 indexes=GetCacheViewAuthenticIndexQueue(magnitude_view);
294 for (x=0L; x < (long) fourier_info->width; x++)
296 switch (fourier_info->channel)
301 q->red=ClampToQuantum(QuantumRange*magnitude_source[i]);
306 q->green=ClampToQuantum(QuantumRange*magnitude_source[i]);
311 q->blue=ClampToQuantum(QuantumRange*magnitude_source[i]);
316 q->opacity=ClampToQuantum(QuantumRange*magnitude_source[i]);
321 indexes[x]=ClampToQuantum(QuantumRange*magnitude_source[i]);
326 q->red=ClampToQuantum(QuantumRange*magnitude_source[i]);
335 status=SyncCacheViewAuthenticPixels(magnitude_view,exception);
336 if (status == MagickFalse)
340 for (y=0L; y < (long) fourier_info->height; y++)
342 q=GetCacheViewAuthenticPixels(phase_view,0L,y,fourier_info->height,1UL,
344 if (q == (PixelPacket *) NULL)
346 indexes=GetCacheViewAuthenticIndexQueue(phase_view);
347 for (x=0L; x < (long) fourier_info->width; x++)
349 switch (fourier_info->channel)
354 q->red=ClampToQuantum(QuantumRange*phase_source[i]);
359 q->green=ClampToQuantum(QuantumRange*phase_source[i]);
364 q->blue=ClampToQuantum(QuantumRange*phase_source[i]);
369 q->opacity=ClampToQuantum(QuantumRange*phase_source[i]);
374 indexes[x]=ClampToQuantum(QuantumRange*phase_source[i]);
379 q->red=ClampToQuantum(QuantumRange*phase_source[i]);
388 status=SyncCacheViewAuthenticPixels(phase_view,exception);
389 if (status == MagickFalse)
392 phase_view=DestroyCacheView(phase_view);
393 magnitude_view=DestroyCacheView(magnitude_view);
394 phase_source=(double *) RelinquishMagickMemory(phase_source);
395 magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
399 static MagickBooleanType ForwardFourierTransform(FourierInfo *fourier_info,
400 const Image *image,double *magnitude,double *phase,ExceptionInfo *exception)
418 register const IndexPacket
421 register const PixelPacket
429 Generate the forward Fourier transform.
431 source=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
432 fourier_info->width*sizeof(*source));
433 if (source == (double *) NULL)
435 (void) ThrowMagickException(exception,GetMagickModule(),
436 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
439 ResetMagickMemory(source,0,fourier_info->width*fourier_info->height*
442 image_view=AcquireCacheView(image);
443 for (y=0L; y < (long) fourier_info->height; y++)
445 p=GetCacheViewVirtualPixels(image_view,0L,y,fourier_info->width,1UL,
447 if (p == (const PixelPacket *) NULL)
449 indexes=GetCacheViewVirtualIndexQueue(image_view);
450 for (x=0L; x < (long) fourier_info->width; x++)
452 switch (fourier_info->channel)
457 source[i]=QuantumScale*GetRedPixelComponent(p);
462 source[i]=QuantumScale*GetGreenPixelComponent(p);
467 source[i]=QuantumScale*GetBluePixelComponent(p);
472 source[i]=QuantumScale*GetOpacityPixelComponent(p);
477 source[i]=QuantumScale*indexes[x];
482 source[i]=QuantumScale*GetRedPixelComponent(p);
490 image_view=DestroyCacheView(image_view);
491 fourier=(fftw_complex *) AcquireAlignedMemory((size_t) fourier_info->height,
492 fourier_info->center*sizeof(*fourier));
493 if (fourier == (fftw_complex *) NULL)
495 (void) ThrowMagickException(exception,GetMagickModule(),
496 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
497 source=(double *) RelinquishMagickMemory(source);
500 #if defined(MAGICKCORE_OPENMP_SUPPORT)
501 #pragma omp critical (MagickCore_ForwardFourierTransform)
503 fftw_r2c_plan=fftw_plan_dft_r2c_2d(fourier_info->width,fourier_info->width,
504 source,fourier,FFTW_ESTIMATE);
505 fftw_execute(fftw_r2c_plan);
506 fftw_destroy_plan(fftw_r2c_plan);
507 source=(double *) RelinquishMagickMemory(source);
509 Normalize Fourier transform.
511 n=(double) fourier_info->width*(double) fourier_info->width;
513 for (y=0L; y < (long) fourier_info->height; y++)
514 for (x=0L; x < (long) fourier_info->center; x++)
516 #if defined(MAGICKCORE_HAVE_COMPLEX_H)
525 Generate magnitude and phase (or real and imaginary).
528 if (fourier_info->modulus != MagickFalse)
529 for (y=0L; y < (long) fourier_info->height; y++)
530 for (x=0L; x < (long) fourier_info->center; x++)
532 magnitude[i]=cabs(fourier[i]);
533 phase[i]=carg(fourier[i]);
537 for (y=0L; y < (long) fourier_info->height; y++)
538 for (x=0L; x < (long) fourier_info->center; x++)
540 magnitude[i]=creal(fourier[i]);
541 phase[i]=cimag(fourier[i]);
544 fourier=(fftw_complex *) RelinquishAlignedMemory(fourier);
548 static MagickBooleanType ForwardFourierTransformChannel(const Image *image,
549 const ChannelType channel,const MagickBooleanType modulus,
550 Image *fourier_image,ExceptionInfo *exception)
568 fourier_info.width=image->columns;
569 if ((image->columns != image->rows) || ((image->columns % 2) != 0) ||
570 ((image->rows % 2) != 0))
572 extent=image->columns < image->rows ? image->rows : image->columns;
573 fourier_info.width=(extent & 0x01) == 1 ? extent+1UL : extent;
575 fourier_info.height=fourier_info.width;
576 fourier_info.center=(long) floor((double) fourier_info.width/2.0)+1L;
577 fourier_info.channel=channel;
578 fourier_info.modulus=modulus;
579 magnitude=(double *) AcquireQuantumMemory((size_t) fourier_info.height,
580 fourier_info.center*sizeof(*magnitude));
581 if (magnitude == (double *) NULL)
583 (void) ThrowMagickException(exception,GetMagickModule(),
584 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
587 phase=(double *) AcquireQuantumMemory((size_t) fourier_info.height,
588 fourier_info.center*sizeof(*phase));
589 if (phase == (double *) NULL)
591 (void) ThrowMagickException(exception,GetMagickModule(),
592 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
593 magnitude=(double *) RelinquishMagickMemory(magnitude);
596 fourier=(fftw_complex *) AcquireAlignedMemory((size_t) fourier_info.height,
597 fourier_info.center*sizeof(*fourier));
598 if (fourier == (fftw_complex *) NULL)
600 (void) ThrowMagickException(exception,GetMagickModule(),
601 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
602 phase=(double *) RelinquishMagickMemory(phase);
603 magnitude=(double *) RelinquishMagickMemory(magnitude);
606 status=ForwardFourierTransform(&fourier_info,image,magnitude,phase,exception);
607 if (status != MagickFalse)
608 status=ForwardFourier(&fourier_info,fourier_image,magnitude,phase,
610 fourier=(fftw_complex *) RelinquishAlignedMemory(fourier);
611 phase=(double *) RelinquishMagickMemory(phase);
612 magnitude=(double *) RelinquishMagickMemory(magnitude);
617 MagickExport Image *ForwardFourierTransformImage(const Image *image,
618 const MagickBooleanType modulus,ExceptionInfo *exception)
623 fourier_image=NewImageList();
624 #if !defined(MAGICKCORE_FFTW_DELEGATE)
626 (void) ThrowMagickException(exception,GetMagickModule(),
627 MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","`%s' (FFTW)",
638 width=image->columns;
639 if ((image->columns != image->rows) || ((image->columns % 2) != 0) ||
640 ((image->rows % 2) != 0))
642 extent=image->columns < image->rows ? image->rows : image->columns;
643 width=(extent & 0x01) == 1 ? extent+1UL : extent;
645 magnitude_image=CloneImage(image,width,width,MagickFalse,exception);
646 if (magnitude_image != (Image *) NULL)
651 magnitude_image->storage_class=DirectClass;
652 magnitude_image->depth=32UL;
653 phase_image=CloneImage(image,width,width,MagickFalse,exception);
654 if (phase_image == (Image *) NULL)
655 magnitude_image=DestroyImage(magnitude_image);
665 phase_image->storage_class=DirectClass;
666 phase_image->depth=32UL;
667 AppendImageToList(&fourier_image,magnitude_image);
668 AppendImageToList(&fourier_image,phase_image);
670 is_gray=IsGrayImage(image,exception);
671 #if defined(MAGICKCORE_OPENMP_SUPPORT)
672 #pragma omp parallel for schedule(dynamic,4) shared(status)
674 for (i=0L; i < 5L; i++)
679 thread_status=MagickTrue;
684 if (is_gray != MagickFalse)
686 thread_status=ForwardFourierTransformChannel(image,
687 GrayChannels,modulus,fourier_image,exception);
690 thread_status=ForwardFourierTransformChannel(image,RedChannel,
691 modulus,fourier_image,exception);
696 if (is_gray == MagickFalse)
697 thread_status=ForwardFourierTransformChannel(image,
698 GreenChannel,modulus,fourier_image,exception);
703 if (is_gray == MagickFalse)
704 thread_status=ForwardFourierTransformChannel(image,
705 BlueChannel,modulus,fourier_image,exception);
710 if (image->matte != MagickFalse)
711 thread_status=ForwardFourierTransformChannel(image,
712 OpacityChannel,modulus,fourier_image,exception);
717 if (image->colorspace == CMYKColorspace)
718 thread_status=ForwardFourierTransformChannel(image,
719 IndexChannel,modulus,fourier_image,exception);
723 if (thread_status == MagickFalse)
724 status=thread_status;
726 if (status == MagickFalse)
727 fourier_image=DestroyImageList(fourier_image);
733 return(fourier_image);
737 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
741 % 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 %
745 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
747 % InverseFourierTransformImage() implements the inverse discrete Fourier
748 % transform (DFT) of the image either as a magnitude / phase or real /
749 % imaginary image pair.
751 % The format of the InverseFourierTransformImage method is:
753 % Image *InverseFourierTransformImage(const Image *magnitude_image,
754 % const Image *phase_image,const MagickBooleanType modulus,
755 % ExceptionInfo *exception)
757 % A description of each parameter follows:
759 % o magnitude_image: the magnitude or real image.
761 % o phase_image: the phase or imaginary image.
763 % o modulus: if true, return transform as a magnitude / phase pair
764 % otherwise a real / imaginary image pair.
766 % o exception: return any errors or warnings in this structure.
770 #if defined(MAGICKCORE_FFTW_DELEGATE)
771 static MagickBooleanType InverseQuadrantSwap(const unsigned long width,
772 const unsigned long height,const double *source,double *destination)
784 center=(long) floor((double) width/2.0)+1L;
785 for (y=1L; y < (long) height; y++)
786 for (x=0L; x < (long) (width/2L+1L); x++)
787 destination[center*(height-y)-x+width/2L]=source[y*width+x];
788 for (y=0L; y < (long) height; y++)
789 destination[center*y]=source[y*width+width/2L];
790 for (x=0L; x < center; x++)
791 destination[x]=source[center-x-1L];
792 return(RollFourier(center,height,0L,(long) height/-2L,destination));
795 static MagickBooleanType InverseFourier(FourierInfo *fourier_info,
796 const Image *magnitude_image,const Image *phase_image,fftw_complex *fourier,
797 ExceptionInfo *exception)
815 register const IndexPacket
818 register const PixelPacket
826 Inverse fourier - read image and break down into a double array.
828 magnitude_source=(double *) AcquireQuantumMemory((size_t)
829 fourier_info->height,fourier_info->width*sizeof(*magnitude_source));
830 if (magnitude_source == (double *) NULL)
832 (void) ThrowMagickException(exception,GetMagickModule(),
833 ResourceLimitError,"MemoryAllocationFailed","`%s'",
834 magnitude_image->filename);
837 phase_source=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
838 fourier_info->height*sizeof(*phase_source));
839 if (phase_source == (double *) NULL)
841 (void) ThrowMagickException(exception,GetMagickModule(),
842 ResourceLimitError,"MemoryAllocationFailed","`%s'",
843 magnitude_image->filename);
844 magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
848 magnitude_view=AcquireCacheView(magnitude_image);
849 for (y=0L; y < (long) fourier_info->height; y++)
851 p=GetCacheViewVirtualPixels(magnitude_view,0L,y,fourier_info->width,1UL,
853 if (p == (const PixelPacket *) NULL)
855 indexes=GetCacheViewAuthenticIndexQueue(magnitude_view);
856 for (x=0L; x < (long) fourier_info->width; x++)
858 switch (fourier_info->channel)
863 magnitude_source[i]=QuantumScale*GetRedPixelComponent(p);
868 magnitude_source[i]=QuantumScale*GetGreenPixelComponent(p);
873 magnitude_source[i]=QuantumScale*GetBluePixelComponent(p);
878 magnitude_source[i]=QuantumScale*GetOpacityPixelComponent(p);
883 magnitude_source[i]=QuantumScale*indexes[x];
888 magnitude_source[i]=QuantumScale*GetRedPixelComponent(p);
897 phase_view=AcquireCacheView(phase_image);
898 for (y=0L; y < (long) fourier_info->height; y++)
900 p=GetCacheViewVirtualPixels(phase_view,0,y,fourier_info->width,1,
902 if (p == (const PixelPacket *) NULL)
904 indexes=GetCacheViewAuthenticIndexQueue(phase_view);
905 for (x=0L; x < (long) fourier_info->width; x++)
907 switch (fourier_info->channel)
912 phase_source[i]=QuantumScale*GetRedPixelComponent(p);
917 phase_source[i]=QuantumScale*GetGreenPixelComponent(p);
922 phase_source[i]=QuantumScale*GetBluePixelComponent(p);
927 phase_source[i]=QuantumScale*GetOpacityPixelComponent(p);
932 phase_source[i]=QuantumScale*indexes[x];
937 phase_source[i]=QuantumScale*GetRedPixelComponent(p);
945 if (fourier_info->modulus != MagickFalse)
948 for (y=0L; y < (long) fourier_info->height; y++)
949 for (x=0L; x < (long) fourier_info->width; x++)
951 phase_source[i]-=0.5;
952 phase_source[i]*=(2.0*MagickPI);
956 magnitude_view=DestroyCacheView(magnitude_view);
957 phase_view=DestroyCacheView(phase_view);
958 magnitude=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
959 fourier_info->center*sizeof(*magnitude));
960 if (magnitude == (double *) NULL)
962 (void) ThrowMagickException(exception,GetMagickModule(),
963 ResourceLimitError,"MemoryAllocationFailed","`%s'",
964 magnitude_image->filename);
965 magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
966 phase_source=(double *) RelinquishMagickMemory(phase_source);
969 status=InverseQuadrantSwap(fourier_info->width,fourier_info->height,
970 magnitude_source,magnitude);
971 magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
972 phase=(double *) AcquireQuantumMemory((size_t) fourier_info->width,
973 fourier_info->height*sizeof(*phase));
974 if (phase == (double *) NULL)
976 (void) ThrowMagickException(exception,GetMagickModule(),
977 ResourceLimitError,"MemoryAllocationFailed","`%s'",
978 magnitude_image->filename);
979 phase_source=(double *) RelinquishMagickMemory(phase_source);
982 CorrectPhaseLHS(fourier_info->width,fourier_info->width,phase_source);
983 if (status != MagickFalse)
984 status=InverseQuadrantSwap(fourier_info->width,fourier_info->height,
986 phase_source=(double *) RelinquishMagickMemory(phase_source);
991 if (fourier_info->modulus != MagickFalse)
992 for (y=0L; y < (long) fourier_info->height; y++)
993 for (x=0L; x < (long) fourier_info->center; x++)
995 #if defined(MAGICKCORE_HAVE_COMPLEX_H)
996 fourier[i]=magnitude[i]*cos(phase[i])+I*magnitude[i]*sin(phase[i]);
998 fourier[i][0]=magnitude[i]*cos(phase[i]);
999 fourier[i][1]=magnitude[i]*sin(phase[i]);
1004 for (y=0L; y < (long) fourier_info->height; y++)
1005 for (x=0L; x < (long) fourier_info->center; x++)
1007 #if defined(MAGICKCORE_HAVE_COMPLEX_H)
1008 fourier[i]=magnitude[i]+I*phase[i];
1010 fourier[i][0]=magnitude[i];
1011 fourier[i][1]=phase[i];
1015 phase=(double *) RelinquishMagickMemory(phase);
1016 magnitude=(double *) RelinquishMagickMemory(magnitude);
1020 static MagickBooleanType InverseFourierTransform(FourierInfo *fourier_info,
1021 fftw_complex *fourier,Image *image,ExceptionInfo *exception)
1035 register IndexPacket
1042 register PixelPacket
1045 source=(double *) AcquireQuantumMemory((size_t) fourier_info->width,
1046 fourier_info->height*sizeof(double));
1047 if (source == (double *) NULL)
1049 (void) ThrowMagickException(exception,GetMagickModule(),
1050 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
1051 return(MagickFalse);
1053 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1054 #pragma omp critical (MagickCore_InverseFourierTransform)
1056 fftw_c2r_plan=fftw_plan_dft_c2r_2d(fourier_info->width,fourier_info->height,
1057 fourier,source,FFTW_ESTIMATE);
1058 fftw_execute(fftw_c2r_plan);
1059 fftw_destroy_plan(fftw_c2r_plan);
1061 image_view=AcquireCacheView(image);
1062 for (y=0L; y < (long) fourier_info->height; y++)
1064 q=GetCacheViewAuthenticPixels(image_view,0L,y,fourier_info->width,1UL,
1066 if (q == (PixelPacket *) NULL)
1068 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1069 for (x=0L; x < (long) fourier_info->width; x++)
1071 switch (fourier_info->channel)
1076 q->red=ClampToQuantum(QuantumRange*source[i]);
1081 q->green=ClampToQuantum(QuantumRange*source[i]);
1086 q->blue=ClampToQuantum(QuantumRange*source[i]);
1089 case OpacityChannel:
1091 q->opacity=ClampToQuantum(QuantumRange*source[i]);
1096 indexes[x]=ClampToQuantum(QuantumRange*source[i]);
1101 q->red=ClampToQuantum(QuantumRange*source[i]);
1110 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1113 image_view=DestroyCacheView(image_view);
1114 source=(double *) RelinquishMagickMemory(source);
1118 static MagickBooleanType InverseFourierTransformChannel(
1119 const Image *magnitude_image,const Image *phase_image,
1120 const ChannelType channel,const MagickBooleanType modulus,
1121 Image *fourier_image,ExceptionInfo *exception)
1139 fourier_info.width=magnitude_image->columns;
1140 if ((magnitude_image->columns != magnitude_image->rows) ||
1141 ((magnitude_image->columns % 2) != 0) ||
1142 ((magnitude_image->rows % 2) != 0))
1144 extent=magnitude_image->columns < magnitude_image->rows ?
1145 magnitude_image->rows : magnitude_image->columns;
1146 fourier_info.width=(extent & 0x01) == 1 ? extent+1UL : extent;
1148 fourier_info.height=fourier_info.width;
1149 fourier_info.center=(long) floor((double) fourier_info.width/2.0)+1L;
1150 fourier_info.channel=channel;
1151 fourier_info.modulus=modulus;
1152 magnitude=(double *) AcquireQuantumMemory((size_t) fourier_info.height,
1153 fourier_info.center*sizeof(double));
1154 if (magnitude == (double *) NULL)
1156 (void) ThrowMagickException(exception,GetMagickModule(),
1157 ResourceLimitError,"MemoryAllocationFailed","`%s'",
1158 magnitude_image->filename);
1159 return(MagickFalse);
1161 phase=(double *) AcquireQuantumMemory((size_t) fourier_info.height,
1162 fourier_info.center*sizeof(double));
1163 if (phase == (double *) NULL)
1165 (void) ThrowMagickException(exception,GetMagickModule(),
1166 ResourceLimitError,"MemoryAllocationFailed","`%s'",
1167 magnitude_image->filename);
1168 magnitude=(double *) RelinquishMagickMemory(magnitude);
1169 return(MagickFalse);
1171 fourier=(fftw_complex *) AcquireAlignedMemory((size_t) fourier_info.height,
1172 fourier_info.center*sizeof(*fourier));
1173 if (fourier == (fftw_complex *) NULL)
1175 (void) ThrowMagickException(exception,GetMagickModule(),
1176 ResourceLimitError,"MemoryAllocationFailed","`%s'",
1177 magnitude_image->filename);
1178 phase=(double *) RelinquishMagickMemory(phase);
1179 magnitude=(double *) RelinquishMagickMemory(magnitude);
1180 return(MagickFalse);
1182 status=InverseFourier(&fourier_info,magnitude_image,phase_image,fourier,
1184 if (status != MagickFalse)
1185 status=InverseFourierTransform(&fourier_info,fourier,fourier_image,
1187 fourier=(fftw_complex *) RelinquishAlignedMemory(fourier);
1188 phase=(double *) RelinquishMagickMemory(phase);
1189 magnitude=(double *) RelinquishMagickMemory(magnitude);
1194 MagickExport Image *InverseFourierTransformImage(const Image *magnitude_image,
1195 const Image *phase_image,const MagickBooleanType modulus,
1196 ExceptionInfo *exception)
1201 assert(magnitude_image != (Image *) NULL);
1202 assert(magnitude_image->signature == MagickSignature);
1203 if (magnitude_image->debug != MagickFalse)
1204 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1205 magnitude_image->filename);
1206 if (phase_image == (Image *) NULL)
1208 (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
1209 "ImageSequenceRequired","`%s'",magnitude_image->filename);
1210 return((Image *) NULL);
1212 #if !defined(MAGICKCORE_FFTW_DELEGATE)
1213 fourier_image=(Image *) NULL;
1215 (void) ThrowMagickException(exception,GetMagickModule(),
1216 MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","`%s' (FFTW)",
1217 magnitude_image->filename);
1220 fourier_image=CloneImage(magnitude_image,magnitude_image->columns,
1221 magnitude_image->rows,MagickFalse,exception);
1222 if (fourier_image != (Image *) NULL)
1232 is_gray=IsGrayImage(magnitude_image,exception);
1233 if (is_gray != MagickFalse)
1234 is_gray=IsGrayImage(phase_image,exception);
1235 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1236 #pragma omp parallel for schedule(dynamic,4) shared(status)
1238 for (i=0L; i < 5L; i++)
1243 thread_status=MagickTrue;
1248 if (is_gray != MagickFalse)
1250 thread_status=InverseFourierTransformChannel(magnitude_image,
1251 phase_image,GrayChannels,modulus,fourier_image,exception);
1254 thread_status=InverseFourierTransformChannel(magnitude_image,
1255 phase_image,RedChannel,modulus,fourier_image,exception);
1260 if (is_gray == MagickFalse)
1261 thread_status=InverseFourierTransformChannel(magnitude_image,
1262 phase_image,GreenChannel,modulus,fourier_image,exception);
1267 if (is_gray == MagickFalse)
1268 thread_status=InverseFourierTransformChannel(magnitude_image,
1269 phase_image,BlueChannel,modulus,fourier_image,exception);
1274 if (magnitude_image->matte != MagickFalse)
1275 thread_status=InverseFourierTransformChannel(magnitude_image,
1276 phase_image,OpacityChannel,modulus,fourier_image,exception);
1281 if (magnitude_image->colorspace == CMYKColorspace)
1282 thread_status=InverseFourierTransformChannel(magnitude_image,
1283 phase_image,IndexChannel,modulus,fourier_image,exception);
1287 if (thread_status == MagickFalse)
1288 status=thread_status;
1290 if (status == MagickFalse)
1291 fourier_image=DestroyImage(fourier_image);
1296 return(fourier_image);