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