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-2013 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 "MagickCore/studio.h"
46 #include "MagickCore/artifact.h"
47 #include "MagickCore/attribute.h"
48 #include "MagickCore/blob.h"
49 #include "MagickCore/cache.h"
50 #include "MagickCore/image.h"
51 #include "MagickCore/image-private.h"
52 #include "MagickCore/list.h"
53 #include "MagickCore/fourier.h"
54 #include "MagickCore/log.h"
55 #include "MagickCore/memory_.h"
56 #include "MagickCore/monitor.h"
57 #include "MagickCore/pixel-accessor.h"
58 #include "MagickCore/pixel-private.h"
59 #include "MagickCore/property.h"
60 #include "MagickCore/quantum-private.h"
61 #include "MagickCore/resource_.h"
62 #include "MagickCore/thread-private.h"
63 #if defined(MAGICKCORE_FFTW_DELEGATE)
64 #if defined(MAGICKCORE_HAVE_COMPLEX_H)
68 #if !defined(MAGICKCORE_HAVE_CABS)
69 #define cabs(z) (sqrt(z[0]*z[0]+z[1]*z[1]))
71 #if !defined(MAGICKCORE_HAVE_CARG)
72 #define carg(z) (atan2(cimag(z),creal(z)))
74 #if !defined(MAGICKCORE_HAVE_CIMAG)
75 #define cimag(z) (z[1])
77 #if !defined(MAGICKCORE_HAVE_CREAL)
78 #define creal(z) (z[0])
85 typedef struct _FourierInfo
102 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
106 % 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 %
110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
112 % ForwardFourierTransformImage() implements the discrete Fourier transform
113 % (DFT) of the image either as a magnitude / phase or real / imaginary image
116 % The format of the ForwadFourierTransformImage method is:
118 % Image *ForwardFourierTransformImage(const Image *image,
119 % const MagickBooleanType modulus,ExceptionInfo *exception)
121 % A description of each parameter follows:
123 % o image: the image.
125 % o modulus: if true, return as transform as a magnitude / phase pair
126 % otherwise a real / imaginary image pair.
128 % o exception: return any errors or warnings in this structure.
132 #if defined(MAGICKCORE_FFTW_DELEGATE)
134 static MagickBooleanType RollFourier(const size_t width,const size_t height,
135 const ssize_t x_offset,const ssize_t y_offset,double *roll_pixels)
153 Move zero frequency (DC, average color) from (0,0) to (width/2,height/2).
155 source_info=AcquireVirtualMemory(height,width*sizeof(*source_pixels));
156 if (source_info == (MemoryInfo *) NULL)
158 source_pixels=(double *) GetVirtualMemoryBlob(source_info);
160 for (y=0L; y < (ssize_t) height; y++)
163 v=((y+y_offset) < 0L) ? y+y_offset+(ssize_t) height : y+y_offset;
165 v=((y+y_offset) > ((ssize_t) height-1L)) ? y+y_offset-(ssize_t) height :
167 for (x=0L; x < (ssize_t) width; x++)
170 u=((x+x_offset) < 0L) ? x+x_offset+(ssize_t) width : x+x_offset;
172 u=((x+x_offset) > ((ssize_t) width-1L)) ? x+x_offset-(ssize_t) width :
174 source_pixels[v*width+u]=roll_pixels[i++];
177 (void) CopyMagickMemory(roll_pixels,source_pixels,height*width*
178 sizeof(*source_pixels));
179 source_info=RelinquishVirtualMemory(source_info);
183 static MagickBooleanType ForwardQuadrantSwap(const size_t width,
184 const size_t height,double *source_pixels,double *forward_pixels)
199 center=(ssize_t) floor((double) width/2L)+1L;
200 status=RollFourier((size_t) center,height,0L,(ssize_t) height/2L,
202 if (status == MagickFalse)
204 for (y=0L; y < (ssize_t) height; y++)
205 for (x=0L; x < (ssize_t) (width/2L-1L); x++)
206 forward_pixels[y*width+x+width/2L]=source_pixels[y*center+x];
207 for (y=1; y < (ssize_t) height; y++)
208 for (x=0L; x < (ssize_t) (width/2L-1L); x++)
209 forward_pixels[(height-y)*width+width/2L-x-1L]=
210 source_pixels[y*center+x+1L];
211 for (x=0L; x < (ssize_t) (width/2L); x++)
212 forward_pixels[-x+width/2L-1L]=forward_pixels[x+width/2L+1L];
216 static void CorrectPhaseLHS(const size_t width,const size_t height,
217 double *fourier_pixels)
225 for (y=0L; y < (ssize_t) height; y++)
226 for (x=0L; x < (ssize_t) (width/2L); x++)
227 fourier_pixels[y*width+x]*=(-1.0);
230 static MagickBooleanType ForwardFourier(const FourierInfo *fourier_info,
231 Image *image,double *magnitude,double *phase,ExceptionInfo *exception)
262 magnitude_image=GetFirstImageInList(image);
263 phase_image=GetNextImageInList(image);
264 if (phase_image == (Image *) NULL)
266 (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
267 "TwoOrMoreImagesRequired","`%s'",image->filename);
271 Create "Fourier Transform" image from constituent arrays.
273 magnitude_info=AcquireVirtualMemory((size_t) fourier_info->height,
274 fourier_info->width*sizeof(*magnitude_pixels));
275 phase_info=AcquireVirtualMemory((size_t) fourier_info->height,
276 fourier_info->width*sizeof(*phase_pixels));
277 if ((magnitude_info == (MemoryInfo *) NULL) ||
278 (phase_info == (MemoryInfo *) NULL))
280 if (phase_info != (MemoryInfo *) NULL)
281 phase_info=RelinquishVirtualMemory(phase_info);
282 if (magnitude_info != (MemoryInfo *) NULL)
283 magnitude_info=RelinquishVirtualMemory(magnitude_info);
284 (void) ThrowMagickException(exception,GetMagickModule(),
285 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
288 magnitude_pixels=(double *) GetVirtualMemoryBlob(magnitude_info);
289 (void) ResetMagickMemory(magnitude_pixels,0,fourier_info->height*
290 fourier_info->width*sizeof(*magnitude_pixels));
291 phase_pixels=(double *) GetVirtualMemoryBlob(phase_info);
292 (void) ResetMagickMemory(phase_pixels,0,fourier_info->height*
293 fourier_info->width*sizeof(*phase_pixels));
294 status=ForwardQuadrantSwap(fourier_info->width,fourier_info->height,
295 magnitude,magnitude_pixels);
296 if (status != MagickFalse)
297 status=ForwardQuadrantSwap(fourier_info->width,fourier_info->height,phase,
299 CorrectPhaseLHS(fourier_info->width,fourier_info->height,phase_pixels);
300 if (fourier_info->modulus != MagickFalse)
303 for (y=0L; y < (ssize_t) fourier_info->height; y++)
304 for (x=0L; x < (ssize_t) fourier_info->width; x++)
306 phase_pixels[i]/=(2.0*MagickPI);
307 phase_pixels[i]+=0.5;
311 magnitude_view=AcquireAuthenticCacheView(magnitude_image,exception);
313 for (y=0L; y < (ssize_t) fourier_info->height; y++)
315 q=GetCacheViewAuthenticPixels(magnitude_view,0L,y,fourier_info->height,1UL,
317 if (q == (Quantum *) NULL)
319 for (x=0L; x < (ssize_t) fourier_info->width; x++)
321 switch (fourier_info->channel)
323 case RedPixelChannel:
326 SetPixelRed(magnitude_image,ClampToQuantum(QuantumRange*
327 magnitude_pixels[i]),q);
330 case GreenPixelChannel:
332 SetPixelGreen(magnitude_image,ClampToQuantum(QuantumRange*
333 magnitude_pixels[i]),q);
336 case BluePixelChannel:
338 SetPixelBlue(magnitude_image,ClampToQuantum(QuantumRange*
339 magnitude_pixels[i]),q);
342 case BlackPixelChannel:
344 SetPixelBlack(magnitude_image,ClampToQuantum(QuantumRange*
345 magnitude_pixels[i]),q);
348 case AlphaPixelChannel:
350 SetPixelAlpha(magnitude_image,ClampToQuantum(QuantumRange*
351 magnitude_pixels[i]),q);
356 q+=GetPixelChannels(magnitude_image);
358 status=SyncCacheViewAuthenticPixels(magnitude_view,exception);
359 if (status == MagickFalse)
362 magnitude_view=DestroyCacheView(magnitude_view);
364 phase_view=AcquireAuthenticCacheView(phase_image,exception);
365 for (y=0L; y < (ssize_t) fourier_info->height; y++)
367 q=GetCacheViewAuthenticPixels(phase_view,0L,y,fourier_info->height,1UL,
369 if (q == (Quantum *) NULL)
371 for (x=0L; x < (ssize_t) fourier_info->width; x++)
373 switch (fourier_info->channel)
375 case RedPixelChannel:
378 SetPixelRed(phase_image,ClampToQuantum(QuantumRange*
382 case GreenPixelChannel:
384 SetPixelGreen(phase_image,ClampToQuantum(QuantumRange*
388 case BluePixelChannel:
390 SetPixelBlue(phase_image,ClampToQuantum(QuantumRange*
394 case BlackPixelChannel:
396 SetPixelBlack(phase_image,ClampToQuantum(QuantumRange*
400 case AlphaPixelChannel:
402 SetPixelAlpha(phase_image,ClampToQuantum(QuantumRange*
408 q+=GetPixelChannels(phase_image);
410 status=SyncCacheViewAuthenticPixels(phase_view,exception);
411 if (status == MagickFalse)
414 phase_view=DestroyCacheView(phase_view);
415 phase_info=RelinquishVirtualMemory(phase_info);
416 magnitude_info=RelinquishVirtualMemory(magnitude_info);
420 static MagickBooleanType ForwardFourierTransform(FourierInfo *fourier_info,
421 const Image *image,double *magnitude_pixels,double *phase_pixels,
422 ExceptionInfo *exception)
443 register const Quantum
454 Generate the forward Fourier transform.
456 source_info=AcquireVirtualMemory((size_t) fourier_info->height,
457 fourier_info->width*sizeof(*source_pixels));
458 if (source_info == (MemoryInfo *) NULL)
460 (void) ThrowMagickException(exception,GetMagickModule(),
461 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
464 source_pixels=(double *) GetVirtualMemoryBlob(source_info);
465 ResetMagickMemory(source_pixels,0,fourier_info->height*fourier_info->width*
466 sizeof(*source_pixels));
468 image_view=AcquireVirtualCacheView(image,exception);
469 for (y=0L; y < (ssize_t) fourier_info->height; y++)
471 p=GetCacheViewVirtualPixels(image_view,0L,y,fourier_info->width,1UL,
473 if (p == (const Quantum *) NULL)
475 for (x=0L; x < (ssize_t) fourier_info->width; x++)
477 switch (fourier_info->channel)
479 case RedPixelChannel:
482 source_pixels[i]=QuantumScale*GetPixelRed(image,p);
485 case GreenPixelChannel:
487 source_pixels[i]=QuantumScale*GetPixelGreen(image,p);
490 case BluePixelChannel:
492 source_pixels[i]=QuantumScale*GetPixelBlue(image,p);
495 case BlackPixelChannel:
497 source_pixels[i]=QuantumScale*GetPixelBlack(image,p);
500 case AlphaPixelChannel:
502 source_pixels[i]=QuantumScale*GetPixelAlpha(image,p);
507 p+=GetPixelChannels(image);
510 image_view=DestroyCacheView(image_view);
511 forward_info=AcquireVirtualMemory((size_t) fourier_info->height,
512 fourier_info->center*sizeof(*forward_pixels));
513 if (forward_info == (MemoryInfo *) NULL)
515 (void) ThrowMagickException(exception,GetMagickModule(),
516 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
517 source_info=(MemoryInfo *) RelinquishVirtualMemory(source_info);
520 forward_pixels=(fftw_complex *) GetVirtualMemoryBlob(forward_info);
521 #if defined(MAGICKCORE_OPENMP_SUPPORT)
522 #pragma omp critical (MagickCore_ForwardFourierTransform)
524 fftw_r2c_plan=fftw_plan_dft_r2c_2d(fourier_info->width,fourier_info->height,
525 source_pixels,forward_pixels,FFTW_ESTIMATE);
526 fftw_execute(fftw_r2c_plan);
527 fftw_destroy_plan(fftw_r2c_plan);
528 source_info=(MemoryInfo *) RelinquishVirtualMemory(source_info);
529 value=GetImageArtifact(image,"fourier:normalize");
530 if ((value == (const char *) NULL) || (LocaleCompare(value,"fft") == 0))
536 Normalize Fourier transform.
539 gamma=PerceptibleReciprocal((double) fourier_info->width*
540 fourier_info->height);
541 for (y=0L; y < (ssize_t) fourier_info->height; y++)
542 for (x=0L; x < (ssize_t) fourier_info->center; x++)
544 #if defined(MAGICKCORE_HAVE_COMPLEX_H)
545 forward_pixels[i]*=gamma;
547 forward_pixels[i][0]*=gamma;
548 forward_pixels[i][1]*=gamma;
554 Generate magnitude and phase (or real and imaginary).
557 if (fourier_info->modulus != MagickFalse)
558 for (y=0L; y < (ssize_t) fourier_info->height; y++)
559 for (x=0L; x < (ssize_t) fourier_info->center; x++)
561 magnitude_pixels[i]=cabs(forward_pixels[i]);
562 phase_pixels[i]=carg(forward_pixels[i]);
566 for (y=0L; y < (ssize_t) fourier_info->height; y++)
567 for (x=0L; x < (ssize_t) fourier_info->center; x++)
569 magnitude_pixels[i]=creal(forward_pixels[i]);
570 phase_pixels[i]=cimag(forward_pixels[i]);
573 forward_info=(MemoryInfo *) RelinquishVirtualMemory(forward_info);
577 static MagickBooleanType ForwardFourierTransformChannel(const Image *image,
578 const PixelChannel channel,const MagickBooleanType modulus,
579 Image *fourier_image,ExceptionInfo *exception)
598 fourier_info.width=image->columns;
599 if ((image->columns != image->rows) || ((image->columns % 2) != 0) ||
600 ((image->rows % 2) != 0))
602 extent=image->columns < image->rows ? image->rows : image->columns;
603 fourier_info.width=(extent & 0x01) == 1 ? extent+1UL : extent;
605 fourier_info.height=fourier_info.width;
606 fourier_info.center=(ssize_t) floor((double) fourier_info.width/2L)+1L;
607 fourier_info.channel=channel;
608 fourier_info.modulus=modulus;
609 magnitude_info=AcquireVirtualMemory((size_t) fourier_info.height,
610 fourier_info.center*sizeof(*magnitude_pixels));
611 phase_info=AcquireVirtualMemory((size_t) fourier_info.height,
612 fourier_info.center*sizeof(*phase_pixels));
613 if ((magnitude_info == (MemoryInfo *) NULL) ||
614 (phase_info == (MemoryInfo *) NULL))
616 if (phase_info != (MemoryInfo *) NULL)
617 phase_info=RelinquishVirtualMemory(phase_info);
618 if (magnitude_info == (MemoryInfo *) NULL)
619 magnitude_info=RelinquishVirtualMemory(magnitude_info);
620 (void) ThrowMagickException(exception,GetMagickModule(),
621 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
624 magnitude_pixels=(double *) GetVirtualMemoryBlob(magnitude_info);
625 phase_pixels=(double *) GetVirtualMemoryBlob(phase_info);
626 status=ForwardFourierTransform(&fourier_info,image,magnitude_pixels,
627 phase_pixels,exception);
628 if (status != MagickFalse)
629 status=ForwardFourier(&fourier_info,fourier_image,magnitude_pixels,
630 phase_pixels,exception);
631 phase_info=RelinquishVirtualMemory(phase_info);
632 magnitude_info=RelinquishVirtualMemory(magnitude_info);
637 MagickExport Image *ForwardFourierTransformImage(const Image *image,
638 const MagickBooleanType modulus,ExceptionInfo *exception)
643 fourier_image=NewImageList();
644 #if !defined(MAGICKCORE_FFTW_DELEGATE)
646 (void) ThrowMagickException(exception,GetMagickModule(),
647 MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","'%s' (FFTW)",
658 width=image->columns;
659 if ((image->columns != image->rows) || ((image->columns % 2) != 0) ||
660 ((image->rows % 2) != 0))
662 extent=image->columns < image->rows ? image->rows : image->columns;
663 width=(extent & 0x01) == 1 ? extent+1UL : extent;
665 magnitude_image=CloneImage(image,width,width,MagickFalse,exception);
666 if (magnitude_image != (Image *) NULL)
671 magnitude_image->storage_class=DirectClass;
672 magnitude_image->depth=32UL;
673 phase_image=CloneImage(image,width,width,MagickFalse,exception);
674 if (phase_image == (Image *) NULL)
675 magnitude_image=DestroyImage(magnitude_image);
682 phase_image->storage_class=DirectClass;
683 phase_image->depth=32UL;
684 AppendImageToList(&fourier_image,magnitude_image);
685 AppendImageToList(&fourier_image,phase_image);
687 is_gray=IsImageGray(image,exception);
688 #if defined(MAGICKCORE_OPENMP_SUPPORT)
689 #pragma omp parallel sections
692 #if defined(MAGICKCORE_OPENMP_SUPPORT)
699 if (is_gray != MagickFalse)
700 thread_status=ForwardFourierTransformChannel(image,
701 GrayPixelChannel,modulus,fourier_image,exception);
703 thread_status=ForwardFourierTransformChannel(image,
704 RedPixelChannel,modulus,fourier_image,exception);
705 if (thread_status == MagickFalse)
706 status=thread_status;
708 #if defined(MAGICKCORE_OPENMP_SUPPORT)
715 thread_status=MagickTrue;
716 if (is_gray == MagickFalse)
717 thread_status=ForwardFourierTransformChannel(image,
718 GreenPixelChannel,modulus,fourier_image,exception);
719 if (thread_status == MagickFalse)
720 status=thread_status;
722 #if defined(MAGICKCORE_OPENMP_SUPPORT)
729 thread_status=MagickTrue;
730 if (is_gray == MagickFalse)
731 thread_status=ForwardFourierTransformChannel(image,
732 BluePixelChannel,modulus,fourier_image,exception);
733 if (thread_status == MagickFalse)
734 status=thread_status;
736 #if defined(MAGICKCORE_OPENMP_SUPPORT)
743 thread_status=MagickTrue;
744 if (image->colorspace == CMYKColorspace)
745 thread_status=ForwardFourierTransformChannel(image,
746 BlackPixelChannel,modulus,fourier_image,exception);
747 if (thread_status == MagickFalse)
748 status=thread_status;
750 #if defined(MAGICKCORE_OPENMP_SUPPORT)
757 thread_status=MagickTrue;
758 if (image->alpha_trait == BlendPixelTrait)
759 thread_status=ForwardFourierTransformChannel(image,
760 AlphaPixelChannel,modulus,fourier_image,exception);
761 if (thread_status == MagickFalse)
762 status=thread_status;
765 if (status == MagickFalse)
766 fourier_image=DestroyImageList(fourier_image);
772 return(fourier_image);
776 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
780 % 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 %
784 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
786 % InverseFourierTransformImage() implements the inverse discrete Fourier
787 % transform (DFT) of the image either as a magnitude / phase or real /
788 % imaginary image pair.
790 % The format of the InverseFourierTransformImage method is:
792 % Image *InverseFourierTransformImage(const Image *magnitude_image,
793 % const Image *phase_image,const MagickBooleanType modulus,
794 % ExceptionInfo *exception)
796 % A description of each parameter follows:
798 % o magnitude_image: the magnitude or real image.
800 % o phase_image: the phase or imaginary image.
802 % o modulus: if true, return transform as a magnitude / phase pair
803 % otherwise a real / imaginary image pair.
805 % o exception: return any errors or warnings in this structure.
809 #if defined(MAGICKCORE_FFTW_DELEGATE)
810 static MagickBooleanType InverseQuadrantSwap(const size_t width,
811 const size_t height,const double *source,double *destination)
823 center=(ssize_t) floor((double) width/2L)+1L;
824 for (y=1L; y < (ssize_t) height; y++)
825 for (x=0L; x < (ssize_t) (width/2L+1L); x++)
826 destination[(height-y)*center-x+width/2L]=source[y*width+x];
827 for (y=0L; y < (ssize_t) height; y++)
828 destination[y*center]=source[y*width+width/2L];
829 for (x=0L; x < center; x++)
830 destination[x]=source[center-x-1L];
831 return(RollFourier(center,height,0L,(ssize_t) height/-2L,destination));
834 static MagickBooleanType InverseFourier(FourierInfo *fourier_info,
835 const Image *magnitude_image,const Image *phase_image,
836 fftw_complex *fourier_pixels,ExceptionInfo *exception)
855 register const Quantum
866 Inverse fourier - read image and break down into a double array.
868 magnitude_info=AcquireVirtualMemory((size_t)fourier_info->height,
869 fourier_info->width*sizeof(*magnitude_pixels));
870 phase_info=AcquireVirtualMemory((size_t) fourier_info->height,
871 fourier_info->width*sizeof(*phase_pixels));
872 inverse_info=AcquireVirtualMemory((size_t) fourier_info->height,
873 fourier_info->center*sizeof(*inverse_pixels));
874 if ((magnitude_info == (MemoryInfo *) NULL) ||
875 (phase_info == (MemoryInfo *) NULL) ||
876 (inverse_info == (MemoryInfo *) NULL))
878 if (magnitude_info != (MemoryInfo *) NULL)
879 magnitude_info=RelinquishVirtualMemory(magnitude_info);
880 if (phase_info != (MemoryInfo *) NULL)
881 phase_info=RelinquishVirtualMemory(phase_info);
882 if (inverse_info != (MemoryInfo *) NULL)
883 inverse_info=RelinquishVirtualMemory(inverse_info);
884 (void) ThrowMagickException(exception,GetMagickModule(),
885 ResourceLimitError,"MemoryAllocationFailed","`%s'",
886 magnitude_image->filename);
889 magnitude_pixels=(double *) GetVirtualMemoryBlob(magnitude_info);
890 phase_pixels=(double *) GetVirtualMemoryBlob(phase_info);
891 inverse_pixels=(double *) GetVirtualMemoryBlob(inverse_info);
893 magnitude_view=AcquireVirtualCacheView(magnitude_image,exception);
894 for (y=0L; y < (ssize_t) fourier_info->height; y++)
896 p=GetCacheViewVirtualPixels(magnitude_view,0L,y,fourier_info->width,1UL,
898 if (p == (const Quantum *) NULL)
900 for (x=0L; x < (ssize_t) fourier_info->width; x++)
902 switch (fourier_info->channel)
904 case RedPixelChannel:
907 magnitude_pixels[i]=QuantumScale*GetPixelRed(magnitude_image,p);
910 case GreenPixelChannel:
912 magnitude_pixels[i]=QuantumScale*GetPixelGreen(magnitude_image,p);
915 case BluePixelChannel:
917 magnitude_pixels[i]=QuantumScale*GetPixelBlue(magnitude_image,p);
920 case BlackPixelChannel:
922 magnitude_pixels[i]=QuantumScale*GetPixelBlack(magnitude_image,p);
925 case AlphaPixelChannel:
927 magnitude_pixels[i]=QuantumScale*GetPixelAlpha(magnitude_image,p);
932 p+=GetPixelChannels(magnitude_image);
935 magnitude_view=DestroyCacheView(magnitude_view);
936 status=InverseQuadrantSwap(fourier_info->width,fourier_info->height,
937 magnitude_pixels,inverse_pixels);
938 (void) CopyMagickMemory(magnitude_pixels,inverse_pixels,fourier_info->height*
939 fourier_info->center*sizeof(*magnitude_pixels));
941 phase_view=AcquireVirtualCacheView(phase_image,exception);
942 for (y=0L; y < (ssize_t) fourier_info->height; y++)
944 p=GetCacheViewVirtualPixels(phase_view,0,y,fourier_info->width,1,
946 if (p == (const Quantum *) NULL)
948 for (x=0L; x < (ssize_t) fourier_info->width; x++)
950 switch (fourier_info->channel)
952 case RedPixelChannel:
955 phase_pixels[i]=QuantumScale*GetPixelRed(phase_image,p);
958 case GreenPixelChannel:
960 phase_pixels[i]=QuantumScale*GetPixelGreen(phase_image,p);
963 case BluePixelChannel:
965 phase_pixels[i]=QuantumScale*GetPixelBlue(phase_image,p);
968 case BlackPixelChannel:
970 phase_pixels[i]=QuantumScale*GetPixelBlack(phase_image,p);
973 case AlphaPixelChannel:
975 phase_pixels[i]=QuantumScale*GetPixelAlpha(phase_image,p);
980 p+=GetPixelChannels(phase_image);
983 if (fourier_info->modulus != MagickFalse)
986 for (y=0L; y < (ssize_t) fourier_info->height; y++)
987 for (x=0L; x < (ssize_t) fourier_info->width; x++)
989 phase_pixels[i]-=0.5;
990 phase_pixels[i]*=(2.0*MagickPI);
994 phase_view=DestroyCacheView(phase_view);
995 CorrectPhaseLHS(fourier_info->width,fourier_info->height,phase_pixels);
996 if (status != MagickFalse)
997 status=InverseQuadrantSwap(fourier_info->width,fourier_info->height,
998 phase_pixels,inverse_pixels);
999 (void) CopyMagickMemory(phase_pixels,inverse_pixels,fourier_info->height*
1000 fourier_info->center*sizeof(*phase_pixels));
1001 inverse_info=RelinquishVirtualMemory(inverse_info);
1006 if (fourier_info->modulus != MagickFalse)
1007 for (y=0L; y < (ssize_t) fourier_info->height; y++)
1008 for (x=0L; x < (ssize_t) fourier_info->center; x++)
1010 #if defined(MAGICKCORE_HAVE_COMPLEX_H)
1011 fourier_pixels[i]=magnitude_pixels[i]*cos(phase_pixels[i])+I*
1012 magnitude_pixels[i]*sin(phase_pixels[i]);
1014 fourier_pixels[i][0]=magnitude_pixels[i]*cos(phase_pixels[i]);
1015 fourier_pixels[i][1]=magnitude_pixels[i]*sin(phase_pixels[i]);
1020 for (y=0L; y < (ssize_t) fourier_info->height; y++)
1021 for (x=0L; x < (ssize_t) fourier_info->center; x++)
1023 #if defined(MAGICKCORE_HAVE_COMPLEX_H)
1024 fourier_pixels[i]=magnitude_pixels[i]+I*phase_pixels[i];
1026 fourier_pixels[i][0]=magnitude_pixels[i];
1027 fourier_pixels[i][1]=phase_pixels[i];
1031 magnitude_info=RelinquishVirtualMemory(magnitude_info);
1032 phase_info=RelinquishVirtualMemory(phase_info);
1036 static MagickBooleanType InverseFourierTransform(FourierInfo *fourier_info,
1037 fftw_complex *fourier_pixels,Image *image,ExceptionInfo *exception)
1064 source_info=AcquireVirtualMemory((size_t) fourier_info->height,
1065 fourier_info->width*sizeof(*source_pixels));
1066 if (source_info == (MemoryInfo *) NULL)
1068 (void) ThrowMagickException(exception,GetMagickModule(),
1069 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
1070 return(MagickFalse);
1072 source_pixels=(double *) GetVirtualMemoryBlob(source_info);
1073 value=GetImageArtifact(image,"fourier:normalize");
1074 if ((value == (const char *) NULL) || (LocaleCompare(value,"fft") == 0))
1080 Normalize inverse transform.
1083 gamma=PerceptibleReciprocal((double) fourier_info->width*
1084 fourier_info->height);
1085 for (y=0L; y < (ssize_t) fourier_info->height; y++)
1086 for (x=0L; x < (ssize_t) fourier_info->center; x++)
1088 #if defined(MAGICKCORE_HAVE_COMPLEX_H)
1089 fourier_pixels[i]*=gamma;
1091 fourier_pixels[i][0]*=gamma;
1092 fourier_pixels[i][1]*=gamma;
1097 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1098 #pragma omp critical (MagickCore_InverseFourierTransform)
1101 fftw_c2r_plan=fftw_plan_dft_c2r_2d(fourier_info->width,fourier_info->height,
1102 fourier_pixels,source_pixels,FFTW_ESTIMATE);
1103 fftw_execute(fftw_c2r_plan);
1104 fftw_destroy_plan(fftw_c2r_plan);
1107 image_view=AcquireAuthenticCacheView(image,exception);
1108 for (y=0L; y < (ssize_t) fourier_info->height; y++)
1110 if (y >= (ssize_t) image->rows)
1112 q=GetCacheViewAuthenticPixels(image_view,0L,y,fourier_info->width >
1113 image->columns ? image->columns : fourier_info->width,1UL,exception);
1114 if (q == (Quantum *) NULL)
1116 for (x=0L; x < (ssize_t) fourier_info->width; x++)
1118 if (x < (ssize_t) image->columns)
1119 switch (fourier_info->channel)
1121 case RedPixelChannel:
1124 SetPixelRed(image,ClampToQuantum(QuantumRange*source_pixels[i]),q);
1127 case GreenPixelChannel:
1129 SetPixelGreen(image,ClampToQuantum(QuantumRange*source_pixels[i]),
1133 case BluePixelChannel:
1135 SetPixelBlue(image,ClampToQuantum(QuantumRange*source_pixels[i]),
1139 case BlackPixelChannel:
1141 SetPixelBlack(image,ClampToQuantum(QuantumRange*source_pixels[i]),
1145 case AlphaPixelChannel:
1147 SetPixelAlpha(image,ClampToQuantum(QuantumRange*source_pixels[i]),
1153 q+=GetPixelChannels(image);
1155 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1158 image_view=DestroyCacheView(image_view);
1159 source_info=RelinquishVirtualMemory(source_info);
1163 static MagickBooleanType InverseFourierTransformChannel(
1164 const Image *magnitude_image,const Image *phase_image,
1165 const PixelChannel channel,const MagickBooleanType modulus,
1166 Image *fourier_image,ExceptionInfo *exception)
1183 fourier_info.width=magnitude_image->columns;
1184 if ((magnitude_image->columns != magnitude_image->rows) ||
1185 ((magnitude_image->columns % 2) != 0) ||
1186 ((magnitude_image->rows % 2) != 0))
1188 extent=magnitude_image->columns < magnitude_image->rows ?
1189 magnitude_image->rows : magnitude_image->columns;
1190 fourier_info.width=(extent & 0x01) == 1 ? extent+1UL : extent;
1192 fourier_info.height=fourier_info.width;
1193 fourier_info.center=(ssize_t) floor((double) fourier_info.width/2L)+1L;
1194 fourier_info.channel=channel;
1195 fourier_info.modulus=modulus;
1196 inverse_info=AcquireVirtualMemory((size_t) fourier_info.height,
1197 fourier_info.center*sizeof(*inverse_pixels));
1198 if (inverse_info == (MemoryInfo *) NULL)
1200 (void) ThrowMagickException(exception,GetMagickModule(),
1201 ResourceLimitError,"MemoryAllocationFailed","`%s'",
1202 magnitude_image->filename);
1203 return(MagickFalse);
1205 inverse_pixels=(fftw_complex *) GetVirtualMemoryBlob(inverse_info);
1206 status=InverseFourier(&fourier_info,magnitude_image,phase_image,
1207 inverse_pixels,exception);
1208 if (status != MagickFalse)
1209 status=InverseFourierTransform(&fourier_info,inverse_pixels,fourier_image,
1211 inverse_info=RelinquishVirtualMemory(inverse_info);
1216 MagickExport Image *InverseFourierTransformImage(const Image *magnitude_image,
1217 const Image *phase_image,const MagickBooleanType modulus,
1218 ExceptionInfo *exception)
1223 assert(magnitude_image != (Image *) NULL);
1224 assert(magnitude_image->signature == MagickSignature);
1225 if (magnitude_image->debug != MagickFalse)
1226 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1227 magnitude_image->filename);
1228 if (phase_image == (Image *) NULL)
1230 (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
1231 "TwoOrMoreImagesRequired","`%s'",magnitude_image->filename);
1232 return((Image *) NULL);
1234 #if !defined(MAGICKCORE_FFTW_DELEGATE)
1235 fourier_image=(Image *) NULL;
1237 (void) ThrowMagickException(exception,GetMagickModule(),
1238 MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","'%s' (FFTW)",
1239 magnitude_image->filename);
1242 fourier_image=CloneImage(magnitude_image,magnitude_image->columns,
1243 magnitude_image->rows,MagickFalse,exception);
1244 if (fourier_image != (Image *) NULL)
1251 is_gray=IsImageGray(magnitude_image,exception);
1252 if (is_gray != MagickFalse)
1253 is_gray=IsImageGray(phase_image,exception);
1254 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1255 #pragma omp parallel sections
1258 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1265 if (is_gray != MagickFalse)
1266 thread_status=InverseFourierTransformChannel(magnitude_image,
1267 phase_image,GrayPixelChannel,modulus,fourier_image,exception);
1269 thread_status=InverseFourierTransformChannel(magnitude_image,
1270 phase_image,RedPixelChannel,modulus,fourier_image,exception);
1271 if (thread_status == MagickFalse)
1272 status=thread_status;
1274 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1281 thread_status=MagickTrue;
1282 if (is_gray == MagickFalse)
1283 thread_status=InverseFourierTransformChannel(magnitude_image,
1284 phase_image,GreenPixelChannel,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,BluePixelChannel,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 (magnitude_image->colorspace == CMYKColorspace)
1311 thread_status=InverseFourierTransformChannel(magnitude_image,
1312 phase_image,BlackPixelChannel,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->alpha_trait == BlendPixelTrait)
1325 thread_status=InverseFourierTransformChannel(magnitude_image,
1326 phase_image,AlphaPixelChannel,modulus,fourier_image,exception);
1327 if (thread_status == MagickFalse)
1328 status=thread_status;
1331 if (status == MagickFalse)
1332 fourier_image=DestroyImage(fourier_image);
1337 return(fourier_image);