PageRenderTime 47ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/MagickCore/fourier.c

https://gitlab.com/ImageMagick/ImageMagick
C | 1589 lines | 1319 code | 101 blank | 169 comment | 251 complexity | d681ab508d88c7a9ea2f173b17e95104 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception
  1. /*
  2. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3. % %
  4. % %
  5. % %
  6. % FFFFF OOO U U RRRR IIIII EEEEE RRRR %
  7. % F O O U U R R I E R R %
  8. % FFF O O U U RRRR I EEE RRRR %
  9. % F O O U U R R I E R R %
  10. % F OOO UUU R R IIIII EEEEE R R %
  11. % %
  12. % %
  13. % MagickCore Discrete Fourier Transform Methods %
  14. % %
  15. % Software Design %
  16. % Sean Burke %
  17. % Fred Weinhaus %
  18. % Cristy %
  19. % July 2009 %
  20. % %
  21. % %
  22. % Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization %
  23. % dedicated to making software imaging solutions freely available. %
  24. % %
  25. % You may not use this file except in compliance with the License. You may %
  26. % obtain a copy of the License at %
  27. % %
  28. % https://imagemagick.org/script/license.php %
  29. % %
  30. % Unless required by applicable law or agreed to in writing, software %
  31. % distributed under the License is distributed on an "AS IS" BASIS, %
  32. % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
  33. % See the License for the specific language governing permissions and %
  34. % limitations under the License. %
  35. % %
  36. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  37. %
  38. %
  39. %
  40. */
  41. /*
  42. Include declarations.
  43. */
  44. #include "MagickCore/studio.h"
  45. #include "MagickCore/artifact.h"
  46. #include "MagickCore/attribute.h"
  47. #include "MagickCore/blob.h"
  48. #include "MagickCore/cache.h"
  49. #include "MagickCore/image.h"
  50. #include "MagickCore/image-private.h"
  51. #include "MagickCore/list.h"
  52. #include "MagickCore/fourier.h"
  53. #include "MagickCore/log.h"
  54. #include "MagickCore/memory_.h"
  55. #include "MagickCore/monitor.h"
  56. #include "MagickCore/monitor-private.h"
  57. #include "MagickCore/pixel-accessor.h"
  58. #include "MagickCore/pixel-private.h"
  59. #include "MagickCore/property.h"
  60. #include "MagickCore/quantum-private.h"
  61. #include "MagickCore/resource_.h"
  62. #include "MagickCore/string-private.h"
  63. #include "MagickCore/thread-private.h"
  64. #if defined(MAGICKCORE_FFTW_DELEGATE)
  65. #if defined(MAGICKCORE_HAVE_COMPLEX_H)
  66. #include <complex.h>
  67. #endif
  68. #include <fftw3.h>
  69. #if !defined(MAGICKCORE_HAVE_CABS)
  70. #define cabs(z) (sqrt(z[0]*z[0]+z[1]*z[1]))
  71. #endif
  72. #if !defined(MAGICKCORE_HAVE_CARG)
  73. #define carg(z) (atan2(cimag(z),creal(z)))
  74. #endif
  75. #if !defined(MAGICKCORE_HAVE_CIMAG)
  76. #define cimag(z) (z[1])
  77. #endif
  78. #if !defined(MAGICKCORE_HAVE_CREAL)
  79. #define creal(z) (z[0])
  80. #endif
  81. #endif
  82. /*
  83. Typedef declarations.
  84. */
  85. typedef struct _FourierInfo
  86. {
  87. PixelChannel
  88. channel;
  89. MagickBooleanType
  90. modulus;
  91. size_t
  92. width,
  93. height;
  94. ssize_t
  95. center;
  96. } FourierInfo;
  97. /*
  98. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  99. % %
  100. % %
  101. % %
  102. % C o m p l e x I m a g e s %
  103. % %
  104. % %
  105. % %
  106. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  107. %
  108. % ComplexImages() performs complex mathematics on an image sequence.
  109. %
  110. % The format of the ComplexImages method is:
  111. %
  112. % MagickBooleanType ComplexImages(Image *images,const ComplexOperator op,
  113. % ExceptionInfo *exception)
  114. %
  115. % A description of each parameter follows:
  116. %
  117. % o image: the image.
  118. %
  119. % o op: A complex operator.
  120. %
  121. % o exception: return any errors or warnings in this structure.
  122. %
  123. */
  124. MagickExport Image *ComplexImages(const Image *images,const ComplexOperator op,
  125. ExceptionInfo *exception)
  126. {
  127. #define ComplexImageTag "Complex/Image"
  128. CacheView
  129. *Ai_view,
  130. *Ar_view,
  131. *Bi_view,
  132. *Br_view,
  133. *Ci_view,
  134. *Cr_view;
  135. const char
  136. *artifact;
  137. const Image
  138. *Ai_image,
  139. *Ar_image,
  140. *Bi_image,
  141. *Br_image;
  142. double
  143. snr;
  144. Image
  145. *Ci_image,
  146. *complex_images,
  147. *Cr_image,
  148. *image;
  149. MagickBooleanType
  150. status;
  151. MagickOffsetType
  152. progress;
  153. ssize_t
  154. y;
  155. assert(images != (Image *) NULL);
  156. assert(images->signature == MagickCoreSignature);
  157. if (images->debug != MagickFalse)
  158. (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
  159. assert(exception != (ExceptionInfo *) NULL);
  160. assert(exception->signature == MagickCoreSignature);
  161. if (images->next == (Image *) NULL)
  162. {
  163. (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
  164. "ImageSequenceRequired","`%s'",images->filename);
  165. return((Image *) NULL);
  166. }
  167. image=CloneImage(images,0,0,MagickTrue,exception);
  168. if (image == (Image *) NULL)
  169. return((Image *) NULL);
  170. if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
  171. {
  172. image=DestroyImageList(image);
  173. return(image);
  174. }
  175. image->depth=32UL;
  176. complex_images=NewImageList();
  177. AppendImageToList(&complex_images,image);
  178. image=CloneImage(images,0,0,MagickTrue,exception);
  179. if (image == (Image *) NULL)
  180. {
  181. complex_images=DestroyImageList(complex_images);
  182. return(complex_images);
  183. }
  184. AppendImageToList(&complex_images,image);
  185. /*
  186. Apply complex mathematics to image pixels.
  187. */
  188. artifact=GetImageArtifact(image,"complex:snr");
  189. snr=0.0;
  190. if (artifact != (const char *) NULL)
  191. snr=StringToDouble(artifact,(char **) NULL);
  192. Ar_image=images;
  193. Ai_image=images->next;
  194. Br_image=images;
  195. Bi_image=images->next;
  196. if ((images->next->next != (Image *) NULL) &&
  197. (images->next->next->next != (Image *) NULL))
  198. {
  199. Br_image=images->next->next;
  200. Bi_image=images->next->next->next;
  201. }
  202. Cr_image=complex_images;
  203. Ci_image=complex_images->next;
  204. Ar_view=AcquireVirtualCacheView(Ar_image,exception);
  205. Ai_view=AcquireVirtualCacheView(Ai_image,exception);
  206. Br_view=AcquireVirtualCacheView(Br_image,exception);
  207. Bi_view=AcquireVirtualCacheView(Bi_image,exception);
  208. Cr_view=AcquireAuthenticCacheView(Cr_image,exception);
  209. Ci_view=AcquireAuthenticCacheView(Ci_image,exception);
  210. status=MagickTrue;
  211. progress=0;
  212. #if defined(MAGICKCORE_OPENMP_SUPPORT)
  213. #pragma omp parallel for schedule(static) shared(progress,status) \
  214. magick_number_threads(images,complex_images,images->rows,1L)
  215. #endif
  216. for (y=0; y < (ssize_t) images->rows; y++)
  217. {
  218. register const Quantum
  219. *magick_restrict Ai,
  220. *magick_restrict Ar,
  221. *magick_restrict Bi,
  222. *magick_restrict Br;
  223. register Quantum
  224. *magick_restrict Ci,
  225. *magick_restrict Cr;
  226. register ssize_t
  227. x;
  228. if (status == MagickFalse)
  229. continue;
  230. Ar=GetCacheViewVirtualPixels(Ar_view,0,y,Ar_image->columns,1,exception);
  231. Ai=GetCacheViewVirtualPixels(Ai_view,0,y,Ai_image->columns,1,exception);
  232. Br=GetCacheViewVirtualPixels(Br_view,0,y,Br_image->columns,1,exception);
  233. Bi=GetCacheViewVirtualPixels(Bi_view,0,y,Bi_image->columns,1,exception);
  234. Cr=QueueCacheViewAuthenticPixels(Cr_view,0,y,Cr_image->columns,1,exception);
  235. Ci=QueueCacheViewAuthenticPixels(Ci_view,0,y,Ci_image->columns,1,exception);
  236. if ((Ar == (const Quantum *) NULL) || (Ai == (const Quantum *) NULL) ||
  237. (Br == (const Quantum *) NULL) || (Bi == (const Quantum *) NULL) ||
  238. (Cr == (Quantum *) NULL) || (Ci == (Quantum *) NULL))
  239. {
  240. status=MagickFalse;
  241. continue;
  242. }
  243. for (x=0; x < (ssize_t) images->columns; x++)
  244. {
  245. register ssize_t
  246. i;
  247. for (i=0; i < (ssize_t) GetPixelChannels(images); i++)
  248. {
  249. switch (op)
  250. {
  251. case AddComplexOperator:
  252. {
  253. Cr[i]=Ar[i]+Br[i];
  254. Ci[i]=Ai[i]+Bi[i];
  255. break;
  256. }
  257. case ConjugateComplexOperator:
  258. default:
  259. {
  260. Cr[i]=Ar[i];
  261. Ci[i]=(-Bi[i]);
  262. break;
  263. }
  264. case DivideComplexOperator:
  265. {
  266. double
  267. gamma;
  268. gamma=PerceptibleReciprocal(Br[i]*Br[i]+Bi[i]*Bi[i]+snr);
  269. Cr[i]=gamma*(Ar[i]*Br[i]+Ai[i]*Bi[i]);
  270. Ci[i]=gamma*(Ai[i]*Br[i]-Ar[i]*Bi[i]);
  271. break;
  272. }
  273. case MagnitudePhaseComplexOperator:
  274. {
  275. Cr[i]=sqrt(Ar[i]*Ar[i]+Ai[i]*Ai[i]);
  276. Ci[i]=atan2(Ai[i],Ar[i])/(2.0*MagickPI)+0.5;
  277. break;
  278. }
  279. case MultiplyComplexOperator:
  280. {
  281. Cr[i]=QuantumScale*(Ar[i]*Br[i]-Ai[i]*Bi[i]);
  282. Ci[i]=QuantumScale*(Ai[i]*Br[i]+Ar[i]*Bi[i]);
  283. break;
  284. }
  285. case RealImaginaryComplexOperator:
  286. {
  287. Cr[i]=Ar[i]*cos(2.0*MagickPI*(Ai[i]-0.5));
  288. Ci[i]=Ar[i]*sin(2.0*MagickPI*(Ai[i]-0.5));
  289. break;
  290. }
  291. case SubtractComplexOperator:
  292. {
  293. Cr[i]=Ar[i]-Br[i];
  294. Ci[i]=Ai[i]-Bi[i];
  295. break;
  296. }
  297. }
  298. }
  299. Ar+=GetPixelChannels(Ar_image);
  300. Ai+=GetPixelChannels(Ai_image);
  301. Br+=GetPixelChannels(Br_image);
  302. Bi+=GetPixelChannels(Bi_image);
  303. Cr+=GetPixelChannels(Cr_image);
  304. Ci+=GetPixelChannels(Ci_image);
  305. }
  306. if (SyncCacheViewAuthenticPixels(Ci_view,exception) == MagickFalse)
  307. status=MagickFalse;
  308. if (SyncCacheViewAuthenticPixels(Cr_view,exception) == MagickFalse)
  309. status=MagickFalse;
  310. if (images->progress_monitor != (MagickProgressMonitor) NULL)
  311. {
  312. MagickBooleanType
  313. proceed;
  314. #if defined(MAGICKCORE_OPENMP_SUPPORT)
  315. #pragma omp atomic
  316. #endif
  317. progress++;
  318. proceed=SetImageProgress(images,ComplexImageTag,progress,images->rows);
  319. if (proceed == MagickFalse)
  320. status=MagickFalse;
  321. }
  322. }
  323. Cr_view=DestroyCacheView(Cr_view);
  324. Ci_view=DestroyCacheView(Ci_view);
  325. Br_view=DestroyCacheView(Br_view);
  326. Bi_view=DestroyCacheView(Bi_view);
  327. Ar_view=DestroyCacheView(Ar_view);
  328. Ai_view=DestroyCacheView(Ai_view);
  329. if (status == MagickFalse)
  330. complex_images=DestroyImageList(complex_images);
  331. return(complex_images);
  332. }
  333. /*
  334. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  335. % %
  336. % %
  337. % %
  338. % 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 %
  339. % %
  340. % %
  341. % %
  342. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  343. %
  344. % ForwardFourierTransformImage() implements the discrete Fourier transform
  345. % (DFT) of the image either as a magnitude / phase or real / imaginary image
  346. % pair.
  347. %
  348. % The format of the ForwadFourierTransformImage method is:
  349. %
  350. % Image *ForwardFourierTransformImage(const Image *image,
  351. % const MagickBooleanType modulus,ExceptionInfo *exception)
  352. %
  353. % A description of each parameter follows:
  354. %
  355. % o image: the image.
  356. %
  357. % o modulus: if true, return as transform as a magnitude / phase pair
  358. % otherwise a real / imaginary image pair.
  359. %
  360. % o exception: return any errors or warnings in this structure.
  361. %
  362. */
  363. #if defined(MAGICKCORE_FFTW_DELEGATE)
  364. static MagickBooleanType RollFourier(const size_t width,const size_t height,
  365. const ssize_t x_offset,const ssize_t y_offset,double *roll_pixels)
  366. {
  367. double
  368. *source_pixels;
  369. MemoryInfo
  370. *source_info;
  371. register ssize_t
  372. i,
  373. x;
  374. ssize_t
  375. u,
  376. v,
  377. y;
  378. /*
  379. Move zero frequency (DC, average color) from (0,0) to (width/2,height/2).
  380. */
  381. source_info=AcquireVirtualMemory(width,height*sizeof(*source_pixels));
  382. if (source_info == (MemoryInfo *) NULL)
  383. return(MagickFalse);
  384. source_pixels=(double *) GetVirtualMemoryBlob(source_info);
  385. i=0L;
  386. for (y=0L; y < (ssize_t) height; y++)
  387. {
  388. if (y_offset < 0L)
  389. v=((y+y_offset) < 0L) ? y+y_offset+(ssize_t) height : y+y_offset;
  390. else
  391. v=((y+y_offset) > ((ssize_t) height-1L)) ? y+y_offset-(ssize_t) height :
  392. y+y_offset;
  393. for (x=0L; x < (ssize_t) width; x++)
  394. {
  395. if (x_offset < 0L)
  396. u=((x+x_offset) < 0L) ? x+x_offset+(ssize_t) width : x+x_offset;
  397. else
  398. u=((x+x_offset) > ((ssize_t) width-1L)) ? x+x_offset-(ssize_t) width :
  399. x+x_offset;
  400. source_pixels[v*width+u]=roll_pixels[i++];
  401. }
  402. }
  403. (void) memcpy(roll_pixels,source_pixels,height*width*
  404. sizeof(*source_pixels));
  405. source_info=RelinquishVirtualMemory(source_info);
  406. return(MagickTrue);
  407. }
  408. static MagickBooleanType ForwardQuadrantSwap(const size_t width,
  409. const size_t height,double *source_pixels,double *forward_pixels)
  410. {
  411. MagickBooleanType
  412. status;
  413. register ssize_t
  414. x;
  415. ssize_t
  416. center,
  417. y;
  418. /*
  419. Swap quadrants.
  420. */
  421. center=(ssize_t) (width/2L)+1L;
  422. status=RollFourier((size_t) center,height,0L,(ssize_t) height/2L,
  423. source_pixels);
  424. if (status == MagickFalse)
  425. return(MagickFalse);
  426. for (y=0L; y < (ssize_t) height; y++)
  427. for (x=0L; x < (ssize_t) (width/2L); x++)
  428. forward_pixels[y*width+x+width/2L]=source_pixels[y*center+x];
  429. for (y=1; y < (ssize_t) height; y++)
  430. for (x=0L; x < (ssize_t) (width/2L); x++)
  431. forward_pixels[(height-y)*width+width/2L-x-1L]=
  432. source_pixels[y*center+x+1L];
  433. for (x=0L; x < (ssize_t) (width/2L); x++)
  434. forward_pixels[width/2L-x-1L]=source_pixels[x+1L];
  435. return(MagickTrue);
  436. }
  437. static void CorrectPhaseLHS(const size_t width,const size_t height,
  438. double *fourier_pixels)
  439. {
  440. register ssize_t
  441. x;
  442. ssize_t
  443. y;
  444. for (y=0L; y < (ssize_t) height; y++)
  445. for (x=0L; x < (ssize_t) (width/2L); x++)
  446. fourier_pixels[y*width+x]*=(-1.0);
  447. }
  448. static MagickBooleanType ForwardFourier(const FourierInfo *fourier_info,
  449. Image *image,double *magnitude,double *phase,ExceptionInfo *exception)
  450. {
  451. CacheView
  452. *magnitude_view,
  453. *phase_view;
  454. double
  455. *magnitude_pixels,
  456. *phase_pixels;
  457. Image
  458. *magnitude_image,
  459. *phase_image;
  460. MagickBooleanType
  461. status;
  462. MemoryInfo
  463. *magnitude_info,
  464. *phase_info;
  465. register Quantum
  466. *q;
  467. register ssize_t
  468. x;
  469. ssize_t
  470. i,
  471. y;
  472. magnitude_image=GetFirstImageInList(image);
  473. phase_image=GetNextImageInList(image);
  474. if (phase_image == (Image *) NULL)
  475. {
  476. (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
  477. "ImageSequenceRequired","`%s'",image->filename);
  478. return(MagickFalse);
  479. }
  480. /*
  481. Create "Fourier Transform" image from constituent arrays.
  482. */
  483. magnitude_info=AcquireVirtualMemory((size_t) fourier_info->width,
  484. fourier_info->height*sizeof(*magnitude_pixels));
  485. phase_info=AcquireVirtualMemory((size_t) fourier_info->width,
  486. fourier_info->height*sizeof(*phase_pixels));
  487. if ((magnitude_info == (MemoryInfo *) NULL) ||
  488. (phase_info == (MemoryInfo *) NULL))
  489. {
  490. if (phase_info != (MemoryInfo *) NULL)
  491. phase_info=RelinquishVirtualMemory(phase_info);
  492. if (magnitude_info != (MemoryInfo *) NULL)
  493. magnitude_info=RelinquishVirtualMemory(magnitude_info);
  494. (void) ThrowMagickException(exception,GetMagickModule(),
  495. ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
  496. return(MagickFalse);
  497. }
  498. magnitude_pixels=(double *) GetVirtualMemoryBlob(magnitude_info);
  499. (void) memset(magnitude_pixels,0,fourier_info->width*
  500. fourier_info->height*sizeof(*magnitude_pixels));
  501. phase_pixels=(double *) GetVirtualMemoryBlob(phase_info);
  502. (void) memset(phase_pixels,0,fourier_info->width*
  503. fourier_info->height*sizeof(*phase_pixels));
  504. status=ForwardQuadrantSwap(fourier_info->width,fourier_info->height,
  505. magnitude,magnitude_pixels);
  506. if (status != MagickFalse)
  507. status=ForwardQuadrantSwap(fourier_info->width,fourier_info->height,phase,
  508. phase_pixels);
  509. CorrectPhaseLHS(fourier_info->width,fourier_info->height,phase_pixels);
  510. if (fourier_info->modulus != MagickFalse)
  511. {
  512. i=0L;
  513. for (y=0L; y < (ssize_t) fourier_info->height; y++)
  514. for (x=0L; x < (ssize_t) fourier_info->width; x++)
  515. {
  516. phase_pixels[i]/=(2.0*MagickPI);
  517. phase_pixels[i]+=0.5;
  518. i++;
  519. }
  520. }
  521. magnitude_view=AcquireAuthenticCacheView(magnitude_image,exception);
  522. i=0L;
  523. for (y=0L; y < (ssize_t) fourier_info->height; y++)
  524. {
  525. q=GetCacheViewAuthenticPixels(magnitude_view,0L,y,fourier_info->width,1UL,
  526. exception);
  527. if (q == (Quantum *) NULL)
  528. break;
  529. for (x=0L; x < (ssize_t) fourier_info->width; x++)
  530. {
  531. switch (fourier_info->channel)
  532. {
  533. case RedPixelChannel:
  534. default:
  535. {
  536. SetPixelRed(magnitude_image,ClampToQuantum(QuantumRange*
  537. magnitude_pixels[i]),q);
  538. break;
  539. }
  540. case GreenPixelChannel:
  541. {
  542. SetPixelGreen(magnitude_image,ClampToQuantum(QuantumRange*
  543. magnitude_pixels[i]),q);
  544. break;
  545. }
  546. case BluePixelChannel:
  547. {
  548. SetPixelBlue(magnitude_image,ClampToQuantum(QuantumRange*
  549. magnitude_pixels[i]),q);
  550. break;
  551. }
  552. case BlackPixelChannel:
  553. {
  554. SetPixelBlack(magnitude_image,ClampToQuantum(QuantumRange*
  555. magnitude_pixels[i]),q);
  556. break;
  557. }
  558. case AlphaPixelChannel:
  559. {
  560. SetPixelAlpha(magnitude_image,ClampToQuantum(QuantumRange*
  561. magnitude_pixels[i]),q);
  562. break;
  563. }
  564. }
  565. i++;
  566. q+=GetPixelChannels(magnitude_image);
  567. }
  568. status=SyncCacheViewAuthenticPixels(magnitude_view,exception);
  569. if (status == MagickFalse)
  570. break;
  571. }
  572. magnitude_view=DestroyCacheView(magnitude_view);
  573. i=0L;
  574. phase_view=AcquireAuthenticCacheView(phase_image,exception);
  575. for (y=0L; y < (ssize_t) fourier_info->height; y++)
  576. {
  577. q=GetCacheViewAuthenticPixels(phase_view,0L,y,fourier_info->width,1UL,
  578. exception);
  579. if (q == (Quantum *) NULL)
  580. break;
  581. for (x=0L; x < (ssize_t) fourier_info->width; x++)
  582. {
  583. switch (fourier_info->channel)
  584. {
  585. case RedPixelChannel:
  586. default:
  587. {
  588. SetPixelRed(phase_image,ClampToQuantum(QuantumRange*
  589. phase_pixels[i]),q);
  590. break;
  591. }
  592. case GreenPixelChannel:
  593. {
  594. SetPixelGreen(phase_image,ClampToQuantum(QuantumRange*
  595. phase_pixels[i]),q);
  596. break;
  597. }
  598. case BluePixelChannel:
  599. {
  600. SetPixelBlue(phase_image,ClampToQuantum(QuantumRange*
  601. phase_pixels[i]),q);
  602. break;
  603. }
  604. case BlackPixelChannel:
  605. {
  606. SetPixelBlack(phase_image,ClampToQuantum(QuantumRange*
  607. phase_pixels[i]),q);
  608. break;
  609. }
  610. case AlphaPixelChannel:
  611. {
  612. SetPixelAlpha(phase_image,ClampToQuantum(QuantumRange*
  613. phase_pixels[i]),q);
  614. break;
  615. }
  616. }
  617. i++;
  618. q+=GetPixelChannels(phase_image);
  619. }
  620. status=SyncCacheViewAuthenticPixels(phase_view,exception);
  621. if (status == MagickFalse)
  622. break;
  623. }
  624. phase_view=DestroyCacheView(phase_view);
  625. phase_info=RelinquishVirtualMemory(phase_info);
  626. magnitude_info=RelinquishVirtualMemory(magnitude_info);
  627. return(status);
  628. }
  629. static MagickBooleanType ForwardFourierTransform(FourierInfo *fourier_info,
  630. const Image *image,double *magnitude_pixels,double *phase_pixels,
  631. ExceptionInfo *exception)
  632. {
  633. CacheView
  634. *image_view;
  635. const char
  636. *value;
  637. double
  638. *source_pixels;
  639. fftw_complex
  640. *forward_pixels;
  641. fftw_plan
  642. fftw_r2c_plan;
  643. MemoryInfo
  644. *forward_info,
  645. *source_info;
  646. register const Quantum
  647. *p;
  648. register ssize_t
  649. i,
  650. x;
  651. ssize_t
  652. y;
  653. /*
  654. Generate the forward Fourier transform.
  655. */
  656. source_info=AcquireVirtualMemory((size_t) fourier_info->width,
  657. fourier_info->height*sizeof(*source_pixels));
  658. if (source_info == (MemoryInfo *) NULL)
  659. {
  660. (void) ThrowMagickException(exception,GetMagickModule(),
  661. ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
  662. return(MagickFalse);
  663. }
  664. source_pixels=(double *) GetVirtualMemoryBlob(source_info);
  665. memset(source_pixels,0,fourier_info->width*fourier_info->height*
  666. sizeof(*source_pixels));
  667. i=0L;
  668. image_view=AcquireVirtualCacheView(image,exception);
  669. for (y=0L; y < (ssize_t) fourier_info->height; y++)
  670. {
  671. p=GetCacheViewVirtualPixels(image_view,0L,y,fourier_info->width,1UL,
  672. exception);
  673. if (p == (const Quantum *) NULL)
  674. break;
  675. for (x=0L; x < (ssize_t) fourier_info->width; x++)
  676. {
  677. switch (fourier_info->channel)
  678. {
  679. case RedPixelChannel:
  680. default:
  681. {
  682. source_pixels[i]=QuantumScale*GetPixelRed(image,p);
  683. break;
  684. }
  685. case GreenPixelChannel:
  686. {
  687. source_pixels[i]=QuantumScale*GetPixelGreen(image,p);
  688. break;
  689. }
  690. case BluePixelChannel:
  691. {
  692. source_pixels[i]=QuantumScale*GetPixelBlue(image,p);
  693. break;
  694. }
  695. case BlackPixelChannel:
  696. {
  697. source_pixels[i]=QuantumScale*GetPixelBlack(image,p);
  698. break;
  699. }
  700. case AlphaPixelChannel:
  701. {
  702. source_pixels[i]=QuantumScale*GetPixelAlpha(image,p);
  703. break;
  704. }
  705. }
  706. i++;
  707. p+=GetPixelChannels(image);
  708. }
  709. }
  710. image_view=DestroyCacheView(image_view);
  711. forward_info=AcquireVirtualMemory((size_t) fourier_info->width,
  712. (fourier_info->height/2+1)*sizeof(*forward_pixels));
  713. if (forward_info == (MemoryInfo *) NULL)
  714. {
  715. (void) ThrowMagickException(exception,GetMagickModule(),
  716. ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
  717. source_info=(MemoryInfo *) RelinquishVirtualMemory(source_info);
  718. return(MagickFalse);
  719. }
  720. forward_pixels=(fftw_complex *) GetVirtualMemoryBlob(forward_info);
  721. #if defined(MAGICKCORE_OPENMP_SUPPORT)
  722. #pragma omp critical (MagickCore_ForwardFourierTransform)
  723. #endif
  724. fftw_r2c_plan=fftw_plan_dft_r2c_2d(fourier_info->width,fourier_info->height,
  725. source_pixels,forward_pixels,FFTW_ESTIMATE);
  726. fftw_execute_dft_r2c(fftw_r2c_plan,source_pixels,forward_pixels);
  727. fftw_destroy_plan(fftw_r2c_plan);
  728. source_info=(MemoryInfo *) RelinquishVirtualMemory(source_info);
  729. value=GetImageArtifact(image,"fourier:normalize");
  730. if ((value == (const char *) NULL) || (LocaleCompare(value,"forward") == 0))
  731. {
  732. double
  733. gamma;
  734. /*
  735. Normalize fourier transform.
  736. */
  737. i=0L;
  738. gamma=PerceptibleReciprocal((double) fourier_info->width*
  739. fourier_info->height);
  740. for (y=0L; y < (ssize_t) fourier_info->height; y++)
  741. for (x=0L; x < (ssize_t) fourier_info->center; x++)
  742. {
  743. #if defined(MAGICKCORE_HAVE_COMPLEX_H)
  744. forward_pixels[i]*=gamma;
  745. #else
  746. forward_pixels[i][0]*=gamma;
  747. forward_pixels[i][1]*=gamma;
  748. #endif
  749. i++;
  750. }
  751. }
  752. /*
  753. Generate magnitude and phase (or real and imaginary).
  754. */
  755. i=0L;
  756. if (fourier_info->modulus != MagickFalse)
  757. for (y=0L; y < (ssize_t) fourier_info->height; y++)
  758. for (x=0L; x < (ssize_t) fourier_info->center; x++)
  759. {
  760. magnitude_pixels[i]=cabs(forward_pixels[i]);
  761. phase_pixels[i]=carg(forward_pixels[i]);
  762. i++;
  763. }
  764. else
  765. for (y=0L; y < (ssize_t) fourier_info->height; y++)
  766. for (x=0L; x < (ssize_t) fourier_info->center; x++)
  767. {
  768. magnitude_pixels[i]=creal(forward_pixels[i]);
  769. phase_pixels[i]=cimag(forward_pixels[i]);
  770. i++;
  771. }
  772. forward_info=(MemoryInfo *) RelinquishVirtualMemory(forward_info);
  773. return(MagickTrue);
  774. }
  775. static MagickBooleanType ForwardFourierTransformChannel(const Image *image,
  776. const PixelChannel channel,const MagickBooleanType modulus,
  777. Image *fourier_image,ExceptionInfo *exception)
  778. {
  779. double
  780. *magnitude_pixels,
  781. *phase_pixels;
  782. FourierInfo
  783. fourier_info;
  784. MagickBooleanType
  785. status;
  786. MemoryInfo
  787. *magnitude_info,
  788. *phase_info;
  789. fourier_info.width=image->columns;
  790. fourier_info.height=image->rows;
  791. if ((image->columns != image->rows) || ((image->columns % 2) != 0) ||
  792. ((image->rows % 2) != 0))
  793. {
  794. size_t extent=image->columns < image->rows ? image->rows : image->columns;
  795. fourier_info.width=(extent & 0x01) == 1 ? extent+1UL : extent;
  796. }
  797. fourier_info.height=fourier_info.width;
  798. fourier_info.center=(ssize_t) (fourier_info.width/2L)+1L;
  799. fourier_info.channel=channel;
  800. fourier_info.modulus=modulus;
  801. magnitude_info=AcquireVirtualMemory((size_t) fourier_info.width,
  802. (fourier_info.height/2+1)*sizeof(*magnitude_pixels));
  803. phase_info=AcquireVirtualMemory((size_t) fourier_info.width,
  804. (fourier_info.height/2+1)*sizeof(*phase_pixels));
  805. if ((magnitude_info == (MemoryInfo *) NULL) ||
  806. (phase_info == (MemoryInfo *) NULL))
  807. {
  808. if (phase_info != (MemoryInfo *) NULL)
  809. phase_info=RelinquishVirtualMemory(phase_info);
  810. if (magnitude_info == (MemoryInfo *) NULL)
  811. magnitude_info=RelinquishVirtualMemory(magnitude_info);
  812. (void) ThrowMagickException(exception,GetMagickModule(),
  813. ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
  814. return(MagickFalse);
  815. }
  816. magnitude_pixels=(double *) GetVirtualMemoryBlob(magnitude_info);
  817. phase_pixels=(double *) GetVirtualMemoryBlob(phase_info);
  818. status=ForwardFourierTransform(&fourier_info,image,magnitude_pixels,
  819. phase_pixels,exception);
  820. if (status != MagickFalse)
  821. status=ForwardFourier(&fourier_info,fourier_image,magnitude_pixels,
  822. phase_pixels,exception);
  823. phase_info=RelinquishVirtualMemory(phase_info);
  824. magnitude_info=RelinquishVirtualMemory(magnitude_info);
  825. return(status);
  826. }
  827. #endif
  828. MagickExport Image *ForwardFourierTransformImage(const Image *image,
  829. const MagickBooleanType modulus,ExceptionInfo *exception)
  830. {
  831. Image
  832. *fourier_image;
  833. fourier_image=NewImageList();
  834. #if !defined(MAGICKCORE_FFTW_DELEGATE)
  835. (void) modulus;
  836. (void) ThrowMagickException(exception,GetMagickModule(),
  837. MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","`%s' (FFTW)",
  838. image->filename);
  839. #else
  840. {
  841. Image
  842. *magnitude_image;
  843. size_t
  844. height,
  845. width;
  846. width=image->columns;
  847. height=image->rows;
  848. if ((image->columns != image->rows) || ((image->columns % 2) != 0) ||
  849. ((image->rows % 2) != 0))
  850. {
  851. size_t extent=image->columns < image->rows ? image->rows :
  852. image->columns;
  853. width=(extent & 0x01) == 1 ? extent+1UL : extent;
  854. }
  855. height=width;
  856. magnitude_image=CloneImage(image,width,height,MagickTrue,exception);
  857. if (magnitude_image != (Image *) NULL)
  858. {
  859. Image
  860. *phase_image;
  861. magnitude_image->storage_class=DirectClass;
  862. magnitude_image->depth=32UL;
  863. phase_image=CloneImage(image,width,height,MagickTrue,exception);
  864. if (phase_image == (Image *) NULL)
  865. magnitude_image=DestroyImage(magnitude_image);
  866. else
  867. {
  868. MagickBooleanType
  869. is_gray,
  870. status;
  871. phase_image->storage_class=DirectClass;
  872. phase_image->depth=32UL;
  873. AppendImageToList(&fourier_image,magnitude_image);
  874. AppendImageToList(&fourier_image,phase_image);
  875. status=MagickTrue;
  876. is_gray=IsImageGray(image);
  877. #if defined(MAGICKCORE_OPENMP_SUPPORT)
  878. #pragma omp parallel sections
  879. #endif
  880. {
  881. #if defined(MAGICKCORE_OPENMP_SUPPORT)
  882. #pragma omp section
  883. #endif
  884. {
  885. MagickBooleanType
  886. thread_status;
  887. if (is_gray != MagickFalse)
  888. thread_status=ForwardFourierTransformChannel(image,
  889. GrayPixelChannel,modulus,fourier_image,exception);
  890. else
  891. thread_status=ForwardFourierTransformChannel(image,
  892. RedPixelChannel,modulus,fourier_image,exception);
  893. if (thread_status == MagickFalse)
  894. status=thread_status;
  895. }
  896. #if defined(MAGICKCORE_OPENMP_SUPPORT)
  897. #pragma omp section
  898. #endif
  899. {
  900. MagickBooleanType
  901. thread_status;
  902. thread_status=MagickTrue;
  903. if (is_gray == MagickFalse)
  904. thread_status=ForwardFourierTransformChannel(image,
  905. GreenPixelChannel,modulus,fourier_image,exception);
  906. if (thread_status == MagickFalse)
  907. status=thread_status;
  908. }
  909. #if defined(MAGICKCORE_OPENMP_SUPPORT)
  910. #pragma omp section
  911. #endif
  912. {
  913. MagickBooleanType
  914. thread_status;
  915. thread_status=MagickTrue;
  916. if (is_gray == MagickFalse)
  917. thread_status=ForwardFourierTransformChannel(image,
  918. BluePixelChannel,modulus,fourier_image,exception);
  919. if (thread_status == MagickFalse)
  920. status=thread_status;
  921. }
  922. #if defined(MAGICKCORE_OPENMP_SUPPORT)
  923. #pragma omp section
  924. #endif
  925. {
  926. MagickBooleanType
  927. thread_status;
  928. thread_status=MagickTrue;
  929. if (image->colorspace == CMYKColorspace)
  930. thread_status=ForwardFourierTransformChannel(image,
  931. BlackPixelChannel,modulus,fourier_image,exception);
  932. if (thread_status == MagickFalse)
  933. status=thread_status;
  934. }
  935. #if defined(MAGICKCORE_OPENMP_SUPPORT)
  936. #pragma omp section
  937. #endif
  938. {
  939. MagickBooleanType
  940. thread_status;
  941. thread_status=MagickTrue;
  942. if (image->alpha_trait != UndefinedPixelTrait)
  943. thread_status=ForwardFourierTransformChannel(image,
  944. AlphaPixelChannel,modulus,fourier_image,exception);
  945. if (thread_status == MagickFalse)
  946. status=thread_status;
  947. }
  948. }
  949. if (status == MagickFalse)
  950. fourier_image=DestroyImageList(fourier_image);
  951. fftw_cleanup();
  952. }
  953. }
  954. }
  955. #endif
  956. return(fourier_image);
  957. }
  958. /*
  959. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  960. % %
  961. % %
  962. % %
  963. % 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 %
  964. % %
  965. % %
  966. % %
  967. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  968. %
  969. % InverseFourierTransformImage() implements the inverse discrete Fourier
  970. % transform (DFT) of the image either as a magnitude / phase or real /
  971. % imaginary image pair.
  972. %
  973. % The format of the InverseFourierTransformImage method is:
  974. %
  975. % Image *InverseFourierTransformImage(const Image *magnitude_image,
  976. % const Image *phase_image,const MagickBooleanType modulus,
  977. % ExceptionInfo *exception)
  978. %
  979. % A description of each parameter follows:
  980. %
  981. % o magnitude_image: the magnitude or real image.
  982. %
  983. % o phase_image: the phase or imaginary image.
  984. %
  985. % o modulus: if true, return transform as a magnitude / phase pair
  986. % otherwise a real / imaginary image pair.
  987. %
  988. % o exception: return any errors or warnings in this structure.
  989. %
  990. */
  991. #if defined(MAGICKCORE_FFTW_DELEGATE)
  992. static MagickBooleanType InverseQuadrantSwap(const size_t width,
  993. const size_t height,const double *source,double *destination)
  994. {
  995. register ssize_t
  996. x;
  997. ssize_t
  998. center,
  999. y;
  1000. /*
  1001. Swap quadrants.
  1002. */
  1003. center=(ssize_t) (width/2L)+1L;
  1004. for (y=1L; y < (ssize_t) height; y++)
  1005. for (x=0L; x < (ssize_t) (width/2L+1L); x++)
  1006. destination[(height-y)*center-x+width/2L]=source[y*width+x];
  1007. for (y=0L; y < (ssize_t) height; y++)
  1008. destination[y*center]=source[y*width+width/2L];
  1009. for (x=0L; x < center; x++)
  1010. destination[x]=source[center-x-1L];
  1011. return(RollFourier(center,height,0L,(ssize_t) height/-2L,destination));
  1012. }
  1013. static MagickBooleanType InverseFourier(FourierInfo *fourier_info,
  1014. const Image *magnitude_image,const Image *phase_image,
  1015. fftw_complex *fourier_pixels,ExceptionInfo *exception)
  1016. {
  1017. CacheView
  1018. *magnitude_view,
  1019. *phase_view;
  1020. double
  1021. *inverse_pixels,
  1022. *magnitude_pixels,
  1023. *phase_pixels;
  1024. MagickBooleanType
  1025. status;
  1026. MemoryInfo
  1027. *inverse_info,
  1028. *magnitude_info,
  1029. *phase_info;
  1030. register const Quantum
  1031. *p;
  1032. register ssize_t
  1033. i,
  1034. x;
  1035. ssize_t
  1036. y;
  1037. /*
  1038. Inverse fourier - read image and break down into a double array.
  1039. */
  1040. magnitude_info=AcquireVirtualMemory((size_t) fourier_info->width,
  1041. fourier_info->height*sizeof(*magnitude_pixels));
  1042. phase_info=AcquireVirtualMemory((size_t) fourier_info->width,
  1043. fourier_info->height*sizeof(*phase_pixels));
  1044. inverse_info=AcquireVirtualMemory((size_t) fourier_info->width,
  1045. (fourier_info->height/2+1)*sizeof(*inverse_pixels));
  1046. if ((magnitude_info == (MemoryInfo *) NULL) ||
  1047. (phase_info == (MemoryInfo *) NULL) ||
  1048. (inverse_info == (MemoryInfo *) NULL))
  1049. {
  1050. if (magnitude_info != (MemoryInfo *) NULL)
  1051. magnitude_info=RelinquishVirtualMemory(magnitude_info);
  1052. if (phase_info != (MemoryInfo *) NULL)
  1053. phase_info=RelinquishVirtualMemory(phase_info);
  1054. if (inverse_info != (MemoryInfo *) NULL)
  1055. inverse_info=RelinquishVirtualMemory(inverse_info);
  1056. (void) ThrowMagickException(exception,GetMagickModule(),
  1057. ResourceLimitError,"MemoryAllocationFailed","`%s'",
  1058. magnitude_image->filename);
  1059. return(MagickFalse);
  1060. }
  1061. magnitude_pixels=(double *) GetVirtualMemoryBlob(magnitude_info);
  1062. phase_pixels=(double *) GetVirtualMemoryBlob(phase_info);
  1063. inverse_pixels=(double *) GetVirtualMemoryBlob(inverse_info);
  1064. i=0L;
  1065. magnitude_view=AcquireVirtualCacheView(magnitude_image,exception);
  1066. for (y=0L; y < (ssize_t) fourier_info->height; y++)
  1067. {
  1068. p=GetCacheViewVirtualPixels(magnitude_view,0L,y,fourier_info->width,1UL,
  1069. exception);
  1070. if (p == (const Quantum *) NULL)
  1071. break;
  1072. for (x=0L; x < (ssize_t) fourier_info->width; x++)
  1073. {
  1074. switch (fourier_info->channel)
  1075. {
  1076. case RedPixelChannel:
  1077. default:
  1078. {
  1079. magnitude_pixels[i]=QuantumScale*GetPixelRed(magnitude_image,p);
  1080. break;
  1081. }
  1082. case GreenPixelChannel:
  1083. {
  1084. magnitude_pixels[i]=QuantumScale*GetPixelGreen(magnitude_image,p);
  1085. break;
  1086. }
  1087. case BluePixelChannel:
  1088. {
  1089. magnitude_pixels[i]=QuantumScale*GetPixelBlue(magnitude_image,p);
  1090. break;
  1091. }
  1092. case BlackPixelChannel:
  1093. {
  1094. magnitude_pixels[i]=QuantumScale*GetPixelBlack(magnitude_image,p);
  1095. break;
  1096. }
  1097. case AlphaPixelChannel:
  1098. {
  1099. magnitude_pixels[i]=QuantumScale*GetPixelAlpha(magnitude_image,p);
  1100. break;
  1101. }
  1102. }
  1103. i++;
  1104. p+=GetPixelChannels(magnitude_image);
  1105. }
  1106. }
  1107. magnitude_view=DestroyCacheView(magnitude_view);
  1108. status=InverseQuadrantSwap(fourier_info->width,fourier_info->height,
  1109. magnitude_pixels,inverse_pixels);
  1110. (void) memcpy(magnitude_pixels,inverse_pixels,fourier_info->height*
  1111. fourier_info->center*sizeof(*magnitude_pixels));
  1112. i=0L;
  1113. phase_view=AcquireVirtualCacheView(phase_image,exception);
  1114. for (y=0L; y < (ssize_t) fourier_info->height; y++)
  1115. {
  1116. p=GetCacheViewVirtualPixels(phase_view,0,y,fourier_info->width,1,
  1117. exception);
  1118. if (p == (const Quantum *) NULL)
  1119. break;
  1120. for (x=0L; x < (ssize_t) fourier_info->width; x++)
  1121. {
  1122. switch (fourier_info->channel)
  1123. {
  1124. case RedPixelChannel:
  1125. default:
  1126. {
  1127. phase_pixels[i]=QuantumScale*GetPixelRed(phase_image,p);
  1128. break;
  1129. }
  1130. case GreenPixelChannel:
  1131. {
  1132. phase_pixels[i]=QuantumScale*GetPixelGreen(phase_image,p);
  1133. break;
  1134. }
  1135. case BluePixelChannel:
  1136. {
  1137. phase_pixels[i]=QuantumScale*GetPixelBlue(phase_image,p);
  1138. break;
  1139. }
  1140. case BlackPixelChannel:
  1141. {
  1142. phase_pixels[i]=QuantumScale*GetPixelBlack(phase_image,p);
  1143. break;
  1144. }
  1145. case AlphaPixelChannel:
  1146. {
  1147. phase_pixels[i]=QuantumScale*GetPixelAlpha(phase_image,p);
  1148. break;
  1149. }
  1150. }
  1151. i++;
  1152. p+=GetPixelChannels(phase_image);
  1153. }
  1154. }
  1155. if (fourier_info->modulus != MagickFalse)
  1156. {
  1157. i=0L;
  1158. for (y=0L; y < (ssize_t) fourier_info->height; y++)
  1159. for (x=0L; x < (ssize_t) fourier_info->width; x++)
  1160. {
  1161. phase_pixels[i]-=0.5;
  1162. phase_pixels[i]*=(2.0*MagickPI);
  1163. i++;
  1164. }
  1165. }
  1166. phase_view=DestroyCacheView(phase_view);
  1167. CorrectPhaseLHS(fourier_info->width,fourier_info->height,phase_pixels);
  1168. if (status != MagickFalse)
  1169. status=InverseQuadrantSwap(fourier_info->width,fourier_info->height,
  1170. phase_pixels,inverse_pixels);
  1171. (void) memcpy(phase_pixels,inverse_pixels,fourier_info->height*
  1172. fourier_info->center*sizeof(*phase_pixels));
  1173. inverse_info=RelinquishVirtualMemory(inverse_info);
  1174. /*
  1175. Merge two sets.
  1176. */
  1177. i=0L;
  1178. if (fourier_info->modulus != MagickFalse)
  1179. for (y=0L; y < (ssize_t) fourier_info->height; y++)
  1180. for (x=0L; x < (ssize_t) fourier_info->center; x++)
  1181. {
  1182. #if defined(MAGICKCORE_HAVE_COMPLEX_H)
  1183. fourier_pixels[i]=magnitude_pixels[i]*cos(phase_pixels[i])+I*
  1184. magnitude_pixels[i]*sin(phase_pixels[i]);
  1185. #else
  1186. fourier_pixels[i][0]=magnitude_pixels[i]*cos(phase_pixels[i]);
  1187. fourier_pixels[i][1]=magnitude_pixels[i]*sin(phase_pixels[i]);
  1188. #endif
  1189. i++;
  1190. }
  1191. else
  1192. for (y=0L; y < (ssize_t) fourier_info->height; y++)
  1193. for (x=0L; x < (ssize_t) fourier_info->center; x++)
  1194. {
  1195. #if defined(MAGICKCORE_HAVE_COMPLEX_H)
  1196. fourier_pixels[i]=magnitude_pixels[i]+I*phase_pixels[i];
  1197. #else
  1198. fourier_pixels[i][0]=magnitude_pixels[i];
  1199. fourier_pixels[i][1]=phase_pixels[i];
  1200. #endif
  1201. i++;
  1202. }
  1203. magnitude_info=RelinquishVirtualMemory(magnitude_info);
  1204. phase_info=RelinquishVirtualMemory(phase_info);
  1205. return(status);
  1206. }
  1207. static MagickBooleanType InverseFourierTransform(FourierInfo *fourier_info,
  1208. fftw_complex *fourier_pixels,Image *image,ExceptionInfo *exception)
  1209. {
  1210. CacheView
  1211. *image_view;
  1212. const char
  1213. *value;
  1214. double
  1215. *source_pixels;
  1216. fftw_plan
  1217. fftw_c2r_plan;
  1218. MemoryInfo
  1219. *source_info;
  1220. register Quantum
  1221. *q;
  1222. register ssize_t
  1223. i,
  1224. x;
  1225. ssize_t
  1226. y;
  1227. source_info=AcquireVirtualMemory((size_t) fourier_info->width,
  1228. fourier_info->height*sizeof(*source_pixels));
  1229. if (source_info == (MemoryInfo *) NULL)
  1230. {
  1231. (void) ThrowMagickException(exception,GetMagickModule(),
  1232. ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
  1233. return(MagickFalse);
  1234. }
  1235. source_pixels=(double *) GetVirtualMemoryBlob(source_info);
  1236. value=GetImageArtifact(image,"fourier:normalize");
  1237. if (LocaleCompare(value,"inverse") == 0)
  1238. {
  1239. double
  1240. gamma;
  1241. /*
  1242. Normalize inverse transform.
  1243. */
  1244. i=0L;
  1245. gamma=PerceptibleReciprocal((double) fourier_info->width*
  1246. fourier_info->height);
  1247. for (y=0L; y < (ssize_t) fourier_info->height; y++)
  1248. for (x=0L; x < (ssize_t) fourier_info->center; x++)
  1249. {
  1250. #if defined(MAGICKCORE_HAVE_COMPLEX_H)
  1251. fourier_pixels[i]*=gamma;
  1252. #else
  1253. fourier_pixels[i][0]*=gamma;
  1254. fourier_pixels[i][1]*=gamma;
  1255. #endif
  1256. i++;
  1257. }
  1258. }
  1259. #if defined(MAGICKCORE_OPENMP_SUPPORT)
  1260. #pragma omp critical (MagickCore_InverseFourierTransform)
  1261. #endif
  1262. fftw_c2r_plan=fftw_plan_dft_c2r_2d(fourier_info->width,fourier_info->height,
  1263. fourier_pixels,source_pixels,FFTW_ESTIMATE);
  1264. fftw_execute_dft_c2r(fftw_c2r_plan,fourier_pixels,source_pixels);
  1265. fftw_destroy_plan(fftw_c2r_plan);
  1266. i=0L;
  1267. image_view=AcquireAuthenticCacheView(image,exception);
  1268. for (y=0L; y < (ssize_t) fourier_info->height; y++)
  1269. {
  1270. if (y >= (ssize_t) image->rows)
  1271. break;
  1272. q=GetCacheViewAuthenticPixels(image_view,0L,y,fourier_info->width >
  1273. image->columns ? image->columns : fourier_info->width,1UL,exception);
  1274. if (q == (Quantum *) NULL)
  1275. break;
  1276. for (x=0L; x < (ssize_t) fourier_info->width; x++)
  1277. {
  1278. if (x < (ssize_t) image->columns)
  1279. switch (fourier_info->channel)
  1280. {
  1281. case RedPixelChannel:
  1282. default:
  1283. {
  1284. SetPixelRed(image,ClampToQuantum(QuantumRange*source_pixels[i]),q);
  1285. break;
  1286. }
  1287. case GreenPixelChannel:
  1288. {
  1289. SetPixelGreen(image,ClampToQuantum(QuantumRange*source_pixels[i]),
  1290. q);
  1291. break;
  1292. }
  1293. case BluePixelChannel:
  1294. {
  1295. SetPixelBlue(image,ClampToQuantum(QuantumRange*source_pixels[i]),
  1296. q);
  1297. break;
  1298. }
  1299. case BlackPixelChannel:
  1300. {
  1301. SetPixelBlack(image,ClampToQuantum(QuantumRange*source_pixels[i]),
  1302. q);
  1303. break;
  1304. }
  1305. case AlphaPixelChannel:
  1306. {
  1307. SetPixelAlpha(image,ClampToQuantum(QuantumRange*source_pixels[i]),
  1308. q);
  1309. break;
  1310. }
  1311. }
  1312. i++;
  1313. q+=GetPixelChannels(image);
  1314. }
  1315. if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
  1316. break;
  1317. }
  1318. image_view=DestroyCacheView(image_view);
  1319. source_info=RelinquishVirtualMemory(source_info);
  1320. return(MagickTrue);
  1321. }
  1322. static MagickBooleanType InverseFourierTransformChannel(
  1323. const Image *magnitude_image,const Image *phase_image,
  1324. const PixelChannel channel,const MagickBooleanType modulus,
  1325. Image *fourier_image,ExceptionInfo *exception)
  1326. {
  1327. fftw_complex
  1328. *inverse_pixels;
  1329. FourierInfo
  1330. fourier_info;
  1331. MagickBooleanType
  1332. status;
  1333. MemoryInfo
  1334. *inverse_info;
  1335. fourier_info.width=magnitude_image->columns;
  1336. fourier_info.height=magnitude_image->rows;
  1337. if ((magnitude_image->columns != magnitude_image->rows) ||
  1338. ((magnitude_image->columns % 2) != 0) ||
  1339. ((magnitude_image->rows % 2) != 0))
  1340. {
  1341. size_t extent=magnitude_image->columns < magnitude_image->rows ?
  1342. magnitude_image->rows : magnitude_image->columns;
  1343. fourier_info.width=(extent & 0x01) == 1 ? extent+1UL : extent;
  1344. }
  1345. fourier_info.height=fourier_info.width;
  1346. fourier_info.center=(ssize_t) (fourier_info.width/2L)+1L;
  1347. fourier_info.channel=channel;
  1348. fourier_info.modulus=modulus;
  1349. inverse_info=AcquireVirtualMemory((size_t) fourier_info.width,
  1350. (fourier_info.height/2+1)*sizeof(*inverse_pixels));
  1351. if (inverse_info == (MemoryInfo *) NULL)
  1352. {
  1353. (void) ThrowMagickException(exception,GetMagickModule(),
  1354. ResourceLimitError,"MemoryAllocationFailed","`%s'",
  1355. magnitude_image->filename);
  1356. return(MagickFalse);
  1357. }
  1358. inverse_pixels=(fftw_complex *) GetVirtualMemoryBlob(inverse_info);
  1359. status=InverseFourier(&fourier_info,magnitude_image,phase_image,
  1360. inverse_pixels,exception);
  1361. if (status != MagickFalse)
  1362. status=InverseFourierTransform(&fourier_info,inverse_pixels,fourier_image,
  1363. exception);
  1364. inverse_info=RelinquishVirtualMemory(inverse_info);
  1365. return(status);
  1366. }
  1367. #endif
  1368. MagickExport Image *InverseFourierTransformImage(const Image *magnitude_image,
  1369. const Image *phase_image,const MagickBooleanType modulus,
  1370. ExceptionInfo *exception)
  1371. {
  1372. Image
  1373. *fourier_image;
  1374. assert(magnitude_image != (Image *) NULL);
  1375. assert(magnitude_image->signature == MagickCoreSignature);
  1376. if (magnitude_image->debug != MagickFalse)
  1377. (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
  1378. magnitude_image->filename);
  1379. if (phase_image == (Image *) NULL)
  1380. {
  1381. (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
  1382. "ImageSequenceRequired","`%s'",magnitude_image->filename);
  1383. return((Image *) NULL);
  1384. }
  1385. #if !defined(MAGICKCORE_FFTW_DELEGATE)
  1386. fourier_image=(Image *) NULL;
  1387. (void) modulus;
  1388. (void) ThrowMagickException(exception,GetMagickModule(),
  1389. MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","`%s' (FFTW)",
  1390. magnitude_image->filename);
  1391. #else
  1392. {
  1393. fourier_image=CloneImage(magnitude_image,magnitude_image->columns,
  1394. magnitude_image->rows,MagickTrue,exception);
  1395. if (fourier_image != (Image *) NULL)
  1396. {
  1397. MagickBooleanType
  1398. is_gray,
  1399. status;
  1400. status=MagickTrue;
  1401. is_gray=IsImageGray(magnitude_image);
  1402. if (is_gray != MagickFalse)
  1403. is_gray=IsImageGray(phase_image);
  1404. #if defined(MAGICKCORE_OPENMP_SUPPORT)
  1405. #pragma omp parallel sections
  1406. #endif
  1407. {
  1408. #if defined(MAGICKCORE_OPENMP_SUPPORT)
  1409. #pragma omp section
  1410. #endif
  1411. {
  1412. MagickBooleanType
  1413. thread_status;
  1414. if (is_gray != MagickFalse)
  1415. thread_status=InverseFourierTransformChannel(magnitude_image,
  1416. phase_image,GrayPixelChannel,modulus,fourier_image,exception);
  1417. else
  1418. thread_status=InverseFourierTransformChannel(magnitude_image,
  1419. phase_image,RedPixelChannel,modulus,fourier_image,exception);
  1420. if (thread_status == MagickFalse)
  1421. status=thread_status;
  1422. }
  1423. #if defined(MAGICKCORE_OPENMP_SUPPORT)
  1424. #pragma omp section
  1425. #endif
  1426. {
  1427. MagickBooleanType
  1428. thread_status;
  1429. thread_status=MagickTrue;
  1430. if (is_gray == MagickFalse)
  1431. thread_status=InverseFourierTransformChannel(magnitude_image,
  1432. phase_image,GreenPixelChannel,modulus,fourier_image,exception);
  1433. if (thread_status == MagickFalse)
  1434. status=thread_status;
  1435. }
  1436. #if defined(MAGICKCORE_OPENMP_SUPPORT)
  1437. #pragma omp section
  1438. #endif
  1439. {
  1440. MagickBooleanType
  1441. thread_status;
  1442. thread_status=MagickTrue;
  1443. if (is_gray == MagickFalse)
  1444. thread_status=InverseFourierTransformChannel(magnitude_image,
  1445. phase_image,BluePixelChannel,modulus,fourier_image,exception);
  1446. if (thread_status == MagickFalse)
  1447. status=thread_status;
  1448. }
  1449. #if defined(MAGICKCORE_OPENMP_SUPPORT)
  1450. #pragma omp section
  1451. #endif
  1452. {
  1453. MagickBooleanType
  1454. thread_status;
  1455. thread_status=MagickTrue;
  1456. if (magnitude_image->colorspace == CMYKColorspace)
  1457. thread_status=InverseFourierTransformChannel(magnitude_image,
  1458. phase_image,BlackPixelChannel,modulus,fourier_image,exception);
  1459. if (thread_status == MagickFalse)
  1460. status=thread_status;
  1461. }
  1462. #if defined(MAGICKCORE_OPENMP_SUPPORT)
  1463. #pragma omp section
  1464. #endif
  1465. {
  1466. MagickBooleanType
  1467. thread_status;
  1468. thread_status=MagickTrue;
  1469. if (magnitude_image->alpha_trait != UndefinedPixelTrait)
  1470. thread_status=InverseFourierTransformChannel(magnitude_image,
  1471. phase_image,AlphaPixelChannel,modulus,fourier_image,exception);
  1472. if (thread_status == MagickFalse)
  1473. status=thread_status;
  1474. }
  1475. }
  1476. if (status == MagickFalse)
  1477. fourier_image=DestroyImage(fourier_image);
  1478. }
  1479. fftw_cleanup();
  1480. }
  1481. #endif
  1482. return(fourier_image);
  1483. }