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/attribute.h"
47 #include "MagickCore/blob.h"
48 #include "MagickCore/cache.h"
49 #include "MagickCore/image.h"
50 #include "MagickCore/image-private.h"
51 #include "MagickCore/list.h"
52 #include "MagickCore/fourier.h"
53 #include "MagickCore/log.h"
54 #include "MagickCore/memory_.h"
55 #include "MagickCore/monitor.h"
56 #include "MagickCore/pixel-accessor.h"
57 #include "MagickCore/property.h"
58 #include "MagickCore/quantum-private.h"
59 #include "MagickCore/resource_.h"
60 #include "MagickCore/thread-private.h"
61 #if defined(MAGICKCORE_FFTW_DELEGATE)
62 #if defined(MAGICKCORE_HAVE_COMPLEX_H)
66 #if !defined(MAGICKCORE_HAVE_CABS)
67 #define cabs(z) (sqrt(z[0]*z[0]+z[1]*z[1]))
69 #if !defined(MAGICKCORE_HAVE_CARG)
70 #define carg(z) (atan2(cimag(z),creal(z)))
72 #if !defined(MAGICKCORE_HAVE_CIMAG)
73 #define cimag(z) (z[1])
75 #if !defined(MAGICKCORE_HAVE_CREAL)
76 #define creal(z) (z[0])
83 typedef struct _FourierInfo
100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
104 % 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 %
108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
110 % ForwardFourierTransformImage() implements the discrete Fourier transform
111 % (DFT) of the image either as a magnitude / phase or real / imaginary image
114 % The format of the ForwadFourierTransformImage method is:
116 % Image *ForwardFourierTransformImage(const Image *image,
117 % const MagickBooleanType modulus,ExceptionInfo *exception)
119 % A description of each parameter follows:
121 % o image: the image.
123 % o modulus: if true, return as transform as a magnitude / phase pair
124 % otherwise a real / imaginary image pair.
126 % o exception: return any errors or warnings in this structure.
130 #if defined(MAGICKCORE_FFTW_DELEGATE)
132 static MagickBooleanType RollFourier(const size_t width,const size_t height,
133 const ssize_t x_offset,const ssize_t y_offset,double *roll_pixels)
151 Move zero frequency (DC, average color) from (0,0) to (width/2,height/2).
153 source_info=AcquireVirtualMemory(height,width*sizeof(*source_pixels));
154 if (source_info == (MemoryInfo *) NULL)
156 source_pixels=(double *) GetVirtualMemoryBlob(source_info);
158 for (y=0L; y < (ssize_t) height; y++)
161 v=((y+y_offset) < 0L) ? y+y_offset+(ssize_t) height : y+y_offset;
163 v=((y+y_offset) > ((ssize_t) height-1L)) ? y+y_offset-(ssize_t) height :
165 for (x=0L; x < (ssize_t) width; x++)
168 u=((x+x_offset) < 0L) ? x+x_offset+(ssize_t) width : x+x_offset;
170 u=((x+x_offset) > ((ssize_t) width-1L)) ? x+x_offset-(ssize_t) width :
172 source_pixels[v*width+u]=roll_pixels[i++];
175 (void) CopyMagickMemory(roll_pixels,source_pixels,height*width*
176 sizeof(*source_pixels));
177 source_info=RelinquishVirtualMemory(source_info);
181 static MagickBooleanType ForwardQuadrantSwap(const size_t width,
182 const size_t height,double *source_pixels,double *forward_pixels)
197 center=(ssize_t) floor((double) width/2L)+1L;
198 status=RollFourier((size_t) center,height,0L,(ssize_t) height/2L,
200 if (status == MagickFalse)
202 for (y=0L; y < (ssize_t) height; y++)
203 for (x=0L; x < (ssize_t) (width/2L-1L); x++)
204 forward_pixels[width*y+x+width/2L]=source_pixels[center*y+x];
205 for (y=1; y < (ssize_t) height; y++)
206 for (x=0L; x < (ssize_t) (width/2L-1L); x++)
207 forward_pixels[width*(height-y)+width/2L-x-1L]=
208 source_pixels[center*y+x+1L];
209 for (x=0L; x < (ssize_t) (width/2L); x++)
210 forward_pixels[-x+width/2L-1L]=forward_pixels[x+width/2L+1L];
214 static void CorrectPhaseLHS(const size_t width,const size_t height,
215 double *fourier_pixels)
223 for (y=0L; y < (ssize_t) height; y++)
224 for (x=0L; x < (ssize_t) (width/2L); x++)
225 fourier_pixels[y*width+x]*=(-1.0);
228 static MagickBooleanType ForwardFourier(const FourierInfo *fourier_info,
229 Image *image,double *magnitude,double *phase,ExceptionInfo *exception)
260 magnitude_image=GetFirstImageInList(image);
261 phase_image=GetNextImageInList(image);
262 if (phase_image == (Image *) NULL)
264 (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
265 "TwoOrMoreImagesRequired","`%s'",image->filename);
269 Create "Fourier Transform" image from constituent arrays.
271 magnitude_info=AcquireVirtualMemory((size_t) fourier_info->height,
272 fourier_info->width*sizeof(*magnitude_pixels));
273 phase_info=AcquireVirtualMemory((size_t) fourier_info->height,
274 fourier_info->width*sizeof(*phase_pixels));
275 if ((magnitude_info == (MemoryInfo *) NULL) ||
276 (phase_info == (MemoryInfo *) NULL))
278 if (phase_info != (MemoryInfo *) NULL)
279 phase_info=RelinquishVirtualMemory(phase_info);
280 if (magnitude_info != (MemoryInfo *) NULL)
281 magnitude_info=RelinquishVirtualMemory(magnitude_info);
282 (void) ThrowMagickException(exception,GetMagickModule(),
283 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
286 magnitude_pixels=(double *) GetVirtualMemoryBlob(magnitude_info);
287 (void) ResetMagickMemory(magnitude_pixels,0,fourier_info->height*
288 fourier_info->width*sizeof(*magnitude_pixels));
289 phase_pixels=(double *) GetVirtualMemoryBlob(phase_info);
290 (void) ResetMagickMemory(phase_pixels,0,fourier_info->height*
291 fourier_info->width*sizeof(*phase_pixels));
292 status=ForwardQuadrantSwap(fourier_info->height,fourier_info->height,
293 magnitude,magnitude_pixels);
294 if (status != MagickFalse)
295 status=ForwardQuadrantSwap(fourier_info->height,fourier_info->height,phase,
297 CorrectPhaseLHS(fourier_info->height,fourier_info->height,phase_pixels);
298 if (fourier_info->modulus != MagickFalse)
301 for (y=0L; y < (ssize_t) fourier_info->height; y++)
302 for (x=0L; x < (ssize_t) fourier_info->width; x++)
304 phase_pixels[i]/=(2.0*MagickPI);
305 phase_pixels[i]+=0.5;
309 magnitude_view=AcquireAuthenticCacheView(magnitude_image,exception);
311 for (y=0L; y < (ssize_t) fourier_info->height; y++)
313 q=GetCacheViewAuthenticPixels(magnitude_view,0L,y,fourier_info->height,1UL,
315 if (q == (Quantum *) NULL)
317 for (x=0L; x < (ssize_t) fourier_info->width; x++)
319 switch (fourier_info->channel)
321 case RedPixelChannel:
324 SetPixelRed(magnitude_image,ClampToQuantum(QuantumRange*
325 magnitude_pixels[i]),q);
328 case GreenPixelChannel:
330 SetPixelGreen(magnitude_image,ClampToQuantum(QuantumRange*
331 magnitude_pixels[i]),q);
334 case BluePixelChannel:
336 SetPixelBlue(magnitude_image,ClampToQuantum(QuantumRange*
337 magnitude_pixels[i]),q);
340 case BlackPixelChannel:
342 SetPixelBlack(magnitude_image,ClampToQuantum(QuantumRange*
343 magnitude_pixels[i]),q);
346 case AlphaPixelChannel:
348 SetPixelAlpha(magnitude_image,ClampToQuantum(QuantumRange*
349 magnitude_pixels[i]),q);
354 q+=GetPixelChannels(magnitude_image);
356 status=SyncCacheViewAuthenticPixels(magnitude_view,exception);
357 if (status == MagickFalse)
360 magnitude_view=DestroyCacheView(magnitude_view);
362 phase_view=AcquireAuthenticCacheView(phase_image,exception);
363 for (y=0L; y < (ssize_t) fourier_info->height; y++)
365 q=GetCacheViewAuthenticPixels(phase_view,0L,y,fourier_info->height,1UL,
367 if (q == (Quantum *) NULL)
369 for (x=0L; x < (ssize_t) fourier_info->width; x++)
371 switch (fourier_info->channel)
373 case RedPixelChannel:
376 SetPixelRed(phase_image,ClampToQuantum(QuantumRange*
380 case GreenPixelChannel:
382 SetPixelGreen(phase_image,ClampToQuantum(QuantumRange*
386 case BluePixelChannel:
388 SetPixelBlue(phase_image,ClampToQuantum(QuantumRange*
392 case BlackPixelChannel:
394 SetPixelBlack(phase_image,ClampToQuantum(QuantumRange*
398 case AlphaPixelChannel:
400 SetPixelAlpha(phase_image,ClampToQuantum(QuantumRange*
406 q+=GetPixelChannels(phase_image);
408 status=SyncCacheViewAuthenticPixels(phase_view,exception);
409 if (status == MagickFalse)
412 phase_view=DestroyCacheView(phase_view);
413 phase_info=RelinquishVirtualMemory(phase_info);
414 magnitude_info=RelinquishVirtualMemory(magnitude_info);
418 static MagickBooleanType ForwardFourierTransform(FourierInfo *fourier_info,
419 const Image *image,double *magnitude_pixels,double *phase_pixels,
420 ExceptionInfo *exception)
439 register const Quantum
450 Generate the forward Fourier transform.
452 source_info=AcquireVirtualMemory((size_t) fourier_info->height,
453 fourier_info->width*sizeof(*source_pixels));
454 if (source_info == (MemoryInfo *) NULL)
456 (void) ThrowMagickException(exception,GetMagickModule(),
457 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
460 source_pixels=(double *) GetVirtualMemoryBlob(source_info);
461 ResetMagickMemory(source_pixels,0,fourier_info->height*fourier_info->width*
462 sizeof(*source_pixels));
464 image_view=AcquireVirtualCacheView(image,exception);
465 for (y=0L; y < (ssize_t) fourier_info->height; y++)
467 p=GetCacheViewVirtualPixels(image_view,0L,y,fourier_info->width,1UL,
469 if (p == (const Quantum *) NULL)
471 for (x=0L; x < (ssize_t) fourier_info->width; x++)
473 switch (fourier_info->channel)
475 case RedPixelChannel:
478 source_pixels[i]=QuantumScale*GetPixelRed(image,p);
481 case GreenPixelChannel:
483 source_pixels[i]=QuantumScale*GetPixelGreen(image,p);
486 case BluePixelChannel:
488 source_pixels[i]=QuantumScale*GetPixelBlue(image,p);
491 case BlackPixelChannel:
493 source_pixels[i]=QuantumScale*GetPixelBlack(image,p);
496 case AlphaPixelChannel:
498 source_pixels[i]=QuantumScale*GetPixelAlpha(image,p);
503 p+=GetPixelChannels(image);
506 image_view=DestroyCacheView(image_view);
507 forward_info=AcquireVirtualMemory((size_t) fourier_info->height,
508 fourier_info->center*sizeof(*forward_pixels));
509 if (forward_info == (MemoryInfo *) NULL)
511 (void) ThrowMagickException(exception,GetMagickModule(),
512 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
513 source_info=(MemoryInfo *) RelinquishVirtualMemory(source_info);
516 forward_pixels=(fftw_complex *) GetVirtualMemoryBlob(forward_info);
517 #if defined(MAGICKCORE_OPENMP_SUPPORT)
518 #pragma omp critical (MagickCore_ForwardFourierTransform)
520 fftw_r2c_plan=fftw_plan_dft_r2c_2d(fourier_info->width,fourier_info->height,
521 source_pixels,forward_pixels,FFTW_ESTIMATE);
522 fftw_execute(fftw_r2c_plan);
523 fftw_destroy_plan(fftw_r2c_plan);
524 source_info=(MemoryInfo *) RelinquishVirtualMemory(source_info);
526 Normalize Fourier transform.
528 n=(double) fourier_info->width*(double) fourier_info->width;
530 for (y=0L; y < (ssize_t) fourier_info->height; y++)
531 for (x=0L; x < (ssize_t) fourier_info->center; x++)
533 #if defined(MAGICKCORE_HAVE_COMPLEX_H)
534 forward_pixels[i]/=n;
536 forward_pixels[i][0]/=n;
537 forward_pixels[i][1]/=n;
542 Generate magnitude and phase (or real and imaginary).
545 if (fourier_info->modulus != MagickFalse)
546 for (y=0L; y < (ssize_t) fourier_info->height; y++)
547 for (x=0L; x < (ssize_t) fourier_info->center; x++)
549 magnitude_pixels[i]=cabs(forward_pixels[i]);
550 phase_pixels[i]=carg(forward_pixels[i]);
554 for (y=0L; y < (ssize_t) fourier_info->height; y++)
555 for (x=0L; x < (ssize_t) fourier_info->center; x++)
557 magnitude_pixels[i]=creal(forward_pixels[i]);
558 phase_pixels[i]=cimag(forward_pixels[i]);
561 forward_info=(MemoryInfo *) RelinquishVirtualMemory(forward_info);
565 static MagickBooleanType ForwardFourierTransformChannel(const Image *image,
566 const PixelChannel channel,const MagickBooleanType modulus,
567 Image *fourier_image,ExceptionInfo *exception)
586 fourier_info.width=image->columns;
587 if ((image->columns != image->rows) || ((image->columns % 2) != 0) ||
588 ((image->rows % 2) != 0))
590 extent=image->columns < image->rows ? image->rows : image->columns;
591 fourier_info.width=(extent & 0x01) == 1 ? extent+1UL : extent;
593 fourier_info.height=fourier_info.width;
594 fourier_info.center=(ssize_t) floor((double) fourier_info.width/2L)+1L;
595 fourier_info.channel=channel;
596 fourier_info.modulus=modulus;
597 magnitude_info=AcquireVirtualMemory((size_t) fourier_info.height,
598 fourier_info.center*sizeof(*magnitude_pixels));
599 phase_info=AcquireVirtualMemory((size_t) fourier_info.height,
600 fourier_info.center*sizeof(*phase_pixels));
601 if ((magnitude_info == (MemoryInfo *) NULL) ||
602 (phase_info == (MemoryInfo *) NULL))
604 if (phase_info != (MemoryInfo *) NULL)
605 phase_info=RelinquishVirtualMemory(phase_info);
606 if (magnitude_info == (MemoryInfo *) NULL)
607 magnitude_info=RelinquishVirtualMemory(magnitude_info);
608 (void) ThrowMagickException(exception,GetMagickModule(),
609 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
612 magnitude_pixels=(double *) GetVirtualMemoryBlob(magnitude_info);
613 phase_pixels=(double *) GetVirtualMemoryBlob(phase_info);
614 status=ForwardFourierTransform(&fourier_info,image,magnitude_pixels,
615 phase_pixels,exception);
616 if (status != MagickFalse)
617 status=ForwardFourier(&fourier_info,fourier_image,magnitude_pixels,
618 phase_pixels,exception);
619 phase_info=RelinquishVirtualMemory(phase_info);
620 magnitude_info=RelinquishVirtualMemory(magnitude_info);
625 MagickExport Image *ForwardFourierTransformImage(const Image *image,
626 const MagickBooleanType modulus,ExceptionInfo *exception)
631 fourier_image=NewImageList();
632 #if !defined(MAGICKCORE_FFTW_DELEGATE)
634 (void) ThrowMagickException(exception,GetMagickModule(),
635 MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","'%s' (FFTW)",
646 width=image->columns;
647 if ((image->columns != image->rows) || ((image->columns % 2) != 0) ||
648 ((image->rows % 2) != 0))
650 extent=image->columns < image->rows ? image->rows : image->columns;
651 width=(extent & 0x01) == 1 ? extent+1UL : extent;
653 magnitude_image=CloneImage(image,width,width,MagickFalse,exception);
654 if (magnitude_image != (Image *) NULL)
659 magnitude_image->storage_class=DirectClass;
660 magnitude_image->depth=32UL;
661 phase_image=CloneImage(image,width,width,MagickFalse,exception);
662 if (phase_image == (Image *) NULL)
663 magnitude_image=DestroyImage(magnitude_image);
670 phase_image->storage_class=DirectClass;
671 phase_image->depth=32UL;
672 AppendImageToList(&fourier_image,magnitude_image);
673 AppendImageToList(&fourier_image,phase_image);
675 is_gray=IsImageGray(image,exception);
676 #if defined(MAGICKCORE_OPENMP_SUPPORT)
677 #pragma omp parallel sections
680 #if defined(MAGICKCORE_OPENMP_SUPPORT)
687 if (is_gray != MagickFalse)
688 thread_status=ForwardFourierTransformChannel(image,
689 GrayPixelChannel,modulus,fourier_image,exception);
691 thread_status=ForwardFourierTransformChannel(image,
692 RedPixelChannel,modulus,fourier_image,exception);
693 if (thread_status == MagickFalse)
694 status=thread_status;
696 #if defined(MAGICKCORE_OPENMP_SUPPORT)
703 thread_status=MagickTrue;
704 if (is_gray == MagickFalse)
705 thread_status=ForwardFourierTransformChannel(image,
706 GreenPixelChannel,modulus,fourier_image,exception);
707 if (thread_status == MagickFalse)
708 status=thread_status;
710 #if defined(MAGICKCORE_OPENMP_SUPPORT)
717 thread_status=MagickTrue;
718 if (is_gray == MagickFalse)
719 thread_status=ForwardFourierTransformChannel(image,
720 BluePixelChannel,modulus,fourier_image,exception);
721 if (thread_status == MagickFalse)
722 status=thread_status;
724 #if defined(MAGICKCORE_OPENMP_SUPPORT)
731 thread_status=MagickTrue;
732 if (image->colorspace == CMYKColorspace)
733 thread_status=ForwardFourierTransformChannel(image,
734 BlackPixelChannel,modulus,fourier_image,exception);
735 if (thread_status == MagickFalse)
736 status=thread_status;
738 #if defined(MAGICKCORE_OPENMP_SUPPORT)
745 thread_status=MagickTrue;
746 if (image->alpha_trait == BlendPixelTrait)
747 thread_status=ForwardFourierTransformChannel(image,
748 AlphaPixelChannel,modulus,fourier_image,exception);
749 if (thread_status == MagickFalse)
750 status=thread_status;
753 if (status == MagickFalse)
754 fourier_image=DestroyImageList(fourier_image);
760 return(fourier_image);
764 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
768 % 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 %
772 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
774 % InverseFourierTransformImage() implements the inverse discrete Fourier
775 % transform (DFT) of the image either as a magnitude / phase or real /
776 % imaginary image pair.
778 % The format of the InverseFourierTransformImage method is:
780 % Image *InverseFourierTransformImage(const Image *magnitude_image,
781 % const Image *phase_image,const MagickBooleanType modulus,
782 % ExceptionInfo *exception)
784 % A description of each parameter follows:
786 % o magnitude_image: the magnitude or real image.
788 % o phase_image: the phase or imaginary image.
790 % o modulus: if true, return transform as a magnitude / phase pair
791 % otherwise a real / imaginary image pair.
793 % o exception: return any errors or warnings in this structure.
797 #if defined(MAGICKCORE_FFTW_DELEGATE)
798 static MagickBooleanType InverseQuadrantSwap(const size_t width,
799 const size_t height,const double *source,double *destination)
811 center=(ssize_t) floor((double) width/2L)+1L;
812 for (y=1L; y < (ssize_t) height; y++)
813 for (x=0L; x < (ssize_t) (width/2L+1L); x++)
814 destination[center*(height-y)-x+width/2L]=source[y*width+x];
815 for (y=0L; y < (ssize_t) height; y++)
816 destination[center*y]=source[y*width+width/2L];
817 for (x=0L; x < center; x++)
818 destination[x]=source[center-x-1L];
819 return(RollFourier(center,height,0L,(ssize_t) height/-2L,destination));
822 static MagickBooleanType InverseFourier(FourierInfo *fourier_info,
823 const Image *magnitude_image,const Image *phase_image,
824 fftw_complex *fourier_pixels,ExceptionInfo *exception)
843 register const Quantum
854 Inverse fourier - read image and break down into a double array.
856 magnitude_info=AcquireVirtualMemory((size_t)fourier_info->height,
857 fourier_info->width*sizeof(*magnitude_pixels));
858 phase_info=AcquireVirtualMemory((size_t) fourier_info->height,
859 fourier_info->width*sizeof(*phase_pixels));
860 inverse_info=AcquireVirtualMemory((size_t) fourier_info->height,
861 fourier_info->center*sizeof(*inverse_pixels));
862 if ((magnitude_info == (MemoryInfo *) NULL) ||
863 (phase_info == (MemoryInfo *) NULL) ||
864 (inverse_info == (MemoryInfo *) NULL))
866 if (magnitude_info != (MemoryInfo *) NULL)
867 magnitude_info=RelinquishVirtualMemory(magnitude_info);
868 if (phase_info != (MemoryInfo *) NULL)
869 phase_info=RelinquishVirtualMemory(phase_info);
870 if (inverse_info != (MemoryInfo *) NULL)
871 inverse_info=RelinquishVirtualMemory(inverse_info);
872 (void) ThrowMagickException(exception,GetMagickModule(),
873 ResourceLimitError,"MemoryAllocationFailed","`%s'",
874 magnitude_image->filename);
877 magnitude_pixels=(double *) GetVirtualMemoryBlob(magnitude_info);
878 phase_pixels=(double *) GetVirtualMemoryBlob(phase_info);
879 inverse_pixels=(double *) GetVirtualMemoryBlob(inverse_info);
881 magnitude_view=AcquireVirtualCacheView(magnitude_image,exception);
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 Quantum *) NULL)
888 for (x=0L; x < (ssize_t) fourier_info->width; x++)
890 switch (fourier_info->channel)
892 case RedPixelChannel:
895 magnitude_pixels[i]=QuantumScale*GetPixelRed(magnitude_image,p);
898 case GreenPixelChannel:
900 magnitude_pixels[i]=QuantumScale*GetPixelGreen(magnitude_image,p);
903 case BluePixelChannel:
905 magnitude_pixels[i]=QuantumScale*GetPixelBlue(magnitude_image,p);
908 case BlackPixelChannel:
910 magnitude_pixels[i]=QuantumScale*GetPixelBlack(magnitude_image,p);
913 case AlphaPixelChannel:
915 magnitude_pixels[i]=QuantumScale*GetPixelAlpha(magnitude_image,p);
920 p+=GetPixelChannels(magnitude_image);
923 magnitude_view=DestroyCacheView(magnitude_view);
924 status=InverseQuadrantSwap(fourier_info->width,fourier_info->height,
925 magnitude_pixels,inverse_pixels);
926 (void) CopyMagickMemory(magnitude_pixels,inverse_pixels,fourier_info->height*
927 fourier_info->center*sizeof(*magnitude_pixels));
929 phase_view=AcquireVirtualCacheView(phase_image,exception);
930 for (y=0L; y < (ssize_t) fourier_info->height; y++)
932 p=GetCacheViewVirtualPixels(phase_view,0,y,fourier_info->width,1,
934 if (p == (const Quantum *) NULL)
936 for (x=0L; x < (ssize_t) fourier_info->width; x++)
938 switch (fourier_info->channel)
940 case RedPixelChannel:
943 phase_pixels[i]=QuantumScale*GetPixelRed(phase_image,p);
946 case GreenPixelChannel:
948 phase_pixels[i]=QuantumScale*GetPixelGreen(phase_image,p);
951 case BluePixelChannel:
953 phase_pixels[i]=QuantumScale*GetPixelBlue(phase_image,p);
956 case BlackPixelChannel:
958 phase_pixels[i]=QuantumScale*GetPixelBlack(phase_image,p);
961 case AlphaPixelChannel:
963 phase_pixels[i]=QuantumScale*GetPixelAlpha(phase_image,p);
968 p+=GetPixelChannels(phase_image);
971 if (fourier_info->modulus != MagickFalse)
974 for (y=0L; y < (ssize_t) fourier_info->height; y++)
975 for (x=0L; x < (ssize_t) fourier_info->width; x++)
977 phase_pixels[i]-=0.5;
978 phase_pixels[i]*=(2.0*MagickPI);
982 phase_view=DestroyCacheView(phase_view);
983 CorrectPhaseLHS(fourier_info->width,fourier_info->width,phase_pixels);
984 if (status != MagickFalse)
985 status=InverseQuadrantSwap(fourier_info->width,fourier_info->height,
986 phase_pixels,inverse_pixels);
987 (void) CopyMagickMemory(phase_pixels,inverse_pixels,fourier_info->height*
988 fourier_info->center*sizeof(*phase_pixels));
989 inverse_info=RelinquishVirtualMemory(inverse_info);
994 if (fourier_info->modulus != MagickFalse)
995 for (y=0L; y < (ssize_t) fourier_info->height; y++)
996 for (x=0L; x < (ssize_t) fourier_info->center; x++)
998 #if defined(MAGICKCORE_HAVE_COMPLEX_H)
999 fourier_pixels[i]=magnitude_pixels[i]*cos(phase_pixels[i])+I*
1000 magnitude_pixels[i]*sin(phase_pixels[i]);
1002 fourier_pixels[i][0]=magnitude_pixels[i]*cos(phase_pixels[i]);
1003 fourier_pixels[i][1]=magnitude_pixels[i]*sin(phase_pixels[i]);
1008 for (y=0L; y < (ssize_t) fourier_info->height; y++)
1009 for (x=0L; x < (ssize_t) fourier_info->center; x++)
1011 #if defined(MAGICKCORE_HAVE_COMPLEX_H)
1012 fourier_pixels[i]=magnitude_pixels[i]+I*phase_pixels[i];
1014 fourier_pixels[i][0]=magnitude_pixels[i];
1015 fourier_pixels[i][1]=phase_pixels[i];
1019 magnitude_info=RelinquishVirtualMemory(magnitude_info);
1020 phase_info=RelinquishVirtualMemory(phase_info);
1024 static MagickBooleanType InverseFourierTransform(FourierInfo *fourier_info,
1025 fftw_complex *fourier_pixels,Image *image,ExceptionInfo *exception)
1049 source_info=AcquireVirtualMemory((size_t) fourier_info->height,
1050 fourier_info->width*sizeof(*source_pixels));
1051 if (source_info == (MemoryInfo *) NULL)
1053 (void) ThrowMagickException(exception,GetMagickModule(),
1054 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
1055 return(MagickFalse);
1057 source_pixels=(double *) GetVirtualMemoryBlob(source_info);
1058 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1059 #pragma omp critical (MagickCore_InverseFourierTransform)
1062 fftw_c2r_plan=fftw_plan_dft_c2r_2d(fourier_info->width,fourier_info->height,
1063 fourier_pixels,source_pixels,FFTW_ESTIMATE);
1064 fftw_execute(fftw_c2r_plan);
1065 fftw_destroy_plan(fftw_c2r_plan);
1068 image_view=AcquireAuthenticCacheView(image,exception);
1069 for (y=0L; y < (ssize_t) fourier_info->height; y++)
1071 if (y >= (ssize_t) image->rows)
1073 q=GetCacheViewAuthenticPixels(image_view,0L,y,fourier_info->width >
1074 image->columns ? image->columns : fourier_info->width,1UL,exception);
1075 if (q == (Quantum *) NULL)
1077 for (x=0L; x < (ssize_t) fourier_info->width; x++)
1079 if (x < (ssize_t) image->columns)
1080 switch (fourier_info->channel)
1082 case RedPixelChannel:
1085 SetPixelRed(image,ClampToQuantum(QuantumRange*source_pixels[i]),q);
1088 case GreenPixelChannel:
1090 SetPixelGreen(image,ClampToQuantum(QuantumRange*source_pixels[i]),
1094 case BluePixelChannel:
1096 SetPixelBlue(image,ClampToQuantum(QuantumRange*source_pixels[i]),
1100 case BlackPixelChannel:
1102 SetPixelBlack(image,ClampToQuantum(QuantumRange*source_pixels[i]),
1106 case AlphaPixelChannel:
1108 SetPixelAlpha(image,ClampToQuantum(QuantumRange*source_pixels[i]),
1114 q+=GetPixelChannels(image);
1116 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1119 image_view=DestroyCacheView(image_view);
1120 source_info=RelinquishVirtualMemory(source_info);
1124 static MagickBooleanType InverseFourierTransformChannel(
1125 const Image *magnitude_image,const Image *phase_image,
1126 const PixelChannel channel,const MagickBooleanType modulus,
1127 Image *fourier_image,ExceptionInfo *exception)
1144 fourier_info.width=magnitude_image->columns;
1145 if ((magnitude_image->columns != magnitude_image->rows) ||
1146 ((magnitude_image->columns % 2) != 0) ||
1147 ((magnitude_image->rows % 2) != 0))
1149 extent=magnitude_image->columns < magnitude_image->rows ?
1150 magnitude_image->rows : magnitude_image->columns;
1151 fourier_info.width=(extent & 0x01) == 1 ? extent+1UL : extent;
1153 fourier_info.height=fourier_info.width;
1154 fourier_info.center=(ssize_t) floor((double) fourier_info.width/2L)+1L;
1155 fourier_info.channel=channel;
1156 fourier_info.modulus=modulus;
1157 inverse_info=AcquireVirtualMemory((size_t) fourier_info.height,
1158 fourier_info.center*sizeof(*inverse_pixels));
1159 if (inverse_info == (MemoryInfo *) NULL)
1161 (void) ThrowMagickException(exception,GetMagickModule(),
1162 ResourceLimitError,"MemoryAllocationFailed","`%s'",
1163 magnitude_image->filename);
1164 return(MagickFalse);
1166 inverse_pixels=(fftw_complex *) GetVirtualMemoryBlob(inverse_info);
1167 status=InverseFourier(&fourier_info,magnitude_image,phase_image,
1168 inverse_pixels,exception);
1169 if (status != MagickFalse)
1170 status=InverseFourierTransform(&fourier_info,inverse_pixels,fourier_image,
1172 inverse_info=RelinquishVirtualMemory(inverse_info);
1177 MagickExport Image *InverseFourierTransformImage(const Image *magnitude_image,
1178 const Image *phase_image,const MagickBooleanType modulus,
1179 ExceptionInfo *exception)
1184 assert(magnitude_image != (Image *) NULL);
1185 assert(magnitude_image->signature == MagickSignature);
1186 if (magnitude_image->debug != MagickFalse)
1187 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1188 magnitude_image->filename);
1189 if (phase_image == (Image *) NULL)
1191 (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
1192 "TwoOrMoreImagesRequired","`%s'",magnitude_image->filename);
1193 return((Image *) NULL);
1195 #if !defined(MAGICKCORE_FFTW_DELEGATE)
1196 fourier_image=(Image *) NULL;
1198 (void) ThrowMagickException(exception,GetMagickModule(),
1199 MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","'%s' (FFTW)",
1200 magnitude_image->filename);
1203 fourier_image=CloneImage(magnitude_image,magnitude_image->columns,
1204 magnitude_image->rows,MagickFalse,exception);
1205 if (fourier_image != (Image *) NULL)
1212 is_gray=IsImageGray(magnitude_image,exception);
1213 if (is_gray != MagickFalse)
1214 is_gray=IsImageGray(phase_image,exception);
1215 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1216 #pragma omp parallel sections
1219 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1226 if (is_gray != MagickFalse)
1227 thread_status=InverseFourierTransformChannel(magnitude_image,
1228 phase_image,GrayPixelChannel,modulus,fourier_image,exception);
1230 thread_status=InverseFourierTransformChannel(magnitude_image,
1231 phase_image,RedPixelChannel,modulus,fourier_image,exception);
1232 if (thread_status == MagickFalse)
1233 status=thread_status;
1235 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1242 thread_status=MagickTrue;
1243 if (is_gray == MagickFalse)
1244 thread_status=InverseFourierTransformChannel(magnitude_image,
1245 phase_image,GreenPixelChannel,modulus,fourier_image,exception);
1246 if (thread_status == MagickFalse)
1247 status=thread_status;
1249 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1256 thread_status=MagickTrue;
1257 if (is_gray == MagickFalse)
1258 thread_status=InverseFourierTransformChannel(magnitude_image,
1259 phase_image,BluePixelChannel,modulus,fourier_image,exception);
1260 if (thread_status == MagickFalse)
1261 status=thread_status;
1263 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1270 thread_status=MagickTrue;
1271 if (magnitude_image->colorspace == CMYKColorspace)
1272 thread_status=InverseFourierTransformChannel(magnitude_image,
1273 phase_image,BlackPixelChannel,modulus,fourier_image,exception);
1274 if (thread_status == MagickFalse)
1275 status=thread_status;
1277 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1284 thread_status=MagickTrue;
1285 if (magnitude_image->alpha_trait == BlendPixelTrait)
1286 thread_status=InverseFourierTransformChannel(magnitude_image,
1287 phase_image,AlphaPixelChannel,modulus,fourier_image,exception);
1288 if (thread_status == MagickFalse)
1289 status=thread_status;
1292 if (status == MagickFalse)
1293 fourier_image=DestroyImage(fourier_image);
1298 return(fourier_image);