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 if (IsEventLogging() != MagickFalse)
1231 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1234 r=p+(y_offset*((ssize_t) columns+2)+x_offset);
1235#if defined(MAGICKCORE_OPENMP_SUPPORT)
1236 #pragma omp parallel for schedule(static) \
1237 magick_number_threads(image,image,rows,2)
1239 for (y=0; y < (ssize_t) rows; y++)
1248 i=(2*y+1)+y*(ssize_t) columns;
1250 for (x=0; x < (ssize_t) columns; x++)
1252 v=(MagickRealType) p[i];
1253 if ((MagickRealType) r[i] >= (v+(double) ScaleCharToQuantum(2)))
1254 v+=(double) ScaleCharToQuantum(1);
1259 for (x=0; x < (ssize_t) columns; x++)
1261 v=(MagickRealType) p[i];
1262 if ((MagickRealType) r[i] <= (v-(double) ScaleCharToQuantum(2)))
1263 v-=(double) ScaleCharToQuantum(1);
1270 r=q+(y_offset*((ssize_t) columns+2)+x_offset);
1271 s=q-(y_offset*((ssize_t) columns+2)+x_offset);
1272#if defined(MAGICKCORE_OPENMP_SUPPORT)
1273 #pragma omp parallel for schedule(static) \
1274 magick_number_threads(image,image,rows,2)
1276 for (y=0; y < (ssize_t) rows; y++)
1285 i=(2*y+1)+y*(ssize_t) columns;
1287 for (x=0; x < (ssize_t) columns; x++)
1289 v=(MagickRealType) q[i];
1290 if (((MagickRealType) s[i] >= (v+(double) ScaleCharToQuantum(2))) &&
1291 ((MagickRealType) r[i] > v))
1292 v+=(
double) ScaleCharToQuantum(1);
1297 for (x=0; x < (ssize_t) columns; x++)
1299 v=(MagickRealType) q[i];
1300 if (((MagickRealType) s[i] <= (v-(double) ScaleCharToQuantum(2))) &&
1301 ((MagickRealType) r[i] < v))
1302 v-=(
double) ScaleCharToQuantum(1);
1311#define DespeckleImageTag "Despeckle/Image"
1328 *magick_restrict buffer,
1329 *magick_restrict pixels;
1337 static const ssize_t
1338 X[4] = {0, 1, 1,-1},
1339 Y[4] = {1, 0, 1, 1};
1344 assert(image != (
const Image *) NULL);
1345 assert(image->signature == MagickCoreSignature);
1347 assert(exception->signature == MagickCoreSignature);
1348 if (IsEventLogging() != MagickFalse)
1349 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1350#if defined(MAGICKCORE_OPENCL_SUPPORT)
1351 despeckle_image=AccelerateDespeckleImage(image,exception);
1352 if (despeckle_image != (
Image *) NULL)
1353 return(despeckle_image);
1355 despeckle_image=CloneImage(image,0,0,MagickTrue,exception);
1356 if (despeckle_image == (
Image *) NULL)
1357 return((
Image *) NULL);
1358 status=SetImageStorageClass(despeckle_image,DirectClass,exception);
1359 if (status == MagickFalse)
1361 despeckle_image=DestroyImage(despeckle_image);
1362 return((
Image *) NULL);
1367 length=(size_t) ((image->columns+2)*(image->rows+2));
1368 pixel_info=AcquireVirtualMemory(length,
sizeof(*pixels));
1369 buffer_info=AcquireVirtualMemory(length,
sizeof(*buffer));
1374 buffer_info=RelinquishVirtualMemory(buffer_info);
1376 pixel_info=RelinquishVirtualMemory(pixel_info);
1377 despeckle_image=DestroyImage(despeckle_image);
1378 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1380 pixels=(Quantum *) GetVirtualMemoryBlob(pixel_info);
1381 buffer=(Quantum *) GetVirtualMemoryBlob(buffer_info);
1386 image_view=AcquireVirtualCacheView(image,exception);
1387 despeckle_view=AcquireAuthenticCacheView(despeckle_image,exception);
1388 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1405 if (status == MagickFalse)
1407 channel=GetPixelChannelChannel(image,i);
1408 traits=GetPixelChannelTraits(image,channel);
1409 despeckle_traits=GetPixelChannelTraits(despeckle_image,channel);
1410 if ((traits == UndefinedPixelTrait) ||
1411 (despeckle_traits == UndefinedPixelTrait))
1413 if ((despeckle_traits & CopyPixelTrait) != 0)
1415 (void) memset(pixels,0,length*
sizeof(*pixels));
1416 j=(ssize_t) image->columns+2;
1417 for (y=0; y < (ssize_t) image->rows; y++)
1422 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1423 if (p == (
const Quantum *) NULL)
1429 for (x=0; x < (ssize_t) image->columns; x++)
1432 p+=GetPixelChannels(image);
1436 (void) memset(buffer,0,length*
sizeof(*buffer));
1437 for (k=0; k < 4; k++)
1439 Hull(image,X[k],Y[k],image->columns,image->rows,1,pixels,buffer);
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);
1444 j=(ssize_t) image->columns+2;
1445 for (y=0; y < (ssize_t) image->rows; y++)
1453 q=GetCacheViewAuthenticPixels(despeckle_view,0,y,despeckle_image->columns,
1455 if (q == (Quantum *) NULL)
1461 for (x=0; x < (ssize_t) image->columns; x++)
1463 SetPixelChannel(despeckle_image,channel,pixels[j++],q);
1464 q+=GetPixelChannels(despeckle_image);
1466 sync=SyncCacheViewAuthenticPixels(despeckle_view,exception);
1467 if (sync == MagickFalse)
1471 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1476 proceed=SetImageProgress(image,DespeckleImageTag,(MagickOffsetType) i,
1477 GetPixelChannels(image));
1478 if (proceed == MagickFalse)
1482 despeckle_view=DestroyCacheView(despeckle_view);
1483 image_view=DestroyCacheView(image_view);
1484 buffer_info=RelinquishVirtualMemory(buffer_info);
1485 pixel_info=RelinquishVirtualMemory(pixel_info);
1486 despeckle_image->type=image->type;
1487 if (status == MagickFalse)
1488 despeckle_image=DestroyImage(despeckle_image);
1489 return(despeckle_image);
1521MagickExport
Image *EdgeImage(
const Image *image,
const double radius,
1536 assert(image != (
const Image *) NULL);
1537 assert(image->signature == MagickCoreSignature);
1539 assert(exception->signature == MagickCoreSignature);
1540 if (IsEventLogging() != MagickFalse)
1541 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1542 width=GetOptimalKernelWidth1D(radius,0.5);
1543 kernel_info=AcquireKernelInfo((
const char *) NULL,exception);
1545 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1546 (void) memset(kernel_info,0,
sizeof(*kernel_info));
1547 kernel_info->width=width;
1548 kernel_info->height=width;
1549 kernel_info->x=(ssize_t) (kernel_info->width-1)/2;
1550 kernel_info->y=(ssize_t) (kernel_info->height-1)/2;
1551 kernel_info->signature=MagickCoreSignature;
1552 kernel_info->values=(MagickRealType *) MagickAssumeAligned(
1553 AcquireAlignedMemory(kernel_info->width,kernel_info->height*
1554 sizeof(*kernel_info->values)));
1555 if (kernel_info->values == (MagickRealType *) NULL)
1557 kernel_info=DestroyKernelInfo(kernel_info);
1558 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1560 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
1561 kernel_info->values[i]=(-1.0);
1562 kernel_info->values[i/2]=(double) kernel_info->width*kernel_info->height-1.0;
1563 edge_image=ConvolveImage(image,kernel_info,exception);
1564 kernel_info=DestroyKernelInfo(kernel_info);
1601MagickExport
Image *EmbossImage(
const Image *image,
const double radius,
1626 assert(image != (
const Image *) NULL);
1627 assert(image->signature == MagickCoreSignature);
1629 assert(exception->signature == MagickCoreSignature);
1630 if (IsEventLogging() != MagickFalse)
1631 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1632 width=GetOptimalKernelWidth1D(radius,sigma);
1633 kernel_info=AcquireKernelInfo((
const char *) NULL,exception);
1635 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1636 kernel_info->width=width;
1637 kernel_info->height=width;
1638 kernel_info->x=(ssize_t) (width-1)/2;
1639 kernel_info->y=(ssize_t) (width-1)/2;
1640 kernel_info->values=(MagickRealType *) MagickAssumeAligned(
1641 AcquireAlignedMemory(kernel_info->width,kernel_info->width*
1642 sizeof(*kernel_info->values)));
1643 if (kernel_info->values == (MagickRealType *) NULL)
1645 kernel_info=DestroyKernelInfo(kernel_info);
1646 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1648 j=(ssize_t) (kernel_info->width-1)/2;
1651 for (v=(-j); v <= j; v++)
1653 for (u=(-j); u <= j; u++)
1655 kernel_info->values[i]=(MagickRealType) (((u < 0) || (v < 0) ? -8.0 :
1656 8.0)*exp(-((double) u*u+v*v)/(2.0*MagickSigma*MagickSigma))/
1657 (2.0*MagickPI*MagickSigma*MagickSigma));
1659 kernel_info->values[i]=0.0;
1665 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
1666 normalize+=kernel_info->values[i];
1667 gamma=PerceptibleReciprocal(normalize);
1668 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
1669 kernel_info->values[i]*=gamma;
1670 emboss_image=ConvolveImage(image,kernel_info,exception);
1671 kernel_info=DestroyKernelInfo(kernel_info);
1672 if (emboss_image != (
Image *) NULL)
1673 (void) EqualizeImage(emboss_image,exception);
1674 return(emboss_image);
1710MagickExport
Image *GaussianBlurImage(
const Image *image,
const double radius,
1714 geometry[MagickPathExtent];
1722 assert(image != (
const Image *) NULL);
1723 assert(image->signature == MagickCoreSignature);
1725 assert(exception->signature == MagickCoreSignature);
1726 if (IsEventLogging() != MagickFalse)
1727 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1728 (void) FormatLocaleString(geometry,MagickPathExtent,
"gaussian:%.20gx%.20g",
1730 kernel_info=AcquireKernelInfo(geometry,exception);
1732 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1733 blur_image=ConvolveImage(image,kernel_info,exception);
1734 kernel_info=DestroyKernelInfo(kernel_info);
1768static inline MagickRealType GetMeanLuma(
const Image *magick_restrict image,
1769 const double *magick_restrict pixel)
1771 return(0.212656*pixel[image->channel_map[RedPixelChannel].offset]+
1772 0.715158*pixel[image->channel_map[GreenPixelChannel].offset]+
1773 0.072186*pixel[image->channel_map[BluePixelChannel].offset]);
1776MagickExport
Image *KuwaharaImage(
const Image *image,
const double radius,
1779#define KuwaharaImageTag "Kuwahara/Image"
1804 assert(image != (
Image *) NULL);
1805 assert(image->signature == MagickCoreSignature);
1807 assert(exception->signature == MagickCoreSignature);
1808 if (IsEventLogging() != MagickFalse)
1809 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1810 width=(size_t) radius+1;
1811 gaussian_image=BlurImage(image,radius,sigma,exception);
1812 if (gaussian_image == (
Image *) NULL)
1813 return((
Image *) NULL);
1814 kuwahara_image=CloneImage(image,0,0,MagickTrue,exception);
1815 if (kuwahara_image == (
Image *) NULL)
1817 gaussian_image=DestroyImage(gaussian_image);
1818 return((
Image *) NULL);
1820 if (SetImageStorageClass(kuwahara_image,DirectClass,exception) == MagickFalse)
1822 gaussian_image=DestroyImage(gaussian_image);
1823 kuwahara_image=DestroyImage(kuwahara_image);
1824 return((
Image *) NULL);
1831 image_view=AcquireVirtualCacheView(gaussian_image,exception);
1832 kuwahara_view=AcquireAuthenticCacheView(kuwahara_image,exception);
1833#if defined(MAGICKCORE_OPENMP_SUPPORT)
1834 #pragma omp parallel for schedule(static) shared(progress,status) \
1835 magick_number_threads(image,kuwahara_image,gaussian_image->rows,1)
1837 for (y=0; y < (ssize_t) gaussian_image->rows; y++)
1845 if (status == MagickFalse)
1847 q=QueueCacheViewAuthenticPixels(kuwahara_view,0,y,kuwahara_image->columns,1,
1849 if (q == (Quantum *) NULL)
1854 for (x=0; x < (ssize_t) gaussian_image->columns; x++)
1869 min_variance=MagickMaximumValue;
1870 SetGeometry(gaussian_image,&target);
1871 quadrant.width=width;
1872 quadrant.height=width;
1873 for (i=0; i < 4; i++)
1879 mean[MaxPixelChannels],
1894 quadrant.x=x-(ssize_t) (width-1);
1895 quadrant.y=y-(ssize_t) (width-1);
1900 quadrant.y=y-(ssize_t) (width-1);
1905 quadrant.x=x-(ssize_t) (width-1);
1912 p=GetCacheViewVirtualPixels(image_view,quadrant.x,quadrant.y,
1913 quadrant.width,quadrant.height,exception);
1914 if (p == (
const Quantum *) NULL)
1916 for (j=0; j < (ssize_t) GetPixelChannels(gaussian_image); j++)
1919 for (n=0; n < (ssize_t) (width*width); n++)
1921 for (j=0; j < (ssize_t) GetPixelChannels(gaussian_image); j++)
1922 mean[j]+=(
double) k[j];
1923 k+=GetPixelChannels(gaussian_image);
1925 for (j=0; j < (ssize_t) GetPixelChannels(gaussian_image); j++)
1926 mean[j]/=(
double) (width*width);
1929 for (n=0; n < (ssize_t) (width*width); n++)
1934 luma=GetPixelLuma(gaussian_image,k);
1935 variance+=(luma-GetMeanLuma(gaussian_image,mean))*
1936 (luma-GetMeanLuma(gaussian_image,mean));
1937 k+=GetPixelChannels(gaussian_image);
1939 if (variance < min_variance)
1941 min_variance=variance;
1950 status=InterpolatePixelChannels(gaussian_image,image_view,kuwahara_image,
1951 UndefinedInterpolatePixel,(
double) target.x+target.width/2.0,(
double)
1952 target.y+target.height/2.0,q,exception);
1953 if (status == MagickFalse)
1955 q+=GetPixelChannels(kuwahara_image);
1957 if (SyncCacheViewAuthenticPixels(kuwahara_view,exception) == MagickFalse)
1959 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1964#if defined(MAGICKCORE_OPENMP_SUPPORT)
1968 proceed=SetImageProgress(image,KuwaharaImageTag,progress,image->rows);
1969 if (proceed == MagickFalse)
1973 kuwahara_view=DestroyCacheView(kuwahara_view);
1974 image_view=DestroyCacheView(image_view);
1975 gaussian_image=DestroyImage(gaussian_image);
1976 if (status == MagickFalse)
1977 kuwahara_image=DestroyImage(kuwahara_image);
1978 return(kuwahara_image);
2014MagickExport
Image *LocalContrastImage(
const Image *image,
const double radius,
2017#define LocalContrastImageTag "LocalContrast/Image"
2047 assert(image != (
const Image *) NULL);
2048 assert(image->signature == MagickCoreSignature);
2050 assert(exception->signature == MagickCoreSignature);
2051 if (IsEventLogging() != MagickFalse)
2052 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2053#if defined(MAGICKCORE_OPENCL_SUPPORT)
2054 contrast_image=AccelerateLocalContrastImage(image,radius,strength,exception);
2055 if (contrast_image != (
Image *) NULL)
2056 return(contrast_image);
2058 contrast_image=CloneImage(image,0,0,MagickTrue,exception);
2059 if (contrast_image == (
Image *) NULL)
2060 return((
Image *) NULL);
2061 if (SetImageStorageClass(contrast_image,DirectClass,exception) == MagickFalse)
2063 contrast_image=DestroyImage(contrast_image);
2064 return((
Image *) NULL);
2066 image_view=AcquireVirtualCacheView(image,exception);
2067 contrast_view=AcquireAuthenticCacheView(contrast_image,exception);
2068 scanLineSize=(ssize_t) MagickMax(image->columns,image->rows);
2069 width=(ssize_t) scanLineSize*0.002*fabs(radius);
2070 scanLineSize+=(2*width);
2071 scanline_info=AcquireVirtualMemory(GetOpenMPMaximumThreads()*
2072 (
size_t) scanLineSize,
sizeof(*scanline));
2075 contrast_view=DestroyCacheView(contrast_view);
2076 image_view=DestroyCacheView(image_view);
2077 contrast_image=DestroyImage(contrast_image);
2078 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2080 scanline=(
float *) GetVirtualMemoryBlob(scanline_info);
2084 interImage_info=AcquireVirtualMemory(image->rows*(image->columns+(
size_t)
2085 (2*width)),
sizeof(*interImage));
2088 scanline_info=RelinquishVirtualMemory(scanline_info);
2089 contrast_view=DestroyCacheView(contrast_view);
2090 image_view=DestroyCacheView(image_view);
2091 contrast_image=DestroyImage(contrast_image);
2092 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2094 interImage=(
float *) GetVirtualMemoryBlob(interImage_info);
2095 totalWeight=(float) ((width+1)*(width+1));
2104#if defined(MAGICKCORE_OPENMP_SUPPORT)
2105#pragma omp parallel for schedule(static) \
2106 magick_number_threads(image,image,image->columns,1)
2108 for (x=0; x < (ssize_t) image->columns; x++)
2111 id = GetOpenMPThreadId();
2127 if (status == MagickFalse)
2130 pixels+=
id*scanLineSize;
2132 p=GetCacheViewVirtualPixels(image_view,x,-(ssize_t) width,1,
2133 image->rows+(
size_t) (2*width),exception);
2134 if (p == (
const Quantum *) NULL)
2139 for (y=0; y < (ssize_t) image->rows+(2*width); y++)
2141 *pix++=(float)GetPixelLuma(image,p);
2142 p+=image->number_channels;
2144 out=interImage+x+width;
2145 for (y=0; y < (ssize_t) image->rows; y++)
2154 for (i=0; i < width; i++)
2156 sum+=weight*((double) *pix++);
2159 for (i=width+1; i < (2*width); i++)
2161 sum+=weight*((double) *pix++);
2165 *out=sum/totalWeight;
2167 if ((x <= width) && (x != 0))
2169 if ((x > (ssize_t) image->columns-width-2) &&
2170 (x != (ssize_t) image->columns-1))
2171 *(out+((image->columns-(size_t) x-1)*2))=*out;
2172 out+=image->columns+(size_t) (width*2);
2183#if defined(MAGICKCORE_OPENMP_SUPPORT)
2184#pragma omp parallel for schedule(static) \
2185 magick_number_threads(image,image,image->rows,1)
2187 for (y=0; y < (ssize_t) image->rows; y++)
2190 id = GetOpenMPThreadId();
2206 if (status == MagickFalse)
2209 pixels+=
id*scanLineSize;
2210 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2211 q=GetCacheViewAuthenticPixels(contrast_view,0,y,image->columns,1,
2213 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
2218 memcpy(pixels,interImage+((
size_t) y*(image->columns+(
size_t) (2*width))),
2219 (image->columns+(
size_t) (2*width))*
sizeof(
float));
2220 for (x=0; x < (ssize_t) image->columns; x++)
2234 for (i=0; i < width; i++)
2236 sum+=weight*((double) *pix++);
2239 for (i=width+1; i < (2*width); i++)
2241 sum+=weight*((double) *pix++);
2247 srcVal=(float) GetPixelLuma(image,p);
2248 mult=(srcVal-(sum/totalWeight))*(strength/100.0);
2249 mult=(srcVal+mult)/srcVal;
2250 traits=GetPixelChannelTraits(image,RedPixelChannel);
2251 if ((traits & UpdatePixelTrait) != 0)
2252 SetPixelRed(contrast_image,ClampToQuantum((MagickRealType)
2253 GetPixelRed(image,p)*mult),q);
2254 traits=GetPixelChannelTraits(image,GreenPixelChannel);
2255 if ((traits & UpdatePixelTrait) != 0)
2256 SetPixelGreen(contrast_image,ClampToQuantum((MagickRealType)
2257 GetPixelGreen(image,p)*mult),q);
2258 traits=GetPixelChannelTraits(image,BluePixelChannel);
2259 if ((traits & UpdatePixelTrait) != 0)
2260 SetPixelBlue(contrast_image,ClampToQuantum((MagickRealType)
2261 GetPixelBlue(image,p)*mult),q);
2262 p+=image->number_channels;
2263 q+=contrast_image->number_channels;
2265 if (SyncCacheViewAuthenticPixels(contrast_view,exception) == MagickFalse)
2269 scanline_info=RelinquishVirtualMemory(scanline_info);
2270 interImage_info=RelinquishVirtualMemory(interImage_info);
2271 contrast_view=DestroyCacheView(contrast_view);
2272 image_view=DestroyCacheView(image_view);
2273 if (status == MagickFalse)
2274 contrast_image=DestroyImage(contrast_image);
2275 return(contrast_image);
2317static MagickRealType *GetMotionBlurKernel(
const size_t width,
2330 if (IsEventLogging() != MagickFalse)
2331 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
2332 kernel=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory((
size_t)
2333 width,
sizeof(*kernel)));
2334 if (kernel == (MagickRealType *) NULL)
2337 for (i=0; i < (ssize_t) width; i++)
2339 kernel[i]=(MagickRealType) (exp((-((
double) i*i)/(
double) (2.0*MagickSigma*
2340 MagickSigma)))/(MagickSQ2PI*MagickSigma));
2341 normalize+=kernel[i];
2343 for (i=0; i < (ssize_t) width; i++)
2344 kernel[i]/=normalize;
2348MagickExport
Image *MotionBlurImage(
const Image *image,
const double radius,
2349 const double sigma,
const double angle,
ExceptionInfo *exception)
2351#define BlurImageTag "Blur/Image"
2383 assert(image != (
Image *) NULL);
2384 assert(image->signature == MagickCoreSignature);
2386 assert(exception->signature == MagickCoreSignature);
2387 if (IsEventLogging() != MagickFalse)
2388 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2389 width=GetOptimalKernelWidth1D(radius,sigma);
2390 kernel=GetMotionBlurKernel(width,sigma);
2391 if (kernel == (MagickRealType *) NULL)
2392 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2393 offset=(
OffsetInfo *) AcquireQuantumMemory(width,
sizeof(*offset));
2396 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2397 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2399 point.x=(double) width*sin(DegreesToRadians(angle));
2400 point.y=(double) width*cos(DegreesToRadians(angle));
2401 for (w=0; w < (ssize_t) width; w++)
2403 offset[w].x=CastDoubleToLong(ceil((
double) (w*point.y)/
2404 hypot(point.x,point.y)-0.5));
2405 offset[w].y=CastDoubleToLong(ceil((
double) (w*point.x)/
2406 hypot(point.x,point.y)-0.5));
2411#if defined(MAGICKCORE_OPENCL_SUPPORT)
2412 blur_image=AccelerateMotionBlurImage(image,kernel,width,offset,exception);
2413 if (blur_image != (
Image *) NULL)
2415 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2416 offset=(
OffsetInfo *) RelinquishMagickMemory(offset);
2420 blur_image=CloneImage(image,0,0,MagickTrue,exception);
2421 if (blur_image == (
Image *) NULL)
2423 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2424 offset=(
OffsetInfo *) RelinquishMagickMemory(offset);
2425 return((
Image *) NULL);
2427 if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
2429 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2430 offset=(
OffsetInfo *) RelinquishMagickMemory(offset);
2431 blur_image=DestroyImage(blur_image);
2432 return((
Image *) NULL);
2436 image_view=AcquireVirtualCacheView(image,exception);
2437 motion_view=AcquireVirtualCacheView(image,exception);
2438 blur_view=AcquireAuthenticCacheView(blur_image,exception);
2439#if defined(MAGICKCORE_OPENMP_SUPPORT)
2440 #pragma omp parallel for schedule(static) shared(progress,status) \
2441 magick_number_threads(image,blur_image,image->rows,1)
2443 for (y=0; y < (ssize_t) image->rows; y++)
2454 if (status == MagickFalse)
2456 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2457 q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
2459 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
2464 for (x=0; x < (ssize_t) image->columns; x++)
2469 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2492 channel=GetPixelChannelChannel(image,i);
2493 traits=GetPixelChannelTraits(image,channel);
2494 blur_traits=GetPixelChannelTraits(blur_image,channel);
2495 if ((traits == UndefinedPixelTrait) ||
2496 (blur_traits == UndefinedPixelTrait))
2498 if ((blur_traits & CopyPixelTrait) != 0)
2500 SetPixelChannel(blur_image,channel,p[i],q);
2505 if ((blur_traits & BlendPixelTrait) == 0)
2507 for (j=0; j < (ssize_t) width; j++)
2509 r=GetCacheViewVirtualPixels(motion_view,x+offset[j].x,y+
2510 offset[j].y,1,1,exception);
2511 if (r == (
const Quantum *) NULL)
2516 pixel+=(*k)*(double) r[i];
2519 SetPixelChannel(blur_image,channel,ClampToQuantum(pixel),q);
2522 for (j=0; j < (ssize_t) width; j++)
2524 r=GetCacheViewVirtualPixels(motion_view,x+offset[j].x,y+offset[j].y,1,
2526 if (r == (
const Quantum *) NULL)
2531 alpha=QuantumScale*(double) GetPixelAlpha(image,r);
2532 pixel+=(*k)*alpha*(double) r[i];
2536 gamma=PerceptibleReciprocal(gamma);
2537 SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
2539 p+=GetPixelChannels(image);
2540 q+=GetPixelChannels(blur_image);
2542 if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
2544 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2549#if defined(MAGICKCORE_OPENMP_SUPPORT)
2553 proceed=SetImageProgress(image,BlurImageTag,progress,image->rows);
2554 if (proceed == MagickFalse)
2558 blur_view=DestroyCacheView(blur_view);
2559 motion_view=DestroyCacheView(motion_view);
2560 image_view=DestroyCacheView(image_view);
2561 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2562 offset=(
OffsetInfo *) RelinquishMagickMemory(offset);
2563 if (status == MagickFalse)
2564 blur_image=DestroyImage(blur_image);
2598MagickExport
Image *PreviewImage(
const Image *image,
const PreviewType preview,
2601#define NumberTiles 9
2602#define PreviewImageTag "Preview/Image"
2603#define DefaultPreviewGeometry "204x204+10+10"
2606 factor[MagickPathExtent],
2607 label[MagickPathExtent];
2649 assert(image != (
Image *) NULL);
2650 assert(image->signature == MagickCoreSignature);
2651 if (IsEventLogging() != MagickFalse)
2652 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2656 preview_info=AcquireImageInfo();
2657 SetGeometry(image,&geometry);
2658 (void) ParseMetaGeometry(DefaultPreviewGeometry,&geometry.x,&geometry.y,
2659 &geometry.width,&geometry.height);
2660 images=NewImageList();
2662 GetQuantizeInfo(&quantize_info);
2666 for (i=0; i < NumberTiles; i++)
2668 thumbnail=ThumbnailImage(image,geometry.width,geometry.height,exception);
2669 if (thumbnail == (
Image *) NULL)
2671 (void) SetImageProgressMonitor(thumbnail,(MagickProgressMonitor) NULL,
2673 (void) SetImageProperty(thumbnail,
"label",DefaultTileLabel,exception);
2674 if (i == (NumberTiles/2))
2676 (void) QueryColorCompliance(
"#dfdfdf",AllCompliance,
2677 &thumbnail->matte_color,exception);
2678 AppendImageToList(&images,thumbnail);
2686 preview_image=RotateImage(thumbnail,degrees,exception);
2687 (void) FormatLocaleString(label,MagickPathExtent,
"rotate %g",degrees);
2693 preview_image=ShearImage(thumbnail,degrees,degrees,exception);
2694 (void) FormatLocaleString(label,MagickPathExtent,
"shear %gx%g",degrees,
2700 x=((i+1)*(ssize_t) thumbnail->columns)/NumberTiles;
2701 y=((i+1)*(ssize_t) thumbnail->rows)/NumberTiles;
2702 preview_image=RollImage(thumbnail,x,y,exception);
2703 (void) FormatLocaleString(label,MagickPathExtent,
"roll %+.20gx%+.20g",
2704 (
double) x,(double) y);
2709 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2710 if (preview_image == (
Image *) NULL)
2712 (void) FormatLocaleString(factor,MagickPathExtent,
"100,100,%g",2.0*
2714 (void) ModulateImage(preview_image,factor,exception);
2715 (void) FormatLocaleString(label,MagickPathExtent,
"modulate %s",factor);
2718 case SaturationPreview:
2720 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2721 if (preview_image == (
Image *) NULL)
2723 (void) FormatLocaleString(factor,MagickPathExtent,
"100,%g",2.0*
2725 (void) ModulateImage(preview_image,factor,exception);
2726 (void) FormatLocaleString(label,MagickPathExtent,
"modulate %s",factor);
2729 case BrightnessPreview:
2731 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2732 if (preview_image == (
Image *) NULL)
2734 (void) FormatLocaleString(factor,MagickPathExtent,
"%g",2.0*percentage);
2735 (void) ModulateImage(preview_image,factor,exception);
2736 (void) FormatLocaleString(label,MagickPathExtent,
"modulate %s",factor);
2742 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2743 if (preview_image == (
Image *) NULL)
2746 (void) GammaImage(preview_image,gamma,exception);
2747 (void) FormatLocaleString(label,MagickPathExtent,
"gamma %g",gamma);
2752 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2753 if (preview_image != (
Image *) NULL)
2754 for (x=0; x < i; x++)
2755 (
void) ContrastImage(preview_image,MagickTrue,exception);
2756 (void) FormatLocaleString(label,MagickPathExtent,
"contrast (%.20g)",
2762 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2763 if (preview_image == (
Image *) NULL)
2765 for (x=0; x < i; x++)
2766 (
void) ContrastImage(preview_image,MagickFalse,exception);
2767 (void) FormatLocaleString(label,MagickPathExtent,
"+contrast (%.20g)",
2771 case GrayscalePreview:
2773 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2774 if (preview_image == (
Image *) NULL)
2777 quantize_info.number_colors=colors;
2778 quantize_info.colorspace=GRAYColorspace;
2779 (void) QuantizeImage(&quantize_info,preview_image,exception);
2780 (void) FormatLocaleString(label,MagickPathExtent,
2781 "-colorspace gray -colors %.20g",(
double) colors);
2784 case QuantizePreview:
2786 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2787 if (preview_image == (
Image *) NULL)
2790 quantize_info.number_colors=colors;
2791 (void) QuantizeImage(&quantize_info,preview_image,exception);
2792 (void) FormatLocaleString(label,MagickPathExtent,
"colors %.20g",
2796 case DespecklePreview:
2798 for (x=0; x < (i-1); x++)
2800 preview_image=DespeckleImage(thumbnail,exception);
2801 if (preview_image == (
Image *) NULL)
2803 thumbnail=DestroyImage(thumbnail);
2804 thumbnail=preview_image;
2806 preview_image=DespeckleImage(thumbnail,exception);
2807 if (preview_image == (
Image *) NULL)
2809 (void) FormatLocaleString(label,MagickPathExtent,
"despeckle (%.20g)",
2813 case ReduceNoisePreview:
2815 preview_image=StatisticImage(thumbnail,NonpeakStatistic,(
size_t)
2816 radius,(
size_t) radius,exception);
2817 (void) FormatLocaleString(label,MagickPathExtent,
"noise %g",radius);
2820 case AddNoisePreview:
2826 (void) CopyMagickString(factor,
"uniform",MagickPathExtent);
2831 (void) CopyMagickString(factor,
"gaussian",MagickPathExtent);
2836 (void) CopyMagickString(factor,
"multiplicative",MagickPathExtent);
2841 (void) CopyMagickString(factor,
"impulse",MagickPathExtent);
2846 (void) CopyMagickString(factor,
"laplacian",MagickPathExtent);
2851 (void) CopyMagickString(factor,
"Poisson",MagickPathExtent);
2856 (void) CopyMagickString(thumbnail->magick,
"NULL",MagickPathExtent);
2860 preview_image=StatisticImage(thumbnail,NonpeakStatistic,(
size_t) i,
2861 (
size_t) i,exception);
2862 (void) FormatLocaleString(label,MagickPathExtent,
"+noise %s",factor);
2865 case SharpenPreview:
2867 preview_image=SharpenImage(thumbnail,radius,sigma,exception);
2868 (void) FormatLocaleString(label,MagickPathExtent,
"sharpen %gx%g",
2874 preview_image=BlurImage(thumbnail,radius,sigma,exception);
2875 (void) FormatLocaleString(label,MagickPathExtent,
"blur %gx%g",radius,
2879 case ThresholdPreview:
2881 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2882 if (preview_image == (
Image *) NULL)
2884 (void) BilevelImage(thumbnail,(
double) (percentage*((double)
2885 QuantumRange+1.0))/100.0,exception);
2886 (void) FormatLocaleString(label,MagickPathExtent,
"threshold %g",
2887 (
double) (percentage*((double) QuantumRange+1.0))/100.0);
2890 case EdgeDetectPreview:
2892 preview_image=EdgeImage(thumbnail,radius,exception);
2893 (void) FormatLocaleString(label,MagickPathExtent,
"edge %g",radius);
2898 preview_image=SpreadImage(thumbnail,image->interpolate,radius,
2900 (void) FormatLocaleString(label,MagickPathExtent,
"spread %g",
2904 case SolarizePreview:
2906 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2907 if (preview_image == (
Image *) NULL)
2909 (void) SolarizeImage(preview_image,(
double) QuantumRange*percentage/
2911 (void) FormatLocaleString(label,MagickPathExtent,
"solarize %g",
2912 ((
double) QuantumRange*percentage)/100.0);
2918 preview_image=ShadeImage(thumbnail,MagickTrue,degrees,degrees,
2920 (void) FormatLocaleString(label,MagickPathExtent,
"shade %gx%g",degrees,
2929 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2930 if (preview_image == (
Image *) NULL)
2932 raise.width=(size_t) (2*i+2);
2933 raise.height=(size_t) (2*i+2);
2936 (void) RaiseImage(preview_image,&raise,MagickTrue,exception);
2937 (void) FormatLocaleString(label,MagickPathExtent,
2938 "raise %.20gx%.20g%+.20g%+.20g",(
double) raise.width,(double)
2939 raise.height,(
double) raise.x,(double) raise.y);
2942 case SegmentPreview:
2944 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2945 if (preview_image == (
Image *) NULL)
2948 (void) SegmentImage(preview_image,sRGBColorspace,MagickFalse,threshold,
2949 threshold,exception);
2950 (void) FormatLocaleString(label,MagickPathExtent,
"segment %gx%g",
2951 threshold,threshold);
2956 preview_image=SwirlImage(thumbnail,degrees,image->interpolate,
2958 (void) FormatLocaleString(label,MagickPathExtent,
"swirl %g",degrees);
2962 case ImplodePreview:
2965 preview_image=ImplodeImage(thumbnail,degrees,image->interpolate,
2967 (void) FormatLocaleString(label,MagickPathExtent,
"implode %g",degrees);
2973 preview_image=WaveImage(thumbnail,0.5*degrees,2.0*degrees,
2974 image->interpolate,exception);
2975 (void) FormatLocaleString(label,MagickPathExtent,
"wave %gx%g",0.5*
2976 degrees,2.0*degrees);
2979 case OilPaintPreview:
2981 preview_image=OilPaintImage(thumbnail,(
double) radius,(
double) sigma,
2983 (void) FormatLocaleString(label,MagickPathExtent,
"charcoal %gx%g",
2987 case CharcoalDrawingPreview:
2989 preview_image=CharcoalImage(thumbnail,(
double) radius,(
double) sigma,
2991 (void) FormatLocaleString(label,MagickPathExtent,
"charcoal %gx%g",
2998 filename[MagickPathExtent];
3006 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
3007 if (preview_image == (
Image *) NULL)
3009 preview_info->quality=(size_t) percentage;
3010 (void) FormatLocaleString(factor,MagickPathExtent,
"%.20g",(
double)
3011 preview_info->quality);
3012 file=AcquireUniqueFileResource(filename);
3015 (void) FormatLocaleString(preview_image->filename,MagickPathExtent,
3016 "jpeg:%s",filename);
3017 status=WriteImage(preview_info,preview_image,exception);
3018 if (status != MagickFalse)
3023 (void) CopyMagickString(preview_info->filename,
3024 preview_image->filename,MagickPathExtent);
3025 quality_image=ReadImage(preview_info,exception);
3026 if (quality_image != (
Image *) NULL)
3028 preview_image=DestroyImage(preview_image);
3029 preview_image=quality_image;
3032 (void) RelinquishUniqueFileResource(preview_image->filename);
3033 if ((GetBlobSize(preview_image)/1024) >= 1024)
3034 (
void) FormatLocaleString(label,MagickPathExtent,
"quality %s\n%gmb ",
3035 factor,(
double) ((MagickOffsetType) GetBlobSize(preview_image))/
3038 if (GetBlobSize(preview_image) >= 1024)
3039 (void) FormatLocaleString(label,MagickPathExtent,
3040 "quality %s\n%gkb ",factor,(
double) ((MagickOffsetType)
3041 GetBlobSize(preview_image))/1024.0);
3043 (
void) FormatLocaleString(label,MagickPathExtent,
3044 "quality %s\n%.20gb ",factor,(
double) ((MagickOffsetType)
3045 GetBlobSize(thumbnail)));
3049 thumbnail=DestroyImage(thumbnail);
3053 if (preview_image == (
Image *) NULL)
3055 preview_image->alpha_trait=UndefinedPixelTrait;
3056 (void) DeleteImageProperty(preview_image,
"label");
3057 (void) SetImageProperty(preview_image,
"label",label,exception);
3058 AppendImageToList(&images,preview_image);
3059 proceed=SetImageProgress(image,PreviewImageTag,(MagickOffsetType) i,
3061 if (proceed == MagickFalse)
3064 if (images == (
Image *) NULL)
3066 preview_info=DestroyImageInfo(preview_info);
3067 return((
Image *) NULL);
3072 montage_info=CloneMontageInfo(preview_info,(
MontageInfo *) NULL);
3073 (void) CopyMagickString(montage_info->filename,image->filename,
3075 montage_info->shadow=MagickTrue;
3076 (void) CloneString(&montage_info->tile,
"3x3");
3077 (void) CloneString(&montage_info->geometry,DefaultPreviewGeometry);
3078 (void) CloneString(&montage_info->frame,DefaultTileFrame);
3079 montage_image=MontageImages(images,montage_info,exception);
3080 montage_info=DestroyMontageInfo(montage_info);
3081 images=DestroyImageList(images);
3082 if (montage_image == (
Image *) NULL)
3083 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3084 if (montage_image->montage != (
char *) NULL)
3089 montage_image->montage=(
char *) RelinquishMagickMemory(
3090 montage_image->montage);
3091 if (image->directory != (
char *) NULL)
3092 montage_image->directory=(
char *) RelinquishMagickMemory(
3093 montage_image->directory);
3095 preview_info=DestroyImageInfo(preview_info);
3096 return(montage_image);
3130MagickExport
Image *RotationalBlurImage(
const Image *image,
const double angle,
3167 assert(image != (
Image *) NULL);
3168 assert(image->signature == MagickCoreSignature);
3170 assert(exception->signature == MagickCoreSignature);
3171 if (IsEventLogging() != MagickFalse)
3172 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3173#if defined(MAGICKCORE_OPENCL_SUPPORT)
3174 blur_image=AccelerateRotationalBlurImage(image,angle,exception);
3175 if (blur_image != (
Image *) NULL)
3178 blur_image=CloneImage(image,0,0,MagickTrue,exception);
3179 if (blur_image == (
Image *) NULL)
3180 return((
Image *) NULL);
3181 if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
3183 blur_image=DestroyImage(blur_image);
3184 return((
Image *) NULL);
3186 blur_center.x=(double) (image->columns-1)/2.0;
3187 blur_center.y=(double) (image->rows-1)/2.0;
3188 blur_radius=hypot(blur_center.x,blur_center.y);
3189 n=(size_t) fabs(4.0*DegreesToRadians(angle)*sqrt((
double) blur_radius)+2UL);
3190 theta=DegreesToRadians(angle)/(double) (n-1);
3191 cos_theta=(
double *) AcquireQuantumMemory((
size_t) n,
sizeof(*cos_theta));
3192 sin_theta=(
double *) AcquireQuantumMemory((
size_t) n,
sizeof(*sin_theta));
3193 if ((cos_theta == (
double *) NULL) || (sin_theta == (
double *) NULL))
3195 if (cos_theta != (
double *) NULL)
3196 cos_theta=(
double *) RelinquishMagickMemory(cos_theta);
3197 if (sin_theta != (
double *) NULL)
3198 sin_theta=(
double *) RelinquishMagickMemory(sin_theta);
3199 blur_image=DestroyImage(blur_image);
3200 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3202 offset=theta*(double) (n-1)/2.0;
3203 for (w=0; w < (ssize_t) n; w++)
3205 cos_theta[w]=cos((
double) (theta*w-offset));
3206 sin_theta[w]=sin((
double) (theta*w-offset));
3213 image_view=AcquireVirtualCacheView(image,exception);
3214 radial_view=AcquireVirtualCacheView(image,exception);
3215 blur_view=AcquireAuthenticCacheView(blur_image,exception);
3216#if defined(MAGICKCORE_OPENMP_SUPPORT)
3217 #pragma omp parallel for schedule(static) shared(progress,status) \
3218 magick_number_threads(image,blur_image,image->rows,1)
3220 for (y=0; y < (ssize_t) image->rows; y++)
3231 if (status == MagickFalse)
3233 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
3234 q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
3236 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3241 for (x=0; x < (ssize_t) image->columns; x++)
3255 center.x=(double) x-blur_center.x;
3256 center.y=(double) y-blur_center.y;
3257 radius=hypot((
double) center.x,center.y);
3262 step=(size_t) (blur_radius/radius);
3269 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3288 channel=GetPixelChannelChannel(image,i);
3289 traits=GetPixelChannelTraits(image,channel);
3290 blur_traits=GetPixelChannelTraits(blur_image,channel);
3291 if ((traits == UndefinedPixelTrait) ||
3292 (blur_traits == UndefinedPixelTrait))
3294 if ((blur_traits & CopyPixelTrait) != 0)
3296 SetPixelChannel(blur_image,channel,p[i],q);
3301 if ((GetPixelChannelTraits(image,AlphaPixelChannel) == UndefinedPixelTrait) ||
3302 (channel == AlphaPixelChannel))
3304 for (j=0; j < (ssize_t) n; j+=(ssize_t) step)
3306 r=GetCacheViewVirtualPixels(radial_view, (ssize_t) (blur_center.x+
3307 center.x*cos_theta[j]-center.y*sin_theta[j]+0.5),(ssize_t)
3308 (blur_center.y+center.x*sin_theta[j]+center.y*cos_theta[j]+0.5),
3310 if (r == (
const Quantum *) NULL)
3315 pixel+=(double) r[i];
3318 gamma=PerceptibleReciprocal(gamma);
3319 SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
3322 for (j=0; j < (ssize_t) n; j+=(ssize_t) step)
3327 r=GetCacheViewVirtualPixels(radial_view, (ssize_t) (blur_center.x+
3328 center.x*cos_theta[j]-center.y*sin_theta[j]+0.5),(ssize_t)
3329 (blur_center.y+center.x*sin_theta[j]+center.y*cos_theta[j]+0.5),
3331 if (r == (
const Quantum *) NULL)
3336 alpha=QuantumScale*(double) GetPixelAlpha(image,r);
3337 pixel+=alpha*(double) r[i];
3340 gamma=PerceptibleReciprocal(gamma);
3341 SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
3343 p+=GetPixelChannels(image);
3344 q+=GetPixelChannels(blur_image);
3346 if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
3348 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3353#if defined(MAGICKCORE_OPENMP_SUPPORT)
3357 proceed=SetImageProgress(image,BlurImageTag,progress,image->rows);
3358 if (proceed == MagickFalse)
3362 blur_view=DestroyCacheView(blur_view);
3363 radial_view=DestroyCacheView(radial_view);
3364 image_view=DestroyCacheView(image_view);
3365 cos_theta=(
double *) RelinquishMagickMemory(cos_theta);
3366 sin_theta=(
double *) RelinquishMagickMemory(sin_theta);
3367 if (status == MagickFalse)
3368 blur_image=DestroyImage(blur_image);
3407MagickExport
Image *SelectiveBlurImage(
const Image *image,
const double radius,
3408 const double sigma,
const double threshold,
ExceptionInfo *exception)
3410#define SelectiveBlurImageTag "SelectiveBlur/Image"
3440 assert(image != (
Image *) NULL);
3441 assert(image->signature == MagickCoreSignature);
3443 assert(exception->signature == MagickCoreSignature);
3444 if (IsEventLogging() != MagickFalse)
3445 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3446 width=GetOptimalKernelWidth1D(radius,sigma);
3447 kernel=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory((
size_t)
3448 width,width*
sizeof(*kernel)));
3449 if (kernel == (MagickRealType *) NULL)
3450 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3457 j=(ssize_t) (width-1)/2;
3459 for (v=(-j); v <= j; v++)
3464 for (u=(-j); u <= j; u++)
3465 kernel[i++]=(MagickRealType) (exp(-((
double) u*u+v*v)/(2.0*MagickSigma*
3466 MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
3469 if (image->debug != MagickFalse)
3472 format[MagickPathExtent],
3475 const MagickRealType
3482 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
3483 " SelectiveBlurImage with %.20gx%.20g kernel:",(double) width,(
double)
3485 message=AcquireString(
"");
3487 for (v=0; v < (ssize_t) width; v++)
3490 (void) FormatLocaleString(format,MagickPathExtent,
"%.20g: ",(
double) v);
3491 (void) ConcatenateString(&message,format);
3492 for (u=0; u < (ssize_t) width; u++)
3494 (void) FormatLocaleString(format,MagickPathExtent,
"%+f ",(
double)
3496 (void) ConcatenateString(&message,format);
3498 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
"%s",message);
3500 message=DestroyString(message);
3502 blur_image=CloneImage(image,0,0,MagickTrue,exception);
3503 if (blur_image == (
Image *) NULL)
3504 return((
Image *) NULL);
3505 if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
3507 blur_image=DestroyImage(blur_image);
3508 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
3509 return((
Image *) NULL);
3511 luminance_image=CloneImage(image,0,0,MagickTrue,exception);
3512 if (luminance_image == (
Image *) NULL)
3514 blur_image=DestroyImage(blur_image);
3515 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
3516 return((
Image *) NULL);
3518 status=TransformImageColorspace(luminance_image,GRAYColorspace,exception);
3519 if (status == MagickFalse)
3521 luminance_image=DestroyImage(luminance_image);
3522 blur_image=DestroyImage(blur_image);
3523 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
3524 return((
Image *) NULL);
3531 center=(ssize_t) (GetPixelChannels(image)*(image->columns+width)*
3532 ((width-1)/2L)+GetPixelChannels(image)*((width-1)/2L));
3533 image_view=AcquireVirtualCacheView(image,exception);
3534 luminance_view=AcquireVirtualCacheView(luminance_image,exception);
3535 blur_view=AcquireAuthenticCacheView(blur_image,exception);
3536#if defined(MAGICKCORE_OPENMP_SUPPORT)
3537 #pragma omp parallel for schedule(static) shared(progress,status) \
3538 magick_number_threads(image,blur_image,image->rows,1)
3540 for (y=0; y < (ssize_t) image->rows; y++)
3558 if (status == MagickFalse)
3560 p=GetCacheViewVirtualPixels(image_view,-((ssize_t) (width-1)/2L),y-(ssize_t)
3561 ((width-1)/2L),image->columns+width,width,exception);
3562 l=GetCacheViewVirtualPixels(luminance_view,-((ssize_t) (width-1)/2L),y-
3563 (ssize_t) ((width-1)/2L),luminance_image->columns+width,width,exception);
3564 q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
3566 if ((p == (
const Quantum *) NULL) || (l == (
const Quantum *) NULL) ||
3567 (q == (Quantum *) NULL))
3572 for (x=0; x < (ssize_t) image->columns; x++)
3580 intensity=GetPixelIntensity(image,p+center);
3581 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3595 const MagickRealType
3599 *magick_restrict luminance_pixels,
3600 *magick_restrict pixels;
3608 channel=GetPixelChannelChannel(image,i);
3609 traits=GetPixelChannelTraits(image,channel);
3610 blur_traits=GetPixelChannelTraits(blur_image,channel);
3611 if ((traits == UndefinedPixelTrait) ||
3612 (blur_traits == UndefinedPixelTrait))
3614 if ((blur_traits & CopyPixelTrait) != 0)
3616 SetPixelChannel(blur_image,channel,p[center+i],q);
3624 if ((blur_traits & BlendPixelTrait) == 0)
3626 for (v=0; v < (ssize_t) width; v++)
3628 for (u=0; u < (ssize_t) width; u++)
3630 contrast=GetPixelIntensity(luminance_image,luminance_pixels)-
3632 if (fabs(contrast) < threshold)
3634 pixel+=(*k)*(double) pixels[i];
3638 pixels+=GetPixelChannels(image);
3639 luminance_pixels+=GetPixelChannels(luminance_image);
3641 pixels+=GetPixelChannels(image)*image->columns;
3642 luminance_pixels+=GetPixelChannels(luminance_image)*
3643 luminance_image->columns;
3645 if (fabs((
double) gamma) < MagickEpsilon)
3647 SetPixelChannel(blur_image,channel,p[center+i],q);
3650 gamma=PerceptibleReciprocal(gamma);
3651 SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
3654 for (v=0; v < (ssize_t) width; v++)
3656 for (u=0; u < (ssize_t) width; u++)
3658 contrast=GetPixelIntensity(image,pixels)-intensity;
3659 if (fabs(contrast) < threshold)
3661 alpha=QuantumScale*(double) GetPixelAlpha(image,pixels);
3662 pixel+=(*k)*alpha*(double) pixels[i];
3666 pixels+=GetPixelChannels(image);
3667 luminance_pixels+=GetPixelChannels(luminance_image);
3669 pixels+=GetPixelChannels(image)*image->columns;
3670 luminance_pixels+=GetPixelChannels(luminance_image)*
3671 luminance_image->columns;
3673 if (fabs((
double) gamma) < MagickEpsilon)
3675 SetPixelChannel(blur_image,channel,p[center+i],q);
3678 gamma=PerceptibleReciprocal(gamma);
3679 SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
3681 p+=GetPixelChannels(image);
3682 l+=GetPixelChannels(luminance_image);
3683 q+=GetPixelChannels(blur_image);
3685 sync=SyncCacheViewAuthenticPixels(blur_view,exception);
3686 if (sync == MagickFalse)
3688 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3693#if defined(MAGICKCORE_OPENMP_SUPPORT)
3697 proceed=SetImageProgress(image,SelectiveBlurImageTag,progress,
3699 if (proceed == MagickFalse)
3703 blur_image->type=image->type;
3704 blur_view=DestroyCacheView(blur_view);
3705 luminance_view=DestroyCacheView(luminance_view);
3706 image_view=DestroyCacheView(image_view);
3707 luminance_image=DestroyImage(luminance_image);
3708 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
3709 if (status == MagickFalse)
3710 blur_image=DestroyImage(blur_image);
3746MagickExport
Image *ShadeImage(
const Image *image,
const MagickBooleanType gray,
3747 const double azimuth,
const double elevation,
ExceptionInfo *exception)
3749#define GetShadeIntensity(image,pixel) \
3750 ClampPixel(GetPixelIntensity((image),(pixel)))
3751#define ShadeImageTag "Shade/Image"
3776 assert(image != (
const Image *) NULL);
3777 assert(image->signature == MagickCoreSignature);
3779 assert(exception->signature == MagickCoreSignature);
3780 if (IsEventLogging() != MagickFalse)
3781 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3782 linear_image=CloneImage(image,0,0,MagickTrue,exception);
3783 shade_image=CloneImage(image,0,0,MagickTrue,exception);
3784 if ((linear_image == (
Image *) NULL) || (shade_image == (
Image *) NULL))
3786 if (linear_image != (
Image *) NULL)
3787 linear_image=DestroyImage(linear_image);
3788 if (shade_image != (
Image *) NULL)
3789 shade_image=DestroyImage(shade_image);
3790 return((
Image *) NULL);
3792 if (SetImageStorageClass(shade_image,DirectClass,exception) == MagickFalse)
3794 linear_image=DestroyImage(linear_image);
3795 shade_image=DestroyImage(shade_image);
3796 return((
Image *) NULL);
3801 light.x=(double) QuantumRange*cos(DegreesToRadians(azimuth))*
3802 cos(DegreesToRadians(elevation));
3803 light.y=(double) QuantumRange*sin(DegreesToRadians(azimuth))*
3804 cos(DegreesToRadians(elevation));
3805 light.z=(double) QuantumRange*sin(DegreesToRadians(elevation));
3811 image_view=AcquireVirtualCacheView(linear_image,exception);
3812 shade_view=AcquireAuthenticCacheView(shade_image,exception);
3813#if defined(MAGICKCORE_OPENMP_SUPPORT)
3814 #pragma omp parallel for schedule(static) shared(progress,status) \
3815 magick_number_threads(linear_image,shade_image,linear_image->rows,1)
3817 for (y=0; y < (ssize_t) linear_image->rows; y++)
3828 *magick_restrict center,
3830 *magick_restrict post,
3831 *magick_restrict pre;
3839 if (status == MagickFalse)
3841 p=GetCacheViewVirtualPixels(image_view,-1,y-1,linear_image->columns+2,3,
3843 q=QueueCacheViewAuthenticPixels(shade_view,0,y,shade_image->columns,1,
3845 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3853 normal.z=2.0*(double) QuantumRange;
3854 for (x=0; x < (ssize_t) linear_image->columns; x++)
3862 pre=p+GetPixelChannels(linear_image);
3863 center=pre+(linear_image->columns+2)*GetPixelChannels(linear_image);
3864 post=center+(linear_image->columns+2)*GetPixelChannels(linear_image);
3866 GetShadeIntensity(linear_image,pre-GetPixelChannels(linear_image))+
3867 GetShadeIntensity(linear_image,center-GetPixelChannels(linear_image))+
3868 GetShadeIntensity(linear_image,post-GetPixelChannels(linear_image))-
3869 GetShadeIntensity(linear_image,pre+GetPixelChannels(linear_image))-
3870 GetShadeIntensity(linear_image,center+GetPixelChannels(linear_image))-
3871 GetShadeIntensity(linear_image,post+GetPixelChannels(linear_image)));
3873 GetShadeIntensity(linear_image,post-GetPixelChannels(linear_image))+
3874 GetShadeIntensity(linear_image,post)+
3875 GetShadeIntensity(linear_image,post+GetPixelChannels(linear_image))-
3876 GetShadeIntensity(linear_image,pre-GetPixelChannels(linear_image))-
3877 GetShadeIntensity(linear_image,pre)-
3878 GetShadeIntensity(linear_image,pre+GetPixelChannels(linear_image)));
3879 if ((fabs(normal.x) <= MagickEpsilon) &&
3880 (fabs(normal.y) <= MagickEpsilon))
3885 distance=normal.x*light.x+normal.y*light.y+normal.z*light.z;
3886 if (distance > MagickEpsilon)
3888 normal_distance=normal.x*normal.x+normal.y*normal.y+
3890 if (normal_distance > (MagickEpsilon*MagickEpsilon))
3891 shade=distance/sqrt((
double) normal_distance);
3894 for (i=0; i < (ssize_t) GetPixelChannels(linear_image); i++)
3903 channel=GetPixelChannelChannel(linear_image,i);
3904 traits=GetPixelChannelTraits(linear_image,channel);
3905 shade_traits=GetPixelChannelTraits(shade_image,channel);
3906 if ((traits == UndefinedPixelTrait) ||
3907 (shade_traits == UndefinedPixelTrait))
3909 if ((shade_traits & CopyPixelTrait) != 0)
3911 SetPixelChannel(shade_image,channel,center[i],q);
3914 if ((traits & UpdatePixelTrait) == 0)
3916 SetPixelChannel(shade_image,channel,center[i],q);
3919 if (gray != MagickFalse)
3921 SetPixelChannel(shade_image,channel,ClampToQuantum(shade),q);
3924 SetPixelChannel(shade_image,channel,ClampToQuantum(QuantumScale*
3925 shade*(
double) center[i]),q);
3927 p+=GetPixelChannels(linear_image);
3928 q+=GetPixelChannels(shade_image);
3930 if (SyncCacheViewAuthenticPixels(shade_view,exception) == MagickFalse)
3932 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3937#if defined(MAGICKCORE_OPENMP_SUPPORT)
3941 proceed=SetImageProgress(image,ShadeImageTag,progress,image->rows);
3942 if (proceed == MagickFalse)
3946 shade_view=DestroyCacheView(shade_view);
3947 image_view=DestroyCacheView(image_view);
3948 linear_image=DestroyImage(linear_image);
3949 if (status == MagickFalse)
3950 shade_image=DestroyImage(shade_image);
3951 return(shade_image);
3992MagickExport
Image *SharpenImage(
const Image *image,
const double radius,
4016 assert(image != (
const Image *) NULL);
4017 assert(image->signature == MagickCoreSignature);
4019 assert(exception->signature == MagickCoreSignature);
4020 if (IsEventLogging() != MagickFalse)
4021 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4022 width=GetOptimalKernelWidth2D(radius,sigma);
4023 kernel_info=AcquireKernelInfo((
const char *) NULL,exception);
4025 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
4026 (void) memset(kernel_info,0,
sizeof(*kernel_info));
4027 kernel_info->width=width;
4028 kernel_info->height=width;
4029 kernel_info->x=(ssize_t) (width-1)/2;
4030 kernel_info->y=(ssize_t) (width-1)/2;
4031 kernel_info->signature=MagickCoreSignature;
4032 kernel_info->values=(MagickRealType *) MagickAssumeAligned(
4033 AcquireAlignedMemory(kernel_info->width,kernel_info->height*
4034 sizeof(*kernel_info->values)));
4035 if (kernel_info->values == (MagickRealType *) NULL)
4037 kernel_info=DestroyKernelInfo(kernel_info);
4038 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
4041 j=(ssize_t) (kernel_info->width-1)/2;
4043 for (v=(-j); v <= j; v++)
4045 for (u=(-j); u <= j; u++)
4047 kernel_info->values[i]=(MagickRealType) (-exp(-((
double) u*u+v*v)/(2.0*
4048 MagickSigma*MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
4049 normalize+=kernel_info->values[i];
4053 kernel_info->values[i/2]=(double) ((-2.0)*normalize);
4055 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
4056 normalize+=kernel_info->values[i];
4057 gamma=PerceptibleReciprocal(normalize);
4058 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
4059 kernel_info->values[i]*=gamma;
4060 sharp_image=ConvolveImage(image,kernel_info,exception);
4061 kernel_info=DestroyKernelInfo(kernel_info);
4062 return(sharp_image);
4096MagickExport
Image *SpreadImage(
const Image *image,
4097 const PixelInterpolateMethod method,
const double radius,
4100#define SpreadImageTag "Spread/Image"
4116 **magick_restrict random_info;
4124#if defined(MAGICKCORE_OPENMP_SUPPORT)
4132 assert(image != (
Image *) NULL);
4133 assert(image->signature == MagickCoreSignature);
4135 assert(exception->signature == MagickCoreSignature);
4136 if (IsEventLogging() != MagickFalse)
4137 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4138 spread_image=CloneImage(image,0,0,MagickTrue,exception);
4139 if (spread_image == (
Image *) NULL)
4140 return((
Image *) NULL);
4141 if (SetImageStorageClass(spread_image,DirectClass,exception) == MagickFalse)
4143 spread_image=DestroyImage(spread_image);
4144 return((
Image *) NULL);
4151 width=GetOptimalKernelWidth1D(radius,0.5);
4152 random_info=AcquireRandomInfoTLS();
4153 image_view=AcquireVirtualCacheView(image,exception);
4154 spread_view=AcquireAuthenticCacheView(spread_image,exception);
4155#if defined(MAGICKCORE_OPENMP_SUPPORT)
4156 key=GetRandomSecretKey(random_info[0]);
4157 #pragma omp parallel for schedule(static) shared(progress,status) \
4158 magick_number_threads(image,spread_image,image->rows,key == ~0UL)
4160 for (y=0; y < (ssize_t) image->rows; y++)
4163 id = GetOpenMPThreadId();
4171 if (status == MagickFalse)
4173 q=QueueCacheViewAuthenticPixels(spread_view,0,y,spread_image->columns,1,
4175 if (q == (Quantum *) NULL)
4180 for (x=0; x < (ssize_t) image->columns; x++)
4185 point.x=GetPseudoRandomValue(random_info[
id]);
4186 point.y=GetPseudoRandomValue(random_info[
id]);
4187 status=InterpolatePixelChannels(image,image_view,spread_image,method,
4188 (
double) x+width*(point.x-0.5),(
double) y+width*(point.y-0.5),q,
4190 if (status == MagickFalse)
4192 q+=GetPixelChannels(spread_image);
4194 if (SyncCacheViewAuthenticPixels(spread_view,exception) == MagickFalse)
4196 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4201#if defined(MAGICKCORE_OPENMP_SUPPORT)
4205 proceed=SetImageProgress(image,SpreadImageTag,progress,image->rows);
4206 if (proceed == MagickFalse)
4210 spread_view=DestroyCacheView(spread_view);
4211 image_view=DestroyCacheView(image_view);
4212 random_info=DestroyRandomInfoTLS(random_info);
4213 if (status == MagickFalse)
4214 spread_image=DestroyImage(spread_image);
4215 return(spread_image);
4257MagickExport
Image *UnsharpMaskImage(
const Image *image,
const double radius,
4258 const double sigma,
const double gain,
const double threshold,
4261#define SharpenImageTag "Sharpen/Image"
4282 assert(image != (
const Image *) NULL);
4283 assert(image->signature == MagickCoreSignature);
4285 assert(exception->signature == MagickCoreSignature);
4286 if (IsEventLogging() != MagickFalse)
4287 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4296 unsharp_image=BlurImage(image,radius,sigma,exception);
4297 if (unsharp_image == (
Image *) NULL)
4298 return((
Image *) NULL);
4299 quantum_threshold=(double) QuantumRange*threshold;
4305 image_view=AcquireVirtualCacheView(image,exception);
4306 unsharp_view=AcquireAuthenticCacheView(unsharp_image,exception);
4307#if defined(MAGICKCORE_OPENMP_SUPPORT)
4308 #pragma omp parallel for schedule(static) shared(progress,status) \
4309 magick_number_threads(image,unsharp_image,image->rows,1)
4311 for (y=0; y < (ssize_t) image->rows; y++)
4322 if (status == MagickFalse)
4324 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
4325 q=GetCacheViewAuthenticPixels(unsharp_view,0,y,unsharp_image->columns,1,
4327 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
4332 for (x=0; x < (ssize_t) image->columns; x++)
4337 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4349 channel=GetPixelChannelChannel(image,i);
4350 traits=GetPixelChannelTraits(image,channel);
4351 unsharp_traits=GetPixelChannelTraits(unsharp_image,channel);
4352 if ((traits == UndefinedPixelTrait) ||
4353 (unsharp_traits == UndefinedPixelTrait))
4355 if ((unsharp_traits & CopyPixelTrait) != 0)
4357 SetPixelChannel(unsharp_image,channel,p[i],q);
4360 pixel=(double) p[i]-(
double) GetPixelChannel(unsharp_image,channel,q);
4361 if (fabs(2.0*pixel) < quantum_threshold)
4362 pixel=(double) p[i];
4364 pixel=(double) p[i]+gain*pixel;
4365 SetPixelChannel(unsharp_image,channel,ClampToQuantum(pixel),q);
4367 p+=GetPixelChannels(image);
4368 q+=GetPixelChannels(unsharp_image);
4370 if (SyncCacheViewAuthenticPixels(unsharp_view,exception) == MagickFalse)
4372 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4377#if defined(MAGICKCORE_OPENMP_SUPPORT)
4381 proceed=SetImageProgress(image,SharpenImageTag,progress,image->rows);
4382 if (proceed == MagickFalse)
4386 unsharp_image->type=image->type;
4387 unsharp_view=DestroyCacheView(unsharp_view);
4388 image_view=DestroyCacheView(image_view);
4389 if (status == MagickFalse)
4390 unsharp_image=DestroyImage(unsharp_image);
4391 return(unsharp_image);