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