MagickExport Image *ConvolveImage(const Image *image,
const KernelInfo *kernel_info,ExceptionInfo *exception)
{
-#define ConvolveImageTag "Convolve/Image"
-
- CacheView
- *convolve_view,
- *image_view;
-
- Image
- *convolve_image;
-
- MagickBooleanType
- status;
-
- MagickOffsetType
- progress;
-
- ssize_t
- center,
- y;
-
- /*
- Initialize convolve image attributes.
- */
- assert(image != (Image *) NULL);
- assert(image->signature == MagickSignature);
- if (image->debug != MagickFalse)
- (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
- assert(exception != (ExceptionInfo *) NULL);
- assert(exception->signature == MagickSignature);
- if ((kernel_info->width % 2) == 0)
- ThrowImageException(OptionError,"KernelWidthMustBeAnOddNumber");
- convolve_image=CloneImage(image,image->columns,image->rows,MagickTrue,
- exception);
- if (convolve_image == (Image *) NULL)
- return((Image *) NULL);
- if (SetImageStorageClass(convolve_image,DirectClass,exception) == MagickFalse)
- {
- convolve_image=DestroyImage(convolve_image);
- return((Image *) NULL);
- }
- if (image->debug != MagickFalse)
- {
- char
- format[MaxTextExtent],
- *message;
-
- register const MagickRealType
- *k;
-
- register ssize_t
- u;
-
- ssize_t
- v;
-
- (void) LogMagickEvent(TransformEvent,GetMagickModule(),
- " ConvolveImage with %.20gx%.20g kernel:",(double) kernel_info->width,
- (double) kernel_info->height);
- message=AcquireString("");
- k=kernel_info->values;
- for (v=0; v < (ssize_t) kernel_info->width; v++)
- {
- *message='\0';
- (void) FormatLocaleString(format,MaxTextExtent,"%.20g: ",(double) v);
- (void) ConcatenateString(&message,format);
- for (u=0; u < (ssize_t) kernel_info->height; u++)
- {
- (void) FormatLocaleString(format,MaxTextExtent,"%g ",*k++);
- (void) ConcatenateString(&message,format);
- }
- (void) LogMagickEvent(TransformEvent,GetMagickModule(),"%s",message);
- }
- message=DestroyString(message);
- }
- status=AccelerateConvolveImage(image,kernel_info,convolve_image,exception);
- if (status == MagickTrue)
- return(convolve_image);
- /*
- Convolve image.
- FUTURE: Use Morphology Convolve instead.
- */
- center=(ssize_t) GetPixelChannels(image)*(image->columns+kernel_info->width)*
- (kernel_info->height/2L)+GetPixelChannels(image)*(kernel_info->width/2L);
- status=MagickTrue;
- progress=0;
- image_view=AcquireCacheView(image);
- convolve_view=AcquireCacheView(convolve_image);
-#if defined(MAGICKCORE_OPENMP_SUPPORT)
- #pragma omp parallel for schedule(static,4) shared(progress,status)
-#endif
- for (y=0; y < (ssize_t) image->rows; y++)
- {
- register const Quantum
- *restrict p;
-
- register Quantum
- *restrict q;
-
- register ssize_t
- x;
-
- if (status == MagickFalse)
- continue;
- p=GetCacheViewVirtualPixels(image_view,-((ssize_t) kernel_info->width/2L),y-
- (ssize_t) (kernel_info->height/2L),image->columns+kernel_info->width,
- kernel_info->height,exception);
- q=QueueCacheViewAuthenticPixels(convolve_view,0,y,convolve_image->columns,1,
- exception);
- if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
- {
- status=MagickFalse;
- continue;
- }
- for (x=0; x < (ssize_t) image->columns; x++)
- {
- register ssize_t
- i;
-
- for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
- {
- MagickRealType
- alpha,
- gamma,
- pixel;
-
- PixelChannel
- channel;
-
- PixelTrait
- convolve_traits,
- traits;
-
- register const MagickRealType
- *restrict k;
-
- register const Quantum
- *restrict pixels;
-
- register ssize_t
- u;
-
- ssize_t
- v;
-
- channel=GetPixelChannelMapChannel(image,i);
- traits=GetPixelChannelMapTraits(image,channel);
- convolve_traits=GetPixelChannelMapTraits(convolve_image,channel);
- if ((traits == UndefinedPixelTrait) ||
- (convolve_traits == UndefinedPixelTrait))
- continue;
- if (((convolve_traits & CopyPixelTrait) != 0) ||
- (GetPixelMask(image,p) != 0))
- {
- SetPixelChannel(convolve_image,channel,p[center+i],q);
- continue;
- }
- k=kernel_info->values;
- pixels=p;
- pixel=kernel_info->bias;
- if ((convolve_traits & BlendPixelTrait) == 0)
- {
- /*
- No alpha blending.
- */
- for (v=0; v < (ssize_t) kernel_info->height; v++)
- {
- for (u=0; u < (ssize_t) kernel_info->width; u++)
- {
- pixel+=(*k)*pixels[i];
- k++;
- pixels+=GetPixelChannels(image);
- }
- pixels+=image->columns*GetPixelChannels(image);
- }
- SetPixelChannel(convolve_image,channel,ClampToQuantum(pixel),q);
- continue;
- }
- /*
- Alpha blending.
- */
- gamma=0.0;
- for (v=0; v < (ssize_t) kernel_info->height; v++)
- {
- for (u=0; u < (ssize_t) kernel_info->width; u++)
- {
- alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(image,pixels));
- pixel+=(*k)*alpha*pixels[i];
- gamma+=(*k)*alpha;
- k++;
- pixels+=GetPixelChannels(image);
- }
- pixels+=image->columns*GetPixelChannels(image);
- }
- gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
- SetPixelChannel(convolve_image,channel,ClampToQuantum(gamma*pixel),q);
- }
- p+=GetPixelChannels(image);
- q+=GetPixelChannels(convolve_image);
- }
- if (SyncCacheViewAuthenticPixels(convolve_view,exception) == MagickFalse)
- status=MagickFalse;
- if (image->progress_monitor != (MagickProgressMonitor) NULL)
- {
- MagickBooleanType
- proceed;
-
-#if defined(MAGICKCORE_OPENMP_SUPPORT)
- #pragma omp critical (MagickCore_ConvolveImage)
-#endif
- proceed=SetImageProgress(image,ConvolveImageTag,progress++,image->rows);
- if (proceed == MagickFalse)
- status=MagickFalse;
- }
- }
- convolve_image->type=image->type;
- convolve_view=DestroyCacheView(convolve_view);
- image_view=DestroyCacheView(image_view);
- if (status == MagickFalse)
- convolve_image=DestroyImage(convolve_image);
- return(convolve_image);
+ return(MorphologyImage(image,ConvolveMorphology,0,kernel_info,exception));
}
\f
/*