X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=MagickCore%2Feffect.c;h=d873bc8351bf4b20fb93747f07d29dc1d0424524;hb=45ef08fd6a09813e4a8f5ddadf85ba9e0ec2cdc7;hp=deb7d5290c7eff1a54a53d68516dd259866fda63;hpb=9950d57e1124b73f684fb5946e206994cefda628;p=imagemagick diff --git a/MagickCore/effect.c b/MagickCore/effect.c index deb7d5290..d873bc835 100644 --- a/MagickCore/effect.c +++ b/MagickCore/effect.c @@ -17,7 +17,7 @@ % October 1996 % % % % % -% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization % +% Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization % % dedicated to making software imaging solutions freely available. % % % % You may not use this file except in compliance with the License. You may % @@ -49,6 +49,7 @@ #include "MagickCore/colorspace.h" #include "MagickCore/constitute.h" #include "MagickCore/decorate.h" +#include "MagickCore/distort.h" #include "MagickCore/draw.h" #include "MagickCore/enhance.h" #include "MagickCore/exception.h" @@ -62,12 +63,14 @@ #include "MagickCore/list.h" #include "MagickCore/log.h" #include "MagickCore/memory_.h" +#include "MagickCore/memory-private.h" #include "MagickCore/monitor.h" #include "MagickCore/monitor-private.h" #include "MagickCore/montage.h" #include "MagickCore/morphology.h" #include "MagickCore/paint.h" #include "MagickCore/pixel-accessor.h" +#include "MagickCore/pixel-private.h" #include "MagickCore/property.h" #include "MagickCore/quantize.h" #include "MagickCore/quantum.h" @@ -81,6 +84,7 @@ #include "MagickCore/segment.h" #include "MagickCore/shear.h" #include "MagickCore/signature-private.h" +#include "MagickCore/statistic.h" #include "MagickCore/string_.h" #include "MagickCore/thread-private.h" #include "MagickCore/transform.h" @@ -106,7 +110,7 @@ % The format of the AdaptiveBlurImage method is: % % Image *AdaptiveBlurImage(const Image *image,const double radius, -% const double sigma,const double bias,ExceptionInfo *exception) +% const double sigma,ExceptionInfo *exception) % % A description of each parameter follows: % @@ -117,8 +121,6 @@ % % o sigma: the standard deviation of the Laplacian, in pixels. % -% o bias: the bias. -% % o exception: return any errors or warnings in this structure. % */ @@ -167,12 +169,11 @@ MagickExport MagickBooleanType AdaptiveLevelImage(Image *image, return(status); } -MagickExport Image *AdaptiveBlurImage(const Image *image, - const double radius,const double sigma,const double bias, - ExceptionInfo *exception) +MagickExport Image *AdaptiveBlurImage(const Image *image,const double radius, + const double sigma,ExceptionInfo *exception) { #define AdaptiveBlurImageTag "Convolve/Image" -#define MagickSigma (fabs(sigma) <= MagickEpsilon ? 1.0 : sigma) +#define MagickSigma (fabs(sigma) < MagickEpsilon ? MagickEpsilon : sigma) CacheView *blur_view, @@ -180,7 +181,6 @@ MagickExport Image *AdaptiveBlurImage(const Image *image, *image_view; double - **kernel, normalize; Image @@ -194,6 +194,9 @@ MagickExport Image *AdaptiveBlurImage(const Image *image, MagickOffsetType progress; + MagickRealType + **kernel; + register ssize_t i; @@ -216,7 +219,7 @@ MagickExport Image *AdaptiveBlurImage(const Image *image, blur_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception); if (blur_image == (Image *) NULL) return((Image *) NULL); - if (fabs(sigma) <= MagickEpsilon) + if (fabs(sigma) < MagickEpsilon) return(blur_image); if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse) { @@ -233,7 +236,7 @@ MagickExport Image *AdaptiveBlurImage(const Image *image, return((Image *) NULL); } (void) AdaptiveLevelImage(edge_image,"20%,95%",exception); - gaussian_image=GaussianBlurImage(edge_image,radius,sigma,bias,exception); + gaussian_image=GaussianBlurImage(edge_image,radius,sigma,exception); if (gaussian_image != (Image *) NULL) { edge_image=DestroyImage(edge_image); @@ -244,8 +247,9 @@ MagickExport Image *AdaptiveBlurImage(const Image *image, Create a set of kernels from maximum (radius,sigma) to minimum. */ width=GetOptimalKernelWidth2D(radius,sigma); - kernel=(double **) AcquireQuantumMemory((size_t) width,sizeof(*kernel)); - if (kernel == (double **) NULL) + kernel=(MagickRealType **) MagickAssumeAligned(AcquireAlignedMemory((size_t) + width,sizeof(*kernel))); + if (kernel == (MagickRealType **) NULL) { edge_image=DestroyImage(edge_image); blur_image=DestroyImage(blur_image); @@ -254,9 +258,9 @@ MagickExport Image *AdaptiveBlurImage(const Image *image, (void) ResetMagickMemory(kernel,0,(size_t) width*sizeof(*kernel)); for (i=0; i < (ssize_t) width; i+=2) { - kernel[i]=(double *) AcquireQuantumMemory((size_t) (width-i),(width-i)* - sizeof(**kernel)); - if (kernel[i] == (double *) NULL) + kernel[i]=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory( + (size_t) (width-i),(width-i)*sizeof(**kernel))); + if (kernel[i] == (MagickRealType *) NULL) break; normalize=0.0; j=(ssize_t) (width-i)/2; @@ -265,23 +269,23 @@ MagickExport Image *AdaptiveBlurImage(const Image *image, { for (u=(-j); u <= j; u++) { - kernel[i][k]=(double) (exp(-((double) u*u+v*v)/(2.0*MagickSigma* + kernel[i][k]=(MagickRealType) (exp(-((double) u*u+v*v)/(2.0*MagickSigma* MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma)); normalize+=kernel[i][k]; k++; } } - if (fabs(normalize) <= MagickEpsilon) - normalize=1.0; - normalize=1.0/normalize; + if (fabs(normalize) < MagickEpsilon) + normalize=MagickEpsilon; + normalize=PerceptibleReciprocal(normalize); for (k=0; k < (j*j); k++) kernel[i][k]=normalize*kernel[i][k]; } if (i < (ssize_t) width) { for (i-=2; i >= 0; i-=2) - kernel[i]=(double *) RelinquishMagickMemory(kernel[i]); - kernel=(double **) RelinquishMagickMemory(kernel); + kernel[i]=(MagickRealType *) RelinquishAlignedMemory(kernel[i]); + kernel=(MagickRealType **) RelinquishAlignedMemory(kernel); edge_image=DestroyImage(edge_image); blur_image=DestroyImage(blur_image); ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); @@ -291,11 +295,12 @@ MagickExport Image *AdaptiveBlurImage(const Image *image, */ status=MagickTrue; progress=0; - image_view=AcquireCacheView(image); - edge_view=AcquireCacheView(edge_image); - blur_view=AcquireCacheView(blur_image); + image_view=AcquireVirtualCacheView(image,exception); + edge_view=AcquireVirtualCacheView(edge_image,exception); + blur_view=AcquireAuthenticCacheView(blur_image,exception); #if defined(MAGICKCORE_OPENMP_SUPPORT) - #pragma omp parallel for schedule(dynamic,4) shared(progress,status) + #pragma omp parallel for schedule(static,4) shared(progress,status) \ + dynamic_number_threads(image,image->columns,image->rows,1) #endif for (y=0; y < (ssize_t) blur_image->rows; y++) { @@ -343,11 +348,11 @@ MagickExport Image *AdaptiveBlurImage(const Image *image, (ssize_t) ((width-j)/2L),width-j,width-j,exception); if (p == (const Quantum *) NULL) break; - center=(ssize_t) GetPixelChannels(image)*(width-j)* - ((width-j)/2L)+GetPixelChannels(image)*((width-j)/2L); + center=(ssize_t) GetPixelChannels(image)*(width-j)*((width-j)/2L)+ + GetPixelChannels(image)*((width-j)/2L); for (i=0; i < (ssize_t) GetPixelChannels(image); i++) { - MagickRealType + double alpha, gamma, pixel; @@ -359,7 +364,7 @@ MagickExport Image *AdaptiveBlurImage(const Image *image, blur_traits, traits; - register const double + register const MagickRealType *restrict k; register const Quantum @@ -371,20 +376,21 @@ MagickExport Image *AdaptiveBlurImage(const Image *image, ssize_t v; - traits=GetPixelChannelMapTraits(image,(PixelChannel) i); - channel=GetPixelChannelMapChannel(image,(PixelChannel) i); - blur_traits=GetPixelChannelMapTraits(blur_image,channel); + channel=GetPixelChannelChannel(image,i); + traits=GetPixelChannelTraits(image,channel); + blur_traits=GetPixelChannelTraits(blur_image,channel); if ((traits == UndefinedPixelTrait) || (blur_traits == UndefinedPixelTrait)) continue; - if ((blur_traits & CopyPixelTrait) != 0) + if (((blur_traits & CopyPixelTrait) != 0) || + (GetPixelMask(image,p) != 0)) { SetPixelChannel(blur_image,channel,p[center+i],q); continue; } k=kernel[j]; pixels=p; - pixel=bias; + pixel=0.0; gamma=0.0; if ((blur_traits & BlendPixelTrait) == 0) { @@ -401,7 +407,7 @@ MagickExport Image *AdaptiveBlurImage(const Image *image, pixels+=GetPixelChannels(image); } } - gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma); + gamma=PerceptibleReciprocal(gamma); SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q); continue; } @@ -412,14 +418,14 @@ MagickExport Image *AdaptiveBlurImage(const Image *image, { for (u=0; u < (ssize_t) (width-j); u++) { - alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(image,pixels)); + alpha=(double) (QuantumScale*GetPixelAlpha(image,pixels)); pixel+=(*k)*alpha*pixels[i]; gamma+=(*k)*alpha; k++; pixels+=GetPixelChannels(image); } } - gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma); + gamma=PerceptibleReciprocal(gamma); SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q); } q+=GetPixelChannels(blur_image); @@ -433,7 +439,7 @@ MagickExport Image *AdaptiveBlurImage(const Image *image, proceed; #if defined(MAGICKCORE_OPENMP_SUPPORT) - #pragma omp critical (MagickCore_AdaptiveBlurImage) + #pragma omp critical (MagickCore_AdaptiveBlurImage) #endif proceed=SetImageProgress(image,AdaptiveBlurImageTag,progress++, image->rows); @@ -447,8 +453,8 @@ MagickExport Image *AdaptiveBlurImage(const Image *image, image_view=DestroyCacheView(image_view); edge_image=DestroyImage(edge_image); for (i=0; i < (ssize_t) width; i+=2) - kernel[i]=(double *) RelinquishMagickMemory(kernel[i]); - kernel=(double **) RelinquishMagickMemory(kernel); + kernel[i]=(MagickRealType *) RelinquishAlignedMemory(kernel[i]); + kernel=(MagickRealType **) RelinquishAlignedMemory(kernel); if (status == MagickFalse) blur_image=DestroyImage(blur_image); return(blur_image); @@ -474,7 +480,7 @@ MagickExport Image *AdaptiveBlurImage(const Image *image, % The format of the AdaptiveSharpenImage method is: % % Image *AdaptiveSharpenImage(const Image *image,const double radius, -% const double sigma,const double bias,ExceptionInfo *exception) +% const double sigma,ExceptionInfo *exception) % % A description of each parameter follows: % @@ -485,16 +491,14 @@ MagickExport Image *AdaptiveBlurImage(const Image *image, % % o sigma: the standard deviation of the Laplacian, in pixels. % -% o bias: the bias. -% % o exception: return any errors or warnings in this structure. % */ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius, - const double sigma,const double bias,ExceptionInfo *exception) + const double sigma,ExceptionInfo *exception) { #define AdaptiveSharpenImageTag "Convolve/Image" -#define MagickSigma (fabs(sigma) <= MagickEpsilon ? 1.0 : sigma) +#define MagickSigma (fabs(sigma) < MagickEpsilon ? MagickEpsilon : sigma) CacheView *sharp_view, @@ -502,7 +506,6 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius, *image_view; double - **kernel, normalize; Image @@ -516,6 +519,9 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius, MagickOffsetType progress; + MagickRealType + **kernel; + register ssize_t i; @@ -538,7 +544,7 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius, sharp_image=CloneImage(image,0,0,MagickTrue,exception); if (sharp_image == (Image *) NULL) return((Image *) NULL); - if (fabs(sigma) <= MagickEpsilon) + if (fabs(sigma) < MagickEpsilon) return(sharp_image); if (SetImageStorageClass(sharp_image,DirectClass,exception) == MagickFalse) { @@ -555,7 +561,7 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius, return((Image *) NULL); } (void) AdaptiveLevelImage(edge_image,"20%,95%",exception); - gaussian_image=GaussianBlurImage(edge_image,radius,sigma,bias,exception); + gaussian_image=GaussianBlurImage(edge_image,radius,sigma,exception); if (gaussian_image != (Image *) NULL) { edge_image=DestroyImage(edge_image); @@ -566,8 +572,9 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius, Create a set of kernels from maximum (radius,sigma) to minimum. */ width=GetOptimalKernelWidth2D(radius,sigma); - kernel=(double **) AcquireQuantumMemory((size_t) width,sizeof(*kernel)); - if (kernel == (double **) NULL) + kernel=(MagickRealType **) MagickAssumeAligned(AcquireAlignedMemory((size_t) + width,sizeof(*kernel))); + if (kernel == (MagickRealType **) NULL) { edge_image=DestroyImage(edge_image); sharp_image=DestroyImage(sharp_image); @@ -576,9 +583,9 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius, (void) ResetMagickMemory(kernel,0,(size_t) width*sizeof(*kernel)); for (i=0; i < (ssize_t) width; i+=2) { - kernel[i]=(double *) AcquireQuantumMemory((size_t) (width-i),(width-i)* - sizeof(**kernel)); - if (kernel[i] == (double *) NULL) + kernel[i]=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory( + (size_t) (width-i),(width-i)*sizeof(**kernel))); + if (kernel[i] == (MagickRealType *) NULL) break; normalize=0.0; j=(ssize_t) (width-i)/2; @@ -587,23 +594,23 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius, { for (u=(-j); u <= j; u++) { - kernel[i][k]=(double) (-exp(-((double) u*u+v*v)/(2.0*MagickSigma* - MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma)); + kernel[i][k]=(MagickRealType) (-exp(-((double) u*u+v*v)/(2.0* + MagickSigma*MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma)); normalize+=kernel[i][k]; k++; } } - if (fabs(normalize) <= MagickEpsilon) - normalize=1.0; - normalize=1.0/normalize; + if (fabs(normalize) < MagickEpsilon) + normalize=MagickEpsilon; + normalize=PerceptibleReciprocal(normalize); for (k=0; k < (j*j); k++) kernel[i][k]=normalize*kernel[i][k]; } if (i < (ssize_t) width) { for (i-=2; i >= 0; i-=2) - kernel[i]=(double *) RelinquishMagickMemory(kernel[i]); - kernel=(double **) RelinquishMagickMemory(kernel); + kernel[i]=(MagickRealType *) RelinquishAlignedMemory(kernel[i]); + kernel=(MagickRealType **) RelinquishAlignedMemory(kernel); edge_image=DestroyImage(edge_image); sharp_image=DestroyImage(sharp_image); ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); @@ -613,11 +620,12 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius, */ status=MagickTrue; progress=0; - image_view=AcquireCacheView(image); - edge_view=AcquireCacheView(edge_image); - sharp_view=AcquireCacheView(sharp_image); + image_view=AcquireVirtualCacheView(image,exception); + edge_view=AcquireVirtualCacheView(edge_image,exception); + sharp_view=AcquireAuthenticCacheView(sharp_image,exception); #if defined(MAGICKCORE_OPENMP_SUPPORT) - #pragma omp parallel for schedule(dynamic,4) shared(progress,status) + #pragma omp parallel for schedule(static,4) shared(progress,status) \ + dynamic_number_threads(image,image->columns,image->rows,1) #endif for (y=0; y < (ssize_t) sharp_image->rows; y++) { @@ -665,11 +673,11 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius, (ssize_t) ((width-j)/2L),width-j,width-j,exception); if (p == (const Quantum *) NULL) break; - center=(ssize_t) GetPixelChannels(image)*(width-j)* - ((width-j)/2L)+GetPixelChannels(image)*((width-j)/2); - for (i=0; i < (ssize_t) GetPixelChannels(image); i++) + center=(ssize_t) GetPixelChannels(image)*(width-j)*((width-j)/2L)+ + GetPixelChannels(image)*((width-j)/2); + for (i=0; i < (ssize_t) GetPixelChannels(sharp_image); i++) { - MagickRealType + double alpha, gamma, pixel; @@ -681,7 +689,7 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius, sharp_traits, traits; - register const double + register const MagickRealType *restrict k; register const Quantum @@ -693,20 +701,21 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius, ssize_t v; - traits=GetPixelChannelMapTraits(image,(PixelChannel) i); - channel=GetPixelChannelMapChannel(image,(PixelChannel) i); - sharp_traits=GetPixelChannelMapTraits(sharp_image,channel); + channel=GetPixelChannelChannel(image,i); + traits=GetPixelChannelTraits(image,channel); + sharp_traits=GetPixelChannelTraits(sharp_image,channel); if ((traits == UndefinedPixelTrait) || (sharp_traits == UndefinedPixelTrait)) continue; - if ((sharp_traits & CopyPixelTrait) != 0) + if (((sharp_traits & CopyPixelTrait) != 0) || + (GetPixelMask(image,p) != 0)) { SetPixelChannel(sharp_image,channel,p[center+i],q); continue; } k=kernel[j]; pixels=p; - pixel=bias; + pixel=0.0; gamma=0.0; if ((sharp_traits & BlendPixelTrait) == 0) { @@ -723,7 +732,7 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius, pixels+=GetPixelChannels(image); } } - gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma); + gamma=PerceptibleReciprocal(gamma); SetPixelChannel(sharp_image,channel,ClampToQuantum(gamma*pixel),q); continue; } @@ -734,14 +743,14 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius, { for (u=0; u < (ssize_t) (width-j); u++) { - alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(image,pixels)); + alpha=(double) (QuantumScale*GetPixelAlpha(image,pixels)); pixel+=(*k)*alpha*pixels[i]; gamma+=(*k)*alpha; k++; pixels+=GetPixelChannels(image); } } - gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma); + gamma=PerceptibleReciprocal(gamma); SetPixelChannel(sharp_image,channel,ClampToQuantum(gamma*pixel),q); } q+=GetPixelChannels(sharp_image); @@ -755,7 +764,7 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius, proceed; #if defined(MAGICKCORE_OPENMP_SUPPORT) - #pragma omp critical (MagickCore_AdaptiveSharpenImage) + #pragma omp critical (MagickCore_AdaptiveSharpenImage) #endif proceed=SetImageProgress(image,AdaptiveSharpenImageTag,progress++, image->rows); @@ -769,8 +778,8 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius, image_view=DestroyCacheView(image_view); edge_image=DestroyImage(edge_image); for (i=0; i < (ssize_t) width; i+=2) - kernel[i]=(double *) RelinquishMagickMemory(kernel[i]); - kernel=(double **) RelinquishMagickMemory(kernel); + kernel[i]=(MagickRealType *) RelinquishAlignedMemory(kernel[i]); + kernel=(MagickRealType **) RelinquishAlignedMemory(kernel); if (status == MagickFalse) sharp_image=DestroyImage(sharp_image); return(sharp_image); @@ -799,7 +808,7 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius, % The format of the BlurImage method is: % % Image *BlurImage(const Image *image,const double radius, -% const double sigma,const double bias,ExceptionInfo *exception) +% const double sigma,ExceptionInfo *exception) % % A description of each parameter follows: % @@ -810,18 +819,18 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius, % % o sigma: the standard deviation of the Gaussian, in pixels. % -% o bias: the bias. -% % o exception: return any errors or warnings in this structure. % */ -static double *GetBlurKernel(const size_t width,const double sigma) +static MagickRealType *GetBlurKernel(const size_t width,const double sigma) { double - *kernel, normalize; + MagickRealType + *kernel; + register ssize_t i; @@ -833,16 +842,17 @@ static double *GetBlurKernel(const size_t width,const double sigma) Generate a 1-D convolution kernel. */ (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); - kernel=(double *) AcquireQuantumMemory((size_t) width,sizeof(*kernel)); - if (kernel == (double *) NULL) + kernel=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory((size_t) + width,sizeof(*kernel))); + if (kernel == (MagickRealType *) NULL) return(0); normalize=0.0; j=(ssize_t) width/2; i=0; for (k=(-j); k <= j; k++) { - kernel[i]=(double) (exp(-((double) k*k)/(2.0*MagickSigma*MagickSigma))/ - (MagickSQ2PI*MagickSigma)); + kernel[i]=(MagickRealType) (exp(-((double) k*k)/(2.0*MagickSigma* + MagickSigma))/(MagickSQ2PI*MagickSigma)); normalize+=kernel[i]; i++; } @@ -852,7 +862,7 @@ static double *GetBlurKernel(const size_t width,const double sigma) } MagickExport Image *BlurImage(const Image *image,const double radius, - const double sigma,const double bias,ExceptionInfo *exception) + const double sigma,ExceptionInfo *exception) { #define BlurImageTag "Blur/Image" @@ -860,9 +870,6 @@ MagickExport Image *BlurImage(const Image *image,const double radius, *blur_view, *image_view; - double - *kernel; - Image *blur_image; @@ -872,6 +879,9 @@ MagickExport Image *BlurImage(const Image *image,const double radius, MagickOffsetType progress; + MagickRealType + *kernel; + register ssize_t i; @@ -895,7 +905,7 @@ MagickExport Image *BlurImage(const Image *image,const double radius, blur_image=CloneImage(image,0,0,MagickTrue,exception); if (blur_image == (Image *) NULL) return((Image *) NULL); - if (fabs(sigma) <= MagickEpsilon) + if (fabs(sigma) < MagickEpsilon) return(blur_image); if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse) { @@ -904,7 +914,7 @@ MagickExport Image *BlurImage(const Image *image,const double radius, } width=GetOptimalKernelWidth1D(radius,sigma); kernel=GetBlurKernel(width,sigma); - if (kernel == (double *) NULL) + if (kernel == (MagickRealType *) NULL) { blur_image=DestroyImage(blur_image); ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); @@ -915,11 +925,11 @@ MagickExport Image *BlurImage(const Image *image,const double radius, format[MaxTextExtent], *message; - register const double + register const MagickRealType *k; (void) LogMagickEvent(TransformEvent,GetMagickModule(), - " BlurImage with %.20g kernel:",(double) width); + " blur image with kernel width %.20g:",(double) width); message=AcquireString(""); k=kernel; for (i=0; i < (ssize_t) width; i++) @@ -927,7 +937,7 @@ MagickExport Image *BlurImage(const Image *image,const double radius, *message='\0'; (void) FormatLocaleString(format,MaxTextExtent,"%.20g: ",(double) i); (void) ConcatenateString(&message,format); - (void) FormatLocaleString(format,MaxTextExtent,"%g ",*k++); + (void) FormatLocaleString(format,MaxTextExtent,"%g ",(double) *k++); (void) ConcatenateString(&message,format); (void) LogMagickEvent(TransformEvent,GetMagickModule(),"%s",message); } @@ -939,10 +949,11 @@ MagickExport Image *BlurImage(const Image *image,const double radius, status=MagickTrue; progress=0; center=(ssize_t) GetPixelChannels(image)*(width/2L); - image_view=AcquireCacheView(image); - blur_view=AcquireCacheView(blur_image); + image_view=AcquireVirtualCacheView(image,exception); + blur_view=AcquireAuthenticCacheView(blur_image,exception); #if defined(MAGICKCORE_OPENMP_SUPPORT) - #pragma omp parallel for schedule(dynamic,4) shared(progress,status) + #pragma omp parallel for schedule(static,4) shared(progress,status) \ + dynamic_number_threads(image,image->columns,image->rows,1) #endif for (y=0; y < (ssize_t) image->rows; y++) { @@ -959,7 +970,7 @@ MagickExport Image *BlurImage(const Image *image,const double radius, continue; p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y, image->columns+width,1,exception); - q=GetCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1, + q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1, exception); if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) { @@ -973,7 +984,7 @@ MagickExport Image *BlurImage(const Image *image,const double radius, for (i=0; i < (ssize_t) GetPixelChannels(image); i++) { - MagickRealType + double alpha, gamma, pixel; @@ -985,7 +996,7 @@ MagickExport Image *BlurImage(const Image *image,const double radius, blur_traits, traits; - register const double + register const MagickRealType *restrict k; register const Quantum @@ -994,13 +1005,14 @@ MagickExport Image *BlurImage(const Image *image,const double radius, register ssize_t u; - traits=GetPixelChannelMapTraits(image,(PixelChannel) i); - channel=GetPixelChannelMapChannel(image,(PixelChannel) i); - blur_traits=GetPixelChannelMapTraits(blur_image,channel); + channel=GetPixelChannelChannel(image,i); + traits=GetPixelChannelTraits(image,channel); + blur_traits=GetPixelChannelTraits(blur_image,channel); if ((traits == UndefinedPixelTrait) || (blur_traits == UndefinedPixelTrait)) continue; - if ((blur_traits & CopyPixelTrait) != 0) + if (((blur_traits & CopyPixelTrait) != 0) || + (GetPixelMask(image,p) != 0)) { SetPixelChannel(blur_image,channel,p[center+i],q); continue; @@ -1028,13 +1040,13 @@ MagickExport Image *BlurImage(const Image *image,const double radius, gamma=0.0; for (u=0; u < (ssize_t) width; u++) { - alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(image,pixels)); + alpha=(double) (QuantumScale*GetPixelAlpha(image,pixels)); pixel+=(*k)*alpha*pixels[i]; gamma+=(*k)*alpha; k++; pixels+=GetPixelChannels(image); } - gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma); + gamma=PerceptibleReciprocal(gamma); SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q); } p+=GetPixelChannels(image); @@ -1048,7 +1060,7 @@ MagickExport Image *BlurImage(const Image *image,const double radius, proceed; #if defined(MAGICKCORE_OPENMP_SUPPORT) - #pragma omp critical (MagickCore_BlurImage) + #pragma omp critical (MagickCore_BlurImage) #endif proceed=SetImageProgress(image,BlurImageTag,progress++,blur_image->rows+ blur_image->columns); @@ -1061,12 +1073,14 @@ MagickExport Image *BlurImage(const Image *image,const double radius, /* Blur columns. */ - image_view=AcquireCacheView(blur_image); - blur_view=AcquireCacheView(blur_image); + center=(ssize_t) GetPixelChannels(blur_image)*(width/2L); + image_view=AcquireVirtualCacheView(blur_image,exception); + blur_view=AcquireAuthenticCacheView(blur_image,exception); #if defined(MAGICKCORE_OPENMP_SUPPORT) - #pragma omp parallel for schedule(dynamic,4) shared(progress,status) + #pragma omp parallel for schedule(static,4) shared(progress,status) \ + dynamic_number_threads(image,image->columns,image->rows,1) #endif - for (x=0; x < (ssize_t) image->columns; x++) + for (x=0; x < (ssize_t) blur_image->columns; x++) { register const Quantum *restrict p; @@ -1080,21 +1094,21 @@ MagickExport Image *BlurImage(const Image *image,const double radius, if (status == MagickFalse) continue; p=GetCacheViewVirtualPixels(image_view,x,-((ssize_t) width/2L),1, - image->rows+width,exception); + blur_image->rows+width,exception); q=GetCacheViewAuthenticPixels(blur_view,x,0,1,blur_image->rows,exception); if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) { status=MagickFalse; continue; } - for (y=0; y < (ssize_t) image->rows; y++) + for (y=0; y < (ssize_t) blur_image->rows; y++) { register ssize_t i; - for (i=0; i < (ssize_t) GetPixelChannels(image); i++) + for (i=0; i < (ssize_t) GetPixelChannels(blur_image); i++) { - MagickRealType + double alpha, gamma, pixel; @@ -1106,7 +1120,7 @@ MagickExport Image *BlurImage(const Image *image,const double radius, blur_traits, traits; - register const double + register const MagickRealType *restrict k; register const Quantum @@ -1115,13 +1129,14 @@ MagickExport Image *BlurImage(const Image *image,const double radius, register ssize_t u; - traits=GetPixelChannelMapTraits(blur_image,(PixelChannel) i); - channel=GetPixelChannelMapChannel(blur_image,(PixelChannel) i); - blur_traits=GetPixelChannelMapTraits(blur_image,channel); + channel=GetPixelChannelChannel(blur_image,i); + traits=GetPixelChannelTraits(blur_image,channel); + blur_traits=GetPixelChannelTraits(blur_image,channel); if ((traits == UndefinedPixelTrait) || (blur_traits == UndefinedPixelTrait)) continue; - if ((blur_traits & CopyPixelTrait) != 0) + if (((blur_traits & CopyPixelTrait) != 0) || + (GetPixelMask(image,p) != 0)) { SetPixelChannel(blur_image,channel,p[center+i],q); continue; @@ -1149,14 +1164,14 @@ MagickExport Image *BlurImage(const Image *image,const double radius, gamma=0.0; for (u=0; u < (ssize_t) width; u++) { - alpha=(MagickRealType) (QuantumScale* - GetPixelAlpha(blur_image,pixels)); + alpha=(double) (QuantumScale*GetPixelAlpha(blur_image, + pixels)); pixel+=(*k)*alpha*pixels[i]; gamma+=(*k)*alpha; k++; pixels+=GetPixelChannels(blur_image); } - gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma); + gamma=PerceptibleReciprocal(gamma); SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q); } p+=GetPixelChannels(blur_image); @@ -1170,7 +1185,7 @@ MagickExport Image *BlurImage(const Image *image,const double radius, proceed; #if defined(MAGICKCORE_OPENMP_SUPPORT) - #pragma omp critical (MagickCore_BlurImage) + #pragma omp critical (MagickCore_BlurImage) #endif proceed=SetImageProgress(blur_image,BlurImageTag,progress++, blur_image->rows+blur_image->columns); @@ -1180,10 +1195,10 @@ MagickExport Image *BlurImage(const Image *image,const double radius, } blur_view=DestroyCacheView(blur_view); image_view=DestroyCacheView(image_view); - kernel=(double *) RelinquishMagickMemory(kernel); + kernel=(MagickRealType *) RelinquishAlignedMemory(kernel); + blur_image->type=image->type; if (status == MagickFalse) blur_image=DestroyImage(blur_image); - blur_image->type=image->type; return(blur_image); } @@ -1217,223 +1232,7 @@ MagickExport Image *BlurImage(const Image *image,const double radius, MagickExport Image *ConvolveImage(const Image *image, const KernelInfo *kernel_info,ExceptionInfo *exception) { -#define ConvolveImageTag "Convolve/Image" - - CacheView - *convolve_view, - *image_view; - - Image - *convolve_image; - - MagickBooleanType - status; - - MagickOffsetType - progress; - - ssize_t - center, - y; - - /* - Initialize convolve image attributes. - */ - assert(image != (Image *) NULL); - assert(image->signature == MagickSignature); - if (image->debug != MagickFalse) - (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); - assert(exception != (ExceptionInfo *) NULL); - assert(exception->signature == MagickSignature); - if ((kernel_info->width % 2) == 0) - ThrowImageException(OptionError,"KernelWidthMustBeAnOddNumber"); - convolve_image=CloneImage(image,image->columns,image->rows,MagickTrue, - exception); - if (convolve_image == (Image *) NULL) - return((Image *) NULL); - if (SetImageStorageClass(convolve_image,DirectClass,exception) == MagickFalse) - { - convolve_image=DestroyImage(convolve_image); - return((Image *) NULL); - } - if (image->debug != MagickFalse) - { - char - format[MaxTextExtent], - *message; - - register const double - *k; - - register ssize_t - u; - - ssize_t - v; - - (void) LogMagickEvent(TransformEvent,GetMagickModule(), - " ConvolveImage with %.20gx%.20g kernel:",(double) kernel_info->width, - (double) kernel_info->height); - message=AcquireString(""); - k=kernel_info->values; - for (v=0; v < (ssize_t) kernel_info->width; v++) - { - *message='\0'; - (void) FormatLocaleString(format,MaxTextExtent,"%.20g: ",(double) v); - (void) ConcatenateString(&message,format); - for (u=0; u < (ssize_t) kernel_info->height; u++) - { - (void) FormatLocaleString(format,MaxTextExtent,"%g ",*k++); - (void) ConcatenateString(&message,format); - } - (void) LogMagickEvent(TransformEvent,GetMagickModule(),"%s",message); - } - message=DestroyString(message); - } - status=AccelerateConvolveImage(image,kernel_info,convolve_image,exception); - if (status == MagickTrue) - return(convolve_image); - /* - Convolve image. - */ - center=(ssize_t) GetPixelChannels(image)*(image->columns+kernel_info->width)* - (kernel_info->height/2L)+GetPixelChannels(image)*(kernel_info->width/2L); - status=MagickTrue; - progress=0; - image_view=AcquireCacheView(image); - convolve_view=AcquireCacheView(convolve_image); -#if defined(MAGICKCORE_OPENMP_SUPPORT) - #pragma omp parallel for schedule(dynamic,4) shared(progress,status) -#endif - for (y=0; y < (ssize_t) image->rows; y++) - { - register const Quantum - *restrict p; - - register Quantum - *restrict q; - - register ssize_t - x; - - if (status == MagickFalse) - continue; - p=GetCacheViewVirtualPixels(image_view,-((ssize_t) kernel_info->width/2L),y- - (ssize_t) (kernel_info->height/2L),image->columns+kernel_info->width, - kernel_info->height,exception); - q=QueueCacheViewAuthenticPixels(convolve_view,0,y,convolve_image->columns,1, - exception); - if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) - { - status=MagickFalse; - continue; - } - for (x=0; x < (ssize_t) image->columns; x++) - { - register ssize_t - i; - - for (i=0; i < (ssize_t) GetPixelChannels(image); i++) - { - MagickRealType - alpha, - gamma, - pixel; - - PixelChannel - channel; - - PixelTrait - convolve_traits, - traits; - - register const double - *restrict k; - - register const Quantum - *restrict pixels; - - register ssize_t - u; - - ssize_t - v; - - traits=GetPixelChannelMapTraits(image,(PixelChannel) i); - channel=GetPixelChannelMapChannel(image,(PixelChannel) i); - convolve_traits=GetPixelChannelMapTraits(convolve_image,channel); - if ((traits == UndefinedPixelTrait) || - (convolve_traits == UndefinedPixelTrait)) - continue; - if ((convolve_traits & CopyPixelTrait) != 0) - { - SetPixelChannel(convolve_image,channel,p[center+i],q); - continue; - } - k=kernel_info->values; - pixels=p; - pixel=kernel_info->bias; - if ((convolve_traits & BlendPixelTrait) == 0) - { - /* - No alpha blending. - */ - for (v=0; v < (ssize_t) kernel_info->height; v++) - { - for (u=0; u < (ssize_t) kernel_info->width; u++) - { - pixel+=(*k)*pixels[i]; - k++; - pixels+=GetPixelChannels(image); - } - pixels+=image->columns*GetPixelChannels(image); - } - SetPixelChannel(convolve_image,channel,ClampToQuantum(pixel),q); - continue; - } - /* - Alpha blending. - */ - gamma=0.0; - for (v=0; v < (ssize_t) kernel_info->height; v++) - { - for (u=0; u < (ssize_t) kernel_info->width; u++) - { - alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(image,pixels)); - pixel+=(*k)*alpha*pixels[i]; - gamma+=(*k)*alpha; - k++; - pixels+=GetPixelChannels(image); - } - pixels+=image->columns*GetPixelChannels(image); - } - gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma); - SetPixelChannel(convolve_image,channel,ClampToQuantum(gamma*pixel),q); - } - p+=GetPixelChannels(image); - q+=GetPixelChannels(convolve_image); - } - if (SyncCacheViewAuthenticPixels(convolve_view,exception) == MagickFalse) - status=MagickFalse; - if (image->progress_monitor != (MagickProgressMonitor) NULL) - { - MagickBooleanType - proceed; - -#if defined(MAGICKCORE_OPENMP_SUPPORT) - #pragma omp critical (MagickCore_ConvolveImage) -#endif - proceed=SetImageProgress(image,ConvolveImageTag,progress++,image->rows); - if (proceed == MagickFalse) - status=MagickFalse; - } - } - convolve_image->type=image->type; - convolve_view=DestroyCacheView(convolve_view); - image_view=DestroyCacheView(image_view); - if (status == MagickFalse) - convolve_image=DestroyImage(convolve_image); - return(convolve_image); + return(MorphologyImage(image,CorrelateMorphology,1,kernel_info,exception)); } /* @@ -1448,7 +1247,10 @@ MagickExport Image *ConvolveImage(const Image *image, %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % DespeckleImage() reduces the speckle noise in an image while perserving the -% edges of the original image. +% edges of the original image. A speckle removing filter uses a complementary % hulling technique (raising pixels that are darker than their surrounding +% neighbors, then complementarily lowering pixels that are brighter than their +% surrounding neighbors) to reduce the speckle index of that image (reference +% Crimmins speckle removal). % % The format of the DespeckleImage method is: % @@ -1462,22 +1264,16 @@ MagickExport Image *ConvolveImage(const Image *image, % */ -static void Hull(const ssize_t x_offset,const ssize_t y_offset, - const size_t columns,const size_t rows,Quantum *f,Quantum *g, - const int polarity) +static void Hull(const Image *image,const ssize_t x_offset, + const ssize_t y_offset,const size_t columns,const size_t rows, + const int polarity,Quantum *restrict f,Quantum *restrict g) { - MagickRealType - v; - register Quantum *p, *q, *r, *s; - register ssize_t - x; - ssize_t y; @@ -1485,80 +1281,78 @@ static void Hull(const ssize_t x_offset,const ssize_t y_offset, assert(g != (Quantum *) NULL); p=f+(columns+2); q=g+(columns+2); - r=p+(y_offset*((ssize_t) columns+2)+x_offset); + r=p+(y_offset*(columns+2)+x_offset); +#if defined(MAGICKCORE_OPENMP_SUPPORT) + #pragma omp parallel for schedule(static) \ + dynamic_number_threads(image,columns,rows,1) +#endif for (y=0; y < (ssize_t) rows; y++) { - p++; - q++; - r++; + MagickRealType + v; + + register ssize_t + i, + x; + + i=(2*y+1)+y*columns; if (polarity > 0) - for (x=(ssize_t) columns; x != 0; x--) + for (x=0; x < (ssize_t) columns; x++) { - v=(MagickRealType) (*p); - if ((MagickRealType) *r >= (v+(MagickRealType) ScaleCharToQuantum(2))) + v=(MagickRealType) p[i]; + if ((MagickRealType) r[i] >= (v+ScaleCharToQuantum(2))) v+=ScaleCharToQuantum(1); - *q=(Quantum) v; - p++; - q++; - r++; + q[i]=(Quantum) v; + i++; } else - for (x=(ssize_t) columns; x != 0; x--) + for (x=0; x < (ssize_t) columns; x++) { - v=(MagickRealType) (*p); - if ((MagickRealType) *r <= (v-(MagickRealType) ScaleCharToQuantum(2))) - v-=(ssize_t) ScaleCharToQuantum(1); - *q=(Quantum) v; - p++; - q++; - r++; + v=(MagickRealType) p[i]; + if ((MagickRealType) r[i] <= (v-ScaleCharToQuantum(2))) + v-=ScaleCharToQuantum(1); + q[i]=(Quantum) v; + i++; } - p++; - q++; - r++; } p=f+(columns+2); q=g+(columns+2); - r=q+(y_offset*((ssize_t) columns+2)+x_offset); - s=q-(y_offset*((ssize_t) columns+2)+x_offset); + r=q+(y_offset*(columns+2)+x_offset); + s=q-(y_offset*(columns+2)+x_offset); +#if defined(MAGICKCORE_OPENMP_SUPPORT) + #pragma omp parallel for schedule(static) \ + dynamic_number_threads(image,columns,rows,1) +#endif for (y=0; y < (ssize_t) rows; y++) { - p++; - q++; - r++; - s++; + register ssize_t + i, + x; + + MagickRealType + v; + + i=(2*y+1)+y*columns; if (polarity > 0) - for (x=(ssize_t) columns; x != 0; x--) + for (x=0; x < (ssize_t) columns; x++) { - v=(MagickRealType) (*q); - if (((MagickRealType) *s >= - (v+(MagickRealType) ScaleCharToQuantum(2))) && - ((MagickRealType) *r > v)) + v=(MagickRealType) q[i]; + if (((MagickRealType) s[i] >= (v+ScaleCharToQuantum(2))) && + ((MagickRealType) r[i] > v)) v+=ScaleCharToQuantum(1); - *p=(Quantum) v; - p++; - q++; - r++; - s++; + p[i]=(Quantum) v; + i++; } else - for (x=(ssize_t) columns; x != 0; x--) + for (x=0; x < (ssize_t) columns; x++) { - v=(MagickRealType) (*q); - if (((MagickRealType) *s <= - (v-(MagickRealType) ScaleCharToQuantum(2))) && - ((MagickRealType) *r < v)) - v-=(MagickRealType) ScaleCharToQuantum(1); - *p=(Quantum) v; - p++; - q++; - r++; - s++; + v=(MagickRealType) q[i]; + if (((MagickRealType) s[i] <= (v-ScaleCharToQuantum(2))) && + ((MagickRealType) r[i] < v)) + v-=ScaleCharToQuantum(1); + p[i]=(Quantum) v; + i++; } - p++; - q++; - r++; - s++; } } @@ -1577,7 +1371,7 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception) status; Quantum - *restrict buffers, + *restrict buffer, *restrict pixels; register ssize_t @@ -1609,15 +1403,15 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception) return((Image *) NULL); } /* - Allocate image buffers. + Allocate image buffer. */ length=(size_t) ((image->columns+2)*(image->rows+2)); - pixels=(Quantum *) AcquireQuantumMemory(length,2*sizeof(*pixels)); - buffers=(Quantum *) AcquireQuantumMemory(length,2*sizeof(*pixels)); - if ((pixels == (Quantum *) NULL) || (buffers == (Quantum *) NULL)) + pixels=(Quantum *) AcquireQuantumMemory(length,sizeof(*pixels)); + buffer=(Quantum *) AcquireQuantumMemory(length,sizeof(*buffer)); + if ((pixels == (Quantum *) NULL) || (buffer == (Quantum *) NULL)) { - if (buffers != (Quantum *) NULL) - buffers=(Quantum *) RelinquishMagickMemory(buffers); + if (buffer != (Quantum *) NULL) + buffer=(Quantum *) RelinquishMagickMemory(buffer); if (pixels != (Quantum *) NULL) pixels=(Quantum *) RelinquishMagickMemory(pixels); despeckle_image=DestroyImage(despeckle_image); @@ -1627,8 +1421,8 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception) Reduce speckle in the image. */ status=MagickTrue; - image_view=AcquireCacheView(image); - despeckle_view=AcquireCacheView(despeckle_image); + image_view=AcquireVirtualCacheView(image,exception); + despeckle_view=AcquireAuthenticCacheView(despeckle_image,exception); for (i=0; i < (ssize_t) GetPixelChannels(image); i++) { PixelChannel @@ -1638,10 +1432,6 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception) despeckle_traits, traits; - register Quantum - *buffer, - *pixel; - register ssize_t k, x; @@ -1652,17 +1442,15 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception) if (status == MagickFalse) continue; - traits=GetPixelChannelMapTraits(image,(PixelChannel) i); - channel=GetPixelChannelMapChannel(image,(PixelChannel) i); - despeckle_traits=GetPixelChannelMapTraits(despeckle_image,channel); + channel=GetPixelChannelChannel(image,i); + traits=GetPixelChannelTraits(image,channel); + despeckle_traits=GetPixelChannelTraits(despeckle_image,channel); if ((traits == UndefinedPixelTrait) || (despeckle_traits == UndefinedPixelTrait)) continue; if ((despeckle_traits & CopyPixelTrait) != 0) continue; - pixel=pixels; - (void) ResetMagickMemory(pixel,0,length*sizeof(*pixel)); - buffer=buffers; + (void) ResetMagickMemory(pixels,0,length*sizeof(*pixels)); j=(ssize_t) image->columns+2; for (y=0; y < (ssize_t) image->rows; y++) { @@ -1678,7 +1466,7 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception) j++; for (x=0; x < (ssize_t) image->columns; x++) { - pixel[j++]=p[i]; + pixels[j++]=p[i]; p+=GetPixelChannels(image); } j++; @@ -1686,10 +1474,10 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception) (void) ResetMagickMemory(buffer,0,length*sizeof(*buffer)); for (k=0; k < 4; k++) { - Hull(X[k],Y[k],image->columns,image->rows,pixel,buffer,1); - Hull(-X[k],-Y[k],image->columns,image->rows,pixel,buffer,1); - Hull(-X[k],-Y[k],image->columns,image->rows,pixel,buffer,-1); - Hull(X[k],Y[k],image->columns,image->rows,pixel,buffer,-1); + Hull(image,X[k],Y[k],image->columns,image->rows,1,pixels,buffer); + Hull(image,-X[k],-Y[k],image->columns,image->rows,1,pixels,buffer); + Hull(image,-X[k],-Y[k],image->columns,image->rows,-1,pixels,buffer); + Hull(image,X[k],Y[k],image->columns,image->rows,-1,pixels,buffer); } j=(ssize_t) image->columns+2; for (y=0; y < (ssize_t) image->rows; y++) @@ -1700,8 +1488,8 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception) register Quantum *restrict q; - q=GetCacheViewAuthenticPixels(despeckle_view,0,y,despeckle_image->columns, - 1,exception); + q=QueueCacheViewAuthenticPixels(despeckle_view,0,y, + despeckle_image->columns,1,exception); if (q == (Quantum *) NULL) { status=MagickFalse; @@ -1710,7 +1498,7 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception) j++; for (x=0; x < (ssize_t) image->columns; x++) { - SetPixelChannel(despeckle_image,channel,pixel[j++],q); + SetPixelChannel(despeckle_image,channel,pixels[j++],q); q+=GetPixelChannels(despeckle_image); } sync=SyncCacheViewAuthenticPixels(despeckle_view,exception); @@ -1731,7 +1519,7 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception) } despeckle_view=DestroyCacheView(despeckle_view); image_view=DestroyCacheView(image_view); - buffers=(Quantum *) RelinquishMagickMemory(buffers); + buffer=(Quantum *) RelinquishMagickMemory(buffer); pixels=(Quantum *) RelinquishMagickMemory(pixels); despeckle_image->type=image->type; if (status == MagickFalse) @@ -1796,15 +1584,16 @@ MagickExport Image *EdgeImage(const Image *image,const double radius, (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickSignature); - width=GetOptimalKernelWidth2D(radius,sigma); + width=GetOptimalKernelWidth1D(radius,sigma); kernel_info=AcquireKernelInfo((const char *) NULL); if (kernel_info == (KernelInfo *) NULL) ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); kernel_info->width=width; kernel_info->height=width; - kernel_info->values=(double *) AcquireAlignedMemory(kernel_info->width, - kernel_info->width*sizeof(*kernel_info->values)); - if (kernel_info->values == (double *) NULL) + kernel_info->values=(MagickRealType *) MagickAssumeAligned( + AcquireAlignedMemory(kernel_info->width,kernel_info->width* + sizeof(*kernel_info->values))); + if (kernel_info->values == (MagickRealType *) NULL) { kernel_info=DestroyKernelInfo(kernel_info); ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); @@ -1815,12 +1604,11 @@ MagickExport Image *EdgeImage(const Image *image,const double radius, { for (u=(-j); u <= j; u++) { - kernel_info->values[i]=(-1.0); + kernel_info->values[i]=(MagickRealType) (-1.0); i++; } } - kernel_info->values[i/2]=(double) (width*width-1.0); - kernel_info->bias=image->bias; + kernel_info->values[i/2]=(MagickRealType) (width*width-1.0); edge_image=ConvolveImage(image,kernel_info,exception); kernel_info=DestroyKernelInfo(kernel_info); return(edge_image); @@ -1886,15 +1674,16 @@ MagickExport Image *EmbossImage(const Image *image,const double radius, (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickSignature); - width=GetOptimalKernelWidth2D(radius,sigma); + width=GetOptimalKernelWidth1D(radius,sigma); kernel_info=AcquireKernelInfo((const char *) NULL); if (kernel_info == (KernelInfo *) NULL) ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); kernel_info->width=width; kernel_info->height=width; - kernel_info->values=(double *) AcquireAlignedMemory(kernel_info->width, - kernel_info->width*sizeof(*kernel_info->values)); - if (kernel_info->values == (double *) NULL) + kernel_info->values=(MagickRealType *) MagickAssumeAligned( + AcquireAlignedMemory(kernel_info->width,kernel_info->width* + sizeof(*kernel_info->values))); + if (kernel_info->values == (MagickRealType *) NULL) { kernel_info=DestroyKernelInfo(kernel_info); ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); @@ -1906,8 +1695,8 @@ MagickExport Image *EmbossImage(const Image *image,const double radius, { for (u=(-j); u <= j; u++) { - kernel_info->values[i]=(double) (((u < 0) || (v < 0) ? -8.0 : 8.0)* - exp(-((double) u*u+v*v)/(2.0*MagickSigma*MagickSigma))/ + kernel_info->values[i]=(MagickRealType) (((u < 0) || (v < 0) ? -8.0 : + 8.0)*exp(-((double) u*u+v*v)/(2.0*MagickSigma*MagickSigma))/ (2.0*MagickPI*MagickSigma*MagickSigma)); if (u != k) kernel_info->values[i]=0.0; @@ -1915,7 +1704,6 @@ MagickExport Image *EmbossImage(const Image *image,const double radius, } k--; } - kernel_info->bias=image->bias; emboss_image=ConvolveImage(image,kernel_info,exception); kernel_info=DestroyKernelInfo(kernel_info); if (emboss_image != (Image *) NULL) @@ -1942,7 +1730,7 @@ MagickExport Image *EmbossImage(const Image *image,const double radius, % The format of the GaussianBlurImage method is: % % Image *GaussianBlurImage(const Image *image,onst double radius, -% const double sigma,const double bias,ExceptionInfo *exception) +% const double sigma,ExceptionInfo *exception) % % A description of each parameter follows: % @@ -1953,13 +1741,11 @@ MagickExport Image *EmbossImage(const Image *image,const double radius, % % o sigma: the standard deviation of the Gaussian, in pixels. % -% o bias: the bias. -% % o exception: return any errors or warnings in this structure. % */ MagickExport Image *GaussianBlurImage(const Image *image,const double radius, - const double sigma,const double bias,ExceptionInfo *exception) + const double sigma,ExceptionInfo *exception) { Image *blur_image; @@ -1991,11 +1777,11 @@ MagickExport Image *GaussianBlurImage(const Image *image,const double radius, (void) ResetMagickMemory(kernel_info,0,sizeof(*kernel_info)); kernel_info->width=width; kernel_info->height=width; - kernel_info->bias=bias; kernel_info->signature=MagickSignature; - kernel_info->values=(double *) AcquireAlignedMemory(kernel_info->width, - kernel_info->width*sizeof(*kernel_info->values)); - if (kernel_info->values == (double *) NULL) + kernel_info->values=(MagickRealType *) MagickAssumeAligned( + AcquireAlignedMemory(kernel_info->width,kernel_info->width* + sizeof(*kernel_info->values))); + if (kernel_info->values == (MagickRealType *) NULL) { kernel_info=DestroyKernelInfo(kernel_info); ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); @@ -2006,7 +1792,7 @@ MagickExport Image *GaussianBlurImage(const Image *image,const double radius, { for (u=(-j); u <= j; u++) { - kernel_info->values[i]=(double) (exp(-((double) u*u+v*v)/(2.0* + kernel_info->values[i]=(MagickRealType) (exp(-((double) u*u+v*v)/(2.0* MagickSigma*MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma)); i++; } @@ -2038,8 +1824,7 @@ MagickExport Image *GaussianBlurImage(const Image *image,const double radius, % The format of the MotionBlurImage method is: % % Image *MotionBlurImage(const Image *image,const double radius, -% const double sigma,const double angle,const double bias, -% ExceptionInfo *exception) +% const double sigma,const double angle,ExceptionInfo *exception) % % A description of each parameter follows: % @@ -2052,15 +1837,14 @@ MagickExport Image *GaussianBlurImage(const Image *image,const double radius, % % o angle: Apply the effect along this angle. % -% o bias: the bias. -% % o exception: return any errors or warnings in this structure. % */ -static double *GetMotionBlurKernel(const size_t width,const double sigma) +static MagickRealType *GetMotionBlurKernel(const size_t width, + const double sigma) { - double + MagickRealType *kernel, normalize; @@ -2071,13 +1855,14 @@ static double *GetMotionBlurKernel(const size_t width,const double sigma) Generate a 1-D convolution kernel. */ (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); - kernel=(double *) AcquireQuantumMemory((size_t) width,sizeof(*kernel)); - if (kernel == (double *) NULL) + kernel=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory((size_t) + width,sizeof(*kernel))); + if (kernel == (MagickRealType *) NULL) return(kernel); normalize=0.0; for (i=0; i < (ssize_t) width; i++) { - kernel[i]=(double) (exp((-((double) i*i)/(double) (2.0*MagickSigma* + kernel[i]=(MagickRealType) (exp((-((double) i*i)/(double) (2.0*MagickSigma* MagickSigma)))/(MagickSQ2PI*MagickSigma)); normalize+=kernel[i]; } @@ -2087,15 +1872,12 @@ static double *GetMotionBlurKernel(const size_t width,const double sigma) } MagickExport Image *MotionBlurImage(const Image *image,const double radius, - const double sigma,const double angle,const double bias, - ExceptionInfo *exception) + const double sigma,const double angle,ExceptionInfo *exception) { CacheView *blur_view, - *image_view; - - double - *kernel; + *image_view, + *motion_view; Image *blur_image; @@ -2106,6 +1888,9 @@ MagickExport Image *MotionBlurImage(const Image *image,const double radius, MagickOffsetType progress; + MagickRealType + *kernel; + OffsetInfo *offset; @@ -2128,24 +1913,24 @@ MagickExport Image *MotionBlurImage(const Image *image,const double radius, assert(exception != (ExceptionInfo *) NULL); width=GetOptimalKernelWidth1D(radius,sigma); kernel=GetMotionBlurKernel(width,sigma); - if (kernel == (double *) NULL) + if (kernel == (MagickRealType *) NULL) ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); offset=(OffsetInfo *) AcquireQuantumMemory(width,sizeof(*offset)); if (offset == (OffsetInfo *) NULL) { - kernel=(double *) RelinquishMagickMemory(kernel); + kernel=(MagickRealType *) RelinquishAlignedMemory(kernel); ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); } blur_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception); if (blur_image == (Image *) NULL) { - kernel=(double *) RelinquishMagickMemory(kernel); + kernel=(MagickRealType *) RelinquishAlignedMemory(kernel); offset=(OffsetInfo *) RelinquishMagickMemory(offset); return((Image *) NULL); } if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse) { - kernel=(double *) RelinquishMagickMemory(kernel); + kernel=(MagickRealType *) RelinquishAlignedMemory(kernel); offset=(OffsetInfo *) RelinquishMagickMemory(offset); blur_image=DestroyImage(blur_image); return((Image *) NULL); @@ -2162,10 +1947,12 @@ MagickExport Image *MotionBlurImage(const Image *image,const double radius, */ status=MagickTrue; progress=0; - image_view=AcquireCacheView(image); - blur_view=AcquireCacheView(blur_image); + image_view=AcquireVirtualCacheView(image,exception); + motion_view=AcquireVirtualCacheView(image,exception); + blur_view=AcquireAuthenticCacheView(blur_image,exception); #if defined(MAGICKCORE_OPENMP_SUPPORT) - #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1) + #pragma omp parallel for schedule(static,4) shared(progress,status) \ + dynamic_number_threads(image,image->columns,image->rows,1) #endif for (y=0; y < (ssize_t) image->rows; y++) { @@ -2180,8 +1967,8 @@ MagickExport Image *MotionBlurImage(const Image *image,const double radius, if (status == MagickFalse) continue; - p=GetCacheViewVirtualPixels(blur_view,0,y,image->columns,1,exception); - q=GetCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1, + p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); + q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1, exception); if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) { @@ -2195,7 +1982,7 @@ MagickExport Image *MotionBlurImage(const Image *image,const double radius, for (i=0; i < (ssize_t) GetPixelChannels(image); i++) { - MagickRealType + double alpha, gamma, pixel; @@ -2210,30 +1997,31 @@ MagickExport Image *MotionBlurImage(const Image *image,const double radius, register const Quantum *restrict r; - register double + register MagickRealType *restrict k; register ssize_t j; - traits=GetPixelChannelMapTraits(image,(PixelChannel) i); - channel=GetPixelChannelMapChannel(image,(PixelChannel) i); - blur_traits=GetPixelChannelMapTraits(blur_image,channel); + channel=GetPixelChannelChannel(image,i); + traits=GetPixelChannelTraits(image,channel); + blur_traits=GetPixelChannelTraits(blur_image,channel); if ((traits == UndefinedPixelTrait) || (blur_traits == UndefinedPixelTrait)) continue; - if ((blur_traits & CopyPixelTrait) != 0) + if (((blur_traits & CopyPixelTrait) != 0) || + (GetPixelMask(image,p) != 0)) { SetPixelChannel(blur_image,channel,p[i],q); continue; } k=kernel; - pixel=bias; + pixel=0.0; if ((blur_traits & BlendPixelTrait) == 0) { for (j=0; j < (ssize_t) width; j++) { - r=GetCacheViewVirtualPixels(image_view,x+offset[j].x,y+ + r=GetCacheViewVirtualPixels(motion_view,x+offset[j].x,y+ offset[j].y,1,1,exception); if (r == (const Quantum *) NULL) { @@ -2250,19 +2038,19 @@ MagickExport Image *MotionBlurImage(const Image *image,const double radius, gamma=0.0; for (j=0; j < (ssize_t) width; j++) { - r=GetCacheViewVirtualPixels(image_view,x+offset[j].x,y+offset[j].y,1, + r=GetCacheViewVirtualPixels(motion_view,x+offset[j].x,y+offset[j].y,1, 1,exception); if (r == (const Quantum *) NULL) { status=MagickFalse; continue; } - alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(image,r)); + alpha=(double) (QuantumScale*GetPixelAlpha(image,r)); pixel+=(*k)*alpha*r[i]; gamma+=(*k)*alpha; k++; } - gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma); + gamma=PerceptibleReciprocal(gamma); SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q); } p+=GetPixelChannels(image); @@ -2276,7 +2064,7 @@ MagickExport Image *MotionBlurImage(const Image *image,const double radius, proceed; #if defined(MAGICKCORE_OPENMP_SUPPORT) - #pragma omp critical (MagickCore_MotionBlurImage) + #pragma omp critical (MagickCore_MotionBlurImage) #endif proceed=SetImageProgress(image,BlurImageTag,progress++,image->rows); if (proceed == MagickFalse) @@ -2284,8 +2072,9 @@ MagickExport Image *MotionBlurImage(const Image *image,const double radius, } } blur_view=DestroyCacheView(blur_view); + motion_view=DestroyCacheView(motion_view); image_view=DestroyCacheView(image_view); - kernel=(double *) RelinquishMagickMemory(kernel); + kernel=(MagickRealType *) RelinquishAlignedMemory(kernel); offset=(OffsetInfo *) RelinquishMagickMemory(offset); if (status == MagickFalse) blur_image=DestroyImage(blur_image); @@ -2341,6 +2130,9 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview, sigma, threshold; + extern const char + DefaultTileFrame[]; + Image *images, *montage_image, @@ -2401,7 +2193,7 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview, break; (void) SetImageProgressMonitor(thumbnail,(MagickProgressMonitor) NULL, (void *) NULL); - (void) SetImageProperty(thumbnail,"label",DefaultTileLabel); + (void) SetImageProperty(thumbnail,"label",DefaultTileLabel,exception); if (i == (NumberTiles/2)) { (void) QueryColorCompliance("#dfdfdf",AllCompliance, @@ -2595,15 +2387,14 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview, } case SharpenPreview: { - preview_image=SharpenImage(thumbnail,radius,sigma,image->bias, - exception); + preview_image=SharpenImage(thumbnail,radius,sigma,exception); (void) FormatLocaleString(label,MaxTextExtent,"sharpen %gx%g", radius,sigma); break; } case BlurPreview: { - preview_image=BlurImage(thumbnail,radius,sigma,image->bias,exception); + preview_image=BlurImage(thumbnail,radius,sigma,exception); (void) FormatLocaleString(label,MaxTextExtent,"blur %gx%g",radius, sigma); break; @@ -2613,10 +2404,10 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview, preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception); if (preview_image == (Image *) NULL) break; - (void) BilevelImage(thumbnail, - (double) (percentage*((MagickRealType) QuantumRange+1.0))/100.0); + (void) BilevelImage(thumbnail,(double) (percentage*((double) + QuantumRange+1.0))/100.0,exception); (void) FormatLocaleString(label,MaxTextExtent,"threshold %g", - (double) (percentage*((MagickRealType) QuantumRange+1.0))/100.0); + (double) (percentage*((double) QuantumRange+1.0))/100.0); break; } case EdgeDetectPreview: @@ -2674,7 +2465,7 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview, if (preview_image == (Image *) NULL) break; threshold+=0.4f; - (void) SegmentImage(preview_image,RGBColorspace,MagickFalse,threshold, + (void) SegmentImage(preview_image,sRGBColorspace,MagickFalse,threshold, threshold,exception); (void) FormatLocaleString(label,MaxTextExtent,"segment %gx%g", threshold,threshold); @@ -2716,7 +2507,7 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview, case CharcoalDrawingPreview: { preview_image=CharcoalImage(thumbnail,(double) radius,(double) sigma, - image->bias,exception); + exception); (void) FormatLocaleString(label,MaxTextExtent,"charcoal %gx%g", radius,sigma); break; @@ -2781,7 +2572,7 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview, if (preview_image == (Image *) NULL) break; (void) DeleteImageProperty(preview_image,"label"); - (void) SetImageProperty(preview_image,"label",label); + (void) SetImageProperty(preview_image,"label",label,exception); AppendImageToList(&images,preview_image); proceed=SetImageProgress(image,PreviewImageTag,(MagickOffsetType) i, NumberTiles); @@ -2840,7 +2631,7 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview, % The format of the RadialBlurImage method is: % % Image *RadialBlurImage(const Image *image,const double angle, -% const double blur,ExceptionInfo *exception) +% ExceptionInfo *exception) % % A description of each parameter follows: % @@ -2853,12 +2644,13 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview, % o exception: return any errors or warnings in this structure. % */ -MagickExport Image *RadialBlurImage(const Image *image, - const double angle,const double bias,ExceptionInfo *exception) +MagickExport Image *RadialBlurImage(const Image *image,const double angle, + ExceptionInfo *exception) { CacheView *blur_view, - *image_view; + *image_view, + *radial_view; Image *blur_image; @@ -2869,7 +2661,7 @@ MagickExport Image *RadialBlurImage(const Image *image, MagickOffsetType progress; - MagickRealType + double blur_radius, *cos_theta, offset, @@ -2909,18 +2701,18 @@ MagickExport Image *RadialBlurImage(const Image *image, blur_center.y=(double) image->rows/2.0; blur_radius=hypot(blur_center.x,blur_center.y); n=(size_t) fabs(4.0*DegreesToRadians(angle)*sqrt((double) blur_radius)+2UL); - theta=DegreesToRadians(angle)/(MagickRealType) (n-1); - cos_theta=(MagickRealType *) AcquireQuantumMemory((size_t) n, + theta=DegreesToRadians(angle)/(double) (n-1); + cos_theta=(double *) AcquireQuantumMemory((size_t) n, sizeof(*cos_theta)); - sin_theta=(MagickRealType *) AcquireQuantumMemory((size_t) n, + sin_theta=(double *) AcquireQuantumMemory((size_t) n, sizeof(*sin_theta)); - if ((cos_theta == (MagickRealType *) NULL) || - (sin_theta == (MagickRealType *) NULL)) + if ((cos_theta == (double *) NULL) || + (sin_theta == (double *) NULL)) { blur_image=DestroyImage(blur_image); ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); } - offset=theta*(MagickRealType) (n-1)/2.0; + offset=theta*(double) (n-1)/2.0; for (i=0; i < (ssize_t) n; i++) { cos_theta[i]=cos((double) (theta*i-offset)); @@ -2931,10 +2723,12 @@ MagickExport Image *RadialBlurImage(const Image *image, */ status=MagickTrue; progress=0; - image_view=AcquireCacheView(image); - blur_view=AcquireCacheView(blur_image); + image_view=AcquireVirtualCacheView(image,exception); + radial_view=AcquireVirtualCacheView(image,exception); + blur_view=AcquireAuthenticCacheView(blur_image,exception); #if defined(MAGICKCORE_OPENMP_SUPPORT) - #pragma omp parallel for schedule(dynamic,4) shared(progress,status) + #pragma omp parallel for schedule(static,4) shared(progress,status) \ + dynamic_number_threads(image,image->columns,image->rows,1) #endif for (y=0; y < (ssize_t) image->rows; y++) { @@ -2949,8 +2743,8 @@ MagickExport Image *RadialBlurImage(const Image *image, if (status == MagickFalse) continue; - p=GetCacheViewVirtualPixels(blur_view,0,y,image->columns,1,exception); - q=GetCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1, + p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); + q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1, exception); if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) { @@ -2959,7 +2753,7 @@ MagickExport Image *RadialBlurImage(const Image *image, } for (x=0; x < (ssize_t) image->columns; x++) { - MagickRealType + double radius; PointInfo @@ -2987,7 +2781,7 @@ MagickExport Image *RadialBlurImage(const Image *image, } for (i=0; i < (ssize_t) GetPixelChannels(image); i++) { - MagickRealType + double gamma, pixel; @@ -3004,24 +2798,25 @@ MagickExport Image *RadialBlurImage(const Image *image, register ssize_t j; - traits=GetPixelChannelMapTraits(image,(PixelChannel) i); - channel=GetPixelChannelMapChannel(image,(PixelChannel) i); - blur_traits=GetPixelChannelMapTraits(blur_image,channel); + channel=GetPixelChannelChannel(image,i); + traits=GetPixelChannelTraits(image,channel); + blur_traits=GetPixelChannelTraits(blur_image,channel); if ((traits == UndefinedPixelTrait) || (blur_traits == UndefinedPixelTrait)) continue; - if ((blur_traits & CopyPixelTrait) != 0) + if (((blur_traits & CopyPixelTrait) != 0) || + (GetPixelMask(image,p) != 0)) { SetPixelChannel(blur_image,channel,p[i],q); continue; } gamma=0.0; - pixel=bias; + pixel=0.0; if ((blur_traits & BlendPixelTrait) == 0) { for (j=0; j < (ssize_t) n; j+=(ssize_t) step) { - r=GetCacheViewVirtualPixels(image_view, (ssize_t) (blur_center.x+ + r=GetCacheViewVirtualPixels(radial_view, (ssize_t) (blur_center.x+ center.x*cos_theta[j]-center.y*sin_theta[j]+0.5),(ssize_t) (blur_center.y+center.x*sin_theta[j]+center.y*cos_theta[j]+0.5), 1,1,exception); @@ -3033,13 +2828,13 @@ MagickExport Image *RadialBlurImage(const Image *image, pixel+=r[i]; gamma++; } - gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma); + gamma=PerceptibleReciprocal(gamma); SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q); continue; } for (j=0; j < (ssize_t) n; j+=(ssize_t) step) { - r=GetCacheViewVirtualPixels(image_view, (ssize_t) (blur_center.x+ + r=GetCacheViewVirtualPixels(radial_view, (ssize_t) (blur_center.x+ center.x*cos_theta[j]-center.y*sin_theta[j]+0.5),(ssize_t) (blur_center.y+center.x*sin_theta[j]+center.y*cos_theta[j]+0.5), 1,1,exception); @@ -3051,7 +2846,7 @@ MagickExport Image *RadialBlurImage(const Image *image, pixel+=GetPixelAlpha(image,r)*r[i]; gamma+=GetPixelAlpha(image,r); } - gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma); + gamma=PerceptibleReciprocal(gamma); SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q); } p+=GetPixelChannels(image); @@ -3065,7 +2860,7 @@ MagickExport Image *RadialBlurImage(const Image *image, proceed; #if defined(MAGICKCORE_OPENMP_SUPPORT) - #pragma omp critical (MagickCore_RadialBlurImage) + #pragma omp critical (MagickCore_RadialBlurImage) #endif proceed=SetImageProgress(image,BlurImageTag,progress++,image->rows); if (proceed == MagickFalse) @@ -3073,9 +2868,10 @@ MagickExport Image *RadialBlurImage(const Image *image, } } blur_view=DestroyCacheView(blur_view); + radial_view=DestroyCacheView(radial_view); image_view=DestroyCacheView(image_view); - cos_theta=(MagickRealType *) RelinquishMagickMemory(cos_theta); - sin_theta=(MagickRealType *) RelinquishMagickMemory(sin_theta); + cos_theta=(double *) RelinquishMagickMemory(cos_theta); + sin_theta=(double *) RelinquishMagickMemory(sin_theta); if (status == MagickFalse) blur_image=DestroyImage(blur_image); return(blur_image); @@ -3099,8 +2895,7 @@ MagickExport Image *RadialBlurImage(const Image *image, % The format of the SelectiveBlurImage method is: % % Image *SelectiveBlurImage(const Image *image,const double radius, -% const double sigma,const double threshold,const double bias, -% ExceptionInfo *exception) +% const double sigma,const double threshold,ExceptionInfo *exception) % % A description of each parameter follows: % @@ -3114,26 +2909,22 @@ MagickExport Image *RadialBlurImage(const Image *image, % o threshold: only pixels within this contrast threshold are included % in the blur operation. % -% o bias: the bias. -% % o exception: return any errors or warnings in this structure. % */ -MagickExport Image *SelectiveBlurImage(const Image *image, - const double radius,const double sigma,const double threshold, - const double bias,ExceptionInfo *exception) +MagickExport Image *SelectiveBlurImage(const Image *image,const double radius, + const double sigma,const double threshold,ExceptionInfo *exception) { #define SelectiveBlurImageTag "SelectiveBlur/Image" CacheView *blur_view, - *image_view; - - double - *kernel; + *image_view, + *luminance_view; Image - *blur_image; + *blur_image, + *luminance_image; MagickBooleanType status; @@ -3141,6 +2932,9 @@ MagickExport Image *SelectiveBlurImage(const Image *image, MagickOffsetType progress; + MagickRealType + *kernel; + register ssize_t i; @@ -3164,15 +2958,16 @@ MagickExport Image *SelectiveBlurImage(const Image *image, assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickSignature); width=GetOptimalKernelWidth1D(radius,sigma); - kernel=(double *) AcquireQuantumMemory((size_t) width,width*sizeof(*kernel)); - if (kernel == (double *) NULL) + kernel=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory((size_t) + width,width*sizeof(*kernel))); + if (kernel == (MagickRealType *) NULL) ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); j=(ssize_t) width/2; i=0; for (v=(-j); v <= j; v++) { for (u=(-j); u <= j; u++) - kernel[i++]=(double) (exp(-((double) u*u+v*v)/(2.0*MagickSigma* + kernel[i++]=(MagickRealType) (exp(-((double) u*u+v*v)/(2.0*MagickSigma* MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma)); } if (image->debug != MagickFalse) @@ -3181,7 +2976,7 @@ MagickExport Image *SelectiveBlurImage(const Image *image, format[MaxTextExtent], *message; - register const double + register const MagickRealType *k; ssize_t @@ -3200,7 +2995,7 @@ MagickExport Image *SelectiveBlurImage(const Image *image, (void) ConcatenateString(&message,format); for (u=0; u < (ssize_t) width; u++) { - (void) FormatLocaleString(format,MaxTextExtent,"%+f ",*k++); + (void) FormatLocaleString(format,MaxTextExtent,"%+f ",(double) *k++); (void) ConcatenateString(&message,format); } (void) LogMagickEvent(TransformEvent,GetMagickModule(),"%s",message); @@ -3213,6 +3008,22 @@ MagickExport Image *SelectiveBlurImage(const Image *image, if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse) { blur_image=DestroyImage(blur_image); + kernel=(MagickRealType *) RelinquishAlignedMemory(kernel); + return((Image *) NULL); + } + luminance_image=CloneImage(image,0,0,MagickTrue,exception); + if (luminance_image == (Image *) NULL) + { + blur_image=DestroyImage(blur_image); + kernel=(MagickRealType *) RelinquishAlignedMemory(kernel); + return((Image *) NULL); + } + status=TransformImageColorspace(luminance_image,GRAYColorspace,exception); + if (status == MagickFalse) + { + luminance_image=DestroyImage(luminance_image); + blur_image=DestroyImage(blur_image); + kernel=(MagickRealType *) RelinquishAlignedMemory(kernel); return((Image *) NULL); } /* @@ -3222,10 +3033,12 @@ MagickExport Image *SelectiveBlurImage(const Image *image, progress=0; center=(ssize_t) (GetPixelChannels(image)*(image->columns+width)*(width/2L)+ GetPixelChannels(image)*(width/2L)); - image_view=AcquireCacheView(image); - blur_view=AcquireCacheView(blur_image); + image_view=AcquireVirtualCacheView(image,exception); + luminance_view=AcquireVirtualCacheView(luminance_image,exception); + blur_view=AcquireAuthenticCacheView(blur_image,exception); #if defined(MAGICKCORE_OPENMP_SUPPORT) - #pragma omp parallel for schedule(dynamic,4) shared(progress,status) + #pragma omp parallel for schedule(static,4) shared(progress,status) \ + dynamic_number_threads(image,image->columns,image->rows,1) #endif for (y=0; y < (ssize_t) image->rows; y++) { @@ -3236,6 +3049,7 @@ MagickExport Image *SelectiveBlurImage(const Image *image, sync; register const Quantum + *restrict l, *restrict p; register Quantum @@ -3248,7 +3062,9 @@ MagickExport Image *SelectiveBlurImage(const Image *image, continue; p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y-(ssize_t) (width/2L),image->columns+width,width,exception); - q=GetCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1, + l=GetCacheViewVirtualPixels(luminance_view,-((ssize_t) width/2L),y-(ssize_t) + (width/2L),luminance_image->columns+width,width,exception); + q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1, exception); if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) { @@ -3257,15 +3073,18 @@ MagickExport Image *SelectiveBlurImage(const Image *image, } for (x=0; x < (ssize_t) image->columns; x++) { + double + intensity; + register ssize_t i; + intensity=GetPixelIntensity(image,p+center); for (i=0; i < (ssize_t) GetPixelChannels(image); i++) { - MagickRealType + double alpha, gamma, - intensity, pixel; PixelChannel @@ -3275,10 +3094,11 @@ MagickExport Image *SelectiveBlurImage(const Image *image, blur_traits, traits; - register const double + register const MagickRealType *restrict k; register const Quantum + *restrict luminance_pixels, *restrict pixels; register ssize_t @@ -3287,21 +3107,22 @@ MagickExport Image *SelectiveBlurImage(const Image *image, ssize_t v; - traits=GetPixelChannelMapTraits(image,(PixelChannel) i); - channel=GetPixelChannelMapChannel(image,(PixelChannel) i); - blur_traits=GetPixelChannelMapTraits(blur_image,channel); + channel=GetPixelChannelChannel(image,i); + traits=GetPixelChannelTraits(image,channel); + blur_traits=GetPixelChannelTraits(blur_image,channel); if ((traits == UndefinedPixelTrait) || (blur_traits == UndefinedPixelTrait)) continue; - if ((blur_traits & CopyPixelTrait) != 0) + if (((blur_traits & CopyPixelTrait) != 0) || + (GetPixelMask(image,p) != 0)) { SetPixelChannel(blur_image,channel,p[center+i],q); continue; } k=kernel; - pixel=bias; + pixel=0.0; pixels=p; - intensity=(MagickRealType) GetPixelIntensity(image,p+center); + luminance_pixels=l; gamma=0.0; if ((blur_traits & BlendPixelTrait) == 0) { @@ -3309,7 +3130,8 @@ MagickExport Image *SelectiveBlurImage(const Image *image, { for (u=0; u < (ssize_t) width; u++) { - contrast=GetPixelIntensity(image,pixels)-intensity; + contrast=GetPixelIntensity(luminance_image,luminance_pixels)- + intensity; if (fabs(contrast) < threshold) { pixel+=(*k)*pixels[i]; @@ -3317,15 +3139,18 @@ MagickExport Image *SelectiveBlurImage(const Image *image, } k++; pixels+=GetPixelChannels(image); + luminance_pixels+=GetPixelChannels(luminance_image); } pixels+=image->columns*GetPixelChannels(image); + luminance_pixels+=luminance_image->columns* + GetPixelChannels(luminance_image); } if (fabs((double) gamma) < MagickEpsilon) { SetPixelChannel(blur_image,channel,p[center+i],q); continue; } - gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma); + gamma=PerceptibleReciprocal(gamma); SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q); continue; } @@ -3336,25 +3161,29 @@ MagickExport Image *SelectiveBlurImage(const Image *image, contrast=GetPixelIntensity(image,pixels)-intensity; if (fabs(contrast) < threshold) { - alpha=(MagickRealType) (QuantumScale* + alpha=(double) (QuantumScale* GetPixelAlpha(image,pixels)); pixel+=(*k)*alpha*pixels[i]; gamma+=(*k)*alpha; } k++; pixels+=GetPixelChannels(image); + luminance_pixels+=GetPixelChannels(luminance_image); } pixels+=image->columns*GetPixelChannels(image); + luminance_pixels+=luminance_image->columns* + GetPixelChannels(luminance_image); } if (fabs((double) gamma) < MagickEpsilon) { SetPixelChannel(blur_image,channel,p[center+i],q); continue; } - gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma); + gamma=PerceptibleReciprocal(gamma); SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q); } p+=GetPixelChannels(image); + l+=GetPixelChannels(luminance_image); q+=GetPixelChannels(blur_image); } sync=SyncCacheViewAuthenticPixels(blur_view,exception); @@ -3366,7 +3195,7 @@ MagickExport Image *SelectiveBlurImage(const Image *image, proceed; #if defined(MAGICKCORE_OPENMP_SUPPORT) - #pragma omp critical (MagickCore_SelectiveBlurImage) + #pragma omp critical (MagickCore_SelectiveBlurImage) #endif proceed=SetImageProgress(image,SelectiveBlurImageTag,progress++, image->rows); @@ -3377,7 +3206,8 @@ MagickExport Image *SelectiveBlurImage(const Image *image, blur_image->type=image->type; blur_view=DestroyCacheView(blur_view); image_view=DestroyCacheView(image_view); - kernel=(double *) RelinquishMagickMemory(kernel); + luminance_image=DestroyImage(luminance_image); + kernel=(MagickRealType *) RelinquishAlignedMemory(kernel); if (status == MagickFalse) blur_image=DestroyImage(blur_image); return(blur_image); @@ -3469,14 +3299,15 @@ MagickExport Image *ShadeImage(const Image *image,const MagickBooleanType gray, */ status=MagickTrue; progress=0; - image_view=AcquireCacheView(image); - shade_view=AcquireCacheView(shade_image); + image_view=AcquireVirtualCacheView(image,exception); + shade_view=AcquireAuthenticCacheView(shade_image,exception); #if defined(MAGICKCORE_OPENMP_SUPPORT) - #pragma omp parallel for schedule(dynamic,4) shared(progress,status) + #pragma omp parallel for schedule(static,4) shared(progress,status) \ + dynamic_number_threads(image,image->columns,image->rows,1) #endif for (y=0; y < (ssize_t) image->rows; y++) { - MagickRealType + double distance, normal_distance, shade; @@ -3555,13 +3386,14 @@ MagickExport Image *ShadeImage(const Image *image,const MagickBooleanType gray, shade_traits, traits; - traits=GetPixelChannelMapTraits(image,(PixelChannel) i); - channel=GetPixelChannelMapChannel(image,(PixelChannel) i); - shade_traits=GetPixelChannelMapTraits(shade_image,channel); + channel=GetPixelChannelChannel(image,i); + traits=GetPixelChannelTraits(image,channel); + shade_traits=GetPixelChannelTraits(shade_image,channel); if ((traits == UndefinedPixelTrait) || (shade_traits == UndefinedPixelTrait)) continue; - if ((shade_traits & CopyPixelTrait) != 0) + if (((shade_traits & CopyPixelTrait) != 0) || + (GetPixelMask(image,p) != 0)) { SetPixelChannel(shade_image,channel,center[i],q); continue; @@ -3587,7 +3419,7 @@ MagickExport Image *ShadeImage(const Image *image,const MagickBooleanType gray, proceed; #if defined(MAGICKCORE_OPENMP_SUPPORT) - #pragma omp critical (MagickCore_ShadeImage) + #pragma omp critical (MagickCore_ShadeImage) #endif proceed=SetImageProgress(image,ShadeImageTag,progress++,image->rows); if (proceed == MagickFalse) @@ -3625,7 +3457,7 @@ MagickExport Image *ShadeImage(const Image *image,const MagickBooleanType gray, % The format of the SharpenImage method is: % % Image *SharpenImage(const Image *image,const double radius, -% const double sigma,const double bias,ExceptionInfo *exception) +% const double sigma,ExceptionInfo *exception) % % A description of each parameter follows: % @@ -3636,13 +3468,11 @@ MagickExport Image *ShadeImage(const Image *image,const MagickBooleanType gray, % % o sigma: the standard deviation of the Laplacian, in pixels. % -% o bias: bias. -% % o exception: return any errors or warnings in this structure. % */ MagickExport Image *SharpenImage(const Image *image,const double radius, - const double sigma,const double bias,ExceptionInfo *exception) + const double sigma,ExceptionInfo *exception) { double normalize; @@ -3677,11 +3507,11 @@ MagickExport Image *SharpenImage(const Image *image,const double radius, (void) ResetMagickMemory(kernel_info,0,sizeof(*kernel_info)); kernel_info->width=width; kernel_info->height=width; - kernel_info->bias=bias; kernel_info->signature=MagickSignature; - kernel_info->values=(double *) AcquireAlignedMemory(kernel_info->width, - kernel_info->width*sizeof(*kernel_info->values)); - if (kernel_info->values == (double *) NULL) + kernel_info->values=(MagickRealType *) MagickAssumeAligned( + AcquireAlignedMemory(kernel_info->width,kernel_info->width* + sizeof(*kernel_info->values))); + if (kernel_info->values == (MagickRealType *) NULL) { kernel_info=DestroyKernelInfo(kernel_info); ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); @@ -3693,7 +3523,7 @@ MagickExport Image *SharpenImage(const Image *image,const double radius, { for (u=(-j); u <= j; u++) { - kernel_info->values[i]=(double) (-exp(-((double) u*u+v*v)/(2.0* + kernel_info->values[i]=(MagickRealType) (-exp(-((double) u*u+v*v)/(2.0* MagickSigma*MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma)); normalize+=kernel_info->values[i]; i++; @@ -3762,6 +3592,11 @@ MagickExport Image *SpreadImage(const Image *image,const double radius, ssize_t y; +#if defined(MAGICKCORE_OPENMP_SUPPORT) + unsigned long + key; +#endif + /* Initialize spread image attributes. */ @@ -3787,10 +3622,14 @@ MagickExport Image *SpreadImage(const Image *image,const double radius, progress=0; width=GetOptimalKernelWidth1D(radius,0.5); random_info=AcquireRandomInfoThreadSet(); - image_view=AcquireCacheView(image); - spread_view=AcquireCacheView(spread_image); #if defined(MAGICKCORE_OPENMP_SUPPORT) - #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1) + key=GetRandomSecretKey(random_info[0]); +#endif + image_view=AcquireVirtualCacheView(image,exception); + spread_view=AcquireAuthenticCacheView(spread_image,exception); +#if defined(MAGICKCORE_OPENMP_SUPPORT) + #pragma omp parallel for schedule(static,4) shared(progress,status) \ + dynamic_number_threads(image,image->columns,image->rows,key == ~0UL) #endif for (y=0; y < (ssize_t) image->rows; y++) { @@ -3835,7 +3674,7 @@ MagickExport Image *SpreadImage(const Image *image,const double radius, proceed; #if defined(MAGICKCORE_OPENMP_SUPPORT) - #pragma omp critical (MagickCore_SpreadImage) + #pragma omp critical (MagickCore_SpreadImage) #endif proceed=SetImageProgress(image,SpreadImageTag,progress++,image->rows); if (proceed == MagickFalse) @@ -3853,688 +3692,6 @@ MagickExport Image *SpreadImage(const Image *image,const double radius, % % % % % % -% S t a t i s t i c I m a g e % -% % -% % -% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% -% StatisticImage() makes each pixel the min / max / median / mode / etc. of -% the neighborhood of the specified width and height. -% -% The format of the StatisticImage method is: -% -% Image *StatisticImage(const Image *image,const StatisticType type, -% const size_t width,const size_t height,ExceptionInfo *exception) -% -% A description of each parameter follows: -% -% o image: the image. -% -% o type: the statistic type (median, mode, etc.). -% -% o width: the width of the pixel neighborhood. -% -% o height: the height of the pixel neighborhood. -% -% o exception: return any errors or warnings in this structure. -% -*/ - -typedef struct _SkipNode -{ - size_t - next[9], - count, - signature; -} SkipNode; - -typedef struct _SkipList -{ - ssize_t - level; - - SkipNode - *nodes; -} SkipList; - -typedef struct _PixelList -{ - size_t - length, - seed; - - SkipList - skip_list; - - size_t - signature; -} PixelList; - -static PixelList *DestroyPixelList(PixelList *pixel_list) -{ - if (pixel_list == (PixelList *) NULL) - return((PixelList *) NULL); - if (pixel_list->skip_list.nodes != (SkipNode *) NULL) - pixel_list->skip_list.nodes=(SkipNode *) RelinquishMagickMemory( - pixel_list->skip_list.nodes); - pixel_list=(PixelList *) RelinquishMagickMemory(pixel_list); - return(pixel_list); -} - -static PixelList **DestroyPixelListThreadSet(PixelList **pixel_list) -{ - register ssize_t - i; - - assert(pixel_list != (PixelList **) NULL); - for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++) - if (pixel_list[i] != (PixelList *) NULL) - pixel_list[i]=DestroyPixelList(pixel_list[i]); - pixel_list=(PixelList **) RelinquishMagickMemory(pixel_list); - return(pixel_list); -} - -static PixelList *AcquirePixelList(const size_t width,const size_t height) -{ - PixelList - *pixel_list; - - pixel_list=(PixelList *) AcquireMagickMemory(sizeof(*pixel_list)); - if (pixel_list == (PixelList *) NULL) - return(pixel_list); - (void) ResetMagickMemory((void *) pixel_list,0,sizeof(*pixel_list)); - pixel_list->length=width*height; - pixel_list->skip_list.nodes=(SkipNode *) AcquireQuantumMemory(65537UL, - sizeof(*pixel_list->skip_list.nodes)); - if (pixel_list->skip_list.nodes == (SkipNode *) NULL) - return(DestroyPixelList(pixel_list)); - (void) ResetMagickMemory(pixel_list->skip_list.nodes,0,65537UL* - sizeof(*pixel_list->skip_list.nodes)); - pixel_list->signature=MagickSignature; - return(pixel_list); -} - -static PixelList **AcquirePixelListThreadSet(const size_t width, - const size_t height) -{ - PixelList - **pixel_list; - - register ssize_t - i; - - size_t - number_threads; - - number_threads=GetOpenMPMaximumThreads(); - pixel_list=(PixelList **) AcquireQuantumMemory(number_threads, - sizeof(*pixel_list)); - if (pixel_list == (PixelList **) NULL) - return((PixelList **) NULL); - (void) ResetMagickMemory(pixel_list,0,number_threads*sizeof(*pixel_list)); - for (i=0; i < (ssize_t) number_threads; i++) - { - pixel_list[i]=AcquirePixelList(width,height); - if (pixel_list[i] == (PixelList *) NULL) - return(DestroyPixelListThreadSet(pixel_list)); - } - return(pixel_list); -} - -static void AddNodePixelList(PixelList *pixel_list,const size_t color) -{ - register SkipList - *p; - - register ssize_t - level; - - size_t - search, - update[9]; - - /* - Initialize the node. - */ - p=(&pixel_list->skip_list); - p->nodes[color].signature=pixel_list->signature; - p->nodes[color].count=1; - /* - Determine where it belongs in the list. - */ - search=65536UL; - for (level=p->level; level >= 0; level--) - { - while (p->nodes[search].next[level] < color) - search=p->nodes[search].next[level]; - update[level]=search; - } - /* - Generate a pseudo-random level for this node. - */ - for (level=0; ; level++) - { - pixel_list->seed=(pixel_list->seed*42893621L)+1L; - if ((pixel_list->seed & 0x300) != 0x300) - break; - } - if (level > 8) - level=8; - if (level > (p->level+2)) - level=p->level+2; - /* - If we're raising the list's level, link back to the root node. - */ - while (level > p->level) - { - p->level++; - update[p->level]=65536UL; - } - /* - Link the node into the skip-list. - */ - do - { - p->nodes[color].next[level]=p->nodes[update[level]].next[level]; - p->nodes[update[level]].next[level]=color; - } while (level-- > 0); -} - -static Quantum GetMaximumPixelList(PixelList *pixel_list) -{ - register SkipList - *p; - - size_t - color, - maximum; - - ssize_t - count; - - /* - Find the maximum value for each of the color. - */ - p=(&pixel_list->skip_list); - color=65536L; - count=0; - maximum=p->nodes[color].next[0]; - do - { - color=p->nodes[color].next[0]; - if (color > maximum) - maximum=color; - count+=p->nodes[color].count; - } while (count < (ssize_t) pixel_list->length); - return(ScaleShortToQuantum((unsigned short) maximum)); -} - -static Quantum GetMeanPixelList(PixelList *pixel_list) -{ - MagickRealType - sum; - - register SkipList - *p; - - size_t - color; - - ssize_t - count; - - /* - Find the mean value for each of the color. - */ - p=(&pixel_list->skip_list); - color=65536L; - count=0; - sum=0.0; - do - { - color=p->nodes[color].next[0]; - sum+=(MagickRealType) p->nodes[color].count*color; - count+=p->nodes[color].count; - } while (count < (ssize_t) pixel_list->length); - sum/=pixel_list->length; - return(ScaleShortToQuantum((unsigned short) sum)); -} - -static Quantum GetMedianPixelList(PixelList *pixel_list) -{ - register SkipList - *p; - - size_t - color; - - ssize_t - count; - - /* - Find the median value for each of the color. - */ - p=(&pixel_list->skip_list); - color=65536L; - count=0; - do - { - color=p->nodes[color].next[0]; - count+=p->nodes[color].count; - } while (count <= (ssize_t) (pixel_list->length >> 1)); - return(ScaleShortToQuantum((unsigned short) color)); -} - -static Quantum GetMinimumPixelList(PixelList *pixel_list) -{ - register SkipList - *p; - - size_t - color, - minimum; - - ssize_t - count; - - /* - Find the minimum value for each of the color. - */ - p=(&pixel_list->skip_list); - count=0; - color=65536UL; - minimum=p->nodes[color].next[0]; - do - { - color=p->nodes[color].next[0]; - if (color < minimum) - minimum=color; - count+=p->nodes[color].count; - } while (count < (ssize_t) pixel_list->length); - return(ScaleShortToQuantum((unsigned short) minimum)); -} - -static Quantum GetModePixelList(PixelList *pixel_list) -{ - register SkipList - *p; - - size_t - color, - max_count, - mode; - - ssize_t - count; - - /* - Make each pixel the 'predominant color' of the specified neighborhood. - */ - p=(&pixel_list->skip_list); - color=65536L; - mode=color; - max_count=p->nodes[mode].count; - count=0; - do - { - color=p->nodes[color].next[0]; - if (p->nodes[color].count > max_count) - { - mode=color; - max_count=p->nodes[mode].count; - } - count+=p->nodes[color].count; - } while (count < (ssize_t) pixel_list->length); - return(ScaleShortToQuantum((unsigned short) mode)); -} - -static Quantum GetNonpeakPixelList(PixelList *pixel_list) -{ - register SkipList - *p; - - size_t - color, - next, - previous; - - ssize_t - count; - - /* - Finds the non peak value for each of the colors. - */ - p=(&pixel_list->skip_list); - color=65536L; - next=p->nodes[color].next[0]; - count=0; - do - { - previous=color; - color=next; - next=p->nodes[color].next[0]; - count+=p->nodes[color].count; - } while (count <= (ssize_t) (pixel_list->length >> 1)); - if ((previous == 65536UL) && (next != 65536UL)) - color=next; - else - if ((previous != 65536UL) && (next == 65536UL)) - color=previous; - return(ScaleShortToQuantum((unsigned short) color)); -} - -static Quantum GetStandardDeviationPixelList(PixelList *pixel_list) -{ - MagickRealType - sum, - sum_squared; - - register SkipList - *p; - - size_t - color; - - ssize_t - count; - - /* - Find the standard-deviation value for each of the color. - */ - p=(&pixel_list->skip_list); - color=65536L; - count=0; - sum=0.0; - sum_squared=0.0; - do - { - register ssize_t - i; - - color=p->nodes[color].next[0]; - sum+=(MagickRealType) p->nodes[color].count*color; - for (i=0; i < (ssize_t) p->nodes[color].count; i++) - sum_squared+=((MagickRealType) color)*((MagickRealType) color); - count+=p->nodes[color].count; - } while (count < (ssize_t) pixel_list->length); - sum/=pixel_list->length; - sum_squared/=pixel_list->length; - return(ScaleShortToQuantum((unsigned short) sqrt(sum_squared-(sum*sum)))); -} - -static inline void InsertPixelList(const Image *image,const Quantum pixel, - PixelList *pixel_list) -{ - size_t - signature; - - unsigned short - index; - - index=ScaleQuantumToShort(pixel); - signature=pixel_list->skip_list.nodes[index].signature; - if (signature == pixel_list->signature) - { - pixel_list->skip_list.nodes[index].count++; - return; - } - AddNodePixelList(pixel_list,index); -} - -static inline MagickRealType MagickAbsoluteValue(const MagickRealType x) -{ - if (x < 0) - return(-x); - return(x); -} - -static inline size_t MagickMax(const size_t x,const size_t y) -{ - if (x > y) - return(x); - return(y); -} - -static void ResetPixelList(PixelList *pixel_list) -{ - int - level; - - register SkipNode - *root; - - register SkipList - *p; - - /* - Reset the skip-list. - */ - p=(&pixel_list->skip_list); - root=p->nodes+65536UL; - p->level=0; - for (level=0; level < 9; level++) - root->next[level]=65536UL; - pixel_list->seed=pixel_list->signature++; -} - -MagickExport Image *StatisticImage(const Image *image,const StatisticType type, - const size_t width,const size_t height,ExceptionInfo *exception) -{ -#define StatisticImageTag "Statistic/Image" - - CacheView - *image_view, - *statistic_view; - - Image - *statistic_image; - - MagickBooleanType - status; - - MagickOffsetType - progress; - - PixelList - **restrict pixel_list; - - ssize_t - center, - y; - - /* - Initialize statistics image attributes. - */ - assert(image != (Image *) NULL); - assert(image->signature == MagickSignature); - if (image->debug != MagickFalse) - (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); - assert(exception != (ExceptionInfo *) NULL); - assert(exception->signature == MagickSignature); - statistic_image=CloneImage(image,image->columns,image->rows,MagickTrue, - exception); - if (statistic_image == (Image *) NULL) - return((Image *) NULL); - status=SetImageStorageClass(statistic_image,DirectClass,exception); - if (status == MagickFalse) - { - statistic_image=DestroyImage(statistic_image); - return((Image *) NULL); - } - pixel_list=AcquirePixelListThreadSet(MagickMax(width,1),MagickMax(height,1)); - if (pixel_list == (PixelList **) NULL) - { - statistic_image=DestroyImage(statistic_image); - ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); - } - /* - Make each pixel the min / max / median / mode / etc. of the neighborhood. - */ - center=(ssize_t) GetPixelChannels(image)*(image->columns+MagickMax(width,1))* - (MagickMax(height,1)/2L)+GetPixelChannels(image)*(MagickMax(width,1)/2L); - status=MagickTrue; - progress=0; - image_view=AcquireCacheView(image); - statistic_view=AcquireCacheView(statistic_image); -#if defined(MAGICKCORE_OPENMP_SUPPORT) - #pragma omp parallel for schedule(dynamic,4) shared(progress,status) -#endif - for (y=0; y < (ssize_t) statistic_image->rows; y++) - { - const int - id = GetOpenMPThreadId(); - - register const Quantum - *restrict p; - - register Quantum - *restrict q; - - register ssize_t - x; - - if (status == MagickFalse) - continue; - p=GetCacheViewVirtualPixels(image_view,-((ssize_t) MagickMax(width,1)/2L),y- - (ssize_t) (MagickMax(height,1)/2L),image->columns+MagickMax(width,1), - MagickMax(height,1),exception); - q=QueueCacheViewAuthenticPixels(statistic_view,0,y,statistic_image->columns, 1,exception); - if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) - { - status=MagickFalse; - continue; - } - for (x=0; x < (ssize_t) statistic_image->columns; x++) - { - register ssize_t - i; - - for (i=0; i < (ssize_t) GetPixelChannels(image); i++) - { - PixelChannel - channel; - - PixelTrait - statistic_traits, - traits; - - Quantum - pixel; - - register const Quantum - *restrict pixels; - - register ssize_t - u; - - ssize_t - v; - - traits=GetPixelChannelMapTraits(image,(PixelChannel) i); - channel=GetPixelChannelMapChannel(image,(PixelChannel) i); - statistic_traits=GetPixelChannelMapTraits(statistic_image,channel); - if ((traits == UndefinedPixelTrait) || - (statistic_traits == UndefinedPixelTrait)) - continue; - if ((statistic_traits & CopyPixelTrait) != 0) - { - SetPixelChannel(statistic_image,channel,p[center+i],q); - continue; - } - pixels=p; - ResetPixelList(pixel_list[id]); - for (v=0; v < (ssize_t) MagickMax(height,1); v++) - { - for (u=0; u < (ssize_t) MagickMax(width,1); u++) - { - InsertPixelList(image,pixels[i],pixel_list[id]); - pixels+=GetPixelChannels(image); - } - pixels+=image->columns*GetPixelChannels(image); - } - switch (type) - { - case GradientStatistic: - { - MagickRealType - maximum, - minimum; - - minimum=(MagickRealType) GetMinimumPixelList(pixel_list[id]); - maximum=(MagickRealType) GetMaximumPixelList(pixel_list[id]); - pixel=ClampToQuantum(MagickAbsoluteValue(maximum-minimum)); - break; - } - case MaximumStatistic: - { - pixel=GetMaximumPixelList(pixel_list[id]); - break; - } - case MeanStatistic: - { - pixel=GetMeanPixelList(pixel_list[id]); - break; - } - case MedianStatistic: - default: - { - pixel=GetMedianPixelList(pixel_list[id]); - break; - } - case MinimumStatistic: - { - pixel=GetMinimumPixelList(pixel_list[id]); - break; - } - case ModeStatistic: - { - pixel=GetModePixelList(pixel_list[id]); - break; - } - case NonpeakStatistic: - { - pixel=GetNonpeakPixelList(pixel_list[id]); - break; - } - case StandardDeviationStatistic: - { - pixel=GetStandardDeviationPixelList(pixel_list[id]); - break; - } - } - SetPixelChannel(statistic_image,channel,pixel,q); - } - p+=GetPixelChannels(image); - q+=GetPixelChannels(statistic_image); - } - if (SyncCacheViewAuthenticPixels(statistic_view,exception) == MagickFalse) - status=MagickFalse; - if (image->progress_monitor != (MagickProgressMonitor) NULL) - { - MagickBooleanType - proceed; - -#if defined(MAGICKCORE_OPENMP_SUPPORT) - #pragma omp critical (MagickCore_StatisticImage) -#endif - proceed=SetImageProgress(image,StatisticImageTag,progress++, - image->rows); - if (proceed == MagickFalse) - status=MagickFalse; - } - } - statistic_view=DestroyCacheView(statistic_view); - image_view=DestroyCacheView(image_view); - pixel_list=DestroyPixelListThreadSet(pixel_list); - return(statistic_image); -} - -/* -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% % -% % -% % % U n s h a r p M a s k I m a g e % % % % % @@ -4569,9 +3726,9 @@ MagickExport Image *StatisticImage(const Image *image,const StatisticType type, % o exception: return any errors or warnings in this structure. % */ -MagickExport Image *UnsharpMaskImage(const Image *image, - const double radius,const double sigma,const double amount, - const double threshold,ExceptionInfo *exception) +MagickExport Image *UnsharpMaskImage(const Image *image,const double radius, + const double sigma,const double amount,const double threshold, + ExceptionInfo *exception) { #define SharpenImageTag "Sharpen/Image" @@ -4588,7 +3745,7 @@ MagickExport Image *UnsharpMaskImage(const Image *image, MagickOffsetType progress; - MagickRealType + double quantum_threshold; ssize_t @@ -4599,19 +3756,20 @@ MagickExport Image *UnsharpMaskImage(const Image *image, if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); assert(exception != (ExceptionInfo *) NULL); - unsharp_image=BlurImage(image,radius,sigma,image->bias,exception); + unsharp_image=BlurImage(image,radius,sigma,exception); if (unsharp_image == (Image *) NULL) return((Image *) NULL); - quantum_threshold=(MagickRealType) QuantumRange*threshold; + quantum_threshold=(double) QuantumRange*threshold; /* Unsharp-mask image. */ status=MagickTrue; progress=0; - image_view=AcquireCacheView(image); - unsharp_view=AcquireCacheView(unsharp_image); + image_view=AcquireVirtualCacheView(image,exception); + unsharp_view=AcquireAuthenticCacheView(unsharp_image,exception); #if defined(MAGICKCORE_OPENMP_SUPPORT) - #pragma omp parallel for schedule(dynamic,4) shared(progress,status) + #pragma omp parallel for schedule(static,4) shared(progress,status) \ + dynamic_number_threads(image,image->columns,image->rows,1) #endif for (y=0; y < (ssize_t) image->rows; y++) { @@ -4627,7 +3785,7 @@ MagickExport Image *UnsharpMaskImage(const Image *image, if (status == MagickFalse) continue; p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); - q=GetCacheViewAuthenticPixels(unsharp_view,0,y,unsharp_image->columns,1, + q=QueueCacheViewAuthenticPixels(unsharp_view,0,y,unsharp_image->columns,1, exception); if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) { @@ -4641,7 +3799,7 @@ MagickExport Image *UnsharpMaskImage(const Image *image, for (i=0; i < (ssize_t) GetPixelChannels(image); i++) { - MagickRealType + double pixel; PixelChannel @@ -4651,22 +3809,23 @@ MagickExport Image *UnsharpMaskImage(const Image *image, traits, unsharp_traits; - traits=GetPixelChannelMapTraits(image,(PixelChannel) i); - channel=GetPixelChannelMapChannel(image,(PixelChannel) i); - unsharp_traits=GetPixelChannelMapTraits(unsharp_image,channel); + channel=GetPixelChannelChannel(image,i); + traits=GetPixelChannelTraits(image,channel); + unsharp_traits=GetPixelChannelTraits(unsharp_image,channel); if ((traits == UndefinedPixelTrait) || (unsharp_traits == UndefinedPixelTrait)) continue; - if ((unsharp_traits & CopyPixelTrait) != 0) + if (((unsharp_traits & CopyPixelTrait) != 0) || + (GetPixelMask(image,p) != 0)) { SetPixelChannel(unsharp_image,channel,p[i],q); continue; } - pixel=p[i]-(MagickRealType) GetPixelChannel(unsharp_image,channel,q); + pixel=p[i]-(double) GetPixelChannel(unsharp_image,channel,q); if (fabs(2.0*pixel) < quantum_threshold) - pixel=(MagickRealType) p[i]; + pixel=(double) p[i]; else - pixel=(MagickRealType) p[i]+amount*pixel; + pixel=(double) p[i]+amount*pixel; SetPixelChannel(unsharp_image,channel,ClampToQuantum(pixel),q); } p+=GetPixelChannels(image); @@ -4680,7 +3839,7 @@ MagickExport Image *UnsharpMaskImage(const Image *image, proceed; #if defined(MAGICKCORE_OPENMP_SUPPORT) - #pragma omp critical (MagickCore_UnsharpMaskImage) + #pragma omp critical (MagickCore_UnsharpMaskImage) #endif proceed=SetImageProgress(image,SharpenImageTag,progress++,image->rows); if (proceed == MagickFalse)