43#include "MagickCore/studio.h"
44#include "MagickCore/accelerate-private.h"
45#include "MagickCore/blob.h"
46#include "MagickCore/cache-view.h"
47#include "MagickCore/color.h"
48#include "MagickCore/color-private.h"
49#include "MagickCore/colorspace.h"
50#include "MagickCore/constitute.h"
51#include "MagickCore/decorate.h"
52#include "MagickCore/distort.h"
53#include "MagickCore/draw.h"
54#include "MagickCore/enhance.h"
55#include "MagickCore/exception.h"
56#include "MagickCore/exception-private.h"
57#include "MagickCore/effect.h"
58#include "MagickCore/fx.h"
59#include "MagickCore/gem.h"
60#include "MagickCore/gem-private.h"
61#include "MagickCore/geometry.h"
62#include "MagickCore/image-private.h"
63#include "MagickCore/list.h"
64#include "MagickCore/log.h"
65#include "MagickCore/matrix.h"
66#include "MagickCore/memory_.h"
67#include "MagickCore/memory-private.h"
68#include "MagickCore/monitor.h"
69#include "MagickCore/monitor-private.h"
70#include "MagickCore/montage.h"
71#include "MagickCore/morphology.h"
72#include "MagickCore/morphology-private.h"
73#include "MagickCore/paint.h"
74#include "MagickCore/pixel-accessor.h"
75#include "MagickCore/property.h"
76#include "MagickCore/quantize.h"
77#include "MagickCore/quantum.h"
78#include "MagickCore/quantum-private.h"
79#include "MagickCore/random_.h"
80#include "MagickCore/random-private.h"
81#include "MagickCore/resample.h"
82#include "MagickCore/resample-private.h"
83#include "MagickCore/resize.h"
84#include "MagickCore/resource_.h"
85#include "MagickCore/segment.h"
86#include "MagickCore/shear.h"
87#include "MagickCore/signature-private.h"
88#include "MagickCore/statistic.h"
89#include "MagickCore/string_.h"
90#include "MagickCore/thread-private.h"
91#include "MagickCore/transform.h"
92#include "MagickCore/threshold.h"
93#include "MagickCore/utility-private.h"
129MagickExport Image *AdaptiveBlurImage(
const Image *image,
const double radius,
130 const double sigma,ExceptionInfo *exception)
132#define AdaptiveBlurImageTag "Convolve/Image"
133#define MagickSigma (fabs(sigma) < MagickEpsilon ? MagickEpsilon : sigma)
162 assert(image != (
const Image *) NULL);
163 assert(image->signature == MagickCoreSignature);
164 assert(exception != (ExceptionInfo *) NULL);
165 assert(exception->signature == MagickCoreSignature);
166 if (IsEventLogging() != MagickFalse)
167 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
168 blur_image=CloneImage(image,0,0,MagickTrue,exception);
169 if (blur_image == (Image *) NULL)
170 return((Image *) NULL);
171 if (fabs(sigma) < MagickEpsilon)
173 if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
175 blur_image=DestroyImage(blur_image);
176 return((Image *) NULL);
181 edge_image=EdgeImage(image,radius,exception);
182 if (edge_image == (Image *) NULL)
184 blur_image=DestroyImage(blur_image);
185 return((Image *) NULL);
187 (void) AutoLevelImage(edge_image,exception);
188 gaussian_image=BlurImage(edge_image,radius,sigma,exception);
189 if (gaussian_image != (Image *) NULL)
191 edge_image=DestroyImage(edge_image);
192 edge_image=gaussian_image;
194 (void) AutoLevelImage(edge_image,exception);
198 width=GetOptimalKernelWidth2D(radius,sigma);
199 kernel=(
double **) MagickAssumeAligned(AcquireAlignedMemory((
size_t) width,
201 if (kernel == (
double **) NULL)
203 edge_image=DestroyImage(edge_image);
204 blur_image=DestroyImage(blur_image);
205 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
207 (void) memset(kernel,0,(
size_t) width*
sizeof(*kernel));
208 for (w=0; w < (ssize_t) width; w+=2)
216 kernel[w]=(
double *) MagickAssumeAligned(AcquireAlignedMemory(
217 (width-(
size_t) w),(width-(
size_t) w)*
sizeof(**kernel)));
218 if (kernel[w] == (
double *) NULL)
221 j=((ssize_t) width-w-1)/2;
223 for (v=(-j); v <= j; v++)
225 for (u=(-j); u <= j; u++)
227 kernel[w][k]=(double) (exp(-((
double) u*u+v*v)/(2.0*MagickSigma*
228 MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
229 normalize+=kernel[w][k];
233 kernel[w][(k-1)/2]+=(
double) (1.0-normalize);
234 if (sigma < MagickEpsilon)
235 kernel[w][(k-1)/2]=1.0;
237 if (w < (ssize_t) width)
239 for (w-=2; w >= 0; w-=2)
240 kernel[w]=(
double *) RelinquishAlignedMemory(kernel[w]);
241 kernel=(
double **) RelinquishAlignedMemory(kernel);
242 edge_image=DestroyImage(edge_image);
243 blur_image=DestroyImage(blur_image);
244 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
251 image_view=AcquireVirtualCacheView(image,exception);
252 edge_view=AcquireVirtualCacheView(edge_image,exception);
253 blur_view=AcquireAuthenticCacheView(blur_image,exception);
254#if defined(MAGICKCORE_OPENMP_SUPPORT)
255 #pragma omp parallel for schedule(static) shared(progress,status) \
256 magick_number_threads(image,blur_image,blur_image->rows,1)
258 for (y=0; y < (ssize_t) blur_image->rows; y++)
269 if (status == MagickFalse)
271 r=GetCacheViewVirtualPixels(edge_view,0,y,edge_image->columns,1,exception);
272 q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
274 if ((r == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
279 for (x=0; x < (ssize_t) blur_image->columns; x++)
291 j=CastDoubleToSsizeT(ceil((
double) width*(1.0-QuantumScale*
292 GetPixelIntensity(edge_image,r))-0.5));
296 if (j > (ssize_t) width)
300 p=GetCacheViewVirtualPixels(image_view,x-((ssize_t) width-j)/2L,y-
301 ((ssize_t) width-j)/2L,width-(
size_t) j,width-(
size_t) j,exception);
302 if (p == (
const Quantum *) NULL)
304 center=(ssize_t) (GetPixelChannels(image)*(width-(
size_t) j)*
305 ((width-(
size_t) j)/2L)+GetPixelChannels(image)*((width-(
size_t) j)/2));
306 for (i=0; i < (ssize_t) GetPixelChannels(blur_image); i++)
312 *magick_restrict pixels;
330 channel=GetPixelChannelChannel(image,i);
331 traits=GetPixelChannelTraits(image,channel);
332 blur_traits=GetPixelChannelTraits(blur_image,channel);
333 if ((traits == UndefinedPixelTrait) ||
334 (blur_traits == UndefinedPixelTrait))
336 if ((blur_traits & CopyPixelTrait) != 0)
338 SetPixelChannel(blur_image,channel,p[center+i],q);
345 if ((blur_traits & BlendPixelTrait) == 0)
350 for (v=0; v < ((ssize_t) width-j); v++)
352 for (u=0; u < ((ssize_t) width-j); u++)
354 pixel+=(*k)*(double) pixels[i];
357 pixels+=(ptrdiff_t) GetPixelChannels(image);
360 gamma=MagickSafeReciprocal(gamma);
361 SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
367 for (v=0; v < ((ssize_t) width-j); v++)
369 for (u=0; u < ((ssize_t) width-j); u++)
371 alpha=(double) (QuantumScale*(
double) GetPixelAlpha(image,pixels));
372 pixel+=(*k)*alpha*(double) pixels[i];
375 pixels+=(ptrdiff_t) GetPixelChannels(image);
378 gamma=MagickSafeReciprocal(gamma);
379 SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
381 q+=(ptrdiff_t) GetPixelChannels(blur_image);
382 r+=(ptrdiff_t) GetPixelChannels(edge_image);
384 if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
386 if (image->progress_monitor != (MagickProgressMonitor) NULL)
391#if defined(MAGICKCORE_OPENMP_SUPPORT)
395 proceed=SetImageProgress(image,AdaptiveBlurImageTag,progress,
397 if (proceed == MagickFalse)
401 blur_image->type=image->type;
402 blur_view=DestroyCacheView(blur_view);
403 edge_view=DestroyCacheView(edge_view);
404 image_view=DestroyCacheView(image_view);
405 edge_image=DestroyImage(edge_image);
406 for (w=0; w < (ssize_t) width; w+=2)
407 kernel[w]=(
double *) RelinquishAlignedMemory(kernel[w]);
408 kernel=(
double **) RelinquishAlignedMemory(kernel);
409 if (status == MagickFalse)
410 blur_image=DestroyImage(blur_image);
448MagickExport Image *AdaptiveSharpenImage(
const Image *image,
const double radius,
449 const double sigma,ExceptionInfo *exception)
451#define AdaptiveSharpenImageTag "Convolve/Image"
452#define MagickSigma (fabs(sigma) < MagickEpsilon ? MagickEpsilon : sigma)
481 assert(image != (
const Image *) NULL);
482 assert(image->signature == MagickCoreSignature);
483 assert(exception != (ExceptionInfo *) NULL);
484 assert(exception->signature == MagickCoreSignature);
485 if (IsEventLogging() != MagickFalse)
486 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
487 sharp_image=CloneImage(image,0,0,MagickTrue,exception);
488 if (sharp_image == (Image *) NULL)
489 return((Image *) NULL);
490 if (fabs(sigma) < MagickEpsilon)
492 if (SetImageStorageClass(sharp_image,DirectClass,exception) == MagickFalse)
494 sharp_image=DestroyImage(sharp_image);
495 return((Image *) NULL);
500 edge_image=EdgeImage(image,radius,exception);
501 if (edge_image == (Image *) NULL)
503 sharp_image=DestroyImage(sharp_image);
504 return((Image *) NULL);
506 (void) AutoLevelImage(edge_image,exception);
507 gaussian_image=BlurImage(edge_image,radius,sigma,exception);
508 if (gaussian_image != (Image *) NULL)
510 edge_image=DestroyImage(edge_image);
511 edge_image=gaussian_image;
513 (void) AutoLevelImage(edge_image,exception);
517 width=GetOptimalKernelWidth2D(radius,sigma);
518 kernel=(
double **) MagickAssumeAligned(AcquireAlignedMemory((
size_t)
519 width,
sizeof(*kernel)));
520 if (kernel == (
double **) NULL)
522 edge_image=DestroyImage(edge_image);
523 sharp_image=DestroyImage(sharp_image);
524 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
526 (void) memset(kernel,0,(
size_t) width*
sizeof(*kernel));
527 for (w=0; w < (ssize_t) width; w+=2)
535 kernel[w]=(
double *) MagickAssumeAligned(AcquireAlignedMemory((
size_t)
536 (width-(
size_t) w),(width-(
size_t) w)*
sizeof(**kernel)));
537 if (kernel[w] == (
double *) NULL)
540 j=((ssize_t) width-w-1)/2;
542 for (v=(-j); v <= j; v++)
544 for (u=(-j); u <= j; u++)
546 kernel[w][k]=(double) (-exp(-((
double) u*u+v*v)/(2.0*MagickSigma*
547 MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
548 normalize+=kernel[w][k];
552 kernel[w][(k-1)/2]=(
double) ((-2.0)*normalize);
553 if (sigma < MagickEpsilon)
554 kernel[w][(k-1)/2]=1.0;
556 if (w < (ssize_t) width)
558 for (w-=2; w >= 0; w-=2)
559 kernel[w]=(
double *) RelinquishAlignedMemory(kernel[w]);
560 kernel=(
double **) RelinquishAlignedMemory(kernel);
561 edge_image=DestroyImage(edge_image);
562 sharp_image=DestroyImage(sharp_image);
563 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
570 image_view=AcquireVirtualCacheView(image,exception);
571 edge_view=AcquireVirtualCacheView(edge_image,exception);
572 sharp_view=AcquireAuthenticCacheView(sharp_image,exception);
573#if defined(MAGICKCORE_OPENMP_SUPPORT)
574 #pragma omp parallel for schedule(static) shared(progress,status) \
575 magick_number_threads(image,sharp_image,sharp_image->rows,1)
577 for (y=0; y < (ssize_t) sharp_image->rows; y++)
588 if (status == MagickFalse)
590 r=GetCacheViewVirtualPixels(edge_view,0,y,edge_image->columns,1,exception);
591 q=QueueCacheViewAuthenticPixels(sharp_view,0,y,sharp_image->columns,1,
593 if ((r == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
598 for (x=0; x < (ssize_t) sharp_image->columns; x++)
610 j=CastDoubleToSsizeT(ceil((
double) width*(1.0-QuantumScale*
611 GetPixelIntensity(edge_image,r))-0.5));
615 if (j > (ssize_t) width)
619 p=GetCacheViewVirtualPixels(image_view,x-(((ssize_t) width-j)/2L),y-
620 (((ssize_t) width-j)/2L),width-(
size_t) j,width-(
size_t) j,exception);
621 if (p == (
const Quantum *) NULL)
623 center=(ssize_t) (GetPixelChannels(image)*(width-(
size_t) j)*
624 ((width-(
size_t) j)/2L)+GetPixelChannels(image)*((width-(
size_t) j)/2));
625 for (i=0; i < (ssize_t) GetPixelChannels(sharp_image); i++)
631 *magick_restrict pixels;
649 channel=GetPixelChannelChannel(image,i);
650 traits=GetPixelChannelTraits(image,channel);
651 sharp_traits=GetPixelChannelTraits(sharp_image,channel);
652 if ((traits == UndefinedPixelTrait) ||
653 (sharp_traits == UndefinedPixelTrait))
655 if ((sharp_traits & CopyPixelTrait) != 0)
657 SetPixelChannel(sharp_image,channel,p[center+i],q);
664 if ((sharp_traits & BlendPixelTrait) == 0)
669 for (v=0; v < ((ssize_t) width-j); v++)
671 for (u=0; u < ((ssize_t) width-j); u++)
673 pixel+=(*k)*(double) pixels[i];
676 pixels+=(ptrdiff_t) GetPixelChannels(image);
679 gamma=MagickSafeReciprocal(gamma);
680 SetPixelChannel(sharp_image,channel,ClampToQuantum(gamma*pixel),q);
686 for (v=0; v < ((ssize_t) width-j); v++)
688 for (u=0; u < ((ssize_t) width-j); u++)
690 alpha=(double) (QuantumScale*(
double) GetPixelAlpha(image,pixels));
691 pixel+=(*k)*alpha*(double) pixels[i];
694 pixels+=(ptrdiff_t) GetPixelChannels(image);
697 gamma=MagickSafeReciprocal(gamma);
698 SetPixelChannel(sharp_image,channel,ClampToQuantum(gamma*pixel),q);
700 q+=(ptrdiff_t) GetPixelChannels(sharp_image);
701 r+=(ptrdiff_t) GetPixelChannels(edge_image);
703 if (SyncCacheViewAuthenticPixels(sharp_view,exception) == MagickFalse)
705 if (image->progress_monitor != (MagickProgressMonitor) NULL)
710#if defined(MAGICKCORE_OPENMP_SUPPORT)
714 proceed=SetImageProgress(image,AdaptiveSharpenImageTag,progress,
716 if (proceed == MagickFalse)
720 sharp_image->type=image->type;
721 sharp_view=DestroyCacheView(sharp_view);
722 edge_view=DestroyCacheView(edge_view);
723 image_view=DestroyCacheView(image_view);
724 edge_image=DestroyImage(edge_image);
725 for (w=0; w < (ssize_t) width; w+=2)
726 kernel[w]=(
double *) RelinquishAlignedMemory(kernel[w]);
727 kernel=(
double **) RelinquishAlignedMemory(kernel);
728 if (status == MagickFalse)
729 sharp_image=DestroyImage(sharp_image);
766MagickExport Image *BlurImage(
const Image *image,
const double radius,
767 const double sigma,ExceptionInfo *exception)
770 geometry[MagickPathExtent];
778 assert(image != (
const Image *) NULL);
779 assert(image->signature == MagickCoreSignature);
780 assert(exception != (ExceptionInfo *) NULL);
781 assert(exception->signature == MagickCoreSignature);
782 if (IsEventLogging() != MagickFalse)
783 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
784#if defined(MAGICKCORE_OPENCL_SUPPORT)
785 blur_image=AccelerateBlurImage(image,radius,sigma,exception);
786 if (blur_image != (Image *) NULL)
789 (void) FormatLocaleString(geometry,MagickPathExtent,
790 "blur:%.17gx%.17g;blur:%.17gx%.17g+90",radius,sigma,radius,sigma);
791 kernel_info=AcquireKernelInfo(geometry,exception);
792 if (kernel_info == (KernelInfo *) NULL)
793 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
794 blur_image=ConvolveImage(image,kernel_info,exception);
795 kernel_info=DestroyKernelInfo(kernel_info);
847static inline double BlurDistance(
const ssize_t x,
const ssize_t y,
848 const ssize_t u,
const ssize_t v)
850 return(sqrt(((
double) x-u)*((
double) x-u)+((
double) y-v)*((
double) y-v)));
853static inline double BlurGaussian(
const double x,
const double sigma)
855 return(exp(-((
double) x*x)*MagickSafeReciprocal(2.0*sigma*sigma))*
856 MagickSafeReciprocal(Magick2PI*sigma*sigma));
859static double **DestroyBilateralTLS(
const size_t number_threads,
865 assert(weights != (
double **) NULL);
866 for (i=0; i <= (ssize_t) number_threads; i++)
867 if (weights[i] != (
double *) NULL)
868 weights[i]=(
double *) RelinquishMagickMemory(weights[i]);
869 weights=(
double **) RelinquishMagickMemory(weights);
873static double **AcquireBilateralTLS(
const size_t number_threads,
874 const size_t width,
const size_t height)
885 if (HeapOverflowSanityCheckGetSize(height,
sizeof(**weights),&count) != MagickFalse)
886 return((
double **) NULL);
887 weights=(
double **) AcquireQuantumMemory(number_threads+1,
sizeof(*weights));
888 if (weights == (
double **) NULL)
889 return((
double **) NULL);
890 (void) memset(weights,0,(number_threads+1)*
sizeof(*weights));
891 for (i=0; i <= (ssize_t) number_threads; i++)
893 weights[i]=(
double *) AcquireQuantumMemory(width,count);
894 if (weights[i] == (
double *) NULL)
895 return(DestroyBilateralTLS(number_threads,weights));
900MagickExport Image *BilateralBlurImage(
const Image *image,
const size_t width,
901 const size_t height,
const double intensity_sigma,
const double spatial_sigma,
902 ExceptionInfo *exception)
904#define MaxIntensity (255)
905#define BilateralBlurImageTag "Blur/Image"
912 intensity_gaussian[2*(MaxIntensity+1)],
935 assert(image != (
const Image *) NULL);
936 assert(image->signature == MagickCoreSignature);
937 assert(exception != (ExceptionInfo *) NULL);
938 assert(exception->signature == MagickCoreSignature);
939 if (IsEventLogging() != MagickFalse)
940 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
941 blur_image=CloneImage(image,0,0,MagickTrue,exception);
942 if (blur_image == (Image *) NULL)
943 return((Image *) NULL);
944 if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
946 blur_image=DestroyImage(blur_image);
947 return((Image *) NULL);
949 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
950 weights=AcquireBilateralTLS(number_threads,MagickMax(width,1),
951 MagickMax(height,1));
952 if (weights == (
double **) NULL)
954 blur_image=DestroyImage(blur_image);
955 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
957 for (w=(-MaxIntensity); w <= MaxIntensity; w++)
958 intensity_gaussian[w+MaxIntensity]=BlurGaussian((
double) w,intensity_sigma);
959 spatial_gaussian=weights[number_threads];
966 mid.x=(ssize_t) (MagickMax(width,1)/2L);
967 mid.y=(ssize_t) (MagickMax(height,1)/2L);
968 for (v=0; v < (ssize_t) MagickMax(height,1); v++)
973 for (u=0; u < (ssize_t) MagickMax(width,1); u++)
974 spatial_gaussian[n++]=BlurGaussian(BlurDistance(0,0,u-mid.x,v-mid.y),
983 image_view=AcquireVirtualCacheView(image,exception);
984 blur_view=AcquireAuthenticCacheView(blur_image,exception);
985#if defined(MAGICKCORE_OPENMP_SUPPORT)
986 #pragma omp parallel for schedule(static) shared(progress,status) \
987 magick_number_threads(image,blur_image,blur_image->rows,1)
989 for (y=0; y < (ssize_t) blur_image->rows; y++)
992 id = GetOpenMPThreadId();
1000 if (status == MagickFalse)
1002 q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
1004 if (q == (Quantum *) NULL)
1009 for (x=0; x < (ssize_t) blur_image->columns; x++)
1028 p=GetCacheViewVirtualPixels(image_view,x-mid.x,y-mid.y,MagickMax(width,1),
1029 MagickMax(height,1),exception);
1030 if (p == (
const Quantum *) NULL)
1032 p+=(ptrdiff_t) (GetPixelChannels(image)*MagickMax(width,1)*(
size_t) mid.y+
1033 GetPixelChannels(image)*(
size_t) mid.x);
1035 for (v=0; v < (ssize_t) MagickMax(height,1); v++)
1037 for (u=0; u < (ssize_t) MagickMax(width,1); u++)
1042 r=p-(ssize_t) (GetPixelChannels(image)*MagickMax(width,1)*
1043 (
size_t) (mid.y-v)+GetPixelChannels(image)*(
size_t) (mid.x-u));
1044 intensity=ScaleQuantumToChar((
const Quantum)
1045 GetPixelIntensity(image,r))-(double)
1046 ScaleQuantumToChar((
const Quantum) GetPixelIntensity(image,p));
1047 if ((intensity >= -MaxIntensity) && (intensity <= MaxIntensity))
1048 weights[id][n]=intensity_gaussian[(ssize_t) intensity+MaxIntensity]*
1049 spatial_gaussian[n];
1051 weights[id][n]=BlurGaussian(intensity,intensity_sigma)*
1052 BlurGaussian(BlurDistance(x,y,x+u-mid.x,y+v-mid.y),spatial_sigma);
1056 for (i=0; i < (ssize_t) GetPixelChannels(blur_image); i++)
1065 channel=GetPixelChannelChannel(image,i);
1066 traits=GetPixelChannelTraits(image,channel);
1067 blur_traits=GetPixelChannelTraits(blur_image,channel);
1068 if ((traits == UndefinedPixelTrait) ||
1069 (blur_traits == UndefinedPixelTrait))
1071 if ((blur_traits & CopyPixelTrait) != 0)
1073 SetPixelChannel(blur_image,channel,p[i],q);
1079 if ((blur_traits & BlendPixelTrait) == 0)
1084 for (v=0; v < (ssize_t) MagickMax(height,1); v++)
1086 for (u=0; u < (ssize_t) MagickMax(width,1); u++)
1088 r=p-(ssize_t) (GetPixelChannels(image)*MagickMax(width,1)*
1089 (
size_t) (mid.y-v)+GetPixelChannels(image)*(
size_t)
1091 pixel+=weights[id][n]*(double) r[i];
1092 gamma+=weights[id][n];
1096 SetPixelChannel(blur_image,channel,ClampToQuantum(
1097 MagickSafeReciprocal(gamma)*pixel),q);
1103 for (v=0; v < (ssize_t) MagickMax(height,1); v++)
1105 for (u=0; u < (ssize_t) MagickMax(width,1); u++)
1111 r=p-(ssize_t) (GetPixelChannels(image)*MagickMax(width,1)*(
size_t)
1112 (mid.y-v)+GetPixelChannels(image)*(
size_t) (mid.x-u));
1113 alpha=(double) (QuantumScale*(
double) GetPixelAlpha(image,p));
1114 beta=(double) (QuantumScale*(
double) GetPixelAlpha(image,r));
1115 pixel+=weights[id][n]*(double) r[i];
1116 gamma+=weights[id][n]*alpha*beta;
1120 SetPixelChannel(blur_image,channel,ClampToQuantum(
1121 MagickSafeReciprocal(gamma)*pixel),q);
1123 q+=(ptrdiff_t) GetPixelChannels(blur_image);
1125 if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
1127 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1132#if defined(MAGICKCORE_OPENMP_SUPPORT)
1136 proceed=SetImageProgress(image,BilateralBlurImageTag,progress,
1138 if (proceed == MagickFalse)
1142 blur_image->type=image->type;
1143 blur_view=DestroyCacheView(blur_view);
1144 image_view=DestroyCacheView(image_view);
1145 weights=DestroyBilateralTLS(number_threads,weights);
1146 if (status == MagickFalse)
1147 blur_image=DestroyImage(blur_image);
1178MagickExport Image *ConvolveImage(
const Image *image,
1179 const KernelInfo *kernel_info,ExceptionInfo *exception)
1184 convolve_image=MorphologyImage(image,ConvolveMorphology,1,kernel_info,
1186 return(convolve_image);
1219static void Hull(
const Image *image,
const ssize_t x_offset,
1220 const ssize_t y_offset,
const size_t columns,
const size_t rows,
1221 const int polarity,Quantum *magick_restrict f,Quantum *magick_restrict g)
1232 assert(image != (
const Image *) NULL);
1233 assert(image->signature == MagickCoreSignature);
1234 assert(f != (Quantum *) NULL);
1235 assert(g != (Quantum *) NULL);
1236 assert(columns <= (
size_t) (MAGICK_SSIZE_MAX-2));
1237 if (IsEventLogging() != MagickFalse)
1238 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1239 p=f+(ptrdiff_t) (columns+2);
1240 q=g+(ptrdiff_t) (columns+2);
1241 r=p+(ptrdiff_t) (y_offset*((ssize_t) columns+2)+x_offset);
1242#if defined(MAGICKCORE_OPENMP_SUPPORT)
1243 #pragma omp parallel for schedule(static) \
1244 magick_number_threads(image,image,rows,2)
1246 for (y=0; y < (ssize_t) rows; y++)
1255 i=(2*y+1)+y*(ssize_t) columns;
1257 for (x=0; x < (ssize_t) columns; x++)
1259 v=(MagickRealType) p[i];
1260 if ((MagickRealType) r[i] >= (v+(
double) ScaleCharToQuantum(2)))
1261 v+=(double) ScaleCharToQuantum(1);
1266 for (x=0; x < (ssize_t) columns; x++)
1268 v=(MagickRealType) p[i];
1269 if ((MagickRealType) r[i] <= (v-(
double) ScaleCharToQuantum(2)))
1270 v-=(double) ScaleCharToQuantum(1);
1275 p=f+(ptrdiff_t) (columns+2);
1276 q=g+(ptrdiff_t) (columns+2);
1277 r=q+(ptrdiff_t) (y_offset*((ssize_t) columns+2)+x_offset);
1278 s=q-(ptrdiff_t) (y_offset*((ssize_t) columns+2)+x_offset);
1279#if defined(MAGICKCORE_OPENMP_SUPPORT)
1280 #pragma omp parallel for schedule(static) \
1281 magick_number_threads(image,image,rows,2)
1283 for (y=0; y < (ssize_t) rows; y++)
1292 i=(2*y+1)+y*(ssize_t) columns;
1294 for (x=0; x < (ssize_t) columns; x++)
1296 v=(MagickRealType) q[i];
1297 if (((MagickRealType) s[i] >= (v+(
double) ScaleCharToQuantum(2))) &&
1298 ((MagickRealType) r[i] > v))
1299 v+=(double) ScaleCharToQuantum(1);
1304 for (x=0; x < (ssize_t) columns; x++)
1306 v=(MagickRealType) q[i];
1307 if (((MagickRealType) s[i] <= (v-(
double) ScaleCharToQuantum(2))) &&
1308 ((MagickRealType) r[i] < v))
1309 v-=(double) ScaleCharToQuantum(1);
1316MagickExport Image *DespeckleImage(
const Image *image,ExceptionInfo *exception)
1318#define DespeckleImageTag "Despeckle/Image"
1335 *magick_restrict buffer,
1336 *magick_restrict pixels;
1344 static const ssize_t
1345 X[4] = {0, 1, 1,-1},
1346 Y[4] = {1, 0, 1, 1};
1351 assert(image != (
const Image *) NULL);
1352 assert(image->signature == MagickCoreSignature);
1353 assert(exception != (ExceptionInfo *) NULL);
1354 assert(exception->signature == MagickCoreSignature);
1355 if (IsEventLogging() != MagickFalse)
1356 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1357#if defined(MAGICKCORE_OPENCL_SUPPORT)
1358 despeckle_image=AccelerateDespeckleImage(image,exception);
1359 if (despeckle_image != (Image *) NULL)
1360 return(despeckle_image);
1362 despeckle_image=CloneImage(image,0,0,MagickTrue,exception);
1363 if (despeckle_image == (Image *) NULL)
1364 return((Image *) NULL);
1365 status=SetImageStorageClass(despeckle_image,DirectClass,exception);
1366 if (status == MagickFalse)
1368 despeckle_image=DestroyImage(despeckle_image);
1369 return((Image *) NULL);
1374 if ((image->columns > (MAGICK_SIZE_MAX-2)) ||
1375 (image->rows > (MAGICK_SIZE_MAX-2)))
1377 despeckle_image=DestroyImage(despeckle_image);
1378 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1380 if (HeapOverflowSanityCheckGetSize(image->columns+2,image->rows+2,&length) != MagickFalse)
1382 despeckle_image=DestroyImage(despeckle_image);
1383 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1385 pixel_info=AcquireVirtualMemory(length,
sizeof(*pixels));
1386 buffer_info=AcquireVirtualMemory(length,
sizeof(*buffer));
1387 if ((pixel_info == (MemoryInfo *) NULL) ||
1388 (buffer_info == (MemoryInfo *) NULL))
1390 if (buffer_info != (MemoryInfo *) NULL)
1391 buffer_info=RelinquishVirtualMemory(buffer_info);
1392 if (pixel_info != (MemoryInfo *) NULL)
1393 pixel_info=RelinquishVirtualMemory(pixel_info);
1394 despeckle_image=DestroyImage(despeckle_image);
1395 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1397 pixels=(Quantum *) GetVirtualMemoryBlob(pixel_info);
1398 buffer=(Quantum *) GetVirtualMemoryBlob(buffer_info);
1403 image_view=AcquireVirtualCacheView(image,exception);
1404 despeckle_view=AcquireAuthenticCacheView(despeckle_image,exception);
1405 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1422 if (status == MagickFalse)
1424 channel=GetPixelChannelChannel(image,i);
1425 traits=GetPixelChannelTraits(image,channel);
1426 despeckle_traits=GetPixelChannelTraits(despeckle_image,channel);
1427 if ((traits == UndefinedPixelTrait) ||
1428 (despeckle_traits == UndefinedPixelTrait))
1430 if ((despeckle_traits & CopyPixelTrait) != 0)
1432 (void) memset(pixels,0,length*
sizeof(*pixels));
1433 j=(ssize_t) image->columns+2;
1434 for (y=0; y < (ssize_t) image->rows; y++)
1439 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1440 if (p == (
const Quantum *) NULL)
1446 for (x=0; x < (ssize_t) image->columns; x++)
1449 p+=(ptrdiff_t) GetPixelChannels(image);
1453 (void) memset(buffer,0,length*
sizeof(*buffer));
1454 for (k=0; k < 4; k++)
1456 Hull(image,X[k],Y[k],image->columns,image->rows,1,pixels,buffer);
1457 Hull(image,-X[k],-Y[k],image->columns,image->rows,1,pixels,buffer);
1458 Hull(image,-X[k],-Y[k],image->columns,image->rows,-1,pixels,buffer);
1459 Hull(image,X[k],Y[k],image->columns,image->rows,-1,pixels,buffer);
1461 j=(ssize_t) image->columns+2;
1462 for (y=0; y < (ssize_t) image->rows; y++)
1470 q=GetCacheViewAuthenticPixels(despeckle_view,0,y,despeckle_image->columns,
1472 if (q == (Quantum *) NULL)
1478 for (x=0; x < (ssize_t) image->columns; x++)
1480 SetPixelChannel(despeckle_image,channel,pixels[j++],q);
1481 q+=(ptrdiff_t) GetPixelChannels(despeckle_image);
1483 sync=SyncCacheViewAuthenticPixels(despeckle_view,exception);
1484 if (sync == MagickFalse)
1488 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1493 proceed=SetImageProgress(image,DespeckleImageTag,(MagickOffsetType) i,
1494 GetPixelChannels(image));
1495 if (proceed == MagickFalse)
1499 despeckle_view=DestroyCacheView(despeckle_view);
1500 image_view=DestroyCacheView(image_view);
1501 buffer_info=RelinquishVirtualMemory(buffer_info);
1502 pixel_info=RelinquishVirtualMemory(pixel_info);
1503 despeckle_image->type=image->type;
1504 if (status == MagickFalse)
1505 despeckle_image=DestroyImage(despeckle_image);
1506 return(despeckle_image);
1538MagickExport Image *EdgeImage(
const Image *image,
const double radius,
1539 ExceptionInfo *exception)
1553 assert(image != (
const Image *) NULL);
1554 assert(image->signature == MagickCoreSignature);
1555 assert(exception != (ExceptionInfo *) NULL);
1556 assert(exception->signature == MagickCoreSignature);
1557 if (IsEventLogging() != MagickFalse)
1558 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1559 width=GetOptimalKernelWidth1D(radius,0.5);
1560 kernel_info=AcquireKernelInfo((
const char *) NULL,exception);
1561 if (kernel_info == (KernelInfo *) NULL)
1562 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1563 (void) memset(kernel_info,0,
sizeof(*kernel_info));
1564 kernel_info->width=width;
1565 kernel_info->height=width;
1566 kernel_info->x=(ssize_t) (kernel_info->width-1)/2;
1567 kernel_info->y=(ssize_t) (kernel_info->height-1)/2;
1568 kernel_info->signature=MagickCoreSignature;
1569 kernel_info->values=(MagickRealType *) MagickAssumeAligned(
1570 AcquireAlignedMemory(kernel_info->width,kernel_info->height*
1571 sizeof(*kernel_info->values)));
1572 if (kernel_info->values == (MagickRealType *) NULL)
1574 kernel_info=DestroyKernelInfo(kernel_info);
1575 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1577 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
1578 kernel_info->values[i]=(-1.0);
1579 kernel_info->values[i/2]=(double) kernel_info->width*kernel_info->height-1.0;
1580 edge_image=ConvolveImage(image,kernel_info,exception);
1581 kernel_info=DestroyKernelInfo(kernel_info);
1618MagickExport Image *EmbossImage(
const Image *image,
const double radius,
1619 const double sigma,ExceptionInfo *exception)
1643 assert(image != (
const Image *) NULL);
1644 assert(image->signature == MagickCoreSignature);
1645 assert(exception != (ExceptionInfo *) NULL);
1646 assert(exception->signature == MagickCoreSignature);
1647 if (IsEventLogging() != MagickFalse)
1648 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1649 width=GetOptimalKernelWidth1D(radius,sigma);
1650 kernel_info=AcquireKernelInfo((
const char *) NULL,exception);
1651 if (kernel_info == (KernelInfo *) NULL)
1652 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1653 kernel_info->width=width;
1654 kernel_info->height=width;
1655 kernel_info->x=(ssize_t) (width-1)/2;
1656 kernel_info->y=(ssize_t) (width-1)/2;
1657 kernel_info->values=(MagickRealType *) MagickAssumeAligned(
1658 AcquireAlignedMemory(kernel_info->width,kernel_info->width*
1659 sizeof(*kernel_info->values)));
1660 if (kernel_info->values == (MagickRealType *) NULL)
1662 kernel_info=DestroyKernelInfo(kernel_info);
1663 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1665 j=(ssize_t) (kernel_info->width-1)/2;
1668 for (v=(-j); v <= j; v++)
1670 for (u=(-j); u <= j; u++)
1672 kernel_info->values[i]=(MagickRealType) (((u < 0) || (v < 0) ? -8.0 :
1673 8.0)*exp(-((
double) u*u+v*v)/(2.0*MagickSigma*MagickSigma))/
1674 (2.0*MagickPI*MagickSigma*MagickSigma));
1676 kernel_info->values[i]=0.0;
1682 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
1683 normalize+=kernel_info->values[i];
1684 gamma=MagickSafeReciprocal(normalize);
1685 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
1686 kernel_info->values[i]*=gamma;
1687 emboss_image=ConvolveImage(image,kernel_info,exception);
1688 kernel_info=DestroyKernelInfo(kernel_info);
1689 if (emboss_image != (Image *) NULL)
1690 (void) EqualizeImage(emboss_image,exception);
1691 return(emboss_image);
1727MagickExport Image *GaussianBlurImage(
const Image *image,
const double radius,
1728 const double sigma,ExceptionInfo *exception)
1731 geometry[MagickPathExtent];
1739 assert(image != (
const Image *) NULL);
1740 assert(image->signature == MagickCoreSignature);
1741 assert(exception != (ExceptionInfo *) NULL);
1742 assert(exception->signature == MagickCoreSignature);
1743 if (IsEventLogging() != MagickFalse)
1744 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1745 (void) FormatLocaleString(geometry,MagickPathExtent,
"gaussian:%.17gx%.17g",
1747 kernel_info=AcquireKernelInfo(geometry,exception);
1748 if (kernel_info == (KernelInfo *) NULL)
1749 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1750 blur_image=ConvolveImage(image,kernel_info,exception);
1751 kernel_info=DestroyKernelInfo(kernel_info);
1785static inline MagickRealType GetMeanLuma(
const Image *magick_restrict image,
1786 const double *magick_restrict pixel)
1788 return(0.212656*pixel[image->channel_map[RedPixelChannel].offset]+
1789 0.715158*pixel[image->channel_map[GreenPixelChannel].offset]+
1790 0.072186*pixel[image->channel_map[BluePixelChannel].offset]);
1793MagickExport Image *KuwaharaImage(
const Image *image,
const double radius,
1794 const double sigma,ExceptionInfo *exception)
1796#define KuwaharaImageTag "Kuwahara/Image"
1821 assert(image != (Image *) NULL);
1822 assert(image->signature == MagickCoreSignature);
1823 assert(exception != (ExceptionInfo *) NULL);
1824 assert(exception->signature == MagickCoreSignature);
1825 if (IsEventLogging() != MagickFalse)
1826 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1827 width=(size_t) radius+1;
1828 gaussian_image=BlurImage(image,radius,sigma,exception);
1829 if (gaussian_image == (Image *) NULL)
1830 return((Image *) NULL);
1831 kuwahara_image=CloneImage(image,0,0,MagickTrue,exception);
1832 if (kuwahara_image == (Image *) NULL)
1834 gaussian_image=DestroyImage(gaussian_image);
1835 return((Image *) NULL);
1837 if (SetImageStorageClass(kuwahara_image,DirectClass,exception) == MagickFalse)
1839 gaussian_image=DestroyImage(gaussian_image);
1840 kuwahara_image=DestroyImage(kuwahara_image);
1841 return((Image *) NULL);
1848 image_view=AcquireVirtualCacheView(gaussian_image,exception);
1849 kuwahara_view=AcquireAuthenticCacheView(kuwahara_image,exception);
1850#if defined(MAGICKCORE_OPENMP_SUPPORT)
1851 #pragma omp parallel for schedule(static) shared(progress,status) \
1852 magick_number_threads(image,kuwahara_image,gaussian_image->rows,1)
1854 for (y=0; y < (ssize_t) gaussian_image->rows; y++)
1862 if (status == MagickFalse)
1864 q=QueueCacheViewAuthenticPixels(kuwahara_view,0,y,kuwahara_image->columns,1,
1866 if (q == (Quantum *) NULL)
1871 for (x=0; x < (ssize_t) gaussian_image->columns; x++)
1886 min_variance=MagickMaximumValue;
1887 SetGeometry(gaussian_image,&target);
1888 quadrant.width=width;
1889 quadrant.height=width;
1890 for (i=0; i < 4; i++)
1896 mean[MaxPixelChannels],
1911 quadrant.x=x-(ssize_t) (width-1);
1912 quadrant.y=y-(ssize_t) (width-1);
1917 quadrant.y=y-(ssize_t) (width-1);
1922 quadrant.x=x-(ssize_t) (width-1);
1929 p=GetCacheViewVirtualPixels(image_view,quadrant.x,quadrant.y,
1930 quadrant.width,quadrant.height,exception);
1931 if (p == (
const Quantum *) NULL)
1933 for (j=0; j < (ssize_t) GetPixelChannels(gaussian_image); j++)
1936 for (n=0; n < (ssize_t) (width*width); n++)
1938 for (j=0; j < (ssize_t) GetPixelChannels(gaussian_image); j++)
1939 mean[j]+=(
double) k[j];
1940 k+=(ptrdiff_t) GetPixelChannels(gaussian_image);
1942 for (j=0; j < (ssize_t) GetPixelChannels(gaussian_image); j++)
1943 mean[j]/=(
double) (width*width);
1946 for (n=0; n < (ssize_t) (width*width); n++)
1951 luma=GetPixelLuma(gaussian_image,k);
1952 variance+=(luma-GetMeanLuma(gaussian_image,mean))*
1953 (luma-GetMeanLuma(gaussian_image,mean));
1954 k+=(ptrdiff_t) GetPixelChannels(gaussian_image);
1956 if (variance < min_variance)
1958 min_variance=variance;
1967 status=InterpolatePixelChannels(gaussian_image,image_view,kuwahara_image,
1968 UndefinedInterpolatePixel,(
double) target.x+target.width/2.0,(
double)
1969 target.y+target.height/2.0,q,exception);
1970 if (status == MagickFalse)
1972 q+=(ptrdiff_t) GetPixelChannels(kuwahara_image);
1974 if (SyncCacheViewAuthenticPixels(kuwahara_view,exception) == MagickFalse)
1976 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1981#if defined(MAGICKCORE_OPENMP_SUPPORT)
1985 proceed=SetImageProgress(image,KuwaharaImageTag,progress,image->rows);
1986 if (proceed == MagickFalse)
1990 kuwahara_view=DestroyCacheView(kuwahara_view);
1991 image_view=DestroyCacheView(image_view);
1992 gaussian_image=DestroyImage(gaussian_image);
1993 if (status == MagickFalse)
1994 kuwahara_image=DestroyImage(kuwahara_image);
1995 return(kuwahara_image);
2031MagickExport Image *LocalContrastImage(
const Image *image,
const double radius,
2032 const double strength,ExceptionInfo *exception)
2034#define LocalContrastImageTag "LocalContrast/Image"
2064 assert(image != (
const Image *) NULL);
2065 assert(image->signature == MagickCoreSignature);
2066 assert(exception != (ExceptionInfo *) NULL);
2067 assert(exception->signature == MagickCoreSignature);
2068 if (IsEventLogging() != MagickFalse)
2069 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2070#if defined(MAGICKCORE_OPENCL_SUPPORT)
2071 contrast_image=AccelerateLocalContrastImage(image,radius,strength,exception);
2072 if (contrast_image != (Image *) NULL)
2073 return(contrast_image);
2075 contrast_image=CloneImage(image,0,0,MagickTrue,exception);
2076 if (contrast_image == (Image *) NULL)
2077 return((Image *) NULL);
2078 if (SetImageStorageClass(contrast_image,DirectClass,exception) == MagickFalse)
2080 contrast_image=DestroyImage(contrast_image);
2081 return((Image *) NULL);
2083 image_view=AcquireVirtualCacheView(image,exception);
2084 contrast_view=AcquireAuthenticCacheView(contrast_image,exception);
2085 scanLineSize=(ssize_t) MagickMax(image->columns,image->rows);
2086 width=(ssize_t) (scanLineSize*0.002*fabs(radius));
2087 scanLineSize+=(2*width);
2088 scanline_info=AcquireVirtualMemory(GetOpenMPMaximumThreads()*
2089 (
size_t) scanLineSize,
sizeof(*scanline));
2090 if (scanline_info == (MemoryInfo *) NULL)
2092 contrast_view=DestroyCacheView(contrast_view);
2093 image_view=DestroyCacheView(image_view);
2094 contrast_image=DestroyImage(contrast_image);
2095 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2097 scanline=(
float *) GetVirtualMemoryBlob(scanline_info);
2101 interImage_info=AcquireVirtualMemory(image->rows*(image->columns+(
size_t)
2102 (2*width)),
sizeof(*interImage));
2103 if (interImage_info == (MemoryInfo *) NULL)
2105 scanline_info=RelinquishVirtualMemory(scanline_info);
2106 contrast_view=DestroyCacheView(contrast_view);
2107 image_view=DestroyCacheView(image_view);
2108 contrast_image=DestroyImage(contrast_image);
2109 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2111 interImage=(
float *) GetVirtualMemoryBlob(interImage_info);
2112 totalWeight=(float) ((width+1)*(width+1));
2121#if defined(MAGICKCORE_OPENMP_SUPPORT)
2122#pragma omp parallel for schedule(static) \
2123 magick_number_threads(image,image,image->columns,1)
2125 for (x=0; x < (ssize_t) image->columns; x++)
2128 id = GetOpenMPThreadId();
2144 if (status == MagickFalse)
2147 pixels+=
id*scanLineSize;
2149 p=GetCacheViewVirtualPixels(image_view,x,-(ssize_t) width,1,
2150 image->rows+(
size_t) (2*width),exception);
2151 if (p == (
const Quantum *) NULL)
2156 for (y=0; y < (ssize_t) image->rows+(2*width); y++)
2158 *pix++=(float)GetPixelLuma(image,p);
2159 p+=(ptrdiff_t) image->number_channels;
2161 out=interImage+x+width;
2162 for (y=0; y < (ssize_t) image->rows; y++)
2171 for (i=0; i < width; i++)
2173 sum+=weight*((double) *pix++);
2176 for (i=width+1; i < (2*width); i++)
2178 sum+=weight*((double) *pix++);
2182 *out=(float) (sum/totalWeight);
2184 if ((x <= width) && (x != 0))
2186 if ((x > (ssize_t) image->columns-width-2) &&
2187 (x != (ssize_t) image->columns-1))
2188 *(out+((image->columns-(size_t) x-1)*2))=*out;
2189 out+=image->columns+(size_t) (width*2);
2200#if defined(MAGICKCORE_OPENMP_SUPPORT)
2201#pragma omp parallel for schedule(static) \
2202 magick_number_threads(image,image,image->rows,1)
2204 for (y=0; y < (ssize_t) image->rows; y++)
2207 id = GetOpenMPThreadId();
2223 if (status == MagickFalse)
2226 pixels+=
id*scanLineSize;
2227 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2228 q=GetCacheViewAuthenticPixels(contrast_view,0,y,image->columns,1,
2230 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
2235 memcpy(pixels,interImage+((
size_t) y*(image->columns+(
size_t) (2*width))),
2236 (image->columns+(
size_t) (2*width))*
sizeof(
float));
2237 for (x=0; x < (ssize_t) image->columns; x++)
2251 for (i=0; i < width; i++)
2253 sum+=weight*((double) *pix++);
2256 for (i=width+1; i < (2*width); i++)
2258 sum+=weight*((double) *pix++);
2264 srcVal=(float) GetPixelLuma(image,p);
2265 mult=(srcVal-(sum/totalWeight))*(strength/100.0);
2266 mult=(srcVal+mult)/srcVal;
2267 traits=GetPixelChannelTraits(image,RedPixelChannel);
2268 if ((traits & UpdatePixelTrait) != 0)
2269 SetPixelRed(contrast_image,ClampToQuantum((MagickRealType)
2270 GetPixelRed(image,p)*mult),q);
2271 traits=GetPixelChannelTraits(image,GreenPixelChannel);
2272 if ((traits & UpdatePixelTrait) != 0)
2273 SetPixelGreen(contrast_image,ClampToQuantum((MagickRealType)
2274 GetPixelGreen(image,p)*mult),q);
2275 traits=GetPixelChannelTraits(image,BluePixelChannel);
2276 if ((traits & UpdatePixelTrait) != 0)
2277 SetPixelBlue(contrast_image,ClampToQuantum((MagickRealType)
2278 GetPixelBlue(image,p)*mult),q);
2279 p+=(ptrdiff_t) image->number_channels;
2280 q+=(ptrdiff_t) contrast_image->number_channels;
2282 if (SyncCacheViewAuthenticPixels(contrast_view,exception) == MagickFalse)
2286 scanline_info=RelinquishVirtualMemory(scanline_info);
2287 interImage_info=RelinquishVirtualMemory(interImage_info);
2288 contrast_view=DestroyCacheView(contrast_view);
2289 image_view=DestroyCacheView(image_view);
2290 if (status == MagickFalse)
2291 contrast_image=DestroyImage(contrast_image);
2292 return(contrast_image);
2334static MagickRealType *GetMotionBlurKernel(
const size_t width,
2347 if (IsEventLogging() != MagickFalse)
2348 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
2349 kernel=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory((
size_t)
2350 width,
sizeof(*kernel)));
2351 if (kernel == (MagickRealType *) NULL)
2354 for (i=0; i < (ssize_t) width; i++)
2356 kernel[i]=(MagickRealType) (exp((-((
double) i*i)/(
double) (2.0*MagickSigma*
2357 MagickSigma)))/(MagickSQ2PI*MagickSigma));
2358 normalize+=kernel[i];
2360 for (i=0; i < (ssize_t) width; i++)
2361 kernel[i]/=normalize;
2365MagickExport Image *MotionBlurImage(
const Image *image,
const double radius,
2366 const double sigma,
const double angle,ExceptionInfo *exception)
2368#define BlurImageTag "Blur/Image"
2400 assert(image != (Image *) NULL);
2401 assert(image->signature == MagickCoreSignature);
2402 assert(exception != (ExceptionInfo *) NULL);
2403 assert(exception->signature == MagickCoreSignature);
2404 if (IsEventLogging() != MagickFalse)
2405 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2406 width=GetOptimalKernelWidth1D(radius,sigma);
2407 kernel=GetMotionBlurKernel(width,sigma);
2408 if (kernel == (MagickRealType *) NULL)
2409 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2410 offset=(OffsetInfo *) AcquireQuantumMemory(width,
sizeof(*offset));
2411 if (offset == (OffsetInfo *) NULL)
2413 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2414 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2416 point.x=(double) width*sin(DegreesToRadians(angle));
2417 point.y=(double) width*cos(DegreesToRadians(angle));
2418 for (w=0; w < (ssize_t) width; w++)
2420 offset[w].x=CastDoubleToSsizeT(ceil((
double) (w*point.y)/
2421 hypot(point.x,point.y)-0.5));
2422 offset[w].y=CastDoubleToSsizeT(ceil((
double) (w*point.x)/
2423 hypot(point.x,point.y)-0.5));
2428#if defined(MAGICKCORE_OPENCL_SUPPORT)
2429 blur_image=AccelerateMotionBlurImage(image,kernel,width,offset,exception);
2430 if (blur_image != (Image *) NULL)
2432 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2433 offset=(OffsetInfo *) RelinquishMagickMemory(offset);
2437 blur_image=CloneImage(image,0,0,MagickTrue,exception);
2438 if (blur_image == (Image *) NULL)
2440 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2441 offset=(OffsetInfo *) RelinquishMagickMemory(offset);
2442 return((Image *) NULL);
2444 if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
2446 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2447 offset=(OffsetInfo *) RelinquishMagickMemory(offset);
2448 blur_image=DestroyImage(blur_image);
2449 return((Image *) NULL);
2453 image_view=AcquireVirtualCacheView(image,exception);
2454 motion_view=AcquireVirtualCacheView(image,exception);
2455 blur_view=AcquireAuthenticCacheView(blur_image,exception);
2456#if defined(MAGICKCORE_OPENMP_SUPPORT)
2457 #pragma omp parallel for schedule(static) shared(progress,status) \
2458 magick_number_threads(image,blur_image,image->rows,1)
2460 for (y=0; y < (ssize_t) image->rows; y++)
2471 if (status == MagickFalse)
2473 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2474 q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
2476 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
2481 for (x=0; x < (ssize_t) image->columns; x++)
2486 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2509 channel=GetPixelChannelChannel(image,i);
2510 traits=GetPixelChannelTraits(image,channel);
2511 blur_traits=GetPixelChannelTraits(blur_image,channel);
2512 if ((traits == UndefinedPixelTrait) ||
2513 (blur_traits == UndefinedPixelTrait))
2515 if ((blur_traits & CopyPixelTrait) != 0)
2517 SetPixelChannel(blur_image,channel,p[i],q);
2522 if ((blur_traits & BlendPixelTrait) == 0)
2524 for (j=0; j < (ssize_t) width; j++)
2526 r=GetCacheViewVirtualPixels(motion_view,x+offset[j].x,y+
2527 offset[j].y,1,1,exception);
2528 if (r == (
const Quantum *) NULL)
2533 pixel+=(*k)*(double) r[i];
2536 SetPixelChannel(blur_image,channel,ClampToQuantum(pixel),q);
2539 for (j=0; j < (ssize_t) width; j++)
2541 r=GetCacheViewVirtualPixels(motion_view,x+offset[j].x,y+offset[j].y,1,
2543 if (r == (
const Quantum *) NULL)
2548 alpha=QuantumScale*(double) GetPixelAlpha(image,r);
2549 pixel+=(*k)*alpha*(double) r[i];
2553 gamma=MagickSafeReciprocal(gamma);
2554 SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
2556 p+=(ptrdiff_t) GetPixelChannels(image);
2557 q+=(ptrdiff_t) GetPixelChannels(blur_image);
2559 if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
2561 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2566#if defined(MAGICKCORE_OPENMP_SUPPORT)
2570 proceed=SetImageProgress(image,BlurImageTag,progress,image->rows);
2571 if (proceed == MagickFalse)
2575 blur_view=DestroyCacheView(blur_view);
2576 motion_view=DestroyCacheView(motion_view);
2577 image_view=DestroyCacheView(image_view);
2578 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2579 offset=(OffsetInfo *) RelinquishMagickMemory(offset);
2580 if (status == MagickFalse)
2581 blur_image=DestroyImage(blur_image);
2615MagickExport Image *PreviewImage(
const Image *image,
const PreviewType preview,
2616 ExceptionInfo *exception)
2618#define NumberTiles 9
2619#define PreviewImageTag "Preview/Image"
2620#define DefaultPreviewGeometry "204x204+10+10"
2623 factor[MagickPathExtent],
2624 label[MagickPathExtent];
2666 assert(image != (Image *) NULL);
2667 assert(image->signature == MagickCoreSignature);
2668 if (IsEventLogging() != MagickFalse)
2669 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2673 preview_info=AcquireImageInfo();
2674 SetGeometry(image,&geometry);
2675 (void) ParseMetaGeometry(DefaultPreviewGeometry,&geometry.x,&geometry.y,
2676 &geometry.width,&geometry.height);
2677 images=NewImageList();
2679 GetQuantizeInfo(&quantize_info);
2683 for (i=0; i < NumberTiles; i++)
2685 thumbnail=ThumbnailImage(image,geometry.width,geometry.height,exception);
2686 if (thumbnail == (Image *) NULL)
2688 (void) SetImageProgressMonitor(thumbnail,(MagickProgressMonitor) NULL,
2690 (void) SetImageProperty(thumbnail,
"label",DefaultTileLabel,exception);
2691 if (i == (NumberTiles/2))
2693 (void) QueryColorCompliance(
"#dfdfdf",AllCompliance,
2694 &thumbnail->matte_color,exception);
2695 AppendImageToList(&images,thumbnail);
2703 preview_image=RotateImage(thumbnail,degrees,exception);
2704 (void) FormatLocaleString(label,MagickPathExtent,
"rotate %g",degrees);
2710 preview_image=ShearImage(thumbnail,degrees,degrees,exception);
2711 (void) FormatLocaleString(label,MagickPathExtent,
"shear %gx%g",degrees,
2717 x=((i+1)*(ssize_t) thumbnail->columns)/NumberTiles;
2718 y=((i+1)*(ssize_t) thumbnail->rows)/NumberTiles;
2719 preview_image=RollImage(thumbnail,x,y,exception);
2720 (void) FormatLocaleString(label,MagickPathExtent,
"roll %+.20gx%+.20g",
2721 (
double) x,(
double) y);
2726 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2727 if (preview_image == (Image *) NULL)
2729 (void) FormatLocaleString(factor,MagickPathExtent,
"100,100,%g",2.0*
2731 (void) ModulateImage(preview_image,factor,exception);
2732 (void) FormatLocaleString(label,MagickPathExtent,
"modulate %s",factor);
2735 case SaturationPreview:
2737 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2738 if (preview_image == (Image *) NULL)
2740 (void) FormatLocaleString(factor,MagickPathExtent,
"100,%g",2.0*
2742 (void) ModulateImage(preview_image,factor,exception);
2743 (void) FormatLocaleString(label,MagickPathExtent,
"modulate %s",factor);
2746 case BrightnessPreview:
2748 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2749 if (preview_image == (Image *) NULL)
2751 (void) FormatLocaleString(factor,MagickPathExtent,
"%g",2.0*percentage);
2752 (void) ModulateImage(preview_image,factor,exception);
2753 (void) FormatLocaleString(label,MagickPathExtent,
"modulate %s",factor);
2759 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2760 if (preview_image == (Image *) NULL)
2763 (void) GammaImage(preview_image,gamma,exception);
2764 (void) FormatLocaleString(label,MagickPathExtent,
"gamma %g",gamma);
2769 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2770 if (preview_image != (Image *) NULL)
2771 for (x=0; x < i; x++)
2772 (
void) ContrastImage(preview_image,MagickTrue,exception);
2773 (void) FormatLocaleString(label,MagickPathExtent,
"contrast (%.17g)",
2779 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2780 if (preview_image == (Image *) NULL)
2782 for (x=0; x < i; x++)
2783 (
void) ContrastImage(preview_image,MagickFalse,exception);
2784 (void) FormatLocaleString(label,MagickPathExtent,
"+contrast (%.17g)",
2788 case GrayscalePreview:
2790 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2791 if (preview_image == (Image *) NULL)
2794 quantize_info.number_colors=colors;
2795 quantize_info.colorspace=GRAYColorspace;
2796 (void) QuantizeImage(&quantize_info,preview_image,exception);
2797 (void) FormatLocaleString(label,MagickPathExtent,
2798 "-colorspace gray -colors %.17g",(
double) colors);
2801 case QuantizePreview:
2803 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2804 if (preview_image == (Image *) NULL)
2807 quantize_info.number_colors=colors;
2808 (void) QuantizeImage(&quantize_info,preview_image,exception);
2809 (void) FormatLocaleString(label,MagickPathExtent,
"colors %.17g",
2813 case DespecklePreview:
2815 for (x=0; x < (i-1); x++)
2817 preview_image=DespeckleImage(thumbnail,exception);
2818 if (preview_image == (Image *) NULL)
2820 thumbnail=DestroyImage(thumbnail);
2821 thumbnail=preview_image;
2823 preview_image=DespeckleImage(thumbnail,exception);
2824 if (preview_image == (Image *) NULL)
2826 (void) FormatLocaleString(label,MagickPathExtent,
"despeckle (%.17g)",
2830 case ReduceNoisePreview:
2832 preview_image=StatisticImage(thumbnail,NonpeakStatistic,(
size_t)
2833 radius,(
size_t) radius,exception);
2834 (void) FormatLocaleString(label,MagickPathExtent,
"noise %g",radius);
2837 case AddNoisePreview:
2843 (void) CopyMagickString(factor,
"uniform",MagickPathExtent);
2848 (void) CopyMagickString(factor,
"gaussian",MagickPathExtent);
2853 (void) CopyMagickString(factor,
"multiplicative",MagickPathExtent);
2858 (void) CopyMagickString(factor,
"impulse",MagickPathExtent);
2863 (void) CopyMagickString(factor,
"laplacian",MagickPathExtent);
2868 (void) CopyMagickString(factor,
"Poisson",MagickPathExtent);
2873 (void) CopyMagickString(thumbnail->magick,
"NULL",MagickPathExtent);
2877 preview_image=StatisticImage(thumbnail,NonpeakStatistic,(
size_t) i,
2878 (
size_t) i,exception);
2879 (void) FormatLocaleString(label,MagickPathExtent,
"+noise %s",factor);
2882 case SharpenPreview:
2884 preview_image=SharpenImage(thumbnail,radius,sigma,exception);
2885 (void) FormatLocaleString(label,MagickPathExtent,
"sharpen %gx%g",
2891 preview_image=BlurImage(thumbnail,radius,sigma,exception);
2892 (void) FormatLocaleString(label,MagickPathExtent,
"blur %gx%g",radius,
2896 case ThresholdPreview:
2898 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2899 if (preview_image == (Image *) NULL)
2901 (void) BilevelImage(thumbnail,(
double) (percentage*((
double)
2902 QuantumRange+1.0))/100.0,exception);
2903 (void) FormatLocaleString(label,MagickPathExtent,
"threshold %g",
2904 (
double) (percentage*((
double) QuantumRange+1.0))/100.0);
2907 case EdgeDetectPreview:
2909 preview_image=EdgeImage(thumbnail,radius,exception);
2910 (void) FormatLocaleString(label,MagickPathExtent,
"edge %g",radius);
2915 preview_image=SpreadImage(thumbnail,image->interpolate,radius,
2917 (void) FormatLocaleString(label,MagickPathExtent,
"spread %g",
2921 case SolarizePreview:
2923 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2924 if (preview_image == (Image *) NULL)
2926 (void) SolarizeImage(preview_image,(
double) QuantumRange*percentage/
2928 (void) FormatLocaleString(label,MagickPathExtent,
"solarize %g",
2929 ((
double) QuantumRange*percentage)/100.0);
2935 preview_image=ShadeImage(thumbnail,MagickTrue,degrees,degrees,
2937 (void) FormatLocaleString(label,MagickPathExtent,
"shade %gx%g",degrees,
2946 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2947 if (preview_image == (Image *) NULL)
2949 raise.width=(size_t) (2*i+2);
2950 raise.height=(size_t) (2*i+2);
2953 (void) RaiseImage(preview_image,&raise,MagickTrue,exception);
2954 (void) FormatLocaleString(label,MagickPathExtent,
2955 "raise %.17gx%.17g%+.20g%+.20g",(
double) raise.width,(
double)
2956 raise.height,(
double) raise.x,(
double) raise.y);
2959 case SegmentPreview:
2961 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2962 if (preview_image == (Image *) NULL)
2965 (void) SegmentImage(preview_image,sRGBColorspace,MagickFalse,threshold,
2966 threshold,exception);
2967 (void) FormatLocaleString(label,MagickPathExtent,
"segment %gx%g",
2968 threshold,threshold);
2973 preview_image=SwirlImage(thumbnail,degrees,image->interpolate,
2975 (void) FormatLocaleString(label,MagickPathExtent,
"swirl %g",degrees);
2979 case ImplodePreview:
2982 preview_image=ImplodeImage(thumbnail,degrees,image->interpolate,
2984 (void) FormatLocaleString(label,MagickPathExtent,
"implode %g",degrees);
2990 preview_image=WaveImage(thumbnail,0.5*degrees,2.0*degrees,
2991 image->interpolate,exception);
2992 (void) FormatLocaleString(label,MagickPathExtent,
"wave %gx%g",0.5*
2993 degrees,2.0*degrees);
2996 case OilPaintPreview:
2998 preview_image=OilPaintImage(thumbnail,(
double) radius,(
double) sigma,
3000 (void) FormatLocaleString(label,MagickPathExtent,
"charcoal %gx%g",
3004 case CharcoalDrawingPreview:
3006 preview_image=CharcoalImage(thumbnail,(
double) radius,(
double) sigma,
3008 (void) FormatLocaleString(label,MagickPathExtent,
"charcoal %gx%g",
3015 filename[MagickPathExtent];
3023 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
3024 if (preview_image == (Image *) NULL)
3026 preview_info->quality=(size_t) percentage;
3027 (void) FormatLocaleString(factor,MagickPathExtent,
"%.17g",(
double)
3028 preview_info->quality);
3029 file=AcquireUniqueFileResource(filename);
3031 file=close_utf8(file)-1;
3032 (void) FormatLocaleString(preview_image->filename,MagickPathExtent,
3033 "jpeg:%s",filename);
3034 status=WriteImage(preview_info,preview_image,exception);
3035 if (status != MagickFalse)
3040 (void) CopyMagickString(preview_info->filename,
3041 preview_image->filename,MagickPathExtent);
3042 quality_image=ReadImage(preview_info,exception);
3043 if (quality_image != (Image *) NULL)
3045 preview_image=DestroyImage(preview_image);
3046 preview_image=quality_image;
3049 (void) RelinquishUniqueFileResource(preview_image->filename);
3050 if ((GetBlobSize(preview_image)/1024) >= 1024)
3051 (void) FormatLocaleString(label,MagickPathExtent,
"quality %s\n%gmb ",
3052 factor,(
double) ((MagickOffsetType) GetBlobSize(preview_image))/
3055 if (GetBlobSize(preview_image) >= 1024)
3056 (void) FormatLocaleString(label,MagickPathExtent,
3057 "quality %s\n%gkb ",factor,(
double) ((MagickOffsetType)
3058 GetBlobSize(preview_image))/1024.0);
3060 (
void) FormatLocaleString(label,MagickPathExtent,
3061 "quality %s\n%.17gb ",factor,(
double) ((MagickOffsetType)
3062 GetBlobSize(thumbnail)));
3066 thumbnail=DestroyImage(thumbnail);
3070 if (preview_image == (Image *) NULL)
3072 preview_image->alpha_trait=UndefinedPixelTrait;
3073 (void) DeleteImageProperty(preview_image,
"label");
3074 (void) SetImageProperty(preview_image,
"label",label,exception);
3075 AppendImageToList(&images,preview_image);
3076 proceed=SetImageProgress(image,PreviewImageTag,(MagickOffsetType) i,
3078 if (proceed == MagickFalse)
3081 if (images == (Image *) NULL)
3083 preview_info=DestroyImageInfo(preview_info);
3084 return((Image *) NULL);
3089 montage_info=CloneMontageInfo(preview_info,(MontageInfo *) NULL);
3090 (void) CopyMagickString(montage_info->filename,image->filename,
3092 montage_info->shadow=MagickTrue;
3093 (void) CloneString(&montage_info->tile,
"3x3");
3094 (void) CloneString(&montage_info->geometry,DefaultPreviewGeometry);
3095 (void) CloneString(&montage_info->frame,DefaultTileFrame);
3096 montage_image=MontageImages(images,montage_info,exception);
3097 montage_info=DestroyMontageInfo(montage_info);
3098 images=DestroyImageList(images);
3099 if (montage_image == (Image *) NULL)
3100 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3101 if (montage_image->montage != (
char *) NULL)
3106 montage_image->montage=(
char *) RelinquishMagickMemory(
3107 montage_image->montage);
3108 if (image->directory != (
char *) NULL)
3109 montage_image->directory=(
char *) RelinquishMagickMemory(
3110 montage_image->directory);
3112 preview_info=DestroyImageInfo(preview_info);
3113 return(montage_image);
3147MagickExport Image *RotationalBlurImage(
const Image *image,
const double angle,
3148 ExceptionInfo *exception)
3184 assert(image != (Image *) NULL);
3185 assert(image->signature == MagickCoreSignature);
3186 assert(exception != (ExceptionInfo *) NULL);
3187 assert(exception->signature == MagickCoreSignature);
3188 if (IsEventLogging() != MagickFalse)
3189 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3190#if defined(MAGICKCORE_OPENCL_SUPPORT)
3191 blur_image=AccelerateRotationalBlurImage(image,angle,exception);
3192 if (blur_image != (Image *) NULL)
3195 blur_image=CloneImage(image,0,0,MagickTrue,exception);
3196 if (blur_image == (Image *) NULL)
3197 return((Image *) NULL);
3198 if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
3200 blur_image=DestroyImage(blur_image);
3201 return((Image *) NULL);
3203 blur_center.x=(double) (image->columns-1)/2.0;
3204 blur_center.y=(double) (image->rows-1)/2.0;
3205 blur_radius=hypot(blur_center.x,blur_center.y);
3206 n=(size_t) fabs(4.0*DegreesToRadians(angle)*sqrt((
double) blur_radius)+2UL);
3207 theta=DegreesToRadians(angle)/(double) (n-1);
3208 cos_theta=(
double *) AcquireQuantumMemory((
size_t) n,
sizeof(*cos_theta));
3209 sin_theta=(
double *) AcquireQuantumMemory((
size_t) n,
sizeof(*sin_theta));
3210 if ((cos_theta == (
double *) NULL) || (sin_theta == (
double *) NULL))
3212 if (cos_theta != (
double *) NULL)
3213 cos_theta=(
double *) RelinquishMagickMemory(cos_theta);
3214 if (sin_theta != (
double *) NULL)
3215 sin_theta=(
double *) RelinquishMagickMemory(sin_theta);
3216 blur_image=DestroyImage(blur_image);
3217 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3219 offset=theta*(double) (n-1)/2.0;
3220 for (w=0; w < (ssize_t) n; w++)
3222 cos_theta[w]=cos((
double) (theta*w-offset));
3223 sin_theta[w]=sin((
double) (theta*w-offset));
3230 image_view=AcquireVirtualCacheView(image,exception);
3231 radial_view=AcquireVirtualCacheView(image,exception);
3232 blur_view=AcquireAuthenticCacheView(blur_image,exception);
3233#if defined(MAGICKCORE_OPENMP_SUPPORT)
3234 #pragma omp parallel for schedule(static) shared(progress,status) \
3235 magick_number_threads(image,blur_image,image->rows,1)
3237 for (y=0; y < (ssize_t) image->rows; y++)
3248 if (status == MagickFalse)
3250 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
3251 q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
3253 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3258 for (x=0; x < (ssize_t) image->columns; x++)
3272 center.x=(double) x-blur_center.x;
3273 center.y=(double) y-blur_center.y;
3274 radius=hypot((
double) center.x,center.y);
3279 step=(size_t) (blur_radius/radius);
3286 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3305 channel=GetPixelChannelChannel(image,i);
3306 traits=GetPixelChannelTraits(image,channel);
3307 blur_traits=GetPixelChannelTraits(blur_image,channel);
3308 if ((traits == UndefinedPixelTrait) ||
3309 (blur_traits == UndefinedPixelTrait))
3311 if ((blur_traits & CopyPixelTrait) != 0)
3313 SetPixelChannel(blur_image,channel,p[i],q);
3318 if ((GetPixelChannelTraits(image,AlphaPixelChannel) == UndefinedPixelTrait) ||
3319 (channel == AlphaPixelChannel))
3321 for (j=0; j < (ssize_t) n; j+=(ssize_t) step)
3323 r=GetCacheViewVirtualPixels(radial_view, (ssize_t) (blur_center.x+
3324 center.x*cos_theta[j]-center.y*sin_theta[j]+0.5),(ssize_t)
3325 (blur_center.y+center.x*sin_theta[j]+center.y*cos_theta[j]+0.5),
3327 if (r == (
const Quantum *) NULL)
3332 pixel+=(double) r[i];
3335 gamma=MagickSafeReciprocal(gamma);
3336 SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
3339 for (j=0; j < (ssize_t) n; j+=(ssize_t) step)
3344 r=GetCacheViewVirtualPixels(radial_view, (ssize_t) (blur_center.x+
3345 center.x*cos_theta[j]-center.y*sin_theta[j]+0.5),(ssize_t)
3346 (blur_center.y+center.x*sin_theta[j]+center.y*cos_theta[j]+0.5),
3348 if (r == (
const Quantum *) NULL)
3353 alpha=QuantumScale*(double) GetPixelAlpha(image,r);
3354 pixel+=alpha*(double) r[i];
3357 gamma=MagickSafeReciprocal(gamma);
3358 SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
3360 p+=(ptrdiff_t) GetPixelChannels(image);
3361 q+=(ptrdiff_t) GetPixelChannels(blur_image);
3363 if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
3365 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3370#if defined(MAGICKCORE_OPENMP_SUPPORT)
3374 proceed=SetImageProgress(image,BlurImageTag,progress,image->rows);
3375 if (proceed == MagickFalse)
3379 blur_view=DestroyCacheView(blur_view);
3380 radial_view=DestroyCacheView(radial_view);
3381 image_view=DestroyCacheView(image_view);
3382 cos_theta=(
double *) RelinquishMagickMemory(cos_theta);
3383 sin_theta=(
double *) RelinquishMagickMemory(sin_theta);
3384 if (status == MagickFalse)
3385 blur_image=DestroyImage(blur_image);
3424MagickExport Image *SelectiveBlurImage(
const Image *image,
const double radius,
3425 const double sigma,
const double threshold,ExceptionInfo *exception)
3427#define SelectiveBlurImageTag "SelectiveBlur/Image"
3457 assert(image != (Image *) NULL);
3458 assert(image->signature == MagickCoreSignature);
3459 assert(exception != (ExceptionInfo *) NULL);
3460 assert(exception->signature == MagickCoreSignature);
3461 if (IsEventLogging() != MagickFalse)
3462 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3463 width=GetOptimalKernelWidth1D(radius,sigma);
3464 kernel=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory((
size_t)
3465 width,width*
sizeof(*kernel)));
3466 if (kernel == (MagickRealType *) NULL)
3467 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3474 j=(ssize_t) (width-1)/2;
3476 for (v=(-j); v <= j; v++)
3481 for (u=(-j); u <= j; u++)
3482 kernel[i++]=(MagickRealType) (exp(-((
double) u*u+v*v)/(2.0*MagickSigma*
3483 MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
3486 if (image->debug != MagickFalse)
3489 format[MagickPathExtent],
3492 const MagickRealType
3499 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
3500 " SelectiveBlurImage with %.17gx%.17g kernel:",(
double) width,(
double)
3502 message=AcquireString(
"");
3504 for (v=0; v < (ssize_t) width; v++)
3507 (void) FormatLocaleString(format,MagickPathExtent,
"%.17g: ",(
double) v);
3508 (void) ConcatenateString(&message,format);
3509 for (u=0; u < (ssize_t) width; u++)
3511 (void) FormatLocaleString(format,MagickPathExtent,
"%+f ",(
double)
3513 (void) ConcatenateString(&message,format);
3515 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
"%s",message);
3517 message=DestroyString(message);
3519 blur_image=CloneImage(image,0,0,MagickTrue,exception);
3520 if (blur_image == (Image *) NULL)
3521 return((Image *) NULL);
3522 if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
3524 blur_image=DestroyImage(blur_image);
3525 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
3526 return((Image *) NULL);
3528 luminance_image=CloneImage(image,0,0,MagickTrue,exception);
3529 if (luminance_image == (Image *) NULL)
3531 blur_image=DestroyImage(blur_image);
3532 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
3533 return((Image *) NULL);
3535 status=TransformImageColorspace(luminance_image,GRAYColorspace,exception);
3536 if (status == MagickFalse)
3538 luminance_image=DestroyImage(luminance_image);
3539 blur_image=DestroyImage(blur_image);
3540 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
3541 return((Image *) NULL);
3548 center=(ssize_t) (GetPixelChannels(image)*(image->columns+width)*
3549 ((width-1)/2L)+GetPixelChannels(image)*((width-1)/2L));
3550 image_view=AcquireVirtualCacheView(image,exception);
3551 luminance_view=AcquireVirtualCacheView(luminance_image,exception);
3552 blur_view=AcquireAuthenticCacheView(blur_image,exception);
3553#if defined(MAGICKCORE_OPENMP_SUPPORT)
3554 #pragma omp parallel for schedule(static) shared(progress,status) \
3555 magick_number_threads(image,blur_image,image->rows,1)
3557 for (y=0; y < (ssize_t) image->rows; y++)
3575 if (status == MagickFalse)
3577 p=GetCacheViewVirtualPixels(image_view,-((ssize_t) (width-1)/2L),y-(ssize_t)
3578 ((width-1)/2L),image->columns+width,width,exception);
3579 l=GetCacheViewVirtualPixels(luminance_view,-((ssize_t) (width-1)/2L),y-
3580 (ssize_t) ((width-1)/2L),luminance_image->columns+width,width,exception);
3581 q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
3583 if ((p == (
const Quantum *) NULL) || (l == (
const Quantum *) NULL) ||
3584 (q == (Quantum *) NULL))
3589 for (x=0; x < (ssize_t) image->columns; x++)
3597 intensity=GetPixelIntensity(image,p+center);
3598 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3612 const MagickRealType
3616 *magick_restrict luminance_pixels,
3617 *magick_restrict pixels;
3625 channel=GetPixelChannelChannel(image,i);
3626 traits=GetPixelChannelTraits(image,channel);
3627 blur_traits=GetPixelChannelTraits(blur_image,channel);
3628 if ((traits == UndefinedPixelTrait) ||
3629 (blur_traits == UndefinedPixelTrait))
3631 if ((blur_traits & CopyPixelTrait) != 0)
3633 SetPixelChannel(blur_image,channel,p[center+i],q);
3641 if ((blur_traits & BlendPixelTrait) == 0)
3643 for (v=0; v < (ssize_t) width; v++)
3645 for (u=0; u < (ssize_t) width; u++)
3647 contrast=GetPixelIntensity(luminance_image,luminance_pixels)-
3649 if (fabs(contrast) < threshold)
3651 pixel+=(*k)*(double) pixels[i];
3655 pixels+=(ptrdiff_t) GetPixelChannels(image);
3656 luminance_pixels+=(ptrdiff_t) GetPixelChannels(luminance_image);
3658 pixels+=(ptrdiff_t) GetPixelChannels(image)*image->columns;
3659 luminance_pixels+=(ptrdiff_t) GetPixelChannels(luminance_image)*
3660 luminance_image->columns;
3662 if (fabs((
double) gamma) < MagickEpsilon)
3664 SetPixelChannel(blur_image,channel,p[center+i],q);
3667 gamma=MagickSafeReciprocal(gamma);
3668 SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
3671 for (v=0; v < (ssize_t) width; v++)
3673 for (u=0; u < (ssize_t) width; u++)
3675 contrast=GetPixelIntensity(image,pixels)-intensity;
3676 if (fabs(contrast) < threshold)
3678 alpha=QuantumScale*(double) GetPixelAlpha(image,pixels);
3679 pixel+=(*k)*alpha*(double) pixels[i];
3683 pixels+=(ptrdiff_t) GetPixelChannels(image);
3684 luminance_pixels+=(ptrdiff_t) GetPixelChannels(luminance_image);
3686 pixels+=(ptrdiff_t) GetPixelChannels(image)*image->columns;
3687 luminance_pixels+=(ptrdiff_t) GetPixelChannels(luminance_image)*
3688 luminance_image->columns;
3690 if (fabs((
double) gamma) < MagickEpsilon)
3692 SetPixelChannel(blur_image,channel,p[center+i],q);
3695 gamma=MagickSafeReciprocal(gamma);
3696 SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
3698 p+=(ptrdiff_t) GetPixelChannels(image);
3699 l+=(ptrdiff_t) GetPixelChannels(luminance_image);
3700 q+=(ptrdiff_t) GetPixelChannels(blur_image);
3702 sync=SyncCacheViewAuthenticPixels(blur_view,exception);
3703 if (sync == MagickFalse)
3705 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3710#if defined(MAGICKCORE_OPENMP_SUPPORT)
3714 proceed=SetImageProgress(image,SelectiveBlurImageTag,progress,
3716 if (proceed == MagickFalse)
3720 blur_image->type=image->type;
3721 blur_view=DestroyCacheView(blur_view);
3722 luminance_view=DestroyCacheView(luminance_view);
3723 image_view=DestroyCacheView(image_view);
3724 luminance_image=DestroyImage(luminance_image);
3725 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
3726 if (status == MagickFalse)
3727 blur_image=DestroyImage(blur_image);
3763MagickExport Image *ShadeImage(
const Image *image,
const MagickBooleanType gray,
3764 const double azimuth,
const double elevation,ExceptionInfo *exception)
3766#define GetShadeIntensity(image,pixel) \
3767 ClampPixel(GetPixelIntensity((image),(pixel)))
3768#define ShadeImageTag "Shade/Image"
3793 assert(image != (
const Image *) NULL);
3794 assert(image->signature == MagickCoreSignature);
3795 assert(exception != (ExceptionInfo *) NULL);
3796 assert(exception->signature == MagickCoreSignature);
3797 if (IsEventLogging() != MagickFalse)
3798 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3799 linear_image=CloneImage(image,0,0,MagickTrue,exception);
3800 shade_image=CloneImage(image,0,0,MagickTrue,exception);
3801 if ((linear_image == (Image *) NULL) || (shade_image == (Image *) NULL))
3803 if (linear_image != (Image *) NULL)
3804 linear_image=DestroyImage(linear_image);
3805 if (shade_image != (Image *) NULL)
3806 shade_image=DestroyImage(shade_image);
3807 return((Image *) NULL);
3809 if (SetImageStorageClass(shade_image,DirectClass,exception) == MagickFalse)
3811 linear_image=DestroyImage(linear_image);
3812 shade_image=DestroyImage(shade_image);
3813 return((Image *) NULL);
3818 light.x=(double) QuantumRange*cos(DegreesToRadians(azimuth))*
3819 cos(DegreesToRadians(elevation));
3820 light.y=(double) QuantumRange*sin(DegreesToRadians(azimuth))*
3821 cos(DegreesToRadians(elevation));
3822 light.z=(double) QuantumRange*sin(DegreesToRadians(elevation));
3828 image_view=AcquireVirtualCacheView(linear_image,exception);
3829 shade_view=AcquireAuthenticCacheView(shade_image,exception);
3830#if defined(MAGICKCORE_OPENMP_SUPPORT)
3831 #pragma omp parallel for schedule(static) shared(progress,status) \
3832 magick_number_threads(linear_image,shade_image,linear_image->rows,1)
3834 for (y=0; y < (ssize_t) linear_image->rows; y++)
3845 *magick_restrict center,
3847 *magick_restrict post,
3848 *magick_restrict pre;
3856 if (status == MagickFalse)
3858 p=GetCacheViewVirtualPixels(image_view,-1,y-1,linear_image->columns+2,3,
3860 q=QueueCacheViewAuthenticPixels(shade_view,0,y,shade_image->columns,1,
3862 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3870 normal.z=2.0*(double) QuantumRange;
3871 for (x=0; x < (ssize_t) linear_image->columns; x++)
3879 pre=p+GetPixelChannels(linear_image);
3880 center=pre+(linear_image->columns+2)*GetPixelChannels(linear_image);
3881 post=center+(linear_image->columns+2)*GetPixelChannels(linear_image);
3883 GetShadeIntensity(linear_image,pre-GetPixelChannels(linear_image))+
3884 GetShadeIntensity(linear_image,center-GetPixelChannels(linear_image))+
3885 GetShadeIntensity(linear_image,post-GetPixelChannels(linear_image))-
3886 GetShadeIntensity(linear_image,pre+GetPixelChannels(linear_image))-
3887 GetShadeIntensity(linear_image,center+GetPixelChannels(linear_image))-
3888 GetShadeIntensity(linear_image,post+GetPixelChannels(linear_image)));
3890 GetShadeIntensity(linear_image,post-GetPixelChannels(linear_image))+
3891 GetShadeIntensity(linear_image,post)+
3892 GetShadeIntensity(linear_image,post+GetPixelChannels(linear_image))-
3893 GetShadeIntensity(linear_image,pre-GetPixelChannels(linear_image))-
3894 GetShadeIntensity(linear_image,pre)-
3895 GetShadeIntensity(linear_image,pre+GetPixelChannels(linear_image)));
3896 if ((fabs(normal.x) <= MagickEpsilon) &&
3897 (fabs(normal.y) <= MagickEpsilon))
3902 distance=normal.x*light.x+normal.y*light.y+normal.z*light.z;
3903 if (distance > MagickEpsilon)
3905 normal_distance=normal.x*normal.x+normal.y*normal.y+
3907 if (normal_distance > (MagickEpsilon*MagickEpsilon))
3908 shade=distance/sqrt((
double) normal_distance);
3911 for (i=0; i < (ssize_t) GetPixelChannels(linear_image); i++)
3920 channel=GetPixelChannelChannel(linear_image,i);
3921 traits=GetPixelChannelTraits(linear_image,channel);
3922 shade_traits=GetPixelChannelTraits(shade_image,channel);
3923 if ((traits == UndefinedPixelTrait) ||
3924 (shade_traits == UndefinedPixelTrait))
3926 if ((shade_traits & CopyPixelTrait) != 0)
3928 SetPixelChannel(shade_image,channel,center[i],q);
3931 if ((traits & UpdatePixelTrait) == 0)
3933 SetPixelChannel(shade_image,channel,center[i],q);
3936 if (gray != MagickFalse)
3938 SetPixelChannel(shade_image,channel,ClampToQuantum(shade),q);
3941 SetPixelChannel(shade_image,channel,ClampToQuantum(QuantumScale*
3942 shade*(
double) center[i]),q);
3944 p+=(ptrdiff_t) GetPixelChannels(linear_image);
3945 q+=(ptrdiff_t) GetPixelChannels(shade_image);
3947 if (SyncCacheViewAuthenticPixels(shade_view,exception) == MagickFalse)
3949 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3954#if defined(MAGICKCORE_OPENMP_SUPPORT)
3958 proceed=SetImageProgress(image,ShadeImageTag,progress,image->rows);
3959 if (proceed == MagickFalse)
3963 shade_view=DestroyCacheView(shade_view);
3964 image_view=DestroyCacheView(image_view);
3965 linear_image=DestroyImage(linear_image);
3966 if (status == MagickFalse)
3967 shade_image=DestroyImage(shade_image);
3968 return(shade_image);
4009MagickExport Image *SharpenImage(
const Image *image,
const double radius,
4010 const double sigma,ExceptionInfo *exception)
4033 assert(image != (
const Image *) NULL);
4034 assert(image->signature == MagickCoreSignature);
4035 assert(exception != (ExceptionInfo *) NULL);
4036 assert(exception->signature == MagickCoreSignature);
4037 if (IsEventLogging() != MagickFalse)
4038 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4039 width=GetOptimalKernelWidth2D(radius,sigma);
4040 kernel_info=AcquireKernelInfo((
const char *) NULL,exception);
4041 if (kernel_info == (KernelInfo *) NULL)
4042 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
4043 (void) memset(kernel_info,0,
sizeof(*kernel_info));
4044 kernel_info->width=width;
4045 kernel_info->height=width;
4046 kernel_info->x=(ssize_t) (width-1)/2;
4047 kernel_info->y=(ssize_t) (width-1)/2;
4048 kernel_info->signature=MagickCoreSignature;
4049 kernel_info->values=(MagickRealType *) MagickAssumeAligned(
4050 AcquireAlignedMemory(kernel_info->width,kernel_info->height*
4051 sizeof(*kernel_info->values)));
4052 if (kernel_info->values == (MagickRealType *) NULL)
4054 kernel_info=DestroyKernelInfo(kernel_info);
4055 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
4058 j=(ssize_t) (kernel_info->width-1)/2;
4060 for (v=(-j); v <= j; v++)
4062 for (u=(-j); u <= j; u++)
4064 kernel_info->values[i]=(MagickRealType) (-exp(-((
double) u*u+v*v)/(2.0*
4065 MagickSigma*MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
4066 normalize+=kernel_info->values[i];
4070 kernel_info->values[i/2]=(double) ((-2.0)*normalize);
4072 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
4073 normalize+=kernel_info->values[i];
4074 gamma=MagickSafeReciprocal(normalize);
4075 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
4076 kernel_info->values[i]*=gamma;
4077 sharp_image=ConvolveImage(image,kernel_info,exception);
4078 kernel_info=DestroyKernelInfo(kernel_info);
4079 return(sharp_image);
4113MagickExport Image *SpreadImage(
const Image *image,
4114 const PixelInterpolateMethod method,
const double radius,
4115 ExceptionInfo *exception)
4117#define SpreadImageTag "Spread/Image"
4133 **magick_restrict random_info;
4141#if defined(MAGICKCORE_OPENMP_SUPPORT)
4149 assert(image != (Image *) NULL);
4150 assert(image->signature == MagickCoreSignature);
4151 assert(exception != (ExceptionInfo *) NULL);
4152 assert(exception->signature == MagickCoreSignature);
4153 if (IsEventLogging() != MagickFalse)
4154 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4155 spread_image=CloneImage(image,0,0,MagickTrue,exception);
4156 if (spread_image == (Image *) NULL)
4157 return((Image *) NULL);
4158 if (SetImageStorageClass(spread_image,DirectClass,exception) == MagickFalse)
4160 spread_image=DestroyImage(spread_image);
4161 return((Image *) NULL);
4168 width=GetOptimalKernelWidth1D(radius,0.5);
4169 random_info=AcquireRandomInfoTLS();
4170 image_view=AcquireVirtualCacheView(image,exception);
4171 spread_view=AcquireAuthenticCacheView(spread_image,exception);
4172#if defined(MAGICKCORE_OPENMP_SUPPORT)
4173 key=GetRandomSecretKey(random_info[0]);
4174 #pragma omp parallel for schedule(static) shared(progress,status) \
4175 magick_number_threads(image,spread_image,image->rows,key == ~0UL)
4177 for (y=0; y < (ssize_t) image->rows; y++)
4180 id = GetOpenMPThreadId();
4188 if (status == MagickFalse)
4190 q=QueueCacheViewAuthenticPixels(spread_view,0,y,spread_image->columns,1,
4192 if (q == (Quantum *) NULL)
4197 for (x=0; x < (ssize_t) image->columns; x++)
4202 point.x=GetPseudoRandomValue(random_info[
id]);
4203 point.y=GetPseudoRandomValue(random_info[
id]);
4204 status=InterpolatePixelChannels(image,image_view,spread_image,method,
4205 (
double) x+width*(point.x-0.5),(
double) y+width*(point.y-0.5),q,
4207 if (status == MagickFalse)
4209 q+=(ptrdiff_t) GetPixelChannels(spread_image);
4211 if (SyncCacheViewAuthenticPixels(spread_view,exception) == MagickFalse)
4213 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4218#if defined(MAGICKCORE_OPENMP_SUPPORT)
4222 proceed=SetImageProgress(image,SpreadImageTag,progress,image->rows);
4223 if (proceed == MagickFalse)
4227 spread_view=DestroyCacheView(spread_view);
4228 image_view=DestroyCacheView(image_view);
4229 random_info=DestroyRandomInfoTLS(random_info);
4230 if (status == MagickFalse)
4231 spread_image=DestroyImage(spread_image);
4232 return(spread_image);
4274MagickExport Image *UnsharpMaskImage(
const Image *image,
const double radius,
4275 const double sigma,
const double gain,
const double threshold,
4276 ExceptionInfo *exception)
4278#define SharpenImageTag "Sharpen/Image"
4299 assert(image != (
const Image *) NULL);
4300 assert(image->signature == MagickCoreSignature);
4301 assert(exception != (ExceptionInfo *) NULL);
4302 assert(exception->signature == MagickCoreSignature);
4303 if (IsEventLogging() != MagickFalse)
4304 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4313 unsharp_image=BlurImage(image,radius,sigma,exception);
4314 if (unsharp_image == (Image *) NULL)
4315 return((Image *) NULL);
4316 quantum_threshold=(double) QuantumRange*threshold;
4322 image_view=AcquireVirtualCacheView(image,exception);
4323 unsharp_view=AcquireAuthenticCacheView(unsharp_image,exception);
4324#if defined(MAGICKCORE_OPENMP_SUPPORT)
4325 #pragma omp parallel for schedule(static) shared(progress,status) \
4326 magick_number_threads(image,unsharp_image,image->rows,1)
4328 for (y=0; y < (ssize_t) image->rows; y++)
4339 if (status == MagickFalse)
4341 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
4342 q=GetCacheViewAuthenticPixels(unsharp_view,0,y,unsharp_image->columns,1,
4344 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
4349 for (x=0; x < (ssize_t) image->columns; x++)
4354 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4366 channel=GetPixelChannelChannel(image,i);
4367 traits=GetPixelChannelTraits(image,channel);
4368 unsharp_traits=GetPixelChannelTraits(unsharp_image,channel);
4369 if ((traits == UndefinedPixelTrait) ||
4370 (unsharp_traits == UndefinedPixelTrait))
4372 if ((unsharp_traits & CopyPixelTrait) != 0)
4374 SetPixelChannel(unsharp_image,channel,p[i],q);
4377 pixel=(double) p[i]-(
double) GetPixelChannel(unsharp_image,channel,q);
4378 if (fabs(2.0*pixel) < quantum_threshold)
4379 pixel=(double) p[i];
4381 pixel=(double) p[i]+gain*pixel;
4382 SetPixelChannel(unsharp_image,channel,ClampToQuantum(pixel),q);
4384 p+=(ptrdiff_t) GetPixelChannels(image);
4385 q+=(ptrdiff_t) GetPixelChannels(unsharp_image);
4387 if (SyncCacheViewAuthenticPixels(unsharp_view,exception) == MagickFalse)
4389 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4394#if defined(MAGICKCORE_OPENMP_SUPPORT)
4398 proceed=SetImageProgress(image,SharpenImageTag,progress,image->rows);
4399 if (proceed == MagickFalse)
4403 unsharp_image->type=image->type;
4404 unsharp_view=DestroyCacheView(unsharp_view);
4405 image_view=DestroyCacheView(image_view);
4406 if (status == MagickFalse)
4407 unsharp_image=DestroyImage(unsharp_image);
4408 return(unsharp_image);