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-2017 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/monitor-private.h"
58 #include "MagickCore/pixel-accessor.h"
59 #include "MagickCore/pixel-private.h"
60 #include "MagickCore/property.h"
61 #include "MagickCore/quantum-private.h"
62 #include "MagickCore/resource_.h"
63 #include "MagickCore/string-private.h"
64 #include "MagickCore/thread-private.h"
65 #if defined(MAGICKCORE_FFTW_DELEGATE)
66 #if defined(MAGICKCORE_HAVE_COMPLEX_H)
70 #if !defined(MAGICKCORE_HAVE_CABS)
71 #define cabs(z) (sqrt(z[0]*z[0]+z[1]*z[1]))
73 #if !defined(MAGICKCORE_HAVE_CARG)
74 #define carg(z) (atan2(cimag(z),creal(z)))
76 #if !defined(MAGICKCORE_HAVE_CIMAG)
77 #define cimag(z) (z[1])
79 #if !defined(MAGICKCORE_HAVE_CREAL)
80 #define creal(z) (z[0])
87 typedef struct _FourierInfo
104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
108 % C o m p l e x I m a g e s %
112 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
114 % ComplexImages() performs complex mathematics on an image sequence.
116 % The format of the ComplexImages method is:
118 % MagickBooleanType ComplexImages(Image *images,const ComplexOperator op,
119 % ExceptionInfo *exception)
121 % A description of each parameter follows:
123 % o image: the image.
125 % o op: A complex operator.
127 % o exception: return any errors or warnings in this structure.
130 MagickExport Image *ComplexImages(const Image *images,const ComplexOperator op,
131 ExceptionInfo *exception)
133 #define ComplexImageTag "Complex/Image"
170 assert(images != (Image *) NULL);
171 assert(images->signature == MagickCoreSignature);
172 if (images->debug != MagickFalse)
173 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
174 assert(exception != (ExceptionInfo *) NULL);
175 assert(exception->signature == MagickCoreSignature);
176 if (images->next == (Image *) NULL)
178 (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
179 "ImageSequenceRequired","`%s'",images->filename);
180 return((Image *) NULL);
182 image=CloneImage(images,images->columns,images->rows,MagickTrue,exception);
183 if (image == (Image *) NULL)
184 return((Image *) NULL);
185 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
187 image=DestroyImageList(image);
191 complex_images=NewImageList();
192 AppendImageToList(&complex_images,image);
193 image=CloneImage(images,images->columns,images->rows,MagickTrue,exception);
194 if (image == (Image *) NULL)
196 complex_images=DestroyImageList(complex_images);
197 return(complex_images);
199 AppendImageToList(&complex_images,image);
201 Apply complex mathematics to image pixels.
203 artifact=GetImageArtifact(image,"complex:snr");
205 if (artifact != (const char *) NULL)
206 snr=StringToDouble(artifact,(char **) NULL);
208 Ai_image=images->next;
210 Bi_image=images->next;
211 if ((images->next->next != (Image *) NULL) &&
212 (images->next->next->next != (Image *) NULL))
214 Br_image=images->next->next;
215 Bi_image=images->next->next->next;
217 Cr_image=complex_images;
218 Ci_image=complex_images->next;
219 Ar_view=AcquireVirtualCacheView(Ar_image,exception);
220 Ai_view=AcquireVirtualCacheView(Ai_image,exception);
221 Br_view=AcquireVirtualCacheView(Br_image,exception);
222 Bi_view=AcquireVirtualCacheView(Bi_image,exception);
223 Cr_view=AcquireAuthenticCacheView(Cr_image,exception);
224 Ci_view=AcquireAuthenticCacheView(Ci_image,exception);
227 #if defined(MAGICKCORE_OPENMP_SUPPORT)
228 #pragma omp parallel for schedule(static,4) shared(progress,status) \
229 magick_threads(images,complex_images,images->rows,1L)
231 for (y=0; y < (ssize_t) images->rows; y++)
233 register const Quantum
246 if (status == MagickFalse)
248 Ar=GetCacheViewVirtualPixels(Ar_view,0,y,Ar_image->columns,1,exception);
249 Ai=GetCacheViewVirtualPixels(Ai_view,0,y,Ai_image->columns,1,exception);
250 Br=GetCacheViewVirtualPixels(Br_view,0,y,Br_image->columns,1,exception);
251 Bi=GetCacheViewVirtualPixels(Bi_view,0,y,Bi_image->columns,1,exception);
252 Cr=QueueCacheViewAuthenticPixels(Cr_view,0,y,Cr_image->columns,1,exception);
253 Ci=QueueCacheViewAuthenticPixels(Ci_view,0,y,Ci_image->columns,1,exception);
254 if ((Ar == (const Quantum *) NULL) || (Ai == (const Quantum *) NULL) ||
255 (Br == (const Quantum *) NULL) || (Bi == (const Quantum *) NULL) ||
256 (Cr == (Quantum *) NULL) || (Ci == (Quantum *) NULL))
261 for (x=0; x < (ssize_t) images->columns; x++)
266 for (i=0; i < (ssize_t) GetPixelChannels(images); i++)
270 case AddComplexOperator:
276 case ConjugateComplexOperator:
283 case DivideComplexOperator:
288 gamma=PerceptibleReciprocal(Br[i]*Br[i]+Bi[i]*Bi[i]+snr);
289 Cr[i]=gamma*(Ar[i]*Br[i]+Ai[i]*Bi[i]);
290 Ci[i]=gamma*(Ai[i]*Br[i]-Ar[i]*Bi[i]);
293 case MagnitudePhaseComplexOperator:
295 Cr[i]=sqrt(Ar[i]*Ar[i]+Ai[i]*Ai[i]);
296 Ci[i]=atan2(Ai[i],Ar[i])/(2.0*MagickPI)+0.5;
299 case MultiplyComplexOperator:
301 Cr[i]=QuantumScale*(Ar[i]*Br[i]-Ai[i]*Bi[i]);
302 Ci[i]=QuantumScale*(Ai[i]*Br[i]+Ar[i]*Bi[i]);
305 case RealImaginaryComplexOperator:
307 Cr[i]=Ar[i]*cos(2.0*MagickPI*(Ai[i]-0.5));
308 Ci[i]=Ar[i]*sin(2.0*MagickPI*(Ai[i]-0.5));
311 case SubtractComplexOperator:
319 Ar+=GetPixelChannels(Ar_image);
320 Ai+=GetPixelChannels(Ai_image);
321 Br+=GetPixelChannels(Br_image);
322 Bi+=GetPixelChannels(Bi_image);
323 Cr+=GetPixelChannels(Cr_image);
324 Ci+=GetPixelChannels(Ci_image);
326 if (SyncCacheViewAuthenticPixels(Ci_view,exception) == MagickFalse)
328 if (SyncCacheViewAuthenticPixels(Cr_view,exception) == MagickFalse)
330 if (images->progress_monitor != (MagickProgressMonitor) NULL)
335 #if defined(MAGICKCORE_OPENMP_SUPPORT)
336 #pragma omp critical (MagickCore_ComplexImages)
338 proceed=SetImageProgress(images,ComplexImageTag,progress++,
340 if (proceed == MagickFalse)
344 Cr_view=DestroyCacheView(Cr_view);
345 Ci_view=DestroyCacheView(Ci_view);
346 Br_view=DestroyCacheView(Br_view);
347 Bi_view=DestroyCacheView(Bi_view);
348 Ar_view=DestroyCacheView(Ar_view);
349 Ai_view=DestroyCacheView(Ai_view);
350 if (status == MagickFalse)
351 complex_images=DestroyImageList(complex_images);
352 return(complex_images);
356 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
360 % 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 %
364 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
366 % ForwardFourierTransformImage() implements the discrete Fourier transform
367 % (DFT) of the image either as a magnitude / phase or real / imaginary image
370 % The format of the ForwadFourierTransformImage method is:
372 % Image *ForwardFourierTransformImage(const Image *image,
373 % const MagickBooleanType modulus,ExceptionInfo *exception)
375 % A description of each parameter follows:
377 % o image: the image.
379 % o modulus: if true, return as transform as a magnitude / phase pair
380 % otherwise a real / imaginary image pair.
382 % o exception: return any errors or warnings in this structure.
386 #if defined(MAGICKCORE_FFTW_DELEGATE)
388 static MagickBooleanType RollFourier(const size_t width,const size_t height,
389 const ssize_t x_offset,const ssize_t y_offset,double *roll_pixels)
407 Move zero frequency (DC, average color) from (0,0) to (width/2,height/2).
409 source_info=AcquireVirtualMemory(width,height*sizeof(*source_pixels));
410 if (source_info == (MemoryInfo *) NULL)
412 source_pixels=(double *) GetVirtualMemoryBlob(source_info);
414 for (y=0L; y < (ssize_t) height; y++)
417 v=((y+y_offset) < 0L) ? y+y_offset+(ssize_t) height : y+y_offset;
419 v=((y+y_offset) > ((ssize_t) height-1L)) ? y+y_offset-(ssize_t) height :
421 for (x=0L; x < (ssize_t) width; x++)
424 u=((x+x_offset) < 0L) ? x+x_offset+(ssize_t) width : x+x_offset;
426 u=((x+x_offset) > ((ssize_t) width-1L)) ? x+x_offset-(ssize_t) width :
428 source_pixels[v*width+u]=roll_pixels[i++];
431 (void) CopyMagickMemory(roll_pixels,source_pixels,height*width*
432 sizeof(*source_pixels));
433 source_info=RelinquishVirtualMemory(source_info);
437 static MagickBooleanType ForwardQuadrantSwap(const size_t width,
438 const size_t height,double *source_pixels,double *forward_pixels)
453 center=(ssize_t) (width/2L)+1L;
454 status=RollFourier((size_t) center,height,0L,(ssize_t) height/2L,
456 if (status == MagickFalse)
458 for (y=0L; y < (ssize_t) height; y++)
459 for (x=0L; x < (ssize_t) (width/2L); x++)
460 forward_pixels[y*width+x+width/2L]=source_pixels[y*center+x];
461 for (y=1; y < (ssize_t) height; y++)
462 for (x=0L; x < (ssize_t) (width/2L); x++)
463 forward_pixels[(height-y)*width+width/2L-x-1L]=
464 source_pixels[y*center+x+1L];
465 for (x=0L; x < (ssize_t) (width/2L); x++)
466 forward_pixels[width/2L-x-1L]=source_pixels[x+1L];
470 static void CorrectPhaseLHS(const size_t width,const size_t height,
471 double *fourier_pixels)
479 for (y=0L; y < (ssize_t) height; y++)
480 for (x=0L; x < (ssize_t) (width/2L); x++)
481 fourier_pixels[y*width+x]*=(-1.0);
484 static MagickBooleanType ForwardFourier(const FourierInfo *fourier_info,
485 Image *image,double *magnitude,double *phase,ExceptionInfo *exception)
516 magnitude_image=GetFirstImageInList(image);
517 phase_image=GetNextImageInList(image);
518 if (phase_image == (Image *) NULL)
520 (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
521 "ImageSequenceRequired","`%s'",image->filename);
525 Create "Fourier Transform" image from constituent arrays.
527 magnitude_info=AcquireVirtualMemory((size_t) fourier_info->width,
528 fourier_info->height*sizeof(*magnitude_pixels));
529 phase_info=AcquireVirtualMemory((size_t) fourier_info->width,
530 fourier_info->height*sizeof(*phase_pixels));
531 if ((magnitude_info == (MemoryInfo *) NULL) ||
532 (phase_info == (MemoryInfo *) NULL))
534 if (phase_info != (MemoryInfo *) NULL)
535 phase_info=RelinquishVirtualMemory(phase_info);
536 if (magnitude_info != (MemoryInfo *) NULL)
537 magnitude_info=RelinquishVirtualMemory(magnitude_info);
538 (void) ThrowMagickException(exception,GetMagickModule(),
539 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
542 magnitude_pixels=(double *) GetVirtualMemoryBlob(magnitude_info);
543 (void) ResetMagickMemory(magnitude_pixels,0,fourier_info->width*
544 fourier_info->height*sizeof(*magnitude_pixels));
545 phase_pixels=(double *) GetVirtualMemoryBlob(phase_info);
546 (void) ResetMagickMemory(phase_pixels,0,fourier_info->width*
547 fourier_info->height*sizeof(*phase_pixels));
548 status=ForwardQuadrantSwap(fourier_info->width,fourier_info->height,
549 magnitude,magnitude_pixels);
550 if (status != MagickFalse)
551 status=ForwardQuadrantSwap(fourier_info->width,fourier_info->height,phase,
553 CorrectPhaseLHS(fourier_info->width,fourier_info->height,phase_pixels);
554 if (fourier_info->modulus != MagickFalse)
557 for (y=0L; y < (ssize_t) fourier_info->height; y++)
558 for (x=0L; x < (ssize_t) fourier_info->width; x++)
560 phase_pixels[i]/=(2.0*MagickPI);
561 phase_pixels[i]+=0.5;
565 magnitude_view=AcquireAuthenticCacheView(magnitude_image,exception);
567 for (y=0L; y < (ssize_t) fourier_info->height; y++)
569 q=GetCacheViewAuthenticPixels(magnitude_view,0L,y,fourier_info->width,1UL,
571 if (q == (Quantum *) NULL)
573 for (x=0L; x < (ssize_t) fourier_info->width; x++)
575 switch (fourier_info->channel)
577 case RedPixelChannel:
580 SetPixelRed(magnitude_image,ClampToQuantum(QuantumRange*
581 magnitude_pixels[i]),q);
584 case GreenPixelChannel:
586 SetPixelGreen(magnitude_image,ClampToQuantum(QuantumRange*
587 magnitude_pixels[i]),q);
590 case BluePixelChannel:
592 SetPixelBlue(magnitude_image,ClampToQuantum(QuantumRange*
593 magnitude_pixels[i]),q);
596 case BlackPixelChannel:
598 SetPixelBlack(magnitude_image,ClampToQuantum(QuantumRange*
599 magnitude_pixels[i]),q);
602 case AlphaPixelChannel:
604 SetPixelAlpha(magnitude_image,ClampToQuantum(QuantumRange*
605 magnitude_pixels[i]),q);
610 q+=GetPixelChannels(magnitude_image);
612 status=SyncCacheViewAuthenticPixels(magnitude_view,exception);
613 if (status == MagickFalse)
616 magnitude_view=DestroyCacheView(magnitude_view);
618 phase_view=AcquireAuthenticCacheView(phase_image,exception);
619 for (y=0L; y < (ssize_t) fourier_info->height; y++)
621 q=GetCacheViewAuthenticPixels(phase_view,0L,y,fourier_info->width,1UL,
623 if (q == (Quantum *) NULL)
625 for (x=0L; x < (ssize_t) fourier_info->width; x++)
627 switch (fourier_info->channel)
629 case RedPixelChannel:
632 SetPixelRed(phase_image,ClampToQuantum(QuantumRange*
636 case GreenPixelChannel:
638 SetPixelGreen(phase_image,ClampToQuantum(QuantumRange*
642 case BluePixelChannel:
644 SetPixelBlue(phase_image,ClampToQuantum(QuantumRange*
648 case BlackPixelChannel:
650 SetPixelBlack(phase_image,ClampToQuantum(QuantumRange*
654 case AlphaPixelChannel:
656 SetPixelAlpha(phase_image,ClampToQuantum(QuantumRange*
662 q+=GetPixelChannels(phase_image);
664 status=SyncCacheViewAuthenticPixels(phase_view,exception);
665 if (status == MagickFalse)
668 phase_view=DestroyCacheView(phase_view);
669 phase_info=RelinquishVirtualMemory(phase_info);
670 magnitude_info=RelinquishVirtualMemory(magnitude_info);
674 static MagickBooleanType ForwardFourierTransform(FourierInfo *fourier_info,
675 const Image *image,double *magnitude_pixels,double *phase_pixels,
676 ExceptionInfo *exception)
697 register const Quantum
708 Generate the forward Fourier transform.
710 source_info=AcquireVirtualMemory((size_t) fourier_info->width,
711 fourier_info->height*sizeof(*source_pixels));
712 if (source_info == (MemoryInfo *) NULL)
714 (void) ThrowMagickException(exception,GetMagickModule(),
715 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
718 source_pixels=(double *) GetVirtualMemoryBlob(source_info);
719 ResetMagickMemory(source_pixels,0,fourier_info->width*fourier_info->height*
720 sizeof(*source_pixels));
722 image_view=AcquireVirtualCacheView(image,exception);
723 for (y=0L; y < (ssize_t) fourier_info->height; y++)
725 p=GetCacheViewVirtualPixels(image_view,0L,y,fourier_info->width,1UL,
727 if (p == (const Quantum *) NULL)
729 for (x=0L; x < (ssize_t) fourier_info->width; x++)
731 switch (fourier_info->channel)
733 case RedPixelChannel:
736 source_pixels[i]=QuantumScale*GetPixelRed(image,p);
739 case GreenPixelChannel:
741 source_pixels[i]=QuantumScale*GetPixelGreen(image,p);
744 case BluePixelChannel:
746 source_pixels[i]=QuantumScale*GetPixelBlue(image,p);
749 case BlackPixelChannel:
751 source_pixels[i]=QuantumScale*GetPixelBlack(image,p);
754 case AlphaPixelChannel:
756 source_pixels[i]=QuantumScale*GetPixelAlpha(image,p);
761 p+=GetPixelChannels(image);
764 image_view=DestroyCacheView(image_view);
765 forward_info=AcquireVirtualMemory((size_t) fourier_info->width,
766 (fourier_info->height/2+1)*sizeof(*forward_pixels));
767 if (forward_info == (MemoryInfo *) NULL)
769 (void) ThrowMagickException(exception,GetMagickModule(),
770 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
771 source_info=(MemoryInfo *) RelinquishVirtualMemory(source_info);
774 forward_pixels=(fftw_complex *) GetVirtualMemoryBlob(forward_info);
775 #if defined(MAGICKCORE_OPENMP_SUPPORT)
776 #pragma omp critical (MagickCore_ForwardFourierTransform)
778 fftw_r2c_plan=fftw_plan_dft_r2c_2d(fourier_info->width,fourier_info->height,
779 source_pixels,forward_pixels,FFTW_ESTIMATE);
780 fftw_execute_dft_r2c(fftw_r2c_plan,source_pixels,forward_pixels);
781 fftw_destroy_plan(fftw_r2c_plan);
782 source_info=(MemoryInfo *) RelinquishVirtualMemory(source_info);
783 value=GetImageArtifact(image,"fourier:normalize");
784 if ((value == (const char *) NULL) || (LocaleCompare(value,"forward") == 0))
790 Normalize fourier transform.
793 gamma=PerceptibleReciprocal((double) fourier_info->width*
794 fourier_info->height);
795 for (y=0L; y < (ssize_t) fourier_info->height; y++)
796 for (x=0L; x < (ssize_t) fourier_info->center; x++)
798 #if defined(MAGICKCORE_HAVE_COMPLEX_H)
799 forward_pixels[i]*=gamma;
801 forward_pixels[i][0]*=gamma;
802 forward_pixels[i][1]*=gamma;
808 Generate magnitude and phase (or real and imaginary).
811 if (fourier_info->modulus != MagickFalse)
812 for (y=0L; y < (ssize_t) fourier_info->height; y++)
813 for (x=0L; x < (ssize_t) fourier_info->center; x++)
815 magnitude_pixels[i]=cabs(forward_pixels[i]);
816 phase_pixels[i]=carg(forward_pixels[i]);
820 for (y=0L; y < (ssize_t) fourier_info->height; y++)
821 for (x=0L; x < (ssize_t) fourier_info->center; x++)
823 magnitude_pixels[i]=creal(forward_pixels[i]);
824 phase_pixels[i]=cimag(forward_pixels[i]);
827 forward_info=(MemoryInfo *) RelinquishVirtualMemory(forward_info);
831 static MagickBooleanType ForwardFourierTransformChannel(const Image *image,
832 const PixelChannel channel,const MagickBooleanType modulus,
833 Image *fourier_image,ExceptionInfo *exception)
849 fourier_info.width=image->columns;
850 fourier_info.height=image->rows;
851 if ((image->columns != image->rows) || ((image->columns % 2) != 0) ||
852 ((image->rows % 2) != 0))
854 size_t extent=image->columns < image->rows ? image->rows : image->columns;
855 fourier_info.width=(extent & 0x01) == 1 ? extent+1UL : extent;
857 fourier_info.height=fourier_info.width;
858 fourier_info.center=(ssize_t) (fourier_info.width/2L)+1L;
859 fourier_info.channel=channel;
860 fourier_info.modulus=modulus;
861 magnitude_info=AcquireVirtualMemory((size_t) fourier_info.width,
862 (fourier_info.height/2+1)*sizeof(*magnitude_pixels));
863 phase_info=AcquireVirtualMemory((size_t) fourier_info.width,
864 (fourier_info.height/2+1)*sizeof(*phase_pixels));
865 if ((magnitude_info == (MemoryInfo *) NULL) ||
866 (phase_info == (MemoryInfo *) NULL))
868 if (phase_info != (MemoryInfo *) NULL)
869 phase_info=RelinquishVirtualMemory(phase_info);
870 if (magnitude_info == (MemoryInfo *) NULL)
871 magnitude_info=RelinquishVirtualMemory(magnitude_info);
872 (void) ThrowMagickException(exception,GetMagickModule(),
873 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
876 magnitude_pixels=(double *) GetVirtualMemoryBlob(magnitude_info);
877 phase_pixels=(double *) GetVirtualMemoryBlob(phase_info);
878 status=ForwardFourierTransform(&fourier_info,image,magnitude_pixels,
879 phase_pixels,exception);
880 if (status != MagickFalse)
881 status=ForwardFourier(&fourier_info,fourier_image,magnitude_pixels,
882 phase_pixels,exception);
883 phase_info=RelinquishVirtualMemory(phase_info);
884 magnitude_info=RelinquishVirtualMemory(magnitude_info);
889 MagickExport Image *ForwardFourierTransformImage(const Image *image,
890 const MagickBooleanType modulus,ExceptionInfo *exception)
895 fourier_image=NewImageList();
896 #if !defined(MAGICKCORE_FFTW_DELEGATE)
898 (void) ThrowMagickException(exception,GetMagickModule(),
899 MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","`%s' (FFTW)",
910 width=image->columns;
912 if ((image->columns != image->rows) || ((image->columns % 2) != 0) ||
913 ((image->rows % 2) != 0))
915 size_t extent=image->columns < image->rows ? image->rows :
917 width=(extent & 0x01) == 1 ? extent+1UL : extent;
920 magnitude_image=CloneImage(image,width,height,MagickTrue,exception);
921 if (magnitude_image != (Image *) NULL)
926 magnitude_image->storage_class=DirectClass;
927 magnitude_image->depth=32UL;
928 phase_image=CloneImage(image,width,height,MagickTrue,exception);
929 if (phase_image == (Image *) NULL)
930 magnitude_image=DestroyImage(magnitude_image);
937 phase_image->storage_class=DirectClass;
938 phase_image->depth=32UL;
939 AppendImageToList(&fourier_image,magnitude_image);
940 AppendImageToList(&fourier_image,phase_image);
942 is_gray=IsImageGray(image);
943 #if defined(MAGICKCORE_OPENMP_SUPPORT)
944 #pragma omp parallel sections
947 #if defined(MAGICKCORE_OPENMP_SUPPORT)
954 if (is_gray != MagickFalse)
955 thread_status=ForwardFourierTransformChannel(image,
956 GrayPixelChannel,modulus,fourier_image,exception);
958 thread_status=ForwardFourierTransformChannel(image,
959 RedPixelChannel,modulus,fourier_image,exception);
960 if (thread_status == MagickFalse)
961 status=thread_status;
963 #if defined(MAGICKCORE_OPENMP_SUPPORT)
970 thread_status=MagickTrue;
971 if (is_gray == MagickFalse)
972 thread_status=ForwardFourierTransformChannel(image,
973 GreenPixelChannel,modulus,fourier_image,exception);
974 if (thread_status == MagickFalse)
975 status=thread_status;
977 #if defined(MAGICKCORE_OPENMP_SUPPORT)
984 thread_status=MagickTrue;
985 if (is_gray == MagickFalse)
986 thread_status=ForwardFourierTransformChannel(image,
987 BluePixelChannel,modulus,fourier_image,exception);
988 if (thread_status == MagickFalse)
989 status=thread_status;
991 #if defined(MAGICKCORE_OPENMP_SUPPORT)
998 thread_status=MagickTrue;
999 if (image->colorspace == CMYKColorspace)
1000 thread_status=ForwardFourierTransformChannel(image,
1001 BlackPixelChannel,modulus,fourier_image,exception);
1002 if (thread_status == MagickFalse)
1003 status=thread_status;
1005 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1012 thread_status=MagickTrue;
1013 if (image->alpha_trait != UndefinedPixelTrait)
1014 thread_status=ForwardFourierTransformChannel(image,
1015 AlphaPixelChannel,modulus,fourier_image,exception);
1016 if (thread_status == MagickFalse)
1017 status=thread_status;
1020 if (status == MagickFalse)
1021 fourier_image=DestroyImageList(fourier_image);
1027 return(fourier_image);
1031 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1035 % 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 %
1039 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1041 % InverseFourierTransformImage() implements the inverse discrete Fourier
1042 % transform (DFT) of the image either as a magnitude / phase or real /
1043 % imaginary image pair.
1045 % The format of the InverseFourierTransformImage method is:
1047 % Image *InverseFourierTransformImage(const Image *magnitude_image,
1048 % const Image *phase_image,const MagickBooleanType modulus,
1049 % ExceptionInfo *exception)
1051 % A description of each parameter follows:
1053 % o magnitude_image: the magnitude or real image.
1055 % o phase_image: the phase or imaginary image.
1057 % o modulus: if true, return transform as a magnitude / phase pair
1058 % otherwise a real / imaginary image pair.
1060 % o exception: return any errors or warnings in this structure.
1064 #if defined(MAGICKCORE_FFTW_DELEGATE)
1065 static MagickBooleanType InverseQuadrantSwap(const size_t width,
1066 const size_t height,const double *source,double *destination)
1078 center=(ssize_t) (width/2L)+1L;
1079 for (y=1L; y < (ssize_t) height; y++)
1080 for (x=0L; x < (ssize_t) (width/2L+1L); x++)
1081 destination[(height-y)*center-x+width/2L]=source[y*width+x];
1082 for (y=0L; y < (ssize_t) height; y++)
1083 destination[y*center]=source[y*width+width/2L];
1084 for (x=0L; x < center; x++)
1085 destination[x]=source[center-x-1L];
1086 return(RollFourier(center,height,0L,(ssize_t) height/-2L,destination));
1089 static MagickBooleanType InverseFourier(FourierInfo *fourier_info,
1090 const Image *magnitude_image,const Image *phase_image,
1091 fftw_complex *fourier_pixels,ExceptionInfo *exception)
1110 register const Quantum
1121 Inverse fourier - read image and break down into a double array.
1123 magnitude_info=AcquireVirtualMemory((size_t) fourier_info->width,
1124 fourier_info->height*sizeof(*magnitude_pixels));
1125 phase_info=AcquireVirtualMemory((size_t) fourier_info->width,
1126 fourier_info->height*sizeof(*phase_pixels));
1127 inverse_info=AcquireVirtualMemory((size_t) fourier_info->width,
1128 (fourier_info->height/2+1)*sizeof(*inverse_pixels));
1129 if ((magnitude_info == (MemoryInfo *) NULL) ||
1130 (phase_info == (MemoryInfo *) NULL) ||
1131 (inverse_info == (MemoryInfo *) NULL))
1133 if (magnitude_info != (MemoryInfo *) NULL)
1134 magnitude_info=RelinquishVirtualMemory(magnitude_info);
1135 if (phase_info != (MemoryInfo *) NULL)
1136 phase_info=RelinquishVirtualMemory(phase_info);
1137 if (inverse_info != (MemoryInfo *) NULL)
1138 inverse_info=RelinquishVirtualMemory(inverse_info);
1139 (void) ThrowMagickException(exception,GetMagickModule(),
1140 ResourceLimitError,"MemoryAllocationFailed","`%s'",
1141 magnitude_image->filename);
1142 return(MagickFalse);
1144 magnitude_pixels=(double *) GetVirtualMemoryBlob(magnitude_info);
1145 phase_pixels=(double *) GetVirtualMemoryBlob(phase_info);
1146 inverse_pixels=(double *) GetVirtualMemoryBlob(inverse_info);
1148 magnitude_view=AcquireVirtualCacheView(magnitude_image,exception);
1149 for (y=0L; y < (ssize_t) fourier_info->height; y++)
1151 p=GetCacheViewVirtualPixels(magnitude_view,0L,y,fourier_info->width,1UL,
1153 if (p == (const Quantum *) NULL)
1155 for (x=0L; x < (ssize_t) fourier_info->width; x++)
1157 switch (fourier_info->channel)
1159 case RedPixelChannel:
1162 magnitude_pixels[i]=QuantumScale*GetPixelRed(magnitude_image,p);
1165 case GreenPixelChannel:
1167 magnitude_pixels[i]=QuantumScale*GetPixelGreen(magnitude_image,p);
1170 case BluePixelChannel:
1172 magnitude_pixels[i]=QuantumScale*GetPixelBlue(magnitude_image,p);
1175 case BlackPixelChannel:
1177 magnitude_pixels[i]=QuantumScale*GetPixelBlack(magnitude_image,p);
1180 case AlphaPixelChannel:
1182 magnitude_pixels[i]=QuantumScale*GetPixelAlpha(magnitude_image,p);
1187 p+=GetPixelChannels(magnitude_image);
1190 magnitude_view=DestroyCacheView(magnitude_view);
1191 status=InverseQuadrantSwap(fourier_info->width,fourier_info->height,
1192 magnitude_pixels,inverse_pixels);
1193 (void) CopyMagickMemory(magnitude_pixels,inverse_pixels,fourier_info->height*
1194 fourier_info->center*sizeof(*magnitude_pixels));
1196 phase_view=AcquireVirtualCacheView(phase_image,exception);
1197 for (y=0L; y < (ssize_t) fourier_info->height; y++)
1199 p=GetCacheViewVirtualPixels(phase_view,0,y,fourier_info->width,1,
1201 if (p == (const Quantum *) NULL)
1203 for (x=0L; x < (ssize_t) fourier_info->width; x++)
1205 switch (fourier_info->channel)
1207 case RedPixelChannel:
1210 phase_pixels[i]=QuantumScale*GetPixelRed(phase_image,p);
1213 case GreenPixelChannel:
1215 phase_pixels[i]=QuantumScale*GetPixelGreen(phase_image,p);
1218 case BluePixelChannel:
1220 phase_pixels[i]=QuantumScale*GetPixelBlue(phase_image,p);
1223 case BlackPixelChannel:
1225 phase_pixels[i]=QuantumScale*GetPixelBlack(phase_image,p);
1228 case AlphaPixelChannel:
1230 phase_pixels[i]=QuantumScale*GetPixelAlpha(phase_image,p);
1235 p+=GetPixelChannels(phase_image);
1238 if (fourier_info->modulus != MagickFalse)
1241 for (y=0L; y < (ssize_t) fourier_info->height; y++)
1242 for (x=0L; x < (ssize_t) fourier_info->width; x++)
1244 phase_pixels[i]-=0.5;
1245 phase_pixels[i]*=(2.0*MagickPI);
1249 phase_view=DestroyCacheView(phase_view);
1250 CorrectPhaseLHS(fourier_info->width,fourier_info->height,phase_pixels);
1251 if (status != MagickFalse)
1252 status=InverseQuadrantSwap(fourier_info->width,fourier_info->height,
1253 phase_pixels,inverse_pixels);
1254 (void) CopyMagickMemory(phase_pixels,inverse_pixels,fourier_info->height*
1255 fourier_info->center*sizeof(*phase_pixels));
1256 inverse_info=RelinquishVirtualMemory(inverse_info);
1261 if (fourier_info->modulus != MagickFalse)
1262 for (y=0L; y < (ssize_t) fourier_info->height; y++)
1263 for (x=0L; x < (ssize_t) fourier_info->center; x++)
1265 #if defined(MAGICKCORE_HAVE_COMPLEX_H)
1266 fourier_pixels[i]=magnitude_pixels[i]*cos(phase_pixels[i])+I*
1267 magnitude_pixels[i]*sin(phase_pixels[i]);
1269 fourier_pixels[i][0]=magnitude_pixels[i]*cos(phase_pixels[i]);
1270 fourier_pixels[i][1]=magnitude_pixels[i]*sin(phase_pixels[i]);
1275 for (y=0L; y < (ssize_t) fourier_info->height; y++)
1276 for (x=0L; x < (ssize_t) fourier_info->center; x++)
1278 #if defined(MAGICKCORE_HAVE_COMPLEX_H)
1279 fourier_pixels[i]=magnitude_pixels[i]+I*phase_pixels[i];
1281 fourier_pixels[i][0]=magnitude_pixels[i];
1282 fourier_pixels[i][1]=phase_pixels[i];
1286 magnitude_info=RelinquishVirtualMemory(magnitude_info);
1287 phase_info=RelinquishVirtualMemory(phase_info);
1291 static MagickBooleanType InverseFourierTransform(FourierInfo *fourier_info,
1292 fftw_complex *fourier_pixels,Image *image,ExceptionInfo *exception)
1319 source_info=AcquireVirtualMemory((size_t) fourier_info->width,
1320 fourier_info->height*sizeof(*source_pixels));
1321 if (source_info == (MemoryInfo *) NULL)
1323 (void) ThrowMagickException(exception,GetMagickModule(),
1324 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
1325 return(MagickFalse);
1327 source_pixels=(double *) GetVirtualMemoryBlob(source_info);
1328 value=GetImageArtifact(image,"fourier:normalize");
1329 if (LocaleCompare(value,"inverse") == 0)
1335 Normalize inverse transform.
1338 gamma=PerceptibleReciprocal((double) fourier_info->width*
1339 fourier_info->height);
1340 for (y=0L; y < (ssize_t) fourier_info->height; y++)
1341 for (x=0L; x < (ssize_t) fourier_info->center; x++)
1343 #if defined(MAGICKCORE_HAVE_COMPLEX_H)
1344 fourier_pixels[i]*=gamma;
1346 fourier_pixels[i][0]*=gamma;
1347 fourier_pixels[i][1]*=gamma;
1352 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1353 #pragma omp critical (MagickCore_InverseFourierTransform)
1355 fftw_c2r_plan=fftw_plan_dft_c2r_2d(fourier_info->width,fourier_info->height,
1356 fourier_pixels,source_pixels,FFTW_ESTIMATE);
1357 fftw_execute_dft_c2r(fftw_c2r_plan,fourier_pixels,source_pixels);
1358 fftw_destroy_plan(fftw_c2r_plan);
1360 image_view=AcquireAuthenticCacheView(image,exception);
1361 for (y=0L; y < (ssize_t) fourier_info->height; y++)
1363 if (y >= (ssize_t) image->rows)
1365 q=GetCacheViewAuthenticPixels(image_view,0L,y,fourier_info->width >
1366 image->columns ? image->columns : fourier_info->width,1UL,exception);
1367 if (q == (Quantum *) NULL)
1369 for (x=0L; x < (ssize_t) fourier_info->width; x++)
1371 if (x < (ssize_t) image->columns)
1372 switch (fourier_info->channel)
1374 case RedPixelChannel:
1377 SetPixelRed(image,ClampToQuantum(QuantumRange*source_pixels[i]),q);
1380 case GreenPixelChannel:
1382 SetPixelGreen(image,ClampToQuantum(QuantumRange*source_pixels[i]),
1386 case BluePixelChannel:
1388 SetPixelBlue(image,ClampToQuantum(QuantumRange*source_pixels[i]),
1392 case BlackPixelChannel:
1394 SetPixelBlack(image,ClampToQuantum(QuantumRange*source_pixels[i]),
1398 case AlphaPixelChannel:
1400 SetPixelAlpha(image,ClampToQuantum(QuantumRange*source_pixels[i]),
1406 q+=GetPixelChannels(image);
1408 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1411 image_view=DestroyCacheView(image_view);
1412 source_info=RelinquishVirtualMemory(source_info);
1416 static MagickBooleanType InverseFourierTransformChannel(
1417 const Image *magnitude_image,const Image *phase_image,
1418 const PixelChannel channel,const MagickBooleanType modulus,
1419 Image *fourier_image,ExceptionInfo *exception)
1433 fourier_info.width=magnitude_image->columns;
1434 fourier_info.height=magnitude_image->rows;
1435 if ((magnitude_image->columns != magnitude_image->rows) ||
1436 ((magnitude_image->columns % 2) != 0) ||
1437 ((magnitude_image->rows % 2) != 0))
1439 size_t extent=magnitude_image->columns < magnitude_image->rows ?
1440 magnitude_image->rows : magnitude_image->columns;
1441 fourier_info.width=(extent & 0x01) == 1 ? extent+1UL : extent;
1443 fourier_info.height=fourier_info.width;
1444 fourier_info.center=(ssize_t) (fourier_info.width/2L)+1L;
1445 fourier_info.channel=channel;
1446 fourier_info.modulus=modulus;
1447 inverse_info=AcquireVirtualMemory((size_t) fourier_info.width,
1448 (fourier_info.height/2+1)*sizeof(*inverse_pixels));
1449 if (inverse_info == (MemoryInfo *) NULL)
1451 (void) ThrowMagickException(exception,GetMagickModule(),
1452 ResourceLimitError,"MemoryAllocationFailed","`%s'",
1453 magnitude_image->filename);
1454 return(MagickFalse);
1456 inverse_pixels=(fftw_complex *) GetVirtualMemoryBlob(inverse_info);
1457 status=InverseFourier(&fourier_info,magnitude_image,phase_image,
1458 inverse_pixels,exception);
1459 if (status != MagickFalse)
1460 status=InverseFourierTransform(&fourier_info,inverse_pixels,fourier_image,
1462 inverse_info=RelinquishVirtualMemory(inverse_info);
1467 MagickExport Image *InverseFourierTransformImage(const Image *magnitude_image,
1468 const Image *phase_image,const MagickBooleanType modulus,
1469 ExceptionInfo *exception)
1474 assert(magnitude_image != (Image *) NULL);
1475 assert(magnitude_image->signature == MagickCoreSignature);
1476 if (magnitude_image->debug != MagickFalse)
1477 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1478 magnitude_image->filename);
1479 if (phase_image == (Image *) NULL)
1481 (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
1482 "ImageSequenceRequired","`%s'",magnitude_image->filename);
1483 return((Image *) NULL);
1485 #if !defined(MAGICKCORE_FFTW_DELEGATE)
1486 fourier_image=(Image *) NULL;
1488 (void) ThrowMagickException(exception,GetMagickModule(),
1489 MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","`%s' (FFTW)",
1490 magnitude_image->filename);
1493 fourier_image=CloneImage(magnitude_image,magnitude_image->columns,
1494 magnitude_image->rows,MagickTrue,exception);
1495 if (fourier_image != (Image *) NULL)
1502 is_gray=IsImageGray(magnitude_image);
1503 if (is_gray != MagickFalse)
1504 is_gray=IsImageGray(phase_image);
1505 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1506 #pragma omp parallel sections
1509 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1516 if (is_gray != MagickFalse)
1517 thread_status=InverseFourierTransformChannel(magnitude_image,
1518 phase_image,GrayPixelChannel,modulus,fourier_image,exception);
1520 thread_status=InverseFourierTransformChannel(magnitude_image,
1521 phase_image,RedPixelChannel,modulus,fourier_image,exception);
1522 if (thread_status == MagickFalse)
1523 status=thread_status;
1525 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1532 thread_status=MagickTrue;
1533 if (is_gray == MagickFalse)
1534 thread_status=InverseFourierTransformChannel(magnitude_image,
1535 phase_image,GreenPixelChannel,modulus,fourier_image,exception);
1536 if (thread_status == MagickFalse)
1537 status=thread_status;
1539 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1546 thread_status=MagickTrue;
1547 if (is_gray == MagickFalse)
1548 thread_status=InverseFourierTransformChannel(magnitude_image,
1549 phase_image,BluePixelChannel,modulus,fourier_image,exception);
1550 if (thread_status == MagickFalse)
1551 status=thread_status;
1553 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1560 thread_status=MagickTrue;
1561 if (magnitude_image->colorspace == CMYKColorspace)
1562 thread_status=InverseFourierTransformChannel(magnitude_image,
1563 phase_image,BlackPixelChannel,modulus,fourier_image,exception);
1564 if (thread_status == MagickFalse)
1565 status=thread_status;
1567 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1574 thread_status=MagickTrue;
1575 if (magnitude_image->alpha_trait != UndefinedPixelTrait)
1576 thread_status=InverseFourierTransformChannel(magnitude_image,
1577 phase_image,AlphaPixelChannel,modulus,fourier_image,exception);
1578 if (thread_status == MagickFalse)
1579 status=thread_status;
1582 if (status == MagickFalse)
1583 fourier_image=DestroyImage(fourier_image);
1588 return(fourier_image);