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