fourier.c

Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %               FFFFF   OOO   U   U  RRRR   IIIII  EEEEE  RRRR                %
00007 %               F      O   O  U   U  R   R    I    E      R   R               %
00008 %               FFF    O   O  U   U  RRRR     I    EEE    RRRR                %
00009 %               F      O   O  U   U  R R      I    E      R R                 %
00010 %               F       OOO    UUU   R  R   IIIII  EEEEE  R  R                %
00011 %                                                                             %
00012 %                                                                             %
00013 %                MagickCore Discrete Fourier Transform Methods                %
00014 %                                                                             %
00015 %                              Software Design                                %
00016 %                                Sean Burke                                   %
00017 %                               Fred Weinhaus                                 %
00018 %                                John Cristy                                  %
00019 %                                 July 2009                                   %
00020 %                                                                             %
00021 %                                                                             %
00022 %  Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization      %
00023 %  dedicated to making software imaging solutions freely available.           %
00024 %                                                                             %
00025 %  You may not use this file except in compliance with the License.  You may  %
00026 %  obtain a copy of the License at                                            %
00027 %                                                                             %
00028 %    http://www.imagemagick.org/script/license.php                            %
00029 %                                                                             %
00030 %  Unless required by applicable law or agreed to in writing, software        %
00031 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00032 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00033 %  See the License for the specific language governing permissions and        %
00034 %  limitations under the License.                                             %
00035 %                                                                             %
00036 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00037 %
00038 %
00039 %
00040 */
00041 
00042 /*
00043   Include declarations.
00044 */
00045 #include "magick/studio.h"
00046 #include "magick/cache.h"
00047 #include "magick/image.h"
00048 #include "magick/image-private.h"
00049 #include "magick/list.h"
00050 #include "magick/fourier.h"
00051 #include "magick/log.h"
00052 #include "magick/memory_.h"
00053 #include "magick/monitor.h"
00054 #include "magick/property.h"
00055 #include "magick/thread-private.h"
00056 #if defined(MAGICKCORE_FFTW_DELEGATE)
00057 #include <complex.h>
00058 #include <fftw3.h>
00059 #endif
00060 
00061 /*
00062   Typedef declarations.
00063 */
00064 typedef struct _FourierInfo
00065 {
00066   ChannelType
00067     channel;
00068 
00069   MagickBooleanType
00070     modulus;
00071 
00072   unsigned long
00073     width,
00074     height;
00075 
00076   long
00077     center;
00078 } FourierInfo;
00079 
00080 /*
00081 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00082 %                                                                             %
00083 %                                                                             %
00084 %                                                                             %
00085 %     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                 %
00086 %                                                                             %
00087 %                                                                             %
00088 %                                                                             %
00089 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00090 %
00091 %  ForwardFourierTransformImage() implements the discrete Fourier transform
00092 %  (DFT) of the image either as a magnitude / phase or real / imaginary image
00093 %  pair.
00094 %
00095 %  The format of the ForwadFourierTransformImage method is:
00096 %
00097 %      Image *ForwardFourierTransformImage(const Image *image,
00098 %        const MagickBooleanType modulus,ExceptionInfo *exception)
00099 %
00100 %  A description of each parameter follows:
00101 %
00102 %    o image: the image.
00103 %
00104 %    o modulus: if true, return as transform as a magnitude / phase pair
00105 %      otherwise a real / imaginary image pair.
00106 %
00107 %    o exception: return any errors or warnings in this structure.
00108 %
00109 */
00110 
00111 #if defined(MAGICKCORE_FFTW_DELEGATE)
00112 
00113 static MagickBooleanType RollFourier(const unsigned long width,
00114   const unsigned long height,const long x_offset,const long y_offset,
00115   double *fourier)
00116 {
00117   double
00118     *roll;
00119 
00120   long
00121     u,
00122     v,
00123     y;
00124 
00125   register long
00126     i,
00127     x;
00128 
00129   /*
00130     Move the zero frequency (DC) from (0,0) to (width/2,height/2).
00131   */
00132   roll=(double *) AcquireQuantumMemory((size_t) width,height*sizeof(*roll));
00133   if (roll == (double *) NULL)
00134     return(MagickFalse);
00135   i=0L;
00136   for (y=0L; y < (long) height; y++)
00137   {
00138     if (y_offset < 0L)
00139       v=((y+y_offset) < 0L) ? y+y_offset+(long) height : y+y_offset;
00140     else
00141       v=((y+y_offset) > ((long) height-1L)) ? y+y_offset-(long) height :
00142         y+y_offset;
00143     for (x=0L; x < (long) width; x++)
00144     {
00145       if (x_offset < 0L)
00146         u=((x+x_offset) < 0L) ? x+x_offset+(long) width : x+x_offset;
00147       else
00148         u=((x+x_offset) > ((long) width-1L)) ? x+x_offset-(long) width :
00149           x+x_offset;
00150       roll[v*width+u]=fourier[i++];
00151    }
00152   }
00153   (void) CopyMagickMemory(fourier,roll,width*height*sizeof(*roll));
00154   roll=(double *) RelinquishMagickMemory(roll);
00155   return(MagickTrue);
00156 }
00157 
00158 static MagickBooleanType ForwardQuadrantSwap(const unsigned long width,
00159   const unsigned long height,double *source,double *destination)
00160 {
00161   long
00162     center,
00163     y;
00164 
00165   MagickBooleanType
00166     status;
00167 
00168   register long
00169     x;
00170 
00171   /*
00172     Swap quadrants.
00173   */
00174   center=(long) floor((double) width/2L)+1L;
00175   status=RollFourier((unsigned long) center,height,0L,(long) height/2L,source);
00176   if (status == MagickFalse)
00177     return(MagickFalse);
00178   for (y=0L; y < (long) height; y++)
00179     for (x=0L; x < (long) (width/2L-1L); x++)
00180       destination[width*y+x+width/2L]=source[center*y+x];
00181   for (y=1; y < (long) height; y++)
00182     for (x=0L; x < (long) (width/2L-1L); x++)
00183       destination[width*(height-y)+width/2L-x-1L]=source[center*y+x+1L];
00184   for (x=0L; x < (long) (width/2L); x++)
00185     destination[-x+width/2L-1L]=destination[x+width/2L+1L];
00186   return(MagickTrue);
00187 }
00188 
00189 static void CorrectPhaseLHS(const unsigned long width,
00190   const unsigned long height,double *fourier)
00191 {
00192   long
00193     y;
00194 
00195   register long
00196     x;
00197 
00198   for (y=0L; y < (long) height; y++)
00199     for (x=0L; x < (long) (width/2L); x++)
00200       fourier[y*width+x]*=(-1.0);
00201 }
00202 
00203 static MagickBooleanType ForwardFourier(const FourierInfo *fourier_info,
00204   Image *image,double *magnitude,double *phase,ExceptionInfo *exception)
00205 {
00206   CacheView
00207     *magnitude_view,
00208     *phase_view;
00209 
00210   double
00211     *magnitude_source,
00212     *phase_source;
00213 
00214   Image
00215     *magnitude_image,
00216     *phase_image;
00217 
00218   long
00219     i,
00220     y;
00221 
00222   MagickBooleanType
00223     status;
00224 
00225   register IndexPacket
00226     *indexes;
00227 
00228   register long
00229     x;
00230 
00231   register PixelPacket
00232     *q;
00233 
00234   magnitude_image=GetFirstImageInList(image);
00235   phase_image=GetNextImageInList(image);
00236   if (phase_image == (Image *) NULL)
00237     {
00238       (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
00239         "ImageSequenceRequired","`%s'",image->filename);
00240       return(MagickFalse);
00241     }
00242   /*
00243     Create "Fourier Transform" image from constituent arrays.
00244   */
00245   magnitude_source=(double *) AcquireQuantumMemory((size_t)
00246     fourier_info->height,fourier_info->width*sizeof(*magnitude_source));
00247   if (magnitude_source == (double *) NULL)
00248     return(MagickFalse);
00249   (void) ResetMagickMemory(magnitude_source,0,fourier_info->width*
00250     fourier_info->height*sizeof(*magnitude_source));
00251   phase_source=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
00252     fourier_info->width*sizeof(*phase_source));
00253   if (magnitude_source == (double *) NULL)
00254     {
00255       (void) ThrowMagickException(exception,GetMagickModule(),
00256         ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
00257       magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
00258       return(MagickFalse);
00259     }
00260   status=ForwardQuadrantSwap(fourier_info->height,fourier_info->height,
00261     magnitude,magnitude_source);
00262   if (status != MagickFalse)
00263     status=ForwardQuadrantSwap(fourier_info->height,fourier_info->height,phase,
00264       phase_source);
00265   CorrectPhaseLHS(fourier_info->height,fourier_info->height,phase_source);
00266   if (fourier_info->modulus != MagickFalse)
00267     {
00268       i=0L;
00269       for (y=0L; y < (long) fourier_info->height; y++)
00270         for (x=0L; x < (long) fourier_info->width; x++)
00271         {
00272           phase_source[i]/=(2.0*MagickPI);
00273           phase_source[i]+=0.5;
00274           i++;
00275         }
00276     }
00277   magnitude_view=AcquireCacheView(magnitude_image);
00278   phase_view=AcquireCacheView(phase_image);
00279   i=0L;
00280   for (y=0L; y < (long) fourier_info->height; y++)
00281   {
00282     q=GetCacheViewAuthenticPixels(magnitude_view,0L,y,fourier_info->height,1UL,
00283       exception);
00284     if (q == (PixelPacket *) NULL)
00285       break;
00286     indexes=GetCacheViewAuthenticIndexQueue(magnitude_view);
00287     for (x=0L; x < (long) fourier_info->width; x++)
00288     {
00289       switch (fourier_info->channel)
00290       {
00291         case RedChannel:
00292         default:
00293         {
00294           q->red=ClampToQuantum(QuantumRange*magnitude_source[i]);
00295           break;
00296         }
00297         case GreenChannel:
00298         {
00299           q->green=ClampToQuantum(QuantumRange*magnitude_source[i]);
00300           break;
00301         }
00302         case BlueChannel:
00303         {
00304           q->blue=ClampToQuantum(QuantumRange*magnitude_source[i]);
00305           break;
00306         }
00307         case OpacityChannel:
00308         {
00309           q->opacity=ClampToQuantum(QuantumRange*magnitude_source[i]);
00310           break;
00311         }
00312         case IndexChannel:
00313         {
00314           indexes[x]=ClampToQuantum(QuantumRange*magnitude_source[i]);
00315           break;
00316         }
00317         case GrayChannels:
00318         {
00319           q->red=ClampToQuantum(QuantumRange*magnitude_source[i]);
00320           q->green=q->red;
00321           q->blue=q->red;
00322           break;
00323         }
00324       }
00325       i++;
00326       q++;
00327     }
00328     status=SyncCacheViewAuthenticPixels(magnitude_view,exception);
00329     if (status == MagickFalse)
00330       break;
00331   }
00332   i=0L;
00333   for (y=0L; y < (long) fourier_info->height; y++)
00334   {
00335     q=GetCacheViewAuthenticPixels(phase_view,0L,y,fourier_info->height,1UL,
00336       exception);
00337     if (q == (PixelPacket *) NULL)
00338       break;
00339     indexes=GetCacheViewAuthenticIndexQueue(phase_view);
00340     for (x=0L; x < (long) fourier_info->width; x++)
00341     {
00342       switch (fourier_info->channel)
00343       {
00344         case RedChannel:
00345         default:
00346         {
00347           q->red=ClampToQuantum(QuantumRange*phase_source[i]);
00348           break;
00349         }
00350         case GreenChannel:
00351         {
00352           q->green=ClampToQuantum(QuantumRange*phase_source[i]);
00353           break;
00354         }
00355         case BlueChannel:
00356         {
00357           q->blue=ClampToQuantum(QuantumRange*phase_source[i]);
00358           break;
00359         }
00360         case OpacityChannel:
00361         {
00362           q->opacity=ClampToQuantum(QuantumRange*phase_source[i]);
00363           break;
00364         }
00365         case IndexChannel:
00366         {
00367           indexes[x]=ClampToQuantum(QuantumRange*phase_source[i]);
00368           break;
00369         }
00370         case GrayChannels:
00371         {
00372           q->red=ClampToQuantum(QuantumRange*phase_source[i]);
00373           q->green=q->red;
00374           q->blue=q->red;
00375           break;
00376         }
00377       }
00378       i++;
00379       q++;
00380     }
00381     status=SyncCacheViewAuthenticPixels(phase_view,exception);
00382     if (status == MagickFalse)
00383       break;
00384    }
00385   phase_view=DestroyCacheView(phase_view);
00386   magnitude_view=DestroyCacheView(magnitude_view);
00387   phase_source=(double *) RelinquishMagickMemory(phase_source);
00388   magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
00389   return(status);
00390 }
00391 
00392 static MagickBooleanType ForwardFourierTransform(FourierInfo *fourier_info,
00393   const Image *image,double *magnitude,double *phase,ExceptionInfo *exception)
00394 {
00395   CacheView
00396     *image_view;
00397 
00398   double
00399     n,
00400     *source;
00401 
00402   fftw_complex
00403     *fourier;
00404 
00405   fftw_plan
00406     fftw_r2c_plan;
00407 
00408   long
00409     y;
00410 
00411   register const IndexPacket
00412     *indexes;
00413 
00414   register const PixelPacket
00415     *p;
00416 
00417   register long
00418     i,
00419     x;
00420 
00421   /*
00422     Generate the forward Fourier transform.
00423   */
00424   source=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
00425     fourier_info->width*sizeof(*source));
00426   if (source == (double *) NULL)
00427     {
00428       (void) ThrowMagickException(exception,GetMagickModule(),
00429         ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
00430       return(MagickFalse);
00431     }
00432   ResetMagickMemory(source,0,fourier_info->width*fourier_info->height*
00433     sizeof(*source));
00434   i=0L;
00435   image_view=AcquireCacheView(image);
00436   for (y=0L; y < (long) fourier_info->height; y++)
00437   {
00438     p=GetCacheViewVirtualPixels(image_view,0L,y,fourier_info->width,1UL,
00439       exception);
00440     if (p == (const PixelPacket *) NULL)
00441       break;
00442     indexes=GetCacheViewVirtualIndexQueue(image_view);
00443     for (x=0L; x < (long) fourier_info->width; x++)
00444     {
00445       switch (fourier_info->channel)
00446       {
00447         case RedChannel:
00448         default:
00449         {
00450           source[i]=QuantumScale*GetRedPixelComponent(p);
00451           break;
00452         }
00453         case GreenChannel:
00454         {
00455           source[i]=QuantumScale*GetGreenPixelComponent(p);
00456           break;
00457         }
00458         case BlueChannel:
00459         {
00460           source[i]=QuantumScale*GetBluePixelComponent(p);
00461           break;
00462         }
00463         case OpacityChannel:
00464         {
00465           source[i]=QuantumScale*GetOpacityPixelComponent(p);
00466           break;
00467         }
00468         case IndexChannel:
00469         {
00470           source[i]=QuantumScale*indexes[x];
00471           break;
00472         }
00473         case GrayChannels:
00474         {
00475           source[i]=QuantumScale*GetRedPixelComponent(p);
00476           break;
00477         }
00478       }
00479       i++;
00480       p++;
00481     }
00482   }
00483   image_view=DestroyCacheView(image_view);
00484   fourier=(fftw_complex *) AcquireAlignedMemory((size_t) fourier_info->height,
00485     fourier_info->center*sizeof(*fourier));
00486   if (fourier == (fftw_complex *) NULL)
00487     {
00488       (void) ThrowMagickException(exception,GetMagickModule(),
00489         ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
00490       source=(double *) RelinquishMagickMemory(source);
00491       return(MagickFalse);
00492     }
00493 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00494   #pragma omp critical (MagickCore_ForwardFourierTransform)
00495 #endif
00496   fftw_r2c_plan=fftw_plan_dft_r2c_2d(fourier_info->width,fourier_info->width,
00497     source,fourier,FFTW_ESTIMATE);
00498   fftw_execute(fftw_r2c_plan);
00499   fftw_destroy_plan(fftw_r2c_plan);
00500   source=(double *) RelinquishMagickMemory(source);
00501   /*
00502     Normalize Fourier transform.
00503   */
00504   n=(double) fourier_info->width*(double) fourier_info->width;
00505   i=0L;
00506   for (y=0L; y < (long) fourier_info->height; y++)
00507     for (x=0L; x < (long) fourier_info->center; x++)
00508       fourier[i++]/=n;
00509   /*
00510     Generate magnitude and phase (or real and imaginary).
00511   */
00512   i=0L;
00513   if (fourier_info->modulus != MagickFalse)
00514     for (y=0L; y < (long) fourier_info->height; y++)
00515       for (x=0L; x < (long) fourier_info->center; x++)
00516       {
00517         magnitude[i]=cabs(fourier[i]);
00518         phase[i]=carg(fourier[i]);
00519         i++;
00520       }
00521   else
00522     for (y=0L; y < (long) fourier_info->height; y++)
00523       for (x=0L; x < (long) fourier_info->center; x++)
00524       {
00525         magnitude[i]=creal(fourier[i]);
00526         phase[i]=cimag(fourier[i]);
00527         i++;
00528       }
00529   fourier=(fftw_complex *) RelinquishAlignedMemory(fourier);
00530   return(MagickTrue);
00531 }
00532 
00533 static MagickBooleanType ForwardFourierTransformChannel(const Image *image,
00534   const ChannelType channel,const MagickBooleanType modulus,
00535   Image *fourier_image,ExceptionInfo *exception)
00536 {
00537   double
00538     *magnitude,
00539     *phase;
00540 
00541   fftw_complex
00542     *fourier;
00543 
00544   MagickBooleanType
00545     status;
00546 
00547   FourierInfo
00548     fourier_info;
00549 
00550   size_t
00551     extent;
00552 
00553   fourier_info.width=image->columns;
00554   if ((image->columns != image->rows) || ((image->columns % 2) != 0) ||
00555       ((image->rows % 2) != 0))
00556     {
00557       extent=image->columns < image->rows ? image->rows : image->columns;
00558       fourier_info.width=(extent & 0x01) == 1 ? extent+1UL : extent;
00559     }
00560   fourier_info.height=fourier_info.width;
00561   fourier_info.center=(long) floor((double) fourier_info.width/2.0)+1L;
00562   fourier_info.channel=channel;
00563   fourier_info.modulus=modulus;
00564   magnitude=(double *) AcquireQuantumMemory((size_t) fourier_info.height,
00565     fourier_info.center*sizeof(*magnitude));
00566   if (magnitude == (double *) NULL)
00567     {
00568       (void) ThrowMagickException(exception,GetMagickModule(),
00569         ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
00570       return(MagickFalse);
00571     }
00572   phase=(double *) AcquireQuantumMemory((size_t) fourier_info.height,
00573     fourier_info.center*sizeof(*phase));
00574   if (phase == (double *) NULL)
00575     {
00576       (void) ThrowMagickException(exception,GetMagickModule(),
00577         ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
00578       magnitude=(double *) RelinquishMagickMemory(magnitude);
00579       return(MagickFalse);
00580     }
00581   fourier=(fftw_complex *) AcquireAlignedMemory((size_t) fourier_info.height,
00582     fourier_info.center*sizeof(*fourier));
00583   if (fourier == (fftw_complex *) NULL)
00584     {
00585       (void) ThrowMagickException(exception,GetMagickModule(),
00586         ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
00587       phase=(double *) RelinquishMagickMemory(phase);
00588       magnitude=(double *) RelinquishMagickMemory(magnitude);
00589       return(MagickFalse);
00590     }
00591   status=ForwardFourierTransform(&fourier_info,image,magnitude,phase,exception);
00592   if (status != MagickFalse)
00593     status=ForwardFourier(&fourier_info,fourier_image,magnitude,phase,
00594       exception);
00595   fourier=(fftw_complex *) RelinquishAlignedMemory(fourier);
00596   phase=(double *) RelinquishMagickMemory(phase);
00597   magnitude=(double *) RelinquishMagickMemory(magnitude);
00598   return(status);
00599 }
00600 #endif
00601 
00602 MagickExport Image *ForwardFourierTransformImage(const Image *image,
00603   const MagickBooleanType modulus,ExceptionInfo *exception)
00604 {
00605   Image
00606     *fourier_image;
00607 
00608   fourier_image=NewImageList();
00609 #if !defined(MAGICKCORE_FFTW_DELEGATE)
00610   (void) modulus;
00611   (void) ThrowMagickException(exception,GetMagickModule(),
00612     MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","`%s' (FFTW)",
00613     image->filename);
00614 #else
00615   {
00616     Image
00617       *magnitude_image;
00618 
00619     unsigned long
00620       extent,
00621       width;
00622 
00623     width=image->columns;
00624     if ((image->columns != image->rows) || ((image->columns % 2) != 0) ||
00625         ((image->rows % 2) != 0))
00626       {
00627         extent=image->columns < image->rows ? image->rows : image->columns;
00628         width=(extent & 0x01) == 1 ? extent+1UL : extent;
00629       }
00630     magnitude_image=CloneImage(image,width,width,MagickFalse,exception);
00631     if (magnitude_image != (Image *) NULL)
00632       {
00633         Image
00634           *phase_image;
00635 
00636         magnitude_image->storage_class=DirectClass;
00637         magnitude_image->depth=32UL;
00638         phase_image=CloneImage(image,width,width,MagickFalse,exception);
00639         if (phase_image == (Image *) NULL)
00640           magnitude_image=DestroyImage(magnitude_image);
00641         else
00642           {
00643             MagickBooleanType
00644               is_gray,
00645               status;
00646 
00647             register long
00648               i;
00649 
00650             phase_image->storage_class=DirectClass;
00651             phase_image->depth=32UL;
00652             AppendImageToList(&fourier_image,magnitude_image);
00653             AppendImageToList(&fourier_image,phase_image);
00654             status=MagickTrue;
00655             is_gray=IsGrayImage(image,exception);
00656 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00657   #pragma omp parallel for schedule(dynamic,4) shared(status)
00658 #endif
00659             for (i=0L; i < 5L; i++)
00660             {
00661               MagickBooleanType
00662                 thread_status;
00663 
00664               thread_status=MagickTrue;
00665               switch (i)
00666               {
00667                 case 0:
00668                 {
00669                   if (is_gray != MagickFalse)
00670                     {
00671                       thread_status=ForwardFourierTransformChannel(image,
00672                         GrayChannels,modulus,fourier_image,exception);
00673                       break;
00674                     }
00675                   thread_status=ForwardFourierTransformChannel(image,RedChannel,
00676                     modulus,fourier_image,exception);
00677                   break;
00678                 }
00679                 case 1:
00680                 {
00681                   if (is_gray == MagickFalse)
00682                     thread_status=ForwardFourierTransformChannel(image,
00683                       GreenChannel,modulus,fourier_image,exception);
00684                   break;
00685                 }
00686                 case 2:
00687                 {
00688                   if (is_gray == MagickFalse)
00689                     thread_status=ForwardFourierTransformChannel(image,
00690                       BlueChannel,modulus,fourier_image,exception);
00691                   break;
00692                 }
00693                 case 4:
00694                 {
00695                   if (image->matte != MagickFalse)
00696                     thread_status=ForwardFourierTransformChannel(image,
00697                       OpacityChannel,modulus,fourier_image,exception);
00698                   break;
00699                 }
00700                 case 5:
00701                 {
00702                   if (image->colorspace == CMYKColorspace)
00703                     thread_status=ForwardFourierTransformChannel(image,
00704                       IndexChannel,modulus,fourier_image,exception);
00705                   break;
00706                 }
00707               }
00708               if (thread_status == MagickFalse)
00709                 status=thread_status;
00710             }
00711             if (status == MagickFalse)
00712               fourier_image=DestroyImageList(fourier_image);
00713             fftw_cleanup();
00714           }
00715       }
00716   }
00717 #endif
00718   return(fourier_image);
00719 }
00720 
00721 /*
00722 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00723 %                                                                             %
00724 %                                                                             %
00725 %                                                                             %
00726 %     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                 %
00727 %                                                                             %
00728 %                                                                             %
00729 %                                                                             %
00730 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00731 %
00732 %  InverseFourierTransformImage() implements the inverse discrete Fourier
00733 %  transform (DFT) of the image either as a magnitude / phase or real /
00734 %  imaginary image pair.
00735 %
00736 %  The format of the InverseFourierTransformImage method is:
00737 %
00738 %      Image *InverseFourierTransformImage(const Image *magnitude_image,
00739 %        const Image *phase_image,const MagickBooleanType modulus,
00740 %        ExceptionInfo *exception)
00741 %
00742 %  A description of each parameter follows:
00743 %
00744 %    o magnitude_image: the magnitude or real image.
00745 %
00746 %    o phase_image: the phase or imaginary image.
00747 %
00748 %    o modulus: if true, return transform as a magnitude / phase pair
00749 %      otherwise a real / imaginary image pair.
00750 %
00751 %    o exception: return any errors or warnings in this structure.
00752 %
00753 */
00754 
00755 #if defined(MAGICKCORE_FFTW_DELEGATE)
00756 static MagickBooleanType InverseQuadrantSwap(const unsigned long width,
00757   const unsigned long height,const double *source,double *destination)
00758 {
00759   long
00760     center,
00761     y;
00762 
00763   register long
00764     x;
00765 
00766   /*
00767     Swap quadrants.
00768   */
00769   center=(long) floor((double) width/2.0)+1L;
00770   for (y=1L; y < (long) height; y++)
00771     for (x=0L; x < (long) (width/2L+1L); x++)
00772       destination[center*(height-y)-x+width/2L]=source[y*width+x];
00773   for (y=0L; y < (long) height; y++)
00774     destination[center*y]=source[y*width+width/2L];
00775   for (x=0L; x < center; x++)
00776     destination[x]=source[center-x-1L];
00777   return(RollFourier(center,height,0L,(long) height/-2L,destination));
00778 }
00779 
00780 static MagickBooleanType InverseFourier(FourierInfo *fourier_info,
00781   const Image *magnitude_image,const Image *phase_image,fftw_complex *fourier,
00782   ExceptionInfo *exception)
00783 {
00784   CacheView
00785     *magnitude_view,
00786     *phase_view;
00787 
00788   double
00789     *magnitude,
00790     *phase,
00791     *magnitude_source,
00792     *phase_source;
00793 
00794   long
00795     y;
00796 
00797   MagickBooleanType
00798     status;
00799 
00800   register const IndexPacket
00801     *indexes;
00802 
00803   register const PixelPacket
00804     *p;
00805 
00806   register long
00807     i,
00808     x;
00809 
00810   /*
00811     Inverse fourier - read image and break down into a double array.
00812   */
00813   magnitude_source=(double *) AcquireQuantumMemory((size_t)
00814     fourier_info->height,fourier_info->width*sizeof(*magnitude_source));
00815   if (magnitude_source == (double *) NULL)
00816     {
00817       (void) ThrowMagickException(exception,GetMagickModule(),
00818         ResourceLimitError,"MemoryAllocationFailed","`%s'",
00819         magnitude_image->filename);
00820       return(MagickFalse);
00821     }
00822   phase_source=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
00823     fourier_info->height*sizeof(*phase_source));
00824   if (phase_source == (double *) NULL)
00825     {
00826       (void) ThrowMagickException(exception,GetMagickModule(),
00827         ResourceLimitError,"MemoryAllocationFailed","`%s'",
00828         magnitude_image->filename);
00829       magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
00830       return(MagickFalse);
00831     }
00832   i=0L;
00833   magnitude_view=AcquireCacheView(magnitude_image);
00834   for (y=0L; y < (long) fourier_info->height; y++)
00835   {
00836     p=GetCacheViewVirtualPixels(magnitude_view,0L,y,fourier_info->width,1UL,
00837       exception);
00838     if (p == (const PixelPacket *) NULL)
00839       break;
00840     indexes=GetCacheViewAuthenticIndexQueue(magnitude_view);
00841     for (x=0L; x < (long) fourier_info->width; x++)
00842     {
00843       switch (fourier_info->channel)
00844       {
00845         case RedChannel:
00846         default:
00847         {
00848           magnitude_source[i]=QuantumScale*GetRedPixelComponent(p);
00849           break;
00850         }
00851         case GreenChannel:
00852         {
00853           magnitude_source[i]=QuantumScale*GetGreenPixelComponent(p);
00854           break;
00855         }
00856         case BlueChannel:
00857         {
00858           magnitude_source[i]=QuantumScale*GetBluePixelComponent(p);
00859           break;
00860         }
00861         case OpacityChannel:
00862         {
00863           magnitude_source[i]=QuantumScale*GetOpacityPixelComponent(p);
00864           break;
00865         }
00866         case IndexChannel:
00867         {
00868           magnitude_source[i]=QuantumScale*indexes[x];
00869           break;
00870         }
00871         case GrayChannels:
00872         {
00873           magnitude_source[i]=QuantumScale*GetRedPixelComponent(p);
00874           break;
00875         }
00876       }
00877       i++;
00878       p++;
00879     }
00880   }
00881   i=0L;
00882   phase_view=AcquireCacheView(phase_image);
00883   for (y=0L; y < (long) fourier_info->height; y++)
00884   {
00885     p=GetCacheViewVirtualPixels(phase_view,0,y,fourier_info->width,1,
00886       exception);
00887     if (p == (const PixelPacket *) NULL)
00888       break;
00889     indexes=GetCacheViewAuthenticIndexQueue(phase_view);
00890     for (x=0L; x < (long) fourier_info->width; x++)
00891     {
00892       switch (fourier_info->channel)
00893       {
00894         case RedChannel:
00895         default:
00896         {
00897           phase_source[i]=QuantumScale*GetRedPixelComponent(p);
00898           break;
00899         }
00900         case GreenChannel:
00901         {
00902           phase_source[i]=QuantumScale*GetGreenPixelComponent(p);
00903           break;
00904         }
00905         case BlueChannel:
00906         {
00907           phase_source[i]=QuantumScale*GetBluePixelComponent(p);
00908           break;
00909         }
00910         case OpacityChannel:
00911         {
00912           phase_source[i]=QuantumScale*GetOpacityPixelComponent(p);
00913           break;
00914         }
00915         case IndexChannel:
00916         {
00917           phase_source[i]=QuantumScale*indexes[x];
00918           break;
00919         }
00920         case GrayChannels:
00921         {
00922           phase_source[i]=QuantumScale*GetRedPixelComponent(p);
00923           break;
00924         }
00925       }
00926       i++;
00927       p++;
00928     }
00929   }
00930   if (fourier_info->modulus != MagickFalse)
00931     {
00932       i=0L;
00933       for (y=0L; y < (long) fourier_info->height; y++)
00934         for (x=0L; x < (long) fourier_info->width; x++)
00935         {
00936           phase_source[i]-=0.5;
00937           phase_source[i]*=(2.0*MagickPI);
00938           i++;
00939         }
00940     }
00941   magnitude_view=DestroyCacheView(magnitude_view);
00942   phase_view=DestroyCacheView(phase_view);
00943   magnitude=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
00944     fourier_info->center*sizeof(*magnitude));
00945   if (magnitude == (double *) NULL)
00946     {
00947       (void) ThrowMagickException(exception,GetMagickModule(),
00948         ResourceLimitError,"MemoryAllocationFailed","`%s'",
00949         magnitude_image->filename);
00950       magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
00951       phase_source=(double *) RelinquishMagickMemory(phase_source);
00952       return(MagickFalse);
00953     }
00954   status=InverseQuadrantSwap(fourier_info->width,fourier_info->height,
00955     magnitude_source,magnitude);
00956   magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
00957   phase=(double *) AcquireQuantumMemory((size_t) fourier_info->width,
00958     fourier_info->height*sizeof(*phase));
00959   if (phase == (double *) NULL)
00960     {
00961       (void) ThrowMagickException(exception,GetMagickModule(),
00962         ResourceLimitError,"MemoryAllocationFailed","`%s'",
00963         magnitude_image->filename);
00964       phase_source=(double *) RelinquishMagickMemory(phase_source);
00965       return(MagickFalse);
00966     }
00967   CorrectPhaseLHS(fourier_info->width,fourier_info->width,phase_source);
00968   if (status != MagickFalse)
00969     status=InverseQuadrantSwap(fourier_info->width,fourier_info->height,
00970       phase_source,phase);
00971   phase_source=(double *) RelinquishMagickMemory(phase_source);
00972   /*
00973     Merge two sets.
00974   */
00975   i=0L;
00976   if (fourier_info->modulus != MagickFalse)
00977     for (y=0L; y < (long) fourier_info->height; y++)
00978        for (x=0L; x < (long) fourier_info->center; x++)
00979        {
00980          fourier[i]=magnitude[i]*cos(phase[i])+I*magnitude[i]*sin(phase[i]);
00981          i++;
00982       }
00983   else
00984     for (y=0L; y < (long) fourier_info->height; y++)
00985       for (x=0L; x < (long) fourier_info->center; x++)
00986       {
00987         fourier[i]=magnitude[i]+I*phase[i];
00988         i++;
00989       }
00990   phase=(double *) RelinquishMagickMemory(phase);
00991   magnitude=(double *) RelinquishMagickMemory(magnitude);
00992   return(status);
00993 }
00994 
00995 static MagickBooleanType InverseFourierTransform(FourierInfo *fourier_info,
00996   fftw_complex *fourier,Image *image,ExceptionInfo *exception)
00997 {
00998   CacheView
00999     *image_view;
01000 
01001   double
01002     *source;
01003 
01004   fftw_plan
01005     fftw_c2r_plan;
01006 
01007   long
01008     y;
01009 
01010   register IndexPacket
01011     *indexes;
01012 
01013   register long
01014     i,
01015     x;
01016 
01017   register PixelPacket
01018     *q;
01019 
01020   source=(double *) AcquireQuantumMemory((size_t) fourier_info->width,
01021     fourier_info->height*sizeof(double));
01022   if (source == (double *) NULL)
01023     {
01024       (void) ThrowMagickException(exception,GetMagickModule(),
01025         ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
01026       return(MagickFalse);
01027     }
01028 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01029   #pragma omp critical (MagickCore_InverseFourierTransform)
01030 #endif
01031   fftw_c2r_plan=fftw_plan_dft_c2r_2d(fourier_info->width,fourier_info->height,
01032     fourier,source,FFTW_ESTIMATE);
01033   fftw_execute(fftw_c2r_plan);
01034   fftw_destroy_plan(fftw_c2r_plan);
01035   i=0L;
01036   image_view=AcquireCacheView(image);
01037   for (y=0L; y < (long) fourier_info->height; y++)
01038   {
01039     q=GetCacheViewAuthenticPixels(image_view,0L,y,fourier_info->width,1UL,
01040       exception);
01041     if (q == (PixelPacket *) NULL)
01042       break;
01043     indexes=GetCacheViewAuthenticIndexQueue(image_view);
01044     for (x=0L; x < (long) fourier_info->width; x++)
01045     {
01046       switch (fourier_info->channel)
01047       {
01048         case RedChannel:
01049         default:
01050         {
01051           q->red=ClampToQuantum(QuantumRange*source[i]);
01052           break;
01053         }
01054         case GreenChannel:
01055         {
01056           q->green=ClampToQuantum(QuantumRange*source[i]);
01057           break;
01058         }
01059         case BlueChannel:
01060         {
01061           q->blue=ClampToQuantum(QuantumRange*source[i]);
01062           break;
01063         }
01064         case OpacityChannel:
01065         {
01066           q->opacity=ClampToQuantum(QuantumRange*source[i]);
01067           break;
01068         }
01069         case IndexChannel:
01070         {
01071           indexes[x]=ClampToQuantum(QuantumRange*source[i]);
01072           break;
01073         }
01074         case GrayChannels:
01075         {
01076           q->red=ClampToQuantum(QuantumRange*source[i]);
01077           q->green=q->red;
01078           q->blue=q->red;
01079           break;
01080         }
01081       }
01082       i++;
01083       q++;
01084     }
01085     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
01086       break;
01087   }
01088   image_view=DestroyCacheView(image_view);
01089   source=(double *) RelinquishMagickMemory(source);
01090   return(MagickTrue);
01091 }
01092 
01093 static MagickBooleanType InverseFourierTransformChannel(
01094   const Image *magnitude_image,const Image *phase_image,
01095   const ChannelType channel,const MagickBooleanType modulus,
01096   Image *fourier_image,ExceptionInfo *exception)
01097 {
01098   double
01099     *magnitude,
01100     *phase;
01101 
01102   fftw_complex
01103     *fourier;
01104 
01105   FourierInfo
01106     fourier_info;
01107 
01108   MagickBooleanType
01109     status;
01110 
01111   size_t
01112     extent;
01113 
01114   fourier_info.width=magnitude_image->columns;
01115   if ((magnitude_image->columns != magnitude_image->rows) ||
01116       ((magnitude_image->columns % 2) != 0) ||
01117       ((magnitude_image->rows % 2) != 0))
01118     {
01119       extent=magnitude_image->columns < magnitude_image->rows ?
01120         magnitude_image->rows : magnitude_image->columns;
01121       fourier_info.width=(extent & 0x01) == 1 ? extent+1UL : extent;
01122     }
01123   fourier_info.height=fourier_info.width;
01124   fourier_info.center=(long) floor((double) fourier_info.width/2.0)+1L;
01125   fourier_info.channel=channel;
01126   fourier_info.modulus=modulus;
01127   magnitude=(double *) AcquireQuantumMemory((size_t) fourier_info.height,
01128     fourier_info.center*sizeof(double));
01129   if (magnitude == (double *) NULL)
01130     {
01131       (void) ThrowMagickException(exception,GetMagickModule(),
01132         ResourceLimitError,"MemoryAllocationFailed","`%s'",
01133         magnitude_image->filename);
01134       return(MagickFalse);
01135     }
01136   phase=(double *) AcquireQuantumMemory((size_t) fourier_info.height,
01137     fourier_info.center*sizeof(double));
01138   if (phase == (double *) NULL)
01139     {
01140       (void) ThrowMagickException(exception,GetMagickModule(),
01141         ResourceLimitError,"MemoryAllocationFailed","`%s'",
01142         magnitude_image->filename);
01143       magnitude=(double *) RelinquishMagickMemory(magnitude);
01144       return(MagickFalse);
01145     }
01146   fourier=(fftw_complex *) AcquireAlignedMemory((size_t) fourier_info.height,
01147     fourier_info.center*sizeof(*fourier));
01148   if (fourier == (fftw_complex *) NULL)
01149     {
01150       (void) ThrowMagickException(exception,GetMagickModule(),
01151         ResourceLimitError,"MemoryAllocationFailed","`%s'",
01152         magnitude_image->filename);
01153       phase=(double *) RelinquishMagickMemory(phase);
01154       magnitude=(double *) RelinquishMagickMemory(magnitude);
01155       return(MagickFalse);
01156     }
01157   status=InverseFourier(&fourier_info,magnitude_image,phase_image,fourier,
01158    exception);
01159   if (status != MagickFalse)
01160     status=InverseFourierTransform(&fourier_info,fourier,fourier_image,
01161       exception);
01162   fourier=(fftw_complex *) RelinquishAlignedMemory(fourier);
01163   phase=(double *) RelinquishMagickMemory(phase);
01164   magnitude=(double *) RelinquishMagickMemory(magnitude);
01165   return(status);
01166 }
01167 #endif
01168 
01169 MagickExport Image *InverseFourierTransformImage(const Image *magnitude_image,
01170   const Image *phase_image,const MagickBooleanType modulus,
01171   ExceptionInfo *exception)
01172 {
01173   Image
01174     *fourier_image;
01175 
01176   assert(magnitude_image != (Image *) NULL);
01177   assert(magnitude_image->signature == MagickSignature);
01178   if (magnitude_image->debug != MagickFalse)
01179     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
01180       magnitude_image->filename);
01181   if (phase_image == (Image *) NULL)
01182     {
01183       (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
01184         "ImageSequenceRequired","`%s'",magnitude_image->filename);
01185       return((Image *) NULL);
01186     }
01187 #if !defined(MAGICKCORE_FFTW_DELEGATE)
01188   fourier_image=(Image *) NULL;
01189   (void) modulus;
01190   (void) ThrowMagickException(exception,GetMagickModule(),
01191     MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","`%s' (FFTW)",
01192     magnitude_image->filename);
01193 #else
01194   {
01195     fourier_image=CloneImage(magnitude_image,magnitude_image->columns,
01196       magnitude_image->rows,MagickFalse,exception);
01197     if (fourier_image != (Image *) NULL)
01198       {
01199         MagickBooleanType
01200           is_gray,
01201           status;
01202 
01203         register long
01204           i;
01205 
01206         status=MagickTrue;
01207         is_gray=IsGrayImage(magnitude_image,exception);
01208         if (is_gray != MagickFalse)
01209           is_gray=IsGrayImage(phase_image,exception);
01210 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01211         #pragma omp parallel for schedule(dynamic,4) shared(status)
01212 #endif
01213         for (i=0L; i < 5L; i++)
01214         {
01215           MagickBooleanType
01216             thread_status;
01217 
01218           thread_status=MagickTrue;
01219           switch (i)
01220           {
01221             case 0:
01222             {
01223               if (is_gray != MagickFalse)
01224                 {
01225                   thread_status=InverseFourierTransformChannel(magnitude_image,
01226                     phase_image,GrayChannels,modulus,fourier_image,exception);
01227                   break;
01228                 }
01229               thread_status=InverseFourierTransformChannel(magnitude_image,
01230                 phase_image,RedChannel,modulus,fourier_image,exception);
01231               break;
01232             }
01233             case 1:
01234             {
01235               if (is_gray == MagickFalse)
01236                 thread_status=InverseFourierTransformChannel(magnitude_image,
01237                   phase_image,GreenChannel,modulus,fourier_image,exception);
01238               break;
01239             }
01240             case 2:
01241             {
01242               if (is_gray == MagickFalse)
01243                 thread_status=InverseFourierTransformChannel(magnitude_image,
01244                   phase_image,BlueChannel,modulus,fourier_image,exception);
01245               break;
01246             }
01247             case 3:
01248             {
01249               if (magnitude_image->matte != MagickFalse)
01250                 thread_status=InverseFourierTransformChannel(magnitude_image,
01251                   phase_image,OpacityChannel,modulus,fourier_image,exception);
01252               break;
01253             }
01254             case 4:
01255             {
01256               if (magnitude_image->colorspace == CMYKColorspace)
01257                 thread_status=InverseFourierTransformChannel(magnitude_image,
01258                   phase_image,IndexChannel,modulus,fourier_image,exception);
01259               break;
01260             }
01261           }
01262           if (thread_status == MagickFalse)
01263             status=thread_status;
01264         }
01265         if (status == MagickFalse)
01266           fourier_image=DestroyImage(fourier_image);
01267       }
01268       fftw_cleanup();
01269   }
01270 #endif
01271   return(fourier_image);
01272 }
Generated by  doxygen 1.6.2-20100208