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"
128MagickExport
Image *AdaptiveBlurImage(
const Image *image,
const double radius,
131#define AdaptiveBlurImageTag "Convolve/Image"
132#define MagickSigma (fabs(sigma) < MagickEpsilon ? MagickEpsilon : sigma)
161 assert(image != (
const Image *) NULL);
162 assert(image->signature == MagickCoreSignature);
164 assert(exception->signature == MagickCoreSignature);
165 if (IsEventLogging() != MagickFalse)
166 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
167 blur_image=CloneImage(image,0,0,MagickTrue,exception);
168 if (blur_image == (
Image *) NULL)
169 return((
Image *) NULL);
170 if (fabs(sigma) < MagickEpsilon)
172 if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
174 blur_image=DestroyImage(blur_image);
175 return((
Image *) NULL);
180 edge_image=EdgeImage(image,radius,exception);
181 if (edge_image == (
Image *) NULL)
183 blur_image=DestroyImage(blur_image);
184 return((
Image *) NULL);
186 (void) AutoLevelImage(edge_image,exception);
187 gaussian_image=BlurImage(edge_image,radius,sigma,exception);
188 if (gaussian_image != (
Image *) NULL)
190 edge_image=DestroyImage(edge_image);
191 edge_image=gaussian_image;
193 (void) AutoLevelImage(edge_image,exception);
197 width=GetOptimalKernelWidth2D(radius,sigma);
198 kernel=(
double **) MagickAssumeAligned(AcquireAlignedMemory((
size_t) width,
200 if (kernel == (
double **) NULL)
202 edge_image=DestroyImage(edge_image);
203 blur_image=DestroyImage(blur_image);
204 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
206 (void) memset(kernel,0,(
size_t) width*
sizeof(*kernel));
207 for (w=0; w < (ssize_t) width; w+=2)
215 kernel[w]=(
double *) MagickAssumeAligned(AcquireAlignedMemory(
216 (width-(
size_t) w),(width-(
size_t) w)*
sizeof(**kernel)));
217 if (kernel[w] == (
double *) NULL)
220 j=((ssize_t) width-w-1)/2;
222 for (v=(-j); v <= j; v++)
224 for (u=(-j); u <= j; u++)
226 kernel[w][k]=(double) (exp(-((
double) u*u+v*v)/(2.0*MagickSigma*
227 MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
228 normalize+=kernel[w][k];
232 kernel[w][(k-1)/2]+=(
double) (1.0-normalize);
233 if (sigma < MagickEpsilon)
234 kernel[w][(k-1)/2]=1.0;
236 if (w < (ssize_t) width)
238 for (w-=2; w >= 0; w-=2)
239 kernel[w]=(
double *) RelinquishAlignedMemory(kernel[w]);
240 kernel=(
double **) RelinquishAlignedMemory(kernel);
241 edge_image=DestroyImage(edge_image);
242 blur_image=DestroyImage(blur_image);
243 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
250 image_view=AcquireVirtualCacheView(image,exception);
251 edge_view=AcquireVirtualCacheView(edge_image,exception);
252 blur_view=AcquireAuthenticCacheView(blur_image,exception);
253#if defined(MAGICKCORE_OPENMP_SUPPORT)
254 #pragma omp parallel for schedule(static) shared(progress,status) \
255 magick_number_threads(image,blur_image,blur_image->rows,1)
257 for (y=0; y < (ssize_t) blur_image->rows; y++)
268 if (status == MagickFalse)
270 r=GetCacheViewVirtualPixels(edge_view,0,y,edge_image->columns,1,exception);
271 q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
273 if ((r == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
278 for (x=0; x < (ssize_t) blur_image->columns; x++)
290 j=CastDoubleToLong(ceil((
double) width*(1.0-QuantumScale*
291 GetPixelIntensity(edge_image,r))-0.5));
295 if (j > (ssize_t) width)
299 p=GetCacheViewVirtualPixels(image_view,x-((ssize_t) width-j)/2L,y-
300 ((ssize_t) width-j)/2L,width-(
size_t) j,width-(
size_t) j,exception);
301 if (p == (
const Quantum *) NULL)
303 center=(ssize_t) (GetPixelChannels(image)*(width-(
size_t) j)*
304 ((width-(
size_t) j)/2L)+GetPixelChannels(image)*((width-(
size_t) j)/2));
305 for (i=0; i < (ssize_t) GetPixelChannels(blur_image); i++)
323 *magick_restrict pixels;
331 channel=GetPixelChannelChannel(image,i);
332 traits=GetPixelChannelTraits(image,channel);
333 blur_traits=GetPixelChannelTraits(blur_image,channel);
334 if ((traits == UndefinedPixelTrait) ||
335 (blur_traits == UndefinedPixelTrait))
337 if ((blur_traits & CopyPixelTrait) != 0)
339 SetPixelChannel(blur_image,channel,p[center+i],q);
346 if ((blur_traits & BlendPixelTrait) == 0)
351 for (v=0; v < ((ssize_t) width-j); v++)
353 for (u=0; u < ((ssize_t) width-j); u++)
355 pixel+=(*k)*(double) pixels[i];
358 pixels+=GetPixelChannels(image);
361 gamma=PerceptibleReciprocal(gamma);
362 SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
368 for (v=0; v < ((ssize_t) width-j); v++)
370 for (u=0; u < ((ssize_t) width-j); u++)
372 alpha=(double) (QuantumScale*(
double) GetPixelAlpha(image,pixels));
373 pixel+=(*k)*alpha*(double) pixels[i];
376 pixels+=GetPixelChannels(image);
379 gamma=PerceptibleReciprocal(gamma);
380 SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
382 q+=GetPixelChannels(blur_image);
383 r+=GetPixelChannels(edge_image);
385 if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
387 if (image->progress_monitor != (MagickProgressMonitor) NULL)
392#if defined(MAGICKCORE_OPENMP_SUPPORT)
396 proceed=SetImageProgress(image,AdaptiveBlurImageTag,progress,
398 if (proceed == MagickFalse)
402 blur_image->type=image->type;
403 blur_view=DestroyCacheView(blur_view);
404 edge_view=DestroyCacheView(edge_view);
405 image_view=DestroyCacheView(image_view);
406 edge_image=DestroyImage(edge_image);
407 for (w=0; w < (ssize_t) width; w+=2)
408 kernel[w]=(
double *) RelinquishAlignedMemory(kernel[w]);
409 kernel=(
double **) RelinquishAlignedMemory(kernel);
410 if (status == MagickFalse)
411 blur_image=DestroyImage(blur_image);
449MagickExport
Image *AdaptiveSharpenImage(
const Image *image,
const double radius,
452#define AdaptiveSharpenImageTag "Convolve/Image"
453#define MagickSigma (fabs(sigma) < MagickEpsilon ? MagickEpsilon : sigma)
482 assert(image != (
const Image *) NULL);
483 assert(image->signature == MagickCoreSignature);
485 assert(exception->signature == MagickCoreSignature);
486 if (IsEventLogging() != MagickFalse)
487 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
488 sharp_image=CloneImage(image,0,0,MagickTrue,exception);
489 if (sharp_image == (
Image *) NULL)
490 return((
Image *) NULL);
491 if (fabs(sigma) < MagickEpsilon)
493 if (SetImageStorageClass(sharp_image,DirectClass,exception) == MagickFalse)
495 sharp_image=DestroyImage(sharp_image);
496 return((
Image *) NULL);
501 edge_image=EdgeImage(image,radius,exception);
502 if (edge_image == (
Image *) NULL)
504 sharp_image=DestroyImage(sharp_image);
505 return((
Image *) NULL);
507 (void) AutoLevelImage(edge_image,exception);
508 gaussian_image=BlurImage(edge_image,radius,sigma,exception);
509 if (gaussian_image != (
Image *) NULL)
511 edge_image=DestroyImage(edge_image);
512 edge_image=gaussian_image;
514 (void) AutoLevelImage(edge_image,exception);
518 width=GetOptimalKernelWidth2D(radius,sigma);
519 kernel=(
double **) MagickAssumeAligned(AcquireAlignedMemory((
size_t)
520 width,
sizeof(*kernel)));
521 if (kernel == (
double **) NULL)
523 edge_image=DestroyImage(edge_image);
524 sharp_image=DestroyImage(sharp_image);
525 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
527 (void) memset(kernel,0,(
size_t) width*
sizeof(*kernel));
528 for (w=0; w < (ssize_t) width; w+=2)
536 kernel[w]=(
double *) MagickAssumeAligned(AcquireAlignedMemory((
size_t)
537 (width-(
size_t) w),(width-(
size_t) w)*
sizeof(**kernel)));
538 if (kernel[w] == (
double *) NULL)
541 j=((ssize_t) width-w-1)/2;
543 for (v=(-j); v <= j; v++)
545 for (u=(-j); u <= j; u++)
547 kernel[w][k]=(double) (-exp(-((
double) u*u+v*v)/(2.0*MagickSigma*
548 MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
549 normalize+=kernel[w][k];
553 kernel[w][(k-1)/2]=(
double) ((-2.0)*normalize);
554 if (sigma < MagickEpsilon)
555 kernel[w][(k-1)/2]=1.0;
557 if (w < (ssize_t) width)
559 for (w-=2; w >= 0; w-=2)
560 kernel[w]=(
double *) RelinquishAlignedMemory(kernel[w]);
561 kernel=(
double **) RelinquishAlignedMemory(kernel);
562 edge_image=DestroyImage(edge_image);
563 sharp_image=DestroyImage(sharp_image);
564 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
571 image_view=AcquireVirtualCacheView(image,exception);
572 edge_view=AcquireVirtualCacheView(edge_image,exception);
573 sharp_view=AcquireAuthenticCacheView(sharp_image,exception);
574#if defined(MAGICKCORE_OPENMP_SUPPORT)
575 #pragma omp parallel for schedule(static) shared(progress,status) \
576 magick_number_threads(image,sharp_image,sharp_image->rows,1)
578 for (y=0; y < (ssize_t) sharp_image->rows; y++)
589 if (status == MagickFalse)
591 r=GetCacheViewVirtualPixels(edge_view,0,y,edge_image->columns,1,exception);
592 q=QueueCacheViewAuthenticPixels(sharp_view,0,y,sharp_image->columns,1,
594 if ((r == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
599 for (x=0; x < (ssize_t) sharp_image->columns; x++)
611 j=CastDoubleToLong(ceil((
double) width*(1.0-QuantumScale*
612 GetPixelIntensity(edge_image,r))-0.5));
616 if (j > (ssize_t) width)
620 p=GetCacheViewVirtualPixels(image_view,x-(((ssize_t) width-j)/2L),y-
621 (((ssize_t) width-j)/2L),width-(
size_t) j,width-(
size_t) j,exception);
622 if (p == (
const Quantum *) NULL)
624 center=(ssize_t) (GetPixelChannels(image)*(width-(
size_t) j)*
625 ((width-(
size_t) j)/2L)+GetPixelChannels(image)*((width-(
size_t) j)/2));
626 for (i=0; i < (ssize_t) GetPixelChannels(sharp_image); i++)
632 *magick_restrict pixels;
650 channel=GetPixelChannelChannel(image,i);
651 traits=GetPixelChannelTraits(image,channel);
652 sharp_traits=GetPixelChannelTraits(sharp_image,channel);
653 if ((traits == UndefinedPixelTrait) ||
654 (sharp_traits == UndefinedPixelTrait))
656 if ((sharp_traits & CopyPixelTrait) != 0)
658 SetPixelChannel(sharp_image,channel,p[center+i],q);
665 if ((sharp_traits & BlendPixelTrait) == 0)
670 for (v=0; v < ((ssize_t) width-j); v++)
672 for (u=0; u < ((ssize_t) width-j); u++)
674 pixel+=(*k)*(double) pixels[i];
677 pixels+=GetPixelChannels(image);
680 gamma=PerceptibleReciprocal(gamma);
681 SetPixelChannel(sharp_image,channel,ClampToQuantum(gamma*pixel),q);
687 for (v=0; v < ((ssize_t) width-j); v++)
689 for (u=0; u < ((ssize_t) width-j); u++)
691 alpha=(double) (QuantumScale*(
double) GetPixelAlpha(image,pixels));
692 pixel+=(*k)*alpha*(double) pixels[i];
695 pixels+=GetPixelChannels(image);
698 gamma=PerceptibleReciprocal(gamma);
699 SetPixelChannel(sharp_image,channel,ClampToQuantum(gamma*pixel),q);
701 q+=GetPixelChannels(sharp_image);
702 r+=GetPixelChannels(edge_image);
704 if (SyncCacheViewAuthenticPixels(sharp_view,exception) == MagickFalse)
706 if (image->progress_monitor != (MagickProgressMonitor) NULL)
711#if defined(MAGICKCORE_OPENMP_SUPPORT)
715 proceed=SetImageProgress(image,AdaptiveSharpenImageTag,progress,
717 if (proceed == MagickFalse)
721 sharp_image->type=image->type;
722 sharp_view=DestroyCacheView(sharp_view);
723 edge_view=DestroyCacheView(edge_view);
724 image_view=DestroyCacheView(image_view);
725 edge_image=DestroyImage(edge_image);
726 for (w=0; w < (ssize_t) width; w+=2)
727 kernel[w]=(
double *) RelinquishAlignedMemory(kernel[w]);
728 kernel=(
double **) RelinquishAlignedMemory(kernel);
729 if (status == MagickFalse)
730 sharp_image=DestroyImage(sharp_image);
767MagickExport
Image *BlurImage(
const Image *image,
const double radius,
771 geometry[MagickPathExtent];
779 assert(image != (
const Image *) NULL);
780 assert(image->signature == MagickCoreSignature);
782 assert(exception->signature == MagickCoreSignature);
783 if (IsEventLogging() != MagickFalse)
784 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
785#if defined(MAGICKCORE_OPENCL_SUPPORT)
786 blur_image=AccelerateBlurImage(image,radius,sigma,exception);
787 if (blur_image != (
Image *) NULL)
790 (void) FormatLocaleString(geometry,MagickPathExtent,
791 "blur:%.20gx%.20g;blur:%.20gx%.20g+90",radius,sigma,radius,sigma);
792 kernel_info=AcquireKernelInfo(geometry,exception);
794 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
795 blur_image=ConvolveImage(image,kernel_info,exception);
796 kernel_info=DestroyKernelInfo(kernel_info);
848static inline double BlurDistance(
const ssize_t x,
const ssize_t y,
849 const ssize_t u,
const ssize_t v)
851 return(sqrt(((
double) x-u)*((
double) x-u)+((
double) y-v)*((
double) y-v)));
854static inline double BlurGaussian(
const double x,
const double sigma)
856 return(exp(-((
double) x*x)*PerceptibleReciprocal(2.0*sigma*sigma))*
857 PerceptibleReciprocal(Magick2PI*sigma*sigma));
860static double **DestroyBilateralTLS(
const size_t number_threads,
866 assert(weights != (
double **) NULL);
867 for (i=0; i <= (ssize_t) number_threads; i++)
868 if (weights[i] != (
double *) NULL)
869 weights[i]=(
double *) RelinquishMagickMemory(weights[i]);
870 weights=(
double **) RelinquishMagickMemory(weights);
874static double **AcquireBilateralTLS(
const size_t number_threads,
875 const size_t width,
const size_t height)
883 weights=(
double **) AcquireQuantumMemory(number_threads+1,
sizeof(*weights));
884 if (weights == (
double **) NULL)
885 return((
double **) NULL);
886 (void) memset(weights,0,number_threads*
sizeof(*weights));
887 for (i=0; i <= (ssize_t) number_threads; i++)
889 weights[i]=(
double *) AcquireQuantumMemory(width,height*
sizeof(**weights));
890 if (weights[i] == (
double *) NULL)
891 return(DestroyBilateralTLS(number_threads,weights));
896MagickExport
Image *BilateralBlurImage(
const Image *image,
const size_t width,
897 const size_t height,
const double intensity_sigma,
const double spatial_sigma,
900#define MaxIntensity (255)
901#define BilateralBlurImageTag "Blur/Image"
908 intensity_gaussian[2*(MaxIntensity+1)],
931 assert(image != (
const Image *) NULL);
932 assert(image->signature == MagickCoreSignature);
934 assert(exception->signature == MagickCoreSignature);
935 if (IsEventLogging() != MagickFalse)
936 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
937 blur_image=CloneImage(image,0,0,MagickTrue,exception);
938 if (blur_image == (
Image *) NULL)
939 return((
Image *) NULL);
940 if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
942 blur_image=DestroyImage(blur_image);
943 return((
Image *) NULL);
945 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
946 weights=AcquireBilateralTLS(number_threads,MagickMax(width,1),
947 MagickMax(height,1));
948 if (weights == (
double **) NULL)
950 blur_image=DestroyImage(blur_image);
951 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
953 for (w=(-MaxIntensity); w < MaxIntensity; w++)
954 intensity_gaussian[w+MaxIntensity]=BlurGaussian((
double) w,intensity_sigma);
955 spatial_gaussian=weights[number_threads];
962 mid.x=(ssize_t) (MagickMax(width,1)/2L);
963 mid.y=(ssize_t) (MagickMax(height,1)/2L);
964 for (v=0; v < (ssize_t) MagickMax(height,1); v++)
969 for (u=0; u < (ssize_t) MagickMax(width,1); u++)
970 spatial_gaussian[n++]=BlurGaussian(BlurDistance(0,0,u-mid.x,v-mid.y),
979 image_view=AcquireVirtualCacheView(image,exception);
980 blur_view=AcquireAuthenticCacheView(blur_image,exception);
981#if defined(MAGICKCORE_OPENMP_SUPPORT)
982 #pragma omp parallel for schedule(static) shared(progress,status) \
983 magick_number_threads(image,blur_image,blur_image->rows,1)
985 for (y=0; y < (ssize_t) blur_image->rows; y++)
988 id = GetOpenMPThreadId();
996 if (status == MagickFalse)
998 q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
1000 if (q == (Quantum *) NULL)
1005 for (x=0; x < (ssize_t) blur_image->columns; x++)
1024 p=GetCacheViewVirtualPixels(image_view,x-mid.x,y-mid.y,MagickMax(width,1),
1025 MagickMax(height,1),exception);
1026 if (p == (
const Quantum *) NULL)
1028 p+=(ssize_t) (GetPixelChannels(image)*MagickMax(width,1)*(
size_t) mid.y+
1029 GetPixelChannels(image)*(
size_t) mid.x);
1031 for (v=0; v < (ssize_t) MagickMax(height,1); v++)
1033 for (u=0; u < (ssize_t) MagickMax(width,1); u++)
1038 r=p+(ssize_t) (GetPixelChannels(image)*MagickMax(width,1)*
1039 (
size_t) (mid.y-v)+GetPixelChannels(image)*(
size_t) (mid.x-u));
1040 intensity=ScaleQuantumToChar(GetPixelIntensity(image,r))-
1041 (double) ScaleQuantumToChar(GetPixelIntensity(image,p));
1042 if ((intensity >= -MaxIntensity) && (intensity <= MaxIntensity))
1043 weights[id][n]=intensity_gaussian[(ssize_t) intensity+MaxIntensity]*
1044 spatial_gaussian[n];
1046 weights[id][n]=BlurGaussian(intensity,intensity_sigma)*
1047 BlurGaussian(BlurDistance(x,y,x+u-mid.x,y+v-mid.y),spatial_sigma);
1051 for (i=0; i < (ssize_t) GetPixelChannels(blur_image); i++)
1060 channel=GetPixelChannelChannel(image,i);
1061 traits=GetPixelChannelTraits(image,channel);
1062 blur_traits=GetPixelChannelTraits(blur_image,channel);
1063 if ((traits == UndefinedPixelTrait) ||
1064 (blur_traits == UndefinedPixelTrait))
1066 if ((blur_traits & CopyPixelTrait) != 0)
1068 SetPixelChannel(blur_image,channel,p[i],q);
1074 if ((blur_traits & BlendPixelTrait) == 0)
1079 for (v=0; v < (ssize_t) MagickMax(height,1); v++)
1081 for (u=0; u < (ssize_t) MagickMax(width,1); u++)
1083 r=p+GetPixelChannels(image)*MagickMax(width,1)*(size_t)
1084 (mid.y-v)+GetPixelChannels(image)*(size_t) (mid.x-u);
1085 pixel+=weights[id][n]*(double) r[i];
1086 gamma+=weights[id][n];
1090 SetPixelChannel(blur_image,channel,ClampToQuantum(
1091 PerceptibleReciprocal(gamma)*pixel),q);
1097 for (v=0; v < (ssize_t) MagickMax(height,1); v++)
1099 for (u=0; u < (ssize_t) MagickMax(width,1); u++)
1105 r=p+GetPixelChannels(image)*MagickMax(width,1)*(size_t) (mid.y-v)+
1106 GetPixelChannels(image)*(size_t) (mid.x-u);
1107 alpha=(double) (QuantumScale*(
double) GetPixelAlpha(image,p));
1108 beta=(double) (QuantumScale*(
double) GetPixelAlpha(image,r));
1109 pixel+=weights[id][n]*(double) r[i];
1110 gamma+=weights[id][n]*alpha*beta;
1114 SetPixelChannel(blur_image,channel,ClampToQuantum(
1115 PerceptibleReciprocal(gamma)*pixel),q);
1117 q+=GetPixelChannels(blur_image);
1119 if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
1121 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1126#if defined(MAGICKCORE_OPENMP_SUPPORT)
1130 proceed=SetImageProgress(image,BilateralBlurImageTag,progress,
1132 if (proceed == MagickFalse)
1136 blur_image->type=image->type;
1137 blur_view=DestroyCacheView(blur_view);
1138 image_view=DestroyCacheView(image_view);
1139 weights=DestroyBilateralTLS(number_threads,weights);
1140 if (status == MagickFalse)
1141 blur_image=DestroyImage(blur_image);
1172MagickExport
Image *ConvolveImage(
const Image *image,
1178 convolve_image=MorphologyImage(image,ConvolveMorphology,1,kernel_info,
1180 return(convolve_image);
1213static void Hull(
const Image *image,
const ssize_t x_offset,
1214 const ssize_t y_offset,
const size_t columns,
const size_t rows,
1215 const int polarity,Quantum *magick_restrict f,Quantum *magick_restrict g)
1226 assert(image != (
const Image *) NULL);
1227 assert(image->signature == MagickCoreSignature);
1228 assert(f != (Quantum *) NULL);
1229 assert(g != (Quantum *) NULL);
1230 assert(columns <= (MAGICK_SSIZE_MAX-2));
1231 if (IsEventLogging() != MagickFalse)
1232 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1235 r=p+(y_offset*((ssize_t) columns+2)+x_offset);
1236#if defined(MAGICKCORE_OPENMP_SUPPORT)
1237 #pragma omp parallel for schedule(static) \
1238 magick_number_threads(image,image,rows,2)
1240 for (y=0; y < (ssize_t) rows; y++)
1249 i=(2*y+1)+y*(ssize_t) columns;
1251 for (x=0; x < (ssize_t) columns; x++)
1253 v=(MagickRealType) p[i];
1254 if ((MagickRealType) r[i] >= (v+(
double) ScaleCharToQuantum(2)))
1255 v+=(double) ScaleCharToQuantum(1);
1260 for (x=0; x < (ssize_t) columns; x++)
1262 v=(MagickRealType) p[i];
1263 if ((MagickRealType) r[i] <= (v-(
double) ScaleCharToQuantum(2)))
1264 v-=(double) ScaleCharToQuantum(1);
1271 r=q+(y_offset*((ssize_t) columns+2)+x_offset);
1272 s=q-(y_offset*((ssize_t) columns+2)+x_offset);
1273#if defined(MAGICKCORE_OPENMP_SUPPORT)
1274 #pragma omp parallel for schedule(static) \
1275 magick_number_threads(image,image,rows,2)
1277 for (y=0; y < (ssize_t) rows; y++)
1286 i=(2*y+1)+y*(ssize_t) columns;
1288 for (x=0; x < (ssize_t) columns; x++)
1290 v=(MagickRealType) q[i];
1291 if (((MagickRealType) s[i] >= (v+(
double) ScaleCharToQuantum(2))) &&
1292 ((MagickRealType) r[i] > v))
1293 v+=(double) ScaleCharToQuantum(1);
1298 for (x=0; x < (ssize_t) columns; x++)
1300 v=(MagickRealType) q[i];
1301 if (((MagickRealType) s[i] <= (v-(
double) ScaleCharToQuantum(2))) &&
1302 ((MagickRealType) r[i] < v))
1303 v-=(double) ScaleCharToQuantum(1);
1312#define DespeckleImageTag "Despeckle/Image"
1329 *magick_restrict buffer,
1330 *magick_restrict pixels;
1338 static const ssize_t
1339 X[4] = {0, 1, 1,-1},
1340 Y[4] = {1, 0, 1, 1};
1345 assert(image != (
const Image *) NULL);
1346 assert(image->signature == MagickCoreSignature);
1348 assert(exception->signature == MagickCoreSignature);
1349 if (IsEventLogging() != MagickFalse)
1350 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1351#if defined(MAGICKCORE_OPENCL_SUPPORT)
1352 despeckle_image=AccelerateDespeckleImage(image,exception);
1353 if (despeckle_image != (
Image *) NULL)
1354 return(despeckle_image);
1356 despeckle_image=CloneImage(image,0,0,MagickTrue,exception);
1357 if (despeckle_image == (
Image *) NULL)
1358 return((
Image *) NULL);
1359 status=SetImageStorageClass(despeckle_image,DirectClass,exception);
1360 if (status == MagickFalse)
1362 despeckle_image=DestroyImage(despeckle_image);
1363 return((
Image *) NULL);
1368 length=(size_t) ((image->columns+2)*(image->rows+2));
1369 pixel_info=AcquireVirtualMemory(length,
sizeof(*pixels));
1370 buffer_info=AcquireVirtualMemory(length,
sizeof(*buffer));
1375 buffer_info=RelinquishVirtualMemory(buffer_info);
1377 pixel_info=RelinquishVirtualMemory(pixel_info);
1378 despeckle_image=DestroyImage(despeckle_image);
1379 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1381 pixels=(Quantum *) GetVirtualMemoryBlob(pixel_info);
1382 buffer=(Quantum *) GetVirtualMemoryBlob(buffer_info);
1387 image_view=AcquireVirtualCacheView(image,exception);
1388 despeckle_view=AcquireAuthenticCacheView(despeckle_image,exception);
1389 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1406 if (status == MagickFalse)
1408 channel=GetPixelChannelChannel(image,i);
1409 traits=GetPixelChannelTraits(image,channel);
1410 despeckle_traits=GetPixelChannelTraits(despeckle_image,channel);
1411 if ((traits == UndefinedPixelTrait) ||
1412 (despeckle_traits == UndefinedPixelTrait))
1414 if ((despeckle_traits & CopyPixelTrait) != 0)
1416 (void) memset(pixels,0,length*
sizeof(*pixels));
1417 j=(ssize_t) image->columns+2;
1418 for (y=0; y < (ssize_t) image->rows; y++)
1423 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1424 if (p == (
const Quantum *) NULL)
1430 for (x=0; x < (ssize_t) image->columns; x++)
1433 p+=GetPixelChannels(image);
1437 (void) memset(buffer,0,length*
sizeof(*buffer));
1438 for (k=0; k < 4; k++)
1440 Hull(image,X[k],Y[k],image->columns,image->rows,1,pixels,buffer);
1441 Hull(image,-X[k],-Y[k],image->columns,image->rows,1,pixels,buffer);
1442 Hull(image,-X[k],-Y[k],image->columns,image->rows,-1,pixels,buffer);
1443 Hull(image,X[k],Y[k],image->columns,image->rows,-1,pixels,buffer);
1445 j=(ssize_t) image->columns+2;
1446 for (y=0; y < (ssize_t) image->rows; y++)
1454 q=GetCacheViewAuthenticPixels(despeckle_view,0,y,despeckle_image->columns,
1456 if (q == (Quantum *) NULL)
1462 for (x=0; x < (ssize_t) image->columns; x++)
1464 SetPixelChannel(despeckle_image,channel,pixels[j++],q);
1465 q+=GetPixelChannels(despeckle_image);
1467 sync=SyncCacheViewAuthenticPixels(despeckle_view,exception);
1468 if (sync == MagickFalse)
1472 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1477 proceed=SetImageProgress(image,DespeckleImageTag,(MagickOffsetType) i,
1478 GetPixelChannels(image));
1479 if (proceed == MagickFalse)
1483 despeckle_view=DestroyCacheView(despeckle_view);
1484 image_view=DestroyCacheView(image_view);
1485 buffer_info=RelinquishVirtualMemory(buffer_info);
1486 pixel_info=RelinquishVirtualMemory(pixel_info);
1487 despeckle_image->type=image->type;
1488 if (status == MagickFalse)
1489 despeckle_image=DestroyImage(despeckle_image);
1490 return(despeckle_image);
1522MagickExport
Image *EdgeImage(
const Image *image,
const double radius,
1537 assert(image != (
const Image *) NULL);
1538 assert(image->signature == MagickCoreSignature);
1540 assert(exception->signature == MagickCoreSignature);
1541 if (IsEventLogging() != MagickFalse)
1542 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1543 width=GetOptimalKernelWidth1D(radius,0.5);
1544 kernel_info=AcquireKernelInfo((
const char *) NULL,exception);
1546 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1547 (void) memset(kernel_info,0,
sizeof(*kernel_info));
1548 kernel_info->width=width;
1549 kernel_info->height=width;
1550 kernel_info->x=(ssize_t) (kernel_info->width-1)/2;
1551 kernel_info->y=(ssize_t) (kernel_info->height-1)/2;
1552 kernel_info->signature=MagickCoreSignature;
1553 kernel_info->values=(MagickRealType *) MagickAssumeAligned(
1554 AcquireAlignedMemory(kernel_info->width,kernel_info->height*
1555 sizeof(*kernel_info->values)));
1556 if (kernel_info->values == (MagickRealType *) NULL)
1558 kernel_info=DestroyKernelInfo(kernel_info);
1559 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1561 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
1562 kernel_info->values[i]=(-1.0);
1563 kernel_info->values[i/2]=(double) kernel_info->width*kernel_info->height-1.0;
1564 edge_image=ConvolveImage(image,kernel_info,exception);
1565 kernel_info=DestroyKernelInfo(kernel_info);
1602MagickExport
Image *EmbossImage(
const Image *image,
const double radius,
1627 assert(image != (
const Image *) NULL);
1628 assert(image->signature == MagickCoreSignature);
1630 assert(exception->signature == MagickCoreSignature);
1631 if (IsEventLogging() != MagickFalse)
1632 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1633 width=GetOptimalKernelWidth1D(radius,sigma);
1634 kernel_info=AcquireKernelInfo((
const char *) NULL,exception);
1636 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1637 kernel_info->width=width;
1638 kernel_info->height=width;
1639 kernel_info->x=(ssize_t) (width-1)/2;
1640 kernel_info->y=(ssize_t) (width-1)/2;
1641 kernel_info->values=(MagickRealType *) MagickAssumeAligned(
1642 AcquireAlignedMemory(kernel_info->width,kernel_info->width*
1643 sizeof(*kernel_info->values)));
1644 if (kernel_info->values == (MagickRealType *) NULL)
1646 kernel_info=DestroyKernelInfo(kernel_info);
1647 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1649 j=(ssize_t) (kernel_info->width-1)/2;
1652 for (v=(-j); v <= j; v++)
1654 for (u=(-j); u <= j; u++)
1656 kernel_info->values[i]=(MagickRealType) (((u < 0) || (v < 0) ? -8.0 :
1657 8.0)*exp(-((
double) u*u+v*v)/(2.0*MagickSigma*MagickSigma))/
1658 (2.0*MagickPI*MagickSigma*MagickSigma));
1660 kernel_info->values[i]=0.0;
1666 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
1667 normalize+=kernel_info->values[i];
1668 gamma=PerceptibleReciprocal(normalize);
1669 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
1670 kernel_info->values[i]*=gamma;
1671 emboss_image=ConvolveImage(image,kernel_info,exception);
1672 kernel_info=DestroyKernelInfo(kernel_info);
1673 if (emboss_image != (
Image *) NULL)
1674 (void) EqualizeImage(emboss_image,exception);
1675 return(emboss_image);
1711MagickExport
Image *GaussianBlurImage(
const Image *image,
const double radius,
1715 geometry[MagickPathExtent];
1723 assert(image != (
const Image *) NULL);
1724 assert(image->signature == MagickCoreSignature);
1726 assert(exception->signature == MagickCoreSignature);
1727 if (IsEventLogging() != MagickFalse)
1728 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1729 (void) FormatLocaleString(geometry,MagickPathExtent,
"gaussian:%.20gx%.20g",
1731 kernel_info=AcquireKernelInfo(geometry,exception);
1733 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1734 blur_image=ConvolveImage(image,kernel_info,exception);
1735 kernel_info=DestroyKernelInfo(kernel_info);
1769static inline MagickRealType GetMeanLuma(
const Image *magick_restrict image,
1770 const double *magick_restrict pixel)
1772 return(0.212656*pixel[image->channel_map[RedPixelChannel].offset]+
1773 0.715158*pixel[image->channel_map[GreenPixelChannel].offset]+
1774 0.072186*pixel[image->channel_map[BluePixelChannel].offset]);
1777MagickExport
Image *KuwaharaImage(
const Image *image,
const double radius,
1780#define KuwaharaImageTag "Kuwahara/Image"
1805 assert(image != (
Image *) NULL);
1806 assert(image->signature == MagickCoreSignature);
1808 assert(exception->signature == MagickCoreSignature);
1809 if (IsEventLogging() != MagickFalse)
1810 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1811 width=(size_t) radius+1;
1812 gaussian_image=BlurImage(image,radius,sigma,exception);
1813 if (gaussian_image == (
Image *) NULL)
1814 return((
Image *) NULL);
1815 kuwahara_image=CloneImage(image,0,0,MagickTrue,exception);
1816 if (kuwahara_image == (
Image *) NULL)
1818 gaussian_image=DestroyImage(gaussian_image);
1819 return((
Image *) NULL);
1821 if (SetImageStorageClass(kuwahara_image,DirectClass,exception) == MagickFalse)
1823 gaussian_image=DestroyImage(gaussian_image);
1824 kuwahara_image=DestroyImage(kuwahara_image);
1825 return((
Image *) NULL);
1832 image_view=AcquireVirtualCacheView(gaussian_image,exception);
1833 kuwahara_view=AcquireAuthenticCacheView(kuwahara_image,exception);
1834#if defined(MAGICKCORE_OPENMP_SUPPORT)
1835 #pragma omp parallel for schedule(static) shared(progress,status) \
1836 magick_number_threads(image,kuwahara_image,gaussian_image->rows,1)
1838 for (y=0; y < (ssize_t) gaussian_image->rows; y++)
1846 if (status == MagickFalse)
1848 q=QueueCacheViewAuthenticPixels(kuwahara_view,0,y,kuwahara_image->columns,1,
1850 if (q == (Quantum *) NULL)
1855 for (x=0; x < (ssize_t) gaussian_image->columns; x++)
1870 min_variance=MagickMaximumValue;
1871 SetGeometry(gaussian_image,&target);
1872 quadrant.width=width;
1873 quadrant.height=width;
1874 for (i=0; i < 4; i++)
1880 mean[MaxPixelChannels],
1895 quadrant.x=x-(ssize_t) (width-1);
1896 quadrant.y=y-(ssize_t) (width-1);
1901 quadrant.y=y-(ssize_t) (width-1);
1906 quadrant.x=x-(ssize_t) (width-1);
1913 p=GetCacheViewVirtualPixels(image_view,quadrant.x,quadrant.y,
1914 quadrant.width,quadrant.height,exception);
1915 if (p == (
const Quantum *) NULL)
1917 for (j=0; j < (ssize_t) GetPixelChannels(gaussian_image); j++)
1920 for (n=0; n < (ssize_t) (width*width); n++)
1922 for (j=0; j < (ssize_t) GetPixelChannels(gaussian_image); j++)
1923 mean[j]+=(
double) k[j];
1924 k+=GetPixelChannels(gaussian_image);
1926 for (j=0; j < (ssize_t) GetPixelChannels(gaussian_image); j++)
1927 mean[j]/=(
double) (width*width);
1930 for (n=0; n < (ssize_t) (width*width); n++)
1935 luma=GetPixelLuma(gaussian_image,k);
1936 variance+=(luma-GetMeanLuma(gaussian_image,mean))*
1937 (luma-GetMeanLuma(gaussian_image,mean));
1938 k+=GetPixelChannels(gaussian_image);
1940 if (variance < min_variance)
1942 min_variance=variance;
1951 status=InterpolatePixelChannels(gaussian_image,image_view,kuwahara_image,
1952 UndefinedInterpolatePixel,(
double) target.x+target.width/2.0,(
double)
1953 target.y+target.height/2.0,q,exception);
1954 if (status == MagickFalse)
1956 q+=GetPixelChannels(kuwahara_image);
1958 if (SyncCacheViewAuthenticPixels(kuwahara_view,exception) == MagickFalse)
1960 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1965#if defined(MAGICKCORE_OPENMP_SUPPORT)
1969 proceed=SetImageProgress(image,KuwaharaImageTag,progress,image->rows);
1970 if (proceed == MagickFalse)
1974 kuwahara_view=DestroyCacheView(kuwahara_view);
1975 image_view=DestroyCacheView(image_view);
1976 gaussian_image=DestroyImage(gaussian_image);
1977 if (status == MagickFalse)
1978 kuwahara_image=DestroyImage(kuwahara_image);
1979 return(kuwahara_image);
2015MagickExport
Image *LocalContrastImage(
const Image *image,
const double radius,
2018#define LocalContrastImageTag "LocalContrast/Image"
2048 assert(image != (
const Image *) NULL);
2049 assert(image->signature == MagickCoreSignature);
2051 assert(exception->signature == MagickCoreSignature);
2052 if (IsEventLogging() != MagickFalse)
2053 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2054#if defined(MAGICKCORE_OPENCL_SUPPORT)
2055 contrast_image=AccelerateLocalContrastImage(image,radius,strength,exception);
2056 if (contrast_image != (
Image *) NULL)
2057 return(contrast_image);
2059 contrast_image=CloneImage(image,0,0,MagickTrue,exception);
2060 if (contrast_image == (
Image *) NULL)
2061 return((
Image *) NULL);
2062 if (SetImageStorageClass(contrast_image,DirectClass,exception) == MagickFalse)
2064 contrast_image=DestroyImage(contrast_image);
2065 return((
Image *) NULL);
2067 image_view=AcquireVirtualCacheView(image,exception);
2068 contrast_view=AcquireAuthenticCacheView(contrast_image,exception);
2069 scanLineSize=(ssize_t) MagickMax(image->columns,image->rows);
2070 width=(ssize_t) scanLineSize*0.002*fabs(radius);
2071 scanLineSize+=(2*width);
2072 scanline_info=AcquireVirtualMemory(GetOpenMPMaximumThreads()*
2073 (
size_t) scanLineSize,
sizeof(*scanline));
2076 contrast_view=DestroyCacheView(contrast_view);
2077 image_view=DestroyCacheView(image_view);
2078 contrast_image=DestroyImage(contrast_image);
2079 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2081 scanline=(
float *) GetVirtualMemoryBlob(scanline_info);
2085 interImage_info=AcquireVirtualMemory(image->rows*(image->columns+(
size_t)
2086 (2*width)),
sizeof(*interImage));
2089 scanline_info=RelinquishVirtualMemory(scanline_info);
2090 contrast_view=DestroyCacheView(contrast_view);
2091 image_view=DestroyCacheView(image_view);
2092 contrast_image=DestroyImage(contrast_image);
2093 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2095 interImage=(
float *) GetVirtualMemoryBlob(interImage_info);
2096 totalWeight=(float) ((width+1)*(width+1));
2105#if defined(MAGICKCORE_OPENMP_SUPPORT)
2106#pragma omp parallel for schedule(static) \
2107 magick_number_threads(image,image,image->columns,1)
2109 for (x=0; x < (ssize_t) image->columns; x++)
2112 id = GetOpenMPThreadId();
2128 if (status == MagickFalse)
2131 pixels+=
id*scanLineSize;
2133 p=GetCacheViewVirtualPixels(image_view,x,-(ssize_t) width,1,
2134 image->rows+(
size_t) (2*width),exception);
2135 if (p == (
const Quantum *) NULL)
2140 for (y=0; y < (ssize_t) image->rows+(2*width); y++)
2142 *pix++=(float)GetPixelLuma(image,p);
2143 p+=image->number_channels;
2145 out=interImage+x+width;
2146 for (y=0; y < (ssize_t) image->rows; y++)
2155 for (i=0; i < width; i++)
2157 sum+=weight*((double) *pix++);
2160 for (i=width+1; i < (2*width); i++)
2162 sum+=weight*((double) *pix++);
2166 *out=sum/totalWeight;
2168 if ((x <= width) && (x != 0))
2170 if ((x > (ssize_t) image->columns-width-2) &&
2171 (x != (ssize_t) image->columns-1))
2172 *(out+((image->columns-(size_t) x-1)*2))=*out;
2173 out+=image->columns+(size_t) (width*2);
2184#if defined(MAGICKCORE_OPENMP_SUPPORT)
2185#pragma omp parallel for schedule(static) \
2186 magick_number_threads(image,image,image->rows,1)
2188 for (y=0; y < (ssize_t) image->rows; y++)
2191 id = GetOpenMPThreadId();
2207 if (status == MagickFalse)
2210 pixels+=
id*scanLineSize;
2211 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2212 q=GetCacheViewAuthenticPixels(contrast_view,0,y,image->columns,1,
2214 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
2219 memcpy(pixels,interImage+((
size_t) y*(image->columns+(
size_t) (2*width))),
2220 (image->columns+(
size_t) (2*width))*
sizeof(
float));
2221 for (x=0; x < (ssize_t) image->columns; x++)
2235 for (i=0; i < width; i++)
2237 sum+=weight*((double) *pix++);
2240 for (i=width+1; i < (2*width); i++)
2242 sum+=weight*((double) *pix++);
2248 srcVal=(float) GetPixelLuma(image,p);
2249 mult=(srcVal-(sum/totalWeight))*(strength/100.0);
2250 mult=(srcVal+mult)/srcVal;
2251 traits=GetPixelChannelTraits(image,RedPixelChannel);
2252 if ((traits & UpdatePixelTrait) != 0)
2253 SetPixelRed(contrast_image,ClampToQuantum((MagickRealType)
2254 GetPixelRed(image,p)*mult),q);
2255 traits=GetPixelChannelTraits(image,GreenPixelChannel);
2256 if ((traits & UpdatePixelTrait) != 0)
2257 SetPixelGreen(contrast_image,ClampToQuantum((MagickRealType)
2258 GetPixelGreen(image,p)*mult),q);
2259 traits=GetPixelChannelTraits(image,BluePixelChannel);
2260 if ((traits & UpdatePixelTrait) != 0)
2261 SetPixelBlue(contrast_image,ClampToQuantum((MagickRealType)
2262 GetPixelBlue(image,p)*mult),q);
2263 p+=image->number_channels;
2264 q+=contrast_image->number_channels;
2266 if (SyncCacheViewAuthenticPixels(contrast_view,exception) == MagickFalse)
2270 scanline_info=RelinquishVirtualMemory(scanline_info);
2271 interImage_info=RelinquishVirtualMemory(interImage_info);
2272 contrast_view=DestroyCacheView(contrast_view);
2273 image_view=DestroyCacheView(image_view);
2274 if (status == MagickFalse)
2275 contrast_image=DestroyImage(contrast_image);
2276 return(contrast_image);
2318static MagickRealType *GetMotionBlurKernel(
const size_t width,
2331 if (IsEventLogging() != MagickFalse)
2332 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
2333 kernel=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory((
size_t)
2334 width,
sizeof(*kernel)));
2335 if (kernel == (MagickRealType *) NULL)
2338 for (i=0; i < (ssize_t) width; i++)
2340 kernel[i]=(MagickRealType) (exp((-((
double) i*i)/(
double) (2.0*MagickSigma*
2341 MagickSigma)))/(MagickSQ2PI*MagickSigma));
2342 normalize+=kernel[i];
2344 for (i=0; i < (ssize_t) width; i++)
2345 kernel[i]/=normalize;
2349MagickExport
Image *MotionBlurImage(
const Image *image,
const double radius,
2350 const double sigma,
const double angle,
ExceptionInfo *exception)
2352#define BlurImageTag "Blur/Image"
2384 assert(image != (
Image *) NULL);
2385 assert(image->signature == MagickCoreSignature);
2387 assert(exception->signature == MagickCoreSignature);
2388 if (IsEventLogging() != MagickFalse)
2389 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2390 width=GetOptimalKernelWidth1D(radius,sigma);
2391 kernel=GetMotionBlurKernel(width,sigma);
2392 if (kernel == (MagickRealType *) NULL)
2393 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2394 offset=(
OffsetInfo *) AcquireQuantumMemory(width,
sizeof(*offset));
2397 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2398 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2400 point.x=(double) width*sin(DegreesToRadians(angle));
2401 point.y=(double) width*cos(DegreesToRadians(angle));
2402 for (w=0; w < (ssize_t) width; w++)
2404 offset[w].x=CastDoubleToLong(ceil((
double) (w*point.y)/
2405 hypot(point.x,point.y)-0.5));
2406 offset[w].y=CastDoubleToLong(ceil((
double) (w*point.x)/
2407 hypot(point.x,point.y)-0.5));
2412#if defined(MAGICKCORE_OPENCL_SUPPORT)
2413 blur_image=AccelerateMotionBlurImage(image,kernel,width,offset,exception);
2414 if (blur_image != (
Image *) NULL)
2416 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2417 offset=(
OffsetInfo *) RelinquishMagickMemory(offset);
2421 blur_image=CloneImage(image,0,0,MagickTrue,exception);
2422 if (blur_image == (
Image *) NULL)
2424 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2425 offset=(
OffsetInfo *) RelinquishMagickMemory(offset);
2426 return((
Image *) NULL);
2428 if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
2430 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2431 offset=(
OffsetInfo *) RelinquishMagickMemory(offset);
2432 blur_image=DestroyImage(blur_image);
2433 return((
Image *) NULL);
2437 image_view=AcquireVirtualCacheView(image,exception);
2438 motion_view=AcquireVirtualCacheView(image,exception);
2439 blur_view=AcquireAuthenticCacheView(blur_image,exception);
2440#if defined(MAGICKCORE_OPENMP_SUPPORT)
2441 #pragma omp parallel for schedule(static) shared(progress,status) \
2442 magick_number_threads(image,blur_image,image->rows,1)
2444 for (y=0; y < (ssize_t) image->rows; y++)
2455 if (status == MagickFalse)
2457 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2458 q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
2460 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
2465 for (x=0; x < (ssize_t) image->columns; x++)
2470 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2493 channel=GetPixelChannelChannel(image,i);
2494 traits=GetPixelChannelTraits(image,channel);
2495 blur_traits=GetPixelChannelTraits(blur_image,channel);
2496 if ((traits == UndefinedPixelTrait) ||
2497 (blur_traits == UndefinedPixelTrait))
2499 if ((blur_traits & CopyPixelTrait) != 0)
2501 SetPixelChannel(blur_image,channel,p[i],q);
2506 if ((blur_traits & BlendPixelTrait) == 0)
2508 for (j=0; j < (ssize_t) width; j++)
2510 r=GetCacheViewVirtualPixels(motion_view,x+offset[j].x,y+
2511 offset[j].y,1,1,exception);
2512 if (r == (
const Quantum *) NULL)
2517 pixel+=(*k)*(double) r[i];
2520 SetPixelChannel(blur_image,channel,ClampToQuantum(pixel),q);
2523 for (j=0; j < (ssize_t) width; j++)
2525 r=GetCacheViewVirtualPixels(motion_view,x+offset[j].x,y+offset[j].y,1,
2527 if (r == (
const Quantum *) NULL)
2532 alpha=QuantumScale*(double) GetPixelAlpha(image,r);
2533 pixel+=(*k)*alpha*(double) r[i];
2537 gamma=PerceptibleReciprocal(gamma);
2538 SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
2540 p+=GetPixelChannels(image);
2541 q+=GetPixelChannels(blur_image);
2543 if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
2545 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2550#if defined(MAGICKCORE_OPENMP_SUPPORT)
2554 proceed=SetImageProgress(image,BlurImageTag,progress,image->rows);
2555 if (proceed == MagickFalse)
2559 blur_view=DestroyCacheView(blur_view);
2560 motion_view=DestroyCacheView(motion_view);
2561 image_view=DestroyCacheView(image_view);
2562 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2563 offset=(
OffsetInfo *) RelinquishMagickMemory(offset);
2564 if (status == MagickFalse)
2565 blur_image=DestroyImage(blur_image);
2599MagickExport
Image *PreviewImage(
const Image *image,
const PreviewType preview,
2602#define NumberTiles 9
2603#define PreviewImageTag "Preview/Image"
2604#define DefaultPreviewGeometry "204x204+10+10"
2607 factor[MagickPathExtent],
2608 label[MagickPathExtent];
2650 assert(image != (
Image *) NULL);
2651 assert(image->signature == MagickCoreSignature);
2652 if (IsEventLogging() != MagickFalse)
2653 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2657 preview_info=AcquireImageInfo();
2658 SetGeometry(image,&geometry);
2659 (void) ParseMetaGeometry(DefaultPreviewGeometry,&geometry.x,&geometry.y,
2660 &geometry.width,&geometry.height);
2661 images=NewImageList();
2663 GetQuantizeInfo(&quantize_info);
2667 for (i=0; i < NumberTiles; i++)
2669 thumbnail=ThumbnailImage(image,geometry.width,geometry.height,exception);
2670 if (thumbnail == (
Image *) NULL)
2672 (void) SetImageProgressMonitor(thumbnail,(MagickProgressMonitor) NULL,
2674 (void) SetImageProperty(thumbnail,
"label",DefaultTileLabel,exception);
2675 if (i == (NumberTiles/2))
2677 (void) QueryColorCompliance(
"#dfdfdf",AllCompliance,
2678 &thumbnail->matte_color,exception);
2679 AppendImageToList(&images,thumbnail);
2687 preview_image=RotateImage(thumbnail,degrees,exception);
2688 (void) FormatLocaleString(label,MagickPathExtent,
"rotate %g",degrees);
2694 preview_image=ShearImage(thumbnail,degrees,degrees,exception);
2695 (void) FormatLocaleString(label,MagickPathExtent,
"shear %gx%g",degrees,
2701 x=((i+1)*(ssize_t) thumbnail->columns)/NumberTiles;
2702 y=((i+1)*(ssize_t) thumbnail->rows)/NumberTiles;
2703 preview_image=RollImage(thumbnail,x,y,exception);
2704 (void) FormatLocaleString(label,MagickPathExtent,
"roll %+.20gx%+.20g",
2705 (
double) x,(
double) y);
2710 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2711 if (preview_image == (
Image *) NULL)
2713 (void) FormatLocaleString(factor,MagickPathExtent,
"100,100,%g",2.0*
2715 (void) ModulateImage(preview_image,factor,exception);
2716 (void) FormatLocaleString(label,MagickPathExtent,
"modulate %s",factor);
2719 case SaturationPreview:
2721 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2722 if (preview_image == (
Image *) NULL)
2724 (void) FormatLocaleString(factor,MagickPathExtent,
"100,%g",2.0*
2726 (void) ModulateImage(preview_image,factor,exception);
2727 (void) FormatLocaleString(label,MagickPathExtent,
"modulate %s",factor);
2730 case BrightnessPreview:
2732 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2733 if (preview_image == (
Image *) NULL)
2735 (void) FormatLocaleString(factor,MagickPathExtent,
"%g",2.0*percentage);
2736 (void) ModulateImage(preview_image,factor,exception);
2737 (void) FormatLocaleString(label,MagickPathExtent,
"modulate %s",factor);
2743 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2744 if (preview_image == (
Image *) NULL)
2747 (void) GammaImage(preview_image,gamma,exception);
2748 (void) FormatLocaleString(label,MagickPathExtent,
"gamma %g",gamma);
2753 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2754 if (preview_image != (
Image *) NULL)
2755 for (x=0; x < i; x++)
2756 (
void) ContrastImage(preview_image,MagickTrue,exception);
2757 (void) FormatLocaleString(label,MagickPathExtent,
"contrast (%.20g)",
2763 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2764 if (preview_image == (
Image *) NULL)
2766 for (x=0; x < i; x++)
2767 (
void) ContrastImage(preview_image,MagickFalse,exception);
2768 (void) FormatLocaleString(label,MagickPathExtent,
"+contrast (%.20g)",
2772 case GrayscalePreview:
2774 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2775 if (preview_image == (
Image *) NULL)
2778 quantize_info.number_colors=colors;
2779 quantize_info.colorspace=GRAYColorspace;
2780 (void) QuantizeImage(&quantize_info,preview_image,exception);
2781 (void) FormatLocaleString(label,MagickPathExtent,
2782 "-colorspace gray -colors %.20g",(
double) colors);
2785 case QuantizePreview:
2787 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2788 if (preview_image == (
Image *) NULL)
2791 quantize_info.number_colors=colors;
2792 (void) QuantizeImage(&quantize_info,preview_image,exception);
2793 (void) FormatLocaleString(label,MagickPathExtent,
"colors %.20g",
2797 case DespecklePreview:
2799 for (x=0; x < (i-1); x++)
2801 preview_image=DespeckleImage(thumbnail,exception);
2802 if (preview_image == (
Image *) NULL)
2804 thumbnail=DestroyImage(thumbnail);
2805 thumbnail=preview_image;
2807 preview_image=DespeckleImage(thumbnail,exception);
2808 if (preview_image == (
Image *) NULL)
2810 (void) FormatLocaleString(label,MagickPathExtent,
"despeckle (%.20g)",
2814 case ReduceNoisePreview:
2816 preview_image=StatisticImage(thumbnail,NonpeakStatistic,(
size_t)
2817 radius,(
size_t) radius,exception);
2818 (void) FormatLocaleString(label,MagickPathExtent,
"noise %g",radius);
2821 case AddNoisePreview:
2827 (void) CopyMagickString(factor,
"uniform",MagickPathExtent);
2832 (void) CopyMagickString(factor,
"gaussian",MagickPathExtent);
2837 (void) CopyMagickString(factor,
"multiplicative",MagickPathExtent);
2842 (void) CopyMagickString(factor,
"impulse",MagickPathExtent);
2847 (void) CopyMagickString(factor,
"laplacian",MagickPathExtent);
2852 (void) CopyMagickString(factor,
"Poisson",MagickPathExtent);
2857 (void) CopyMagickString(thumbnail->magick,
"NULL",MagickPathExtent);
2861 preview_image=StatisticImage(thumbnail,NonpeakStatistic,(
size_t) i,
2862 (
size_t) i,exception);
2863 (void) FormatLocaleString(label,MagickPathExtent,
"+noise %s",factor);
2866 case SharpenPreview:
2868 preview_image=SharpenImage(thumbnail,radius,sigma,exception);
2869 (void) FormatLocaleString(label,MagickPathExtent,
"sharpen %gx%g",
2875 preview_image=BlurImage(thumbnail,radius,sigma,exception);
2876 (void) FormatLocaleString(label,MagickPathExtent,
"blur %gx%g",radius,
2880 case ThresholdPreview:
2882 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2883 if (preview_image == (
Image *) NULL)
2885 (void) BilevelImage(thumbnail,(
double) (percentage*((
double)
2886 QuantumRange+1.0))/100.0,exception);
2887 (void) FormatLocaleString(label,MagickPathExtent,
"threshold %g",
2888 (
double) (percentage*((
double) QuantumRange+1.0))/100.0);
2891 case EdgeDetectPreview:
2893 preview_image=EdgeImage(thumbnail,radius,exception);
2894 (void) FormatLocaleString(label,MagickPathExtent,
"edge %g",radius);
2899 preview_image=SpreadImage(thumbnail,image->interpolate,radius,
2901 (void) FormatLocaleString(label,MagickPathExtent,
"spread %g",
2905 case SolarizePreview:
2907 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2908 if (preview_image == (
Image *) NULL)
2910 (void) SolarizeImage(preview_image,(
double) QuantumRange*percentage/
2912 (void) FormatLocaleString(label,MagickPathExtent,
"solarize %g",
2913 ((
double) QuantumRange*percentage)/100.0);
2919 preview_image=ShadeImage(thumbnail,MagickTrue,degrees,degrees,
2921 (void) FormatLocaleString(label,MagickPathExtent,
"shade %gx%g",degrees,
2930 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2931 if (preview_image == (
Image *) NULL)
2933 raise.width=(size_t) (2*i+2);
2934 raise.height=(size_t) (2*i+2);
2937 (void) RaiseImage(preview_image,&raise,MagickTrue,exception);
2938 (void) FormatLocaleString(label,MagickPathExtent,
2939 "raise %.20gx%.20g%+.20g%+.20g",(
double) raise.width,(
double)
2940 raise.height,(
double) raise.x,(
double) raise.y);
2943 case SegmentPreview:
2945 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2946 if (preview_image == (
Image *) NULL)
2949 (void) SegmentImage(preview_image,sRGBColorspace,MagickFalse,threshold,
2950 threshold,exception);
2951 (void) FormatLocaleString(label,MagickPathExtent,
"segment %gx%g",
2952 threshold,threshold);
2957 preview_image=SwirlImage(thumbnail,degrees,image->interpolate,
2959 (void) FormatLocaleString(label,MagickPathExtent,
"swirl %g",degrees);
2963 case ImplodePreview:
2966 preview_image=ImplodeImage(thumbnail,degrees,image->interpolate,
2968 (void) FormatLocaleString(label,MagickPathExtent,
"implode %g",degrees);
2974 preview_image=WaveImage(thumbnail,0.5*degrees,2.0*degrees,
2975 image->interpolate,exception);
2976 (void) FormatLocaleString(label,MagickPathExtent,
"wave %gx%g",0.5*
2977 degrees,2.0*degrees);
2980 case OilPaintPreview:
2982 preview_image=OilPaintImage(thumbnail,(
double) radius,(
double) sigma,
2984 (void) FormatLocaleString(label,MagickPathExtent,
"charcoal %gx%g",
2988 case CharcoalDrawingPreview:
2990 preview_image=CharcoalImage(thumbnail,(
double) radius,(
double) sigma,
2992 (void) FormatLocaleString(label,MagickPathExtent,
"charcoal %gx%g",
2999 filename[MagickPathExtent];
3007 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
3008 if (preview_image == (
Image *) NULL)
3010 preview_info->quality=(size_t) percentage;
3011 (void) FormatLocaleString(factor,MagickPathExtent,
"%.20g",(
double)
3012 preview_info->quality);
3013 file=AcquireUniqueFileResource(filename);
3016 (void) FormatLocaleString(preview_image->filename,MagickPathExtent,
3017 "jpeg:%s",filename);
3018 status=WriteImage(preview_info,preview_image,exception);
3019 if (status != MagickFalse)
3024 (void) CopyMagickString(preview_info->filename,
3025 preview_image->filename,MagickPathExtent);
3026 quality_image=ReadImage(preview_info,exception);
3027 if (quality_image != (
Image *) NULL)
3029 preview_image=DestroyImage(preview_image);
3030 preview_image=quality_image;
3033 (void) RelinquishUniqueFileResource(preview_image->filename);
3034 if ((GetBlobSize(preview_image)/1024) >= 1024)
3035 (void) FormatLocaleString(label,MagickPathExtent,
"quality %s\n%gmb ",
3036 factor,(
double) ((MagickOffsetType) GetBlobSize(preview_image))/
3039 if (GetBlobSize(preview_image) >= 1024)
3040 (void) FormatLocaleString(label,MagickPathExtent,
3041 "quality %s\n%gkb ",factor,(
double) ((MagickOffsetType)
3042 GetBlobSize(preview_image))/1024.0);
3044 (
void) FormatLocaleString(label,MagickPathExtent,
3045 "quality %s\n%.20gb ",factor,(
double) ((MagickOffsetType)
3046 GetBlobSize(thumbnail)));
3050 thumbnail=DestroyImage(thumbnail);
3054 if (preview_image == (
Image *) NULL)
3056 preview_image->alpha_trait=UndefinedPixelTrait;
3057 (void) DeleteImageProperty(preview_image,
"label");
3058 (void) SetImageProperty(preview_image,
"label",label,exception);
3059 AppendImageToList(&images,preview_image);
3060 proceed=SetImageProgress(image,PreviewImageTag,(MagickOffsetType) i,
3062 if (proceed == MagickFalse)
3065 if (images == (
Image *) NULL)
3067 preview_info=DestroyImageInfo(preview_info);
3068 return((
Image *) NULL);
3073 montage_info=CloneMontageInfo(preview_info,(
MontageInfo *) NULL);
3074 (void) CopyMagickString(montage_info->filename,image->filename,
3076 montage_info->shadow=MagickTrue;
3077 (void) CloneString(&montage_info->tile,
"3x3");
3078 (void) CloneString(&montage_info->geometry,DefaultPreviewGeometry);
3079 (void) CloneString(&montage_info->frame,DefaultTileFrame);
3080 montage_image=MontageImages(images,montage_info,exception);
3081 montage_info=DestroyMontageInfo(montage_info);
3082 images=DestroyImageList(images);
3083 if (montage_image == (
Image *) NULL)
3084 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3085 if (montage_image->montage != (
char *) NULL)
3090 montage_image->montage=(
char *) RelinquishMagickMemory(
3091 montage_image->montage);
3092 if (image->directory != (
char *) NULL)
3093 montage_image->directory=(
char *) RelinquishMagickMemory(
3094 montage_image->directory);
3096 preview_info=DestroyImageInfo(preview_info);
3097 return(montage_image);
3131MagickExport
Image *RotationalBlurImage(
const Image *image,
const double angle,
3168 assert(image != (
Image *) NULL);
3169 assert(image->signature == MagickCoreSignature);
3171 assert(exception->signature == MagickCoreSignature);
3172 if (IsEventLogging() != MagickFalse)
3173 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3174#if defined(MAGICKCORE_OPENCL_SUPPORT)
3175 blur_image=AccelerateRotationalBlurImage(image,angle,exception);
3176 if (blur_image != (
Image *) NULL)
3179 blur_image=CloneImage(image,0,0,MagickTrue,exception);
3180 if (blur_image == (
Image *) NULL)
3181 return((
Image *) NULL);
3182 if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
3184 blur_image=DestroyImage(blur_image);
3185 return((
Image *) NULL);
3187 blur_center.x=(double) (image->columns-1)/2.0;
3188 blur_center.y=(double) (image->rows-1)/2.0;
3189 blur_radius=hypot(blur_center.x,blur_center.y);
3190 n=(size_t) fabs(4.0*DegreesToRadians(angle)*sqrt((
double) blur_radius)+2UL);
3191 theta=DegreesToRadians(angle)/(double) (n-1);
3192 cos_theta=(
double *) AcquireQuantumMemory((
size_t) n,
sizeof(*cos_theta));
3193 sin_theta=(
double *) AcquireQuantumMemory((
size_t) n,
sizeof(*sin_theta));
3194 if ((cos_theta == (
double *) NULL) || (sin_theta == (
double *) NULL))
3196 if (cos_theta != (
double *) NULL)
3197 cos_theta=(
double *) RelinquishMagickMemory(cos_theta);
3198 if (sin_theta != (
double *) NULL)
3199 sin_theta=(
double *) RelinquishMagickMemory(sin_theta);
3200 blur_image=DestroyImage(blur_image);
3201 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3203 offset=theta*(double) (n-1)/2.0;
3204 for (w=0; w < (ssize_t) n; w++)
3206 cos_theta[w]=cos((
double) (theta*w-offset));
3207 sin_theta[w]=sin((
double) (theta*w-offset));
3214 image_view=AcquireVirtualCacheView(image,exception);
3215 radial_view=AcquireVirtualCacheView(image,exception);
3216 blur_view=AcquireAuthenticCacheView(blur_image,exception);
3217#if defined(MAGICKCORE_OPENMP_SUPPORT)
3218 #pragma omp parallel for schedule(static) shared(progress,status) \
3219 magick_number_threads(image,blur_image,image->rows,1)
3221 for (y=0; y < (ssize_t) image->rows; y++)
3232 if (status == MagickFalse)
3234 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
3235 q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
3237 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3242 for (x=0; x < (ssize_t) image->columns; x++)
3256 center.x=(double) x-blur_center.x;
3257 center.y=(double) y-blur_center.y;
3258 radius=hypot((
double) center.x,center.y);
3263 step=(size_t) (blur_radius/radius);
3270 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3289 channel=GetPixelChannelChannel(image,i);
3290 traits=GetPixelChannelTraits(image,channel);
3291 blur_traits=GetPixelChannelTraits(blur_image,channel);
3292 if ((traits == UndefinedPixelTrait) ||
3293 (blur_traits == UndefinedPixelTrait))
3295 if ((blur_traits & CopyPixelTrait) != 0)
3297 SetPixelChannel(blur_image,channel,p[i],q);
3302 if ((GetPixelChannelTraits(image,AlphaPixelChannel) == UndefinedPixelTrait) ||
3303 (channel == AlphaPixelChannel))
3305 for (j=0; j < (ssize_t) n; j+=(ssize_t) step)
3307 r=GetCacheViewVirtualPixels(radial_view, (ssize_t) (blur_center.x+
3308 center.x*cos_theta[j]-center.y*sin_theta[j]+0.5),(ssize_t)
3309 (blur_center.y+center.x*sin_theta[j]+center.y*cos_theta[j]+0.5),
3311 if (r == (
const Quantum *) NULL)
3316 pixel+=(double) r[i];
3319 gamma=PerceptibleReciprocal(gamma);
3320 SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
3323 for (j=0; j < (ssize_t) n; j+=(ssize_t) step)
3328 r=GetCacheViewVirtualPixels(radial_view, (ssize_t) (blur_center.x+
3329 center.x*cos_theta[j]-center.y*sin_theta[j]+0.5),(ssize_t)
3330 (blur_center.y+center.x*sin_theta[j]+center.y*cos_theta[j]+0.5),
3332 if (r == (
const Quantum *) NULL)
3337 alpha=QuantumScale*(double) GetPixelAlpha(image,r);
3338 pixel+=alpha*(double) r[i];
3341 gamma=PerceptibleReciprocal(gamma);
3342 SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
3344 p+=GetPixelChannels(image);
3345 q+=GetPixelChannels(blur_image);
3347 if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
3349 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3354#if defined(MAGICKCORE_OPENMP_SUPPORT)
3358 proceed=SetImageProgress(image,BlurImageTag,progress,image->rows);
3359 if (proceed == MagickFalse)
3363 blur_view=DestroyCacheView(blur_view);
3364 radial_view=DestroyCacheView(radial_view);
3365 image_view=DestroyCacheView(image_view);
3366 cos_theta=(
double *) RelinquishMagickMemory(cos_theta);
3367 sin_theta=(
double *) RelinquishMagickMemory(sin_theta);
3368 if (status == MagickFalse)
3369 blur_image=DestroyImage(blur_image);
3408MagickExport
Image *SelectiveBlurImage(
const Image *image,
const double radius,
3409 const double sigma,
const double threshold,
ExceptionInfo *exception)
3411#define SelectiveBlurImageTag "SelectiveBlur/Image"
3441 assert(image != (
Image *) NULL);
3442 assert(image->signature == MagickCoreSignature);
3444 assert(exception->signature == MagickCoreSignature);
3445 if (IsEventLogging() != MagickFalse)
3446 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3447 width=GetOptimalKernelWidth1D(radius,sigma);
3448 kernel=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory((
size_t)
3449 width,width*
sizeof(*kernel)));
3450 if (kernel == (MagickRealType *) NULL)
3451 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3458 j=(ssize_t) (width-1)/2;
3460 for (v=(-j); v <= j; v++)
3465 for (u=(-j); u <= j; u++)
3466 kernel[i++]=(MagickRealType) (exp(-((
double) u*u+v*v)/(2.0*MagickSigma*
3467 MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
3470 if (image->debug != MagickFalse)
3473 format[MagickPathExtent],
3476 const MagickRealType
3483 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
3484 " SelectiveBlurImage with %.20gx%.20g kernel:",(
double) width,(
double)
3486 message=AcquireString(
"");
3488 for (v=0; v < (ssize_t) width; v++)
3491 (void) FormatLocaleString(format,MagickPathExtent,
"%.20g: ",(
double) v);
3492 (void) ConcatenateString(&message,format);
3493 for (u=0; u < (ssize_t) width; u++)
3495 (void) FormatLocaleString(format,MagickPathExtent,
"%+f ",(
double)
3497 (void) ConcatenateString(&message,format);
3499 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
"%s",message);
3501 message=DestroyString(message);
3503 blur_image=CloneImage(image,0,0,MagickTrue,exception);
3504 if (blur_image == (
Image *) NULL)
3505 return((
Image *) NULL);
3506 if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
3508 blur_image=DestroyImage(blur_image);
3509 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
3510 return((
Image *) NULL);
3512 luminance_image=CloneImage(image,0,0,MagickTrue,exception);
3513 if (luminance_image == (
Image *) NULL)
3515 blur_image=DestroyImage(blur_image);
3516 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
3517 return((
Image *) NULL);
3519 status=TransformImageColorspace(luminance_image,GRAYColorspace,exception);
3520 if (status == MagickFalse)
3522 luminance_image=DestroyImage(luminance_image);
3523 blur_image=DestroyImage(blur_image);
3524 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
3525 return((
Image *) NULL);
3532 center=(ssize_t) (GetPixelChannels(image)*(image->columns+width)*
3533 ((width-1)/2L)+GetPixelChannels(image)*((width-1)/2L));
3534 image_view=AcquireVirtualCacheView(image,exception);
3535 luminance_view=AcquireVirtualCacheView(luminance_image,exception);
3536 blur_view=AcquireAuthenticCacheView(blur_image,exception);
3537#if defined(MAGICKCORE_OPENMP_SUPPORT)
3538 #pragma omp parallel for schedule(static) shared(progress,status) \
3539 magick_number_threads(image,blur_image,image->rows,1)
3541 for (y=0; y < (ssize_t) image->rows; y++)
3559 if (status == MagickFalse)
3561 p=GetCacheViewVirtualPixels(image_view,-((ssize_t) (width-1)/2L),y-(ssize_t)
3562 ((width-1)/2L),image->columns+width,width,exception);
3563 l=GetCacheViewVirtualPixels(luminance_view,-((ssize_t) (width-1)/2L),y-
3564 (ssize_t) ((width-1)/2L),luminance_image->columns+width,width,exception);
3565 q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
3567 if ((p == (
const Quantum *) NULL) || (l == (
const Quantum *) NULL) ||
3568 (q == (Quantum *) NULL))
3573 for (x=0; x < (ssize_t) image->columns; x++)
3581 intensity=GetPixelIntensity(image,p+center);
3582 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3596 const MagickRealType
3600 *magick_restrict luminance_pixels,
3601 *magick_restrict pixels;
3609 channel=GetPixelChannelChannel(image,i);
3610 traits=GetPixelChannelTraits(image,channel);
3611 blur_traits=GetPixelChannelTraits(blur_image,channel);
3612 if ((traits == UndefinedPixelTrait) ||
3613 (blur_traits == UndefinedPixelTrait))
3615 if ((blur_traits & CopyPixelTrait) != 0)
3617 SetPixelChannel(blur_image,channel,p[center+i],q);
3625 if ((blur_traits & BlendPixelTrait) == 0)
3627 for (v=0; v < (ssize_t) width; v++)
3629 for (u=0; u < (ssize_t) width; u++)
3631 contrast=GetPixelIntensity(luminance_image,luminance_pixels)-
3633 if (fabs(contrast) < threshold)
3635 pixel+=(*k)*(double) pixels[i];
3639 pixels+=GetPixelChannels(image);
3640 luminance_pixels+=GetPixelChannels(luminance_image);
3642 pixels+=GetPixelChannels(image)*image->columns;
3643 luminance_pixels+=GetPixelChannels(luminance_image)*
3644 luminance_image->columns;
3646 if (fabs((
double) gamma) < MagickEpsilon)
3648 SetPixelChannel(blur_image,channel,p[center+i],q);
3651 gamma=PerceptibleReciprocal(gamma);
3652 SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
3655 for (v=0; v < (ssize_t) width; v++)
3657 for (u=0; u < (ssize_t) width; u++)
3659 contrast=GetPixelIntensity(image,pixels)-intensity;
3660 if (fabs(contrast) < threshold)
3662 alpha=QuantumScale*(double) GetPixelAlpha(image,pixels);
3663 pixel+=(*k)*alpha*(double) pixels[i];
3667 pixels+=GetPixelChannels(image);
3668 luminance_pixels+=GetPixelChannels(luminance_image);
3670 pixels+=GetPixelChannels(image)*image->columns;
3671 luminance_pixels+=GetPixelChannels(luminance_image)*
3672 luminance_image->columns;
3674 if (fabs((
double) gamma) < MagickEpsilon)
3676 SetPixelChannel(blur_image,channel,p[center+i],q);
3679 gamma=PerceptibleReciprocal(gamma);
3680 SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
3682 p+=GetPixelChannels(image);
3683 l+=GetPixelChannels(luminance_image);
3684 q+=GetPixelChannels(blur_image);
3686 sync=SyncCacheViewAuthenticPixels(blur_view,exception);
3687 if (sync == MagickFalse)
3689 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3694#if defined(MAGICKCORE_OPENMP_SUPPORT)
3698 proceed=SetImageProgress(image,SelectiveBlurImageTag,progress,
3700 if (proceed == MagickFalse)
3704 blur_image->type=image->type;
3705 blur_view=DestroyCacheView(blur_view);
3706 luminance_view=DestroyCacheView(luminance_view);
3707 image_view=DestroyCacheView(image_view);
3708 luminance_image=DestroyImage(luminance_image);
3709 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
3710 if (status == MagickFalse)
3711 blur_image=DestroyImage(blur_image);
3747MagickExport
Image *ShadeImage(
const Image *image,
const MagickBooleanType gray,
3748 const double azimuth,
const double elevation,
ExceptionInfo *exception)
3750#define GetShadeIntensity(image,pixel) \
3751 ClampPixel(GetPixelIntensity((image),(pixel)))
3752#define ShadeImageTag "Shade/Image"
3777 assert(image != (
const Image *) NULL);
3778 assert(image->signature == MagickCoreSignature);
3780 assert(exception->signature == MagickCoreSignature);
3781 if (IsEventLogging() != MagickFalse)
3782 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3783 linear_image=CloneImage(image,0,0,MagickTrue,exception);
3784 shade_image=CloneImage(image,0,0,MagickTrue,exception);
3785 if ((linear_image == (
Image *) NULL) || (shade_image == (
Image *) NULL))
3787 if (linear_image != (
Image *) NULL)
3788 linear_image=DestroyImage(linear_image);
3789 if (shade_image != (
Image *) NULL)
3790 shade_image=DestroyImage(shade_image);
3791 return((
Image *) NULL);
3793 if (SetImageStorageClass(shade_image,DirectClass,exception) == MagickFalse)
3795 linear_image=DestroyImage(linear_image);
3796 shade_image=DestroyImage(shade_image);
3797 return((
Image *) NULL);
3802 light.x=(double) QuantumRange*cos(DegreesToRadians(azimuth))*
3803 cos(DegreesToRadians(elevation));
3804 light.y=(double) QuantumRange*sin(DegreesToRadians(azimuth))*
3805 cos(DegreesToRadians(elevation));
3806 light.z=(double) QuantumRange*sin(DegreesToRadians(elevation));
3812 image_view=AcquireVirtualCacheView(linear_image,exception);
3813 shade_view=AcquireAuthenticCacheView(shade_image,exception);
3814#if defined(MAGICKCORE_OPENMP_SUPPORT)
3815 #pragma omp parallel for schedule(static) shared(progress,status) \
3816 magick_number_threads(linear_image,shade_image,linear_image->rows,1)
3818 for (y=0; y < (ssize_t) linear_image->rows; y++)
3829 *magick_restrict center,
3831 *magick_restrict post,
3832 *magick_restrict pre;
3840 if (status == MagickFalse)
3842 p=GetCacheViewVirtualPixels(image_view,-1,y-1,linear_image->columns+2,3,
3844 q=QueueCacheViewAuthenticPixels(shade_view,0,y,shade_image->columns,1,
3846 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3854 normal.z=2.0*(double) QuantumRange;
3855 for (x=0; x < (ssize_t) linear_image->columns; x++)
3863 pre=p+GetPixelChannels(linear_image);
3864 center=pre+(linear_image->columns+2)*GetPixelChannels(linear_image);
3865 post=center+(linear_image->columns+2)*GetPixelChannels(linear_image);
3867 GetShadeIntensity(linear_image,pre-GetPixelChannels(linear_image))+
3868 GetShadeIntensity(linear_image,center-GetPixelChannels(linear_image))+
3869 GetShadeIntensity(linear_image,post-GetPixelChannels(linear_image))-
3870 GetShadeIntensity(linear_image,pre+GetPixelChannels(linear_image))-
3871 GetShadeIntensity(linear_image,center+GetPixelChannels(linear_image))-
3872 GetShadeIntensity(linear_image,post+GetPixelChannels(linear_image)));
3874 GetShadeIntensity(linear_image,post-GetPixelChannels(linear_image))+
3875 GetShadeIntensity(linear_image,post)+
3876 GetShadeIntensity(linear_image,post+GetPixelChannels(linear_image))-
3877 GetShadeIntensity(linear_image,pre-GetPixelChannels(linear_image))-
3878 GetShadeIntensity(linear_image,pre)-
3879 GetShadeIntensity(linear_image,pre+GetPixelChannels(linear_image)));
3880 if ((fabs(normal.x) <= MagickEpsilon) &&
3881 (fabs(normal.y) <= MagickEpsilon))
3886 distance=normal.x*light.x+normal.y*light.y+normal.z*light.z;
3887 if (distance > MagickEpsilon)
3889 normal_distance=normal.x*normal.x+normal.y*normal.y+
3891 if (normal_distance > (MagickEpsilon*MagickEpsilon))
3892 shade=distance/sqrt((
double) normal_distance);
3895 for (i=0; i < (ssize_t) GetPixelChannels(linear_image); i++)
3904 channel=GetPixelChannelChannel(linear_image,i);
3905 traits=GetPixelChannelTraits(linear_image,channel);
3906 shade_traits=GetPixelChannelTraits(shade_image,channel);
3907 if ((traits == UndefinedPixelTrait) ||
3908 (shade_traits == UndefinedPixelTrait))
3910 if ((shade_traits & CopyPixelTrait) != 0)
3912 SetPixelChannel(shade_image,channel,center[i],q);
3915 if ((traits & UpdatePixelTrait) == 0)
3917 SetPixelChannel(shade_image,channel,center[i],q);
3920 if (gray != MagickFalse)
3922 SetPixelChannel(shade_image,channel,ClampToQuantum(shade),q);
3925 SetPixelChannel(shade_image,channel,ClampToQuantum(QuantumScale*
3926 shade*(
double) center[i]),q);
3928 p+=GetPixelChannels(linear_image);
3929 q+=GetPixelChannels(shade_image);
3931 if (SyncCacheViewAuthenticPixels(shade_view,exception) == MagickFalse)
3933 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3938#if defined(MAGICKCORE_OPENMP_SUPPORT)
3942 proceed=SetImageProgress(image,ShadeImageTag,progress,image->rows);
3943 if (proceed == MagickFalse)
3947 shade_view=DestroyCacheView(shade_view);
3948 image_view=DestroyCacheView(image_view);
3949 linear_image=DestroyImage(linear_image);
3950 if (status == MagickFalse)
3951 shade_image=DestroyImage(shade_image);
3952 return(shade_image);
3993MagickExport
Image *SharpenImage(
const Image *image,
const double radius,
4017 assert(image != (
const Image *) NULL);
4018 assert(image->signature == MagickCoreSignature);
4020 assert(exception->signature == MagickCoreSignature);
4021 if (IsEventLogging() != MagickFalse)
4022 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4023 width=GetOptimalKernelWidth2D(radius,sigma);
4024 kernel_info=AcquireKernelInfo((
const char *) NULL,exception);
4026 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
4027 (void) memset(kernel_info,0,
sizeof(*kernel_info));
4028 kernel_info->width=width;
4029 kernel_info->height=width;
4030 kernel_info->x=(ssize_t) (width-1)/2;
4031 kernel_info->y=(ssize_t) (width-1)/2;
4032 kernel_info->signature=MagickCoreSignature;
4033 kernel_info->values=(MagickRealType *) MagickAssumeAligned(
4034 AcquireAlignedMemory(kernel_info->width,kernel_info->height*
4035 sizeof(*kernel_info->values)));
4036 if (kernel_info->values == (MagickRealType *) NULL)
4038 kernel_info=DestroyKernelInfo(kernel_info);
4039 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
4042 j=(ssize_t) (kernel_info->width-1)/2;
4044 for (v=(-j); v <= j; v++)
4046 for (u=(-j); u <= j; u++)
4048 kernel_info->values[i]=(MagickRealType) (-exp(-((
double) u*u+v*v)/(2.0*
4049 MagickSigma*MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
4050 normalize+=kernel_info->values[i];
4054 kernel_info->values[i/2]=(double) ((-2.0)*normalize);
4056 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
4057 normalize+=kernel_info->values[i];
4058 gamma=PerceptibleReciprocal(normalize);
4059 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
4060 kernel_info->values[i]*=gamma;
4061 sharp_image=ConvolveImage(image,kernel_info,exception);
4062 kernel_info=DestroyKernelInfo(kernel_info);
4063 return(sharp_image);
4097MagickExport
Image *SpreadImage(
const Image *image,
4098 const PixelInterpolateMethod method,
const double radius,
4101#define SpreadImageTag "Spread/Image"
4117 **magick_restrict random_info;
4125#if defined(MAGICKCORE_OPENMP_SUPPORT)
4133 assert(image != (
Image *) NULL);
4134 assert(image->signature == MagickCoreSignature);
4136 assert(exception->signature == MagickCoreSignature);
4137 if (IsEventLogging() != MagickFalse)
4138 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4139 spread_image=CloneImage(image,0,0,MagickTrue,exception);
4140 if (spread_image == (
Image *) NULL)
4141 return((
Image *) NULL);
4142 if (SetImageStorageClass(spread_image,DirectClass,exception) == MagickFalse)
4144 spread_image=DestroyImage(spread_image);
4145 return((
Image *) NULL);
4152 width=GetOptimalKernelWidth1D(radius,0.5);
4153 random_info=AcquireRandomInfoTLS();
4154 image_view=AcquireVirtualCacheView(image,exception);
4155 spread_view=AcquireAuthenticCacheView(spread_image,exception);
4156#if defined(MAGICKCORE_OPENMP_SUPPORT)
4157 key=GetRandomSecretKey(random_info[0]);
4158 #pragma omp parallel for schedule(static) shared(progress,status) \
4159 magick_number_threads(image,spread_image,image->rows,key == ~0UL)
4161 for (y=0; y < (ssize_t) image->rows; y++)
4164 id = GetOpenMPThreadId();
4172 if (status == MagickFalse)
4174 q=QueueCacheViewAuthenticPixels(spread_view,0,y,spread_image->columns,1,
4176 if (q == (Quantum *) NULL)
4181 for (x=0; x < (ssize_t) image->columns; x++)
4186 point.x=GetPseudoRandomValue(random_info[
id]);
4187 point.y=GetPseudoRandomValue(random_info[
id]);
4188 status=InterpolatePixelChannels(image,image_view,spread_image,method,
4189 (
double) x+width*(point.x-0.5),(
double) y+width*(point.y-0.5),q,
4191 if (status == MagickFalse)
4193 q+=GetPixelChannels(spread_image);
4195 if (SyncCacheViewAuthenticPixels(spread_view,exception) == MagickFalse)
4197 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4202#if defined(MAGICKCORE_OPENMP_SUPPORT)
4206 proceed=SetImageProgress(image,SpreadImageTag,progress,image->rows);
4207 if (proceed == MagickFalse)
4211 spread_view=DestroyCacheView(spread_view);
4212 image_view=DestroyCacheView(image_view);
4213 random_info=DestroyRandomInfoTLS(random_info);
4214 if (status == MagickFalse)
4215 spread_image=DestroyImage(spread_image);
4216 return(spread_image);
4258MagickExport
Image *UnsharpMaskImage(
const Image *image,
const double radius,
4259 const double sigma,
const double gain,
const double threshold,
4262#define SharpenImageTag "Sharpen/Image"
4283 assert(image != (
const Image *) NULL);
4284 assert(image->signature == MagickCoreSignature);
4286 assert(exception->signature == MagickCoreSignature);
4287 if (IsEventLogging() != MagickFalse)
4288 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4297 unsharp_image=BlurImage(image,radius,sigma,exception);
4298 if (unsharp_image == (
Image *) NULL)
4299 return((
Image *) NULL);
4300 quantum_threshold=(double) QuantumRange*threshold;
4306 image_view=AcquireVirtualCacheView(image,exception);
4307 unsharp_view=AcquireAuthenticCacheView(unsharp_image,exception);
4308#if defined(MAGICKCORE_OPENMP_SUPPORT)
4309 #pragma omp parallel for schedule(static) shared(progress,status) \
4310 magick_number_threads(image,unsharp_image,image->rows,1)
4312 for (y=0; y < (ssize_t) image->rows; y++)
4323 if (status == MagickFalse)
4325 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
4326 q=GetCacheViewAuthenticPixels(unsharp_view,0,y,unsharp_image->columns,1,
4328 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
4333 for (x=0; x < (ssize_t) image->columns; x++)
4338 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4350 channel=GetPixelChannelChannel(image,i);
4351 traits=GetPixelChannelTraits(image,channel);
4352 unsharp_traits=GetPixelChannelTraits(unsharp_image,channel);
4353 if ((traits == UndefinedPixelTrait) ||
4354 (unsharp_traits == UndefinedPixelTrait))
4356 if ((unsharp_traits & CopyPixelTrait) != 0)
4358 SetPixelChannel(unsharp_image,channel,p[i],q);
4361 pixel=(double) p[i]-(
double) GetPixelChannel(unsharp_image,channel,q);
4362 if (fabs(2.0*pixel) < quantum_threshold)
4363 pixel=(double) p[i];
4365 pixel=(double) p[i]+gain*pixel;
4366 SetPixelChannel(unsharp_image,channel,ClampToQuantum(pixel),q);
4368 p+=GetPixelChannels(image);
4369 q+=GetPixelChannels(unsharp_image);
4371 if (SyncCacheViewAuthenticPixels(unsharp_view,exception) == MagickFalse)
4373 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4378#if defined(MAGICKCORE_OPENMP_SUPPORT)
4382 proceed=SetImageProgress(image,SharpenImageTag,progress,image->rows);
4383 if (proceed == MagickFalse)
4387 unsharp_image->type=image->type;
4388 unsharp_view=DestroyCacheView(unsharp_view);
4389 image_view=DestroyCacheView(image_view);
4390 if (status == MagickFalse)
4391 unsharp_image=DestroyImage(unsharp_image);
4392 return(unsharp_image);