fourier.c revision 2e035cd272c0993d28f757f4a913070170095939
13ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
23ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
33ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
43ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
53ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
63ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%               FFFFF   OOO   U   U  RRRR   IIIII  EEEEE  RRRR                %
73ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%               F      O   O  U   U  R   R    I    E      R   R               %
83ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%               FFF    O   O  U   U  RRRR     I    EEE    RRRR                %
93ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%               F      O   O  U   U  R R      I    E      R R                 %
103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%               F       OOO    UUU   R  R   IIIII  EEEEE  R  R                %
113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                MagickCore Discrete Fourier Transform Methods                %
143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                              Software Design                                %
163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                Sean Burke                                   %
173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                               Fred Weinhaus                                 %
18de984cdc3631106b1cbbb8d3972b76a0fc27e8e8cristy%                                   Cristy                                    %
193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                 July 2009                                   %
203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
227ce65e7125a4e1df1a274ce373c537a9df9c16cdCristy%  Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization      %
233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  dedicated to making software imaging solutions freely available.           %
243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  You may not use this file except in compliance with the License.  You may  %
263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  obtain a copy of the License at                                            %
273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    http://www.imagemagick.org/script/license.php                            %
293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Unless required by applicable law or agreed to in writing, software        %
313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  distributed under the License is distributed on an "AS IS" BASIS,          %
323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  See the License for the specific language governing permissions and        %
343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  limitations under the License.                                             %
353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Include declarations.
443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
454c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/studio.h"
4699dc036190f292a67801dc4b141898bf18c96b36cristy#include "MagickCore/artifact.h"
474c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/attribute.h"
487d4aa38318c20a4309d855f45e3744c9f300f697cristy#include "MagickCore/blob.h"
494c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/cache.h"
504c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/image.h"
514c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/image-private.h"
524c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/list.h"
534c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/fourier.h"
544c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/log.h"
554c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/memory_.h"
564c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/monitor.h"
571042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy#include "MagickCore/monitor-private.h"
584c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/pixel-accessor.h"
5999dc036190f292a67801dc4b141898bf18c96b36cristy#include "MagickCore/pixel-private.h"
604c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/property.h"
614c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/quantum-private.h"
62ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy#include "MagickCore/resource_.h"
6334b78eacf3bef963cade67c70f5f12785b9fe702cristy#include "MagickCore/string-private.h"
644c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/thread-private.h"
653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#if defined(MAGICKCORE_FFTW_DELEGATE)
6656ed31cc763800a9fb1f0df96104c354b40d2cbccristy#if defined(MAGICKCORE_HAVE_COMPLEX_H)
673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include <complex.h>
6847b022b2592e21e468c453ad44f550b62f77b2cbcristy#endif
6947b022b2592e21e468c453ad44f550b62f77b2cbcristy#include <fftw3.h>
7047b022b2592e21e468c453ad44f550b62f77b2cbcristy#if !defined(MAGICKCORE_HAVE_CABS)
7156ed31cc763800a9fb1f0df96104c354b40d2cbccristy#define cabs(z)  (sqrt(z[0]*z[0]+z[1]*z[1]))
7247b022b2592e21e468c453ad44f550b62f77b2cbcristy#endif
7347b022b2592e21e468c453ad44f550b62f77b2cbcristy#if !defined(MAGICKCORE_HAVE_CARG)
744da3ba3eedd349b48f5c8bbb9f15faee04f6e09fcristy#define carg(z)  (atan2(cimag(z),creal(z)))
7547b022b2592e21e468c453ad44f550b62f77b2cbcristy#endif
7647b022b2592e21e468c453ad44f550b62f77b2cbcristy#if !defined(MAGICKCORE_HAVE_CIMAG)
7756ed31cc763800a9fb1f0df96104c354b40d2cbccristy#define cimag(z)  (z[1])
7856ed31cc763800a9fb1f0df96104c354b40d2cbccristy#endif
7947b022b2592e21e468c453ad44f550b62f77b2cbcristy#if !defined(MAGICKCORE_HAVE_CREAL)
8047b022b2592e21e468c453ad44f550b62f77b2cbcristy#define creal(z)  (z[0])
8147b022b2592e21e468c453ad44f550b62f77b2cbcristy#endif
823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Typedef declarations.
863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
873ed852eea50f9d4cd633efb8c2b054b8e33c253cristytypedef struct _FourierInfo
883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
89d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy  PixelChannel
903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    channel;
913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    modulus;
943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
95bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  size_t
963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    width,
973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    height;
983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
99bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  ssize_t
1003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    center;
1013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy} FourierInfo;
1023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
1043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
107790190d9d1e6f011220d0003ce5b51063f0ab417cristy%                                                                             %
108790190d9d1e6f011220d0003ce5b51063f0ab417cristy%     C o m p l e x I m a g e s                                               %
109790190d9d1e6f011220d0003ce5b51063f0ab417cristy%                                                                             %
110790190d9d1e6f011220d0003ce5b51063f0ab417cristy%                                                                             %
111790190d9d1e6f011220d0003ce5b51063f0ab417cristy%                                                                             %
112790190d9d1e6f011220d0003ce5b51063f0ab417cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
113790190d9d1e6f011220d0003ce5b51063f0ab417cristy%
114790190d9d1e6f011220d0003ce5b51063f0ab417cristy%  ComplexImages() performs complex mathematics on an image sequence.
115790190d9d1e6f011220d0003ce5b51063f0ab417cristy%
116790190d9d1e6f011220d0003ce5b51063f0ab417cristy%  The format of the ComplexImages method is:
117790190d9d1e6f011220d0003ce5b51063f0ab417cristy%
1184167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy%      MagickBooleanType ComplexImages(Image *images,const ComplexOperator op,
1194167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy%        ExceptionInfo *exception)
120790190d9d1e6f011220d0003ce5b51063f0ab417cristy%
121790190d9d1e6f011220d0003ce5b51063f0ab417cristy%  A description of each parameter follows:
122790190d9d1e6f011220d0003ce5b51063f0ab417cristy%
123790190d9d1e6f011220d0003ce5b51063f0ab417cristy%    o image: the image.
124790190d9d1e6f011220d0003ce5b51063f0ab417cristy%
1252e035cd272c0993d28f757f4a913070170095939Cristy%    o op: A complex operator.
126790190d9d1e6f011220d0003ce5b51063f0ab417cristy%
127790190d9d1e6f011220d0003ce5b51063f0ab417cristy%    o exception: return any errors or warnings in this structure.
128790190d9d1e6f011220d0003ce5b51063f0ab417cristy%
129790190d9d1e6f011220d0003ce5b51063f0ab417cristy*/
130220c4d505bfb9cf557e8ec1616d7cdc0596379b8cristyMagickExport Image *ComplexImages(const Image *images,const ComplexOperator op,
131220c4d505bfb9cf557e8ec1616d7cdc0596379b8cristy  ExceptionInfo *exception)
132790190d9d1e6f011220d0003ce5b51063f0ab417cristy{
133790190d9d1e6f011220d0003ce5b51063f0ab417cristy#define ComplexImageTag  "Complex/Image"
134790190d9d1e6f011220d0003ce5b51063f0ab417cristy
135790190d9d1e6f011220d0003ce5b51063f0ab417cristy  CacheView
1361042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    *Ai_view,
1371042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    *Ar_view,
1381042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    *Bi_view,
1391042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    *Br_view,
1401042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    *Ci_view,
1411042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    *Cr_view;
1421042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy
14334b78eacf3bef963cade67c70f5f12785b9fe702cristy  const char
14434b78eacf3bef963cade67c70f5f12785b9fe702cristy    *artifact;
14534b78eacf3bef963cade67c70f5f12785b9fe702cristy
1461042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  const Image
1471042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    *Ai_image,
1481042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    *Ar_image,
1491042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    *Bi_image,
1501042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    *Br_image;
151790190d9d1e6f011220d0003ce5b51063f0ab417cristy
15234b78eacf3bef963cade67c70f5f12785b9fe702cristy  double
15334b78eacf3bef963cade67c70f5f12785b9fe702cristy    snr;
15434b78eacf3bef963cade67c70f5f12785b9fe702cristy
155790190d9d1e6f011220d0003ce5b51063f0ab417cristy  Image
1561042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    *Ci_image,
1571042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    *complex_images,
15834919ed07da683cc334cd74e3c9d9c29c8b79b98cristy    *Cr_image,
15934919ed07da683cc334cd74e3c9d9c29c8b79b98cristy    *image;
160790190d9d1e6f011220d0003ce5b51063f0ab417cristy
161790190d9d1e6f011220d0003ce5b51063f0ab417cristy  MagickBooleanType
162790190d9d1e6f011220d0003ce5b51063f0ab417cristy    status;
163790190d9d1e6f011220d0003ce5b51063f0ab417cristy
164790190d9d1e6f011220d0003ce5b51063f0ab417cristy  MagickOffsetType
165790190d9d1e6f011220d0003ce5b51063f0ab417cristy    progress;
166790190d9d1e6f011220d0003ce5b51063f0ab417cristy
167790190d9d1e6f011220d0003ce5b51063f0ab417cristy  ssize_t
168790190d9d1e6f011220d0003ce5b51063f0ab417cristy    y;
169790190d9d1e6f011220d0003ce5b51063f0ab417cristy
170790190d9d1e6f011220d0003ce5b51063f0ab417cristy  assert(images != (Image *) NULL);
171e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(images->signature == MagickCoreSignature);
172790190d9d1e6f011220d0003ce5b51063f0ab417cristy  if (images->debug != MagickFalse)
173790190d9d1e6f011220d0003ce5b51063f0ab417cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
174790190d9d1e6f011220d0003ce5b51063f0ab417cristy  assert(exception != (ExceptionInfo *) NULL);
175e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(exception->signature == MagickCoreSignature);
1761042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  if (images->next == (Image *) NULL)
1771042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    {
1781042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy      (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
1791042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy        "ImageSequenceRequired","`%s'",images->filename);
1801042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy      return((Image *) NULL);
1811042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    }
18234919ed07da683cc334cd74e3c9d9c29c8b79b98cristy  image=CloneImage(images,images->columns,images->rows,MagickTrue,exception);
18334919ed07da683cc334cd74e3c9d9c29c8b79b98cristy  if (image == (Image *) NULL)
1841042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    return((Image *) NULL);
18534919ed07da683cc334cd74e3c9d9c29c8b79b98cristy  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
18634919ed07da683cc334cd74e3c9d9c29c8b79b98cristy    {
18734919ed07da683cc334cd74e3c9d9c29c8b79b98cristy      image=DestroyImageList(image);
18834919ed07da683cc334cd74e3c9d9c29c8b79b98cristy      return(image);
18934919ed07da683cc334cd74e3c9d9c29c8b79b98cristy    }
1902e035cd272c0993d28f757f4a913070170095939Cristy  image->depth=32UL;
19134919ed07da683cc334cd74e3c9d9c29c8b79b98cristy  complex_images=NewImageList();
19234919ed07da683cc334cd74e3c9d9c29c8b79b98cristy  AppendImageToList(&complex_images,image);
19334919ed07da683cc334cd74e3c9d9c29c8b79b98cristy  image=CloneImage(images,images->columns,images->rows,MagickTrue,exception);
19434919ed07da683cc334cd74e3c9d9c29c8b79b98cristy  if (image == (Image *) NULL)
19534919ed07da683cc334cd74e3c9d9c29c8b79b98cristy    {
19634919ed07da683cc334cd74e3c9d9c29c8b79b98cristy      complex_images=DestroyImageList(complex_images);
19734919ed07da683cc334cd74e3c9d9c29c8b79b98cristy      return(complex_images);
19834919ed07da683cc334cd74e3c9d9c29c8b79b98cristy    }
199dc6589cac93cf46a2d9d7ee71c48df8c215f398fcristy  AppendImageToList(&complex_images,image);
2002e035cd272c0993d28f757f4a913070170095939Cristy  complex_images->storage_class=DirectClass;
2012e035cd272c0993d28f757f4a913070170095939Cristy  complex_images->depth=32UL;
2021042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  /*
2031042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    Apply complex mathematics to image pixels.
2041042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  */
20534b78eacf3bef963cade67c70f5f12785b9fe702cristy  artifact=GetImageArtifact(image,"complex:snr");
20634b78eacf3bef963cade67c70f5f12785b9fe702cristy  snr=0.0;
20734b78eacf3bef963cade67c70f5f12785b9fe702cristy  if (artifact != (const char *) NULL)
20834b78eacf3bef963cade67c70f5f12785b9fe702cristy    snr=StringToDouble(artifact,(char **) NULL);
2091042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Ar_image=images;
2101042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Ai_image=images->next;
2118dc6a07d751896a7c400a6d888a5964c538fad2dcristy  Br_image=images;
2128dc6a07d751896a7c400a6d888a5964c538fad2dcristy  Bi_image=images->next;
2138dc6a07d751896a7c400a6d888a5964c538fad2dcristy  if ((images->next->next != (Image *) NULL) &&
2148dc6a07d751896a7c400a6d888a5964c538fad2dcristy      (images->next->next->next != (Image *) NULL))
2151042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    {
2161042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy      Br_image=images->next->next;
2171042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy      Bi_image=images->next->next->next;
2181042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    }
2191042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Cr_image=complex_images;
2201042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Ci_image=complex_images->next;
2211042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Ar_view=AcquireVirtualCacheView(Ar_image,exception);
2221042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Ai_view=AcquireVirtualCacheView(Ai_image,exception);
2231042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Br_view=AcquireVirtualCacheView(Br_image,exception);
2241042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Bi_view=AcquireVirtualCacheView(Bi_image,exception);
2251042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Cr_view=AcquireAuthenticCacheView(Cr_image,exception);
2261042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Ci_view=AcquireAuthenticCacheView(Ci_image,exception);
2271042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  status=MagickTrue;
2281042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  progress=0;
2291042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
2304167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy  #pragma omp parallel for schedule(static,4) shared(progress,status) \
2314167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy    magick_threads(images,complex_images,images->rows,1L)
2321042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy#endif
2331042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  for (y=0; y < (ssize_t) images->rows; y++)
2341042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  {
2351042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    register const Quantum
23605d2ff7ebf21f659f5b11e45afb294e152f4330cdirk      *magick_restrict Ai,
23705d2ff7ebf21f659f5b11e45afb294e152f4330cdirk      *magick_restrict Ar,
23805d2ff7ebf21f659f5b11e45afb294e152f4330cdirk      *magick_restrict Bi,
23905d2ff7ebf21f659f5b11e45afb294e152f4330cdirk      *magick_restrict Br;
2401042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy
2411042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    register Quantum
24205d2ff7ebf21f659f5b11e45afb294e152f4330cdirk      *magick_restrict Ci,
24305d2ff7ebf21f659f5b11e45afb294e152f4330cdirk      *magick_restrict Cr;
2441042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy
2451042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    register ssize_t
2461042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy      x;
2471042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy
24834919ed07da683cc334cd74e3c9d9c29c8b79b98cristy    if (status == MagickFalse)
24934919ed07da683cc334cd74e3c9d9c29c8b79b98cristy      continue;
2504167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy    Ar=GetCacheViewVirtualPixels(Ar_view,0,y,Ar_image->columns,1,exception);
2514167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy    Ai=GetCacheViewVirtualPixels(Ai_view,0,y,Ai_image->columns,1,exception);
2524167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy    Br=GetCacheViewVirtualPixels(Br_view,0,y,Br_image->columns,1,exception);
2534167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy    Bi=GetCacheViewVirtualPixels(Bi_view,0,y,Bi_image->columns,1,exception);
2544167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy    Cr=QueueCacheViewAuthenticPixels(Cr_view,0,y,Cr_image->columns,1,exception);
2554167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy    Ci=QueueCacheViewAuthenticPixels(Ci_view,0,y,Ci_image->columns,1,exception);
2561042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    if ((Ar == (const Quantum *) NULL) || (Ai == (const Quantum *) NULL) ||
2571042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy        (Br == (const Quantum *) NULL) || (Bi == (const Quantum *) NULL) ||
2581042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy        (Cr == (Quantum *) NULL) || (Ci == (Quantum *) NULL))
2591042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy      {
2601042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy        status=MagickFalse;
2611042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy        continue;
2621042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy      }
2631042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    for (x=0; x < (ssize_t) images->columns; x++)
2641042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    {
2659f654472e80883bb7c4ec299036733e0e23570d7cristy      register ssize_t
2669f654472e80883bb7c4ec299036733e0e23570d7cristy        i;
2679f654472e80883bb7c4ec299036733e0e23570d7cristy
2689f654472e80883bb7c4ec299036733e0e23570d7cristy      for (i=0; i < (ssize_t) GetPixelChannels(images); i++)
2699f654472e80883bb7c4ec299036733e0e23570d7cristy      {
270220c4d505bfb9cf557e8ec1616d7cdc0596379b8cristy        switch (op)
2719f654472e80883bb7c4ec299036733e0e23570d7cristy        {
27219f7886e4423cd5ce3eef31092942f55ba770983cristy          case AddComplexOperator:
27319f7886e4423cd5ce3eef31092942f55ba770983cristy          {
27419f7886e4423cd5ce3eef31092942f55ba770983cristy            Cr[i]=Ar[i]+Br[i];
27519f7886e4423cd5ce3eef31092942f55ba770983cristy            Ci[i]=Ai[i]+Bi[i];
27619f7886e4423cd5ce3eef31092942f55ba770983cristy            break;
27719f7886e4423cd5ce3eef31092942f55ba770983cristy          }
2789f654472e80883bb7c4ec299036733e0e23570d7cristy          case ConjugateComplexOperator:
2799f654472e80883bb7c4ec299036733e0e23570d7cristy          default:
2809f654472e80883bb7c4ec299036733e0e23570d7cristy          {
2819f654472e80883bb7c4ec299036733e0e23570d7cristy            Cr[i]=Ar[i];
2829f654472e80883bb7c4ec299036733e0e23570d7cristy            Ci[i]=(-Bi[i]);
2839f654472e80883bb7c4ec299036733e0e23570d7cristy            break;
2849f654472e80883bb7c4ec299036733e0e23570d7cristy          }
2859f654472e80883bb7c4ec299036733e0e23570d7cristy          case DivideComplexOperator:
2869f654472e80883bb7c4ec299036733e0e23570d7cristy          {
2879f654472e80883bb7c4ec299036733e0e23570d7cristy            double
2889f654472e80883bb7c4ec299036733e0e23570d7cristy              gamma;
2899f654472e80883bb7c4ec299036733e0e23570d7cristy
29034b78eacf3bef963cade67c70f5f12785b9fe702cristy            gamma=PerceptibleReciprocal(Br[i]*Br[i]+Bi[i]*Bi[i]+snr);
2919f654472e80883bb7c4ec299036733e0e23570d7cristy            Cr[i]=gamma*(Ar[i]*Br[i]+Ai[i]*Bi[i]);
292857c8a100c50bd902586a902c27fccab271dce1dcristy            Ci[i]=gamma*(Ai[i]*Br[i]-Ar[i]*Bi[i]);
2939f654472e80883bb7c4ec299036733e0e23570d7cristy            break;
2949f654472e80883bb7c4ec299036733e0e23570d7cristy          }
295f46941ca310386db5b9939840c884c6f8a5c7189cristy          case MagnitudePhaseComplexOperator:
296f46941ca310386db5b9939840c884c6f8a5c7189cristy          {
2978526a9763e0671ebad481fd00679fb857ce8d84acristy            Cr[i]=sqrt(Ar[i]*Ar[i]+Ai[i]*Ai[i]);
2984ab069406391dd3d34359d17a6ab7333f7200729cristy            Ci[i]=atan2(Ai[i],Ar[i])/(2.0*MagickPI)+0.5;
299f46941ca310386db5b9939840c884c6f8a5c7189cristy            break;
300f46941ca310386db5b9939840c884c6f8a5c7189cristy          }
3019f654472e80883bb7c4ec299036733e0e23570d7cristy          case MultiplyComplexOperator:
3029f654472e80883bb7c4ec299036733e0e23570d7cristy          {
30315b07b3f81434e5cee2ed16d51ec3f504949d992cristy            Cr[i]=QuantumScale*(Ar[i]*Br[i]-Ai[i]*Bi[i]);
30415b07b3f81434e5cee2ed16d51ec3f504949d992cristy            Ci[i]=QuantumScale*(Ai[i]*Br[i]+Ar[i]*Bi[i]);
305f46941ca310386db5b9939840c884c6f8a5c7189cristy            break;
306f46941ca310386db5b9939840c884c6f8a5c7189cristy          }
307f46941ca310386db5b9939840c884c6f8a5c7189cristy          case RealImaginaryComplexOperator:
308f46941ca310386db5b9939840c884c6f8a5c7189cristy          {
3094ab069406391dd3d34359d17a6ab7333f7200729cristy            Cr[i]=Ar[i]*cos(2.0*MagickPI*(Ai[i]-0.5));
3104ab069406391dd3d34359d17a6ab7333f7200729cristy            Ci[i]=Ar[i]*sin(2.0*MagickPI*(Ai[i]-0.5));
3119f654472e80883bb7c4ec299036733e0e23570d7cristy            break;
3129f654472e80883bb7c4ec299036733e0e23570d7cristy          }
31319f7886e4423cd5ce3eef31092942f55ba770983cristy          case SubtractComplexOperator:
31419f7886e4423cd5ce3eef31092942f55ba770983cristy          {
31519f7886e4423cd5ce3eef31092942f55ba770983cristy            Cr[i]=Ar[i]-Br[i];
31619f7886e4423cd5ce3eef31092942f55ba770983cristy            Ci[i]=Ai[i]-Bi[i];
31719f7886e4423cd5ce3eef31092942f55ba770983cristy            break;
31819f7886e4423cd5ce3eef31092942f55ba770983cristy          }
3199f654472e80883bb7c4ec299036733e0e23570d7cristy        }
3209f654472e80883bb7c4ec299036733e0e23570d7cristy      }
3214167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy      Ar+=GetPixelChannels(Ar_image);
3224167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy      Ai+=GetPixelChannels(Ai_image);
3234167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy      Br+=GetPixelChannels(Br_image);
3244167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy      Bi+=GetPixelChannels(Bi_image);
3254167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy      Cr+=GetPixelChannels(Cr_image);
3264167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy      Ci+=GetPixelChannels(Ci_image);
3271042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    }
3281042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    if (SyncCacheViewAuthenticPixels(Ci_view,exception) == MagickFalse)
3291042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy      status=MagickFalse;
3301042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    if (SyncCacheViewAuthenticPixels(Cr_view,exception) == MagickFalse)
3311042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy      status=MagickFalse;
3321042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    if (images->progress_monitor != (MagickProgressMonitor) NULL)
3331042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy      {
3341042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy        MagickBooleanType
3351042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy          proceed;
3361042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy
3371042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
3381042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy        #pragma omp critical (MagickCore_ComplexImages)
3391042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy#endif
3401042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy        proceed=SetImageProgress(images,ComplexImageTag,progress++,
3411042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy          images->rows);
3421042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy        if (proceed == MagickFalse)
3431042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy          status=MagickFalse;
3441042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy      }
3451042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  }
3461042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Cr_view=DestroyCacheView(Cr_view);
3471042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Ci_view=DestroyCacheView(Ci_view);
3481042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Br_view=DestroyCacheView(Br_view);
3491042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Bi_view=DestroyCacheView(Bi_view);
3501042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Ar_view=DestroyCacheView(Ar_view);
3511042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Ai_view=DestroyCacheView(Ai_view);
3521042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  if (status == MagickFalse)
3531042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    complex_images=DestroyImageList(complex_images);
3541042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  return(complex_images);
355790190d9d1e6f011220d0003ce5b51063f0ab417cristy}
356790190d9d1e6f011220d0003ce5b51063f0ab417cristy
357790190d9d1e6f011220d0003ce5b51063f0ab417cristy/*
358790190d9d1e6f011220d0003ce5b51063f0ab417cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
359790190d9d1e6f011220d0003ce5b51063f0ab417cristy%                                                                             %
360790190d9d1e6f011220d0003ce5b51063f0ab417cristy%                                                                             %
3613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
3623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%     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                 %
3633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
3643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
3653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
3663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  ForwardFourierTransformImage() implements the discrete Fourier transform
3693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  (DFT) of the image either as a magnitude / phase or real / imaginary image
3703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  pair.
3713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the ForwadFourierTransformImage method is:
3733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      Image *ForwardFourierTransformImage(const Image *image,
3753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%        const MagickBooleanType modulus,ExceptionInfo *exception)
3763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
3783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: the image.
3803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o modulus: if true, return as transform as a magnitude / phase pair
3823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      otherwise a real / imaginary image pair.
3833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o exception: return any errors or warnings in this structure.
3853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
3873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#if defined(MAGICKCORE_FFTW_DELEGATE)
3893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
390c4ea4a479c90f81168aa2b99e7680c7b0459d415cristystatic MagickBooleanType RollFourier(const size_t width,const size_t height,
391699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  const ssize_t x_offset,const ssize_t y_offset,double *roll_pixels)
3923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
3933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double
394699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    *source_pixels;
3953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3967d4aa38318c20a4309d855f45e3744c9f300f697cristy  MemoryInfo
397699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    *source_info;
3987d4aa38318c20a4309d855f45e3744c9f300f697cristy
399c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy  register ssize_t
400c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy    i,
401c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy    x;
402c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy
403bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  ssize_t
4043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    u,
4053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    v,
4063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    y;
4073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
4092da0535a82cc655e5a48deac466bd6fcef1f4924cristy    Move zero frequency (DC, average color) from (0,0) to (width/2,height/2).
4103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
4112e035cd272c0993d28f757f4a913070170095939Cristy  source_info=AcquireVirtualMemory(width,height*sizeof(*source_pixels));
412699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  if (source_info == (MemoryInfo *) NULL)
4133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(MagickFalse);
414699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  source_pixels=(double *) GetVirtualMemoryBlob(source_info);
4153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  i=0L;
416bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=0L; y < (ssize_t) height; y++)
4173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
4183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (y_offset < 0L)
419bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      v=((y+y_offset) < 0L) ? y+y_offset+(ssize_t) height : y+y_offset;
4203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    else
421bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      v=((y+y_offset) > ((ssize_t) height-1L)) ? y+y_offset-(ssize_t) height :
4223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        y+y_offset;
423bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (x=0L; x < (ssize_t) width; x++)
4243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
4253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (x_offset < 0L)
426bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy        u=((x+x_offset) < 0L) ? x+x_offset+(ssize_t) width : x+x_offset;
4273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      else
428bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy        u=((x+x_offset) > ((ssize_t) width-1L)) ? x+x_offset-(ssize_t) width :
4293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          x+x_offset;
430699ae5b6cbee363e53f58e0fedd414f282d07eddcristy      source_pixels[v*width+u]=roll_pixels[i++];
431c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy    }
4323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
433699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  (void) CopyMagickMemory(roll_pixels,source_pixels,height*width*
434699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    sizeof(*source_pixels));
435699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  source_info=RelinquishVirtualMemory(source_info);
4363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickTrue);
4373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
4383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
439bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristystatic MagickBooleanType ForwardQuadrantSwap(const size_t width,
440699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  const size_t height,double *source_pixels,double *forward_pixels)
4413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
4423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
4433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
4443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
445bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
4463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    x;
4473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
448c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy  ssize_t
449c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy    center,
450c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy    y;
451c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy
4523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
4533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Swap quadrants.
4543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
4552e035cd272c0993d28f757f4a913070170095939Cristy  center=(ssize_t) (width/2L)+1L;
456699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  status=RollFourier((size_t) center,height,0L,(ssize_t) height/2L,
457699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    source_pixels);
4583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (status == MagickFalse)
4593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(MagickFalse);
460bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=0L; y < (ssize_t) height; y++)
4616831e2f47f00e8b78275319e4aec01d120a3876fCristy    for (x=0L; x < (ssize_t) (width/2L); x++)
4623d04ed7ddc7a93c09476e84cc64412687bf5261acristy      forward_pixels[y*width+x+width/2L]=source_pixels[y*center+x];
463bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=1; y < (ssize_t) height; y++)
4646831e2f47f00e8b78275319e4aec01d120a3876fCristy    for (x=0L; x < (ssize_t) (width/2L); x++)
4659b1d6c756cb32746846b038ccb0439db540ba509cristy      forward_pixels[(height-y)*width+width/2L-x-1L]=
4663d04ed7ddc7a93c09476e84cc64412687bf5261acristy        source_pixels[y*center+x+1L];
467bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (x=0L; x < (ssize_t) (width/2L); x++)
4686831e2f47f00e8b78275319e4aec01d120a3876fCristy    forward_pixels[width/2L-x-1L]=source_pixels[x+1L];
4693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickTrue);
4703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
4713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
472c4ea4a479c90f81168aa2b99e7680c7b0459d415cristystatic void CorrectPhaseLHS(const size_t width,const size_t height,
473699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  double *fourier_pixels)
4743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
475bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
4763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    x;
4773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4789d314ff2c17a77996c05413c2013880387e50f0ecristy  ssize_t
4799d314ff2c17a77996c05413c2013880387e50f0ecristy    y;
4809d314ff2c17a77996c05413c2013880387e50f0ecristy
481bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=0L; y < (ssize_t) height; y++)
482bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (x=0L; x < (ssize_t) (width/2L); x++)
483699ae5b6cbee363e53f58e0fedd414f282d07eddcristy      fourier_pixels[y*width+x]*=(-1.0);
4843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
4853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4863ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic MagickBooleanType ForwardFourier(const FourierInfo *fourier_info,
4873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Image *image,double *magnitude,double *phase,ExceptionInfo *exception)
4883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
4893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  CacheView
4903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *magnitude_view,
4913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *phase_view;
4923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double
4947d4aa38318c20a4309d855f45e3744c9f300f697cristy    *magnitude_pixels,
4957d4aa38318c20a4309d855f45e3744c9f300f697cristy    *phase_pixels;
4963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Image
4983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *magnitude_image,
4993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *phase_image;
5003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
5023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
5033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5047d4aa38318c20a4309d855f45e3744c9f300f697cristy  MemoryInfo
5057d4aa38318c20a4309d855f45e3744c9f300f697cristy    *magnitude_info,
5067d4aa38318c20a4309d855f45e3744c9f300f697cristy    *phase_info;
5077d4aa38318c20a4309d855f45e3744c9f300f697cristy
5084c08aed51c5899665ade97263692328eea4af106cristy  register Quantum
5093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *q;
5103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
511f5742794873c63f8b052150a2f44015e1ad55356cristy  register ssize_t
512f5742794873c63f8b052150a2f44015e1ad55356cristy    x;
513f5742794873c63f8b052150a2f44015e1ad55356cristy
514c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy  ssize_t
515c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy    i,
516c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy    y;
517c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy
5183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  magnitude_image=GetFirstImageInList(image);
5193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  phase_image=GetNextImageInList(image);
5203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (phase_image == (Image *) NULL)
5213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
5223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
5232e035cd272c0993d28f757f4a913070170095939Cristy        "ImageSequenceRequired","`%s'",image->filename);
5243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return(MagickFalse);
5253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
5263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
5273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Create "Fourier Transform" image from constituent arrays.
5283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
5292e035cd272c0993d28f757f4a913070170095939Cristy  magnitude_info=AcquireVirtualMemory((size_t) fourier_info->width,
5302e035cd272c0993d28f757f4a913070170095939Cristy    fourier_info->height*sizeof(*magnitude_pixels));
5312e035cd272c0993d28f757f4a913070170095939Cristy  phase_info=AcquireVirtualMemory((size_t) fourier_info->width,
5322e035cd272c0993d28f757f4a913070170095939Cristy    fourier_info->height*sizeof(*phase_pixels));
533bb3c02e054634545e7595cea2048c07de0407f1acristy  if ((magnitude_info == (MemoryInfo *) NULL) ||
534bb3c02e054634545e7595cea2048c07de0407f1acristy      (phase_info == (MemoryInfo *) NULL))
5353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
5367d4aa38318c20a4309d855f45e3744c9f300f697cristy      if (phase_info != (MemoryInfo *) NULL)
5377d4aa38318c20a4309d855f45e3744c9f300f697cristy        phase_info=RelinquishVirtualMemory(phase_info);
5387d4aa38318c20a4309d855f45e3744c9f300f697cristy      if (magnitude_info != (MemoryInfo *) NULL)
5397d4aa38318c20a4309d855f45e3744c9f300f697cristy        magnitude_info=RelinquishVirtualMemory(magnitude_info);
5403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) ThrowMagickException(exception,GetMagickModule(),
541efe601ce9ea5ad34ad0e8ad6e61d9be9b148b2a3cristy        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
5423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return(MagickFalse);
5433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
5447d4aa38318c20a4309d855f45e3744c9f300f697cristy  magnitude_pixels=(double *) GetVirtualMemoryBlob(magnitude_info);
5457d4aa38318c20a4309d855f45e3744c9f300f697cristy  (void) ResetMagickMemory(magnitude_pixels,0,fourier_info->height*
5467d4aa38318c20a4309d855f45e3744c9f300f697cristy    fourier_info->width*sizeof(*magnitude_pixels));
547bb3c02e054634545e7595cea2048c07de0407f1acristy  phase_pixels=(double *) GetVirtualMemoryBlob(phase_info);
5487d4aa38318c20a4309d855f45e3744c9f300f697cristy  (void) ResetMagickMemory(phase_pixels,0,fourier_info->height*
5497d4aa38318c20a4309d855f45e3744c9f300f697cristy    fourier_info->width*sizeof(*phase_pixels));
55013c99c4243ef58ec6f752aba6df9970ec16c87e6cristy  status=ForwardQuadrantSwap(fourier_info->width,fourier_info->height,
5517d4aa38318c20a4309d855f45e3744c9f300f697cristy    magnitude,magnitude_pixels);
5523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (status != MagickFalse)
55313c99c4243ef58ec6f752aba6df9970ec16c87e6cristy    status=ForwardQuadrantSwap(fourier_info->width,fourier_info->height,phase,
5547d4aa38318c20a4309d855f45e3744c9f300f697cristy      phase_pixels);
55513c99c4243ef58ec6f752aba6df9970ec16c87e6cristy  CorrectPhaseLHS(fourier_info->width,fourier_info->height,phase_pixels);
5563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (fourier_info->modulus != MagickFalse)
5573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
5583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      i=0L;
559bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      for (y=0L; y < (ssize_t) fourier_info->height; y++)
560bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy        for (x=0L; x < (ssize_t) fourier_info->width; x++)
5613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
5627d4aa38318c20a4309d855f45e3744c9f300f697cristy          phase_pixels[i]/=(2.0*MagickPI);
5637d4aa38318c20a4309d855f45e3744c9f300f697cristy          phase_pixels[i]+=0.5;
5643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          i++;
5653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
5663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
56746ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy  magnitude_view=AcquireAuthenticCacheView(magnitude_image,exception);
5683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  i=0L;
569bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=0L; y < (ssize_t) fourier_info->height; y++)
5703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
5715570fc587fc1fb64666649c75bb7531e08e96a0aCristy    q=GetCacheViewAuthenticPixels(magnitude_view,0L,y,fourier_info->width,1UL,
5723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      exception);
573acd2ed254c18c254a0ab5aafa06d1645e5d079d8cristy    if (q == (Quantum *) NULL)
5743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
575bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (x=0L; x < (ssize_t) fourier_info->width; x++)
5763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
5773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      switch (fourier_info->channel)
5783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
579d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case RedPixelChannel:
5803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        default:
5813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
5824c08aed51c5899665ade97263692328eea4af106cristy          SetPixelRed(magnitude_image,ClampToQuantum(QuantumRange*
5837d4aa38318c20a4309d855f45e3744c9f300f697cristy            magnitude_pixels[i]),q);
5843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
5853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
586d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case GreenPixelChannel:
5873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
5884c08aed51c5899665ade97263692328eea4af106cristy          SetPixelGreen(magnitude_image,ClampToQuantum(QuantumRange*
5897d4aa38318c20a4309d855f45e3744c9f300f697cristy            magnitude_pixels[i]),q);
5903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
5913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
592d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case BluePixelChannel:
5933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
5944c08aed51c5899665ade97263692328eea4af106cristy          SetPixelBlue(magnitude_image,ClampToQuantum(QuantumRange*
5957d4aa38318c20a4309d855f45e3744c9f300f697cristy            magnitude_pixels[i]),q);
5963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
5973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
598d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case BlackPixelChannel:
5993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
6004c08aed51c5899665ade97263692328eea4af106cristy          SetPixelBlack(magnitude_image,ClampToQuantum(QuantumRange*
6017d4aa38318c20a4309d855f45e3744c9f300f697cristy            magnitude_pixels[i]),q);
6023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
6033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
604d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case AlphaPixelChannel:
6053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
6064c08aed51c5899665ade97263692328eea4af106cristy          SetPixelAlpha(magnitude_image,ClampToQuantum(QuantumRange*
6077d4aa38318c20a4309d855f45e3744c9f300f697cristy            magnitude_pixels[i]),q);
6083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
6093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
6103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
6113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      i++;
612ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      q+=GetPixelChannels(magnitude_image);
6133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
6143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status=SyncCacheViewAuthenticPixels(magnitude_view,exception);
6153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (status == MagickFalse)
6163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
6173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
618db070957cf6bf959df9283a482377e8854c3d4d2cristy  magnitude_view=DestroyCacheView(magnitude_view);
6193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  i=0L;
62046ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy  phase_view=AcquireAuthenticCacheView(phase_image,exception);
621bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=0L; y < (ssize_t) fourier_info->height; y++)
6223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
6235570fc587fc1fb64666649c75bb7531e08e96a0aCristy    q=GetCacheViewAuthenticPixels(phase_view,0L,y,fourier_info->width,1UL,
6243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      exception);
625acd2ed254c18c254a0ab5aafa06d1645e5d079d8cristy    if (q == (Quantum *) NULL)
6263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
627bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (x=0L; x < (ssize_t) fourier_info->width; x++)
6283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
6293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      switch (fourier_info->channel)
6303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
631d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case RedPixelChannel:
6323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        default:
6333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
6344c08aed51c5899665ade97263692328eea4af106cristy          SetPixelRed(phase_image,ClampToQuantum(QuantumRange*
6357d4aa38318c20a4309d855f45e3744c9f300f697cristy            phase_pixels[i]),q);
6363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
6373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
638d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case GreenPixelChannel:
6393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
6404c08aed51c5899665ade97263692328eea4af106cristy          SetPixelGreen(phase_image,ClampToQuantum(QuantumRange*
6417d4aa38318c20a4309d855f45e3744c9f300f697cristy            phase_pixels[i]),q);
6423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
6433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
644d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case BluePixelChannel:
6453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
6464c08aed51c5899665ade97263692328eea4af106cristy          SetPixelBlue(phase_image,ClampToQuantum(QuantumRange*
6477d4aa38318c20a4309d855f45e3744c9f300f697cristy            phase_pixels[i]),q);
6483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
6493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
650d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case BlackPixelChannel:
6513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
6524c08aed51c5899665ade97263692328eea4af106cristy          SetPixelBlack(phase_image,ClampToQuantum(QuantumRange*
6537d4aa38318c20a4309d855f45e3744c9f300f697cristy            phase_pixels[i]),q);
6543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
6553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
656d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case AlphaPixelChannel:
6573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
6584c08aed51c5899665ade97263692328eea4af106cristy          SetPixelAlpha(phase_image,ClampToQuantum(QuantumRange*
6597d4aa38318c20a4309d855f45e3744c9f300f697cristy            phase_pixels[i]),q);
6603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
6613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
6623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
6633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      i++;
664ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      q+=GetPixelChannels(phase_image);
6653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
6663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status=SyncCacheViewAuthenticPixels(phase_view,exception);
6673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (status == MagickFalse)
6683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
6693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy   }
6703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  phase_view=DestroyCacheView(phase_view);
6717d4aa38318c20a4309d855f45e3744c9f300f697cristy  phase_info=RelinquishVirtualMemory(phase_info);
6727d4aa38318c20a4309d855f45e3744c9f300f697cristy  magnitude_info=RelinquishVirtualMemory(magnitude_info);
6733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(status);
6743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
6753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6763ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic MagickBooleanType ForwardFourierTransform(FourierInfo *fourier_info,
677699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  const Image *image,double *magnitude_pixels,double *phase_pixels,
678699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  ExceptionInfo *exception)
6793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
6803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  CacheView
6813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *image_view;
6823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
68399dc036190f292a67801dc4b141898bf18c96b36cristy  const char
68499dc036190f292a67801dc4b141898bf18c96b36cristy    *value;
68599dc036190f292a67801dc4b141898bf18c96b36cristy
6863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double
687bb3c02e054634545e7595cea2048c07de0407f1acristy    *source_pixels;
6883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fftw_complex
690699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    *forward_pixels;
6913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fftw_plan
6933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    fftw_r2c_plan;
6943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6957d4aa38318c20a4309d855f45e3744c9f300f697cristy  MemoryInfo
696699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    *forward_info,
6977d4aa38318c20a4309d855f45e3744c9f300f697cristy    *source_info;
6987d4aa38318c20a4309d855f45e3744c9f300f697cristy
6994c08aed51c5899665ade97263692328eea4af106cristy  register const Quantum
7003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *p;
7013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
702bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
7033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i,
7043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    x;
7053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
706c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy  ssize_t
707c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy    y;
708c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy
7093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
7103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Generate the forward Fourier transform.
7113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
7122e035cd272c0993d28f757f4a913070170095939Cristy  source_info=AcquireVirtualMemory((size_t) fourier_info->width,
7132e035cd272c0993d28f757f4a913070170095939Cristy    fourier_info->height*sizeof(*source_pixels));
7147d4aa38318c20a4309d855f45e3744c9f300f697cristy  if (source_info == (MemoryInfo *) NULL)
7153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
7163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) ThrowMagickException(exception,GetMagickModule(),
717efe601ce9ea5ad34ad0e8ad6e61d9be9b148b2a3cristy        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
7183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return(MagickFalse);
7193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
720bb3c02e054634545e7595cea2048c07de0407f1acristy  source_pixels=(double *) GetVirtualMemoryBlob(source_info);
721bb3c02e054634545e7595cea2048c07de0407f1acristy  ResetMagickMemory(source_pixels,0,fourier_info->height*fourier_info->width*
722bb3c02e054634545e7595cea2048c07de0407f1acristy    sizeof(*source_pixels));
7233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  i=0L;
72446ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy  image_view=AcquireVirtualCacheView(image,exception);
725bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=0L; y < (ssize_t) fourier_info->height; y++)
7263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
7273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    p=GetCacheViewVirtualPixels(image_view,0L,y,fourier_info->width,1UL,
7283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      exception);
7294c08aed51c5899665ade97263692328eea4af106cristy    if (p == (const Quantum *) NULL)
7303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
731bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (x=0L; x < (ssize_t) fourier_info->width; x++)
7323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
7333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      switch (fourier_info->channel)
7343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
735d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case RedPixelChannel:
7363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        default:
7373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
738bb3c02e054634545e7595cea2048c07de0407f1acristy          source_pixels[i]=QuantumScale*GetPixelRed(image,p);
7393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
7403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
741d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case GreenPixelChannel:
7423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
743bb3c02e054634545e7595cea2048c07de0407f1acristy          source_pixels[i]=QuantumScale*GetPixelGreen(image,p);
7443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
7453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
746d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case BluePixelChannel:
7473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
748bb3c02e054634545e7595cea2048c07de0407f1acristy          source_pixels[i]=QuantumScale*GetPixelBlue(image,p);
7493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
7503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
751d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case BlackPixelChannel:
7523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
753bb3c02e054634545e7595cea2048c07de0407f1acristy          source_pixels[i]=QuantumScale*GetPixelBlack(image,p);
7543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
7553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
756d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case AlphaPixelChannel:
7573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
758bb3c02e054634545e7595cea2048c07de0407f1acristy          source_pixels[i]=QuantumScale*GetPixelAlpha(image,p);
7593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
7603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
7613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
7623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      i++;
763ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      p+=GetPixelChannels(image);
7643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
7653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
7663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  image_view=DestroyCacheView(image_view);
767bbc9a95a7875c8c9b4a8e0b87491aa52e56ec849Cristy  forward_info=AcquireVirtualMemory((size_t) fourier_info->width,
7682e035cd272c0993d28f757f4a913070170095939Cristy    (fourier_info->height/2+1)*sizeof(*forward_pixels));
769699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  if (forward_info == (MemoryInfo *) NULL)
7703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
7713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) ThrowMagickException(exception,GetMagickModule(),
772efe601ce9ea5ad34ad0e8ad6e61d9be9b148b2a3cristy        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
773bb3c02e054634545e7595cea2048c07de0407f1acristy      source_info=(MemoryInfo *) RelinquishVirtualMemory(source_info);
7743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return(MagickFalse);
7753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
776699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  forward_pixels=(fftw_complex *) GetVirtualMemoryBlob(forward_info);
777b5d5f725fef80ff5d50db3111c05a1a521b81e7fcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
7783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  #pragma omp critical (MagickCore_ForwardFourierTransform)
7793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
78070841a141aec156091268e1c6e20938abffbfa5ccristy  fftw_r2c_plan=fftw_plan_dft_r2c_2d(fourier_info->width,fourier_info->height,
781699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    source_pixels,forward_pixels,FFTW_ESTIMATE);
782bbc9a95a7875c8c9b4a8e0b87491aa52e56ec849Cristy  fftw_execute_dft_r2c(fftw_r2c_plan,source_pixels,forward_pixels);
7833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fftw_destroy_plan(fftw_r2c_plan);
784bb3c02e054634545e7595cea2048c07de0407f1acristy  source_info=(MemoryInfo *) RelinquishVirtualMemory(source_info);
78599dc036190f292a67801dc4b141898bf18c96b36cristy  value=GetImageArtifact(image,"fourier:normalize");
786f8ecbfdd4702c1b9dcc8f35870b60d61e6d32d79cristy  if ((value == (const char *) NULL) || (LocaleCompare(value,"forward") == 0))
78756ed31cc763800a9fb1f0df96104c354b40d2cbccristy    {
78899dc036190f292a67801dc4b141898bf18c96b36cristy      double
78999dc036190f292a67801dc4b141898bf18c96b36cristy        gamma;
79099dc036190f292a67801dc4b141898bf18c96b36cristy
79199dc036190f292a67801dc4b141898bf18c96b36cristy      /*
7922e035cd272c0993d28f757f4a913070170095939Cristy        Normalize fourier transform.
79399dc036190f292a67801dc4b141898bf18c96b36cristy      */
79499dc036190f292a67801dc4b141898bf18c96b36cristy      i=0L;
79599dc036190f292a67801dc4b141898bf18c96b36cristy      gamma=PerceptibleReciprocal((double) fourier_info->width*
79699dc036190f292a67801dc4b141898bf18c96b36cristy        fourier_info->height);
79799dc036190f292a67801dc4b141898bf18c96b36cristy      for (y=0L; y < (ssize_t) fourier_info->height; y++)
79899dc036190f292a67801dc4b141898bf18c96b36cristy        for (x=0L; x < (ssize_t) fourier_info->center; x++)
79999dc036190f292a67801dc4b141898bf18c96b36cristy        {
80056ed31cc763800a9fb1f0df96104c354b40d2cbccristy#if defined(MAGICKCORE_HAVE_COMPLEX_H)
80199dc036190f292a67801dc4b141898bf18c96b36cristy          forward_pixels[i]*=gamma;
80256ed31cc763800a9fb1f0df96104c354b40d2cbccristy#else
80399dc036190f292a67801dc4b141898bf18c96b36cristy          forward_pixels[i][0]*=gamma;
80499dc036190f292a67801dc4b141898bf18c96b36cristy          forward_pixels[i][1]*=gamma;
80556ed31cc763800a9fb1f0df96104c354b40d2cbccristy#endif
80699dc036190f292a67801dc4b141898bf18c96b36cristy          i++;
80799dc036190f292a67801dc4b141898bf18c96b36cristy        }
80856ed31cc763800a9fb1f0df96104c354b40d2cbccristy    }
8093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
8103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Generate magnitude and phase (or real and imaginary).
8113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
8123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  i=0L;
8133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (fourier_info->modulus != MagickFalse)
814bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (y=0L; y < (ssize_t) fourier_info->height; y++)
815bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      for (x=0L; x < (ssize_t) fourier_info->center; x++)
8163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
817699ae5b6cbee363e53f58e0fedd414f282d07eddcristy        magnitude_pixels[i]=cabs(forward_pixels[i]);
818699ae5b6cbee363e53f58e0fedd414f282d07eddcristy        phase_pixels[i]=carg(forward_pixels[i]);
8193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        i++;
8203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
8213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  else
822bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (y=0L; y < (ssize_t) fourier_info->height; y++)
823bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      for (x=0L; x < (ssize_t) fourier_info->center; x++)
8243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
825699ae5b6cbee363e53f58e0fedd414f282d07eddcristy        magnitude_pixels[i]=creal(forward_pixels[i]);
826699ae5b6cbee363e53f58e0fedd414f282d07eddcristy        phase_pixels[i]=cimag(forward_pixels[i]);
8273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        i++;
8283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
829699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  forward_info=(MemoryInfo *) RelinquishVirtualMemory(forward_info);
8303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickTrue);
8313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
8323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
8333ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic MagickBooleanType ForwardFourierTransformChannel(const Image *image,
834d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy  const PixelChannel channel,const MagickBooleanType modulus,
8353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Image *fourier_image,ExceptionInfo *exception)
8363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
8373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double
838ce9fe78c6f9452d2bc114f6e4075838313943a82cristy    *magnitude_pixels,
839ce9fe78c6f9452d2bc114f6e4075838313943a82cristy    *phase_pixels;
840bb3c02e054634545e7595cea2048c07de0407f1acristy
84156ed31cc763800a9fb1f0df96104c354b40d2cbccristy  FourierInfo
84256ed31cc763800a9fb1f0df96104c354b40d2cbccristy    fourier_info;
84356ed31cc763800a9fb1f0df96104c354b40d2cbccristy
844c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy  MagickBooleanType
845c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy    status;
846c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy
847ce9fe78c6f9452d2bc114f6e4075838313943a82cristy  MemoryInfo
848ce9fe78c6f9452d2bc114f6e4075838313943a82cristy    *magnitude_info,
849ce9fe78c6f9452d2bc114f6e4075838313943a82cristy    *phase_info;
850ce9fe78c6f9452d2bc114f6e4075838313943a82cristy
8513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fourier_info.width=image->columns;
852740b4f1b3bbfb255bd4bd08132acfd0ee9977ccecristy  fourier_info.height=image->rows;
8532e035cd272c0993d28f757f4a913070170095939Cristy  fourier_info.center=(ssize_t) (fourier_info.width/2L)+1L;
8543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fourier_info.channel=channel;
8553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fourier_info.modulus=modulus;
8562e035cd272c0993d28f757f4a913070170095939Cristy  magnitude_info=AcquireVirtualMemory((size_t) fourier_info.width,
8572e035cd272c0993d28f757f4a913070170095939Cristy    (fourier_info.height/2+1)*sizeof(*magnitude_pixels));
8582e035cd272c0993d28f757f4a913070170095939Cristy  phase_info=AcquireVirtualMemory((size_t) fourier_info.width,
8592e035cd272c0993d28f757f4a913070170095939Cristy    (fourier_info.height/2+1)*sizeof(*phase_pixels));
860ce9fe78c6f9452d2bc114f6e4075838313943a82cristy  if ((magnitude_info == (MemoryInfo *) NULL) ||
861ce9fe78c6f9452d2bc114f6e4075838313943a82cristy      (phase_info == (MemoryInfo *) NULL))
862bb3c02e054634545e7595cea2048c07de0407f1acristy    {
863ce9fe78c6f9452d2bc114f6e4075838313943a82cristy      if (phase_info != (MemoryInfo *) NULL)
864ce9fe78c6f9452d2bc114f6e4075838313943a82cristy        phase_info=RelinquishVirtualMemory(phase_info);
865ce9fe78c6f9452d2bc114f6e4075838313943a82cristy      if (magnitude_info == (MemoryInfo *) NULL)
866ce9fe78c6f9452d2bc114f6e4075838313943a82cristy        magnitude_info=RelinquishVirtualMemory(magnitude_info);
867bb3c02e054634545e7595cea2048c07de0407f1acristy      (void) ThrowMagickException(exception,GetMagickModule(),
868bb3c02e054634545e7595cea2048c07de0407f1acristy        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
8693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return(MagickFalse);
8703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
871ce9fe78c6f9452d2bc114f6e4075838313943a82cristy  magnitude_pixels=(double *) GetVirtualMemoryBlob(magnitude_info);
872ce9fe78c6f9452d2bc114f6e4075838313943a82cristy  phase_pixels=(double *) GetVirtualMemoryBlob(phase_info);
873ce9fe78c6f9452d2bc114f6e4075838313943a82cristy  status=ForwardFourierTransform(&fourier_info,image,magnitude_pixels,
874ce9fe78c6f9452d2bc114f6e4075838313943a82cristy    phase_pixels,exception);
8753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (status != MagickFalse)
876ce9fe78c6f9452d2bc114f6e4075838313943a82cristy    status=ForwardFourier(&fourier_info,fourier_image,magnitude_pixels,
877ce9fe78c6f9452d2bc114f6e4075838313943a82cristy      phase_pixels,exception);
878ce9fe78c6f9452d2bc114f6e4075838313943a82cristy  phase_info=RelinquishVirtualMemory(phase_info);
879ce9fe78c6f9452d2bc114f6e4075838313943a82cristy  magnitude_info=RelinquishVirtualMemory(magnitude_info);
8803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(status);
8813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
8823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
8833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
8843ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport Image *ForwardFourierTransformImage(const Image *image,
8853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  const MagickBooleanType modulus,ExceptionInfo *exception)
8863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
8873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Image
8883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *fourier_image;
8893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
8903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fourier_image=NewImageList();
8913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#if !defined(MAGICKCORE_FFTW_DELEGATE)
8923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) modulus;
8933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) ThrowMagickException(exception,GetMagickModule(),
8942e035cd272c0993d28f757f4a913070170095939Cristy    MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","`%s' (FFTW)",
8953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    image->filename);
8963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#else
8973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
8983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Image
8993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      *magnitude_image;
9003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
901bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    size_t
902c9721ffe0e76156deb0d518ec41c0431e1b61922cristy      height,
9033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      width;
9043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
9053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    width=image->columns;
906c9721ffe0e76156deb0d518ec41c0431e1b61922cristy    height=image->rows;
907c9721ffe0e76156deb0d518ec41c0431e1b61922cristy    magnitude_image=CloneImage(image,width,height,MagickTrue,exception);
9083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (magnitude_image != (Image *) NULL)
9093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
9103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        Image
9113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          *phase_image;
9123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
9133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        magnitude_image->storage_class=DirectClass;
9143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        magnitude_image->depth=32UL;
915c9721ffe0e76156deb0d518ec41c0431e1b61922cristy        phase_image=CloneImage(image,width,height,MagickTrue,exception);
9163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (phase_image == (Image *) NULL)
9173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          magnitude_image=DestroyImage(magnitude_image);
9183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        else
9193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          {
9203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            MagickBooleanType
9213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              is_gray,
9223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              status;
9233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
9243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            phase_image->storage_class=DirectClass;
9253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            phase_image->depth=32UL;
9263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            AppendImageToList(&fourier_image,magnitude_image);
9273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            AppendImageToList(&fourier_image,phase_image);
9283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            status=MagickTrue;
929c6f2ac9fbacb63eb30ab87d80dba97d634742d4bcristy            is_gray=IsImageGray(image);
930b5d5f725fef80ff5d50db3111c05a1a521b81e7fcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
931564a56979706a30a3d0f920fd5f538a408efd4f1cristy            #pragma omp parallel sections
9323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
9333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
934b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
935b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              #pragma omp section
936b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#endif
9373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              {
938b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                MagickBooleanType
939b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  thread_status;
940b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy
941b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                if (is_gray != MagickFalse)
942b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  thread_status=ForwardFourierTransformChannel(image,
943d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy                    GrayPixelChannel,modulus,fourier_image,exception);
944b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                else
945b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  thread_status=ForwardFourierTransformChannel(image,
946d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy                    RedPixelChannel,modulus,fourier_image,exception);
947b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                if (thread_status == MagickFalse)
948b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  status=thread_status;
949b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              }
950b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
951b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              #pragma omp section
952b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#endif
953b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              {
954b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                MagickBooleanType
955b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  thread_status;
956b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy
957b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                thread_status=MagickTrue;
958b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                if (is_gray == MagickFalse)
959b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  thread_status=ForwardFourierTransformChannel(image,
960d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy                    GreenPixelChannel,modulus,fourier_image,exception);
961b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                if (thread_status == MagickFalse)
962b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  status=thread_status;
963b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              }
964b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
965b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              #pragma omp section
966b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#endif
967b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              {
968b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                MagickBooleanType
969b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  thread_status;
970b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy
971b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                thread_status=MagickTrue;
972b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                if (is_gray == MagickFalse)
973b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  thread_status=ForwardFourierTransformChannel(image,
974d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy                    BluePixelChannel,modulus,fourier_image,exception);
975b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                if (thread_status == MagickFalse)
976b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  status=thread_status;
977b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              }
978b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
979b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              #pragma omp section
980b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#endif
981b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              {
982b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                MagickBooleanType
983b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  thread_status;
984b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy
985b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                thread_status=MagickTrue;
9864c08aed51c5899665ade97263692328eea4af106cristy                if (image->colorspace == CMYKColorspace)
987b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  thread_status=ForwardFourierTransformChannel(image,
988d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy                    BlackPixelChannel,modulus,fourier_image,exception);
989b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                if (thread_status == MagickFalse)
990b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  status=thread_status;
991b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              }
992b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
993b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              #pragma omp section
994b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#endif
995b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              {
996b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                MagickBooleanType
997b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  thread_status;
998b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy
999b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                thread_status=MagickTrue;
100017f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy                if (image->alpha_trait != UndefinedPixelTrait)
1001b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  thread_status=ForwardFourierTransformChannel(image,
1002d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy                    AlphaPixelChannel,modulus,fourier_image,exception);
1003b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                if (thread_status == MagickFalse)
1004b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  status=thread_status;
10053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              }
10063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
10073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            if (status == MagickFalse)
10083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              fourier_image=DestroyImageList(fourier_image);
10093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            fftw_cleanup();
10103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          }
10113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
10123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
10133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
10143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(fourier_image);
10153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
10163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
10183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%     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                 %
10233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  InverseFourierTransformImage() implements the inverse discrete Fourier
10293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  transform (DFT) of the image either as a magnitude / phase or real /
10303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  imaginary image pair.
10313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the InverseFourierTransformImage method is:
10333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1034c9550792cd47c57370cd82fef338304f9e576473cristy%      Image *InverseFourierTransformImage(const Image *magnitude_image,
1035c9550792cd47c57370cd82fef338304f9e576473cristy%        const Image *phase_image,const MagickBooleanType modulus,
1036c9550792cd47c57370cd82fef338304f9e576473cristy%        ExceptionInfo *exception)
10373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
10393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1040c9550792cd47c57370cd82fef338304f9e576473cristy%    o magnitude_image: the magnitude or real image.
1041c9550792cd47c57370cd82fef338304f9e576473cristy%
1042c9550792cd47c57370cd82fef338304f9e576473cristy%    o phase_image: the phase or imaginary image.
10433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o modulus: if true, return transform as a magnitude / phase pair
10453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      otherwise a real / imaginary image pair.
10463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o exception: return any errors or warnings in this structure.
10483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
10503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#if defined(MAGICKCORE_FFTW_DELEGATE)
1052bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristystatic MagickBooleanType InverseQuadrantSwap(const size_t width,
1053bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  const size_t height,const double *source,double *destination)
10543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
1055c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy  register ssize_t
1056c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy    x;
1057c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy
1058bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  ssize_t
10593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    center,
10603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    y;
10613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
10633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Swap quadrants.
10643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
10652e035cd272c0993d28f757f4a913070170095939Cristy  center=(ssize_t) (width/2L)+1L;
1066bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=1L; y < (ssize_t) height; y++)
1067bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (x=0L; x < (ssize_t) (width/2L+1L); x++)
10689b1d6c756cb32746846b038ccb0439db540ba509cristy      destination[(height-y)*center-x+width/2L]=source[y*width+x];
1069bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=0L; y < (ssize_t) height; y++)
10703d04ed7ddc7a93c09476e84cc64412687bf5261acristy    destination[y*center]=source[y*width+width/2L];
10713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  for (x=0L; x < center; x++)
10723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    destination[x]=source[center-x-1L];
1073bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  return(RollFourier(center,height,0L,(ssize_t) height/-2L,destination));
10743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
10753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10763ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic MagickBooleanType InverseFourier(FourierInfo *fourier_info,
1077699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  const Image *magnitude_image,const Image *phase_image,
1078699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  fftw_complex *fourier_pixels,ExceptionInfo *exception)
10793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
10803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  CacheView
10813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *magnitude_view,
10823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *phase_view;
10833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double
1085699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    *inverse_pixels,
10867d4aa38318c20a4309d855f45e3744c9f300f697cristy    *magnitude_pixels,
10877d4aa38318c20a4309d855f45e3744c9f300f697cristy    *phase_pixels;
10883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
10903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
10913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1092699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  MemoryInfo
1093699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    *inverse_info,
1094699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    *magnitude_info,
1095699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    *phase_info;
1096699ae5b6cbee363e53f58e0fedd414f282d07eddcristy
10974c08aed51c5899665ade97263692328eea4af106cristy  register const Quantum
10983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *p;
10993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1100bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
11013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i,
11023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    x;
11033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1104c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy  ssize_t
1105c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy    y;
1106c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy
11073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
11083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Inverse fourier - read image and break down into a double array.
11093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
11102e035cd272c0993d28f757f4a913070170095939Cristy  magnitude_info=AcquireVirtualMemory((size_t) fourier_info->width,
11112e035cd272c0993d28f757f4a913070170095939Cristy    fourier_info->height*sizeof(*magnitude_pixels));
11122e035cd272c0993d28f757f4a913070170095939Cristy  phase_info=AcquireVirtualMemory((size_t) fourier_info->width,
11132e035cd272c0993d28f757f4a913070170095939Cristy    fourier_info->height*sizeof(*phase_pixels));
11142e035cd272c0993d28f757f4a913070170095939Cristy  inverse_info=AcquireVirtualMemory((size_t) fourier_info->width,
11152e035cd272c0993d28f757f4a913070170095939Cristy    (fourier_info->height/2+1)*sizeof(*inverse_pixels));
1116699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  if ((magnitude_info == (MemoryInfo *) NULL) ||
1117699ae5b6cbee363e53f58e0fedd414f282d07eddcristy      (phase_info == (MemoryInfo *) NULL) ||
1118699ae5b6cbee363e53f58e0fedd414f282d07eddcristy      (inverse_info == (MemoryInfo *) NULL))
11193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
1120699ae5b6cbee363e53f58e0fedd414f282d07eddcristy      if (magnitude_info != (MemoryInfo *) NULL)
1121699ae5b6cbee363e53f58e0fedd414f282d07eddcristy        magnitude_info=RelinquishVirtualMemory(magnitude_info);
1122699ae5b6cbee363e53f58e0fedd414f282d07eddcristy      if (phase_info != (MemoryInfo *) NULL)
1123699ae5b6cbee363e53f58e0fedd414f282d07eddcristy        phase_info=RelinquishVirtualMemory(phase_info);
1124699ae5b6cbee363e53f58e0fedd414f282d07eddcristy      if (inverse_info != (MemoryInfo *) NULL)
1125699ae5b6cbee363e53f58e0fedd414f282d07eddcristy        inverse_info=RelinquishVirtualMemory(inverse_info);
11263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) ThrowMagickException(exception,GetMagickModule(),
1127efe601ce9ea5ad34ad0e8ad6e61d9be9b148b2a3cristy        ResourceLimitError,"MemoryAllocationFailed","`%s'",
1128c9550792cd47c57370cd82fef338304f9e576473cristy        magnitude_image->filename);
11293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return(MagickFalse);
11303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
1131699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  magnitude_pixels=(double *) GetVirtualMemoryBlob(magnitude_info);
1132699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  phase_pixels=(double *) GetVirtualMemoryBlob(phase_info);
1133699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  inverse_pixels=(double *) GetVirtualMemoryBlob(inverse_info);
11343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  i=0L;
113546ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy  magnitude_view=AcquireVirtualCacheView(magnitude_image,exception);
1136bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=0L; y < (ssize_t) fourier_info->height; y++)
11373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
11383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    p=GetCacheViewVirtualPixels(magnitude_view,0L,y,fourier_info->width,1UL,
11393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      exception);
11404c08aed51c5899665ade97263692328eea4af106cristy    if (p == (const Quantum *) NULL)
11413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
1142bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (x=0L; x < (ssize_t) fourier_info->width; x++)
11433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
11443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      switch (fourier_info->channel)
11453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
1146d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case RedPixelChannel:
11473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        default:
11483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
11497d4aa38318c20a4309d855f45e3744c9f300f697cristy          magnitude_pixels[i]=QuantumScale*GetPixelRed(magnitude_image,p);
11503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
11513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
1152d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case GreenPixelChannel:
11533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
11547d4aa38318c20a4309d855f45e3744c9f300f697cristy          magnitude_pixels[i]=QuantumScale*GetPixelGreen(magnitude_image,p);
11553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
11563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
1157d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case BluePixelChannel:
11583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
11597d4aa38318c20a4309d855f45e3744c9f300f697cristy          magnitude_pixels[i]=QuantumScale*GetPixelBlue(magnitude_image,p);
11603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
11613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
1162d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case BlackPixelChannel:
11633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
11647d4aa38318c20a4309d855f45e3744c9f300f697cristy          magnitude_pixels[i]=QuantumScale*GetPixelBlack(magnitude_image,p);
11653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
11663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
1167d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case AlphaPixelChannel:
11683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
11697d4aa38318c20a4309d855f45e3744c9f300f697cristy          magnitude_pixels[i]=QuantumScale*GetPixelAlpha(magnitude_image,p);
11703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
11713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
11723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
11733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      i++;
1174ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      p+=GetPixelChannels(magnitude_image);
11753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
11763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
1177699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  magnitude_view=DestroyCacheView(magnitude_view);
1178699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  status=InverseQuadrantSwap(fourier_info->width,fourier_info->height,
1179699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    magnitude_pixels,inverse_pixels);
1180699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  (void) CopyMagickMemory(magnitude_pixels,inverse_pixels,fourier_info->height*
1181699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    fourier_info->center*sizeof(*magnitude_pixels));
11823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  i=0L;
118346ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy  phase_view=AcquireVirtualCacheView(phase_image,exception);
1184bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=0L; y < (ssize_t) fourier_info->height; y++)
11853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
11863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    p=GetCacheViewVirtualPixels(phase_view,0,y,fourier_info->width,1,
11873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      exception);
11884c08aed51c5899665ade97263692328eea4af106cristy    if (p == (const Quantum *) NULL)
11893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
1190bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (x=0L; x < (ssize_t) fourier_info->width; x++)
11913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
11923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      switch (fourier_info->channel)
11933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
1194d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case RedPixelChannel:
11953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        default:
11963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
11977d4aa38318c20a4309d855f45e3744c9f300f697cristy          phase_pixels[i]=QuantumScale*GetPixelRed(phase_image,p);
11983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
11993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
1200d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case GreenPixelChannel:
12013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
12027d4aa38318c20a4309d855f45e3744c9f300f697cristy          phase_pixels[i]=QuantumScale*GetPixelGreen(phase_image,p);
12033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
12043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
1205d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case BluePixelChannel:
12063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
12077d4aa38318c20a4309d855f45e3744c9f300f697cristy          phase_pixels[i]=QuantumScale*GetPixelBlue(phase_image,p);
12083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
12093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
1210d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case BlackPixelChannel:
12113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
12127d4aa38318c20a4309d855f45e3744c9f300f697cristy          phase_pixels[i]=QuantumScale*GetPixelBlack(phase_image,p);
12133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
12143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
1215d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case AlphaPixelChannel:
12163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
12177d4aa38318c20a4309d855f45e3744c9f300f697cristy          phase_pixels[i]=QuantumScale*GetPixelAlpha(phase_image,p);
12183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
12193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
12203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
12213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      i++;
1222ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      p+=GetPixelChannels(phase_image);
12233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
12243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
12253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (fourier_info->modulus != MagickFalse)
12263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
12273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      i=0L;
1228bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      for (y=0L; y < (ssize_t) fourier_info->height; y++)
1229bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy        for (x=0L; x < (ssize_t) fourier_info->width; x++)
12303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
12317d4aa38318c20a4309d855f45e3744c9f300f697cristy          phase_pixels[i]-=0.5;
12327d4aa38318c20a4309d855f45e3744c9f300f697cristy          phase_pixels[i]*=(2.0*MagickPI);
12333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          i++;
12343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
12353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
12363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  phase_view=DestroyCacheView(phase_view);
123713c99c4243ef58ec6f752aba6df9970ec16c87e6cristy  CorrectPhaseLHS(fourier_info->width,fourier_info->height,phase_pixels);
12383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (status != MagickFalse)
12393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status=InverseQuadrantSwap(fourier_info->width,fourier_info->height,
1240699ae5b6cbee363e53f58e0fedd414f282d07eddcristy      phase_pixels,inverse_pixels);
1241699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  (void) CopyMagickMemory(phase_pixels,inverse_pixels,fourier_info->height*
1242699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    fourier_info->center*sizeof(*phase_pixels));
1243699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  inverse_info=RelinquishVirtualMemory(inverse_info);
12443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
12453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Merge two sets.
12463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
12473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  i=0L;
12483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (fourier_info->modulus != MagickFalse)
1249bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (y=0L; y < (ssize_t) fourier_info->height; y++)
1250bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy       for (x=0L; x < (ssize_t) fourier_info->center; x++)
12513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy       {
125256ed31cc763800a9fb1f0df96104c354b40d2cbccristy#if defined(MAGICKCORE_HAVE_COMPLEX_H)
1253699ae5b6cbee363e53f58e0fedd414f282d07eddcristy         fourier_pixels[i]=magnitude_pixels[i]*cos(phase_pixels[i])+I*
1254699ae5b6cbee363e53f58e0fedd414f282d07eddcristy           magnitude_pixels[i]*sin(phase_pixels[i]);
125556ed31cc763800a9fb1f0df96104c354b40d2cbccristy#else
1256699ae5b6cbee363e53f58e0fedd414f282d07eddcristy         fourier_pixels[i][0]=magnitude_pixels[i]*cos(phase_pixels[i]);
1257699ae5b6cbee363e53f58e0fedd414f282d07eddcristy         fourier_pixels[i][1]=magnitude_pixels[i]*sin(phase_pixels[i]);
125856ed31cc763800a9fb1f0df96104c354b40d2cbccristy#endif
12593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy         i++;
12603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
12613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  else
1262bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (y=0L; y < (ssize_t) fourier_info->height; y++)
1263bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      for (x=0L; x < (ssize_t) fourier_info->center; x++)
12643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
126556ed31cc763800a9fb1f0df96104c354b40d2cbccristy#if defined(MAGICKCORE_HAVE_COMPLEX_H)
1266699ae5b6cbee363e53f58e0fedd414f282d07eddcristy        fourier_pixels[i]=magnitude_pixels[i]+I*phase_pixels[i];
126756ed31cc763800a9fb1f0df96104c354b40d2cbccristy#else
1268699ae5b6cbee363e53f58e0fedd414f282d07eddcristy        fourier_pixels[i][0]=magnitude_pixels[i];
1269699ae5b6cbee363e53f58e0fedd414f282d07eddcristy        fourier_pixels[i][1]=phase_pixels[i];
127056ed31cc763800a9fb1f0df96104c354b40d2cbccristy#endif
12713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        i++;
12723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
1273699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  magnitude_info=RelinquishVirtualMemory(magnitude_info);
1274699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  phase_info=RelinquishVirtualMemory(phase_info);
12753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(status);
12763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
12773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12783ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic MagickBooleanType InverseFourierTransform(FourierInfo *fourier_info,
1279699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  fftw_complex *fourier_pixels,Image *image,ExceptionInfo *exception)
12803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
12813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  CacheView
12823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *image_view;
12833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
128499dc036190f292a67801dc4b141898bf18c96b36cristy  const char
128599dc036190f292a67801dc4b141898bf18c96b36cristy    *value;
128699dc036190f292a67801dc4b141898bf18c96b36cristy
12873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double
1288699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    *source_pixels;
12893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fftw_plan
12913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    fftw_c2r_plan;
12923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1293699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  MemoryInfo
1294699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    *source_info;
1295699ae5b6cbee363e53f58e0fedd414f282d07eddcristy
12964c08aed51c5899665ade97263692328eea4af106cristy  register Quantum
1297c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy    *q;
1298c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy
1299bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
13003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i,
13013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    x;
13023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1303c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy  ssize_t
1304c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy    y;
13053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
13062e035cd272c0993d28f757f4a913070170095939Cristy  source_info=AcquireVirtualMemory((size_t) fourier_info->width,
13072e035cd272c0993d28f757f4a913070170095939Cristy    fourier_info->height*sizeof(*source_pixels));
1308699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  if (source_info == (MemoryInfo *) NULL)
13093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
13103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) ThrowMagickException(exception,GetMagickModule(),
1311efe601ce9ea5ad34ad0e8ad6e61d9be9b148b2a3cristy        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
13123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return(MagickFalse);
13133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
1314699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  source_pixels=(double *) GetVirtualMemoryBlob(source_info);
131599dc036190f292a67801dc4b141898bf18c96b36cristy  value=GetImageArtifact(image,"fourier:normalize");
1316f8ecbfdd4702c1b9dcc8f35870b60d61e6d32d79cristy  if (LocaleCompare(value,"inverse") == 0)
131799dc036190f292a67801dc4b141898bf18c96b36cristy    {
131899dc036190f292a67801dc4b141898bf18c96b36cristy      double
131999dc036190f292a67801dc4b141898bf18c96b36cristy        gamma;
132099dc036190f292a67801dc4b141898bf18c96b36cristy
132199dc036190f292a67801dc4b141898bf18c96b36cristy      /*
132299dc036190f292a67801dc4b141898bf18c96b36cristy        Normalize inverse transform.
132399dc036190f292a67801dc4b141898bf18c96b36cristy      */
132499dc036190f292a67801dc4b141898bf18c96b36cristy      i=0L;
132599dc036190f292a67801dc4b141898bf18c96b36cristy      gamma=PerceptibleReciprocal((double) fourier_info->width*
132699dc036190f292a67801dc4b141898bf18c96b36cristy        fourier_info->height);
132799dc036190f292a67801dc4b141898bf18c96b36cristy      for (y=0L; y < (ssize_t) fourier_info->height; y++)
132899dc036190f292a67801dc4b141898bf18c96b36cristy        for (x=0L; x < (ssize_t) fourier_info->center; x++)
132999dc036190f292a67801dc4b141898bf18c96b36cristy        {
133099dc036190f292a67801dc4b141898bf18c96b36cristy#if defined(MAGICKCORE_HAVE_COMPLEX_H)
133199dc036190f292a67801dc4b141898bf18c96b36cristy          fourier_pixels[i]*=gamma;
133299dc036190f292a67801dc4b141898bf18c96b36cristy#else
133399dc036190f292a67801dc4b141898bf18c96b36cristy          fourier_pixels[i][0]*=gamma;
133499dc036190f292a67801dc4b141898bf18c96b36cristy          fourier_pixels[i][1]*=gamma;
133599dc036190f292a67801dc4b141898bf18c96b36cristy#endif
133699dc036190f292a67801dc4b141898bf18c96b36cristy          i++;
133799dc036190f292a67801dc4b141898bf18c96b36cristy        }
133899dc036190f292a67801dc4b141898bf18c96b36cristy    }
1339b5d5f725fef80ff5d50db3111c05a1a521b81e7fcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
13403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  #pragma omp critical (MagickCore_InverseFourierTransform)
13413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
1342bbc9a95a7875c8c9b4a8e0b87491aa52e56ec849Cristy  fftw_c2r_plan=fftw_plan_dft_c2r_2d(fourier_info->width,fourier_info->height,
1343bbc9a95a7875c8c9b4a8e0b87491aa52e56ec849Cristy    fourier_pixels,source_pixels,FFTW_ESTIMATE);
1344bbc9a95a7875c8c9b4a8e0b87491aa52e56ec849Cristy  fftw_execute_dft_c2r(fftw_c2r_plan,fourier_pixels,source_pixels);
1345bbc9a95a7875c8c9b4a8e0b87491aa52e56ec849Cristy  fftw_destroy_plan(fftw_c2r_plan);
13463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  i=0L;
134746ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy  image_view=AcquireAuthenticCacheView(image,exception);
1348bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=0L; y < (ssize_t) fourier_info->height; y++)
13493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
135085812051623aa663ad40386ebfc4b8d0ca87bd55cristy    if (y >= (ssize_t) image->rows)
135185812051623aa663ad40386ebfc4b8d0ca87bd55cristy      break;
135285812051623aa663ad40386ebfc4b8d0ca87bd55cristy    q=GetCacheViewAuthenticPixels(image_view,0L,y,fourier_info->width >
135385812051623aa663ad40386ebfc4b8d0ca87bd55cristy      image->columns ? image->columns : fourier_info->width,1UL,exception);
1354acd2ed254c18c254a0ab5aafa06d1645e5d079d8cristy    if (q == (Quantum *) NULL)
13553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
1356bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (x=0L; x < (ssize_t) fourier_info->width; x++)
13573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
1358233fe5816db8ff3930e64adebd232757d8d2c06ecristy      if (x < (ssize_t) image->columns)
1359233fe5816db8ff3930e64adebd232757d8d2c06ecristy        switch (fourier_info->channel)
13603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
1361233fe5816db8ff3930e64adebd232757d8d2c06ecristy          case RedPixelChannel:
1362233fe5816db8ff3930e64adebd232757d8d2c06ecristy          default:
1363233fe5816db8ff3930e64adebd232757d8d2c06ecristy          {
1364699ae5b6cbee363e53f58e0fedd414f282d07eddcristy            SetPixelRed(image,ClampToQuantum(QuantumRange*source_pixels[i]),q);
1365233fe5816db8ff3930e64adebd232757d8d2c06ecristy            break;
1366233fe5816db8ff3930e64adebd232757d8d2c06ecristy          }
1367233fe5816db8ff3930e64adebd232757d8d2c06ecristy          case GreenPixelChannel:
1368233fe5816db8ff3930e64adebd232757d8d2c06ecristy          {
1369699ae5b6cbee363e53f58e0fedd414f282d07eddcristy            SetPixelGreen(image,ClampToQuantum(QuantumRange*source_pixels[i]),
1370699ae5b6cbee363e53f58e0fedd414f282d07eddcristy              q);
1371233fe5816db8ff3930e64adebd232757d8d2c06ecristy            break;
1372233fe5816db8ff3930e64adebd232757d8d2c06ecristy          }
1373233fe5816db8ff3930e64adebd232757d8d2c06ecristy          case BluePixelChannel:
1374233fe5816db8ff3930e64adebd232757d8d2c06ecristy          {
1375699ae5b6cbee363e53f58e0fedd414f282d07eddcristy            SetPixelBlue(image,ClampToQuantum(QuantumRange*source_pixels[i]),
1376699ae5b6cbee363e53f58e0fedd414f282d07eddcristy              q);
1377233fe5816db8ff3930e64adebd232757d8d2c06ecristy            break;
1378233fe5816db8ff3930e64adebd232757d8d2c06ecristy          }
1379233fe5816db8ff3930e64adebd232757d8d2c06ecristy          case BlackPixelChannel:
1380233fe5816db8ff3930e64adebd232757d8d2c06ecristy          {
1381699ae5b6cbee363e53f58e0fedd414f282d07eddcristy            SetPixelBlack(image,ClampToQuantum(QuantumRange*source_pixels[i]),
1382699ae5b6cbee363e53f58e0fedd414f282d07eddcristy              q);
1383233fe5816db8ff3930e64adebd232757d8d2c06ecristy            break;
1384233fe5816db8ff3930e64adebd232757d8d2c06ecristy          }
1385233fe5816db8ff3930e64adebd232757d8d2c06ecristy          case AlphaPixelChannel:
1386233fe5816db8ff3930e64adebd232757d8d2c06ecristy          {
1387699ae5b6cbee363e53f58e0fedd414f282d07eddcristy            SetPixelAlpha(image,ClampToQuantum(QuantumRange*source_pixels[i]),
1388699ae5b6cbee363e53f58e0fedd414f282d07eddcristy              q);
1389233fe5816db8ff3930e64adebd232757d8d2c06ecristy            break;
1390233fe5816db8ff3930e64adebd232757d8d2c06ecristy          }
13913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
13923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      i++;
1393ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      q+=GetPixelChannels(image);
13943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
13953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
13963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
13973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
13983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  image_view=DestroyCacheView(image_view);
1399699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  source_info=RelinquishVirtualMemory(source_info);
14003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickTrue);
14013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
14023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1403c9550792cd47c57370cd82fef338304f9e576473cristystatic MagickBooleanType InverseFourierTransformChannel(
1404c9550792cd47c57370cd82fef338304f9e576473cristy  const Image *magnitude_image,const Image *phase_image,
1405d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy  const PixelChannel channel,const MagickBooleanType modulus,
14063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Image *fourier_image,ExceptionInfo *exception)
14073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
14083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fftw_complex
1409699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    *inverse_pixels;
14103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
14113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  FourierInfo
14123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    fourier_info;
14133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
14143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
14153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
14163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1417699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  MemoryInfo
1418699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    *inverse_info;
1419699ae5b6cbee363e53f58e0fedd414f282d07eddcristy
1420c9550792cd47c57370cd82fef338304f9e576473cristy  fourier_info.width=magnitude_image->columns;
14210a69e6429fff81c8de551ed10e358df7b0b2a585cristy  fourier_info.height=magnitude_image->rows;
14222e035cd272c0993d28f757f4a913070170095939Cristy  fourier_info.center=(ssize_t) (fourier_info.width/2L)+1L;
14233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fourier_info.channel=channel;
14243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fourier_info.modulus=modulus;
14252e035cd272c0993d28f757f4a913070170095939Cristy  inverse_info=AcquireVirtualMemory((size_t) fourier_info.width,
14262e035cd272c0993d28f757f4a913070170095939Cristy    (fourier_info.height/2+1)*sizeof(*inverse_pixels));
1427699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  if (inverse_info == (MemoryInfo *) NULL)
14283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
14293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) ThrowMagickException(exception,GetMagickModule(),
1430efe601ce9ea5ad34ad0e8ad6e61d9be9b148b2a3cristy        ResourceLimitError,"MemoryAllocationFailed","`%s'",
1431c9550792cd47c57370cd82fef338304f9e576473cristy        magnitude_image->filename);
14323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return(MagickFalse);
14333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
1434699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  inverse_pixels=(fftw_complex *) GetVirtualMemoryBlob(inverse_info);
1435699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  status=InverseFourier(&fourier_info,magnitude_image,phase_image,
1436699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    inverse_pixels,exception);
14373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (status != MagickFalse)
1438699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    status=InverseFourierTransform(&fourier_info,inverse_pixels,fourier_image,
14393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      exception);
1440699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  inverse_info=RelinquishVirtualMemory(inverse_info);
14413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(status);
14423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
14433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
14443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1445c9550792cd47c57370cd82fef338304f9e576473cristyMagickExport Image *InverseFourierTransformImage(const Image *magnitude_image,
1446c9550792cd47c57370cd82fef338304f9e576473cristy  const Image *phase_image,const MagickBooleanType modulus,
1447c9550792cd47c57370cd82fef338304f9e576473cristy  ExceptionInfo *exception)
14483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
14493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Image
14503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *fourier_image;
14513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1452c9550792cd47c57370cd82fef338304f9e576473cristy  assert(magnitude_image != (Image *) NULL);
1453e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(magnitude_image->signature == MagickCoreSignature);
1454c9550792cd47c57370cd82fef338304f9e576473cristy  if (magnitude_image->debug != MagickFalse)
1455c9550792cd47c57370cd82fef338304f9e576473cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1456c9550792cd47c57370cd82fef338304f9e576473cristy      magnitude_image->filename);
1457c9550792cd47c57370cd82fef338304f9e576473cristy  if (phase_image == (Image *) NULL)
1458c9550792cd47c57370cd82fef338304f9e576473cristy    {
1459c9550792cd47c57370cd82fef338304f9e576473cristy      (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
14602e035cd272c0993d28f757f4a913070170095939Cristy        "ImageSequenceRequired","`%s'",magnitude_image->filename);
14619372a158e662d81ce4df26249238df39d66102ffcristy      return((Image *) NULL);
1462c9550792cd47c57370cd82fef338304f9e576473cristy    }
14633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#if !defined(MAGICKCORE_FFTW_DELEGATE)
14643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fourier_image=(Image *) NULL;
14653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) modulus;
14663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) ThrowMagickException(exception,GetMagickModule(),
14672e035cd272c0993d28f757f4a913070170095939Cristy    MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","`%s' (FFTW)",
1468c9550792cd47c57370cd82fef338304f9e576473cristy    magnitude_image->filename);
14693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#else
14703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
1471c9550792cd47c57370cd82fef338304f9e576473cristy    fourier_image=CloneImage(magnitude_image,magnitude_image->columns,
14724c9c4d0c413e922bc941efc7657a5c075a944c1fcristy      magnitude_image->rows,MagickTrue,exception);
14733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (fourier_image != (Image *) NULL)
14743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
14753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        MagickBooleanType
14763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          is_gray,
14773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status;
14783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
14793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        status=MagickTrue;
1480c6f2ac9fbacb63eb30ab87d80dba97d634742d4bcristy        is_gray=IsImageGray(magnitude_image);
1481c9550792cd47c57370cd82fef338304f9e576473cristy        if (is_gray != MagickFalse)
1482c6f2ac9fbacb63eb30ab87d80dba97d634742d4bcristy          is_gray=IsImageGray(phase_image);
1483b5d5f725fef80ff5d50db3111c05a1a521b81e7fcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
1484b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy        #pragma omp parallel sections
14853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
14863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
1487b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
1488b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy          #pragma omp section
1489b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#endif
14903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          {
1491b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            MagickBooleanType
1492b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              thread_status;
1493b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy
1494b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            if (is_gray != MagickFalse)
1495b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              thread_status=InverseFourierTransformChannel(magnitude_image,
1496d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy                phase_image,GrayPixelChannel,modulus,fourier_image,exception);
1497b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            else
1498c9550792cd47c57370cd82fef338304f9e576473cristy              thread_status=InverseFourierTransformChannel(magnitude_image,
1499d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy                phase_image,RedPixelChannel,modulus,fourier_image,exception);
1500b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            if (thread_status == MagickFalse)
1501b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              status=thread_status;
1502b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy          }
1503b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
1504b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy          #pragma omp section
1505b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#endif
1506b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy          {
1507b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            MagickBooleanType
1508b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              thread_status;
1509b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy
1510b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            thread_status=MagickTrue;
1511b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            if (is_gray == MagickFalse)
1512b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              thread_status=InverseFourierTransformChannel(magnitude_image,
1513d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy                phase_image,GreenPixelChannel,modulus,fourier_image,exception);
1514b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            if (thread_status == MagickFalse)
1515b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              status=thread_status;
1516b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy          }
1517b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
1518b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy          #pragma omp section
1519b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#endif
1520b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy          {
1521b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            MagickBooleanType
1522b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              thread_status;
1523b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy
1524b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            thread_status=MagickTrue;
1525b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            if (is_gray == MagickFalse)
1526b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              thread_status=InverseFourierTransformChannel(magnitude_image,
1527d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy                phase_image,BluePixelChannel,modulus,fourier_image,exception);
1528b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            if (thread_status == MagickFalse)
1529b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              status=thread_status;
1530b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy          }
1531b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
1532b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy          #pragma omp section
1533b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#endif
1534b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy          {
1535b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            MagickBooleanType
1536b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              thread_status;
1537b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy
1538b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            thread_status=MagickTrue;
15394c08aed51c5899665ade97263692328eea4af106cristy            if (magnitude_image->colorspace == CMYKColorspace)
1540b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              thread_status=InverseFourierTransformChannel(magnitude_image,
1541d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy                phase_image,BlackPixelChannel,modulus,fourier_image,exception);
1542b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            if (thread_status == MagickFalse)
1543b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              status=thread_status;
1544b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy          }
1545b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
1546b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy          #pragma omp section
1547b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#endif
1548b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy          {
1549b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            MagickBooleanType
1550b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              thread_status;
1551b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy
1552b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            thread_status=MagickTrue;
155317f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy            if (magnitude_image->alpha_trait != UndefinedPixelTrait)
1554b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              thread_status=InverseFourierTransformChannel(magnitude_image,
1555d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy                phase_image,AlphaPixelChannel,modulus,fourier_image,exception);
1556b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            if (thread_status == MagickFalse)
1557b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              status=thread_status;
15583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          }
15593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
15603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (status == MagickFalse)
15613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          fourier_image=DestroyImage(fourier_image);
15623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
1563b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy    fftw_cleanup();
15643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
15653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
15663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(fourier_image);
15673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
1568