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);
2001042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  /*
2011042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    Apply complex mathematics to image pixels.
2021042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  */
20334b78eacf3bef963cade67c70f5f12785b9fe702cristy  artifact=GetImageArtifact(image,"complex:snr");
20434b78eacf3bef963cade67c70f5f12785b9fe702cristy  snr=0.0;
20534b78eacf3bef963cade67c70f5f12785b9fe702cristy  if (artifact != (const char *) NULL)
20634b78eacf3bef963cade67c70f5f12785b9fe702cristy    snr=StringToDouble(artifact,(char **) NULL);
2071042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Ar_image=images;
2081042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Ai_image=images->next;
2098dc6a07d751896a7c400a6d888a5964c538fad2dcristy  Br_image=images;
2108dc6a07d751896a7c400a6d888a5964c538fad2dcristy  Bi_image=images->next;
2118dc6a07d751896a7c400a6d888a5964c538fad2dcristy  if ((images->next->next != (Image *) NULL) &&
2128dc6a07d751896a7c400a6d888a5964c538fad2dcristy      (images->next->next->next != (Image *) NULL))
2131042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    {
2141042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy      Br_image=images->next->next;
2151042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy      Bi_image=images->next->next->next;
2161042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    }
2171042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Cr_image=complex_images;
2181042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Ci_image=complex_images->next;
2191042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Ar_view=AcquireVirtualCacheView(Ar_image,exception);
2201042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Ai_view=AcquireVirtualCacheView(Ai_image,exception);
2211042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Br_view=AcquireVirtualCacheView(Br_image,exception);
2221042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Bi_view=AcquireVirtualCacheView(Bi_image,exception);
2231042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Cr_view=AcquireAuthenticCacheView(Cr_image,exception);
2241042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Ci_view=AcquireAuthenticCacheView(Ci_image,exception);
2251042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  status=MagickTrue;
2261042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  progress=0;
2271042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
2284167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy  #pragma omp parallel for schedule(static,4) shared(progress,status) \
2294167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy    magick_threads(images,complex_images,images->rows,1L)
2301042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy#endif
2311042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  for (y=0; y < (ssize_t) images->rows; y++)
2321042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  {
2331042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    register const Quantum
23405d2ff7ebf21f659f5b11e45afb294e152f4330cdirk      *magick_restrict Ai,
23505d2ff7ebf21f659f5b11e45afb294e152f4330cdirk      *magick_restrict Ar,
23605d2ff7ebf21f659f5b11e45afb294e152f4330cdirk      *magick_restrict Bi,
23705d2ff7ebf21f659f5b11e45afb294e152f4330cdirk      *magick_restrict Br;
2381042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy
2391042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    register Quantum
24005d2ff7ebf21f659f5b11e45afb294e152f4330cdirk      *magick_restrict Ci,
24105d2ff7ebf21f659f5b11e45afb294e152f4330cdirk      *magick_restrict Cr;
2421042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy
2431042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    register ssize_t
2441042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy      x;
2451042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy
24634919ed07da683cc334cd74e3c9d9c29c8b79b98cristy    if (status == MagickFalse)
24734919ed07da683cc334cd74e3c9d9c29c8b79b98cristy      continue;
2484167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy    Ar=GetCacheViewVirtualPixels(Ar_view,0,y,Ar_image->columns,1,exception);
2494167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy    Ai=GetCacheViewVirtualPixels(Ai_view,0,y,Ai_image->columns,1,exception);
2504167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy    Br=GetCacheViewVirtualPixels(Br_view,0,y,Br_image->columns,1,exception);
2514167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy    Bi=GetCacheViewVirtualPixels(Bi_view,0,y,Bi_image->columns,1,exception);
2524167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy    Cr=QueueCacheViewAuthenticPixels(Cr_view,0,y,Cr_image->columns,1,exception);
2534167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy    Ci=QueueCacheViewAuthenticPixels(Ci_view,0,y,Ci_image->columns,1,exception);
2541042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    if ((Ar == (const Quantum *) NULL) || (Ai == (const Quantum *) NULL) ||
2551042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy        (Br == (const Quantum *) NULL) || (Bi == (const Quantum *) NULL) ||
2561042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy        (Cr == (Quantum *) NULL) || (Ci == (Quantum *) NULL))
2571042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy      {
2581042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy        status=MagickFalse;
2591042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy        continue;
2601042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy      }
2611042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    for (x=0; x < (ssize_t) images->columns; x++)
2621042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    {
2639f654472e80883bb7c4ec299036733e0e23570d7cristy      register ssize_t
2649f654472e80883bb7c4ec299036733e0e23570d7cristy        i;
2659f654472e80883bb7c4ec299036733e0e23570d7cristy
2669f654472e80883bb7c4ec299036733e0e23570d7cristy      for (i=0; i < (ssize_t) GetPixelChannels(images); i++)
2679f654472e80883bb7c4ec299036733e0e23570d7cristy      {
268220c4d505bfb9cf557e8ec1616d7cdc0596379b8cristy        switch (op)
2699f654472e80883bb7c4ec299036733e0e23570d7cristy        {
27019f7886e4423cd5ce3eef31092942f55ba770983cristy          case AddComplexOperator:
27119f7886e4423cd5ce3eef31092942f55ba770983cristy          {
27219f7886e4423cd5ce3eef31092942f55ba770983cristy            Cr[i]=Ar[i]+Br[i];
27319f7886e4423cd5ce3eef31092942f55ba770983cristy            Ci[i]=Ai[i]+Bi[i];
27419f7886e4423cd5ce3eef31092942f55ba770983cristy            break;
27519f7886e4423cd5ce3eef31092942f55ba770983cristy          }
2769f654472e80883bb7c4ec299036733e0e23570d7cristy          case ConjugateComplexOperator:
2779f654472e80883bb7c4ec299036733e0e23570d7cristy          default:
2789f654472e80883bb7c4ec299036733e0e23570d7cristy          {
2799f654472e80883bb7c4ec299036733e0e23570d7cristy            Cr[i]=Ar[i];
2809f654472e80883bb7c4ec299036733e0e23570d7cristy            Ci[i]=(-Bi[i]);
2819f654472e80883bb7c4ec299036733e0e23570d7cristy            break;
2829f654472e80883bb7c4ec299036733e0e23570d7cristy          }
2839f654472e80883bb7c4ec299036733e0e23570d7cristy          case DivideComplexOperator:
2849f654472e80883bb7c4ec299036733e0e23570d7cristy          {
2859f654472e80883bb7c4ec299036733e0e23570d7cristy            double
2869f654472e80883bb7c4ec299036733e0e23570d7cristy              gamma;
2879f654472e80883bb7c4ec299036733e0e23570d7cristy
28834b78eacf3bef963cade67c70f5f12785b9fe702cristy            gamma=PerceptibleReciprocal(Br[i]*Br[i]+Bi[i]*Bi[i]+snr);
2899f654472e80883bb7c4ec299036733e0e23570d7cristy            Cr[i]=gamma*(Ar[i]*Br[i]+Ai[i]*Bi[i]);
290857c8a100c50bd902586a902c27fccab271dce1dcristy            Ci[i]=gamma*(Ai[i]*Br[i]-Ar[i]*Bi[i]);
2919f654472e80883bb7c4ec299036733e0e23570d7cristy            break;
2929f654472e80883bb7c4ec299036733e0e23570d7cristy          }
293f46941ca310386db5b9939840c884c6f8a5c7189cristy          case MagnitudePhaseComplexOperator:
294f46941ca310386db5b9939840c884c6f8a5c7189cristy          {
2958526a9763e0671ebad481fd00679fb857ce8d84acristy            Cr[i]=sqrt(Ar[i]*Ar[i]+Ai[i]*Ai[i]);
2964ab069406391dd3d34359d17a6ab7333f7200729cristy            Ci[i]=atan2(Ai[i],Ar[i])/(2.0*MagickPI)+0.5;
297f46941ca310386db5b9939840c884c6f8a5c7189cristy            break;
298f46941ca310386db5b9939840c884c6f8a5c7189cristy          }
2999f654472e80883bb7c4ec299036733e0e23570d7cristy          case MultiplyComplexOperator:
3009f654472e80883bb7c4ec299036733e0e23570d7cristy          {
30115b07b3f81434e5cee2ed16d51ec3f504949d992cristy            Cr[i]=QuantumScale*(Ar[i]*Br[i]-Ai[i]*Bi[i]);
30215b07b3f81434e5cee2ed16d51ec3f504949d992cristy            Ci[i]=QuantumScale*(Ai[i]*Br[i]+Ar[i]*Bi[i]);
303f46941ca310386db5b9939840c884c6f8a5c7189cristy            break;
304f46941ca310386db5b9939840c884c6f8a5c7189cristy          }
305f46941ca310386db5b9939840c884c6f8a5c7189cristy          case RealImaginaryComplexOperator:
306f46941ca310386db5b9939840c884c6f8a5c7189cristy          {
3074ab069406391dd3d34359d17a6ab7333f7200729cristy            Cr[i]=Ar[i]*cos(2.0*MagickPI*(Ai[i]-0.5));
3084ab069406391dd3d34359d17a6ab7333f7200729cristy            Ci[i]=Ar[i]*sin(2.0*MagickPI*(Ai[i]-0.5));
3099f654472e80883bb7c4ec299036733e0e23570d7cristy            break;
3109f654472e80883bb7c4ec299036733e0e23570d7cristy          }
31119f7886e4423cd5ce3eef31092942f55ba770983cristy          case SubtractComplexOperator:
31219f7886e4423cd5ce3eef31092942f55ba770983cristy          {
31319f7886e4423cd5ce3eef31092942f55ba770983cristy            Cr[i]=Ar[i]-Br[i];
31419f7886e4423cd5ce3eef31092942f55ba770983cristy            Ci[i]=Ai[i]-Bi[i];
31519f7886e4423cd5ce3eef31092942f55ba770983cristy            break;
31619f7886e4423cd5ce3eef31092942f55ba770983cristy          }
3179f654472e80883bb7c4ec299036733e0e23570d7cristy        }
3189f654472e80883bb7c4ec299036733e0e23570d7cristy      }
3194167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy      Ar+=GetPixelChannels(Ar_image);
3204167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy      Ai+=GetPixelChannels(Ai_image);
3214167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy      Br+=GetPixelChannels(Br_image);
3224167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy      Bi+=GetPixelChannels(Bi_image);
3234167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy      Cr+=GetPixelChannels(Cr_image);
3244167f3a934b7c75a501ac7b4f1ceaf3e1bb192fdcristy      Ci+=GetPixelChannels(Ci_image);
3251042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    }
3261042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    if (SyncCacheViewAuthenticPixels(Ci_view,exception) == MagickFalse)
3271042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy      status=MagickFalse;
3281042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    if (SyncCacheViewAuthenticPixels(Cr_view,exception) == MagickFalse)
3291042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy      status=MagickFalse;
3301042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    if (images->progress_monitor != (MagickProgressMonitor) NULL)
3311042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy      {
3321042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy        MagickBooleanType
3331042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy          proceed;
3341042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy
3351042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
3361042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy        #pragma omp critical (MagickCore_ComplexImages)
3371042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy#endif
3381042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy        proceed=SetImageProgress(images,ComplexImageTag,progress++,
3391042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy          images->rows);
3401042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy        if (proceed == MagickFalse)
3411042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy          status=MagickFalse;
3421042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy      }
3431042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  }
3441042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Cr_view=DestroyCacheView(Cr_view);
3451042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Ci_view=DestroyCacheView(Ci_view);
3461042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Br_view=DestroyCacheView(Br_view);
3471042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Bi_view=DestroyCacheView(Bi_view);
3481042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Ar_view=DestroyCacheView(Ar_view);
3491042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  Ai_view=DestroyCacheView(Ai_view);
3501042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  if (status == MagickFalse)
3511042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy    complex_images=DestroyImageList(complex_images);
3521042ed2a43b6a660a6f6dd803e1ee79897da4c3fcristy  return(complex_images);
353790190d9d1e6f011220d0003ce5b51063f0ab417cristy}
354790190d9d1e6f011220d0003ce5b51063f0ab417cristy
355790190d9d1e6f011220d0003ce5b51063f0ab417cristy/*
356790190d9d1e6f011220d0003ce5b51063f0ab417cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
357790190d9d1e6f011220d0003ce5b51063f0ab417cristy%                                                                             %
358790190d9d1e6f011220d0003ce5b51063f0ab417cristy%                                                                             %
3593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
3603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%     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                 %
3613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
3623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
3633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
3643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  ForwardFourierTransformImage() implements the discrete Fourier transform
3673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  (DFT) of the image either as a magnitude / phase or real / imaginary image
3683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  pair.
3693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the ForwadFourierTransformImage method is:
3713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      Image *ForwardFourierTransformImage(const Image *image,
3733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%        const MagickBooleanType modulus,ExceptionInfo *exception)
3743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
3763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: the image.
3783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o modulus: if true, return as transform as a magnitude / phase pair
3803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      otherwise a real / imaginary image pair.
3813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o exception: return any errors or warnings in this structure.
3833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
3853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#if defined(MAGICKCORE_FFTW_DELEGATE)
3873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
388c4ea4a479c90f81168aa2b99e7680c7b0459d415cristystatic MagickBooleanType RollFourier(const size_t width,const size_t height,
389699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  const ssize_t x_offset,const ssize_t y_offset,double *roll_pixels)
3903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
3913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double
392699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    *source_pixels;
3933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3947d4aa38318c20a4309d855f45e3744c9f300f697cristy  MemoryInfo
395699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    *source_info;
3967d4aa38318c20a4309d855f45e3744c9f300f697cristy
397c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy  register ssize_t
398c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy    i,
399c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy    x;
400c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy
401bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  ssize_t
4023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    u,
4033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    v,
4043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    y;
4053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
4072da0535a82cc655e5a48deac466bd6fcef1f4924cristy    Move zero frequency (DC, average color) from (0,0) to (width/2,height/2).
4083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
4092e035cd272c0993d28f757f4a913070170095939Cristy  source_info=AcquireVirtualMemory(width,height*sizeof(*source_pixels));
410699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  if (source_info == (MemoryInfo *) NULL)
4113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(MagickFalse);
412699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  source_pixels=(double *) GetVirtualMemoryBlob(source_info);
4133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  i=0L;
414bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=0L; y < (ssize_t) height; y++)
4153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
4163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (y_offset < 0L)
417bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      v=((y+y_offset) < 0L) ? y+y_offset+(ssize_t) height : y+y_offset;
4183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    else
419bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      v=((y+y_offset) > ((ssize_t) height-1L)) ? y+y_offset-(ssize_t) height :
4203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        y+y_offset;
421bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (x=0L; x < (ssize_t) width; x++)
4223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
4233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (x_offset < 0L)
424bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy        u=((x+x_offset) < 0L) ? x+x_offset+(ssize_t) width : x+x_offset;
4253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      else
426bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy        u=((x+x_offset) > ((ssize_t) width-1L)) ? x+x_offset-(ssize_t) width :
4273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          x+x_offset;
428699ae5b6cbee363e53f58e0fedd414f282d07eddcristy      source_pixels[v*width+u]=roll_pixels[i++];
429c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy    }
4303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
431699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  (void) CopyMagickMemory(roll_pixels,source_pixels,height*width*
432699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    sizeof(*source_pixels));
433699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  source_info=RelinquishVirtualMemory(source_info);
4343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickTrue);
4353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
4363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
437bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristystatic MagickBooleanType ForwardQuadrantSwap(const size_t width,
438699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  const size_t height,double *source_pixels,double *forward_pixels)
4393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
4403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
4413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
4423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
443bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
4443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    x;
4453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
446c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy  ssize_t
447c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy    center,
448c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy    y;
449c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy
4503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
4513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Swap quadrants.
4523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
4532e035cd272c0993d28f757f4a913070170095939Cristy  center=(ssize_t) (width/2L)+1L;
454699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  status=RollFourier((size_t) center,height,0L,(ssize_t) height/2L,
455699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    source_pixels);
4563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (status == MagickFalse)
4573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(MagickFalse);
458bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=0L; y < (ssize_t) height; y++)
4596831e2f47f00e8b78275319e4aec01d120a3876fCristy    for (x=0L; x < (ssize_t) (width/2L); x++)
4603d04ed7ddc7a93c09476e84cc64412687bf5261acristy      forward_pixels[y*width+x+width/2L]=source_pixels[y*center+x];
461bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=1; y < (ssize_t) height; y++)
4626831e2f47f00e8b78275319e4aec01d120a3876fCristy    for (x=0L; x < (ssize_t) (width/2L); x++)
4639b1d6c756cb32746846b038ccb0439db540ba509cristy      forward_pixels[(height-y)*width+width/2L-x-1L]=
4643d04ed7ddc7a93c09476e84cc64412687bf5261acristy        source_pixels[y*center+x+1L];
465bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (x=0L; x < (ssize_t) (width/2L); x++)
4666831e2f47f00e8b78275319e4aec01d120a3876fCristy    forward_pixels[width/2L-x-1L]=source_pixels[x+1L];
4673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickTrue);
4683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
4693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
470c4ea4a479c90f81168aa2b99e7680c7b0459d415cristystatic void CorrectPhaseLHS(const size_t width,const size_t height,
471699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  double *fourier_pixels)
4723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
473bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
4743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    x;
4753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4769d314ff2c17a77996c05413c2013880387e50f0ecristy  ssize_t
4779d314ff2c17a77996c05413c2013880387e50f0ecristy    y;
4789d314ff2c17a77996c05413c2013880387e50f0ecristy
479bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=0L; y < (ssize_t) height; y++)
480bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (x=0L; x < (ssize_t) (width/2L); x++)
481699ae5b6cbee363e53f58e0fedd414f282d07eddcristy      fourier_pixels[y*width+x]*=(-1.0);
4823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
4833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4843ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic MagickBooleanType ForwardFourier(const FourierInfo *fourier_info,
4853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Image *image,double *magnitude,double *phase,ExceptionInfo *exception)
4863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
4873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  CacheView
4883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *magnitude_view,
4893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *phase_view;
4903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double
4927d4aa38318c20a4309d855f45e3744c9f300f697cristy    *magnitude_pixels,
4937d4aa38318c20a4309d855f45e3744c9f300f697cristy    *phase_pixels;
4943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Image
4963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *magnitude_image,
4973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *phase_image;
4983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
5003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
5013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5027d4aa38318c20a4309d855f45e3744c9f300f697cristy  MemoryInfo
5037d4aa38318c20a4309d855f45e3744c9f300f697cristy    *magnitude_info,
5047d4aa38318c20a4309d855f45e3744c9f300f697cristy    *phase_info;
5057d4aa38318c20a4309d855f45e3744c9f300f697cristy
5064c08aed51c5899665ade97263692328eea4af106cristy  register Quantum
5073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *q;
5083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
509f5742794873c63f8b052150a2f44015e1ad55356cristy  register ssize_t
510f5742794873c63f8b052150a2f44015e1ad55356cristy    x;
511f5742794873c63f8b052150a2f44015e1ad55356cristy
512c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy  ssize_t
513c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy    i,
514c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy    y;
515c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy
5163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  magnitude_image=GetFirstImageInList(image);
5173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  phase_image=GetNextImageInList(image);
5183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (phase_image == (Image *) NULL)
5193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
5203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
5212e035cd272c0993d28f757f4a913070170095939Cristy        "ImageSequenceRequired","`%s'",image->filename);
5223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return(MagickFalse);
5233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
5243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
5253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Create "Fourier Transform" image from constituent arrays.
5263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
5272e035cd272c0993d28f757f4a913070170095939Cristy  magnitude_info=AcquireVirtualMemory((size_t) fourier_info->width,
5282e035cd272c0993d28f757f4a913070170095939Cristy    fourier_info->height*sizeof(*magnitude_pixels));
5292e035cd272c0993d28f757f4a913070170095939Cristy  phase_info=AcquireVirtualMemory((size_t) fourier_info->width,
5302e035cd272c0993d28f757f4a913070170095939Cristy    fourier_info->height*sizeof(*phase_pixels));
531bb3c02e054634545e7595cea2048c07de0407f1acristy  if ((magnitude_info == (MemoryInfo *) NULL) ||
532bb3c02e054634545e7595cea2048c07de0407f1acristy      (phase_info == (MemoryInfo *) NULL))
5333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
5347d4aa38318c20a4309d855f45e3744c9f300f697cristy      if (phase_info != (MemoryInfo *) NULL)
5357d4aa38318c20a4309d855f45e3744c9f300f697cristy        phase_info=RelinquishVirtualMemory(phase_info);
5367d4aa38318c20a4309d855f45e3744c9f300f697cristy      if (magnitude_info != (MemoryInfo *) NULL)
5377d4aa38318c20a4309d855f45e3744c9f300f697cristy        magnitude_info=RelinquishVirtualMemory(magnitude_info);
5383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) ThrowMagickException(exception,GetMagickModule(),
539efe601ce9ea5ad34ad0e8ad6e61d9be9b148b2a3cristy        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
5403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return(MagickFalse);
5413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
5427d4aa38318c20a4309d855f45e3744c9f300f697cristy  magnitude_pixels=(double *) GetVirtualMemoryBlob(magnitude_info);
5432a5f27cd841820bdf64d9aa42d02c54df8ea7885Cristy  (void) ResetMagickMemory(magnitude_pixels,0,fourier_info->width*
5442a5f27cd841820bdf64d9aa42d02c54df8ea7885Cristy    fourier_info->height*sizeof(*magnitude_pixels));
545bb3c02e054634545e7595cea2048c07de0407f1acristy  phase_pixels=(double *) GetVirtualMemoryBlob(phase_info);
5462a5f27cd841820bdf64d9aa42d02c54df8ea7885Cristy  (void) ResetMagickMemory(phase_pixels,0,fourier_info->width*
5472a5f27cd841820bdf64d9aa42d02c54df8ea7885Cristy    fourier_info->height*sizeof(*phase_pixels));
54813c99c4243ef58ec6f752aba6df9970ec16c87e6cristy  status=ForwardQuadrantSwap(fourier_info->width,fourier_info->height,
5497d4aa38318c20a4309d855f45e3744c9f300f697cristy    magnitude,magnitude_pixels);
5503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (status != MagickFalse)
55113c99c4243ef58ec6f752aba6df9970ec16c87e6cristy    status=ForwardQuadrantSwap(fourier_info->width,fourier_info->height,phase,
5527d4aa38318c20a4309d855f45e3744c9f300f697cristy      phase_pixels);
55313c99c4243ef58ec6f752aba6df9970ec16c87e6cristy  CorrectPhaseLHS(fourier_info->width,fourier_info->height,phase_pixels);
5543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (fourier_info->modulus != MagickFalse)
5553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
5563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      i=0L;
557bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      for (y=0L; y < (ssize_t) fourier_info->height; y++)
558bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy        for (x=0L; x < (ssize_t) fourier_info->width; x++)
5593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
5607d4aa38318c20a4309d855f45e3744c9f300f697cristy          phase_pixels[i]/=(2.0*MagickPI);
5617d4aa38318c20a4309d855f45e3744c9f300f697cristy          phase_pixels[i]+=0.5;
5623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          i++;
5633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
5643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
56546ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy  magnitude_view=AcquireAuthenticCacheView(magnitude_image,exception);
5663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  i=0L;
567bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=0L; y < (ssize_t) fourier_info->height; y++)
5683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
5695570fc587fc1fb64666649c75bb7531e08e96a0aCristy    q=GetCacheViewAuthenticPixels(magnitude_view,0L,y,fourier_info->width,1UL,
5703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      exception);
571acd2ed254c18c254a0ab5aafa06d1645e5d079d8cristy    if (q == (Quantum *) NULL)
5723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
573bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (x=0L; x < (ssize_t) fourier_info->width; x++)
5743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
5753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      switch (fourier_info->channel)
5763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
577d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case RedPixelChannel:
5783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        default:
5793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
5804c08aed51c5899665ade97263692328eea4af106cristy          SetPixelRed(magnitude_image,ClampToQuantum(QuantumRange*
5817d4aa38318c20a4309d855f45e3744c9f300f697cristy            magnitude_pixels[i]),q);
5823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
5833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
584d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case GreenPixelChannel:
5853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
5864c08aed51c5899665ade97263692328eea4af106cristy          SetPixelGreen(magnitude_image,ClampToQuantum(QuantumRange*
5877d4aa38318c20a4309d855f45e3744c9f300f697cristy            magnitude_pixels[i]),q);
5883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
5893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
590d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case BluePixelChannel:
5913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
5924c08aed51c5899665ade97263692328eea4af106cristy          SetPixelBlue(magnitude_image,ClampToQuantum(QuantumRange*
5937d4aa38318c20a4309d855f45e3744c9f300f697cristy            magnitude_pixels[i]),q);
5943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
5953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
596d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case BlackPixelChannel:
5973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
5984c08aed51c5899665ade97263692328eea4af106cristy          SetPixelBlack(magnitude_image,ClampToQuantum(QuantumRange*
5997d4aa38318c20a4309d855f45e3744c9f300f697cristy            magnitude_pixels[i]),q);
6003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
6013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
602d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case AlphaPixelChannel:
6033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
6044c08aed51c5899665ade97263692328eea4af106cristy          SetPixelAlpha(magnitude_image,ClampToQuantum(QuantumRange*
6057d4aa38318c20a4309d855f45e3744c9f300f697cristy            magnitude_pixels[i]),q);
6063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
6073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
6083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
6093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      i++;
610ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      q+=GetPixelChannels(magnitude_image);
6113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
6123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status=SyncCacheViewAuthenticPixels(magnitude_view,exception);
6133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (status == MagickFalse)
6143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
6153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
616db070957cf6bf959df9283a482377e8854c3d4d2cristy  magnitude_view=DestroyCacheView(magnitude_view);
6173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  i=0L;
61846ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy  phase_view=AcquireAuthenticCacheView(phase_image,exception);
619bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=0L; y < (ssize_t) fourier_info->height; y++)
6203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
6215570fc587fc1fb64666649c75bb7531e08e96a0aCristy    q=GetCacheViewAuthenticPixels(phase_view,0L,y,fourier_info->width,1UL,
6223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      exception);
623acd2ed254c18c254a0ab5aafa06d1645e5d079d8cristy    if (q == (Quantum *) NULL)
6243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
625bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (x=0L; x < (ssize_t) fourier_info->width; x++)
6263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
6273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      switch (fourier_info->channel)
6283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
629d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case RedPixelChannel:
6303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        default:
6313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
6324c08aed51c5899665ade97263692328eea4af106cristy          SetPixelRed(phase_image,ClampToQuantum(QuantumRange*
6337d4aa38318c20a4309d855f45e3744c9f300f697cristy            phase_pixels[i]),q);
6343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
6353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
636d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case GreenPixelChannel:
6373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
6384c08aed51c5899665ade97263692328eea4af106cristy          SetPixelGreen(phase_image,ClampToQuantum(QuantumRange*
6397d4aa38318c20a4309d855f45e3744c9f300f697cristy            phase_pixels[i]),q);
6403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
6413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
642d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case BluePixelChannel:
6433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
6444c08aed51c5899665ade97263692328eea4af106cristy          SetPixelBlue(phase_image,ClampToQuantum(QuantumRange*
6457d4aa38318c20a4309d855f45e3744c9f300f697cristy            phase_pixels[i]),q);
6463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
6473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
648d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case BlackPixelChannel:
6493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
6504c08aed51c5899665ade97263692328eea4af106cristy          SetPixelBlack(phase_image,ClampToQuantum(QuantumRange*
6517d4aa38318c20a4309d855f45e3744c9f300f697cristy            phase_pixels[i]),q);
6523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
6533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
654d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case AlphaPixelChannel:
6553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
6564c08aed51c5899665ade97263692328eea4af106cristy          SetPixelAlpha(phase_image,ClampToQuantum(QuantumRange*
6577d4aa38318c20a4309d855f45e3744c9f300f697cristy            phase_pixels[i]),q);
6583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
6593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
6603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
6613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      i++;
662ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      q+=GetPixelChannels(phase_image);
6633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
6643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status=SyncCacheViewAuthenticPixels(phase_view,exception);
6653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (status == MagickFalse)
6663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
6673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy   }
6683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  phase_view=DestroyCacheView(phase_view);
6697d4aa38318c20a4309d855f45e3744c9f300f697cristy  phase_info=RelinquishVirtualMemory(phase_info);
6707d4aa38318c20a4309d855f45e3744c9f300f697cristy  magnitude_info=RelinquishVirtualMemory(magnitude_info);
6713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(status);
6723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
6733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6743ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic MagickBooleanType ForwardFourierTransform(FourierInfo *fourier_info,
675699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  const Image *image,double *magnitude_pixels,double *phase_pixels,
676699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  ExceptionInfo *exception)
6773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
6783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  CacheView
6793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *image_view;
6803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
68199dc036190f292a67801dc4b141898bf18c96b36cristy  const char
68299dc036190f292a67801dc4b141898bf18c96b36cristy    *value;
68399dc036190f292a67801dc4b141898bf18c96b36cristy
6843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double
685bb3c02e054634545e7595cea2048c07de0407f1acristy    *source_pixels;
6863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fftw_complex
688699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    *forward_pixels;
6893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fftw_plan
6913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    fftw_r2c_plan;
6923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6937d4aa38318c20a4309d855f45e3744c9f300f697cristy  MemoryInfo
694699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    *forward_info,
6957d4aa38318c20a4309d855f45e3744c9f300f697cristy    *source_info;
6967d4aa38318c20a4309d855f45e3744c9f300f697cristy
6974c08aed51c5899665ade97263692328eea4af106cristy  register const Quantum
6983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *p;
6993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
700bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
7013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i,
7023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    x;
7033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
704c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy  ssize_t
705c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy    y;
706c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy
7073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
7083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Generate the forward Fourier transform.
7093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
7102e035cd272c0993d28f757f4a913070170095939Cristy  source_info=AcquireVirtualMemory((size_t) fourier_info->width,
7112e035cd272c0993d28f757f4a913070170095939Cristy    fourier_info->height*sizeof(*source_pixels));
7127d4aa38318c20a4309d855f45e3744c9f300f697cristy  if (source_info == (MemoryInfo *) NULL)
7133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
7143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) ThrowMagickException(exception,GetMagickModule(),
715efe601ce9ea5ad34ad0e8ad6e61d9be9b148b2a3cristy        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
7163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return(MagickFalse);
7173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
718bb3c02e054634545e7595cea2048c07de0407f1acristy  source_pixels=(double *) GetVirtualMemoryBlob(source_info);
7192a5f27cd841820bdf64d9aa42d02c54df8ea7885Cristy  ResetMagickMemory(source_pixels,0,fourier_info->width*fourier_info->height*
720bb3c02e054634545e7595cea2048c07de0407f1acristy    sizeof(*source_pixels));
7213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  i=0L;
72246ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy  image_view=AcquireVirtualCacheView(image,exception);
723bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=0L; y < (ssize_t) fourier_info->height; y++)
7243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
7253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    p=GetCacheViewVirtualPixels(image_view,0L,y,fourier_info->width,1UL,
7263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      exception);
7274c08aed51c5899665ade97263692328eea4af106cristy    if (p == (const Quantum *) NULL)
7283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
729bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (x=0L; x < (ssize_t) fourier_info->width; x++)
7303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
7313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      switch (fourier_info->channel)
7323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
733d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case RedPixelChannel:
7343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        default:
7353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
736bb3c02e054634545e7595cea2048c07de0407f1acristy          source_pixels[i]=QuantumScale*GetPixelRed(image,p);
7373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
7383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
739d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case GreenPixelChannel:
7403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
741bb3c02e054634545e7595cea2048c07de0407f1acristy          source_pixels[i]=QuantumScale*GetPixelGreen(image,p);
7423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
7433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
744d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case BluePixelChannel:
7453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
746bb3c02e054634545e7595cea2048c07de0407f1acristy          source_pixels[i]=QuantumScale*GetPixelBlue(image,p);
7473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
7483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
749d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case BlackPixelChannel:
7503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
751bb3c02e054634545e7595cea2048c07de0407f1acristy          source_pixels[i]=QuantumScale*GetPixelBlack(image,p);
7523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
7533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
754d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case AlphaPixelChannel:
7553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
756bb3c02e054634545e7595cea2048c07de0407f1acristy          source_pixels[i]=QuantumScale*GetPixelAlpha(image,p);
7573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
7583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
7593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
7603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      i++;
761ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      p+=GetPixelChannels(image);
7623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
7633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
7643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  image_view=DestroyCacheView(image_view);
765bbc9a95a7875c8c9b4a8e0b87491aa52e56ec849Cristy  forward_info=AcquireVirtualMemory((size_t) fourier_info->width,
7662e035cd272c0993d28f757f4a913070170095939Cristy    (fourier_info->height/2+1)*sizeof(*forward_pixels));
767699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  if (forward_info == (MemoryInfo *) NULL)
7683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
7693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) ThrowMagickException(exception,GetMagickModule(),
770efe601ce9ea5ad34ad0e8ad6e61d9be9b148b2a3cristy        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
771bb3c02e054634545e7595cea2048c07de0407f1acristy      source_info=(MemoryInfo *) RelinquishVirtualMemory(source_info);
7723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return(MagickFalse);
7733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
774699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  forward_pixels=(fftw_complex *) GetVirtualMemoryBlob(forward_info);
775b5d5f725fef80ff5d50db3111c05a1a521b81e7fcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
7763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  #pragma omp critical (MagickCore_ForwardFourierTransform)
7773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
77870841a141aec156091268e1c6e20938abffbfa5ccristy  fftw_r2c_plan=fftw_plan_dft_r2c_2d(fourier_info->width,fourier_info->height,
779699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    source_pixels,forward_pixels,FFTW_ESTIMATE);
780bbc9a95a7875c8c9b4a8e0b87491aa52e56ec849Cristy  fftw_execute_dft_r2c(fftw_r2c_plan,source_pixels,forward_pixels);
7813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fftw_destroy_plan(fftw_r2c_plan);
782bb3c02e054634545e7595cea2048c07de0407f1acristy  source_info=(MemoryInfo *) RelinquishVirtualMemory(source_info);
78399dc036190f292a67801dc4b141898bf18c96b36cristy  value=GetImageArtifact(image,"fourier:normalize");
784f8ecbfdd4702c1b9dcc8f35870b60d61e6d32d79cristy  if ((value == (const char *) NULL) || (LocaleCompare(value,"forward") == 0))
78556ed31cc763800a9fb1f0df96104c354b40d2cbccristy    {
78699dc036190f292a67801dc4b141898bf18c96b36cristy      double
78799dc036190f292a67801dc4b141898bf18c96b36cristy        gamma;
78899dc036190f292a67801dc4b141898bf18c96b36cristy
78999dc036190f292a67801dc4b141898bf18c96b36cristy      /*
7902e035cd272c0993d28f757f4a913070170095939Cristy        Normalize fourier transform.
79199dc036190f292a67801dc4b141898bf18c96b36cristy      */
79299dc036190f292a67801dc4b141898bf18c96b36cristy      i=0L;
79399dc036190f292a67801dc4b141898bf18c96b36cristy      gamma=PerceptibleReciprocal((double) fourier_info->width*
79499dc036190f292a67801dc4b141898bf18c96b36cristy        fourier_info->height);
79599dc036190f292a67801dc4b141898bf18c96b36cristy      for (y=0L; y < (ssize_t) fourier_info->height; y++)
79699dc036190f292a67801dc4b141898bf18c96b36cristy        for (x=0L; x < (ssize_t) fourier_info->center; x++)
79799dc036190f292a67801dc4b141898bf18c96b36cristy        {
79856ed31cc763800a9fb1f0df96104c354b40d2cbccristy#if defined(MAGICKCORE_HAVE_COMPLEX_H)
79999dc036190f292a67801dc4b141898bf18c96b36cristy          forward_pixels[i]*=gamma;
80056ed31cc763800a9fb1f0df96104c354b40d2cbccristy#else
80199dc036190f292a67801dc4b141898bf18c96b36cristy          forward_pixels[i][0]*=gamma;
80299dc036190f292a67801dc4b141898bf18c96b36cristy          forward_pixels[i][1]*=gamma;
80356ed31cc763800a9fb1f0df96104c354b40d2cbccristy#endif
80499dc036190f292a67801dc4b141898bf18c96b36cristy          i++;
80599dc036190f292a67801dc4b141898bf18c96b36cristy        }
80656ed31cc763800a9fb1f0df96104c354b40d2cbccristy    }
8073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
8083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Generate magnitude and phase (or real and imaginary).
8093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
8103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  i=0L;
8113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (fourier_info->modulus != MagickFalse)
812bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (y=0L; y < (ssize_t) fourier_info->height; y++)
813bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      for (x=0L; x < (ssize_t) fourier_info->center; x++)
8143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
815699ae5b6cbee363e53f58e0fedd414f282d07eddcristy        magnitude_pixels[i]=cabs(forward_pixels[i]);
816699ae5b6cbee363e53f58e0fedd414f282d07eddcristy        phase_pixels[i]=carg(forward_pixels[i]);
8173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        i++;
8183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
8193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  else
820bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (y=0L; y < (ssize_t) fourier_info->height; y++)
821bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      for (x=0L; x < (ssize_t) fourier_info->center; x++)
8223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
823699ae5b6cbee363e53f58e0fedd414f282d07eddcristy        magnitude_pixels[i]=creal(forward_pixels[i]);
824699ae5b6cbee363e53f58e0fedd414f282d07eddcristy        phase_pixels[i]=cimag(forward_pixels[i]);
8253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        i++;
8263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
827699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  forward_info=(MemoryInfo *) RelinquishVirtualMemory(forward_info);
8283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickTrue);
8293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
8303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
8313ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic MagickBooleanType ForwardFourierTransformChannel(const Image *image,
832d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy  const PixelChannel channel,const MagickBooleanType modulus,
8333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Image *fourier_image,ExceptionInfo *exception)
8343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
8353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double
836ce9fe78c6f9452d2bc114f6e4075838313943a82cristy    *magnitude_pixels,
837ce9fe78c6f9452d2bc114f6e4075838313943a82cristy    *phase_pixels;
838bb3c02e054634545e7595cea2048c07de0407f1acristy
83956ed31cc763800a9fb1f0df96104c354b40d2cbccristy  FourierInfo
84056ed31cc763800a9fb1f0df96104c354b40d2cbccristy    fourier_info;
84156ed31cc763800a9fb1f0df96104c354b40d2cbccristy
842c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy  MagickBooleanType
843c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy    status;
844c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy
845ce9fe78c6f9452d2bc114f6e4075838313943a82cristy  MemoryInfo
846ce9fe78c6f9452d2bc114f6e4075838313943a82cristy    *magnitude_info,
847ce9fe78c6f9452d2bc114f6e4075838313943a82cristy    *phase_info;
848ce9fe78c6f9452d2bc114f6e4075838313943a82cristy
8493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fourier_info.width=image->columns;
850740b4f1b3bbfb255bd4bd08132acfd0ee9977ccecristy  fourier_info.height=image->rows;
8512a5f27cd841820bdf64d9aa42d02c54df8ea7885Cristy  if ((image->columns != image->rows) || ((image->columns % 2) != 0) ||
8522a5f27cd841820bdf64d9aa42d02c54df8ea7885Cristy      ((image->rows % 2) != 0))
8532a5f27cd841820bdf64d9aa42d02c54df8ea7885Cristy    {
8542a5f27cd841820bdf64d9aa42d02c54df8ea7885Cristy      size_t extent=image->columns < image->rows ? image->rows : image->columns;
8552a5f27cd841820bdf64d9aa42d02c54df8ea7885Cristy      fourier_info.width=(extent & 0x01) == 1 ? extent+1UL : extent;
8562a5f27cd841820bdf64d9aa42d02c54df8ea7885Cristy    }
8572a5f27cd841820bdf64d9aa42d02c54df8ea7885Cristy  fourier_info.height=fourier_info.width;
8582e035cd272c0993d28f757f4a913070170095939Cristy  fourier_info.center=(ssize_t) (fourier_info.width/2L)+1L;
8593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fourier_info.channel=channel;
8603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fourier_info.modulus=modulus;
8612e035cd272c0993d28f757f4a913070170095939Cristy  magnitude_info=AcquireVirtualMemory((size_t) fourier_info.width,
8622e035cd272c0993d28f757f4a913070170095939Cristy    (fourier_info.height/2+1)*sizeof(*magnitude_pixels));
8632e035cd272c0993d28f757f4a913070170095939Cristy  phase_info=AcquireVirtualMemory((size_t) fourier_info.width,
8642e035cd272c0993d28f757f4a913070170095939Cristy    (fourier_info.height/2+1)*sizeof(*phase_pixels));
865ce9fe78c6f9452d2bc114f6e4075838313943a82cristy  if ((magnitude_info == (MemoryInfo *) NULL) ||
866ce9fe78c6f9452d2bc114f6e4075838313943a82cristy      (phase_info == (MemoryInfo *) NULL))
867bb3c02e054634545e7595cea2048c07de0407f1acristy    {
868ce9fe78c6f9452d2bc114f6e4075838313943a82cristy      if (phase_info != (MemoryInfo *) NULL)
869ce9fe78c6f9452d2bc114f6e4075838313943a82cristy        phase_info=RelinquishVirtualMemory(phase_info);
870ce9fe78c6f9452d2bc114f6e4075838313943a82cristy      if (magnitude_info == (MemoryInfo *) NULL)
871ce9fe78c6f9452d2bc114f6e4075838313943a82cristy        magnitude_info=RelinquishVirtualMemory(magnitude_info);
872bb3c02e054634545e7595cea2048c07de0407f1acristy      (void) ThrowMagickException(exception,GetMagickModule(),
873bb3c02e054634545e7595cea2048c07de0407f1acristy        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
8743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return(MagickFalse);
8753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
876ce9fe78c6f9452d2bc114f6e4075838313943a82cristy  magnitude_pixels=(double *) GetVirtualMemoryBlob(magnitude_info);
877ce9fe78c6f9452d2bc114f6e4075838313943a82cristy  phase_pixels=(double *) GetVirtualMemoryBlob(phase_info);
878ce9fe78c6f9452d2bc114f6e4075838313943a82cristy  status=ForwardFourierTransform(&fourier_info,image,magnitude_pixels,
879ce9fe78c6f9452d2bc114f6e4075838313943a82cristy    phase_pixels,exception);
8803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (status != MagickFalse)
881ce9fe78c6f9452d2bc114f6e4075838313943a82cristy    status=ForwardFourier(&fourier_info,fourier_image,magnitude_pixels,
882ce9fe78c6f9452d2bc114f6e4075838313943a82cristy      phase_pixels,exception);
883ce9fe78c6f9452d2bc114f6e4075838313943a82cristy  phase_info=RelinquishVirtualMemory(phase_info);
884ce9fe78c6f9452d2bc114f6e4075838313943a82cristy  magnitude_info=RelinquishVirtualMemory(magnitude_info);
8853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(status);
8863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
8873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
8883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
8893ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport Image *ForwardFourierTransformImage(const Image *image,
8903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  const MagickBooleanType modulus,ExceptionInfo *exception)
8913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
8923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Image
8933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *fourier_image;
8943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
8953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fourier_image=NewImageList();
8963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#if !defined(MAGICKCORE_FFTW_DELEGATE)
8973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) modulus;
8983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) ThrowMagickException(exception,GetMagickModule(),
8992e035cd272c0993d28f757f4a913070170095939Cristy    MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","`%s' (FFTW)",
9003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    image->filename);
9013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#else
9023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
9033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Image
9043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      *magnitude_image;
9053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
906bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    size_t
907c9721ffe0e76156deb0d518ec41c0431e1b61922cristy      height,
9083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      width;
9093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
9103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    width=image->columns;
911c9721ffe0e76156deb0d518ec41c0431e1b61922cristy    height=image->rows;
9122a5f27cd841820bdf64d9aa42d02c54df8ea7885Cristy    if ((image->columns != image->rows) || ((image->columns % 2) != 0) ||
9132a5f27cd841820bdf64d9aa42d02c54df8ea7885Cristy        ((image->rows % 2) != 0))
9142a5f27cd841820bdf64d9aa42d02c54df8ea7885Cristy      {
9152a5f27cd841820bdf64d9aa42d02c54df8ea7885Cristy        size_t extent=image->columns < image->rows ? image->rows :
9162a5f27cd841820bdf64d9aa42d02c54df8ea7885Cristy          image->columns;
9172a5f27cd841820bdf64d9aa42d02c54df8ea7885Cristy        width=(extent & 0x01) == 1 ? extent+1UL : extent;
9182a5f27cd841820bdf64d9aa42d02c54df8ea7885Cristy      }
9192a5f27cd841820bdf64d9aa42d02c54df8ea7885Cristy    height=width;
920c9721ffe0e76156deb0d518ec41c0431e1b61922cristy    magnitude_image=CloneImage(image,width,height,MagickTrue,exception);
9213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (magnitude_image != (Image *) NULL)
9223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
9233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        Image
9243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          *phase_image;
9253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
9263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        magnitude_image->storage_class=DirectClass;
9273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        magnitude_image->depth=32UL;
928c9721ffe0e76156deb0d518ec41c0431e1b61922cristy        phase_image=CloneImage(image,width,height,MagickTrue,exception);
9293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (phase_image == (Image *) NULL)
9303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          magnitude_image=DestroyImage(magnitude_image);
9313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        else
9323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          {
9333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            MagickBooleanType
9343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              is_gray,
9353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              status;
9363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
9373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            phase_image->storage_class=DirectClass;
9383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            phase_image->depth=32UL;
9393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            AppendImageToList(&fourier_image,magnitude_image);
9403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            AppendImageToList(&fourier_image,phase_image);
9413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            status=MagickTrue;
942c6f2ac9fbacb63eb30ab87d80dba97d634742d4bcristy            is_gray=IsImageGray(image);
943b5d5f725fef80ff5d50db3111c05a1a521b81e7fcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
944564a56979706a30a3d0f920fd5f538a408efd4f1cristy            #pragma omp parallel sections
9453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
9463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
947b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
948b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              #pragma omp section
949b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#endif
9503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              {
951b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                MagickBooleanType
952b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  thread_status;
953b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy
954b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                if (is_gray != MagickFalse)
955b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  thread_status=ForwardFourierTransformChannel(image,
956d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy                    GrayPixelChannel,modulus,fourier_image,exception);
957b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                else
958b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  thread_status=ForwardFourierTransformChannel(image,
959d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy                    RedPixelChannel,modulus,fourier_image,exception);
960b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                if (thread_status == MagickFalse)
961b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  status=thread_status;
962b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              }
963b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
964b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              #pragma omp section
965b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#endif
966b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              {
967b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                MagickBooleanType
968b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  thread_status;
969b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy
970b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                thread_status=MagickTrue;
971b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                if (is_gray == MagickFalse)
972b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  thread_status=ForwardFourierTransformChannel(image,
973d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy                    GreenPixelChannel,modulus,fourier_image,exception);
974b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                if (thread_status == MagickFalse)
975b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  status=thread_status;
976b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              }
977b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
978b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              #pragma omp section
979b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#endif
980b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              {
981b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                MagickBooleanType
982b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  thread_status;
983b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy
984b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                thread_status=MagickTrue;
985b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                if (is_gray == MagickFalse)
986b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  thread_status=ForwardFourierTransformChannel(image,
987d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy                    BluePixelChannel,modulus,fourier_image,exception);
988b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                if (thread_status == MagickFalse)
989b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  status=thread_status;
990b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              }
991b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
992b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              #pragma omp section
993b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#endif
994b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              {
995b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                MagickBooleanType
996b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  thread_status;
997b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy
998b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                thread_status=MagickTrue;
9994c08aed51c5899665ade97263692328eea4af106cristy                if (image->colorspace == CMYKColorspace)
1000b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  thread_status=ForwardFourierTransformChannel(image,
1001d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy                    BlackPixelChannel,modulus,fourier_image,exception);
1002b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                if (thread_status == MagickFalse)
1003b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  status=thread_status;
1004b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              }
1005b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
1006b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              #pragma omp section
1007b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#endif
1008b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              {
1009b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                MagickBooleanType
1010b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  thread_status;
1011b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy
1012b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                thread_status=MagickTrue;
101317f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy                if (image->alpha_trait != UndefinedPixelTrait)
1014b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  thread_status=ForwardFourierTransformChannel(image,
1015d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy                    AlphaPixelChannel,modulus,fourier_image,exception);
1016b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                if (thread_status == MagickFalse)
1017b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy                  status=thread_status;
10183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              }
10193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
10203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            if (status == MagickFalse)
10213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              fourier_image=DestroyImageList(fourier_image);
10223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            fftw_cleanup();
10233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          }
10243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
10253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
10263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
10273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(fourier_image);
10283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
10293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
10313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%     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                 %
10363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  InverseFourierTransformImage() implements the inverse discrete Fourier
10423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  transform (DFT) of the image either as a magnitude / phase or real /
10433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  imaginary image pair.
10443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the InverseFourierTransformImage method is:
10463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1047c9550792cd47c57370cd82fef338304f9e576473cristy%      Image *InverseFourierTransformImage(const Image *magnitude_image,
1048c9550792cd47c57370cd82fef338304f9e576473cristy%        const Image *phase_image,const MagickBooleanType modulus,
1049c9550792cd47c57370cd82fef338304f9e576473cristy%        ExceptionInfo *exception)
10503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
10523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1053c9550792cd47c57370cd82fef338304f9e576473cristy%    o magnitude_image: the magnitude or real image.
1054c9550792cd47c57370cd82fef338304f9e576473cristy%
1055c9550792cd47c57370cd82fef338304f9e576473cristy%    o phase_image: the phase or imaginary image.
10563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o modulus: if true, return transform as a magnitude / phase pair
10583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      otherwise a real / imaginary image pair.
10593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o exception: return any errors or warnings in this structure.
10613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
10633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#if defined(MAGICKCORE_FFTW_DELEGATE)
1065bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristystatic MagickBooleanType InverseQuadrantSwap(const size_t width,
1066bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  const size_t height,const double *source,double *destination)
10673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
1068c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy  register ssize_t
1069c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy    x;
1070c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy
1071bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  ssize_t
10723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    center,
10733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    y;
10743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
10763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Swap quadrants.
10773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
10782e035cd272c0993d28f757f4a913070170095939Cristy  center=(ssize_t) (width/2L)+1L;
1079bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=1L; y < (ssize_t) height; y++)
1080bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (x=0L; x < (ssize_t) (width/2L+1L); x++)
10819b1d6c756cb32746846b038ccb0439db540ba509cristy      destination[(height-y)*center-x+width/2L]=source[y*width+x];
1082bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=0L; y < (ssize_t) height; y++)
10833d04ed7ddc7a93c09476e84cc64412687bf5261acristy    destination[y*center]=source[y*width+width/2L];
10843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  for (x=0L; x < center; x++)
10853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    destination[x]=source[center-x-1L];
1086bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  return(RollFourier(center,height,0L,(ssize_t) height/-2L,destination));
10873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
10883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10893ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic MagickBooleanType InverseFourier(FourierInfo *fourier_info,
1090699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  const Image *magnitude_image,const Image *phase_image,
1091699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  fftw_complex *fourier_pixels,ExceptionInfo *exception)
10923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
10933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  CacheView
10943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *magnitude_view,
10953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *phase_view;
10963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double
1098699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    *inverse_pixels,
10997d4aa38318c20a4309d855f45e3744c9f300f697cristy    *magnitude_pixels,
11007d4aa38318c20a4309d855f45e3744c9f300f697cristy    *phase_pixels;
11013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
11033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
11043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1105699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  MemoryInfo
1106699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    *inverse_info,
1107699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    *magnitude_info,
1108699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    *phase_info;
1109699ae5b6cbee363e53f58e0fedd414f282d07eddcristy
11104c08aed51c5899665ade97263692328eea4af106cristy  register const Quantum
11113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *p;
11123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1113bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
11143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i,
11153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    x;
11163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1117c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy  ssize_t
1118c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy    y;
1119c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy
11203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
11213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Inverse fourier - read image and break down into a double array.
11223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
11232e035cd272c0993d28f757f4a913070170095939Cristy  magnitude_info=AcquireVirtualMemory((size_t) fourier_info->width,
11242e035cd272c0993d28f757f4a913070170095939Cristy    fourier_info->height*sizeof(*magnitude_pixels));
11252e035cd272c0993d28f757f4a913070170095939Cristy  phase_info=AcquireVirtualMemory((size_t) fourier_info->width,
11262e035cd272c0993d28f757f4a913070170095939Cristy    fourier_info->height*sizeof(*phase_pixels));
11272e035cd272c0993d28f757f4a913070170095939Cristy  inverse_info=AcquireVirtualMemory((size_t) fourier_info->width,
11282e035cd272c0993d28f757f4a913070170095939Cristy    (fourier_info->height/2+1)*sizeof(*inverse_pixels));
1129699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  if ((magnitude_info == (MemoryInfo *) NULL) ||
1130699ae5b6cbee363e53f58e0fedd414f282d07eddcristy      (phase_info == (MemoryInfo *) NULL) ||
1131699ae5b6cbee363e53f58e0fedd414f282d07eddcristy      (inverse_info == (MemoryInfo *) NULL))
11323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
1133699ae5b6cbee363e53f58e0fedd414f282d07eddcristy      if (magnitude_info != (MemoryInfo *) NULL)
1134699ae5b6cbee363e53f58e0fedd414f282d07eddcristy        magnitude_info=RelinquishVirtualMemory(magnitude_info);
1135699ae5b6cbee363e53f58e0fedd414f282d07eddcristy      if (phase_info != (MemoryInfo *) NULL)
1136699ae5b6cbee363e53f58e0fedd414f282d07eddcristy        phase_info=RelinquishVirtualMemory(phase_info);
1137699ae5b6cbee363e53f58e0fedd414f282d07eddcristy      if (inverse_info != (MemoryInfo *) NULL)
1138699ae5b6cbee363e53f58e0fedd414f282d07eddcristy        inverse_info=RelinquishVirtualMemory(inverse_info);
11393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) ThrowMagickException(exception,GetMagickModule(),
1140efe601ce9ea5ad34ad0e8ad6e61d9be9b148b2a3cristy        ResourceLimitError,"MemoryAllocationFailed","`%s'",
1141c9550792cd47c57370cd82fef338304f9e576473cristy        magnitude_image->filename);
11423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return(MagickFalse);
11433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
1144699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  magnitude_pixels=(double *) GetVirtualMemoryBlob(magnitude_info);
1145699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  phase_pixels=(double *) GetVirtualMemoryBlob(phase_info);
1146699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  inverse_pixels=(double *) GetVirtualMemoryBlob(inverse_info);
11473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  i=0L;
114846ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy  magnitude_view=AcquireVirtualCacheView(magnitude_image,exception);
1149bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=0L; y < (ssize_t) fourier_info->height; y++)
11503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
11513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    p=GetCacheViewVirtualPixels(magnitude_view,0L,y,fourier_info->width,1UL,
11523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      exception);
11534c08aed51c5899665ade97263692328eea4af106cristy    if (p == (const Quantum *) NULL)
11543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
1155bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (x=0L; x < (ssize_t) fourier_info->width; x++)
11563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
11573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      switch (fourier_info->channel)
11583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
1159d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case RedPixelChannel:
11603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        default:
11613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
11627d4aa38318c20a4309d855f45e3744c9f300f697cristy          magnitude_pixels[i]=QuantumScale*GetPixelRed(magnitude_image,p);
11633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
11643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
1165d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case GreenPixelChannel:
11663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
11677d4aa38318c20a4309d855f45e3744c9f300f697cristy          magnitude_pixels[i]=QuantumScale*GetPixelGreen(magnitude_image,p);
11683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
11693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
1170d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case BluePixelChannel:
11713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
11727d4aa38318c20a4309d855f45e3744c9f300f697cristy          magnitude_pixels[i]=QuantumScale*GetPixelBlue(magnitude_image,p);
11733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
11743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
1175d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case BlackPixelChannel:
11763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
11777d4aa38318c20a4309d855f45e3744c9f300f697cristy          magnitude_pixels[i]=QuantumScale*GetPixelBlack(magnitude_image,p);
11783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
11793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
1180d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case AlphaPixelChannel:
11813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
11827d4aa38318c20a4309d855f45e3744c9f300f697cristy          magnitude_pixels[i]=QuantumScale*GetPixelAlpha(magnitude_image,p);
11833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
11843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
11853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
11863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      i++;
1187ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      p+=GetPixelChannels(magnitude_image);
11883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
11893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
1190699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  magnitude_view=DestroyCacheView(magnitude_view);
1191699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  status=InverseQuadrantSwap(fourier_info->width,fourier_info->height,
1192699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    magnitude_pixels,inverse_pixels);
1193699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  (void) CopyMagickMemory(magnitude_pixels,inverse_pixels,fourier_info->height*
1194699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    fourier_info->center*sizeof(*magnitude_pixels));
11953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  i=0L;
119646ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy  phase_view=AcquireVirtualCacheView(phase_image,exception);
1197bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=0L; y < (ssize_t) fourier_info->height; y++)
11983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
11993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    p=GetCacheViewVirtualPixels(phase_view,0,y,fourier_info->width,1,
12003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      exception);
12014c08aed51c5899665ade97263692328eea4af106cristy    if (p == (const Quantum *) NULL)
12023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
1203bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (x=0L; x < (ssize_t) fourier_info->width; x++)
12043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
12053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      switch (fourier_info->channel)
12063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
1207d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case RedPixelChannel:
12083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        default:
12093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
12107d4aa38318c20a4309d855f45e3744c9f300f697cristy          phase_pixels[i]=QuantumScale*GetPixelRed(phase_image,p);
12113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
12123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
1213d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case GreenPixelChannel:
12143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
12157d4aa38318c20a4309d855f45e3744c9f300f697cristy          phase_pixels[i]=QuantumScale*GetPixelGreen(phase_image,p);
12163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
12173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
1218d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case BluePixelChannel:
12193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
12207d4aa38318c20a4309d855f45e3744c9f300f697cristy          phase_pixels[i]=QuantumScale*GetPixelBlue(phase_image,p);
12213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
12223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
1223d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case BlackPixelChannel:
12243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
12257d4aa38318c20a4309d855f45e3744c9f300f697cristy          phase_pixels[i]=QuantumScale*GetPixelBlack(phase_image,p);
12263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
12273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
1228d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy        case AlphaPixelChannel:
12293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
12307d4aa38318c20a4309d855f45e3744c9f300f697cristy          phase_pixels[i]=QuantumScale*GetPixelAlpha(phase_image,p);
12313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
12323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
12333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
12343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      i++;
1235ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      p+=GetPixelChannels(phase_image);
12363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
12373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
12383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (fourier_info->modulus != MagickFalse)
12393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
12403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      i=0L;
1241bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      for (y=0L; y < (ssize_t) fourier_info->height; y++)
1242bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy        for (x=0L; x < (ssize_t) fourier_info->width; x++)
12433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
12447d4aa38318c20a4309d855f45e3744c9f300f697cristy          phase_pixels[i]-=0.5;
12457d4aa38318c20a4309d855f45e3744c9f300f697cristy          phase_pixels[i]*=(2.0*MagickPI);
12463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          i++;
12473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
12483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
12493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  phase_view=DestroyCacheView(phase_view);
125013c99c4243ef58ec6f752aba6df9970ec16c87e6cristy  CorrectPhaseLHS(fourier_info->width,fourier_info->height,phase_pixels);
12513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (status != MagickFalse)
12523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status=InverseQuadrantSwap(fourier_info->width,fourier_info->height,
1253699ae5b6cbee363e53f58e0fedd414f282d07eddcristy      phase_pixels,inverse_pixels);
1254699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  (void) CopyMagickMemory(phase_pixels,inverse_pixels,fourier_info->height*
1255699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    fourier_info->center*sizeof(*phase_pixels));
1256699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  inverse_info=RelinquishVirtualMemory(inverse_info);
12573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
12583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Merge two sets.
12593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
12603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  i=0L;
12613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (fourier_info->modulus != MagickFalse)
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]*cos(phase_pixels[i])+I*
1267699ae5b6cbee363e53f58e0fedd414f282d07eddcristy           magnitude_pixels[i]*sin(phase_pixels[i]);
126856ed31cc763800a9fb1f0df96104c354b40d2cbccristy#else
1269699ae5b6cbee363e53f58e0fedd414f282d07eddcristy         fourier_pixels[i][0]=magnitude_pixels[i]*cos(phase_pixels[i]);
1270699ae5b6cbee363e53f58e0fedd414f282d07eddcristy         fourier_pixels[i][1]=magnitude_pixels[i]*sin(phase_pixels[i]);
127156ed31cc763800a9fb1f0df96104c354b40d2cbccristy#endif
12723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy         i++;
12733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
12743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  else
1275bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (y=0L; y < (ssize_t) fourier_info->height; y++)
1276bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      for (x=0L; x < (ssize_t) fourier_info->center; x++)
12773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
127856ed31cc763800a9fb1f0df96104c354b40d2cbccristy#if defined(MAGICKCORE_HAVE_COMPLEX_H)
1279699ae5b6cbee363e53f58e0fedd414f282d07eddcristy        fourier_pixels[i]=magnitude_pixels[i]+I*phase_pixels[i];
128056ed31cc763800a9fb1f0df96104c354b40d2cbccristy#else
1281699ae5b6cbee363e53f58e0fedd414f282d07eddcristy        fourier_pixels[i][0]=magnitude_pixels[i];
1282699ae5b6cbee363e53f58e0fedd414f282d07eddcristy        fourier_pixels[i][1]=phase_pixels[i];
128356ed31cc763800a9fb1f0df96104c354b40d2cbccristy#endif
12843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        i++;
12853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
1286699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  magnitude_info=RelinquishVirtualMemory(magnitude_info);
1287699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  phase_info=RelinquishVirtualMemory(phase_info);
12883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(status);
12893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
12903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12913ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic MagickBooleanType InverseFourierTransform(FourierInfo *fourier_info,
1292699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  fftw_complex *fourier_pixels,Image *image,ExceptionInfo *exception)
12933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
12943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  CacheView
12953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *image_view;
12963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
129799dc036190f292a67801dc4b141898bf18c96b36cristy  const char
129899dc036190f292a67801dc4b141898bf18c96b36cristy    *value;
129999dc036190f292a67801dc4b141898bf18c96b36cristy
13003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double
1301699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    *source_pixels;
13023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
13033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fftw_plan
13043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    fftw_c2r_plan;
13053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1306699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  MemoryInfo
1307699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    *source_info;
1308699ae5b6cbee363e53f58e0fedd414f282d07eddcristy
13094c08aed51c5899665ade97263692328eea4af106cristy  register Quantum
1310c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy    *q;
1311c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy
1312bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
13133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i,
13143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    x;
13153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1316c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy  ssize_t
1317c4ea4a479c90f81168aa2b99e7680c7b0459d415cristy    y;
13183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
13192e035cd272c0993d28f757f4a913070170095939Cristy  source_info=AcquireVirtualMemory((size_t) fourier_info->width,
13202e035cd272c0993d28f757f4a913070170095939Cristy    fourier_info->height*sizeof(*source_pixels));
1321699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  if (source_info == (MemoryInfo *) NULL)
13223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
13233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) ThrowMagickException(exception,GetMagickModule(),
1324efe601ce9ea5ad34ad0e8ad6e61d9be9b148b2a3cristy        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
13253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return(MagickFalse);
13263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
1327699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  source_pixels=(double *) GetVirtualMemoryBlob(source_info);
132899dc036190f292a67801dc4b141898bf18c96b36cristy  value=GetImageArtifact(image,"fourier:normalize");
1329f8ecbfdd4702c1b9dcc8f35870b60d61e6d32d79cristy  if (LocaleCompare(value,"inverse") == 0)
133099dc036190f292a67801dc4b141898bf18c96b36cristy    {
133199dc036190f292a67801dc4b141898bf18c96b36cristy      double
133299dc036190f292a67801dc4b141898bf18c96b36cristy        gamma;
133399dc036190f292a67801dc4b141898bf18c96b36cristy
133499dc036190f292a67801dc4b141898bf18c96b36cristy      /*
133599dc036190f292a67801dc4b141898bf18c96b36cristy        Normalize inverse transform.
133699dc036190f292a67801dc4b141898bf18c96b36cristy      */
133799dc036190f292a67801dc4b141898bf18c96b36cristy      i=0L;
133899dc036190f292a67801dc4b141898bf18c96b36cristy      gamma=PerceptibleReciprocal((double) fourier_info->width*
133999dc036190f292a67801dc4b141898bf18c96b36cristy        fourier_info->height);
134099dc036190f292a67801dc4b141898bf18c96b36cristy      for (y=0L; y < (ssize_t) fourier_info->height; y++)
134199dc036190f292a67801dc4b141898bf18c96b36cristy        for (x=0L; x < (ssize_t) fourier_info->center; x++)
134299dc036190f292a67801dc4b141898bf18c96b36cristy        {
134399dc036190f292a67801dc4b141898bf18c96b36cristy#if defined(MAGICKCORE_HAVE_COMPLEX_H)
134499dc036190f292a67801dc4b141898bf18c96b36cristy          fourier_pixels[i]*=gamma;
134599dc036190f292a67801dc4b141898bf18c96b36cristy#else
134699dc036190f292a67801dc4b141898bf18c96b36cristy          fourier_pixels[i][0]*=gamma;
134799dc036190f292a67801dc4b141898bf18c96b36cristy          fourier_pixels[i][1]*=gamma;
134899dc036190f292a67801dc4b141898bf18c96b36cristy#endif
134999dc036190f292a67801dc4b141898bf18c96b36cristy          i++;
135099dc036190f292a67801dc4b141898bf18c96b36cristy        }
135199dc036190f292a67801dc4b141898bf18c96b36cristy    }
1352b5d5f725fef80ff5d50db3111c05a1a521b81e7fcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
13533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  #pragma omp critical (MagickCore_InverseFourierTransform)
13543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
1355bbc9a95a7875c8c9b4a8e0b87491aa52e56ec849Cristy  fftw_c2r_plan=fftw_plan_dft_c2r_2d(fourier_info->width,fourier_info->height,
1356bbc9a95a7875c8c9b4a8e0b87491aa52e56ec849Cristy    fourier_pixels,source_pixels,FFTW_ESTIMATE);
1357bbc9a95a7875c8c9b4a8e0b87491aa52e56ec849Cristy  fftw_execute_dft_c2r(fftw_c2r_plan,fourier_pixels,source_pixels);
1358bbc9a95a7875c8c9b4a8e0b87491aa52e56ec849Cristy  fftw_destroy_plan(fftw_c2r_plan);
13593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  i=0L;
136046ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy  image_view=AcquireAuthenticCacheView(image,exception);
1361bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=0L; y < (ssize_t) fourier_info->height; y++)
13623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
136385812051623aa663ad40386ebfc4b8d0ca87bd55cristy    if (y >= (ssize_t) image->rows)
136485812051623aa663ad40386ebfc4b8d0ca87bd55cristy      break;
136585812051623aa663ad40386ebfc4b8d0ca87bd55cristy    q=GetCacheViewAuthenticPixels(image_view,0L,y,fourier_info->width >
136685812051623aa663ad40386ebfc4b8d0ca87bd55cristy      image->columns ? image->columns : fourier_info->width,1UL,exception);
1367acd2ed254c18c254a0ab5aafa06d1645e5d079d8cristy    if (q == (Quantum *) NULL)
13683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
1369bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (x=0L; x < (ssize_t) fourier_info->width; x++)
13703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
1371233fe5816db8ff3930e64adebd232757d8d2c06ecristy      if (x < (ssize_t) image->columns)
1372233fe5816db8ff3930e64adebd232757d8d2c06ecristy        switch (fourier_info->channel)
13733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
1374233fe5816db8ff3930e64adebd232757d8d2c06ecristy          case RedPixelChannel:
1375233fe5816db8ff3930e64adebd232757d8d2c06ecristy          default:
1376233fe5816db8ff3930e64adebd232757d8d2c06ecristy          {
1377699ae5b6cbee363e53f58e0fedd414f282d07eddcristy            SetPixelRed(image,ClampToQuantum(QuantumRange*source_pixels[i]),q);
1378233fe5816db8ff3930e64adebd232757d8d2c06ecristy            break;
1379233fe5816db8ff3930e64adebd232757d8d2c06ecristy          }
1380233fe5816db8ff3930e64adebd232757d8d2c06ecristy          case GreenPixelChannel:
1381233fe5816db8ff3930e64adebd232757d8d2c06ecristy          {
1382699ae5b6cbee363e53f58e0fedd414f282d07eddcristy            SetPixelGreen(image,ClampToQuantum(QuantumRange*source_pixels[i]),
1383699ae5b6cbee363e53f58e0fedd414f282d07eddcristy              q);
1384233fe5816db8ff3930e64adebd232757d8d2c06ecristy            break;
1385233fe5816db8ff3930e64adebd232757d8d2c06ecristy          }
1386233fe5816db8ff3930e64adebd232757d8d2c06ecristy          case BluePixelChannel:
1387233fe5816db8ff3930e64adebd232757d8d2c06ecristy          {
1388699ae5b6cbee363e53f58e0fedd414f282d07eddcristy            SetPixelBlue(image,ClampToQuantum(QuantumRange*source_pixels[i]),
1389699ae5b6cbee363e53f58e0fedd414f282d07eddcristy              q);
1390233fe5816db8ff3930e64adebd232757d8d2c06ecristy            break;
1391233fe5816db8ff3930e64adebd232757d8d2c06ecristy          }
1392233fe5816db8ff3930e64adebd232757d8d2c06ecristy          case BlackPixelChannel:
1393233fe5816db8ff3930e64adebd232757d8d2c06ecristy          {
1394699ae5b6cbee363e53f58e0fedd414f282d07eddcristy            SetPixelBlack(image,ClampToQuantum(QuantumRange*source_pixels[i]),
1395699ae5b6cbee363e53f58e0fedd414f282d07eddcristy              q);
1396233fe5816db8ff3930e64adebd232757d8d2c06ecristy            break;
1397233fe5816db8ff3930e64adebd232757d8d2c06ecristy          }
1398233fe5816db8ff3930e64adebd232757d8d2c06ecristy          case AlphaPixelChannel:
1399233fe5816db8ff3930e64adebd232757d8d2c06ecristy          {
1400699ae5b6cbee363e53f58e0fedd414f282d07eddcristy            SetPixelAlpha(image,ClampToQuantum(QuantumRange*source_pixels[i]),
1401699ae5b6cbee363e53f58e0fedd414f282d07eddcristy              q);
1402233fe5816db8ff3930e64adebd232757d8d2c06ecristy            break;
1403233fe5816db8ff3930e64adebd232757d8d2c06ecristy          }
14043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
14053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      i++;
1406ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      q+=GetPixelChannels(image);
14073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
14083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
14093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
14103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
14113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  image_view=DestroyCacheView(image_view);
1412699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  source_info=RelinquishVirtualMemory(source_info);
14133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickTrue);
14143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
14153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1416c9550792cd47c57370cd82fef338304f9e576473cristystatic MagickBooleanType InverseFourierTransformChannel(
1417c9550792cd47c57370cd82fef338304f9e576473cristy  const Image *magnitude_image,const Image *phase_image,
1418d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy  const PixelChannel channel,const MagickBooleanType modulus,
14193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Image *fourier_image,ExceptionInfo *exception)
14203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
14213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fftw_complex
1422699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    *inverse_pixels;
14233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
14243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  FourierInfo
14253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    fourier_info;
14263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
14273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
14283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
14293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1430699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  MemoryInfo
1431699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    *inverse_info;
1432699ae5b6cbee363e53f58e0fedd414f282d07eddcristy
1433c9550792cd47c57370cd82fef338304f9e576473cristy  fourier_info.width=magnitude_image->columns;
14340a69e6429fff81c8de551ed10e358df7b0b2a585cristy  fourier_info.height=magnitude_image->rows;
14352a5f27cd841820bdf64d9aa42d02c54df8ea7885Cristy  if ((magnitude_image->columns != magnitude_image->rows) ||
14362a5f27cd841820bdf64d9aa42d02c54df8ea7885Cristy      ((magnitude_image->columns % 2) != 0) ||
14372a5f27cd841820bdf64d9aa42d02c54df8ea7885Cristy      ((magnitude_image->rows % 2) != 0))
14382a5f27cd841820bdf64d9aa42d02c54df8ea7885Cristy    {
14392a5f27cd841820bdf64d9aa42d02c54df8ea7885Cristy      size_t extent=magnitude_image->columns < magnitude_image->rows ?
14402a5f27cd841820bdf64d9aa42d02c54df8ea7885Cristy        magnitude_image->rows : magnitude_image->columns;
14412a5f27cd841820bdf64d9aa42d02c54df8ea7885Cristy      fourier_info.width=(extent & 0x01) == 1 ? extent+1UL : extent;
14422a5f27cd841820bdf64d9aa42d02c54df8ea7885Cristy    }
14432a5f27cd841820bdf64d9aa42d02c54df8ea7885Cristy  fourier_info.height=fourier_info.width;
14442e035cd272c0993d28f757f4a913070170095939Cristy  fourier_info.center=(ssize_t) (fourier_info.width/2L)+1L;
14453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fourier_info.channel=channel;
14463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fourier_info.modulus=modulus;
14472e035cd272c0993d28f757f4a913070170095939Cristy  inverse_info=AcquireVirtualMemory((size_t) fourier_info.width,
14482e035cd272c0993d28f757f4a913070170095939Cristy    (fourier_info.height/2+1)*sizeof(*inverse_pixels));
1449699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  if (inverse_info == (MemoryInfo *) NULL)
14503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
14513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) ThrowMagickException(exception,GetMagickModule(),
1452efe601ce9ea5ad34ad0e8ad6e61d9be9b148b2a3cristy        ResourceLimitError,"MemoryAllocationFailed","`%s'",
1453c9550792cd47c57370cd82fef338304f9e576473cristy        magnitude_image->filename);
14543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return(MagickFalse);
14553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
1456699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  inverse_pixels=(fftw_complex *) GetVirtualMemoryBlob(inverse_info);
1457699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  status=InverseFourier(&fourier_info,magnitude_image,phase_image,
1458699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    inverse_pixels,exception);
14593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (status != MagickFalse)
1460699ae5b6cbee363e53f58e0fedd414f282d07eddcristy    status=InverseFourierTransform(&fourier_info,inverse_pixels,fourier_image,
14613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      exception);
1462699ae5b6cbee363e53f58e0fedd414f282d07eddcristy  inverse_info=RelinquishVirtualMemory(inverse_info);
14633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(status);
14643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
14653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
14663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1467c9550792cd47c57370cd82fef338304f9e576473cristyMagickExport Image *InverseFourierTransformImage(const Image *magnitude_image,
1468c9550792cd47c57370cd82fef338304f9e576473cristy  const Image *phase_image,const MagickBooleanType modulus,
1469c9550792cd47c57370cd82fef338304f9e576473cristy  ExceptionInfo *exception)
14703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
14713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Image
14723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *fourier_image;
14733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1474c9550792cd47c57370cd82fef338304f9e576473cristy  assert(magnitude_image != (Image *) NULL);
1475e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(magnitude_image->signature == MagickCoreSignature);
1476c9550792cd47c57370cd82fef338304f9e576473cristy  if (magnitude_image->debug != MagickFalse)
1477c9550792cd47c57370cd82fef338304f9e576473cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1478c9550792cd47c57370cd82fef338304f9e576473cristy      magnitude_image->filename);
1479c9550792cd47c57370cd82fef338304f9e576473cristy  if (phase_image == (Image *) NULL)
1480c9550792cd47c57370cd82fef338304f9e576473cristy    {
1481c9550792cd47c57370cd82fef338304f9e576473cristy      (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
14822e035cd272c0993d28f757f4a913070170095939Cristy        "ImageSequenceRequired","`%s'",magnitude_image->filename);
14839372a158e662d81ce4df26249238df39d66102ffcristy      return((Image *) NULL);
1484c9550792cd47c57370cd82fef338304f9e576473cristy    }
14853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#if !defined(MAGICKCORE_FFTW_DELEGATE)
14863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fourier_image=(Image *) NULL;
14873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) modulus;
14883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) ThrowMagickException(exception,GetMagickModule(),
14892e035cd272c0993d28f757f4a913070170095939Cristy    MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","`%s' (FFTW)",
1490c9550792cd47c57370cd82fef338304f9e576473cristy    magnitude_image->filename);
14913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#else
14923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
1493c9550792cd47c57370cd82fef338304f9e576473cristy    fourier_image=CloneImage(magnitude_image,magnitude_image->columns,
14944c9c4d0c413e922bc941efc7657a5c075a944c1fcristy      magnitude_image->rows,MagickTrue,exception);
14953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (fourier_image != (Image *) NULL)
14963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
14973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        MagickBooleanType
14983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          is_gray,
14993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status;
15003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
15013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        status=MagickTrue;
1502c6f2ac9fbacb63eb30ab87d80dba97d634742d4bcristy        is_gray=IsImageGray(magnitude_image);
1503c9550792cd47c57370cd82fef338304f9e576473cristy        if (is_gray != MagickFalse)
1504c6f2ac9fbacb63eb30ab87d80dba97d634742d4bcristy          is_gray=IsImageGray(phase_image);
1505b5d5f725fef80ff5d50db3111c05a1a521b81e7fcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
1506b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy        #pragma omp parallel sections
15073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
15083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
1509b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
1510b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy          #pragma omp section
1511b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#endif
15123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          {
1513b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            MagickBooleanType
1514b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              thread_status;
1515b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy
1516b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            if (is_gray != MagickFalse)
1517b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              thread_status=InverseFourierTransformChannel(magnitude_image,
1518d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy                phase_image,GrayPixelChannel,modulus,fourier_image,exception);
1519b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            else
1520c9550792cd47c57370cd82fef338304f9e576473cristy              thread_status=InverseFourierTransformChannel(magnitude_image,
1521d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy                phase_image,RedPixelChannel,modulus,fourier_image,exception);
1522b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            if (thread_status == MagickFalse)
1523b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              status=thread_status;
1524b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy          }
1525b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
1526b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy          #pragma omp section
1527b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#endif
1528b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy          {
1529b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            MagickBooleanType
1530b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              thread_status;
1531b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy
1532b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            thread_status=MagickTrue;
1533b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            if (is_gray == MagickFalse)
1534b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              thread_status=InverseFourierTransformChannel(magnitude_image,
1535d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy                phase_image,GreenPixelChannel,modulus,fourier_image,exception);
1536b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            if (thread_status == MagickFalse)
1537b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              status=thread_status;
1538b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy          }
1539b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
1540b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy          #pragma omp section
1541b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#endif
1542b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy          {
1543b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            MagickBooleanType
1544b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              thread_status;
1545b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy
1546b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            thread_status=MagickTrue;
1547b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            if (is_gray == MagickFalse)
1548b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              thread_status=InverseFourierTransformChannel(magnitude_image,
1549d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy                phase_image,BluePixelChannel,modulus,fourier_image,exception);
1550b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            if (thread_status == MagickFalse)
1551b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              status=thread_status;
1552b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy          }
1553b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
1554b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy          #pragma omp section
1555b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#endif
1556b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy          {
1557b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            MagickBooleanType
1558b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              thread_status;
1559b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy
1560b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            thread_status=MagickTrue;
15614c08aed51c5899665ade97263692328eea4af106cristy            if (magnitude_image->colorspace == CMYKColorspace)
1562b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              thread_status=InverseFourierTransformChannel(magnitude_image,
1563d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy                phase_image,BlackPixelChannel,modulus,fourier_image,exception);
1564b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            if (thread_status == MagickFalse)
1565b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              status=thread_status;
1566b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy          }
1567b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
1568b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy          #pragma omp section
1569b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy#endif
1570b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy          {
1571b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            MagickBooleanType
1572b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              thread_status;
1573b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy
1574b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            thread_status=MagickTrue;
157517f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy            if (magnitude_image->alpha_trait != UndefinedPixelTrait)
1576b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              thread_status=InverseFourierTransformChannel(magnitude_image,
1577d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy                phase_image,AlphaPixelChannel,modulus,fourier_image,exception);
1578b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy            if (thread_status == MagickFalse)
1579b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy              status=thread_status;
15803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          }
15813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
15823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (status == MagickFalse)
15833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          fourier_image=DestroyImage(fourier_image);
15843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
1585b34ef05f2607256ec3d54920fb4dbace9d0db20dcristy    fftw_cleanup();
15863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
15873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
15883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(fourier_image);
15893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
1590