% October 1996 %
% %
% %
-% Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
+% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
% dedicated to making software imaging solutions freely available. %
% %
% You may not use this file except in compliance with the License. You may %
{
for (u=(-j); u <= j; u++)
{
- kernel[i][k]=exp(-((double) u*u+v*v)/(2.0*MagickSigma*MagickSigma))/
- (2.0*MagickPI*MagickSigma*MagickSigma);
+ kernel[i][k]=(double) (exp(-((double) u*u+v*v)/(2.0*MagickSigma*
+ MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
normalize+=kernel[i][k];
k++;
}
register IndexPacket
*restrict blur_indexes;
- register ssize_t
- x;
-
register PixelPacket
*restrict q;
+ register ssize_t
+ x;
+
if (status == MagickFalse)
continue;
r=GetCacheViewVirtualPixels(edge_view,0,y,edge_image->columns,1,exception);
i=(ssize_t) width;
if ((i & 0x01) != 0)
i--;
- p=GetCacheViewVirtualPixels(image_view,x-((ssize_t) (width-i)/2L),y-(ssize_t)
- ((width-i)/2L),width-i,width-i,exception);
+ p=GetCacheViewVirtualPixels(image_view,x-((ssize_t) (width-i)/2L),y-
+ (ssize_t) ((width-i)/2L),width-i,width-i,exception);
if (p == (const PixelPacket *) NULL)
break;
indexes=GetCacheViewVirtualIndexQueue(image_view);
pixel.opacity+=(*k)*GetOpacityPixelComponent(p);
if (((channel & IndexChannel) != 0) &&
(image->colorspace == CMYKColorspace))
- pixel.index+=(*k)*alpha*indexes[x+(width-i)*v+u];
+ pixel.index+=(*k)*alpha*GetIndexPixelComponent(indexes+x+(width-i)*
+ v+u);
gamma+=(*k)*alpha;
k++;
p++;
}
gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
if ((channel & RedChannel) != 0)
- q->red=ClampToQuantum(gamma*GetRedPixelComponent(&pixel));
+ SetRedPixelComponent(q,ClampToQuantum(gamma*pixel.red));
if ((channel & GreenChannel) != 0)
- q->green=ClampToQuantum(gamma*GetGreenPixelComponent(&pixel));
+ SetGreenPixelComponent(q,ClampToQuantum(gamma*pixel.green));
if ((channel & BlueChannel) != 0)
- q->blue=ClampToQuantum(gamma*GetBluePixelComponent(&pixel));
+ SetBluePixelComponent(q,ClampToQuantum(gamma*pixel.blue));
if ((channel & OpacityChannel) != 0)
- SetOpacityPixelComponent(q,ClampOpacityPixelComponent(&pixel));
+ SetOpacityPixelComponent(q,ClampToQuantum(pixel.opacity));
if (((channel & IndexChannel) != 0) &&
(image->colorspace == CMYKColorspace))
- blur_indexes[x]=ClampToQuantum(gamma*GetIndexPixelComponent(&pixel));
+ SetIndexPixelComponent(blur_indexes+x,ClampToQuantum(gamma*
+ pixel.index));
q++;
r++;
}
{
for (u=(-j); u <= j; u++)
{
- kernel[i][k]=(-exp(-((double) u*u+v*v)/(2.0*MagickSigma*MagickSigma))/
- (2.0*MagickPI*MagickSigma*MagickSigma));
+ kernel[i][k]=(double) (-exp(-((double) u*u+v*v)/(2.0*MagickSigma*
+ MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
normalize+=kernel[i][k];
k++;
}
register IndexPacket
*restrict sharp_indexes;
- register ssize_t
- x;
-
register PixelPacket
*restrict q;
+ register ssize_t
+ x;
+
if (status == MagickFalse)
continue;
r=GetCacheViewVirtualPixels(edge_view,0,y,edge_image->columns,1,exception);
i=(ssize_t) width;
if ((i & 0x01) != 0)
i--;
- p=GetCacheViewVirtualPixels(image_view,x-((ssize_t) (width-i)/2L),y-(ssize_t)
- ((width-i)/2L),width-i,width-i,exception);
+ p=GetCacheViewVirtualPixels(image_view,x-((ssize_t) (width-i)/2L),y-
+ (ssize_t) ((width-i)/2L),width-i,width-i,exception);
if (p == (const PixelPacket *) NULL)
break;
indexes=GetCacheViewVirtualIndexQueue(image_view);
pixel.opacity+=(*k)*GetOpacityPixelComponent(p);
if (((channel & IndexChannel) != 0) &&
(image->colorspace == CMYKColorspace))
- pixel.index+=(*k)*alpha*indexes[x+(width-i)*v+u];
+ pixel.index+=(*k)*alpha*GetIndexPixelComponent(indexes+x+(width-i)*
+ v+u);
gamma+=(*k)*alpha;
k++;
p++;
}
gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
if ((channel & RedChannel) != 0)
- q->red=ClampToQuantum(gamma*GetRedPixelComponent(&pixel));
+ SetRedPixelComponent(q,ClampToQuantum(gamma*pixel.red));
if ((channel & GreenChannel) != 0)
- q->green=ClampToQuantum(gamma*GetGreenPixelComponent(&pixel));
+ SetGreenPixelComponent(q,ClampToQuantum(gamma*pixel.green));
if ((channel & BlueChannel) != 0)
- q->blue=ClampToQuantum(gamma*GetBluePixelComponent(&pixel));
+ SetBluePixelComponent(q,ClampToQuantum(gamma*pixel.blue));
if ((channel & OpacityChannel) != 0)
- SetOpacityPixelComponent(q,ClampOpacityPixelComponent(&pixel));
+ SetOpacityPixelComponent(q,ClampToQuantum(pixel.opacity));
if (((channel & IndexChannel) != 0) &&
(image->colorspace == CMYKColorspace))
- sharp_indexes[x]=ClampToQuantum(gamma*GetIndexPixelComponent(&pixel));
+ SetIndexPixelComponent(sharp_indexes+x,ClampToQuantum(gamma*
+ pixel.index));
q++;
r++;
}
*kernel,
normalize;
+ register ssize_t
+ i;
+
ssize_t
j,
k;
- register ssize_t
- i;
-
/*
Generate a 1-D convolution kernel.
*/
i=0;
for (k=(-j); k <= j; k++)
{
- kernel[i]=exp(-((double) k*k)/(2.0*MagickSigma*MagickSigma))/
- (MagickSQ2PI*MagickSigma);
+ kernel[i]=(double) (exp(-((double) k*k)/(2.0*MagickSigma*MagickSigma))/
+ (MagickSQ2PI*MagickSigma));
normalize+=kernel[i];
i++;
}
*k;
(void) LogMagickEvent(TransformEvent,GetMagickModule(),
- " BlurImage with %lu kernel:",(unsigned long) width);
+ " BlurImage with %.20g kernel:",(double) width);
message=AcquireString("");
k=kernel;
for (i=0; i < (ssize_t) width; i++)
{
*message='\0';
- (void) FormatMagickString(format,MaxTextExtent,"%ld: ",(long) i);
+ (void) FormatLocaleString(format,MaxTextExtent,"%.20g: ",(double) i);
(void) ConcatenateString(&message,format);
- (void) FormatMagickString(format,MaxTextExtent,"%g ",*k++);
+ (void) FormatLocaleString(format,MaxTextExtent,"%g ",*k++);
(void) ConcatenateString(&message,format);
(void) LogMagickEvent(TransformEvent,GetMagickModule(),"%s",message);
}
register IndexPacket
*restrict blur_indexes;
- register ssize_t
- x;
-
register PixelPacket
*restrict q;
+ register ssize_t
+ x;
+
if (status == MagickFalse)
continue;
- p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y,image->columns+
- width,1,exception);
+ p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y,
+ image->columns+width,1,exception);
q=GetCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
exception);
if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
{
for (i=0; i < (ssize_t) width; i++)
{
- pixel.red+=(*k)*kernel_pixels->red;
- pixel.green+=(*k)*kernel_pixels->green;
- pixel.blue+=(*k)*kernel_pixels->blue;
+ pixel.red+=(*k)*GetRedPixelComponent(kernel_pixels);
+ pixel.green+=(*k)*GetGreenPixelComponent(kernel_pixels);
+ pixel.blue+=(*k)*GetBluePixelComponent(kernel_pixels);
k++;
kernel_pixels++;
}
if ((channel & RedChannel) != 0)
- SetRedPixelComponent(q,ClampRedPixelComponent(&pixel));
+ SetRedPixelComponent(q,ClampToQuantum(pixel.red));
if ((channel & GreenChannel) != 0)
- SetGreenPixelComponent(q,ClampGreenPixelComponent(&pixel));
+ SetGreenPixelComponent(q,ClampToQuantum(pixel.green));
if ((channel & BlueChannel) != 0)
- SetBluePixelComponent(q,ClampBluePixelComponent(&pixel));
+ SetBluePixelComponent(q,ClampToQuantum(pixel.blue));
if ((channel & OpacityChannel) != 0)
{
k=kernel;
kernel_pixels=p;
for (i=0; i < (ssize_t) width; i++)
{
- pixel.opacity+=(*k)*kernel_pixels->opacity;
+ pixel.opacity+=(*k)*GetOpacityPixelComponent(kernel_pixels);
k++;
kernel_pixels++;
}
- SetOpacityPixelComponent(q,ClampOpacityPixelComponent(&pixel));
+ SetOpacityPixelComponent(q,ClampToQuantum(pixel.opacity));
}
if (((channel & IndexChannel) != 0) &&
(image->colorspace == CMYKColorspace))
kernel_indexes=indexes;
for (i=0; i < (ssize_t) width; i++)
{
- pixel.index+=(*k)*(*kernel_indexes);
+ pixel.index+=(*k)*GetIndexPixelComponent(kernel_indexes);
k++;
kernel_indexes++;
}
- blur_indexes[x]=ClampToQuantum(pixel.index);
+ SetIndexPixelComponent(blur_indexes+x,ClampToQuantum(
+ pixel.index));
}
}
else
{
alpha=(MagickRealType) (QuantumScale*
GetAlphaPixelComponent(kernel_pixels));
- pixel.red+=(*k)*alpha*kernel_pixels->red;
- pixel.green+=(*k)*alpha*kernel_pixels->green;
- pixel.blue+=(*k)*alpha*kernel_pixels->blue;
+ pixel.red+=(*k)*alpha*GetRedPixelComponent(kernel_pixels);
+ pixel.green+=(*k)*alpha*GetGreenPixelComponent(kernel_pixels);
+ pixel.blue+=(*k)*alpha*GetBluePixelComponent(kernel_pixels);
gamma+=(*k)*alpha;
k++;
kernel_pixels++;
}
gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
if ((channel & RedChannel) != 0)
- q->red=ClampToQuantum(gamma*GetRedPixelComponent(&pixel));
+ SetRedPixelComponent(q,ClampToQuantum(gamma*pixel.red));
if ((channel & GreenChannel) != 0)
- q->green=ClampToQuantum(gamma*GetGreenPixelComponent(&pixel));
+ SetGreenPixelComponent(q,ClampToQuantum(gamma*pixel.green));
if ((channel & BlueChannel) != 0)
- q->blue=ClampToQuantum(gamma*GetBluePixelComponent(&pixel));
+ SetBluePixelComponent(q,ClampToQuantum(gamma*pixel.blue));
if ((channel & OpacityChannel) != 0)
{
k=kernel;
kernel_pixels=p;
for (i=0; i < (ssize_t) width; i++)
{
- pixel.opacity+=(*k)*kernel_pixels->opacity;
+ pixel.opacity+=(*k)*GetOpacityPixelComponent(kernel_pixels);
k++;
kernel_pixels++;
}
- SetOpacityPixelComponent(q,ClampOpacityPixelComponent(&pixel));
+ SetOpacityPixelComponent(q,ClampToQuantum(pixel.opacity));
}
if (((channel & IndexChannel) != 0) &&
(image->colorspace == CMYKColorspace))
kernel_pixels++;
kernel_indexes++;
}
- blur_indexes[x]=ClampToQuantum(gamma*
- GetIndexPixelComponent(&pixel));
+ SetIndexPixelComponent(blur_indexes+x,ClampToQuantum(gamma*
+ pixel.index));
}
}
+ indexes++;
p++;
q++;
}
register IndexPacket
*restrict blur_indexes;
- register ssize_t
- y;
-
register PixelPacket
*restrict q;
+ register ssize_t
+ y;
+
if (status == MagickFalse)
continue;
- p=GetCacheViewVirtualPixels(image_view,x,-((ssize_t) width/2L),1,image->rows+
- width,exception);
+ p=GetCacheViewVirtualPixels(image_view,x,-((ssize_t) width/2L),1,
+ image->rows+width,exception);
q=GetCacheViewAuthenticPixels(blur_view,x,0,1,blur_image->rows,exception);
if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
{
{
for (i=0; i < (ssize_t) width; i++)
{
- pixel.red+=(*k)*kernel_pixels->red;
- pixel.green+=(*k)*kernel_pixels->green;
- pixel.blue+=(*k)*kernel_pixels->blue;
+ pixel.red+=(*k)*GetRedPixelComponent(kernel_pixels);
+ pixel.green+=(*k)*GetGreenPixelComponent(kernel_pixels);
+ pixel.blue+=(*k)*GetBluePixelComponent(kernel_pixels);
k++;
kernel_pixels++;
}
if ((channel & RedChannel) != 0)
- SetRedPixelComponent(q,ClampRedPixelComponent(&pixel));
+ SetRedPixelComponent(q,ClampToQuantum(pixel.red));
if ((channel & GreenChannel) != 0)
- SetGreenPixelComponent(q,ClampGreenPixelComponent(&pixel));
+ SetGreenPixelComponent(q,ClampToQuantum(pixel.green));
if ((channel & BlueChannel) != 0)
- SetBluePixelComponent(q,ClampBluePixelComponent(&pixel));
+ SetBluePixelComponent(q,ClampToQuantum(pixel.blue));
if ((channel & OpacityChannel) != 0)
{
k=kernel;
kernel_pixels=p;
for (i=0; i < (ssize_t) width; i++)
{
- pixel.opacity+=(*k)*kernel_pixels->opacity;
+ pixel.opacity+=(*k)*GetOpacityPixelComponent(kernel_pixels);
k++;
kernel_pixels++;
}
- SetOpacityPixelComponent(q,ClampOpacityPixelComponent(&pixel));
+ SetOpacityPixelComponent(q,ClampToQuantum(pixel.opacity));
}
if (((channel & IndexChannel) != 0) &&
(image->colorspace == CMYKColorspace))
kernel_indexes=indexes;
for (i=0; i < (ssize_t) width; i++)
{
- pixel.index+=(*k)*(*kernel_indexes);
+ pixel.index+=(*k)*GetIndexPixelComponent(kernel_indexes);
k++;
kernel_indexes++;
}
- blur_indexes[y]=ClampToQuantum(pixel.index);
+ SetIndexPixelComponent(blur_indexes+y,ClampToQuantum(
+ pixel.index));
}
}
else
{
alpha=(MagickRealType) (QuantumScale*
GetAlphaPixelComponent(kernel_pixels));
- pixel.red+=(*k)*alpha*kernel_pixels->red;
- pixel.green+=(*k)*alpha*kernel_pixels->green;
- pixel.blue+=(*k)*alpha*kernel_pixels->blue;
+ pixel.red+=(*k)*alpha*GetRedPixelComponent(kernel_pixels);
+ pixel.green+=(*k)*alpha*GetGreenPixelComponent(kernel_pixels);
+ pixel.blue+=(*k)*alpha*GetBluePixelComponent(kernel_pixels);
gamma+=(*k)*alpha;
k++;
kernel_pixels++;
}
gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
if ((channel & RedChannel) != 0)
- q->red=ClampToQuantum(gamma*GetRedPixelComponent(&pixel));
+ SetRedPixelComponent(q,ClampToQuantum(gamma*pixel.red));
if ((channel & GreenChannel) != 0)
- q->green=ClampToQuantum(gamma*GetGreenPixelComponent(&pixel));
+ SetGreenPixelComponent(q,ClampToQuantum(gamma*pixel.green));
if ((channel & BlueChannel) != 0)
- q->blue=ClampToQuantum(gamma*GetBluePixelComponent(&pixel));
+ SetBluePixelComponent(q,ClampToQuantum(gamma*pixel.blue));
if ((channel & OpacityChannel) != 0)
{
k=kernel;
kernel_pixels=p;
for (i=0; i < (ssize_t) width; i++)
{
- pixel.opacity+=(*k)*kernel_pixels->opacity;
+ pixel.opacity+=(*k)*GetOpacityPixelComponent(kernel_pixels);
k++;
kernel_pixels++;
}
- SetOpacityPixelComponent(q,ClampOpacityPixelComponent(&pixel));
+ SetOpacityPixelComponent(q,ClampToQuantum(pixel.opacity));
}
if (((channel & IndexChannel) != 0) &&
(image->colorspace == CMYKColorspace))
kernel_pixels++;
kernel_indexes++;
}
- blur_indexes[y]=ClampToQuantum(gamma*
- GetIndexPixelComponent(&pixel));
+ SetIndexPixelComponent(blur_indexes+y,ClampToQuantum(gamma*
+ pixel.index));
}
}
+ indexes++;
p++;
q++;
}
% Image *ConvolveImage(const Image *image,const size_t order,
% const double *kernel,ExceptionInfo *exception)
% Image *ConvolveImageChannel(const Image *image,const ChannelType channel,
-% const size_t order,const double *kernel,
-% ExceptionInfo *exception)
+% const size_t order,const double *kernel,ExceptionInfo *exception)
%
% A description of each parameter follows:
%
format[MaxTextExtent],
*message;
+ register const double
+ *k;
+
ssize_t
u,
v;
- register const double
- *k;
-
(void) LogMagickEvent(TransformEvent,GetMagickModule(),
- " ConvolveImage with %lux%lu kernel:",(unsigned long) width,
- (unsigned long) width);
+ " ConvolveImage with %.20gx%.20g kernel:",(double) width,(double)
+ width);
message=AcquireString("");
k=kernel;
for (v=0; v < (ssize_t) width; v++)
{
*message='\0';
- (void) FormatMagickString(format,MaxTextExtent,"%ld: ",(long) v);
+ (void) FormatLocaleString(format,MaxTextExtent,"%.20g: ",(double) v);
(void) ConcatenateString(&message,format);
for (u=0; u < (ssize_t) width; u++)
{
- (void) FormatMagickString(format,MaxTextExtent,"%g ",*k++);
+ (void) FormatLocaleString(format,MaxTextExtent,"%g ",*k++);
(void) ConcatenateString(&message,format);
}
(void) LogMagickEvent(TransformEvent,GetMagickModule(),"%s",message);
register IndexPacket
*restrict convolve_indexes;
- register ssize_t
- x;
-
register PixelPacket
*restrict q;
+ register ssize_t
+ x;
+
if (status == MagickFalse)
continue;
- p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y-(ssize_t) (width/
- 2L),image->columns+width,width,exception);
+ p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y-(ssize_t)
+ (width/2L),image->columns+width,width,exception);
q=GetCacheViewAuthenticPixels(convolve_view,0,y,convolve_image->columns,1,
exception);
if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
convolve_indexes=GetCacheViewAuthenticIndexQueue(convolve_view);
for (x=0; x < (ssize_t) image->columns; x++)
{
- ssize_t
- v;
-
MagickPixelPacket
pixel;
register ssize_t
u;
+ ssize_t
+ v;
+
pixel=bias;
k=normal_kernel;
kernel_pixels=p;
kernel_pixels+=image->columns+width;
}
if ((channel & RedChannel) != 0)
- SetRedPixelComponent(q,ClampRedPixelComponent(&pixel));
+ SetRedPixelComponent(q,ClampToQuantum(pixel.red));
if ((channel & GreenChannel) != 0)
- SetGreenPixelComponent(q,ClampGreenPixelComponent(&pixel));
+ SetGreenPixelComponent(q,ClampToQuantum(pixel.green));
if ((channel & BlueChannel) != 0)
- SetBluePixelComponent(q,ClampBluePixelComponent(&pixel));
+ SetBluePixelComponent(q,ClampToQuantum(pixel.blue));
if ((channel & OpacityChannel) != 0)
{
k=normal_kernel;
}
kernel_pixels+=image->columns+width;
}
- SetOpacityPixelComponent(q,ClampOpacityPixelComponent(&pixel));
+ SetOpacityPixelComponent(q,ClampToQuantum(pixel.opacity));
}
if (((channel & IndexChannel) != 0) &&
(image->colorspace == CMYKColorspace))
{
for (u=0; u < (ssize_t) width; u++)
{
- pixel.index+=(*k)*kernel_indexes[u];
+ pixel.index+=(*k)*GetIndexPixelComponent(kernel_indexes+u);
k++;
}
kernel_indexes+=image->columns+width;
}
- convolve_indexes[x]=ClampToQuantum(pixel.index);
+ SetIndexPixelComponent(convolve_indexes+x,ClampToQuantum(
+ pixel.index));
}
}
else
}
gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
if ((channel & RedChannel) != 0)
- q->red=ClampToQuantum(gamma*GetRedPixelComponent(&pixel));
+ SetRedPixelComponent(q,ClampToQuantum(gamma*pixel.red));
if ((channel & GreenChannel) != 0)
- q->green=ClampToQuantum(gamma*GetGreenPixelComponent(&pixel));
+ SetGreenPixelComponent(q,ClampToQuantum(gamma*pixel.green));
if ((channel & BlueChannel) != 0)
- q->blue=ClampToQuantum(gamma*GetBluePixelComponent(&pixel));
+ SetBluePixelComponent(q,ClampToQuantum(gamma*pixel.blue));
if ((channel & OpacityChannel) != 0)
{
k=normal_kernel;
{
for (u=0; u < (ssize_t) width; u++)
{
- pixel.opacity+=(*k)*kernel_pixels[u].opacity;
+ pixel.opacity+=(*k)*GetOpacityPixelComponent(kernel_pixels+u);
k++;
}
kernel_pixels+=image->columns+width;
}
- SetOpacityPixelComponent(q,ClampOpacityPixelComponent(&pixel));
+ SetOpacityPixelComponent(q,ClampToQuantum(pixel.opacity));
}
if (((channel & IndexChannel) != 0) &&
(image->colorspace == CMYKColorspace))
{
alpha=(MagickRealType) (QuantumScale*(QuantumRange-
kernel_pixels[u].opacity));
- pixel.index+=(*k)*alpha*kernel_indexes[u];
+ pixel.index+=(*k)*alpha*GetIndexPixelComponent(
+ kernel_indexes+u);
k++;
}
kernel_pixels+=image->columns+width;
kernel_indexes+=image->columns+width;
}
- convolve_indexes[x]=ClampToQuantum(gamma*
- GetIndexPixelComponent(&pixel));
+ SetIndexPixelComponent(convolve_indexes+x,ClampToQuantum(gamma*
+ pixel.index));
}
}
+ indexes++;
p++;
q++;
}
%
*/
-static Quantum **DestroyPixelThreadSet(Quantum **pixels)
-{
- register ssize_t
- i;
-
- assert(pixels != (Quantum **) NULL);
- for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
- if (pixels[i] != (Quantum *) NULL)
- pixels[i]=(Quantum *) RelinquishMagickMemory(pixels[i]);
- pixels=(Quantum **) RelinquishAlignedMemory(pixels);
- return(pixels);
-}
-
-static Quantum **AcquirePixelThreadSet(const size_t count)
-{
- register ssize_t
- i;
-
- Quantum
- **pixels;
-
- size_t
- number_threads;
-
- number_threads=GetOpenMPMaximumThreads();
- pixels=(Quantum **) AcquireAlignedMemory(number_threads,sizeof(*pixels));
- if (pixels == (Quantum **) NULL)
- return((Quantum **) NULL);
- (void) ResetMagickMemory(pixels,0,number_threads*sizeof(*pixels));
- for (i=0; i < (ssize_t) number_threads; i++)
- {
- pixels[i]=(Quantum *) AcquireQuantumMemory(count,sizeof(**pixels));
- if (pixels[i] == (Quantum *) NULL)
- return(DestroyPixelThreadSet(pixels));
- }
- return(pixels);
-}
-
static void Hull(const ssize_t x_offset,const ssize_t y_offset,
const size_t columns,const size_t rows,Quantum *f,Quantum *g,
const int polarity)
{
- ssize_t
- y;
-
MagickRealType
v;
- register ssize_t
- x;
-
register Quantum
*p,
*q,
*r,
*s;
+ register ssize_t
+ x;
+
+ ssize_t
+ y;
+
assert(f != (Quantum *) NULL);
assert(g != (Quantum *) NULL);
p=f+(columns+2);
Image
*despeckle_image;
- ssize_t
- channel;
-
MagickBooleanType
status;
+ register ssize_t
+ i;
+
Quantum
- **restrict buffers,
- **restrict pixels;
+ *restrict buffers,
+ *restrict pixels;
size_t
- length;
+ length,
+ number_channels;
static const ssize_t
X[4] = {0, 1, 1,-1},
Allocate image buffers.
*/
length=(size_t) ((image->columns+2)*(image->rows+2));
- pixels=AcquirePixelThreadSet(length);
- buffers=AcquirePixelThreadSet(length);
- if ((pixels == (Quantum **) NULL) || (buffers == (Quantum **) NULL))
+ pixels=(Quantum *) AcquireQuantumMemory(length,2*sizeof(*pixels));
+ buffers=(Quantum *) AcquireQuantumMemory(length,2*sizeof(*pixels));
+ if ((pixels == (Quantum *) NULL) || (buffers == (Quantum *) NULL))
{
- if (buffers != (Quantum **) NULL)
- buffers=DestroyPixelThreadSet(buffers);
- if (pixels != (Quantum **) NULL)
- pixels=DestroyPixelThreadSet(pixels);
+ if (buffers != (Quantum *) NULL)
+ buffers=(Quantum *) RelinquishMagickMemory(buffers);
+ if (pixels != (Quantum *) NULL)
+ pixels=(Quantum *) RelinquishMagickMemory(pixels);
despeckle_image=DestroyImage(despeckle_image);
ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
}
Reduce speckle in the image.
*/
status=MagickTrue;
+ number_channels=(size_t) (image->colorspace == CMYKColorspace ? 5 : 4);
image_view=AcquireCacheView(image);
despeckle_view=AcquireCacheView(despeckle_image);
-#if defined(MAGICKCORE_OPENMP_SUPPORT)
- #pragma omp parallel for schedule(dynamic,4) shared(status)
-#endif
- for (channel=0; channel <= 3; channel++)
+ for (i=0; i < (ssize_t) number_channels; i++)
{
- ssize_t
- j,
- y;
+ register Quantum
+ *buffer,
+ *pixel;
register ssize_t
- i,
- id,
+ k,
x;
- register Quantum
- *buffer,
- *pixel;
+ ssize_t
+ j,
+ y;
if (status == MagickFalse)
continue;
- id=GetOpenMPThreadId();
- pixel=pixels[id];
+ pixel=pixels;
(void) ResetMagickMemory(pixel,0,length*sizeof(*pixel));
- buffer=buffers[id];
+ buffer=buffers;
j=(ssize_t) image->columns+2;
for (y=0; y < (ssize_t) image->rows; y++)
{
+ register const IndexPacket
+ *restrict indexes;
+
register const PixelPacket
*restrict p;
p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
if (p == (const PixelPacket *) NULL)
break;
+ indexes=GetCacheViewVirtualIndexQueue(image_view);
j++;
for (x=0; x < (ssize_t) image->columns; x++)
{
- switch (channel)
+ switch (i)
{
case 0: pixel[j]=GetRedPixelComponent(p); break;
case 1: pixel[j]=GetGreenPixelComponent(p); break;
case 2: pixel[j]=GetBluePixelComponent(p); break;
case 3: pixel[j]=GetOpacityPixelComponent(p); break;
+ case 4: pixel[j]=GetBlackPixelComponent(indexes+x); break;
default: break;
}
p++;
j++;
}
(void) ResetMagickMemory(buffer,0,length*sizeof(*buffer));
- for (i=0; i < 4; i++)
+ for (k=0; k < 4; k++)
{
- Hull(X[i],Y[i],image->columns,image->rows,pixel,buffer,1);
- Hull(-X[i],-Y[i],image->columns,image->rows,pixel,buffer,1);
- Hull(-X[i],-Y[i],image->columns,image->rows,pixel,buffer,-1);
- Hull(X[i],Y[i],image->columns,image->rows,pixel,buffer,-1);
+ Hull(X[k],Y[k],image->columns,image->rows,pixel,buffer,1);
+ Hull(-X[k],-Y[k],image->columns,image->rows,pixel,buffer,1);
+ Hull(-X[k],-Y[k],image->columns,image->rows,pixel,buffer,-1);
+ Hull(X[k],Y[k],image->columns,image->rows,pixel,buffer,-1);
}
j=(ssize_t) image->columns+2;
for (y=0; y < (ssize_t) image->rows; y++)
MagickBooleanType
sync;
+ register IndexPacket
+ *restrict indexes;
+
register PixelPacket
*restrict q;
1,exception);
if (q == (PixelPacket *) NULL)
break;
+ indexes=GetCacheViewAuthenticIndexQueue(image_view);
j++;
for (x=0; x < (ssize_t) image->columns; x++)
{
- switch (channel)
+ switch (i)
{
- case 0: q->red=pixel[j]; break;
- case 1: q->green=pixel[j]; break;
- case 2: q->blue=pixel[j]; break;
- case 3: q->opacity=pixel[j]; break;
+ case 0: SetRedPixelComponent(q,pixel[j]); break;
+ case 1: SetGreenPixelComponent(q,pixel[j]); break;
+ case 2: SetBluePixelComponent(q,pixel[j]); break;
+ case 3: SetOpacityPixelComponent(q,pixel[j]); break;
+ case 4: SetIndexPixelComponent(indexes+x,pixel[j]); break;
default: break;
}
q++;
MagickBooleanType
proceed;
-#if defined(MAGICKCORE_OPENMP_SUPPORT)
- #pragma omp critical (MagickCore_DespeckleImage)
-#endif
- proceed=SetImageProgress(image,DespeckleImageTag,(MagickOffsetType)
- channel,3);
+ proceed=SetImageProgress(image,DespeckleImageTag,(MagickOffsetType) i,
+ number_channels);
if (proceed == MagickFalse)
status=MagickFalse;
}
}
despeckle_view=DestroyCacheView(despeckle_view);
image_view=DestroyCacheView(image_view);
- buffers=DestroyPixelThreadSet(buffers);
- pixels=DestroyPixelThreadSet(pixels);
+ buffers=(Quantum *) RelinquishMagickMemory(buffers);
+ pixels=(Quantum *) RelinquishMagickMemory(pixels);
despeckle_image->type=image->type;
if (status == MagickFalse)
despeckle_image=DestroyImage(despeckle_image);
Image
*emboss_image;
- ssize_t
- j,
- k,
- u,
- v;
-
register ssize_t
i;
size_t
width;
+ ssize_t
+ j,
+ k,
+ u,
+ v;
+
assert(image != (Image *) NULL);
assert(image->signature == MagickSignature);
if (image->debug != MagickFalse)
{
for (u=(-j); u <= j; u++)
{
- kernel[i]=((u < 0) || (v < 0) ? -8.0 : 8.0)*
+ kernel[i]=(double) (((u < 0) || (v < 0) ? -8.0 : 8.0)*
exp(-((double) u*u+v*v)/(2.0*MagickSigma*MagickSigma))/
- (2.0*MagickPI*MagickSigma*MagickSigma);
+ (2.0*MagickPI*MagickSigma*MagickSigma));
if (u != k)
kernel[i]=0.0;
i++;
format[MaxTextExtent],
*message;
+ register const double
+ *k;
+
ssize_t
u,
v;
- register const double
- *k;
-
(void) LogMagickEvent(TransformEvent,GetMagickModule(),
- " FilterImage with %ldx%ld kernel:",(unsigned long) kernel->width,
- (unsigned long) kernel->height);
+ " FilterImage with %.20gx%.20g kernel:",(double) kernel->width,(double)
+ kernel->height);
message=AcquireString("");
k=kernel->values;
for (v=0; v < (ssize_t) kernel->height; v++)
{
*message='\0';
- (void) FormatMagickString(format,MaxTextExtent,"%ld: ",(long) v);
+ (void) FormatLocaleString(format,MaxTextExtent,"%.20g: ",(double) v);
(void) ConcatenateString(&message,format);
for (u=0; u < (ssize_t) kernel->width; u++)
{
- (void) FormatMagickString(format,MaxTextExtent,"%g ",*k++);
+ (void) FormatLocaleString(format,MaxTextExtent,"%g ",*k++);
(void) ConcatenateString(&message,format);
}
(void) LogMagickEvent(TransformEvent,GetMagickModule(),"%s",message);
register IndexPacket
*restrict filter_indexes;
- register ssize_t
- x;
-
register PixelPacket
*restrict q;
+ register ssize_t
+ x;
+
if (status == MagickFalse)
continue;
p=GetCacheViewVirtualPixels(image_view,-((ssize_t) kernel->width/2L),
- y-(ssize_t) (kernel->height/2L),image->columns+kernel->width,kernel->height,
- exception);
+ y-(ssize_t) (kernel->height/2L),image->columns+kernel->width,
+ kernel->height,exception);
q=GetCacheViewAuthenticPixels(filter_view,0,y,filter_image->columns,1,
exception);
if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
filter_indexes=GetCacheViewAuthenticIndexQueue(filter_view);
for (x=0; x < (ssize_t) image->columns; x++)
{
- ssize_t
- v;
-
MagickPixelPacket
pixel;
register ssize_t
u;
+ ssize_t
+ v;
+
pixel=bias;
k=kernel->values;
kernel_pixels=p;
kernel_pixels+=image->columns+kernel->width;
}
if ((channel & RedChannel) != 0)
- SetRedPixelComponent(q,ClampRedPixelComponent(&pixel));
+ SetRedPixelComponent(q,ClampToQuantum(pixel.red));
if ((channel & GreenChannel) != 0)
- SetGreenPixelComponent(q,ClampGreenPixelComponent(&pixel));
+ SetGreenPixelComponent(q,ClampToQuantum(pixel.green));
if ((channel & BlueChannel) != 0)
- SetBluePixelComponent(q,ClampBluePixelComponent(&pixel));
+ SetBluePixelComponent(q,ClampToQuantum(pixel.blue));
if ((channel & OpacityChannel) != 0)
{
k=kernel->values;
}
kernel_pixels+=image->columns+kernel->width;
}
- SetOpacityPixelComponent(q,ClampOpacityPixelComponent(&pixel));
+ SetOpacityPixelComponent(q,ClampToQuantum(pixel.opacity));
}
if (((channel & IndexChannel) != 0) &&
(image->colorspace == CMYKColorspace))
{
for (u=0; u < (ssize_t) kernel->height; u++)
{
- pixel.index+=(*k)*kernel_indexes[u];
+ pixel.index+=(*k)*GetIndexPixelComponent(kernel_indexes+u);
k++;
}
kernel_indexes+=image->columns+kernel->width;
}
- filter_indexes[x]=ClampToQuantum(pixel.index);
+ SetIndexPixelComponent(filter_indexes+x,ClampToQuantum(
+ pixel.index));
}
}
else
for (u=0; u < (ssize_t) kernel->height; u++)
{
alpha=(MagickRealType) (QuantumScale*(QuantumRange-
- kernel_pixels[u].opacity));
- pixel.red+=(*k)*alpha*kernel_pixels[u].red;
- pixel.green+=(*k)*alpha*kernel_pixels[u].green;
- pixel.blue+=(*k)*alpha*kernel_pixels[u].blue;
+ GetOpacityPixelComponent(kernel_pixels+u)));
+ pixel.red+=(*k)*alpha*GetRedPixelComponent(kernel_pixels+u);
+ pixel.green+=(*k)*alpha*GetGreenPixelComponent(kernel_pixels+u);
+ pixel.blue+=(*k)*alpha*GetBluePixelComponent(kernel_pixels+u);
gamma+=(*k)*alpha;
k++;
}
}
gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
if ((channel & RedChannel) != 0)
- q->red=ClampToQuantum(gamma*GetRedPixelComponent(&pixel));
+ SetRedPixelComponent(q,ClampToQuantum(gamma*pixel.red));
if ((channel & GreenChannel) != 0)
- q->green=ClampToQuantum(gamma*GetGreenPixelComponent(&pixel));
+ SetGreenPixelComponent(q,ClampToQuantum(gamma*pixel.green));
if ((channel & BlueChannel) != 0)
- q->blue=ClampToQuantum(gamma*GetBluePixelComponent(&pixel));
+ SetBluePixelComponent(q,ClampToQuantum(gamma*pixel.blue));
if ((channel & OpacityChannel) != 0)
{
k=kernel->values;
{
for (u=0; u < (ssize_t) kernel->height; u++)
{
- pixel.opacity+=(*k)*kernel_pixels[u].opacity;
+ pixel.opacity+=(*k)*GetOpacityPixelComponent(kernel_pixels+u);
k++;
}
kernel_pixels+=image->columns+kernel->width;
}
- SetOpacityPixelComponent(q,ClampOpacityPixelComponent(&pixel));
+ SetOpacityPixelComponent(q,ClampToQuantum(pixel.opacity));
}
if (((channel & IndexChannel) != 0) &&
(image->colorspace == CMYKColorspace))
{
alpha=(MagickRealType) (QuantumScale*(QuantumRange-
kernel_pixels[u].opacity));
- pixel.index+=(*k)*alpha*kernel_indexes[u];
+ pixel.index+=(*k)*alpha*GetIndexPixelComponent(
+ kernel_indexes+u);
k++;
}
kernel_pixels+=image->columns+kernel->width;
kernel_indexes+=image->columns+kernel->width;
}
- filter_indexes[x]=ClampToQuantum(gamma*
- GetIndexPixelComponent(&pixel));
+ SetIndexPixelComponent(filter_indexes+x,ClampToQuantum(gamma*
+ pixel.index));
}
}
+ indexes++;
p++;
q++;
}
Image
*blur_image;
- ssize_t
- j,
- u,
- v;
-
register ssize_t
i;
size_t
width;
+ ssize_t
+ j,
+ u,
+ v;
+
assert(image != (const Image *) NULL);
assert(image->signature == MagickSignature);
if (image->debug != MagickFalse)
for (v=(-j); v <= j; v++)
{
for (u=(-j); u <= j; u++)
- kernel[i++]=exp(-((double) u*u+v*v)/(2.0*MagickSigma*MagickSigma))/
- (2.0*MagickPI*MagickSigma*MagickSigma);
+ kernel[i++]=(double) (exp(-((double) u*u+v*v)/(2.0*MagickSigma*
+ MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
}
blur_image=ConvolveImageChannel(image,channel,width,kernel,exception);
kernel=(double *) RelinquishMagickMemory(kernel);
% %
% %
% %
-% M e d i a n F i l t e r I m a g e %
+% M o t i o n B l u r I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
-% MedianFilterImage() applies a digital filter that improves the quality
-% of a noisy image. Each pixel is replaced by the median in a set of
-% neighboring pixels as defined by radius.
+% MotionBlurImage() simulates motion blur. We convolve the image with a
+% Gaussian operator of the given radius and standard deviation (sigma).
+% For reasonable results, radius should be larger than sigma. Use a
+% radius of 0 and MotionBlurImage() selects a suitable radius for you.
+% Angle gives the angle of the blurring motion.
%
-% The algorithm was contributed by Mike Edmonds and implements an insertion
-% sort for selecting median color-channel values. For more on this algorithm
-% see "Skip Lists: A probabilistic Alternative to Balanced Trees" by William
-% Pugh in the June 1990 of Communications of the ACM.
+% Andrew Protano contributed this effect.
%
-% The format of the MedianFilterImage method is:
+% The format of the MotionBlurImage method is:
%
-% Image *MedianFilterImage(const Image *image,const double radius,
-% ExceptionInfo *exception)
+% Image *MotionBlurImage(const Image *image,const double radius,
+% const double sigma,const double angle,ExceptionInfo *exception)
+% Image *MotionBlurImageChannel(const Image *image,const ChannelType channel,
+% const double radius,const double sigma,const double angle,
+% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o image: the image.
%
-% o radius: the radius of the pixel neighborhood.
+% o channel: the channel type.
+%
+% o radius: the radius of the Gaussian, in pixels, not counting the center
+% o radius: the radius of the Gaussian, in pixels, not counting
+% the center pixel.
+%
+% o sigma: the standard deviation of the Gaussian, in pixels.
+%
+% o angle: Apply the effect along this angle.
%
% o exception: return any errors or warnings in this structure.
%
*/
-#define MedianListChannels 5
-
-typedef struct _MedianListNode
-{
- size_t
- next[9],
- count,
- signature;
-} MedianListNode;
-
-typedef struct _MedianSkipList
-{
- ssize_t
- level;
-
- MedianListNode
- *nodes;
-} MedianSkipList;
-
-typedef struct _MedianPixelList
+static double *GetMotionBlurKernel(const size_t width,const double sigma)
{
- size_t
- center,
- seed,
- signature;
-
- MedianSkipList
- lists[MedianListChannels];
-} MedianPixelList;
+ double
+ *kernel,
+ normalize;
-static MedianPixelList *DestroyMedianPixelList(MedianPixelList *pixel_list)
-{
register ssize_t
i;
- if (pixel_list == (MedianPixelList *) NULL)
- return((MedianPixelList *) NULL);
- for (i=0; i < MedianListChannels; i++)
- if (pixel_list->lists[i].nodes != (MedianListNode *) NULL)
- pixel_list->lists[i].nodes=(MedianListNode *) RelinquishMagickMemory(
- pixel_list->lists[i].nodes);
- pixel_list=(MedianPixelList *) RelinquishAlignedMemory(pixel_list);
- return(pixel_list);
+ /*
+ Generate a 1-D convolution kernel.
+ */
+ (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+ kernel=(double *) AcquireQuantumMemory((size_t) width,sizeof(*kernel));
+ if (kernel == (double *) NULL)
+ return(kernel);
+ normalize=0.0;
+ for (i=0; i < (ssize_t) width; i++)
+ {
+ kernel[i]=(double) (exp((-((double) i*i)/(double) (2.0*MagickSigma*
+ MagickSigma)))/(MagickSQ2PI*MagickSigma));
+ normalize+=kernel[i];
+ }
+ for (i=0; i < (ssize_t) width; i++)
+ kernel[i]/=normalize;
+ return(kernel);
}
-static MedianPixelList **DestroyMedianPixelListThreadSet(
- MedianPixelList **pixel_list)
+MagickExport Image *MotionBlurImage(const Image *image,const double radius,
+ const double sigma,const double angle,ExceptionInfo *exception)
{
- register ssize_t
- i;
+ Image
+ *motion_blur;
- assert(pixel_list != (MedianPixelList **) NULL);
- for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
- if (pixel_list[i] != (MedianPixelList *) NULL)
- pixel_list[i]=DestroyMedianPixelList(pixel_list[i]);
- pixel_list=(MedianPixelList **) RelinquishAlignedMemory(pixel_list);
- return(pixel_list);
+ motion_blur=MotionBlurImageChannel(image,DefaultChannels,radius,sigma,angle,
+ exception);
+ return(motion_blur);
}
-static MedianPixelList *AcquireMedianPixelList(const size_t width)
+MagickExport Image *MotionBlurImageChannel(const Image *image,
+ const ChannelType channel,const double radius,const double sigma,
+ const double angle,ExceptionInfo *exception)
{
- MedianPixelList
- *pixel_list;
+ CacheView
+ *blur_view,
+ *image_view;
- register ssize_t
- i;
+ double
+ *kernel;
- pixel_list=(MedianPixelList *) AcquireAlignedMemory(1,sizeof(*pixel_list));
- if (pixel_list == (MedianPixelList *) NULL)
- return(pixel_list);
- (void) ResetMagickMemory((void *) pixel_list,0,sizeof(*pixel_list));
- pixel_list->center=width*width/2;
- for (i=0; i < MedianListChannels; i++)
- {
- pixel_list->lists[i].nodes=(MedianListNode *) AcquireQuantumMemory(65537UL,
- sizeof(*pixel_list->lists[i].nodes));
- if (pixel_list->lists[i].nodes == (MedianListNode *) NULL)
- return(DestroyMedianPixelList(pixel_list));
- (void) ResetMagickMemory(pixel_list->lists[i].nodes,0,65537UL*
- sizeof(*pixel_list->lists[i].nodes));
- }
- pixel_list->signature=MagickSignature;
- return(pixel_list);
-}
+ Image
+ *blur_image;
-static MedianPixelList **AcquireMedianPixelListThreadSet(
- const size_t width)
-{
- register ssize_t
- i;
-
- MedianPixelList
- **pixel_list;
-
- size_t
- number_threads;
-
- number_threads=GetOpenMPMaximumThreads();
- pixel_list=(MedianPixelList **) AcquireAlignedMemory(number_threads,
- sizeof(*pixel_list));
- if (pixel_list == (MedianPixelList **) NULL)
- return((MedianPixelList **) NULL);
- (void) ResetMagickMemory(pixel_list,0,number_threads*sizeof(*pixel_list));
- for (i=0; i < (ssize_t) number_threads; i++)
- {
- pixel_list[i]=AcquireMedianPixelList(width);
- if (pixel_list[i] == (MedianPixelList *) NULL)
- return(DestroyMedianPixelListThreadSet(pixel_list));
- }
- return(pixel_list);
-}
-
-static void AddNodeMedianPixelList(MedianPixelList *pixel_list,
- const ssize_t channel,const size_t color)
-{
- register ssize_t
- level;
-
- register MedianSkipList
- *list;
-
- size_t
- search,
- update[9];
+ MagickBooleanType
+ status;
- /*
- Initialize the node.
- */
- list=pixel_list->lists+channel;
- list->nodes[color].signature=pixel_list->signature;
- list->nodes[color].count=1;
- /*
- Determine where it bessize_ts in the list.
- */
- search=65536UL;
- for (level=list->level; level >= 0; level--)
- {
- while (list->nodes[search].next[level] < color)
- search=list->nodes[search].next[level];
- update[level]=search;
- }
- /*
- Generate a pseudo-random level for this node.
- */
- for (level=0; ; level++)
- {
- pixel_list->seed=(pixel_list->seed*42893621L)+1L;
- if ((pixel_list->seed & 0x300) != 0x300)
- break;
- }
- if (level > 8)
- level=8;
- if (level > (list->level+2))
- level=list->level+2;
- /*
- If we're raising the list's level, link back to the root node.
- */
- while (level > list->level)
- {
- list->level++;
- update[list->level]=65536UL;
- }
- /*
- Link the node into the skip-list.
- */
- do
- {
- list->nodes[color].next[level]=list->nodes[update[level]].next[level];
- list->nodes[update[level]].next[level]=color;
- }
- while (level-- > 0);
-}
+ MagickOffsetType
+ progress;
-static MagickPixelPacket GetMedianPixelList(MedianPixelList *pixel_list)
-{
MagickPixelPacket
- pixel;
-
- register ssize_t
- channel;
-
- register MedianSkipList
- *list;
-
- size_t
- center,
- color,
- count;
-
- unsigned short
- channels[MedianListChannels];
-
- /*
- Find the median value for each of the color.
- */
- center=pixel_list->center;
- for (channel=0; channel < 5; channel++)
- {
- list=pixel_list->lists+channel;
- color=65536UL;
- count=0;
- do
- {
- color=list->nodes[color].next[0];
- count+=list->nodes[color].count;
- }
- while (count <= center);
- channels[channel]=(unsigned short) color;
- }
- GetMagickPixelPacket((const Image *) NULL,&pixel);
- pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
- pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
- pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
- pixel.opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
- pixel.index=(MagickRealType) ScaleShortToQuantum(channels[4]);
- return(pixel);
-}
-
-static inline void InsertMedianPixelList(const Image *image,
- const PixelPacket *pixel,const IndexPacket *indexes,
- MedianPixelList *pixel_list)
-{
- size_t
- signature;
-
- unsigned short
- index;
+ bias;
- index=ScaleQuantumToShort(pixel->red);
- signature=pixel_list->lists[0].nodes[index].signature;
- if (signature == pixel_list->signature)
- pixel_list->lists[0].nodes[index].count++;
- else
- AddNodeMedianPixelList(pixel_list,0,index);
- index=ScaleQuantumToShort(pixel->green);
- signature=pixel_list->lists[1].nodes[index].signature;
- if (signature == pixel_list->signature)
- pixel_list->lists[1].nodes[index].count++;
- else
- AddNodeMedianPixelList(pixel_list,1,index);
- index=ScaleQuantumToShort(pixel->blue);
- signature=pixel_list->lists[2].nodes[index].signature;
- if (signature == pixel_list->signature)
- pixel_list->lists[2].nodes[index].count++;
- else
- AddNodeMedianPixelList(pixel_list,2,index);
- index=ScaleQuantumToShort(pixel->opacity);
- signature=pixel_list->lists[3].nodes[index].signature;
- if (signature == pixel_list->signature)
- pixel_list->lists[3].nodes[index].count++;
- else
- AddNodeMedianPixelList(pixel_list,3,index);
- if (image->colorspace == CMYKColorspace)
- index=ScaleQuantumToShort(*indexes);
- signature=pixel_list->lists[4].nodes[index].signature;
- if (signature == pixel_list->signature)
- pixel_list->lists[4].nodes[index].count++;
- else
- AddNodeMedianPixelList(pixel_list,4,index);
-}
+ OffsetInfo
+ *offset;
-static void ResetMedianPixelList(MedianPixelList *pixel_list)
-{
- int
- level;
+ PointInfo
+ point;
register ssize_t
- channel;
-
- register MedianListNode
- *root;
-
- register MedianSkipList
- *list;
-
- /*
- Reset the skip-list.
- */
- for (channel=0; channel < 5; channel++)
- {
- list=pixel_list->lists+channel;
- root=list->nodes+65536UL;
- list->level=0;
- for (level=0; level < 9; level++)
- root->next[level]=65536UL;
- }
- pixel_list->seed=pixel_list->signature++;
-}
-
-MagickExport Image *MedianFilterImage(const Image *image,const double radius,
- ExceptionInfo *exception)
-{
-#define MedianFilterImageTag "MedianFilter/Image"
-
- CacheView
- *image_view,
- *median_view;
-
- Image
- *median_image;
-
- MagickBooleanType
- status;
-
- MagickOffsetType
- progress;
-
- MedianPixelList
- **restrict pixel_list;
+ i;
size_t
width;
ssize_t
y;
- /*
- Initialize median 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);
- width=GetOptimalKernelWidth2D(radius,0.5);
- if ((image->columns < width) || (image->rows < width))
- ThrowImageException(OptionError,"ImageSmallerThanKernelRadius");
- median_image=CloneImage(image,image->columns,image->rows,MagickTrue,
- exception);
- if (median_image == (Image *) NULL)
- return((Image *) NULL);
- if (SetImageStorageClass(median_image,DirectClass) == MagickFalse)
+ width=GetOptimalKernelWidth1D(radius,sigma);
+ kernel=GetMotionBlurKernel(width,sigma);
+ if (kernel == (double *) NULL)
+ ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+ offset=(OffsetInfo *) AcquireQuantumMemory(width,sizeof(*offset));
+ if (offset == (OffsetInfo *) NULL)
+ {
+ kernel=(double *) RelinquishMagickMemory(kernel);
+ ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+ }
+ blur_image=CloneImage(image,0,0,MagickTrue,exception);
+ if (blur_image == (Image *) NULL)
{
- InheritException(exception,&median_image->exception);
- median_image=DestroyImage(median_image);
+ kernel=(double *) RelinquishMagickMemory(kernel);
+ offset=(OffsetInfo *) RelinquishMagickMemory(offset);
return((Image *) NULL);
}
- pixel_list=AcquireMedianPixelListThreadSet(width);
- if (pixel_list == (MedianPixelList **) NULL)
+ if (SetImageStorageClass(blur_image,DirectClass) == MagickFalse)
{
- median_image=DestroyImage(median_image);
- ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+ kernel=(double *) RelinquishMagickMemory(kernel);
+ offset=(OffsetInfo *) RelinquishMagickMemory(offset);
+ InheritException(exception,&blur_image->exception);
+ blur_image=DestroyImage(blur_image);
+ return((Image *) NULL);
}
+ point.x=(double) width*sin(DegreesToRadians(angle));
+ point.y=(double) width*cos(DegreesToRadians(angle));
+ for (i=0; i < (ssize_t) width; i++)
+ {
+ offset[i].x=(ssize_t) ceil((double) (i*point.y)/hypot(point.x,point.y)-0.5);
+ offset[i].y=(ssize_t) ceil((double) (i*point.x)/hypot(point.x,point.y)-0.5);
+ }
/*
- Median filter each image row.
+ Motion blur image.
*/
status=MagickTrue;
progress=0;
+ GetMagickPixelPacket(image,&bias);
image_view=AcquireCacheView(image);
- median_view=AcquireCacheView(median_image);
+ blur_view=AcquireCacheView(blur_image);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
- #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+ #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
#endif
- for (y=0; y < (ssize_t) median_image->rows; y++)
+ for (y=0; y < (ssize_t) image->rows; y++)
{
- register const IndexPacket
- *restrict indexes;
-
- register const PixelPacket
- *restrict p;
-
register IndexPacket
- *restrict median_indexes;
-
- register ssize_t
- id,
- x;
+ *restrict blur_indexes;
register PixelPacket
*restrict q;
+ register ssize_t
+ x;
+
if (status == MagickFalse)
continue;
- p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y-(ssize_t) (width/
- 2L),image->columns+width,width,exception);
- q=QueueCacheViewAuthenticPixels(median_view,0,y,median_image->columns,1,
+ q=GetCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
exception);
- if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+ if (q == (PixelPacket *) NULL)
{
status=MagickFalse;
continue;
}
- indexes=GetCacheViewVirtualIndexQueue(image_view);
- median_indexes=GetCacheViewAuthenticIndexQueue(median_view);
- id=GetOpenMPThreadId();
- for (x=0; x < (ssize_t) median_image->columns; x++)
+ blur_indexes=GetCacheViewAuthenticIndexQueue(blur_view);
+ for (x=0; x < (ssize_t) image->columns; x++)
{
MagickPixelPacket
- pixel;
+ qixel;
- register const PixelPacket
- *restrict r;
+ PixelPacket
+ pixel;
register const IndexPacket
- *restrict s;
+ *restrict indexes;
- register ssize_t
- u,
- v;
-
- r=p;
- s=indexes+x;
- ResetMedianPixelList(pixel_list[id]);
- for (v=0; v < (ssize_t) width; v++)
- {
- for (u=0; u < (ssize_t) width; u++)
- InsertMedianPixelList(image,r+u,s+u,pixel_list[id]);
- r+=image->columns+width;
- s+=image->columns+width;
- }
- pixel=GetMedianPixelList(pixel_list[id]);
- SetPixelPacket(median_image,&pixel,q,median_indexes+x);
- p++;
- q++;
- }
- if (SyncCacheViewAuthenticPixels(median_view,exception) == MagickFalse)
- status=MagickFalse;
- if (image->progress_monitor != (MagickProgressMonitor) NULL)
- {
- MagickBooleanType
- proceed;
-
-#if defined(MAGICKCORE_OPENMP_SUPPORT)
- #pragma omp critical (MagickCore_MedianFilterImage)
-#endif
- proceed=SetImageProgress(image,MedianFilterImageTag,progress++,
- image->rows);
- if (proceed == MagickFalse)
- status=MagickFalse;
- }
- }
- median_view=DestroyCacheView(median_view);
- image_view=DestroyCacheView(image_view);
- pixel_list=DestroyMedianPixelListThreadSet(pixel_list);
- return(median_image);
-}
-\f
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% %
-% %
-% %
-% M o t i o n B l u r I m a g e %
-% %
-% %
-% %
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%
-% MotionBlurImage() simulates motion blur. We convolve the image with a
-% Gaussian operator of the given radius and standard deviation (sigma).
-% For reasonable results, radius should be larger than sigma. Use a
-% radius of 0 and MotionBlurImage() selects a suitable radius for you.
-% Angle gives the angle of the blurring motion.
-%
-% Andrew Protano contributed this effect.
-%
-% The format of the MotionBlurImage method is:
-%
-% Image *MotionBlurImage(const Image *image,const double radius,
-% const double sigma,const double angle,ExceptionInfo *exception)
-% Image *MotionBlurImageChannel(const Image *image,const ChannelType channel,
-% const double radius,const double sigma,const double angle,
-% ExceptionInfo *exception)
-%
-% A description of each parameter follows:
-%
-% o image: the image.
-%
-% o channel: the channel type.
-%
-% o radius: the radius of the Gaussian, in pixels, not counting the center
-% o radius: the radius of the Gaussian, in pixels, not counting
-% the center pixel.
-%
-% o sigma: the standard deviation of the Gaussian, in pixels.
-%
-% o angle: Apply the effect along this angle.
-%
-% o exception: return any errors or warnings in this structure.
-%
-*/
-
-static double *GetMotionBlurKernel(const size_t width,const double sigma)
-{
- double
- *kernel,
- normalize;
-
- register ssize_t
- i;
-
- /*
- Generate a 1-D convolution kernel.
- */
- (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
- kernel=(double *) AcquireQuantumMemory((size_t) width,sizeof(*kernel));
- if (kernel == (double *) NULL)
- return(kernel);
- normalize=0.0;
- for (i=0; i < (ssize_t) width; i++)
- {
- kernel[i]=exp((-((double) i*i)/(double) (2.0*MagickSigma*MagickSigma)))/
- (MagickSQ2PI*MagickSigma);
- normalize+=kernel[i];
- }
- for (i=0; i < (ssize_t) width; i++)
- kernel[i]/=normalize;
- return(kernel);
-}
-
-MagickExport Image *MotionBlurImage(const Image *image,const double radius,
- const double sigma,const double angle,ExceptionInfo *exception)
-{
- Image
- *motion_blur;
-
- motion_blur=MotionBlurImageChannel(image,DefaultChannels,radius,sigma,angle,
- exception);
- return(motion_blur);
-}
-
-MagickExport Image *MotionBlurImageChannel(const Image *image,
- const ChannelType channel,const double radius,const double sigma,
- const double angle,ExceptionInfo *exception)
-{
- CacheView
- *blur_view,
- *image_view;
-
- double
- *kernel;
-
- Image
- *blur_image;
-
- MagickBooleanType
- status;
-
- MagickOffsetType
- progress;
-
- MagickPixelPacket
- bias;
-
- OffsetInfo
- *offset;
-
- PointInfo
- point;
-
- register ssize_t
- i;
-
- size_t
- width;
-
- ssize_t
- y;
-
- assert(image != (Image *) NULL);
- assert(image->signature == MagickSignature);
- if (image->debug != MagickFalse)
- (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
- assert(exception != (ExceptionInfo *) NULL);
- width=GetOptimalKernelWidth1D(radius,sigma);
- kernel=GetMotionBlurKernel(width,sigma);
- if (kernel == (double *) NULL)
- ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
- offset=(OffsetInfo *) AcquireQuantumMemory(width,sizeof(*offset));
- if (offset == (OffsetInfo *) NULL)
- {
- kernel=(double *) RelinquishMagickMemory(kernel);
- ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
- }
- blur_image=CloneImage(image,0,0,MagickTrue,exception);
- if (blur_image == (Image *) NULL)
- {
- kernel=(double *) RelinquishMagickMemory(kernel);
- offset=(OffsetInfo *) RelinquishMagickMemory(offset);
- return((Image *) NULL);
- }
- if (SetImageStorageClass(blur_image,DirectClass) == MagickFalse)
- {
- kernel=(double *) RelinquishMagickMemory(kernel);
- offset=(OffsetInfo *) RelinquishMagickMemory(offset);
- InheritException(exception,&blur_image->exception);
- blur_image=DestroyImage(blur_image);
- return((Image *) NULL);
- }
- point.x=(double) width*sin(DegreesToRadians(angle));
- point.y=(double) width*cos(DegreesToRadians(angle));
- for (i=0; i < (ssize_t) width; i++)
- {
- offset[i].x=(ssize_t) ceil((double) (i*point.y)/hypot(point.x,point.y)-0.5);
- offset[i].y=(ssize_t) ceil((double) (i*point.x)/hypot(point.x,point.y)-0.5);
- }
- /*
- Motion blur image.
- */
- status=MagickTrue;
- progress=0;
- GetMagickPixelPacket(image,&bias);
- image_view=AcquireCacheView(image);
- blur_view=AcquireCacheView(blur_image);
-#if defined(MAGICKCORE_OPENMP_SUPPORT) && defined(MAGICKCORE_FUTURE)
- #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
-#endif
- for (y=0; y < (ssize_t) image->rows; y++)
- {
- register IndexPacket
- *restrict blur_indexes;
-
- register ssize_t
- x;
-
- register PixelPacket
- *restrict q;
-
- if (status == MagickFalse)
- continue;
- q=GetCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
- exception);
- if (q == (PixelPacket *) NULL)
- {
- status=MagickFalse;
- continue;
- }
- blur_indexes=GetCacheViewAuthenticIndexQueue(blur_view);
- for (x=0; x < (ssize_t) image->columns; x++)
- {
- MagickPixelPacket
- qixel;
-
- PixelPacket
- pixel;
-
- register double
- *restrict k;
+ register double
+ *restrict k;
register ssize_t
i;
- register const IndexPacket
- *restrict indexes;
-
k=kernel;
qixel=bias;
if (((channel & OpacityChannel) == 0) || (image->matte == MagickFalse))
k++;
}
if ((channel & RedChannel) != 0)
- q->red=ClampToQuantum(qixel.red);
+ SetRedPixelComponent(q,ClampToQuantum(qixel.red));
if ((channel & GreenChannel) != 0)
- q->green=ClampToQuantum(qixel.green);
+ SetGreenPixelComponent(q,ClampToQuantum(qixel.green));
if ((channel & BlueChannel) != 0)
- q->blue=ClampToQuantum(qixel.blue);
+ SetBluePixelComponent(q,ClampToQuantum(qixel.blue));
if ((channel & OpacityChannel) != 0)
- q->opacity=ClampToQuantum(qixel.opacity);
+ SetOpacityPixelComponent(q,ClampToQuantum(qixel.opacity));
if (((channel & IndexChannel) != 0) &&
(image->colorspace == CMYKColorspace))
- blur_indexes[x]=(IndexPacket) ClampToQuantum(qixel.index);
+ SetIndexPixelComponent(blur_indexes+x,ClampToQuantum(qixel.index));
}
else
{
if (image->colorspace == CMYKColorspace)
{
indexes=GetCacheViewVirtualIndexQueue(image_view);
- qixel.index+=(*k)*alpha*(*indexes);
+ qixel.index+=(*k)*alpha*GetIndexPixelComponent(indexes);
}
gamma+=(*k)*alpha;
k++;
}
gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
if ((channel & RedChannel) != 0)
- q->red=ClampToQuantum(gamma*qixel.red);
+ SetRedPixelComponent(q,ClampToQuantum(gamma*qixel.red));
if ((channel & GreenChannel) != 0)
- q->green=ClampToQuantum(gamma*qixel.green);
+ SetGreenPixelComponent(q,ClampToQuantum(gamma*qixel.green));
if ((channel & BlueChannel) != 0)
- q->blue=ClampToQuantum(gamma*qixel.blue);
+ SetBluePixelComponent(q,ClampToQuantum(gamma*qixel.blue));
if ((channel & OpacityChannel) != 0)
- q->opacity=ClampToQuantum(qixel.opacity);
+ SetOpacityPixelComponent(q,ClampToQuantum(qixel.opacity));
if (((channel & IndexChannel) != 0) &&
(image->colorspace == CMYKColorspace))
- blur_indexes[x]=(IndexPacket) ClampToQuantum(gamma*qixel.index);
+ SetIndexPixelComponent(blur_indexes+x,ClampToQuantum(gamma*
+ qixel.index));
}
q++;
}
MagickBooleanType
proceed;
-#if defined(MAGICKCORE_OPENMP_SUPPORT) && defined(MAGICKCORE_FUTURE)
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
#pragma omp critical (MagickCore_MotionBlurImageChannel)
#endif
proceed=SetImageProgress(image,BlurImageTag,progress++,image->rows);
ImageInfo
*preview_info;
- ssize_t
- y;
-
MagickBooleanType
proceed;
size_t
colors;
+ ssize_t
+ y;
+
/*
Open output image file.
*/
{
degrees+=45.0;
preview_image=RotateImage(thumbnail,degrees,exception);
- (void) FormatMagickString(label,MaxTextExtent,"rotate %g",degrees);
+ (void) FormatLocaleString(label,MaxTextExtent,"rotate %g",degrees);
break;
}
case ShearPreview:
{
degrees+=5.0;
preview_image=ShearImage(thumbnail,degrees,degrees,exception);
- (void) FormatMagickString(label,MaxTextExtent,"shear %gx%g",
+ (void) FormatLocaleString(label,MaxTextExtent,"shear %gx%g",
degrees,2.0*degrees);
break;
}
x=(ssize_t) ((i+1)*thumbnail->columns)/NumberTiles;
y=(ssize_t) ((i+1)*thumbnail->rows)/NumberTiles;
preview_image=RollImage(thumbnail,x,y,exception);
- (void) FormatMagickString(label,MaxTextExtent,"roll %ldx%ld",(long) x,
- (long) y);
+ (void) FormatLocaleString(label,MaxTextExtent,"roll %+.20gx%+.20g",
+ (double) x,(double) y);
break;
}
case HuePreview:
preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
if (preview_image == (Image *) NULL)
break;
- (void) FormatMagickString(factor,MaxTextExtent,"100,100,%g",
+ (void) FormatLocaleString(factor,MaxTextExtent,"100,100,%g",
2.0*percentage);
(void) ModulateImage(preview_image,factor);
- (void) FormatMagickString(label,MaxTextExtent,"modulate %s",factor);
+ (void) FormatLocaleString(label,MaxTextExtent,"modulate %s",factor);
break;
}
case SaturationPreview:
preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
if (preview_image == (Image *) NULL)
break;
- (void) FormatMagickString(factor,MaxTextExtent,"100,%g",
+ (void) FormatLocaleString(factor,MaxTextExtent,"100,%g",
2.0*percentage);
(void) ModulateImage(preview_image,factor);
- (void) FormatMagickString(label,MaxTextExtent,"modulate %s",factor);
+ (void) FormatLocaleString(label,MaxTextExtent,"modulate %s",factor);
break;
}
case BrightnessPreview:
preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
if (preview_image == (Image *) NULL)
break;
- (void) FormatMagickString(factor,MaxTextExtent,"%g",2.0*percentage);
+ (void) FormatLocaleString(factor,MaxTextExtent,"%g",2.0*percentage);
(void) ModulateImage(preview_image,factor);
- (void) FormatMagickString(label,MaxTextExtent,"modulate %s",factor);
+ (void) FormatLocaleString(label,MaxTextExtent,"modulate %s",factor);
break;
}
case GammaPreview:
break;
gamma+=0.4f;
(void) GammaImageChannel(preview_image,DefaultChannels,gamma);
- (void) FormatMagickString(label,MaxTextExtent,"gamma %g",gamma);
+ (void) FormatLocaleString(label,MaxTextExtent,"gamma %g",gamma);
break;
}
case SpiffPreview:
if (preview_image != (Image *) NULL)
for (x=0; x < i; x++)
(void) ContrastImage(preview_image,MagickTrue);
- (void) FormatMagickString(label,MaxTextExtent,"contrast (%ld)",(long)
- i+1);
+ (void) FormatLocaleString(label,MaxTextExtent,"contrast (%.20g)",
+ (double) i+1);
break;
}
case DullPreview:
break;
for (x=0; x < i; x++)
(void) ContrastImage(preview_image,MagickFalse);
- (void) FormatMagickString(label,MaxTextExtent,"+contrast (%ld)",
- (long) i+1);
+ (void) FormatLocaleString(label,MaxTextExtent,"+contrast (%.20g)",
+ (double) i+1);
break;
}
case GrayscalePreview:
quantize_info.number_colors=colors;
quantize_info.colorspace=GRAYColorspace;
(void) QuantizeImage(&quantize_info,preview_image);
- (void) FormatMagickString(label,MaxTextExtent,
- "-colorspace gray -colors %lu",(unsigned long) colors);
+ (void) FormatLocaleString(label,MaxTextExtent,
+ "-colorspace gray -colors %.20g",(double) colors);
break;
}
case QuantizePreview:
colors<<=1;
quantize_info.number_colors=colors;
(void) QuantizeImage(&quantize_info,preview_image);
- (void) FormatMagickString(label,MaxTextExtent,"colors %lu",
- (unsigned long) colors);
+ (void) FormatLocaleString(label,MaxTextExtent,"colors %.20g",(double)
+ colors);
break;
}
case DespecklePreview:
preview_image=DespeckleImage(thumbnail,exception);
if (preview_image == (Image *) NULL)
break;
- (void) FormatMagickString(label,MaxTextExtent,"despeckle (%ld)",(long)
- i+1);
+ (void) FormatLocaleString(label,MaxTextExtent,"despeckle (%.20g)",
+ (double) i+1);
break;
}
case ReduceNoisePreview:
{
- preview_image=ReduceNoiseImage(thumbnail,radius,exception);
- (void) FormatMagickString(label,MaxTextExtent,"noise %g",radius);
+ preview_image=StatisticImage(thumbnail,NonpeakStatistic,(size_t) radius,
+ (size_t) radius,exception);
+ (void) FormatLocaleString(label,MaxTextExtent,"noise %g",radius);
break;
}
case AddNoisePreview:
break;
}
}
- preview_image=ReduceNoiseImage(thumbnail,(double) i,exception);
- (void) FormatMagickString(label,MaxTextExtent,"+noise %s",factor);
+ preview_image=StatisticImage(thumbnail,NonpeakStatistic,(size_t) i,
+ (size_t) i,exception);
+ (void) FormatLocaleString(label,MaxTextExtent,"+noise %s",factor);
break;
}
case SharpenPreview:
{
preview_image=SharpenImage(thumbnail,radius,sigma,exception);
- (void) FormatMagickString(label,MaxTextExtent,"sharpen %gx%g",
+ (void) FormatLocaleString(label,MaxTextExtent,"sharpen %gx%g",
radius,sigma);
break;
}
case BlurPreview:
{
preview_image=BlurImage(thumbnail,radius,sigma,exception);
- (void) FormatMagickString(label,MaxTextExtent,"blur %gx%g",radius,
+ (void) FormatLocaleString(label,MaxTextExtent,"blur %gx%g",radius,
sigma);
break;
}
break;
(void) BilevelImage(thumbnail,
(double) (percentage*((MagickRealType) QuantumRange+1.0))/100.0);
- (void) FormatMagickString(label,MaxTextExtent,"threshold %g",
+ (void) FormatLocaleString(label,MaxTextExtent,"threshold %g",
(double) (percentage*((MagickRealType) QuantumRange+1.0))/100.0);
break;
}
case EdgeDetectPreview:
{
preview_image=EdgeImage(thumbnail,radius,exception);
- (void) FormatMagickString(label,MaxTextExtent,"edge %g",radius);
+ (void) FormatLocaleString(label,MaxTextExtent,"edge %g",radius);
break;
}
case SpreadPreview:
{
preview_image=SpreadImage(thumbnail,radius,exception);
- (void) FormatMagickString(label,MaxTextExtent,"spread %g",
+ (void) FormatLocaleString(label,MaxTextExtent,"spread %g",
radius+0.5);
break;
}
break;
(void) SolarizeImage(preview_image,(double) QuantumRange*
percentage/100.0);
- (void) FormatMagickString(label,MaxTextExtent,"solarize %g",
+ (void) FormatLocaleString(label,MaxTextExtent,"solarize %g",
(QuantumRange*percentage)/100.0);
break;
}
degrees+=10.0;
preview_image=ShadeImage(thumbnail,MagickTrue,degrees,degrees,
exception);
- (void) FormatMagickString(label,MaxTextExtent,"shade %gx%g",
+ (void) FormatLocaleString(label,MaxTextExtent,"shade %gx%g",
degrees,degrees);
break;
}
geometry.x=i/2;
geometry.y=i/2;
(void) RaiseImage(preview_image,&geometry,MagickTrue);
- (void) FormatMagickString(label,MaxTextExtent,"raise %lux%lu%+ld%+ld",
- (unsigned long) geometry.width,(unsigned long) geometry.height,
- (long) geometry.x,(long) geometry.y);
+ (void) FormatLocaleString(label,MaxTextExtent,
+ "raise %.20gx%.20g%+.20g%+.20g",(double) geometry.width,(double)
+ geometry.height,(double) geometry.x,(double) geometry.y);
break;
}
case SegmentPreview:
threshold+=0.4f;
(void) SegmentImage(preview_image,RGBColorspace,MagickFalse,threshold,
threshold);
- (void) FormatMagickString(label,MaxTextExtent,"segment %gx%g",
+ (void) FormatLocaleString(label,MaxTextExtent,"segment %gx%g",
threshold,threshold);
break;
}
case SwirlPreview:
{
preview_image=SwirlImage(thumbnail,degrees,exception);
- (void) FormatMagickString(label,MaxTextExtent,"swirl %g",degrees);
+ (void) FormatLocaleString(label,MaxTextExtent,"swirl %g",degrees);
degrees+=45.0;
break;
}
{
degrees+=0.1f;
preview_image=ImplodeImage(thumbnail,degrees,exception);
- (void) FormatMagickString(label,MaxTextExtent,"implode %g",degrees);
+ (void) FormatLocaleString(label,MaxTextExtent,"implode %g",degrees);
break;
}
case WavePreview:
{
degrees+=5.0f;
preview_image=WaveImage(thumbnail,0.5*degrees,2.0*degrees,exception);
- (void) FormatMagickString(label,MaxTextExtent,"wave %gx%g",
+ (void) FormatLocaleString(label,MaxTextExtent,"wave %gx%g",
0.5*degrees,2.0*degrees);
break;
}
case OilPaintPreview:
{
preview_image=OilPaintImage(thumbnail,(double) radius,exception);
- (void) FormatMagickString(label,MaxTextExtent,"paint %g",radius);
+ (void) FormatLocaleString(label,MaxTextExtent,"paint %g",radius);
break;
}
case CharcoalDrawingPreview:
{
preview_image=CharcoalImage(thumbnail,(double) radius,(double) sigma,
exception);
- (void) FormatMagickString(label,MaxTextExtent,"charcoal %gx%g",
+ (void) FormatLocaleString(label,MaxTextExtent,"charcoal %gx%g",
radius,sigma);
break;
}
if (preview_image == (Image *) NULL)
break;
preview_info->quality=(size_t) percentage;
- (void) FormatMagickString(factor,MaxTextExtent,"%lu",
- (unsigned long) preview_info->quality);
+ (void) FormatLocaleString(factor,MaxTextExtent,"%.20g",(double)
+ preview_info->quality);
file=AcquireUniqueFileResource(filename);
if (file != -1)
file=close(file)-1;
- (void) FormatMagickString(preview_image->filename,MaxTextExtent,
+ (void) FormatLocaleString(preview_image->filename,MaxTextExtent,
"jpeg:%s",filename);
status=WriteImage(preview_info,preview_image);
if (status != MagickFalse)
}
(void) RelinquishUniqueFileResource(preview_image->filename);
if ((GetBlobSize(preview_image)/1024) >= 1024)
- (void) FormatMagickString(label,MaxTextExtent,"quality %s\n%gmb ",
+ (void) FormatLocaleString(label,MaxTextExtent,"quality %s\n%gmb ",
factor,(double) ((MagickOffsetType) GetBlobSize(preview_image))/
1024.0/1024.0);
else
if (GetBlobSize(preview_image) >= 1024)
- (void) FormatMagickString(label,MaxTextExtent,
+ (void) FormatLocaleString(label,MaxTextExtent,
"quality %s\n%gkb ",factor,(double) ((MagickOffsetType)
GetBlobSize(preview_image))/1024.0);
else
- (void) FormatMagickString(label,MaxTextExtent,"quality %s\n%lub ",
- factor,(unsigned long) GetBlobSize(thumbnail));
+ (void) FormatLocaleString(label,MaxTextExtent,"quality %s\n%.20gb ",
+ factor,(double) GetBlobSize(thumbnail));
break;
}
}
blur_center.x=(double) image->columns/2.0;
blur_center.y=(double) image->rows/2.0;
blur_radius=hypot(blur_center.x,blur_center.y);
- n=(size_t) fabs(4.0*DegreesToRadians(angle)*sqrt((double) blur_radius)+
- 2UL);
+ n=(size_t) fabs(4.0*DegreesToRadians(angle)*sqrt((double) blur_radius)+2UL);
theta=DegreesToRadians(angle)/(MagickRealType) (n-1);
cos_theta=(MagickRealType *) AcquireQuantumMemory((size_t) n,
sizeof(*cos_theta));
register IndexPacket
*restrict blur_indexes;
- register ssize_t
- x;
-
register PixelPacket
*restrict q;
+ register ssize_t
+ x;
+
if (status == MagickFalse)
continue;
q=GetCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
qixel=bias;
if (((channel & OpacityChannel) == 0) || (image->matte == MagickFalse))
{
- for (i=0; i < (ssize_t) n; i+=step)
+ for (i=0; i < (ssize_t) n; i+=(ssize_t) step)
{
- (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) (blur_center.x+
- center.x*cos_theta[i]-center.y*sin_theta[i]+0.5),(ssize_t) (
- blur_center.y+center.x*sin_theta[i]+center.y*cos_theta[i]+0.5),
- &pixel,exception);
+ (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t)
+ (blur_center.x+center.x*cos_theta[i]-center.y*sin_theta[i]+0.5),
+ (ssize_t) (blur_center.y+center.x*sin_theta[i]+center.y*
+ cos_theta[i]+0.5),&pixel,exception);
qixel.red+=pixel.red;
qixel.green+=pixel.green;
qixel.blue+=pixel.blue;
normalize=1.0/(fabs((double) normalize) <= MagickEpsilon ? 1.0 :
normalize);
if ((channel & RedChannel) != 0)
- q->red=ClampToQuantum(normalize*qixel.red);
+ SetRedPixelComponent(q,ClampToQuantum(normalize*qixel.red));
if ((channel & GreenChannel) != 0)
- q->green=ClampToQuantum(normalize*qixel.green);
+ SetGreenPixelComponent(q,ClampToQuantum(normalize*qixel.green));
if ((channel & BlueChannel) != 0)
- q->blue=ClampToQuantum(normalize*qixel.blue);
+ SetBluePixelComponent(q,ClampToQuantum(normalize*qixel.blue));
if ((channel & OpacityChannel) != 0)
- q->opacity=ClampToQuantum(normalize*qixel.opacity);
+ SetOpacityPixelComponent(q,ClampToQuantum(normalize*qixel.opacity));
if (((channel & IndexChannel) != 0) &&
(image->colorspace == CMYKColorspace))
- blur_indexes[x]=(IndexPacket) ClampToQuantum(normalize*qixel.index);
+ SetIndexPixelComponent(blur_indexes+x,ClampToQuantum(normalize*
+ qixel.index));
}
else
{
alpha=1.0;
gamma=0.0;
- for (i=0; i < (ssize_t) n; i+=step)
+ for (i=0; i < (ssize_t) n; i+=(ssize_t) step)
{
- (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) (blur_center.x+
- center.x*cos_theta[i]-center.y*sin_theta[i]+0.5),(ssize_t) (
- blur_center.y+center.x*sin_theta[i]+center.y*cos_theta[i]+0.5),
- &pixel,exception);
+ (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t)
+ (blur_center.x+center.x*cos_theta[i]-center.y*sin_theta[i]+0.5),
+ (ssize_t) (blur_center.y+center.x*sin_theta[i]+center.y*
+ cos_theta[i]+0.5),&pixel,exception);
alpha=(MagickRealType) (QuantumScale*
GetAlphaPixelComponent(&pixel));
qixel.red+=alpha*pixel.red;
normalize=1.0/(fabs((double) normalize) <= MagickEpsilon ? 1.0 :
normalize);
if ((channel & RedChannel) != 0)
- q->red=ClampToQuantum(gamma*qixel.red);
+ SetRedPixelComponent(q,ClampToQuantum(gamma*qixel.red));
if ((channel & GreenChannel) != 0)
- q->green=ClampToQuantum(gamma*qixel.green);
+ SetGreenPixelComponent(q,ClampToQuantum(gamma*qixel.green));
if ((channel & BlueChannel) != 0)
- q->blue=ClampToQuantum(gamma*qixel.blue);
+ SetBluePixelComponent(q,ClampToQuantum(gamma*qixel.blue));
if ((channel & OpacityChannel) != 0)
- q->opacity=ClampToQuantum(normalize*qixel.opacity);
+ SetOpacityPixelComponent(q,ClampToQuantum(normalize*qixel.opacity));
if (((channel & IndexChannel) != 0) &&
(image->colorspace == CMYKColorspace))
- blur_indexes[x]=(IndexPacket) ClampToQuantum(gamma*qixel.index);
+ SetIndexPixelComponent(blur_indexes+x,ClampToQuantum(gamma*
+ qixel.index));
}
q++;
}
% %
% %
% %
-% R e d u c e N o i s e I m a g e %
+% S e l e c t i v e B l u r I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
-% ReduceNoiseImage() smooths the contours of an image while still preserving
-% edge information. The algorithm works by replacing each pixel with its
-% neighbor closest in value. A neighbor is defined by radius. Use a radius
-% of 0 and ReduceNoise() selects a suitable radius for you.
+% SelectiveBlurImage() selectively blur pixels within a contrast threshold.
+% It is similar to the unsharpen mask that sharpens everything with contrast
+% above a certain threshold.
%
-% The format of the ReduceNoiseImage method is:
+% The format of the SelectiveBlurImage method is:
%
-% Image *ReduceNoiseImage(const Image *image,const double radius,
-% ExceptionInfo *exception)
+% Image *SelectiveBlurImage(const Image *image,const double radius,
+% const double sigma,const double threshold,ExceptionInfo *exception)
+% Image *SelectiveBlurImageChannel(const Image *image,
+% const ChannelType channel,const double radius,const double sigma,
+% const double threshold,ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o image: the image.
%
-% o radius: the radius of the pixel neighborhood.
+% o channel: the channel type.
%
-% o exception: return any errors or warnings in this structure.
-%
-*/
-
-static MagickPixelPacket GetNonpeakMedianPixelList(MedianPixelList *pixel_list)
-{
- MagickPixelPacket
- pixel;
-
- register ssize_t
- channel;
-
- register MedianSkipList
- *list;
-
- size_t
- center,
- color,
- count,
- previous,
- next;
-
- unsigned short
- channels[5];
-
- /*
- Finds the median value for each of the color.
- */
- center=pixel_list->center;
- for (channel=0; channel < 5; channel++)
- {
- list=pixel_list->lists+channel;
- color=65536UL;
- next=list->nodes[color].next[0];
- count=0;
- do
- {
- previous=color;
- color=next;
- next=list->nodes[color].next[0];
- count+=list->nodes[color].count;
- }
- while (count <= center);
- if ((previous == 65536UL) && (next != 65536UL))
- color=next;
- else
- if ((previous != 65536UL) && (next == 65536UL))
- color=previous;
- channels[channel]=(unsigned short) color;
- }
- GetMagickPixelPacket((const Image *) NULL,&pixel);
- pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
- pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
- pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
- pixel.opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
- pixel.index=(MagickRealType) ScaleShortToQuantum(channels[4]);
- return(pixel);
-}
-
-MagickExport Image *ReduceNoiseImage(const Image *image,const double radius,
- ExceptionInfo *exception)
-{
-#define ReduceNoiseImageTag "ReduceNoise/Image"
-
- CacheView
- *image_view,
- *noise_view;
-
- Image
- *noise_image;
-
- MagickBooleanType
- status;
-
- MagickOffsetType
- progress;
-
- MedianPixelList
- **restrict pixel_list;
-
- size_t
- width;
-
- ssize_t
- y;
-
- /*
- Initialize noise 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);
- width=GetOptimalKernelWidth2D(radius,0.5);
- if ((image->columns < width) || (image->rows < width))
- ThrowImageException(OptionError,"ImageSmallerThanKernelRadius");
- noise_image=CloneImage(image,image->columns,image->rows,MagickTrue,
- exception);
- if (noise_image == (Image *) NULL)
- return((Image *) NULL);
- if (SetImageStorageClass(noise_image,DirectClass) == MagickFalse)
- {
- InheritException(exception,&noise_image->exception);
- noise_image=DestroyImage(noise_image);
- return((Image *) NULL);
- }
- pixel_list=AcquireMedianPixelListThreadSet(width);
- if (pixel_list == (MedianPixelList **) NULL)
- {
- noise_image=DestroyImage(noise_image);
- ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
- }
- /*
- Reduce noise image.
- */
- status=MagickTrue;
- progress=0;
- image_view=AcquireCacheView(image);
- noise_view=AcquireCacheView(noise_image);
-#if defined(MAGICKCORE_OPENMP_SUPPORT)
- #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
-#endif
- for (y=0; y < (ssize_t) noise_image->rows; y++)
- {
- register const IndexPacket
- *restrict indexes;
-
- register const PixelPacket
- *restrict p;
-
- register IndexPacket
- *restrict noise_indexes;
-
- register ssize_t
- id,
- x;
-
- register PixelPacket
- *restrict q;
-
- if (status == MagickFalse)
- continue;
- p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y-(ssize_t) (width/
- 2L),image->columns+width,width,exception);
- q=QueueCacheViewAuthenticPixels(noise_view,0,y,noise_image->columns,1,
- exception);
- if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
- {
- status=MagickFalse;
- continue;
- }
- indexes=GetCacheViewVirtualIndexQueue(image_view);
- noise_indexes=GetCacheViewAuthenticIndexQueue(noise_view);
- id=GetOpenMPThreadId();
- for (x=0; x < (ssize_t) noise_image->columns; x++)
- {
- MagickPixelPacket
- pixel;
-
- register const PixelPacket
- *restrict r;
-
- register const IndexPacket
- *restrict s;
-
- register ssize_t
- u,
- v;
-
- r=p;
- s=indexes+x;
- ResetMedianPixelList(pixel_list[id]);
- for (v=0; v < (ssize_t) width; v++)
- {
- for (u=0; u < (ssize_t) width; u++)
- InsertMedianPixelList(image,r+u,s+u,pixel_list[id]);
- r+=image->columns+width;
- s+=image->columns+width;
- }
- pixel=GetNonpeakMedianPixelList(pixel_list[id]);
- SetPixelPacket(noise_image,&pixel,q,noise_indexes+x);
- p++;
- q++;
- }
- if (SyncCacheViewAuthenticPixels(noise_view,exception) == MagickFalse)
- status=MagickFalse;
- if (image->progress_monitor != (MagickProgressMonitor) NULL)
- {
- MagickBooleanType
- proceed;
-
-#if defined(MAGICKCORE_OPENMP_SUPPORT)
- #pragma omp critical (MagickCore_ReduceNoiseImage)
-#endif
- proceed=SetImageProgress(image,ReduceNoiseImageTag,progress++,
- image->rows);
- if (proceed == MagickFalse)
- status=MagickFalse;
- }
- }
- noise_view=DestroyCacheView(noise_view);
- image_view=DestroyCacheView(image_view);
- pixel_list=DestroyMedianPixelListThreadSet(pixel_list);
- return(noise_image);
-}
-\f
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% %
-% %
-% %
-% S e l e c t i v e B l u r I m a g e %
-% %
-% %
-% %
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%
-% SelectiveBlurImage() selectively blur pixels within a contrast threshold.
-% It is similar to the unsharpen mask that sharpens everything with contrast
-% above a certain threshold.
-%
-% The format of the SelectiveBlurImage method is:
-%
-% Image *SelectiveBlurImage(const Image *image,const double radius,
-% const double sigma,const double threshold,ExceptionInfo *exception)
-% Image *SelectiveBlurImageChannel(const Image *image,
-% const ChannelType channel,const double radius,const double sigma,
-% const double threshold,ExceptionInfo *exception)
-%
-% A description of each parameter follows:
-%
-% o image: the image.
-%
-% o channel: the channel type.
-%
-% o radius: the radius of the Gaussian, in pixels, not counting the center
-% pixel.
+% o radius: the radius of the Gaussian, in pixels, not counting the center
+% pixel.
%
% o sigma: the standard deviation of the Gaussian, in pixels.
%
for (v=(-j); v <= j; v++)
{
for (u=(-j); u <= j; u++)
- kernel[i++]=exp(-((double) u*u+v*v)/(2.0*MagickSigma*MagickSigma))/
- (2.0*MagickPI*MagickSigma*MagickSigma);
+ kernel[i++]=(double) (exp(-((double) u*u+v*v)/(2.0*MagickSigma*
+ MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
}
if (image->debug != MagickFalse)
{
format[MaxTextExtent],
*message;
+ register const double
+ *k;
+
ssize_t
u,
v;
- register const double
- *k;
-
(void) LogMagickEvent(TransformEvent,GetMagickModule(),
- " SelectiveBlurImage with %lux%lu kernel:",(unsigned long) width,
- (unsigned long) width);
+ " SelectiveBlurImage with %.20gx%.20g kernel:",(double) width,(double)
+ width);
message=AcquireString("");
k=kernel;
for (v=0; v < (ssize_t) width; v++)
{
*message='\0';
- (void) FormatMagickString(format,MaxTextExtent,"%ld: ",(long) v);
+ (void) FormatLocaleString(format,MaxTextExtent,"%.20g: ",(double) v);
(void) ConcatenateString(&message,format);
for (u=0; u < (ssize_t) width; u++)
{
- (void) FormatMagickString(format,MaxTextExtent,"%+f ",*k++);
+ (void) FormatLocaleString(format,MaxTextExtent,"%+f ",*k++);
(void) ConcatenateString(&message,format);
}
(void) LogMagickEvent(TransformEvent,GetMagickModule(),"%s",message);
register IndexPacket
*restrict blur_indexes;
- register ssize_t
- x;
-
register PixelPacket
*restrict q;
+ register ssize_t
+ x;
+
if (status == MagickFalse)
continue;
- p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y-(ssize_t) (width/
- 2L),image->columns+width,width,exception);
+ p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y-(ssize_t)
+ (width/2L),image->columns+width,width,exception);
q=GetCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
exception);
if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
blur_indexes=GetCacheViewAuthenticIndexQueue(blur_view);
for (x=0; x < (ssize_t) image->columns; x++)
{
- ssize_t
- j,
- v;
-
MagickPixelPacket
pixel;
register ssize_t
u;
+ ssize_t
+ j,
+ v;
+
pixel=bias;
k=kernel;
gamma=0.0;
{
if (SelectiveContrast(p+u+j,q,threshold) != MagickFalse)
{
- pixel.red+=(*k)*(p+u+j)->red;
- pixel.green+=(*k)*(p+u+j)->green;
- pixel.blue+=(*k)*(p+u+j)->blue;
+ pixel.red+=(*k)*GetRedPixelComponent(p+u+j);
+ pixel.green+=(*k)*GetGreenPixelComponent(p+u+j);
+ pixel.blue+=(*k)*GetBluePixelComponent(p+u+j);
gamma+=(*k);
k++;
}
}
- j+=image->columns+width;
+ j+=(ssize_t) (image->columns+width);
}
if (gamma != 0.0)
{
gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
if ((channel & RedChannel) != 0)
- q->red=ClampToQuantum(gamma*GetRedPixelComponent(&pixel));
+ SetRedPixelComponent(q,ClampToQuantum(gamma*pixel.red));
if ((channel & GreenChannel) != 0)
- q->green=ClampToQuantum(gamma*GetGreenPixelComponent(&pixel));
+ SetGreenPixelComponent(q,ClampToQuantum(gamma*pixel.green));
if ((channel & BlueChannel) != 0)
- q->blue=ClampToQuantum(gamma*GetBluePixelComponent(&pixel));
+ SetBluePixelComponent(q,ClampToQuantum(gamma*pixel.blue));
}
if ((channel & OpacityChannel) != 0)
{
k++;
}
}
- j+=image->columns+width;
+ j+=(ssize_t) (image->columns+width);
}
if (gamma != 0.0)
{
gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 :
gamma);
SetOpacityPixelComponent(q,ClampToQuantum(gamma*
- GetOpacityPixelComponent(&pixel)));
+ pixel.opacity));
}
}
if (((channel & IndexChannel) != 0) &&
{
if (SelectiveContrast(p+u+j,q,threshold) != MagickFalse)
{
- pixel.index+=(*k)*indexes[x+u+j];
+ pixel.index+=(*k)*GetIndexPixelComponent(indexes+x+u+j);
gamma+=(*k);
k++;
}
}
- j+=image->columns+width;
+ j+=(ssize_t) (image->columns+width);
}
if (gamma != 0.0)
{
gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 :
gamma);
- blur_indexes[x]=ClampToQuantum(gamma*
- GetIndexPixelComponent(&pixel));
+ SetIndexPixelComponent(blur_indexes+x,ClampToQuantum(gamma*
+ pixel.index));
}
}
}
{
alpha=(MagickRealType) (QuantumScale*
GetAlphaPixelComponent(p+u+j));
- pixel.red+=(*k)*alpha*(p+u+j)->red;
- pixel.green+=(*k)*alpha*(p+u+j)->green;
- pixel.blue+=(*k)*alpha*(p+u+j)->blue;
- pixel.opacity+=(*k)*(p+u+j)->opacity;
+ pixel.red+=(*k)*alpha*GetRedPixelComponent(p+u+j);
+ pixel.green+=(*k)*alpha*GetGreenPixelComponent(p+u+j);
+ pixel.blue+=(*k)*alpha*GetBluePixelComponent(p+u+j);
+ pixel.opacity+=(*k)*GetOpacityPixelComponent(p+u+j);
gamma+=(*k)*alpha;
k++;
}
}
- j+=image->columns+width;
+ j+=(ssize_t) (image->columns+width);
}
if (gamma != 0.0)
{
gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
if ((channel & RedChannel) != 0)
- q->red=ClampToQuantum(gamma*GetRedPixelComponent(&pixel));
+ SetRedPixelComponent(q,ClampToQuantum(gamma*pixel.red));
if ((channel & GreenChannel) != 0)
- q->green=ClampToQuantum(gamma*GetGreenPixelComponent(&pixel));
+ SetGreenPixelComponent(q,ClampToQuantum(gamma*pixel.green));
if ((channel & BlueChannel) != 0)
- q->blue=ClampToQuantum(gamma*GetBluePixelComponent(&pixel));
+ SetBluePixelComponent(q,ClampToQuantum(gamma*pixel.blue));
}
if ((channel & OpacityChannel) != 0)
{
{
if (SelectiveContrast(p+u+j,q,threshold) != MagickFalse)
{
- pixel.opacity+=(*k)*(p+u+j)->opacity;
+ pixel.opacity+=(*k)*GetOpacityPixelComponent(p+u+j);
gamma+=(*k);
k++;
}
}
- j+=image->columns+width;
+ j+=(ssize_t) (image->columns+width);
}
if (gamma != 0.0)
{
gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 :
gamma);
- SetOpacityPixelComponent(q,
- ClampOpacityPixelComponent(&pixel));
+ SetOpacityPixelComponent(q,ClampToQuantum(pixel.opacity));
}
}
if (((channel & IndexChannel) != 0) &&
{
alpha=(MagickRealType) (QuantumScale*
GetAlphaPixelComponent(p+u+j));
- pixel.index+=(*k)*alpha*indexes[x+u+j];
+ pixel.index+=(*k)*alpha*GetIndexPixelComponent(indexes+x+
+ u+j);
gamma+=(*k);
k++;
}
}
- j+=image->columns+width;
+ j+=(ssize_t) (image->columns+width);
}
if (gamma != 0.0)
{
gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 :
gamma);
- blur_indexes[x]=ClampToQuantum(gamma*
- GetIndexPixelComponent(&pixel));
+ SetIndexPixelComponent(blur_indexes+x,ClampToQuantum(gamma*
+ pixel.index));
}
}
}
*restrict s1,
*restrict s2;
- register ssize_t
- x;
-
register PixelPacket
*restrict q;
+ register ssize_t
+ x;
+
if (status == MagickFalse)
continue;
p=GetCacheViewVirtualPixels(image_view,-1,y-1,image->columns+2,3,exception);
}
if (gray != MagickFalse)
{
- q->red=(Quantum) shade;
- q->green=(Quantum) shade;
- q->blue=(Quantum) shade;
+ SetRedPixelComponent(q,shade);
+ SetGreenPixelComponent(q,shade);
+ SetBluePixelComponent(q,shade);
}
else
{
- q->red=ClampToQuantum(QuantumScale*shade*s1->red);
- q->green=ClampToQuantum(QuantumScale*shade*s1->green);
- q->blue=ClampToQuantum(QuantumScale*shade*s1->blue);
+ SetRedPixelComponent(q,ClampToQuantum(QuantumScale*shade*
+ GetRedPixelComponent(s1)));
+ SetGreenPixelComponent(q,ClampToQuantum(QuantumScale*shade*
+ GetGreenPixelComponent(s1)));
+ SetBluePixelComponent(q,ClampToQuantum(QuantumScale*shade*
+ GetBluePixelComponent(s1)));
}
q->opacity=s1->opacity;
s0++;
%
*/
-MagickExport Image *SharpenImage(const Image *image,const double radius,
- const double sigma,ExceptionInfo *exception)
+MagickExport Image *SharpenImage(const Image *image,const double radius,
+ const double sigma,ExceptionInfo *exception)
+{
+ Image
+ *sharp_image;
+
+ sharp_image=SharpenImageChannel(image,DefaultChannels,radius,sigma,exception);
+ return(sharp_image);
+}
+
+MagickExport Image *SharpenImageChannel(const Image *image,
+ const ChannelType channel,const double radius,const double sigma,
+ ExceptionInfo *exception)
+{
+ double
+ *kernel,
+ normalize;
+
+ Image
+ *sharp_image;
+
+ register ssize_t
+ i;
+
+ size_t
+ width;
+
+ ssize_t
+ j,
+ u,
+ v;
+
+ assert(image != (const 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);
+ width=GetOptimalKernelWidth2D(radius,sigma);
+ kernel=(double *) AcquireQuantumMemory((size_t) width*width,sizeof(*kernel));
+ if (kernel == (double *) NULL)
+ ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+ normalize=0.0;
+ j=(ssize_t) width/2;
+ i=0;
+ for (v=(-j); v <= j; v++)
+ {
+ for (u=(-j); u <= j; u++)
+ {
+ kernel[i]=(double) (-exp(-((double) u*u+v*v)/(2.0*MagickSigma*
+ MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
+ normalize+=kernel[i];
+ i++;
+ }
+ }
+ kernel[i/2]=(double) ((-2.0)*normalize);
+ sharp_image=ConvolveImageChannel(image,channel,width,kernel,exception);
+ kernel=(double *) RelinquishMagickMemory(kernel);
+ return(sharp_image);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% %
+% %
+% %
+% S p r e a d I m a g e %
+% %
+% %
+% %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% SpreadImage() is a special effects method that randomly displaces each
+% pixel in a block defined by the radius parameter.
+%
+% The format of the SpreadImage method is:
+%
+% Image *SpreadImage(const Image *image,const double radius,
+% ExceptionInfo *exception)
+%
+% A description of each parameter follows:
+%
+% o image: the image.
+%
+% o radius: Choose a random pixel in a neighborhood of this extent.
+%
+% o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *SpreadImage(const Image *image,const double radius,
+ ExceptionInfo *exception)
+{
+#define SpreadImageTag "Spread/Image"
+
+ CacheView
+ *image_view,
+ *spread_view;
+
+ Image
+ *spread_image;
+
+ MagickBooleanType
+ status;
+
+ MagickOffsetType
+ progress;
+
+ MagickPixelPacket
+ bias;
+
+ RandomInfo
+ **restrict random_info;
+
+ size_t
+ width;
+
+ ssize_t
+ y;
+
+ /*
+ Initialize spread 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);
+ spread_image=CloneImage(image,image->columns,image->rows,MagickTrue,
+ exception);
+ if (spread_image == (Image *) NULL)
+ return((Image *) NULL);
+ if (SetImageStorageClass(spread_image,DirectClass) == MagickFalse)
+ {
+ InheritException(exception,&spread_image->exception);
+ spread_image=DestroyImage(spread_image);
+ return((Image *) NULL);
+ }
+ /*
+ Spread image.
+ */
+ status=MagickTrue;
+ progress=0;
+ GetMagickPixelPacket(spread_image,&bias);
+ width=GetOptimalKernelWidth1D(radius,0.5);
+ random_info=AcquireRandomInfoThreadSet();
+ image_view=AcquireCacheView(image);
+ spread_view=AcquireCacheView(spread_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+ #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
+#endif
+ for (y=0; y < (ssize_t) spread_image->rows; y++)
+ {
+ const int
+ id = GetOpenMPThreadId();
+
+ MagickPixelPacket
+ pixel;
+
+ register IndexPacket
+ *restrict indexes;
+
+ register PixelPacket
+ *restrict q;
+
+ register ssize_t
+ x;
+
+ if (status == MagickFalse)
+ continue;
+ q=QueueCacheViewAuthenticPixels(spread_view,0,y,spread_image->columns,1,
+ exception);
+ if (q == (PixelPacket *) NULL)
+ {
+ status=MagickFalse;
+ continue;
+ }
+ indexes=GetCacheViewAuthenticIndexQueue(spread_view);
+ pixel=bias;
+ for (x=0; x < (ssize_t) spread_image->columns; x++)
+ {
+ (void) InterpolateMagickPixelPacket(image,image_view,
+ UndefinedInterpolatePixel,(double) x+width*(GetPseudoRandomValue(
+ random_info[id])-0.5),(double) y+width*(GetPseudoRandomValue(
+ random_info[id])-0.5),&pixel,exception);
+ SetPixelPacket(spread_image,&pixel,q,indexes+x);
+ q++;
+ }
+ if (SyncCacheViewAuthenticPixels(spread_view,exception) == MagickFalse)
+ status=MagickFalse;
+ if (image->progress_monitor != (MagickProgressMonitor) NULL)
+ {
+ MagickBooleanType
+ proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+ #pragma omp critical (MagickCore_SpreadImage)
+#endif
+ proceed=SetImageProgress(image,SpreadImageTag,progress++,image->rows);
+ if (proceed == MagickFalse)
+ status=MagickFalse;
+ }
+ }
+ spread_view=DestroyCacheView(spread_view);
+ image_view=DestroyCacheView(image_view);
+ random_info=DestroyRandomInfoThreadSet(random_info);
+ return(spread_image);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% %
+% %
+% %
+% S t a t i s t i c I m a g e %
+% %
+% %
+% %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% StatisticImage() makes each pixel the min / max / median / mode / etc. of
+% the neighborhood of the specified width and height.
+%
+% The format of the StatisticImage method is:
+%
+% Image *StatisticImage(const Image *image,const StatisticType type,
+% const size_t width,const size_t height,ExceptionInfo *exception)
+% Image *StatisticImageChannel(const Image *image,
+% const ChannelType channel,const StatisticType type,
+% const size_t width,const size_t height,ExceptionInfo *exception)
+%
+% A description of each parameter follows:
+%
+% o image: the image.
+%
+% o channel: the image channel.
+%
+% o type: the statistic type (median, mode, etc.).
+%
+% o width: the width of the pixel neighborhood.
+%
+% o height: the height of the pixel neighborhood.
+%
+% o exception: return any errors or warnings in this structure.
+%
+*/
+
+#define ListChannels 5
+
+typedef struct _ListNode
+{
+ size_t
+ next[9],
+ count,
+ signature;
+} ListNode;
+
+typedef struct _SkipList
+{
+ ssize_t
+ level;
+
+ ListNode
+ *nodes;
+} SkipList;
+
+typedef struct _PixelList
+{
+ size_t
+ length,
+ seed,
+ signature;
+
+ SkipList
+ lists[ListChannels];
+} PixelList;
+
+static PixelList *DestroyPixelList(PixelList *pixel_list)
+{
+ register ssize_t
+ i;
+
+ if (pixel_list == (PixelList *) NULL)
+ return((PixelList *) NULL);
+ for (i=0; i < ListChannels; i++)
+ if (pixel_list->lists[i].nodes != (ListNode *) NULL)
+ pixel_list->lists[i].nodes=(ListNode *) RelinquishMagickMemory(
+ pixel_list->lists[i].nodes);
+ pixel_list=(PixelList *) RelinquishMagickMemory(pixel_list);
+ return(pixel_list);
+}
+
+static PixelList **DestroyPixelListThreadSet(PixelList **pixel_list)
+{
+ register ssize_t
+ i;
+
+ assert(pixel_list != (PixelList **) NULL);
+ for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
+ if (pixel_list[i] != (PixelList *) NULL)
+ pixel_list[i]=DestroyPixelList(pixel_list[i]);
+ pixel_list=(PixelList **) RelinquishMagickMemory(pixel_list);
+ return(pixel_list);
+}
+
+static PixelList *AcquirePixelList(const size_t width,const size_t height)
+{
+ PixelList
+ *pixel_list;
+
+ register ssize_t
+ i;
+
+ pixel_list=(PixelList *) AcquireMagickMemory(sizeof(*pixel_list));
+ if (pixel_list == (PixelList *) NULL)
+ return(pixel_list);
+ (void) ResetMagickMemory((void *) pixel_list,0,sizeof(*pixel_list));
+ pixel_list->length=width*height;
+ for (i=0; i < ListChannels; i++)
+ {
+ pixel_list->lists[i].nodes=(ListNode *) AcquireQuantumMemory(65537UL,
+ sizeof(*pixel_list->lists[i].nodes));
+ if (pixel_list->lists[i].nodes == (ListNode *) NULL)
+ return(DestroyPixelList(pixel_list));
+ (void) ResetMagickMemory(pixel_list->lists[i].nodes,0,65537UL*
+ sizeof(*pixel_list->lists[i].nodes));
+ }
+ pixel_list->signature=MagickSignature;
+ return(pixel_list);
+}
+
+static PixelList **AcquirePixelListThreadSet(const size_t width,
+ const size_t height)
+{
+ PixelList
+ **pixel_list;
+
+ register ssize_t
+ i;
+
+ size_t
+ number_threads;
+
+ number_threads=GetOpenMPMaximumThreads();
+ pixel_list=(PixelList **) AcquireQuantumMemory(number_threads,
+ sizeof(*pixel_list));
+ if (pixel_list == (PixelList **) NULL)
+ return((PixelList **) NULL);
+ (void) ResetMagickMemory(pixel_list,0,number_threads*sizeof(*pixel_list));
+ for (i=0; i < (ssize_t) number_threads; i++)
+ {
+ pixel_list[i]=AcquirePixelList(width,height);
+ if (pixel_list[i] == (PixelList *) NULL)
+ return(DestroyPixelListThreadSet(pixel_list));
+ }
+ return(pixel_list);
+}
+
+static void AddNodePixelList(PixelList *pixel_list,const ssize_t channel,
+ const size_t color)
+{
+ register SkipList
+ *list;
+
+ register ssize_t
+ level;
+
+ size_t
+ search,
+ update[9];
+
+ /*
+ Initialize the node.
+ */
+ list=pixel_list->lists+channel;
+ list->nodes[color].signature=pixel_list->signature;
+ list->nodes[color].count=1;
+ /*
+ Determine where it belongs in the list.
+ */
+ search=65536UL;
+ for (level=list->level; level >= 0; level--)
+ {
+ while (list->nodes[search].next[level] < color)
+ search=list->nodes[search].next[level];
+ update[level]=search;
+ }
+ /*
+ Generate a pseudo-random level for this node.
+ */
+ for (level=0; ; level++)
+ {
+ pixel_list->seed=(pixel_list->seed*42893621L)+1L;
+ if ((pixel_list->seed & 0x300) != 0x300)
+ break;
+ }
+ if (level > 8)
+ level=8;
+ if (level > (list->level+2))
+ level=list->level+2;
+ /*
+ If we're raising the list's level, link back to the root node.
+ */
+ while (level > list->level)
+ {
+ list->level++;
+ update[list->level]=65536UL;
+ }
+ /*
+ Link the node into the skip-list.
+ */
+ do
+ {
+ list->nodes[color].next[level]=list->nodes[update[level]].next[level];
+ list->nodes[update[level]].next[level]=color;
+ } while (level-- > 0);
+}
+
+static MagickPixelPacket GetMaximumPixelList(PixelList *pixel_list)
+{
+ MagickPixelPacket
+ pixel;
+
+ register SkipList
+ *list;
+
+ register ssize_t
+ channel;
+
+ size_t
+ color,
+ maximum;
+
+ ssize_t
+ count;
+
+ unsigned short
+ channels[ListChannels];
+
+ /*
+ Find the maximum value for each of the color.
+ */
+ for (channel=0; channel < 5; channel++)
+ {
+ list=pixel_list->lists+channel;
+ color=65536L;
+ count=0;
+ maximum=list->nodes[color].next[0];
+ do
+ {
+ color=list->nodes[color].next[0];
+ if (color > maximum)
+ maximum=color;
+ count+=list->nodes[color].count;
+ } while (count < (ssize_t) pixel_list->length);
+ channels[channel]=(unsigned short) maximum;
+ }
+ GetMagickPixelPacket((const Image *) NULL,&pixel);
+ pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
+ pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
+ pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
+ pixel.opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
+ pixel.index=(MagickRealType) ScaleShortToQuantum(channels[4]);
+ return(pixel);
+}
+
+static MagickPixelPacket GetMeanPixelList(PixelList *pixel_list)
+{
+ MagickPixelPacket
+ pixel;
+
+ MagickRealType
+ sum;
+
+ register SkipList
+ *list;
+
+ register ssize_t
+ channel;
+
+ size_t
+ color;
+
+ ssize_t
+ count;
+
+ unsigned short
+ channels[ListChannels];
+
+ /*
+ Find the mean value for each of the color.
+ */
+ for (channel=0; channel < 5; channel++)
+ {
+ list=pixel_list->lists+channel;
+ color=65536L;
+ count=0;
+ sum=0.0;
+ do
+ {
+ color=list->nodes[color].next[0];
+ sum+=(MagickRealType) list->nodes[color].count*color;
+ count+=list->nodes[color].count;
+ } while (count < (ssize_t) pixel_list->length);
+ sum/=pixel_list->length;
+ channels[channel]=(unsigned short) sum;
+ }
+ GetMagickPixelPacket((const Image *) NULL,&pixel);
+ pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
+ pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
+ pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
+ pixel.opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
+ pixel.index=(MagickRealType) ScaleShortToQuantum(channels[4]);
+ return(pixel);
+}
+
+static MagickPixelPacket GetMedianPixelList(PixelList *pixel_list)
+{
+ MagickPixelPacket
+ pixel;
+
+ register SkipList
+ *list;
+
+ register ssize_t
+ channel;
+
+ size_t
+ color;
+
+ ssize_t
+ count;
+
+ unsigned short
+ channels[ListChannels];
+
+ /*
+ Find the median value for each of the color.
+ */
+ for (channel=0; channel < 5; channel++)
+ {
+ list=pixel_list->lists+channel;
+ color=65536L;
+ count=0;
+ do
+ {
+ color=list->nodes[color].next[0];
+ count+=list->nodes[color].count;
+ } while (count <= (ssize_t) (pixel_list->length >> 1));
+ channels[channel]=(unsigned short) color;
+ }
+ GetMagickPixelPacket((const Image *) NULL,&pixel);
+ pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
+ pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
+ pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
+ pixel.opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
+ pixel.index=(MagickRealType) ScaleShortToQuantum(channels[4]);
+ return(pixel);
+}
+
+static MagickPixelPacket GetMinimumPixelList(PixelList *pixel_list)
+{
+ MagickPixelPacket
+ pixel;
+
+ register SkipList
+ *list;
+
+ register ssize_t
+ channel;
+
+ size_t
+ color,
+ minimum;
+
+ ssize_t
+ count;
+
+ unsigned short
+ channels[ListChannels];
+
+ /*
+ Find the minimum value for each of the color.
+ */
+ for (channel=0; channel < 5; channel++)
+ {
+ list=pixel_list->lists+channel;
+ count=0;
+ color=65536UL;
+ minimum=list->nodes[color].next[0];
+ do
+ {
+ color=list->nodes[color].next[0];
+ if (color < minimum)
+ minimum=color;
+ count+=list->nodes[color].count;
+ } while (count < (ssize_t) pixel_list->length);
+ channels[channel]=(unsigned short) minimum;
+ }
+ GetMagickPixelPacket((const Image *) NULL,&pixel);
+ pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
+ pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
+ pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
+ pixel.opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
+ pixel.index=(MagickRealType) ScaleShortToQuantum(channels[4]);
+ return(pixel);
+}
+
+static MagickPixelPacket GetModePixelList(PixelList *pixel_list)
+{
+ MagickPixelPacket
+ pixel;
+
+ register SkipList
+ *list;
+
+ register ssize_t
+ channel;
+
+ size_t
+ color,
+ max_count,
+ mode;
+
+ ssize_t
+ count;
+
+ unsigned short
+ channels[5];
+
+ /*
+ Make each pixel the 'predominate color' of the specified neighborhood.
+ */
+ for (channel=0; channel < 5; channel++)
+ {
+ list=pixel_list->lists+channel;
+ color=65536L;
+ mode=color;
+ max_count=list->nodes[mode].count;
+ count=0;
+ do
+ {
+ color=list->nodes[color].next[0];
+ if (list->nodes[color].count > max_count)
+ {
+ mode=color;
+ max_count=list->nodes[mode].count;
+ }
+ count+=list->nodes[color].count;
+ } while (count < (ssize_t) pixel_list->length);
+ channels[channel]=(unsigned short) mode;
+ }
+ GetMagickPixelPacket((const Image *) NULL,&pixel);
+ pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
+ pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
+ pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
+ pixel.opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
+ pixel.index=(MagickRealType) ScaleShortToQuantum(channels[4]);
+ return(pixel);
+}
+
+static MagickPixelPacket GetNonpeakPixelList(PixelList *pixel_list)
+{
+ MagickPixelPacket
+ pixel;
+
+ register SkipList
+ *list;
+
+ register ssize_t
+ channel;
+
+ size_t
+ color,
+ next,
+ previous;
+
+ ssize_t
+ count;
+
+ unsigned short
+ channels[5];
+
+ /*
+ Finds the non peak value for each of the colors.
+ */
+ for (channel=0; channel < 5; channel++)
+ {
+ list=pixel_list->lists+channel;
+ color=65536L;
+ next=list->nodes[color].next[0];
+ count=0;
+ do
+ {
+ previous=color;
+ color=next;
+ next=list->nodes[color].next[0];
+ count+=list->nodes[color].count;
+ } while (count <= (ssize_t) (pixel_list->length >> 1));
+ if ((previous == 65536UL) && (next != 65536UL))
+ color=next;
+ else
+ if ((previous != 65536UL) && (next == 65536UL))
+ color=previous;
+ channels[channel]=(unsigned short) color;
+ }
+ GetMagickPixelPacket((const Image *) NULL,&pixel);
+ pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
+ pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
+ pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
+ pixel.opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
+ pixel.index=(MagickRealType) ScaleShortToQuantum(channels[4]);
+ return(pixel);
+}
+
+static MagickPixelPacket GetStandardDeviationPixelList(PixelList *pixel_list)
+{
+ MagickPixelPacket
+ pixel;
+
+ MagickRealType
+ sum,
+ sum_squared;
+
+ register SkipList
+ *list;
+
+ register ssize_t
+ channel;
+
+ size_t
+ color;
+
+ ssize_t
+ count;
+
+ unsigned short
+ channels[ListChannels];
+
+ /*
+ Find the standard-deviation value for each of the color.
+ */
+ for (channel=0; channel < 5; channel++)
+ {
+ list=pixel_list->lists+channel;
+ color=65536L;
+ count=0;
+ sum=0.0;
+ sum_squared=0.0;
+ do
+ {
+ register ssize_t
+ i;
+
+ color=list->nodes[color].next[0];
+ sum+=(MagickRealType) list->nodes[color].count*color;
+ for (i=0; i < (ssize_t) list->nodes[color].count; i++)
+ sum_squared+=((MagickRealType) color)*((MagickRealType) color);
+ count+=list->nodes[color].count;
+ } while (count < (ssize_t) pixel_list->length);
+ sum/=pixel_list->length;
+ sum_squared/=pixel_list->length;
+ channels[channel]=(unsigned short) sqrt(sum_squared-(sum*sum));
+ }
+ GetMagickPixelPacket((const Image *) NULL,&pixel);
+ pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
+ pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
+ pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
+ pixel.opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
+ pixel.index=(MagickRealType) ScaleShortToQuantum(channels[4]);
+ return(pixel);
+}
+
+static inline void InsertPixelList(const Image *image,const PixelPacket *pixel,
+ const IndexPacket *indexes,PixelList *pixel_list)
{
- Image
- *sharp_image;
+ size_t
+ signature;
- sharp_image=SharpenImageChannel(image,DefaultChannels,radius,sigma,exception);
- return(sharp_image);
+ unsigned short
+ index;
+
+ index=ScaleQuantumToShort(GetRedPixelComponent(pixel));
+ signature=pixel_list->lists[0].nodes[index].signature;
+ if (signature == pixel_list->signature)
+ pixel_list->lists[0].nodes[index].count++;
+ else
+ AddNodePixelList(pixel_list,0,index);
+ index=ScaleQuantumToShort(GetGreenPixelComponent(pixel));
+ signature=pixel_list->lists[1].nodes[index].signature;
+ if (signature == pixel_list->signature)
+ pixel_list->lists[1].nodes[index].count++;
+ else
+ AddNodePixelList(pixel_list,1,index);
+ index=ScaleQuantumToShort(GetBluePixelComponent(pixel));
+ signature=pixel_list->lists[2].nodes[index].signature;
+ if (signature == pixel_list->signature)
+ pixel_list->lists[2].nodes[index].count++;
+ else
+ AddNodePixelList(pixel_list,2,index);
+ index=ScaleQuantumToShort(GetOpacityPixelComponent(pixel));
+ signature=pixel_list->lists[3].nodes[index].signature;
+ if (signature == pixel_list->signature)
+ pixel_list->lists[3].nodes[index].count++;
+ else
+ AddNodePixelList(pixel_list,3,index);
+ if (image->colorspace == CMYKColorspace)
+ index=ScaleQuantumToShort(GetIndexPixelComponent(indexes));
+ signature=pixel_list->lists[4].nodes[index].signature;
+ if (signature == pixel_list->signature)
+ pixel_list->lists[4].nodes[index].count++;
+ else
+ AddNodePixelList(pixel_list,4,index);
}
-MagickExport Image *SharpenImageChannel(const Image *image,
- const ChannelType channel,const double radius,const double sigma,
- ExceptionInfo *exception)
+static inline MagickRealType MagickAbsoluteValue(const MagickRealType x)
{
- double
- *kernel,
- normalize;
+ if (x < 0)
+ return(-x);
+ return(x);
+}
- Image
- *sharp_image;
+static void ResetPixelList(PixelList *pixel_list)
+{
+ int
+ level;
- ssize_t
- j,
- u,
- v;
+ register ListNode
+ *root;
- register ssize_t
- i;
+ register SkipList
+ *list;
- size_t
- width;
+ register ssize_t
+ channel;
- assert(image != (const 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);
- width=GetOptimalKernelWidth2D(radius,sigma);
- kernel=(double *) AcquireQuantumMemory((size_t) width*width,sizeof(*kernel));
- if (kernel == (double *) NULL)
- ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
- normalize=0.0;
- j=(ssize_t) width/2;
- i=0;
- for (v=(-j); v <= j; v++)
+ /*
+ Reset the skip-list.
+ */
+ for (channel=0; channel < 5; channel++)
{
- for (u=(-j); u <= j; u++)
- {
- kernel[i]=(-exp(-((double) u*u+v*v)/(2.0*MagickSigma*MagickSigma))/
- (2.0*MagickPI*MagickSigma*MagickSigma));
- normalize+=kernel[i];
- i++;
- }
+ list=pixel_list->lists+channel;
+ root=list->nodes+65536UL;
+ list->level=0;
+ for (level=0; level < 9; level++)
+ root->next[level]=65536UL;
}
- kernel[i/2]=(double) ((-2.0)*normalize);
- sharp_image=ConvolveImageChannel(image,channel,width,kernel,exception);
- kernel=(double *) RelinquishMagickMemory(kernel);
- return(sharp_image);
+ pixel_list->seed=pixel_list->signature++;
}
-\f
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% %
-% %
-% %
-% S p r e a d I m a g e %
-% %
-% %
-% %
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%
-% SpreadImage() is a special effects method that randomly displaces each
-% pixel in a block defined by the radius parameter.
-%
-% The format of the SpreadImage method is:
-%
-% Image *SpreadImage(const Image *image,const double radius,
-% ExceptionInfo *exception)
-%
-% A description of each parameter follows:
-%
-% o image: the image.
-%
-% o radius: Choose a random pixel in a neighborhood of this extent.
-%
-% o exception: return any errors or warnings in this structure.
-%
-*/
-MagickExport Image *SpreadImage(const Image *image,const double radius,
- ExceptionInfo *exception)
+
+MagickExport Image *StatisticImage(const Image *image,const StatisticType type,
+ const size_t width,const size_t height,ExceptionInfo *exception)
{
-#define SpreadImageTag "Spread/Image"
+ Image
+ *statistic_image;
+
+ statistic_image=StatisticImageChannel(image,DefaultChannels,type,width,
+ height,exception);
+ return(statistic_image);
+}
+
+MagickExport Image *StatisticImageChannel(const Image *image,
+ const ChannelType channel,const StatisticType type,const size_t width,
+ const size_t height,ExceptionInfo *exception)
+{
+#define StatisticWidth \
+ (width == 0 ? GetOptimalKernelWidth2D((double) width,0.5) : width)
+#define StatisticHeight \
+ (height == 0 ? GetOptimalKernelWidth2D((double) height,0.5) : height)
+#define StatisticImageTag "Statistic/Image"
CacheView
- *image_view;
+ *image_view,
+ *statistic_view;
Image
- *spread_image;
+ *statistic_image;
MagickBooleanType
status;
MagickOffsetType
progress;
- MagickPixelPacket
- bias;
-
- RandomInfo
- **restrict random_info;
-
- ResampleFilter
- **restrict resample_filter;
-
- size_t
- width;
+ PixelList
+ **restrict pixel_list;
ssize_t
y;
/*
- Initialize spread image attributes.
+ Initialize statistics image attributes.
*/
assert(image != (Image *) NULL);
assert(image->signature == MagickSignature);
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
assert(exception != (ExceptionInfo *) NULL);
assert(exception->signature == MagickSignature);
- spread_image=CloneImage(image,image->columns,image->rows,MagickTrue,
+ statistic_image=CloneImage(image,image->columns,image->rows,MagickTrue,
exception);
- if (spread_image == (Image *) NULL)
+ if (statistic_image == (Image *) NULL)
return((Image *) NULL);
- if (SetImageStorageClass(spread_image,DirectClass) == MagickFalse)
+ if (SetImageStorageClass(statistic_image,DirectClass) == MagickFalse)
{
- InheritException(exception,&spread_image->exception);
- spread_image=DestroyImage(spread_image);
+ InheritException(exception,&statistic_image->exception);
+ statistic_image=DestroyImage(statistic_image);
return((Image *) NULL);
}
+ pixel_list=AcquirePixelListThreadSet(StatisticWidth,StatisticHeight);
+ if (pixel_list == (PixelList **) NULL)
+ {
+ statistic_image=DestroyImage(statistic_image);
+ ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+ }
/*
- Spread image.
+ Make each pixel the min / max / median / mode / etc. of the neighborhood.
*/
status=MagickTrue;
progress=0;
- GetMagickPixelPacket(spread_image,&bias);
- width=GetOptimalKernelWidth1D(radius,0.5);
- resample_filter=AcquireResampleFilterThreadSet(image,
- UndefinedVirtualPixelMethod,MagickTrue,exception);
- random_info=AcquireRandomInfoThreadSet();
- image_view=AcquireCacheView(spread_image);
-#if defined(MAGICKCORE_OPENMP_SUPPORT) && defined(MAGICKCORE_FUTURE)
+ image_view=AcquireCacheView(image);
+ statistic_view=AcquireCacheView(statistic_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
#pragma omp parallel for schedule(dynamic,4) shared(progress,status)
#endif
- for (y=0; y < (ssize_t) spread_image->rows; y++)
+ for (y=0; y < (ssize_t) statistic_image->rows; y++)
{
- MagickPixelPacket
- pixel;
+ const int
+ id = GetOpenMPThreadId();
- register IndexPacket
+ register const IndexPacket
*restrict indexes;
- register ssize_t
- id,
- x;
+ register const PixelPacket
+ *restrict p;
+
+ register IndexPacket
+ *restrict statistic_indexes;
register PixelPacket
*restrict q;
+ register ssize_t
+ x;
+
if (status == MagickFalse)
continue;
- q=QueueCacheViewAuthenticPixels(image_view,0,y,spread_image->columns,1,
- exception);
- if (q == (PixelPacket *) NULL)
+ p=GetCacheViewVirtualPixels(image_view,-((ssize_t) StatisticWidth/2L),y-
+ (ssize_t) (StatisticHeight/2L),image->columns+StatisticWidth,
+ StatisticHeight,exception);
+ q=QueueCacheViewAuthenticPixels(statistic_view,0,y,statistic_image->columns, 1,exception);
+ if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
{
status=MagickFalse;
continue;
}
- indexes=GetCacheViewAuthenticIndexQueue(image_view);
- pixel=bias;
- id=GetOpenMPThreadId();
- for (x=0; x < (ssize_t) spread_image->columns; x++)
+ indexes=GetCacheViewVirtualIndexQueue(image_view);
+ statistic_indexes=GetCacheViewAuthenticIndexQueue(statistic_view);
+ for (x=0; x < (ssize_t) statistic_image->columns; x++)
{
- (void) ResamplePixelColor(resample_filter[id],(double) x+width*
- (GetPseudoRandomValue(random_info[id])-0.5),(double) y+width*
- (GetPseudoRandomValue(random_info[id])-0.5),&pixel);
- SetPixelPacket(spread_image,&pixel,q,indexes+x);
+ MagickPixelPacket
+ pixel;
+
+ register const IndexPacket
+ *restrict s;
+
+ register const PixelPacket
+ *restrict r;
+
+ register ssize_t
+ u,
+ v;
+
+ r=p;
+ s=indexes+x;
+ ResetPixelList(pixel_list[id]);
+ for (v=0; v < (ssize_t) StatisticHeight; v++)
+ {
+ for (u=0; u < (ssize_t) StatisticWidth; u++)
+ InsertPixelList(image,r+u,s+u,pixel_list[id]);
+ r+=image->columns+StatisticWidth;
+ s+=image->columns+StatisticWidth;
+ }
+ GetMagickPixelPacket(image,&pixel);
+ SetMagickPixelPacket(image,p+StatisticWidth*StatisticHeight/2,indexes+
+ StatisticWidth*StatisticHeight/2+x,&pixel);
+ switch (type)
+ {
+ case GradientStatistic:
+ {
+ MagickPixelPacket
+ maximum,
+ minimum;
+
+ minimum=GetMinimumPixelList(pixel_list[id]);
+ maximum=GetMaximumPixelList(pixel_list[id]);
+ pixel.red=MagickAbsoluteValue(maximum.red-minimum.red);
+ pixel.green=MagickAbsoluteValue(maximum.green-minimum.green);
+ pixel.blue=MagickAbsoluteValue(maximum.blue-minimum.blue);
+ pixel.opacity=MagickAbsoluteValue(maximum.opacity-minimum.opacity);
+ if (image->colorspace == CMYKColorspace)
+ pixel.index=MagickAbsoluteValue(maximum.index-minimum.index);
+ break;
+ }
+ case MaximumStatistic:
+ {
+ pixel=GetMaximumPixelList(pixel_list[id]);
+ break;
+ }
+ case MeanStatistic:
+ {
+ pixel=GetMeanPixelList(pixel_list[id]);
+ break;
+ }
+ case MedianStatistic:
+ default:
+ {
+ pixel=GetMedianPixelList(pixel_list[id]);
+ break;
+ }
+ case MinimumStatistic:
+ {
+ pixel=GetMinimumPixelList(pixel_list[id]);
+ break;
+ }
+ case ModeStatistic:
+ {
+ pixel=GetModePixelList(pixel_list[id]);
+ break;
+ }
+ case NonpeakStatistic:
+ {
+ pixel=GetNonpeakPixelList(pixel_list[id]);
+ break;
+ }
+ case StandardDeviationStatistic:
+ {
+ pixel=GetStandardDeviationPixelList(pixel_list[id]);
+ break;
+ }
+ }
+ if ((channel & RedChannel) != 0)
+ SetRedPixelComponent(q,ClampToQuantum(pixel.red));
+ if ((channel & GreenChannel) != 0)
+ SetGreenPixelComponent(q,ClampToQuantum(pixel.green));
+ if ((channel & BlueChannel) != 0)
+ SetBluePixelComponent(q,ClampToQuantum(pixel.blue));
+ if (((channel & OpacityChannel) != 0) &&
+ (image->matte != MagickFalse))
+ SetOpacityPixelComponent(q,ClampToQuantum(pixel.opacity));
+ if (((channel & IndexChannel) != 0) &&
+ (image->colorspace == CMYKColorspace))
+ SetIndexPixelComponent(statistic_indexes+x,ClampToQuantum(pixel.index));
+ p++;
q++;
}
- if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+ if (SyncCacheViewAuthenticPixels(statistic_view,exception) == MagickFalse)
status=MagickFalse;
if (image->progress_monitor != (MagickProgressMonitor) NULL)
{
MagickBooleanType
proceed;
-#if defined(MAGICKCORE_OPENMP_SUPPORT) && defined(MAGICKCORE_FUTURE)
- #pragma omp critical (MagickCore_SpreadImage)
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+ #pragma omp critical (MagickCore_StatisticImage)
#endif
- proceed=SetImageProgress(image,SpreadImageTag,progress++,image->rows);
+ proceed=SetImageProgress(image,StatisticImageTag,progress++,
+ image->rows);
if (proceed == MagickFalse)
status=MagickFalse;
}
}
+ statistic_view=DestroyCacheView(statistic_view);
image_view=DestroyCacheView(image_view);
- random_info=DestroyRandomInfoThreadSet(random_info);
- resample_filter=DestroyResampleFilterThreadSet(resample_filter);
- return(spread_image);
+ pixel_list=DestroyPixelListThreadSet(pixel_list);
+ return(statistic_image);
}
\f
/*
register IndexPacket
*restrict unsharp_indexes;
- register ssize_t
- x;
-
register PixelPacket
*restrict q;
+ register ssize_t
+ x;
+
if (status == MagickFalse)
continue;
p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
{
if ((channel & RedChannel) != 0)
{
- pixel.red=p->red-(MagickRealType) q->red;
+ pixel.red=GetRedPixelComponent(p)-(MagickRealType)
+ GetRedPixelComponent(q);
if (fabs(2.0*pixel.red) < quantum_threshold)
pixel.red=(MagickRealType) GetRedPixelComponent(p);
else
- pixel.red=(MagickRealType) p->red+(pixel.red*amount);
- SetRedPixelComponent(q,ClampRedPixelComponent(&pixel));
+ pixel.red=(MagickRealType) GetRedPixelComponent(p)+
+ (pixel.red*amount);
+ SetRedPixelComponent(q,ClampToQuantum(pixel.red));
}
if ((channel & GreenChannel) != 0)
{
- pixel.green=p->green-(MagickRealType) q->green;
+ pixel.green=GetGreenPixelComponent(p)-(MagickRealType) q->green;
if (fabs(2.0*pixel.green) < quantum_threshold)
pixel.green=(MagickRealType) GetGreenPixelComponent(p);
else
- pixel.green=(MagickRealType) p->green+(pixel.green*amount);
- SetGreenPixelComponent(q,ClampGreenPixelComponent(&pixel));
+ pixel.green=(MagickRealType) GetGreenPixelComponent(p)+(pixel.green*amount);
+ SetGreenPixelComponent(q,ClampToQuantum(pixel.green));
}
if ((channel & BlueChannel) != 0)
{
- pixel.blue=p->blue-(MagickRealType) q->blue;
+ pixel.blue=GetBluePixelComponent(p)-(MagickRealType) q->blue;
if (fabs(2.0*pixel.blue) < quantum_threshold)
pixel.blue=(MagickRealType) GetBluePixelComponent(p);
else
- pixel.blue=(MagickRealType) p->blue+(pixel.blue*amount);
- SetBluePixelComponent(q,ClampBluePixelComponent(&pixel));
+ pixel.blue=(MagickRealType) GetBluePixelComponent(p)+(pixel.blue*amount);
+ SetBluePixelComponent(q,ClampToQuantum(pixel.blue));
}
if ((channel & OpacityChannel) != 0)
{
- pixel.opacity=p->opacity-(MagickRealType) q->opacity;
+ pixel.opacity=GetOpacityPixelComponent(p)-(MagickRealType) q->opacity;
if (fabs(2.0*pixel.opacity) < quantum_threshold)
pixel.opacity=(MagickRealType) GetOpacityPixelComponent(p);
else
- pixel.opacity=p->opacity+(pixel.opacity*amount);
- SetOpacityPixelComponent(q,ClampOpacityPixelComponent(&pixel));
+ pixel.opacity=GetOpacityPixelComponent(p)+(pixel.opacity*amount);
+ SetOpacityPixelComponent(q,ClampToQuantum(pixel.opacity));
}
if (((channel & IndexChannel) != 0) &&
(image->colorspace == CMYKColorspace))
{
- pixel.index=unsharp_indexes[x]-(MagickRealType) indexes[x];
+ pixel.index=GetIndexPixelComponent(indexes+x)-(MagickRealType)
+ GetIndexPixelComponent(unsharp_indexes+x);
if (fabs(2.0*pixel.index) < quantum_threshold)
- pixel.index=(MagickRealType) unsharp_indexes[x];
+ pixel.index=(MagickRealType) GetIndexPixelComponent(indexes+x);
else
- pixel.index=(MagickRealType) unsharp_indexes[x]+(pixel.index*
- amount);
- unsharp_indexes[x]=ClampToQuantum(pixel.index);
+ pixel.index=(MagickRealType) GetIndexPixelComponent(indexes+x)+
+ (pixel.index*amount);
+ SetIndexPixelComponent(unsharp_indexes+x,ClampToQuantum(pixel.index));
}
p++;
q++;