% January 2010 %
% %
% %
-% Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization %
+% Copyright 1999-2014 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 %
#include "MagickCore/studio.h"
#include "MagickCore/artifact.h"
#include "MagickCore/cache-view.h"
+#include "MagickCore/channel.h"
#include "MagickCore/color-private.h"
#include "MagickCore/enhance.h"
#include "MagickCore/exception.h"
static inline KernelInfo *LastKernelInfo(KernelInfo *kernel)
{
while (kernel->next != (KernelInfo *) NULL)
- kernel = kernel->next;
+ kernel=kernel->next;
return(kernel);
}
kernel->width,kernel->height*sizeof(*kernel->values)));
if (kernel->values == (MagickRealType *) NULL)
return(DestroyKernelInfo(kernel));
- kernel->minimum = +MagickHuge;
- kernel->maximum = -MagickHuge;
+ kernel->minimum=MagickMaximumValue;
+ kernel->maximum=(-MagickMaximumValue);
kernel->negative_range = kernel->positive_range = 0.0;
for (i=0; (i < (ssize_t) (kernel->width*kernel->height)) && (p < end); i++)
{
#endif
/* check that we recieved at least one real (non-nan) value! */
- if ( kernel->minimum == MagickHuge )
+ if (kernel->minimum == MagickMaximumValue)
return(DestroyKernelInfo(kernel));
if ( (flags & AreaValue) != 0 ) /* '@' symbol in kernel size */
MagickExport KernelInfo *AcquireKernelInfo(const char *kernel_string)
{
-
KernelInfo
*kernel,
*new_kernel;
const char
*p;
- size_t
- kernel_number;
-
if (kernel_string == (const char *) NULL)
return(ParseKernelArray(kernel_string));
- p = kernel_string;
- kernel = NULL;
- kernel_number = 0;
-
- while ( GetMagickToken(p,NULL,token), *token != '\0' ) {
+ p=kernel_string;
+ kernel=NULL;
+ while (GetMagickToken(p,NULL,token), *token != '\0')
+ {
/* ignore extra or multiple ';' kernel separators */
- if ( *token != ';' ) {
-
- /* tokens starting with alpha is a Named kernel */
- if (isalpha((int) *token) != 0)
- new_kernel = ParseKernelName(p);
- else /* otherwise a user defined kernel array */
- new_kernel = ParseKernelArray(p);
-
- /* Error handling -- this is not proper error handling! */
- if ( new_kernel == (KernelInfo *) NULL ) {
- (void) FormatLocaleFile(stderr,"Failed to parse kernel number #%.20g\n",
- (double) kernel_number);
- if ( kernel != (KernelInfo *) NULL )
- kernel=DestroyKernelInfo(kernel);
- return((KernelInfo *) NULL);
- }
+ if (*token != ';')
+ {
+ /* tokens starting with alpha is a Named kernel */
+ if (isalpha((int) ((unsigned char) *token)) != 0)
+ new_kernel=ParseKernelName(p);
+ else /* otherwise a user defined kernel array */
+ new_kernel=ParseKernelArray(p);
+
+ /* Error handling -- this is not proper error handling! */
+ if (new_kernel == (KernelInfo *) NULL)
+ {
+ if (kernel != (KernelInfo *) NULL)
+ kernel=DestroyKernelInfo(kernel);
+ return((KernelInfo *) NULL);
+ }
- /* initialise or append the kernel list */
- if ( kernel == (KernelInfo *) NULL )
- kernel = new_kernel;
- else
- LastKernelInfo(kernel)->next = new_kernel;
- }
+ /* initialise or append the kernel list */
+ if (kernel == (KernelInfo *) NULL)
+ kernel=new_kernel;
+ else
+ LastKernelInfo(kernel)->next=new_kernel;
+ }
/* look for the next kernel in list */
- p = strchr(p, ';');
- if ( p == (char *) NULL )
+ p=strchr(p,';');
+ if (p == (char *) NULL)
break;
p++;
-
}
return(kernel);
}
MagickExport KernelInfo *DestroyKernelInfo(KernelInfo *kernel)
{
assert(kernel != (KernelInfo *) NULL);
- if ( kernel->next != (KernelInfo *) NULL )
+ if (kernel->next != (KernelInfo *) NULL)
kernel->next=DestroyKernelInfo(kernel->next);
kernel->values=(MagickRealType *) RelinquishAlignedMemory(kernel->values);
kernel=(KernelInfo *) RelinquishMagickMemory(kernel);
*last;
last = kernel;
+DisableMSCWarning(4127)
while(1) {
+RestoreMSCWarning
clone = CloneKernelInfo(last);
RotateKernelInfo(clone, angle);
- if ( SameKernelInfo(kernel, clone) == MagickTrue )
+ if ( SameKernelInfo(kernel, clone) != MagickFalse )
break;
LastKernelInfo(last)->next = clone;
last = clone;
OffsetInfo
offset;
+ register ssize_t
+ i;
+
ssize_t
y;
size_t
- width,
- changed;
+ *changes,
+ changed,
+ width;
MagickBooleanType
status;
assert(exception != (ExceptionInfo *) NULL);
assert(exception->signature == MagickSignature);
status=MagickTrue;
- changed=0;
progress=0;
image_view=AcquireVirtualCacheView(image,exception);
morphology_view=AcquireAuthenticCacheView(morphology_image,exception);
width=image->columns+kernel->width-1;
+ offset.x=0.0;
+ offset.y=0.0;
switch (method)
{
case ConvolveMorphology:
break;
}
}
+ changed=0;
+ changes=(size_t *) AcquireQuantumMemory(GetOpenMPMaximumThreads(),
+ sizeof(*changes));
+ if (changes == (size_t *) NULL)
+ ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+ for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
+ changes[i]=0;
if ((method == ConvolveMorphology) && (kernel->width == 1))
{
+ const int
+ id = GetOpenMPThreadId();
+
register ssize_t
x;
vertical kernels (such as a 'BlurKernel')
*/
#if defined(MAGICKCORE_OPENMP_SUPPORT)
- #pragma omp parallel for schedule(static,4) shared(changed,progress,status) \
+ #pragma omp parallel for schedule(static,4) shared(progress,status) \
magick_threads(image,morphology_image,image->columns,1)
#endif
for (x=0; x < (ssize_t) image->columns; x++)
{
double
alpha,
+ gamma,
pixel;
PixelChannel
register ssize_t
u;
+ size_t
+ count;
+
ssize_t
v;
k=(&kernel->values[kernel->width*kernel->height-1]);
pixels=p;
pixel=bias;
+ count=0;
if ((morphology_traits & BlendPixelTrait) == 0)
{
/*
for (u=0; u < (ssize_t) kernel->width; u++)
{
if (IfNaN(*k) == MagickFalse)
- pixel+=(*k)*pixels[i];
+ {
+ pixel+=(*k)*pixels[i];
+ count++;
+ }
k--;
pixels+=GetPixelChannels(image);
}
}
- #pragma omp critical (MagickCore_MorphologyPrimitive)
if (fabs(pixel-p[center+i]) > MagickEpsilon)
- changed++;
- SetPixelChannel(morphology_image,channel,ClampToQuantum(pixel),
- q);
+ changes[id]++;
+ gamma=(double) kernel->height*kernel->width/count;
+ SetPixelChannel(morphology_image,channel,ClampToQuantum(gamma*
+ pixel),q);
continue;
}
/*
Alpha blending.
*/
+ gamma=0.0;
for (v=0; v < (ssize_t) kernel->height; v++)
{
for (u=0; u < (ssize_t) kernel->width; u++)
{
alpha=(double) (QuantumScale*GetPixelAlpha(image,pixels));
pixel+=(*k)*alpha*pixels[i];
+ gamma+=(*k)*alpha;
+ count++;
}
k--;
pixels+=GetPixelChannels(image);
}
}
- #pragma omp critical (MagickCore_MorphologyPrimitive)
if (fabs(pixel-p[center+i]) > MagickEpsilon)
- changed++;
- SetPixelChannel(morphology_image,channel,ClampToQuantum(pixel),q);
+ changes[id]++;
+ gamma=PerceptibleReciprocal(gamma);
+ gamma*=(double) kernel->height*kernel->width/count;
+ SetPixelChannel(morphology_image,channel,ClampToQuantum(gamma*
+ pixel),q);
}
p+=GetPixelChannels(image);
q+=GetPixelChannels(morphology_image);
morphology_image->type=image->type;
morphology_view=DestroyCacheView(morphology_view);
image_view=DestroyCacheView(image_view);
+ for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
+ changed+=changes[i];
+ changes=(size_t *) RelinquishMagickMemory(changes);
return(status ? (ssize_t) changed : 0);
}
/*
Normal handling of horizontal or rectangular kernels (row by row).
*/
#if defined(MAGICKCORE_OPENMP_SUPPORT)
- #pragma omp parallel for schedule(static,4) shared(changed,progress,status) \
+ #pragma omp parallel for schedule(static,4) shared(progress,status) \
magick_threads(image,morphology_image,image->rows,1)
#endif
for (y=0; y < (ssize_t) image->rows; y++)
{
+ const int
+ id = GetOpenMPThreadId();
+
register const Quantum
*restrict p;
{
double
alpha,
+ gamma,
maximum,
minimum,
pixel;
register ssize_t
u;
+ size_t
+ count;
+
ssize_t
v;
pixels=p;
maximum=0.0;
minimum=(double) QuantumRange;
+ count=kernel->width*kernel->height;
switch (method)
{
case ConvolveMorphology: pixel=bias; break;
}
default: pixel=0; break;
}
+ gamma=1.0;
switch (method)
{
case ConvolveMorphology:
http://www.cs.umd.edu/~djacobs/CMSC426/Convolution.pdf
*/
k=(&kernel->values[kernel->width*kernel->height-1]);
+ count=0;
if ((morphology_traits & BlendPixelTrait) == 0)
{
/*
for (u=0; u < (ssize_t) kernel->width; u++)
{
if (IfNaN(*k) == MagickFalse)
- pixel+=(*k)*pixels[i];
+ {
+ pixel+=(*k)*pixels[i];
+ count++;
+ }
k--;
pixels+=GetPixelChannels(image);
}
{
alpha=(double) (QuantumScale*GetPixelAlpha(image,pixels));
pixel+=(*k)*alpha*pixels[i];
+ gamma+=(*k)*alpha;
+ count++;
}
k--;
pixels+=GetPixelChannels(image);
added to the real value, this is currently not done, due to the
nature of the boolean kernels being used.
*/
+ count=0;
k=(&kernel->values[kernel->width*kernel->height-1]);
for (v=0; v < (ssize_t) kernel->height; v++)
{
{
if ((double) pixels[i] > pixel)
pixel=(double) pixels[i];
+ count++;
}
k--;
pixels+=GetPixelChannels(image);
cause Thinning/Thicken to not work correctly when used against a
greyscale image.
*/
+ count=0;
k=kernel->values;
for (v=0; v < (ssize_t) kernel->height; v++)
{
if ((double) pixels[i] > maximum)
maximum=(double) pixels[i];
}
+ count++;
}
k++;
pixels+=GetPixelChannels(image);
The kernel is not reflected for this operation.
*/
+ count=0;
k=kernel->values;
for (v=0; v < (ssize_t) kernel->height; v++)
{
pixel=(double) pixels[i];
minimum=GetPixelIntensity(image,pixels);
}
+ count++;
}
k++;
pixels+=GetPixelChannels(image);
The kernel is not reflected for this operation.
*/
+ count=0;
k=(&kernel->values[kernel->width*kernel->height-1]);
for (v=0; v < (ssize_t) kernel->height; v++)
{
pixel=(double) pixels[i];
maximum=GetPixelIntensity(image,pixels);
}
+ count++;
}
k--;
pixels+=GetPixelChannels(image);
GrayErode, but with negative kernel values, and kernel rotation
applied.
*/
+ count=0;
k=(&kernel->values[kernel->width*kernel->height-1]);
for (v=0; v < (ssize_t) kernel->height; v++)
{
{
if ((pixels[i]+(*k)) < pixel)
pixel=(double) pixels[i]+(*k);
+ count++;
}
k--;
pixels+=GetPixelChannels(image);
default:
break;
}
- #pragma omp critical (MagickCore_MorphologyPrimitive)
if (fabs(pixel-p[center+i]) > MagickEpsilon)
- changed++;
- SetPixelChannel(morphology_image,channel,ClampToQuantum(pixel),q);
+ changes[id]++;
+ gamma=PerceptibleReciprocal(gamma);
+ gamma*=(double) kernel->height*kernel->width/count;
+ SetPixelChannel(morphology_image,channel,ClampToQuantum(gamma*pixel),q);
}
p+=GetPixelChannels(image);
q+=GetPixelChannels(morphology_image);
}
morphology_view=DestroyCacheView(morphology_view);
image_view=DestroyCacheView(image_view);
- return(status ? (ssize_t)changed : -1);
+ for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
+ changed+=changes[i];
+ changes=(size_t *) RelinquishMagickMemory(changes);
+ return(status ? (ssize_t) changed : -1);
}
/*
ssize_t
v;
- traits=GetPixelChannelTraits(image,i);
+ traits=GetPixelChannelTraits(image,(PixelChannel) i);
if (traits == UndefinedPixelTrait)
continue;
if (((traits & CopyPixelTrait) != 0) ||
ssize_t
v;
- traits=GetPixelChannelTraits(image,i);
+ traits=GetPixelChannelTraits(image,(PixelChannel) i);
if (traits == UndefinedPixelTrait)
continue;
if (((traits & CopyPixelTrait) != 0) ||
- (GetPixelReadMask(image,p+center) == 0))
+ (GetPixelReadMask(image,p+center) == 0))
continue;
pixels=p;
pixel=(double) QuantumRange;
changed; /* number pixels changed by last primitive operation */
char
- v_info[80];
+ v_info[MaxTextExtent];
assert(image != (Image *) NULL);
assert(image->signature == MagickSignature);
if ( iterations < 0 ) /* negative interations = infinite (well alomst) */
kernel_limit = image->columns>image->rows ? image->columns : image->rows;
- verbose = IsStringTrue(GetImageArtifact(image,"verbose"));
+ verbose = IsStringTrue(GetImageArtifact(image,"debug"));
/* initialise for cleanup */
curr_image = (Image *) image;
/* Apply special methods with special requirments
** For example, single run only, or post-processing requirements
*/
- if ( special == MagickTrue )
+ if ( special != MagickFalse )
{
rslt_image=CloneImage(image,0,0,MagickTrue,exception);
if (rslt_image == (Image *) NULL)
}
if ( changed < 0 )
goto error_cleanup;
- #pragma omp flush(changed)
kernel_changed += changed;
method_changed += changed;