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++)
311 *magick_restrict pixels;
329 channel=GetPixelChannelChannel(image,i);
330 traits=GetPixelChannelTraits(image,channel);
331 blur_traits=GetPixelChannelTraits(blur_image,channel);
332 if ((traits == UndefinedPixelTrait) ||
333 (blur_traits == UndefinedPixelTrait))
335 if ((blur_traits & CopyPixelTrait) != 0)
337 SetPixelChannel(blur_image,channel,p[center+i],q);
344 if ((blur_traits & BlendPixelTrait) == 0)
349 for (v=0; v < ((ssize_t) width-j); v++)
351 for (u=0; u < ((ssize_t) width-j); u++)
353 pixel+=(*k)*(double) pixels[i];
356 pixels+=(ptrdiff_t) GetPixelChannels(image);
359 gamma=PerceptibleReciprocal(gamma);
360 SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
366 for (v=0; v < ((ssize_t) width-j); v++)
368 for (u=0; u < ((ssize_t) width-j); u++)
370 alpha=(double) (QuantumScale*(
double) GetPixelAlpha(image,pixels));
371 pixel+=(*k)*alpha*(double) pixels[i];
374 pixels+=(ptrdiff_t) GetPixelChannels(image);
377 gamma=PerceptibleReciprocal(gamma);
378 SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
380 q+=(ptrdiff_t) GetPixelChannels(blur_image);
381 r+=(ptrdiff_t) GetPixelChannels(edge_image);
383 if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
385 if (image->progress_monitor != (MagickProgressMonitor) NULL)
390#if defined(MAGICKCORE_OPENMP_SUPPORT)
394 proceed=SetImageProgress(image,AdaptiveBlurImageTag,progress,
396 if (proceed == MagickFalse)
400 blur_image->type=image->type;
401 blur_view=DestroyCacheView(blur_view);
402 edge_view=DestroyCacheView(edge_view);
403 image_view=DestroyCacheView(image_view);
404 edge_image=DestroyImage(edge_image);
405 for (w=0; w < (ssize_t) width; w+=2)
406 kernel[w]=(
double *) RelinquishAlignedMemory(kernel[w]);
407 kernel=(
double **) RelinquishAlignedMemory(kernel);
408 if (status == MagickFalse)
409 blur_image=DestroyImage(blur_image);
447MagickExport
Image *AdaptiveSharpenImage(
const Image *image,
const double radius,
450#define AdaptiveSharpenImageTag "Convolve/Image"
451#define MagickSigma (fabs(sigma) < MagickEpsilon ? MagickEpsilon : sigma)
480 assert(image != (
const Image *) NULL);
481 assert(image->signature == MagickCoreSignature);
483 assert(exception->signature == MagickCoreSignature);
484 if (IsEventLogging() != MagickFalse)
485 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
486 sharp_image=CloneImage(image,0,0,MagickTrue,exception);
487 if (sharp_image == (
Image *) NULL)
488 return((
Image *) NULL);
489 if (fabs(sigma) < MagickEpsilon)
491 if (SetImageStorageClass(sharp_image,DirectClass,exception) == MagickFalse)
493 sharp_image=DestroyImage(sharp_image);
494 return((
Image *) NULL);
499 edge_image=EdgeImage(image,radius,exception);
500 if (edge_image == (
Image *) NULL)
502 sharp_image=DestroyImage(sharp_image);
503 return((
Image *) NULL);
505 (void) AutoLevelImage(edge_image,exception);
506 gaussian_image=BlurImage(edge_image,radius,sigma,exception);
507 if (gaussian_image != (
Image *) NULL)
509 edge_image=DestroyImage(edge_image);
510 edge_image=gaussian_image;
512 (void) AutoLevelImage(edge_image,exception);
516 width=GetOptimalKernelWidth2D(radius,sigma);
517 kernel=(
double **) MagickAssumeAligned(AcquireAlignedMemory((
size_t)
518 width,
sizeof(*kernel)));
519 if (kernel == (
double **) NULL)
521 edge_image=DestroyImage(edge_image);
522 sharp_image=DestroyImage(sharp_image);
523 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
525 (void) memset(kernel,0,(
size_t) width*
sizeof(*kernel));
526 for (w=0; w < (ssize_t) width; w+=2)
534 kernel[w]=(
double *) MagickAssumeAligned(AcquireAlignedMemory((
size_t)
535 (width-(size_t) w),(width-(size_t) w)*
sizeof(**kernel)));
536 if (kernel[w] == (
double *) NULL)
539 j=((ssize_t) width-w-1)/2;
541 for (v=(-j); v <= j; v++)
543 for (u=(-j); u <= j; u++)
545 kernel[w][k]=(double) (-exp(-((
double) u*u+v*v)/(2.0*MagickSigma*
546 MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
547 normalize+=kernel[w][k];
551 kernel[w][(k-1)/2]=(
double) ((-2.0)*normalize);
552 if (sigma < MagickEpsilon)
553 kernel[w][(k-1)/2]=1.0;
555 if (w < (ssize_t) width)
557 for (w-=2; w >= 0; w-=2)
558 kernel[w]=(
double *) RelinquishAlignedMemory(kernel[w]);
559 kernel=(
double **) RelinquishAlignedMemory(kernel);
560 edge_image=DestroyImage(edge_image);
561 sharp_image=DestroyImage(sharp_image);
562 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
569 image_view=AcquireVirtualCacheView(image,exception);
570 edge_view=AcquireVirtualCacheView(edge_image,exception);
571 sharp_view=AcquireAuthenticCacheView(sharp_image,exception);
572#if defined(MAGICKCORE_OPENMP_SUPPORT)
573 #pragma omp parallel for schedule(static) shared(progress,status) \
574 magick_number_threads(image,sharp_image,sharp_image->rows,1)
576 for (y=0; y < (ssize_t) sharp_image->rows; y++)
587 if (status == MagickFalse)
589 r=GetCacheViewVirtualPixels(edge_view,0,y,edge_image->columns,1,exception);
590 q=QueueCacheViewAuthenticPixels(sharp_view,0,y,sharp_image->columns,1,
592 if ((r == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
597 for (x=0; x < (ssize_t) sharp_image->columns; x++)
609 j=CastDoubleToLong(ceil((
double) width*(1.0-QuantumScale*
610 GetPixelIntensity(edge_image,r))-0.5));
614 if (j > (ssize_t) width)
618 p=GetCacheViewVirtualPixels(image_view,x-(((ssize_t) width-j)/2L),y-
619 (((ssize_t) width-j)/2L),width-(
size_t) j,width-(
size_t) j,exception);
620 if (p == (
const Quantum *) NULL)
622 center=(ssize_t) (GetPixelChannels(image)*(width-(size_t) j)*
623 ((width-(size_t) j)/2L)+GetPixelChannels(image)*((width-(size_t) j)/2));
624 for (i=0; i < (ssize_t) GetPixelChannels(sharp_image); i++)
630 *magick_restrict pixels;
648 channel=GetPixelChannelChannel(image,i);
649 traits=GetPixelChannelTraits(image,channel);
650 sharp_traits=GetPixelChannelTraits(sharp_image,channel);
651 if ((traits == UndefinedPixelTrait) ||
652 (sharp_traits == UndefinedPixelTrait))
654 if ((sharp_traits & CopyPixelTrait) != 0)
656 SetPixelChannel(sharp_image,channel,p[center+i],q);
663 if ((sharp_traits & BlendPixelTrait) == 0)
668 for (v=0; v < ((ssize_t) width-j); v++)
670 for (u=0; u < ((ssize_t) width-j); u++)
672 pixel+=(*k)*(double) pixels[i];
675 pixels+=(ptrdiff_t) GetPixelChannels(image);
678 gamma=PerceptibleReciprocal(gamma);
679 SetPixelChannel(sharp_image,channel,ClampToQuantum(gamma*pixel),q);
685 for (v=0; v < ((ssize_t) width-j); v++)
687 for (u=0; u < ((ssize_t) width-j); u++)
689 alpha=(double) (QuantumScale*(
double) GetPixelAlpha(image,pixels));
690 pixel+=(*k)*alpha*(double) pixels[i];
693 pixels+=(ptrdiff_t) GetPixelChannels(image);
696 gamma=PerceptibleReciprocal(gamma);
697 SetPixelChannel(sharp_image,channel,ClampToQuantum(gamma*pixel),q);
699 q+=(ptrdiff_t) GetPixelChannels(sharp_image);
700 r+=(ptrdiff_t) GetPixelChannels(edge_image);
702 if (SyncCacheViewAuthenticPixels(sharp_view,exception) == MagickFalse)
704 if (image->progress_monitor != (MagickProgressMonitor) NULL)
709#if defined(MAGICKCORE_OPENMP_SUPPORT)
713 proceed=SetImageProgress(image,AdaptiveSharpenImageTag,progress,
715 if (proceed == MagickFalse)
719 sharp_image->type=image->type;
720 sharp_view=DestroyCacheView(sharp_view);
721 edge_view=DestroyCacheView(edge_view);
722 image_view=DestroyCacheView(image_view);
723 edge_image=DestroyImage(edge_image);
724 for (w=0; w < (ssize_t) width; w+=2)
725 kernel[w]=(
double *) RelinquishAlignedMemory(kernel[w]);
726 kernel=(
double **) RelinquishAlignedMemory(kernel);
727 if (status == MagickFalse)
728 sharp_image=DestroyImage(sharp_image);
765MagickExport
Image *BlurImage(
const Image *image,
const double radius,
769 geometry[MagickPathExtent];
777 assert(image != (
const Image *) NULL);
778 assert(image->signature == MagickCoreSignature);
780 assert(exception->signature == MagickCoreSignature);
781 if (IsEventLogging() != MagickFalse)
782 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
783#if defined(MAGICKCORE_OPENCL_SUPPORT)
784 blur_image=AccelerateBlurImage(image,radius,sigma,exception);
785 if (blur_image != (
Image *) NULL)
788 (void) FormatLocaleString(geometry,MagickPathExtent,
789 "blur:%.20gx%.20g;blur:%.20gx%.20g+90",radius,sigma,radius,sigma);
790 kernel_info=AcquireKernelInfo(geometry,exception);
792 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
793 blur_image=ConvolveImage(image,kernel_info,exception);
794 kernel_info=DestroyKernelInfo(kernel_info);
846static inline double BlurDistance(
const ssize_t x,
const ssize_t y,
847 const ssize_t u,
const ssize_t v)
849 return(sqrt(((
double) x-u)*((
double) x-u)+((
double) y-v)*((
double) y-v)));
852static inline double BlurGaussian(
const double x,
const double sigma)
854 return(exp(-((
double) x*x)*PerceptibleReciprocal(2.0*sigma*sigma))*
855 PerceptibleReciprocal(Magick2PI*sigma*sigma));
858static double **DestroyBilateralTLS(
const size_t number_threads,
864 assert(weights != (
double **) NULL);
865 for (i=0; i <= (ssize_t) number_threads; i++)
866 if (weights[i] != (
double *) NULL)
867 weights[i]=(
double *) RelinquishMagickMemory(weights[i]);
868 weights=(
double **) RelinquishMagickMemory(weights);
872static double **AcquireBilateralTLS(
const size_t number_threads,
873 const size_t width,
const size_t height)
884 if (HeapOverflowSanityCheckGetSize(height,
sizeof(**weights),&count) != MagickFalse)
885 return((
double **) NULL);
886 weights=(
double **) AcquireQuantumMemory(number_threads+1,
sizeof(*weights));
887 if (weights == (
double **) NULL)
888 return((
double **) NULL);
889 (void) memset(weights,0,(number_threads+1)*
sizeof(*weights));
890 for (i=0; i <= (ssize_t) number_threads; i++)
892 weights[i]=(
double *) AcquireQuantumMemory(width,count);
893 if (weights[i] == (
double *) NULL)
894 return(DestroyBilateralTLS(number_threads,weights));
899MagickExport
Image *BilateralBlurImage(
const Image *image,
const size_t width,
900 const size_t height,
const double intensity_sigma,
const double spatial_sigma,
903#define MaxIntensity (255)
904#define BilateralBlurImageTag "Blur/Image"
911 intensity_gaussian[2*(MaxIntensity+1)],
934 assert(image != (
const Image *) NULL);
935 assert(image->signature == MagickCoreSignature);
937 assert(exception->signature == MagickCoreSignature);
938 if (IsEventLogging() != MagickFalse)
939 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
940 blur_image=CloneImage(image,0,0,MagickTrue,exception);
941 if (blur_image == (
Image *) NULL)
942 return((
Image *) NULL);
943 if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
945 blur_image=DestroyImage(blur_image);
946 return((
Image *) NULL);
948 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
949 weights=AcquireBilateralTLS(number_threads,MagickMax(width,1),
950 MagickMax(height,1));
951 if (weights == (
double **) NULL)
953 blur_image=DestroyImage(blur_image);
954 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
956 for (w=(-MaxIntensity); w < MaxIntensity; w++)
957 intensity_gaussian[w+MaxIntensity]=BlurGaussian((
double) w,intensity_sigma);
958 spatial_gaussian=weights[number_threads];
965 mid.x=(ssize_t) (MagickMax(width,1)/2L);
966 mid.y=(ssize_t) (MagickMax(height,1)/2L);
967 for (v=0; v < (ssize_t) MagickMax(height,1); v++)
972 for (u=0; u < (ssize_t) MagickMax(width,1); u++)
973 spatial_gaussian[n++]=BlurGaussian(BlurDistance(0,0,u-mid.x,v-mid.y),
982 image_view=AcquireVirtualCacheView(image,exception);
983 blur_view=AcquireAuthenticCacheView(blur_image,exception);
984#if defined(MAGICKCORE_OPENMP_SUPPORT)
985 #pragma omp parallel for schedule(static) shared(progress,status) \
986 magick_number_threads(image,blur_image,blur_image->rows,1)
988 for (y=0; y < (ssize_t) blur_image->rows; y++)
991 id = GetOpenMPThreadId();
999 if (status == MagickFalse)
1001 q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
1003 if (q == (Quantum *) NULL)
1008 for (x=0; x < (ssize_t) blur_image->columns; x++)
1027 p=GetCacheViewVirtualPixels(image_view,x-mid.x,y-mid.y,MagickMax(width,1),
1028 MagickMax(height,1),exception);
1029 if (p == (
const Quantum *) NULL)
1031 p+=(ptrdiff_t) (GetPixelChannels(image)*MagickMax(width,1)*(size_t) mid.y+
1032 GetPixelChannels(image)*(size_t) mid.x);
1034 for (v=0; v < (ssize_t) MagickMax(height,1); v++)
1036 for (u=0; u < (ssize_t) MagickMax(width,1); u++)
1041 r=p+(ssize_t) (GetPixelChannels(image)*MagickMax(width,1)*
1042 (size_t) (mid.y-v)+GetPixelChannels(image)*(size_t) (mid.x-u));
1043 intensity=ScaleQuantumToChar(GetPixelIntensity(image,r))-
1044 (double) ScaleQuantumToChar(GetPixelIntensity(image,p));
1045 if ((intensity >= -MaxIntensity) && (intensity <= MaxIntensity))
1046 weights[id][n]=intensity_gaussian[(ssize_t) intensity+MaxIntensity]*
1047 spatial_gaussian[n];
1049 weights[id][n]=BlurGaussian(intensity,intensity_sigma)*
1050 BlurGaussian(BlurDistance(x,y,x+u-mid.x,y+v-mid.y),spatial_sigma);
1054 for (i=0; i < (ssize_t) GetPixelChannels(blur_image); i++)
1063 channel=GetPixelChannelChannel(image,i);
1064 traits=GetPixelChannelTraits(image,channel);
1065 blur_traits=GetPixelChannelTraits(blur_image,channel);
1066 if ((traits == UndefinedPixelTrait) ||
1067 (blur_traits == UndefinedPixelTrait))
1069 if ((blur_traits & CopyPixelTrait) != 0)
1071 SetPixelChannel(blur_image,channel,p[i],q);
1077 if ((blur_traits & BlendPixelTrait) == 0)
1082 for (v=0; v < (ssize_t) MagickMax(height,1); v++)
1084 for (u=0; u < (ssize_t) MagickMax(width,1); u++)
1086 r=p+GetPixelChannels(image)*MagickMax(width,1)*(size_t)
1087 (mid.y-v)+GetPixelChannels(image)*(size_t) (mid.x-u);
1088 pixel+=weights[id][n]*(double) r[i];
1089 gamma+=weights[id][n];
1093 SetPixelChannel(blur_image,channel,ClampToQuantum(
1094 PerceptibleReciprocal(gamma)*pixel),q);
1100 for (v=0; v < (ssize_t) MagickMax(height,1); v++)
1102 for (u=0; u < (ssize_t) MagickMax(width,1); u++)
1108 r=p+GetPixelChannels(image)*MagickMax(width,1)*(size_t) (mid.y-v)+
1109 GetPixelChannels(image)*(size_t) (mid.x-u);
1110 alpha=(double) (QuantumScale*(
double) GetPixelAlpha(image,p));
1111 beta=(double) (QuantumScale*(
double) GetPixelAlpha(image,r));
1112 pixel+=weights[id][n]*(double) r[i];
1113 gamma+=weights[id][n]*alpha*beta;
1117 SetPixelChannel(blur_image,channel,ClampToQuantum(
1118 PerceptibleReciprocal(gamma)*pixel),q);
1120 q+=(ptrdiff_t) GetPixelChannels(blur_image);
1122 if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
1124 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1129#if defined(MAGICKCORE_OPENMP_SUPPORT)
1133 proceed=SetImageProgress(image,BilateralBlurImageTag,progress,
1135 if (proceed == MagickFalse)
1139 blur_image->type=image->type;
1140 blur_view=DestroyCacheView(blur_view);
1141 image_view=DestroyCacheView(image_view);
1142 weights=DestroyBilateralTLS(number_threads,weights);
1143 if (status == MagickFalse)
1144 blur_image=DestroyImage(blur_image);
1175MagickExport
Image *ConvolveImage(
const Image *image,
1181 convolve_image=MorphologyImage(image,ConvolveMorphology,1,kernel_info,
1183 return(convolve_image);
1216static void Hull(
const Image *image,
const ssize_t x_offset,
1217 const ssize_t y_offset,
const size_t columns,
const size_t rows,
1218 const int polarity,Quantum *magick_restrict f,Quantum *magick_restrict g)
1229 assert(image != (
const Image *) NULL);
1230 assert(image->signature == MagickCoreSignature);
1231 assert(f != (Quantum *) NULL);
1232 assert(g != (Quantum *) NULL);
1233 assert(columns <= (MAGICK_SSIZE_MAX-2));
1234 if (IsEventLogging() != MagickFalse)
1235 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1236 p=f+(ptrdiff_t) (columns+2);
1237 q=g+(ptrdiff_t) (columns+2);
1238 r=p+(ptrdiff_t) (y_offset*((ssize_t) columns+2)+x_offset);
1239#if defined(MAGICKCORE_OPENMP_SUPPORT)
1240 #pragma omp parallel for schedule(static) \
1241 magick_number_threads(image,image,rows,2)
1243 for (y=0; y < (ssize_t) rows; y++)
1252 i=(2*y+1)+y*(ssize_t) columns;
1254 for (x=0; x < (ssize_t) columns; x++)
1256 v=(MagickRealType) p[i];
1257 if ((MagickRealType) r[i] >= (v+(double) ScaleCharToQuantum(2)))
1258 v+=(double) ScaleCharToQuantum(1);
1263 for (x=0; x < (ssize_t) columns; x++)
1265 v=(MagickRealType) p[i];
1266 if ((MagickRealType) r[i] <= (v-(double) ScaleCharToQuantum(2)))
1267 v-=(double) ScaleCharToQuantum(1);
1272 p=f+(ptrdiff_t) (columns+2);
1273 q=g+(ptrdiff_t) (columns+2);
1274 r=q+(ptrdiff_t) (y_offset*((ssize_t) columns+2)+x_offset);
1275 s=q-(ptrdiff_t) (y_offset*((ssize_t) columns+2)+x_offset);
1276#if defined(MAGICKCORE_OPENMP_SUPPORT)
1277 #pragma omp parallel for schedule(static) \
1278 magick_number_threads(image,image,rows,2)
1280 for (y=0; y < (ssize_t) rows; y++)
1289 i=(2*y+1)+y*(ssize_t) columns;
1291 for (x=0; x < (ssize_t) columns; x++)
1293 v=(MagickRealType) q[i];
1294 if (((MagickRealType) s[i] >= (v+(double) ScaleCharToQuantum(2))) &&
1295 ((MagickRealType) r[i] > v))
1296 v+=(
double) ScaleCharToQuantum(1);
1301 for (x=0; x < (ssize_t) columns; x++)
1303 v=(MagickRealType) q[i];
1304 if (((MagickRealType) s[i] <= (v-(double) ScaleCharToQuantum(2))) &&
1305 ((MagickRealType) r[i] < v))
1306 v-=(
double) ScaleCharToQuantum(1);
1315#define DespeckleImageTag "Despeckle/Image"
1332 *magick_restrict buffer,
1333 *magick_restrict pixels;
1341 static const ssize_t
1342 X[4] = {0, 1, 1,-1},
1343 Y[4] = {1, 0, 1, 1};
1348 assert(image != (
const Image *) NULL);
1349 assert(image->signature == MagickCoreSignature);
1351 assert(exception->signature == MagickCoreSignature);
1352 if (IsEventLogging() != MagickFalse)
1353 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1354#if defined(MAGICKCORE_OPENCL_SUPPORT)
1355 despeckle_image=AccelerateDespeckleImage(image,exception);
1356 if (despeckle_image != (
Image *) NULL)
1357 return(despeckle_image);
1359 despeckle_image=CloneImage(image,0,0,MagickTrue,exception);
1360 if (despeckle_image == (
Image *) NULL)
1361 return((
Image *) NULL);
1362 status=SetImageStorageClass(despeckle_image,DirectClass,exception);
1363 if (status == MagickFalse)
1365 despeckle_image=DestroyImage(despeckle_image);
1366 return((
Image *) NULL);
1371 length=(size_t) ((image->columns+2)*(image->rows+2));
1372 pixel_info=AcquireVirtualMemory(length,
sizeof(*pixels));
1373 buffer_info=AcquireVirtualMemory(length,
sizeof(*buffer));
1378 buffer_info=RelinquishVirtualMemory(buffer_info);
1380 pixel_info=RelinquishVirtualMemory(pixel_info);
1381 despeckle_image=DestroyImage(despeckle_image);
1382 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1384 pixels=(Quantum *) GetVirtualMemoryBlob(pixel_info);
1385 buffer=(Quantum *) GetVirtualMemoryBlob(buffer_info);
1390 image_view=AcquireVirtualCacheView(image,exception);
1391 despeckle_view=AcquireAuthenticCacheView(despeckle_image,exception);
1392 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1409 if (status == MagickFalse)
1411 channel=GetPixelChannelChannel(image,i);
1412 traits=GetPixelChannelTraits(image,channel);
1413 despeckle_traits=GetPixelChannelTraits(despeckle_image,channel);
1414 if ((traits == UndefinedPixelTrait) ||
1415 (despeckle_traits == UndefinedPixelTrait))
1417 if ((despeckle_traits & CopyPixelTrait) != 0)
1419 (void) memset(pixels,0,length*
sizeof(*pixels));
1420 j=(ssize_t) image->columns+2;
1421 for (y=0; y < (ssize_t) image->rows; y++)
1426 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1427 if (p == (
const Quantum *) NULL)
1433 for (x=0; x < (ssize_t) image->columns; x++)
1436 p+=(ptrdiff_t) GetPixelChannels(image);
1440 (void) memset(buffer,0,length*
sizeof(*buffer));
1441 for (k=0; k < 4; k++)
1443 Hull(image,X[k],Y[k],image->columns,image->rows,1,pixels,buffer);
1444 Hull(image,-X[k],-Y[k],image->columns,image->rows,1,pixels,buffer);
1445 Hull(image,-X[k],-Y[k],image->columns,image->rows,-1,pixels,buffer);
1446 Hull(image,X[k],Y[k],image->columns,image->rows,-1,pixels,buffer);
1448 j=(ssize_t) image->columns+2;
1449 for (y=0; y < (ssize_t) image->rows; y++)
1457 q=GetCacheViewAuthenticPixels(despeckle_view,0,y,despeckle_image->columns,
1459 if (q == (Quantum *) NULL)
1465 for (x=0; x < (ssize_t) image->columns; x++)
1467 SetPixelChannel(despeckle_image,channel,pixels[j++],q);
1468 q+=(ptrdiff_t) GetPixelChannels(despeckle_image);
1470 sync=SyncCacheViewAuthenticPixels(despeckle_view,exception);
1471 if (sync == MagickFalse)
1475 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1480 proceed=SetImageProgress(image,DespeckleImageTag,(MagickOffsetType) i,
1481 GetPixelChannels(image));
1482 if (proceed == MagickFalse)
1486 despeckle_view=DestroyCacheView(despeckle_view);
1487 image_view=DestroyCacheView(image_view);
1488 buffer_info=RelinquishVirtualMemory(buffer_info);
1489 pixel_info=RelinquishVirtualMemory(pixel_info);
1490 despeckle_image->type=image->type;
1491 if (status == MagickFalse)
1492 despeckle_image=DestroyImage(despeckle_image);
1493 return(despeckle_image);
1525MagickExport
Image *EdgeImage(
const Image *image,
const double radius,
1540 assert(image != (
const Image *) NULL);
1541 assert(image->signature == MagickCoreSignature);
1543 assert(exception->signature == MagickCoreSignature);
1544 if (IsEventLogging() != MagickFalse)
1545 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1546 width=GetOptimalKernelWidth1D(radius,0.5);
1547 kernel_info=AcquireKernelInfo((
const char *) NULL,exception);
1549 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1550 (void) memset(kernel_info,0,
sizeof(*kernel_info));
1551 kernel_info->width=width;
1552 kernel_info->height=width;
1553 kernel_info->x=(ssize_t) (kernel_info->width-1)/2;
1554 kernel_info->y=(ssize_t) (kernel_info->height-1)/2;
1555 kernel_info->signature=MagickCoreSignature;
1556 kernel_info->values=(MagickRealType *) MagickAssumeAligned(
1557 AcquireAlignedMemory(kernel_info->width,kernel_info->height*
1558 sizeof(*kernel_info->values)));
1559 if (kernel_info->values == (MagickRealType *) NULL)
1561 kernel_info=DestroyKernelInfo(kernel_info);
1562 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1564 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
1565 kernel_info->values[i]=(-1.0);
1566 kernel_info->values[i/2]=(double) kernel_info->width*kernel_info->height-1.0;
1567 edge_image=ConvolveImage(image,kernel_info,exception);
1568 kernel_info=DestroyKernelInfo(kernel_info);
1605MagickExport
Image *EmbossImage(
const Image *image,
const double radius,
1630 assert(image != (
const Image *) NULL);
1631 assert(image->signature == MagickCoreSignature);
1633 assert(exception->signature == MagickCoreSignature);
1634 if (IsEventLogging() != MagickFalse)
1635 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1636 width=GetOptimalKernelWidth1D(radius,sigma);
1637 kernel_info=AcquireKernelInfo((
const char *) NULL,exception);
1639 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1640 kernel_info->width=width;
1641 kernel_info->height=width;
1642 kernel_info->x=(ssize_t) (width-1)/2;
1643 kernel_info->y=(ssize_t) (width-1)/2;
1644 kernel_info->values=(MagickRealType *) MagickAssumeAligned(
1645 AcquireAlignedMemory(kernel_info->width,kernel_info->width*
1646 sizeof(*kernel_info->values)));
1647 if (kernel_info->values == (MagickRealType *) NULL)
1649 kernel_info=DestroyKernelInfo(kernel_info);
1650 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1652 j=(ssize_t) (kernel_info->width-1)/2;
1655 for (v=(-j); v <= j; v++)
1657 for (u=(-j); u <= j; u++)
1659 kernel_info->values[i]=(MagickRealType) (((u < 0) || (v < 0) ? -8.0 :
1660 8.0)*exp(-((double) u*u+v*v)/(2.0*MagickSigma*MagickSigma))/
1661 (2.0*MagickPI*MagickSigma*MagickSigma));
1663 kernel_info->values[i]=0.0;
1669 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
1670 normalize+=kernel_info->values[i];
1671 gamma=PerceptibleReciprocal(normalize);
1672 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
1673 kernel_info->values[i]*=gamma;
1674 emboss_image=ConvolveImage(image,kernel_info,exception);
1675 kernel_info=DestroyKernelInfo(kernel_info);
1676 if (emboss_image != (
Image *) NULL)
1677 (void) EqualizeImage(emboss_image,exception);
1678 return(emboss_image);
1714MagickExport
Image *GaussianBlurImage(
const Image *image,
const double radius,
1718 geometry[MagickPathExtent];
1726 assert(image != (
const Image *) NULL);
1727 assert(image->signature == MagickCoreSignature);
1729 assert(exception->signature == MagickCoreSignature);
1730 if (IsEventLogging() != MagickFalse)
1731 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1732 (void) FormatLocaleString(geometry,MagickPathExtent,
"gaussian:%.20gx%.20g",
1734 kernel_info=AcquireKernelInfo(geometry,exception);
1736 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1737 blur_image=ConvolveImage(image,kernel_info,exception);
1738 kernel_info=DestroyKernelInfo(kernel_info);
1772static inline MagickRealType GetMeanLuma(
const Image *magick_restrict image,
1773 const double *magick_restrict pixel)
1775 return(0.212656*pixel[image->channel_map[RedPixelChannel].offset]+
1776 0.715158*pixel[image->channel_map[GreenPixelChannel].offset]+
1777 0.072186*pixel[image->channel_map[BluePixelChannel].offset]);
1780MagickExport
Image *KuwaharaImage(
const Image *image,
const double radius,
1783#define KuwaharaImageTag "Kuwahara/Image"
1808 assert(image != (
Image *) NULL);
1809 assert(image->signature == MagickCoreSignature);
1811 assert(exception->signature == MagickCoreSignature);
1812 if (IsEventLogging() != MagickFalse)
1813 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1814 width=(size_t) radius+1;
1815 gaussian_image=BlurImage(image,radius,sigma,exception);
1816 if (gaussian_image == (
Image *) NULL)
1817 return((
Image *) NULL);
1818 kuwahara_image=CloneImage(image,0,0,MagickTrue,exception);
1819 if (kuwahara_image == (
Image *) NULL)
1821 gaussian_image=DestroyImage(gaussian_image);
1822 return((
Image *) NULL);
1824 if (SetImageStorageClass(kuwahara_image,DirectClass,exception) == MagickFalse)
1826 gaussian_image=DestroyImage(gaussian_image);
1827 kuwahara_image=DestroyImage(kuwahara_image);
1828 return((
Image *) NULL);
1835 image_view=AcquireVirtualCacheView(gaussian_image,exception);
1836 kuwahara_view=AcquireAuthenticCacheView(kuwahara_image,exception);
1837#if defined(MAGICKCORE_OPENMP_SUPPORT)
1838 #pragma omp parallel for schedule(static) shared(progress,status) \
1839 magick_number_threads(image,kuwahara_image,gaussian_image->rows,1)
1841 for (y=0; y < (ssize_t) gaussian_image->rows; y++)
1849 if (status == MagickFalse)
1851 q=QueueCacheViewAuthenticPixels(kuwahara_view,0,y,kuwahara_image->columns,1,
1853 if (q == (Quantum *) NULL)
1858 for (x=0; x < (ssize_t) gaussian_image->columns; x++)
1873 min_variance=MagickMaximumValue;
1874 SetGeometry(gaussian_image,&target);
1875 quadrant.width=width;
1876 quadrant.height=width;
1877 for (i=0; i < 4; i++)
1883 mean[MaxPixelChannels],
1898 quadrant.x=x-(ssize_t) (width-1);
1899 quadrant.y=y-(ssize_t) (width-1);
1904 quadrant.y=y-(ssize_t) (width-1);
1909 quadrant.x=x-(ssize_t) (width-1);
1916 p=GetCacheViewVirtualPixels(image_view,quadrant.x,quadrant.y,
1917 quadrant.width,quadrant.height,exception);
1918 if (p == (
const Quantum *) NULL)
1920 for (j=0; j < (ssize_t) GetPixelChannels(gaussian_image); j++)
1923 for (n=0; n < (ssize_t) (width*width); n++)
1925 for (j=0; j < (ssize_t) GetPixelChannels(gaussian_image); j++)
1926 mean[j]+=(
double) k[j];
1927 k+=(ptrdiff_t) GetPixelChannels(gaussian_image);
1929 for (j=0; j < (ssize_t) GetPixelChannels(gaussian_image); j++)
1930 mean[j]/=(
double) (width*width);
1933 for (n=0; n < (ssize_t) (width*width); n++)
1938 luma=GetPixelLuma(gaussian_image,k);
1939 variance+=(luma-GetMeanLuma(gaussian_image,mean))*
1940 (luma-GetMeanLuma(gaussian_image,mean));
1941 k+=(ptrdiff_t) GetPixelChannels(gaussian_image);
1943 if (variance < min_variance)
1945 min_variance=variance;
1954 status=InterpolatePixelChannels(gaussian_image,image_view,kuwahara_image,
1955 UndefinedInterpolatePixel,(
double) target.x+target.width/2.0,(
double)
1956 target.y+target.height/2.0,q,exception);
1957 if (status == MagickFalse)
1959 q+=(ptrdiff_t) GetPixelChannels(kuwahara_image);
1961 if (SyncCacheViewAuthenticPixels(kuwahara_view,exception) == MagickFalse)
1963 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1968#if defined(MAGICKCORE_OPENMP_SUPPORT)
1972 proceed=SetImageProgress(image,KuwaharaImageTag,progress,image->rows);
1973 if (proceed == MagickFalse)
1977 kuwahara_view=DestroyCacheView(kuwahara_view);
1978 image_view=DestroyCacheView(image_view);
1979 gaussian_image=DestroyImage(gaussian_image);
1980 if (status == MagickFalse)
1981 kuwahara_image=DestroyImage(kuwahara_image);
1982 return(kuwahara_image);
2018MagickExport
Image *LocalContrastImage(
const Image *image,
const double radius,
2021#define LocalContrastImageTag "LocalContrast/Image"
2051 assert(image != (
const Image *) NULL);
2052 assert(image->signature == MagickCoreSignature);
2054 assert(exception->signature == MagickCoreSignature);
2055 if (IsEventLogging() != MagickFalse)
2056 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2057#if defined(MAGICKCORE_OPENCL_SUPPORT)
2058 contrast_image=AccelerateLocalContrastImage(image,radius,strength,exception);
2059 if (contrast_image != (
Image *) NULL)
2060 return(contrast_image);
2062 contrast_image=CloneImage(image,0,0,MagickTrue,exception);
2063 if (contrast_image == (
Image *) NULL)
2064 return((
Image *) NULL);
2065 if (SetImageStorageClass(contrast_image,DirectClass,exception) == MagickFalse)
2067 contrast_image=DestroyImage(contrast_image);
2068 return((
Image *) NULL);
2070 image_view=AcquireVirtualCacheView(image,exception);
2071 contrast_view=AcquireAuthenticCacheView(contrast_image,exception);
2072 scanLineSize=(ssize_t) MagickMax(image->columns,image->rows);
2073 width=(ssize_t) scanLineSize*0.002*fabs(radius);
2074 scanLineSize+=(2*width);
2075 scanline_info=AcquireVirtualMemory(GetOpenMPMaximumThreads()*
2076 (
size_t) scanLineSize,
sizeof(*scanline));
2079 contrast_view=DestroyCacheView(contrast_view);
2080 image_view=DestroyCacheView(image_view);
2081 contrast_image=DestroyImage(contrast_image);
2082 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2084 scanline=(
float *) GetVirtualMemoryBlob(scanline_info);
2088 interImage_info=AcquireVirtualMemory(image->rows*(image->columns+(
size_t)
2089 (2*width)),
sizeof(*interImage));
2092 scanline_info=RelinquishVirtualMemory(scanline_info);
2093 contrast_view=DestroyCacheView(contrast_view);
2094 image_view=DestroyCacheView(image_view);
2095 contrast_image=DestroyImage(contrast_image);
2096 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2098 interImage=(
float *) GetVirtualMemoryBlob(interImage_info);
2099 totalWeight=(float) ((width+1)*(width+1));
2108#if defined(MAGICKCORE_OPENMP_SUPPORT)
2109#pragma omp parallel for schedule(static) \
2110 magick_number_threads(image,image,image->columns,1)
2112 for (x=0; x < (ssize_t) image->columns; x++)
2115 id = GetOpenMPThreadId();
2131 if (status == MagickFalse)
2134 pixels+=
id*scanLineSize;
2136 p=GetCacheViewVirtualPixels(image_view,x,-(ssize_t) width,1,
2137 image->rows+(
size_t) (2*width),exception);
2138 if (p == (
const Quantum *) NULL)
2143 for (y=0; y < (ssize_t) image->rows+(2*width); y++)
2145 *pix++=(float)GetPixelLuma(image,p);
2146 p+=(ptrdiff_t) image->number_channels;
2148 out=interImage+x+width;
2149 for (y=0; y < (ssize_t) image->rows; y++)
2158 for (i=0; i < width; i++)
2160 sum+=weight*((double) *pix++);
2163 for (i=width+1; i < (2*width); i++)
2165 sum+=weight*((double) *pix++);
2169 *out=sum/totalWeight;
2171 if ((x <= width) && (x != 0))
2173 if ((x > (ssize_t) image->columns-width-2) &&
2174 (x != (ssize_t) image->columns-1))
2175 *(out+((image->columns-(size_t) x-1)*2))=*out;
2176 out+=image->columns+(size_t) (width*2);
2187#if defined(MAGICKCORE_OPENMP_SUPPORT)
2188#pragma omp parallel for schedule(static) \
2189 magick_number_threads(image,image,image->rows,1)
2191 for (y=0; y < (ssize_t) image->rows; y++)
2194 id = GetOpenMPThreadId();
2210 if (status == MagickFalse)
2213 pixels+=
id*scanLineSize;
2214 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2215 q=GetCacheViewAuthenticPixels(contrast_view,0,y,image->columns,1,
2217 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
2222 memcpy(pixels,interImage+((
size_t) y*(image->columns+(
size_t) (2*width))),
2223 (image->columns+(
size_t) (2*width))*
sizeof(
float));
2224 for (x=0; x < (ssize_t) image->columns; x++)
2238 for (i=0; i < width; i++)
2240 sum+=weight*((double) *pix++);
2243 for (i=width+1; i < (2*width); i++)
2245 sum+=weight*((double) *pix++);
2251 srcVal=(float) GetPixelLuma(image,p);
2252 mult=(srcVal-(sum/totalWeight))*(strength/100.0);
2253 mult=(srcVal+mult)/srcVal;
2254 traits=GetPixelChannelTraits(image,RedPixelChannel);
2255 if ((traits & UpdatePixelTrait) != 0)
2256 SetPixelRed(contrast_image,ClampToQuantum((MagickRealType)
2257 GetPixelRed(image,p)*mult),q);
2258 traits=GetPixelChannelTraits(image,GreenPixelChannel);
2259 if ((traits & UpdatePixelTrait) != 0)
2260 SetPixelGreen(contrast_image,ClampToQuantum((MagickRealType)
2261 GetPixelGreen(image,p)*mult),q);
2262 traits=GetPixelChannelTraits(image,BluePixelChannel);
2263 if ((traits & UpdatePixelTrait) != 0)
2264 SetPixelBlue(contrast_image,ClampToQuantum((MagickRealType)
2265 GetPixelBlue(image,p)*mult),q);
2266 p+=(ptrdiff_t) image->number_channels;
2267 q+=(ptrdiff_t) contrast_image->number_channels;
2269 if (SyncCacheViewAuthenticPixels(contrast_view,exception) == MagickFalse)
2273 scanline_info=RelinquishVirtualMemory(scanline_info);
2274 interImage_info=RelinquishVirtualMemory(interImage_info);
2275 contrast_view=DestroyCacheView(contrast_view);
2276 image_view=DestroyCacheView(image_view);
2277 if (status == MagickFalse)
2278 contrast_image=DestroyImage(contrast_image);
2279 return(contrast_image);
2321static MagickRealType *GetMotionBlurKernel(
const size_t width,
2334 if (IsEventLogging() != MagickFalse)
2335 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
2336 kernel=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory((
size_t)
2337 width,
sizeof(*kernel)));
2338 if (kernel == (MagickRealType *) NULL)
2341 for (i=0; i < (ssize_t) width; i++)
2343 kernel[i]=(MagickRealType) (exp((-((
double) i*i)/(
double) (2.0*MagickSigma*
2344 MagickSigma)))/(MagickSQ2PI*MagickSigma));
2345 normalize+=kernel[i];
2347 for (i=0; i < (ssize_t) width; i++)
2348 kernel[i]/=normalize;
2352MagickExport
Image *MotionBlurImage(
const Image *image,
const double radius,
2353 const double sigma,
const double angle,
ExceptionInfo *exception)
2355#define BlurImageTag "Blur/Image"
2387 assert(image != (
Image *) NULL);
2388 assert(image->signature == MagickCoreSignature);
2390 assert(exception->signature == MagickCoreSignature);
2391 if (IsEventLogging() != MagickFalse)
2392 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2393 width=GetOptimalKernelWidth1D(radius,sigma);
2394 kernel=GetMotionBlurKernel(width,sigma);
2395 if (kernel == (MagickRealType *) NULL)
2396 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2397 offset=(
OffsetInfo *) AcquireQuantumMemory(width,
sizeof(*offset));
2400 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2401 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2403 point.x=(double) width*sin(DegreesToRadians(angle));
2404 point.y=(double) width*cos(DegreesToRadians(angle));
2405 for (w=0; w < (ssize_t) width; w++)
2407 offset[w].x=CastDoubleToLong(ceil((
double) (w*point.y)/
2408 hypot(point.x,point.y)-0.5));
2409 offset[w].y=CastDoubleToLong(ceil((
double) (w*point.x)/
2410 hypot(point.x,point.y)-0.5));
2415#if defined(MAGICKCORE_OPENCL_SUPPORT)
2416 blur_image=AccelerateMotionBlurImage(image,kernel,width,offset,exception);
2417 if (blur_image != (
Image *) NULL)
2419 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2420 offset=(
OffsetInfo *) RelinquishMagickMemory(offset);
2424 blur_image=CloneImage(image,0,0,MagickTrue,exception);
2425 if (blur_image == (
Image *) NULL)
2427 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2428 offset=(
OffsetInfo *) RelinquishMagickMemory(offset);
2429 return((
Image *) NULL);
2431 if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
2433 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2434 offset=(
OffsetInfo *) RelinquishMagickMemory(offset);
2435 blur_image=DestroyImage(blur_image);
2436 return((
Image *) NULL);
2440 image_view=AcquireVirtualCacheView(image,exception);
2441 motion_view=AcquireVirtualCacheView(image,exception);
2442 blur_view=AcquireAuthenticCacheView(blur_image,exception);
2443#if defined(MAGICKCORE_OPENMP_SUPPORT)
2444 #pragma omp parallel for schedule(static) shared(progress,status) \
2445 magick_number_threads(image,blur_image,image->rows,1)
2447 for (y=0; y < (ssize_t) image->rows; y++)
2458 if (status == MagickFalse)
2460 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2461 q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
2463 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
2468 for (x=0; x < (ssize_t) image->columns; x++)
2473 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2496 channel=GetPixelChannelChannel(image,i);
2497 traits=GetPixelChannelTraits(image,channel);
2498 blur_traits=GetPixelChannelTraits(blur_image,channel);
2499 if ((traits == UndefinedPixelTrait) ||
2500 (blur_traits == UndefinedPixelTrait))
2502 if ((blur_traits & CopyPixelTrait) != 0)
2504 SetPixelChannel(blur_image,channel,p[i],q);
2509 if ((blur_traits & BlendPixelTrait) == 0)
2511 for (j=0; j < (ssize_t) width; j++)
2513 r=GetCacheViewVirtualPixels(motion_view,x+offset[j].x,y+
2514 offset[j].y,1,1,exception);
2515 if (r == (
const Quantum *) NULL)
2520 pixel+=(*k)*(double) r[i];
2523 SetPixelChannel(blur_image,channel,ClampToQuantum(pixel),q);
2526 for (j=0; j < (ssize_t) width; j++)
2528 r=GetCacheViewVirtualPixels(motion_view,x+offset[j].x,y+offset[j].y,1,
2530 if (r == (
const Quantum *) NULL)
2535 alpha=QuantumScale*(double) GetPixelAlpha(image,r);
2536 pixel+=(*k)*alpha*(double) r[i];
2540 gamma=PerceptibleReciprocal(gamma);
2541 SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
2543 p+=(ptrdiff_t) GetPixelChannels(image);
2544 q+=(ptrdiff_t) GetPixelChannels(blur_image);
2546 if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
2548 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2553#if defined(MAGICKCORE_OPENMP_SUPPORT)
2557 proceed=SetImageProgress(image,BlurImageTag,progress,image->rows);
2558 if (proceed == MagickFalse)
2562 blur_view=DestroyCacheView(blur_view);
2563 motion_view=DestroyCacheView(motion_view);
2564 image_view=DestroyCacheView(image_view);
2565 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2566 offset=(
OffsetInfo *) RelinquishMagickMemory(offset);
2567 if (status == MagickFalse)
2568 blur_image=DestroyImage(blur_image);
2602MagickExport
Image *PreviewImage(
const Image *image,
const PreviewType preview,
2605#define NumberTiles 9
2606#define PreviewImageTag "Preview/Image"
2607#define DefaultPreviewGeometry "204x204+10+10"
2610 factor[MagickPathExtent],
2611 label[MagickPathExtent];
2653 assert(image != (
Image *) NULL);
2654 assert(image->signature == MagickCoreSignature);
2655 if (IsEventLogging() != MagickFalse)
2656 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2660 preview_info=AcquireImageInfo();
2661 SetGeometry(image,&geometry);
2662 (void) ParseMetaGeometry(DefaultPreviewGeometry,&geometry.x,&geometry.y,
2663 &geometry.width,&geometry.height);
2664 images=NewImageList();
2666 GetQuantizeInfo(&quantize_info);
2670 for (i=0; i < NumberTiles; i++)
2672 thumbnail=ThumbnailImage(image,geometry.width,geometry.height,exception);
2673 if (thumbnail == (
Image *) NULL)
2675 (void) SetImageProgressMonitor(thumbnail,(MagickProgressMonitor) NULL,
2677 (void) SetImageProperty(thumbnail,
"label",DefaultTileLabel,exception);
2678 if (i == (NumberTiles/2))
2680 (void) QueryColorCompliance(
"#dfdfdf",AllCompliance,
2681 &thumbnail->matte_color,exception);
2682 AppendImageToList(&images,thumbnail);
2690 preview_image=RotateImage(thumbnail,degrees,exception);
2691 (void) FormatLocaleString(label,MagickPathExtent,
"rotate %g",degrees);
2697 preview_image=ShearImage(thumbnail,degrees,degrees,exception);
2698 (void) FormatLocaleString(label,MagickPathExtent,
"shear %gx%g",degrees,
2704 x=((i+1)*(ssize_t) thumbnail->columns)/NumberTiles;
2705 y=((i+1)*(ssize_t) thumbnail->rows)/NumberTiles;
2706 preview_image=RollImage(thumbnail,x,y,exception);
2707 (void) FormatLocaleString(label,MagickPathExtent,
"roll %+.20gx%+.20g",
2708 (
double) x,(double) y);
2713 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2714 if (preview_image == (
Image *) NULL)
2716 (void) FormatLocaleString(factor,MagickPathExtent,
"100,100,%g",2.0*
2718 (void) ModulateImage(preview_image,factor,exception);
2719 (void) FormatLocaleString(label,MagickPathExtent,
"modulate %s",factor);
2722 case SaturationPreview:
2724 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2725 if (preview_image == (
Image *) NULL)
2727 (void) FormatLocaleString(factor,MagickPathExtent,
"100,%g",2.0*
2729 (void) ModulateImage(preview_image,factor,exception);
2730 (void) FormatLocaleString(label,MagickPathExtent,
"modulate %s",factor);
2733 case BrightnessPreview:
2735 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2736 if (preview_image == (
Image *) NULL)
2738 (void) FormatLocaleString(factor,MagickPathExtent,
"%g",2.0*percentage);
2739 (void) ModulateImage(preview_image,factor,exception);
2740 (void) FormatLocaleString(label,MagickPathExtent,
"modulate %s",factor);
2746 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2747 if (preview_image == (
Image *) NULL)
2750 (void) GammaImage(preview_image,gamma,exception);
2751 (void) FormatLocaleString(label,MagickPathExtent,
"gamma %g",gamma);
2756 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2757 if (preview_image != (
Image *) NULL)
2758 for (x=0; x < i; x++)
2759 (
void) ContrastImage(preview_image,MagickTrue,exception);
2760 (void) FormatLocaleString(label,MagickPathExtent,
"contrast (%.20g)",
2766 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2767 if (preview_image == (
Image *) NULL)
2769 for (x=0; x < i; x++)
2770 (
void) ContrastImage(preview_image,MagickFalse,exception);
2771 (void) FormatLocaleString(label,MagickPathExtent,
"+contrast (%.20g)",
2775 case GrayscalePreview:
2777 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2778 if (preview_image == (
Image *) NULL)
2781 quantize_info.number_colors=colors;
2782 quantize_info.colorspace=GRAYColorspace;
2783 (void) QuantizeImage(&quantize_info,preview_image,exception);
2784 (void) FormatLocaleString(label,MagickPathExtent,
2785 "-colorspace gray -colors %.20g",(
double) colors);
2788 case QuantizePreview:
2790 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2791 if (preview_image == (
Image *) NULL)
2794 quantize_info.number_colors=colors;
2795 (void) QuantizeImage(&quantize_info,preview_image,exception);
2796 (void) FormatLocaleString(label,MagickPathExtent,
"colors %.20g",
2800 case DespecklePreview:
2802 for (x=0; x < (i-1); x++)
2804 preview_image=DespeckleImage(thumbnail,exception);
2805 if (preview_image == (
Image *) NULL)
2807 thumbnail=DestroyImage(thumbnail);
2808 thumbnail=preview_image;
2810 preview_image=DespeckleImage(thumbnail,exception);
2811 if (preview_image == (
Image *) NULL)
2813 (void) FormatLocaleString(label,MagickPathExtent,
"despeckle (%.20g)",
2817 case ReduceNoisePreview:
2819 preview_image=StatisticImage(thumbnail,NonpeakStatistic,(
size_t)
2820 radius,(
size_t) radius,exception);
2821 (void) FormatLocaleString(label,MagickPathExtent,
"noise %g",radius);
2824 case AddNoisePreview:
2830 (void) CopyMagickString(factor,
"uniform",MagickPathExtent);
2835 (void) CopyMagickString(factor,
"gaussian",MagickPathExtent);
2840 (void) CopyMagickString(factor,
"multiplicative",MagickPathExtent);
2845 (void) CopyMagickString(factor,
"impulse",MagickPathExtent);
2850 (void) CopyMagickString(factor,
"laplacian",MagickPathExtent);
2855 (void) CopyMagickString(factor,
"Poisson",MagickPathExtent);
2860 (void) CopyMagickString(thumbnail->magick,
"NULL",MagickPathExtent);
2864 preview_image=StatisticImage(thumbnail,NonpeakStatistic,(
size_t) i,
2865 (
size_t) i,exception);
2866 (void) FormatLocaleString(label,MagickPathExtent,
"+noise %s",factor);
2869 case SharpenPreview:
2871 preview_image=SharpenImage(thumbnail,radius,sigma,exception);
2872 (void) FormatLocaleString(label,MagickPathExtent,
"sharpen %gx%g",
2878 preview_image=BlurImage(thumbnail,radius,sigma,exception);
2879 (void) FormatLocaleString(label,MagickPathExtent,
"blur %gx%g",radius,
2883 case ThresholdPreview:
2885 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2886 if (preview_image == (
Image *) NULL)
2888 (void) BilevelImage(thumbnail,(
double) (percentage*((double)
2889 QuantumRange+1.0))/100.0,exception);
2890 (void) FormatLocaleString(label,MagickPathExtent,
"threshold %g",
2891 (
double) (percentage*((double) QuantumRange+1.0))/100.0);
2894 case EdgeDetectPreview:
2896 preview_image=EdgeImage(thumbnail,radius,exception);
2897 (void) FormatLocaleString(label,MagickPathExtent,
"edge %g",radius);
2902 preview_image=SpreadImage(thumbnail,image->interpolate,radius,
2904 (void) FormatLocaleString(label,MagickPathExtent,
"spread %g",
2908 case SolarizePreview:
2910 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2911 if (preview_image == (
Image *) NULL)
2913 (void) SolarizeImage(preview_image,(
double) QuantumRange*percentage/
2915 (void) FormatLocaleString(label,MagickPathExtent,
"solarize %g",
2916 ((
double) QuantumRange*percentage)/100.0);
2922 preview_image=ShadeImage(thumbnail,MagickTrue,degrees,degrees,
2924 (void) FormatLocaleString(label,MagickPathExtent,
"shade %gx%g",degrees,
2933 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2934 if (preview_image == (
Image *) NULL)
2936 raise.width=(size_t) (2*i+2);
2937 raise.height=(size_t) (2*i+2);
2940 (void) RaiseImage(preview_image,&raise,MagickTrue,exception);
2941 (void) FormatLocaleString(label,MagickPathExtent,
2942 "raise %.20gx%.20g%+.20g%+.20g",(
double) raise.width,(double)
2943 raise.height,(
double) raise.x,(double) raise.y);
2946 case SegmentPreview:
2948 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2949 if (preview_image == (
Image *) NULL)
2952 (void) SegmentImage(preview_image,sRGBColorspace,MagickFalse,threshold,
2953 threshold,exception);
2954 (void) FormatLocaleString(label,MagickPathExtent,
"segment %gx%g",
2955 threshold,threshold);
2960 preview_image=SwirlImage(thumbnail,degrees,image->interpolate,
2962 (void) FormatLocaleString(label,MagickPathExtent,
"swirl %g",degrees);
2966 case ImplodePreview:
2969 preview_image=ImplodeImage(thumbnail,degrees,image->interpolate,
2971 (void) FormatLocaleString(label,MagickPathExtent,
"implode %g",degrees);
2977 preview_image=WaveImage(thumbnail,0.5*degrees,2.0*degrees,
2978 image->interpolate,exception);
2979 (void) FormatLocaleString(label,MagickPathExtent,
"wave %gx%g",0.5*
2980 degrees,2.0*degrees);
2983 case OilPaintPreview:
2985 preview_image=OilPaintImage(thumbnail,(
double) radius,(
double) sigma,
2987 (void) FormatLocaleString(label,MagickPathExtent,
"charcoal %gx%g",
2991 case CharcoalDrawingPreview:
2993 preview_image=CharcoalImage(thumbnail,(
double) radius,(
double) sigma,
2995 (void) FormatLocaleString(label,MagickPathExtent,
"charcoal %gx%g",
3002 filename[MagickPathExtent];
3010 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
3011 if (preview_image == (
Image *) NULL)
3013 preview_info->quality=(size_t) percentage;
3014 (void) FormatLocaleString(factor,MagickPathExtent,
"%.20g",(
double)
3015 preview_info->quality);
3016 file=AcquireUniqueFileResource(filename);
3019 (void) FormatLocaleString(preview_image->filename,MagickPathExtent,
3020 "jpeg:%s",filename);
3021 status=WriteImage(preview_info,preview_image,exception);
3022 if (status != MagickFalse)
3027 (void) CopyMagickString(preview_info->filename,
3028 preview_image->filename,MagickPathExtent);
3029 quality_image=ReadImage(preview_info,exception);
3030 if (quality_image != (
Image *) NULL)
3032 preview_image=DestroyImage(preview_image);
3033 preview_image=quality_image;
3036 (void) RelinquishUniqueFileResource(preview_image->filename);
3037 if ((GetBlobSize(preview_image)/1024) >= 1024)
3038 (
void) FormatLocaleString(label,MagickPathExtent,
"quality %s\n%gmb ",
3039 factor,(
double) ((MagickOffsetType) GetBlobSize(preview_image))/
3042 if (GetBlobSize(preview_image) >= 1024)
3043 (void) FormatLocaleString(label,MagickPathExtent,
3044 "quality %s\n%gkb ",factor,(
double) ((MagickOffsetType)
3045 GetBlobSize(preview_image))/1024.0);
3047 (
void) FormatLocaleString(label,MagickPathExtent,
3048 "quality %s\n%.20gb ",factor,(
double) ((MagickOffsetType)
3049 GetBlobSize(thumbnail)));
3053 thumbnail=DestroyImage(thumbnail);
3057 if (preview_image == (
Image *) NULL)
3059 preview_image->alpha_trait=UndefinedPixelTrait;
3060 (void) DeleteImageProperty(preview_image,
"label");
3061 (void) SetImageProperty(preview_image,
"label",label,exception);
3062 AppendImageToList(&images,preview_image);
3063 proceed=SetImageProgress(image,PreviewImageTag,(MagickOffsetType) i,
3065 if (proceed == MagickFalse)
3068 if (images == (
Image *) NULL)
3070 preview_info=DestroyImageInfo(preview_info);
3071 return((
Image *) NULL);
3076 montage_info=CloneMontageInfo(preview_info,(
MontageInfo *) NULL);
3077 (void) CopyMagickString(montage_info->filename,image->filename,
3079 montage_info->shadow=MagickTrue;
3080 (void) CloneString(&montage_info->tile,
"3x3");
3081 (void) CloneString(&montage_info->geometry,DefaultPreviewGeometry);
3082 (void) CloneString(&montage_info->frame,DefaultTileFrame);
3083 montage_image=MontageImages(images,montage_info,exception);
3084 montage_info=DestroyMontageInfo(montage_info);
3085 images=DestroyImageList(images);
3086 if (montage_image == (
Image *) NULL)
3087 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3088 if (montage_image->montage != (
char *) NULL)
3093 montage_image->montage=(
char *) RelinquishMagickMemory(
3094 montage_image->montage);
3095 if (image->directory != (
char *) NULL)
3096 montage_image->directory=(
char *) RelinquishMagickMemory(
3097 montage_image->directory);
3099 preview_info=DestroyImageInfo(preview_info);
3100 return(montage_image);
3134MagickExport
Image *RotationalBlurImage(
const Image *image,
const double angle,
3171 assert(image != (
Image *) NULL);
3172 assert(image->signature == MagickCoreSignature);
3174 assert(exception->signature == MagickCoreSignature);
3175 if (IsEventLogging() != MagickFalse)
3176 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3177#if defined(MAGICKCORE_OPENCL_SUPPORT)
3178 blur_image=AccelerateRotationalBlurImage(image,angle,exception);
3179 if (blur_image != (
Image *) NULL)
3182 blur_image=CloneImage(image,0,0,MagickTrue,exception);
3183 if (blur_image == (
Image *) NULL)
3184 return((
Image *) NULL);
3185 if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
3187 blur_image=DestroyImage(blur_image);
3188 return((
Image *) NULL);
3190 blur_center.x=(double) (image->columns-1)/2.0;
3191 blur_center.y=(double) (image->rows-1)/2.0;
3192 blur_radius=hypot(blur_center.x,blur_center.y);
3193 n=(size_t) fabs(4.0*DegreesToRadians(angle)*sqrt((
double) blur_radius)+2UL);
3194 theta=DegreesToRadians(angle)/(double) (n-1);
3195 cos_theta=(
double *) AcquireQuantumMemory((
size_t) n,
sizeof(*cos_theta));
3196 sin_theta=(
double *) AcquireQuantumMemory((
size_t) n,
sizeof(*sin_theta));
3197 if ((cos_theta == (
double *) NULL) || (sin_theta == (
double *) NULL))
3199 if (cos_theta != (
double *) NULL)
3200 cos_theta=(
double *) RelinquishMagickMemory(cos_theta);
3201 if (sin_theta != (
double *) NULL)
3202 sin_theta=(
double *) RelinquishMagickMemory(sin_theta);
3203 blur_image=DestroyImage(blur_image);
3204 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3206 offset=theta*(double) (n-1)/2.0;
3207 for (w=0; w < (ssize_t) n; w++)
3209 cos_theta[w]=cos((
double) (theta*w-offset));
3210 sin_theta[w]=sin((
double) (theta*w-offset));
3217 image_view=AcquireVirtualCacheView(image,exception);
3218 radial_view=AcquireVirtualCacheView(image,exception);
3219 blur_view=AcquireAuthenticCacheView(blur_image,exception);
3220#if defined(MAGICKCORE_OPENMP_SUPPORT)
3221 #pragma omp parallel for schedule(static) shared(progress,status) \
3222 magick_number_threads(image,blur_image,image->rows,1)
3224 for (y=0; y < (ssize_t) image->rows; y++)
3235 if (status == MagickFalse)
3237 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
3238 q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
3240 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3245 for (x=0; x < (ssize_t) image->columns; x++)
3259 center.x=(double) x-blur_center.x;
3260 center.y=(double) y-blur_center.y;
3261 radius=hypot((
double) center.x,center.y);
3266 step=(size_t) (blur_radius/radius);
3273 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3292 channel=GetPixelChannelChannel(image,i);
3293 traits=GetPixelChannelTraits(image,channel);
3294 blur_traits=GetPixelChannelTraits(blur_image,channel);
3295 if ((traits == UndefinedPixelTrait) ||
3296 (blur_traits == UndefinedPixelTrait))
3298 if ((blur_traits & CopyPixelTrait) != 0)
3300 SetPixelChannel(blur_image,channel,p[i],q);
3305 if ((GetPixelChannelTraits(image,AlphaPixelChannel) == UndefinedPixelTrait) ||
3306 (channel == AlphaPixelChannel))
3308 for (j=0; j < (ssize_t) n; j+=(ssize_t) step)
3310 r=GetCacheViewVirtualPixels(radial_view, (ssize_t) (blur_center.x+
3311 center.x*cos_theta[j]-center.y*sin_theta[j]+0.5),(ssize_t)
3312 (blur_center.y+center.x*sin_theta[j]+center.y*cos_theta[j]+0.5),
3314 if (r == (
const Quantum *) NULL)
3319 pixel+=(double) r[i];
3322 gamma=PerceptibleReciprocal(gamma);
3323 SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
3326 for (j=0; j < (ssize_t) n; j+=(ssize_t) step)
3331 r=GetCacheViewVirtualPixels(radial_view, (ssize_t) (blur_center.x+
3332 center.x*cos_theta[j]-center.y*sin_theta[j]+0.5),(ssize_t)
3333 (blur_center.y+center.x*sin_theta[j]+center.y*cos_theta[j]+0.5),
3335 if (r == (
const Quantum *) NULL)
3340 alpha=QuantumScale*(double) GetPixelAlpha(image,r);
3341 pixel+=alpha*(double) r[i];
3344 gamma=PerceptibleReciprocal(gamma);
3345 SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
3347 p+=(ptrdiff_t) GetPixelChannels(image);
3348 q+=(ptrdiff_t) GetPixelChannels(blur_image);
3350 if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
3352 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3357#if defined(MAGICKCORE_OPENMP_SUPPORT)
3361 proceed=SetImageProgress(image,BlurImageTag,progress,image->rows);
3362 if (proceed == MagickFalse)
3366 blur_view=DestroyCacheView(blur_view);
3367 radial_view=DestroyCacheView(radial_view);
3368 image_view=DestroyCacheView(image_view);
3369 cos_theta=(
double *) RelinquishMagickMemory(cos_theta);
3370 sin_theta=(
double *) RelinquishMagickMemory(sin_theta);
3371 if (status == MagickFalse)
3372 blur_image=DestroyImage(blur_image);
3411MagickExport
Image *SelectiveBlurImage(
const Image *image,
const double radius,
3412 const double sigma,
const double threshold,
ExceptionInfo *exception)
3414#define SelectiveBlurImageTag "SelectiveBlur/Image"
3444 assert(image != (
Image *) NULL);
3445 assert(image->signature == MagickCoreSignature);
3447 assert(exception->signature == MagickCoreSignature);
3448 if (IsEventLogging() != MagickFalse)
3449 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3450 width=GetOptimalKernelWidth1D(radius,sigma);
3451 kernel=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory((
size_t)
3452 width,width*
sizeof(*kernel)));
3453 if (kernel == (MagickRealType *) NULL)
3454 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3461 j=(ssize_t) (width-1)/2;
3463 for (v=(-j); v <= j; v++)
3468 for (u=(-j); u <= j; u++)
3469 kernel[i++]=(MagickRealType) (exp(-((
double) u*u+v*v)/(2.0*MagickSigma*
3470 MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
3473 if (image->debug != MagickFalse)
3476 format[MagickPathExtent],
3479 const MagickRealType
3486 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
3487 " SelectiveBlurImage with %.20gx%.20g kernel:",(double) width,(
double)
3489 message=AcquireString(
"");
3491 for (v=0; v < (ssize_t) width; v++)
3494 (void) FormatLocaleString(format,MagickPathExtent,
"%.20g: ",(
double) v);
3495 (void) ConcatenateString(&message,format);
3496 for (u=0; u < (ssize_t) width; u++)
3498 (void) FormatLocaleString(format,MagickPathExtent,
"%+f ",(
double)
3500 (void) ConcatenateString(&message,format);
3502 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
"%s",message);
3504 message=DestroyString(message);
3506 blur_image=CloneImage(image,0,0,MagickTrue,exception);
3507 if (blur_image == (
Image *) NULL)
3508 return((
Image *) NULL);
3509 if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
3511 blur_image=DestroyImage(blur_image);
3512 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
3513 return((
Image *) NULL);
3515 luminance_image=CloneImage(image,0,0,MagickTrue,exception);
3516 if (luminance_image == (
Image *) NULL)
3518 blur_image=DestroyImage(blur_image);
3519 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
3520 return((
Image *) NULL);
3522 status=TransformImageColorspace(luminance_image,GRAYColorspace,exception);
3523 if (status == MagickFalse)
3525 luminance_image=DestroyImage(luminance_image);
3526 blur_image=DestroyImage(blur_image);
3527 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
3528 return((
Image *) NULL);
3535 center=(ssize_t) (GetPixelChannels(image)*(image->columns+width)*
3536 ((width-1)/2L)+GetPixelChannels(image)*((width-1)/2L));
3537 image_view=AcquireVirtualCacheView(image,exception);
3538 luminance_view=AcquireVirtualCacheView(luminance_image,exception);
3539 blur_view=AcquireAuthenticCacheView(blur_image,exception);
3540#if defined(MAGICKCORE_OPENMP_SUPPORT)
3541 #pragma omp parallel for schedule(static) shared(progress,status) \
3542 magick_number_threads(image,blur_image,image->rows,1)
3544 for (y=0; y < (ssize_t) image->rows; y++)
3562 if (status == MagickFalse)
3564 p=GetCacheViewVirtualPixels(image_view,-((ssize_t) (width-1)/2L),y-(ssize_t)
3565 ((width-1)/2L),image->columns+width,width,exception);
3566 l=GetCacheViewVirtualPixels(luminance_view,-((ssize_t) (width-1)/2L),y-
3567 (ssize_t) ((width-1)/2L),luminance_image->columns+width,width,exception);
3568 q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
3570 if ((p == (
const Quantum *) NULL) || (l == (
const Quantum *) NULL) ||
3571 (q == (Quantum *) NULL))
3576 for (x=0; x < (ssize_t) image->columns; x++)
3584 intensity=GetPixelIntensity(image,p+center);
3585 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3599 const MagickRealType
3603 *magick_restrict luminance_pixels,
3604 *magick_restrict pixels;
3612 channel=GetPixelChannelChannel(image,i);
3613 traits=GetPixelChannelTraits(image,channel);
3614 blur_traits=GetPixelChannelTraits(blur_image,channel);
3615 if ((traits == UndefinedPixelTrait) ||
3616 (blur_traits == UndefinedPixelTrait))
3618 if ((blur_traits & CopyPixelTrait) != 0)
3620 SetPixelChannel(blur_image,channel,p[center+i],q);
3628 if ((blur_traits & BlendPixelTrait) == 0)
3630 for (v=0; v < (ssize_t) width; v++)
3632 for (u=0; u < (ssize_t) width; u++)
3634 contrast=GetPixelIntensity(luminance_image,luminance_pixels)-
3636 if (fabs(contrast) < threshold)
3638 pixel+=(*k)*(double) pixels[i];
3642 pixels+=(ptrdiff_t) GetPixelChannels(image);
3643 luminance_pixels+=(ptrdiff_t) GetPixelChannels(luminance_image);
3645 pixels+=(ptrdiff_t) GetPixelChannels(image)*image->columns;
3646 luminance_pixels+=(ptrdiff_t) GetPixelChannels(luminance_image)*
3647 luminance_image->columns;
3649 if (fabs((
double) gamma) < MagickEpsilon)
3651 SetPixelChannel(blur_image,channel,p[center+i],q);
3654 gamma=PerceptibleReciprocal(gamma);
3655 SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
3658 for (v=0; v < (ssize_t) width; v++)
3660 for (u=0; u < (ssize_t) width; u++)
3662 contrast=GetPixelIntensity(image,pixels)-intensity;
3663 if (fabs(contrast) < threshold)
3665 alpha=QuantumScale*(double) GetPixelAlpha(image,pixels);
3666 pixel+=(*k)*alpha*(double) pixels[i];
3670 pixels+=(ptrdiff_t) GetPixelChannels(image);
3671 luminance_pixels+=(ptrdiff_t) GetPixelChannels(luminance_image);
3673 pixels+=(ptrdiff_t) GetPixelChannels(image)*image->columns;
3674 luminance_pixels+=(ptrdiff_t) GetPixelChannels(luminance_image)*
3675 luminance_image->columns;
3677 if (fabs((
double) gamma) < MagickEpsilon)
3679 SetPixelChannel(blur_image,channel,p[center+i],q);
3682 gamma=PerceptibleReciprocal(gamma);
3683 SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
3685 p+=(ptrdiff_t) GetPixelChannels(image);
3686 l+=(ptrdiff_t) GetPixelChannels(luminance_image);
3687 q+=(ptrdiff_t) GetPixelChannels(blur_image);
3689 sync=SyncCacheViewAuthenticPixels(blur_view,exception);
3690 if (sync == MagickFalse)
3692 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3697#if defined(MAGICKCORE_OPENMP_SUPPORT)
3701 proceed=SetImageProgress(image,SelectiveBlurImageTag,progress,
3703 if (proceed == MagickFalse)
3707 blur_image->type=image->type;
3708 blur_view=DestroyCacheView(blur_view);
3709 luminance_view=DestroyCacheView(luminance_view);
3710 image_view=DestroyCacheView(image_view);
3711 luminance_image=DestroyImage(luminance_image);
3712 kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
3713 if (status == MagickFalse)
3714 blur_image=DestroyImage(blur_image);
3750MagickExport
Image *ShadeImage(
const Image *image,
const MagickBooleanType gray,
3751 const double azimuth,
const double elevation,
ExceptionInfo *exception)
3753#define GetShadeIntensity(image,pixel) \
3754 ClampPixel(GetPixelIntensity((image),(pixel)))
3755#define ShadeImageTag "Shade/Image"
3780 assert(image != (
const Image *) NULL);
3781 assert(image->signature == MagickCoreSignature);
3783 assert(exception->signature == MagickCoreSignature);
3784 if (IsEventLogging() != MagickFalse)
3785 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3786 linear_image=CloneImage(image,0,0,MagickTrue,exception);
3787 shade_image=CloneImage(image,0,0,MagickTrue,exception);
3788 if ((linear_image == (
Image *) NULL) || (shade_image == (
Image *) NULL))
3790 if (linear_image != (
Image *) NULL)
3791 linear_image=DestroyImage(linear_image);
3792 if (shade_image != (
Image *) NULL)
3793 shade_image=DestroyImage(shade_image);
3794 return((
Image *) NULL);
3796 if (SetImageStorageClass(shade_image,DirectClass,exception) == MagickFalse)
3798 linear_image=DestroyImage(linear_image);
3799 shade_image=DestroyImage(shade_image);
3800 return((
Image *) NULL);
3805 light.x=(double) QuantumRange*cos(DegreesToRadians(azimuth))*
3806 cos(DegreesToRadians(elevation));
3807 light.y=(double) QuantumRange*sin(DegreesToRadians(azimuth))*
3808 cos(DegreesToRadians(elevation));
3809 light.z=(double) QuantumRange*sin(DegreesToRadians(elevation));
3815 image_view=AcquireVirtualCacheView(linear_image,exception);
3816 shade_view=AcquireAuthenticCacheView(shade_image,exception);
3817#if defined(MAGICKCORE_OPENMP_SUPPORT)
3818 #pragma omp parallel for schedule(static) shared(progress,status) \
3819 magick_number_threads(linear_image,shade_image,linear_image->rows,1)
3821 for (y=0; y < (ssize_t) linear_image->rows; y++)
3832 *magick_restrict center,
3834 *magick_restrict post,
3835 *magick_restrict pre;
3843 if (status == MagickFalse)
3845 p=GetCacheViewVirtualPixels(image_view,-1,y-1,linear_image->columns+2,3,
3847 q=QueueCacheViewAuthenticPixels(shade_view,0,y,shade_image->columns,1,
3849 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3857 normal.z=2.0*(double) QuantumRange;
3858 for (x=0; x < (ssize_t) linear_image->columns; x++)
3866 pre=p+GetPixelChannels(linear_image);
3867 center=pre+(linear_image->columns+2)*GetPixelChannels(linear_image);
3868 post=center+(linear_image->columns+2)*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))-
3873 GetShadeIntensity(linear_image,pre+GetPixelChannels(linear_image))-
3874 GetShadeIntensity(linear_image,center+GetPixelChannels(linear_image))-
3875 GetShadeIntensity(linear_image,post+GetPixelChannels(linear_image)));
3877 GetShadeIntensity(linear_image,post-GetPixelChannels(linear_image))+
3878 GetShadeIntensity(linear_image,post)+
3879 GetShadeIntensity(linear_image,post+GetPixelChannels(linear_image))-
3880 GetShadeIntensity(linear_image,pre-GetPixelChannels(linear_image))-
3881 GetShadeIntensity(linear_image,pre)-
3882 GetShadeIntensity(linear_image,pre+GetPixelChannels(linear_image)));
3883 if ((fabs(normal.x) <= MagickEpsilon) &&
3884 (fabs(normal.y) <= MagickEpsilon))
3889 distance=normal.x*light.x+normal.y*light.y+normal.z*light.z;
3890 if (distance > MagickEpsilon)
3892 normal_distance=normal.x*normal.x+normal.y*normal.y+
3894 if (normal_distance > (MagickEpsilon*MagickEpsilon))
3895 shade=distance/sqrt((
double) normal_distance);
3898 for (i=0; i < (ssize_t) GetPixelChannels(linear_image); i++)
3907 channel=GetPixelChannelChannel(linear_image,i);
3908 traits=GetPixelChannelTraits(linear_image,channel);
3909 shade_traits=GetPixelChannelTraits(shade_image,channel);
3910 if ((traits == UndefinedPixelTrait) ||
3911 (shade_traits == UndefinedPixelTrait))
3913 if ((shade_traits & CopyPixelTrait) != 0)
3915 SetPixelChannel(shade_image,channel,center[i],q);
3918 if ((traits & UpdatePixelTrait) == 0)
3920 SetPixelChannel(shade_image,channel,center[i],q);
3923 if (gray != MagickFalse)
3925 SetPixelChannel(shade_image,channel,ClampToQuantum(shade),q);
3928 SetPixelChannel(shade_image,channel,ClampToQuantum(QuantumScale*
3929 shade*(
double) center[i]),q);
3931 p+=(ptrdiff_t) GetPixelChannels(linear_image);
3932 q+=(ptrdiff_t) GetPixelChannels(shade_image);
3934 if (SyncCacheViewAuthenticPixels(shade_view,exception) == MagickFalse)
3936 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3941#if defined(MAGICKCORE_OPENMP_SUPPORT)
3945 proceed=SetImageProgress(image,ShadeImageTag,progress,image->rows);
3946 if (proceed == MagickFalse)
3950 shade_view=DestroyCacheView(shade_view);
3951 image_view=DestroyCacheView(image_view);
3952 linear_image=DestroyImage(linear_image);
3953 if (status == MagickFalse)
3954 shade_image=DestroyImage(shade_image);
3955 return(shade_image);
3996MagickExport
Image *SharpenImage(
const Image *image,
const double radius,
4020 assert(image != (
const Image *) NULL);
4021 assert(image->signature == MagickCoreSignature);
4023 assert(exception->signature == MagickCoreSignature);
4024 if (IsEventLogging() != MagickFalse)
4025 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4026 width=GetOptimalKernelWidth2D(radius,sigma);
4027 kernel_info=AcquireKernelInfo((
const char *) NULL,exception);
4029 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
4030 (void) memset(kernel_info,0,
sizeof(*kernel_info));
4031 kernel_info->width=width;
4032 kernel_info->height=width;
4033 kernel_info->x=(ssize_t) (width-1)/2;
4034 kernel_info->y=(ssize_t) (width-1)/2;
4035 kernel_info->signature=MagickCoreSignature;
4036 kernel_info->values=(MagickRealType *) MagickAssumeAligned(
4037 AcquireAlignedMemory(kernel_info->width,kernel_info->height*
4038 sizeof(*kernel_info->values)));
4039 if (kernel_info->values == (MagickRealType *) NULL)
4041 kernel_info=DestroyKernelInfo(kernel_info);
4042 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
4045 j=(ssize_t) (kernel_info->width-1)/2;
4047 for (v=(-j); v <= j; v++)
4049 for (u=(-j); u <= j; u++)
4051 kernel_info->values[i]=(MagickRealType) (-exp(-((
double) u*u+v*v)/(2.0*
4052 MagickSigma*MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
4053 normalize+=kernel_info->values[i];
4057 kernel_info->values[i/2]=(double) ((-2.0)*normalize);
4059 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
4060 normalize+=kernel_info->values[i];
4061 gamma=PerceptibleReciprocal(normalize);
4062 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
4063 kernel_info->values[i]*=gamma;
4064 sharp_image=ConvolveImage(image,kernel_info,exception);
4065 kernel_info=DestroyKernelInfo(kernel_info);
4066 return(sharp_image);
4100MagickExport
Image *SpreadImage(
const Image *image,
4101 const PixelInterpolateMethod method,
const double radius,
4104#define SpreadImageTag "Spread/Image"
4120 **magick_restrict random_info;
4128#if defined(MAGICKCORE_OPENMP_SUPPORT)
4136 assert(image != (
Image *) NULL);
4137 assert(image->signature == MagickCoreSignature);
4139 assert(exception->signature == MagickCoreSignature);
4140 if (IsEventLogging() != MagickFalse)
4141 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4142 spread_image=CloneImage(image,0,0,MagickTrue,exception);
4143 if (spread_image == (
Image *) NULL)
4144 return((
Image *) NULL);
4145 if (SetImageStorageClass(spread_image,DirectClass,exception) == MagickFalse)
4147 spread_image=DestroyImage(spread_image);
4148 return((
Image *) NULL);
4155 width=GetOptimalKernelWidth1D(radius,0.5);
4156 random_info=AcquireRandomInfoTLS();
4157 image_view=AcquireVirtualCacheView(image,exception);
4158 spread_view=AcquireAuthenticCacheView(spread_image,exception);
4159#if defined(MAGICKCORE_OPENMP_SUPPORT)
4160 key=GetRandomSecretKey(random_info[0]);
4161 #pragma omp parallel for schedule(static) shared(progress,status) \
4162 magick_number_threads(image,spread_image,image->rows,key == ~0UL)
4164 for (y=0; y < (ssize_t) image->rows; y++)
4167 id = GetOpenMPThreadId();
4175 if (status == MagickFalse)
4177 q=QueueCacheViewAuthenticPixels(spread_view,0,y,spread_image->columns,1,
4179 if (q == (Quantum *) NULL)
4184 for (x=0; x < (ssize_t) image->columns; x++)
4189 point.x=GetPseudoRandomValue(random_info[
id]);
4190 point.y=GetPseudoRandomValue(random_info[
id]);
4191 status=InterpolatePixelChannels(image,image_view,spread_image,method,
4192 (
double) x+width*(point.x-0.5),(
double) y+width*(point.y-0.5),q,
4194 if (status == MagickFalse)
4196 q+=(ptrdiff_t) GetPixelChannels(spread_image);
4198 if (SyncCacheViewAuthenticPixels(spread_view,exception) == MagickFalse)
4200 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4205#if defined(MAGICKCORE_OPENMP_SUPPORT)
4209 proceed=SetImageProgress(image,SpreadImageTag,progress,image->rows);
4210 if (proceed == MagickFalse)
4214 spread_view=DestroyCacheView(spread_view);
4215 image_view=DestroyCacheView(image_view);
4216 random_info=DestroyRandomInfoTLS(random_info);
4217 if (status == MagickFalse)
4218 spread_image=DestroyImage(spread_image);
4219 return(spread_image);
4261MagickExport
Image *UnsharpMaskImage(
const Image *image,
const double radius,
4262 const double sigma,
const double gain,
const double threshold,
4265#define SharpenImageTag "Sharpen/Image"
4286 assert(image != (
const Image *) NULL);
4287 assert(image->signature == MagickCoreSignature);
4289 assert(exception->signature == MagickCoreSignature);
4290 if (IsEventLogging() != MagickFalse)
4291 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4300 unsharp_image=BlurImage(image,radius,sigma,exception);
4301 if (unsharp_image == (
Image *) NULL)
4302 return((
Image *) NULL);
4303 quantum_threshold=(double) QuantumRange*threshold;
4309 image_view=AcquireVirtualCacheView(image,exception);
4310 unsharp_view=AcquireAuthenticCacheView(unsharp_image,exception);
4311#if defined(MAGICKCORE_OPENMP_SUPPORT)
4312 #pragma omp parallel for schedule(static) shared(progress,status) \
4313 magick_number_threads(image,unsharp_image,image->rows,1)
4315 for (y=0; y < (ssize_t) image->rows; y++)
4326 if (status == MagickFalse)
4328 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
4329 q=GetCacheViewAuthenticPixels(unsharp_view,0,y,unsharp_image->columns,1,
4331 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
4336 for (x=0; x < (ssize_t) image->columns; x++)
4341 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4353 channel=GetPixelChannelChannel(image,i);
4354 traits=GetPixelChannelTraits(image,channel);
4355 unsharp_traits=GetPixelChannelTraits(unsharp_image,channel);
4356 if ((traits == UndefinedPixelTrait) ||
4357 (unsharp_traits == UndefinedPixelTrait))
4359 if ((unsharp_traits & CopyPixelTrait) != 0)
4361 SetPixelChannel(unsharp_image,channel,p[i],q);
4364 pixel=(double) p[i]-(
double) GetPixelChannel(unsharp_image,channel,q);
4365 if (fabs(2.0*pixel) < quantum_threshold)
4366 pixel=(double) p[i];
4368 pixel=(double) p[i]+gain*pixel;
4369 SetPixelChannel(unsharp_image,channel,ClampToQuantum(pixel),q);
4371 p+=(ptrdiff_t) GetPixelChannels(image);
4372 q+=(ptrdiff_t) GetPixelChannels(unsharp_image);
4374 if (SyncCacheViewAuthenticPixels(unsharp_view,exception) == MagickFalse)
4376 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4381#if defined(MAGICKCORE_OPENMP_SUPPORT)
4385 proceed=SetImageProgress(image,SharpenImageTag,progress,image->rows);
4386 if (proceed == MagickFalse)
4390 unsharp_image->type=image->type;
4391 unsharp_view=DestroyCacheView(unsharp_view);
4392 image_view=DestroyCacheView(image_view);
4393 if (status == MagickFalse)
4394 unsharp_image=DestroyImage(unsharp_image);
4395 return(unsharp_image);