52#include "MagickCore/studio.h"
53#include "MagickCore/artifact.h"
54#include "MagickCore/cache-view.h"
55#include "MagickCore/channel.h"
56#include "MagickCore/color-private.h"
57#include "MagickCore/enhance.h"
58#include "MagickCore/exception.h"
59#include "MagickCore/exception-private.h"
60#include "MagickCore/gem.h"
61#include "MagickCore/gem-private.h"
62#include "MagickCore/image.h"
63#include "MagickCore/image-private.h"
64#include "MagickCore/linked-list.h"
65#include "MagickCore/list.h"
66#include "MagickCore/magick.h"
67#include "MagickCore/memory_.h"
68#include "MagickCore/memory-private.h"
69#include "MagickCore/monitor-private.h"
70#include "MagickCore/morphology.h"
71#include "MagickCore/morphology-private.h"
72#include "MagickCore/option.h"
73#include "MagickCore/pixel-accessor.h"
74#include "MagickCore/prepress.h"
75#include "MagickCore/quantize.h"
76#include "MagickCore/resource_.h"
77#include "MagickCore/registry.h"
78#include "MagickCore/semaphore.h"
79#include "MagickCore/splay-tree.h"
80#include "MagickCore/statistic.h"
81#include "MagickCore/string_.h"
82#include "MagickCore/string-private.h"
83#include "MagickCore/thread-private.h"
84#include "MagickCore/token.h"
85#include "MagickCore/utility.h"
86#include "MagickCore/utility-private.h"
91#define Minimize(assign,value) assign=MagickMin(assign,value)
92#define Maximize(assign,value) assign=MagickMax(assign,value)
95static inline size_t fact(
size_t n)
98 for(f=1, l=2; l <= n; f=f*l, l++);
104 CalcKernelMetaData(KernelInfo *),
105 ExpandMirrorKernelInfo(KernelInfo *),
106 ExpandRotateKernelInfo(KernelInfo *,
const double),
107 RotateKernelInfo(KernelInfo *,
double);
111static inline KernelInfo *LastKernelInfo(KernelInfo *kernel)
113 while (kernel->next != (KernelInfo *) NULL)
203static inline MagickBooleanType AcquireKernelValues(KernelInfo *kernel)
208 kernel->values=(MagickRealType *) NULL;
209 if (HeapOverflowSanityCheckGetSize(kernel->width,kernel->height,&elements) != MagickFalse)
211 kernel->values=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory(
212 elements,
sizeof(*kernel->values)));
213 return(kernel->values == (MagickRealType *) NULL ? MagickFalse : MagickTrue);
219static KernelInfo *ParseKernelArray(
const char *kernel_string)
225 token[MagickPathExtent];
246 kernel=(KernelInfo *) AcquireMagickMemory(
sizeof(*kernel));
247 if (kernel == (KernelInfo *) NULL)
249 (void) memset(kernel,0,
sizeof(*kernel));
250 kernel->minimum = kernel->maximum = kernel->angle = 0.0;
251 kernel->negative_range = kernel->positive_range = 0.0;
252 kernel->type = UserDefinedKernel;
253 kernel->next = (KernelInfo *) NULL;
254 kernel->signature=MagickCoreSignature;
255 if (kernel_string == (
const char *) NULL)
259 end = strchr(kernel_string,
';');
260 if ( end == (
char *) NULL )
261 end = strchr(kernel_string,
'\0');
269 p = strchr(kernel_string,
':');
270 if ( p != (
char *) NULL && p < end)
273 length=MagickMin((
size_t) (p-kernel_string),
sizeof(token)-1);
274 (void) memcpy(token, kernel_string, length);
275 token[length] =
'\0';
276 SetGeometryInfo(&args);
277 flags = ParseGeometry(token, &args);
280 if ( (flags & WidthValue) == 0 )
281 args.rho = args.sigma;
282 if ( args.rho < 1.0 )
284 if ( args.sigma < 1.0 )
285 args.sigma = args.rho;
286 kernel->width = CastDoubleToSizeT(args.rho);
287 kernel->height = CastDoubleToSizeT(args.sigma);
290 if ( args.xi < 0.0 || args.psi < 0.0 )
291 return(DestroyKernelInfo(kernel));
292 kernel->x = ((flags & XValue)!=0) ? (ssize_t)args.xi
293 : (ssize_t) (kernel->width-1)/2;
294 kernel->y = ((flags & YValue)!=0) ? (ssize_t)args.psi
295 : (ssize_t) (kernel->height-1)/2;
296 if ( kernel->x >= (ssize_t) kernel->width ||
297 kernel->y >= (ssize_t) kernel->height )
298 return(DestroyKernelInfo(kernel));
305 p=(
const char *) kernel_string;
306 while ((isspace((
int) ((
unsigned char) *p)) != 0) || (*p ==
'\''))
308 for (i=0; p < end; i++)
310 (void) GetNextToken(p,&p,MagickPathExtent,token);
312 (void) GetNextToken(p,&p,MagickPathExtent,token);
315 kernel->width = kernel->height=CastDoubleToSizeT(sqrt((
double) i+1.0));
316 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
317 p=(
const char *) kernel_string;
318 while ((isspace((
int) ((
unsigned char) *p)) != 0) || (*p ==
'\''))
323 if (AcquireKernelValues(kernel) == MagickFalse)
324 return(DestroyKernelInfo(kernel));
325 kernel->minimum=MagickMaximumValue;
326 kernel->maximum=(-MagickMaximumValue);
327 kernel->negative_range = kernel->positive_range = 0.0;
328 for (i=0; (i < (ssize_t) (kernel->width*kernel->height)) && (p < end); i++)
330 (void) GetNextToken(p,&p,MagickPathExtent,token);
332 (void) GetNextToken(p,&p,MagickPathExtent,token);
333 if ( LocaleCompare(
"nan",token) == 0
334 || LocaleCompare(
"-",token) == 0 ) {
335 kernel->values[i] = nan;
338 kernel->values[i] = StringToDouble(token,(
char **) NULL);
339 ( kernel->values[i] < 0)
340 ? ( kernel->negative_range += kernel->values[i] )
341 : ( kernel->positive_range += kernel->values[i] );
342 Minimize(kernel->minimum, kernel->values[i]);
343 Maximize(kernel->maximum, kernel->values[i]);
348 (void) GetNextToken(p,&p,MagickPathExtent,token);
349 if ( *token !=
'\0' && *token !=
';' && *token !=
'\'' )
350 return(DestroyKernelInfo(kernel));
354 if ( i < (ssize_t) (kernel->width*kernel->height) ) {
355 Minimize(kernel->minimum, kernel->values[i]);
356 Maximize(kernel->maximum, kernel->values[i]);
357 for ( ; i < (ssize_t) (kernel->width*kernel->height); i++)
358 kernel->values[i]=0.0;
362 if ( i < (ssize_t) (kernel->width*kernel->height) )
363 return(DestroyKernelInfo(kernel));
367 if (kernel->minimum == MagickMaximumValue)
368 return(DestroyKernelInfo(kernel));
370 if ( (flags & AreaValue) != 0 )
371 ExpandRotateKernelInfo(kernel, 45.0);
372 else if ( (flags & GreaterValue) != 0 )
373 ExpandRotateKernelInfo(kernel, 90.0);
374 else if ( (flags & LessValue) != 0 )
375 ExpandMirrorKernelInfo(kernel);
380static KernelInfo *ParseKernelName(
const char *kernel_string,
381 ExceptionInfo *exception)
384 token[MagickPathExtent] =
"";
406 (void) GetNextToken(kernel_string,&p,MagickPathExtent,token);
407 type=ParseCommandOption(MagickKernelOptions,MagickFalse,token);
408 if ( type < 0 || type == UserDefinedKernel )
409 return((KernelInfo *) NULL);
411 while (((isspace((
int) ((
unsigned char) *p)) != 0) ||
412 (*p ==
',') || (*p ==
':' )) && (*p !=
'\0') && (*p !=
';'))
415 end = strchr(p,
';');
416 if ( end == (
char *) NULL )
417 end = strchr(p,
'\0');
420 length=MagickMin((
size_t) (end-p),
sizeof(token)-1);
421 (void) memcpy(token, p, length);
422 token[length] =
'\0';
423 SetGeometryInfo(&args);
424 flags = ParseGeometry(token, &args);
428 (void) FormatLocaleFile(stderr,
"Geometry = 0x%04X : %lg x %lg %+lg %+lg\n",
429 flags, args.rho, args.sigma, args.xi, args.psi );
436 if ( (flags & WidthValue) == 0 )
445 if ( (flags & HeightValue) == 0 )
449 if ( (flags & XValue) == 0 )
452 case RectangleKernel:
453 if ( (flags & WidthValue) == 0 )
454 args.rho = args.sigma;
455 if ( args.rho < 1.0 )
457 if ( args.sigma < 1.0 )
458 args.sigma = args.rho;
459 if ( (flags & XValue) == 0 )
460 args.xi = (double)(((ssize_t)args.rho-1)/2);
461 if ( (flags & YValue) == 0 )
462 args.psi = (double)(((ssize_t)args.sigma-1)/2);
465 case ChebyshevKernel:
466 case ManhattanKernel:
467 case OctagonalKernel:
468 case EuclideanKernel:
469 if ( (flags & HeightValue) == 0 )
471 else if ( (flags & AspectValue ) != 0 )
472 args.sigma = (double) QuantumRange/(args.sigma+1);
473 else if ( (flags & PercentValue ) != 0 )
474 args.sigma *= (double) QuantumRange/100.0;
480 kernel = AcquireKernelBuiltIn((KernelInfoType)type, &args, exception);
481 if ( kernel == (KernelInfo *) NULL )
485 if ( kernel->next == (KernelInfo *) NULL ) {
486 if ( (flags & AreaValue) != 0 )
487 ExpandRotateKernelInfo(kernel, 45.0);
488 else if ( (flags & GreaterValue) != 0 )
489 ExpandRotateKernelInfo(kernel, 90.0);
490 else if ( (flags & LessValue) != 0 )
491 ExpandMirrorKernelInfo(kernel);
497MagickExport KernelInfo *AcquireKernelInfo(
const char *kernel_string,
498 ExceptionInfo *exception)
506 token[MagickPathExtent];
511 if (kernel_string == (
const char *) NULL)
512 return(ParseKernelArray(kernel_string));
514 kernel_cache=(
char *) NULL;
515 if (*kernel_string ==
'@')
517 kernel_cache=FileToString(kernel_string,~0UL,exception);
518 if (kernel_cache == (
char *) NULL)
519 return((KernelInfo *) NULL);
520 p=(
const char *) kernel_cache;
523 while (GetNextToken(p,(
const char **) NULL,MagickPathExtent,token), *token !=
'\0')
529 if (isalpha((
int) ((
unsigned char) *token)) != 0)
530 new_kernel=ParseKernelName(p,exception);
532 new_kernel=ParseKernelArray(p);
535 if (new_kernel == (KernelInfo *) NULL)
537 if (kernel != (KernelInfo *) NULL)
538 kernel=DestroyKernelInfo(kernel);
539 return((KernelInfo *) NULL);
543 if (kernel == (KernelInfo *) NULL)
546 LastKernelInfo(kernel)->next=new_kernel;
551 if (p == (
char *) NULL)
555 if (kernel_cache != (
char *) NULL)
556 kernel_cache=DestroyString(kernel_cache);
962MagickExport KernelInfo *AcquireKernelBuiltIn(
const KernelInfoType type,
963 const GeometryInfo *args,ExceptionInfo *exception)
979 kernel=(KernelInfo *) NULL;
981 case UndefinedKernel:
982 case UserDefinedKernel:
983 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
984 "InvalidOption",
"`%s'",
"Should not call this function");
985 return((KernelInfo *) NULL);
986 case LaplacianKernel:
995 case DiagonalsKernel:
997 case LineJunctionsKernel:
999 case ConvexHullKernel:
1000 case SkeletonKernel:
1006 case GaussianKernel:
1011 case BinomialKernel:
1014 case RectangleKernel:
1021 case ChebyshevKernel:
1022 case ManhattanKernel:
1023 case OctagonalKernel:
1024 case EuclideanKernel:
1029 kernel=(KernelInfo *) AcquireMagickMemory(
sizeof(*kernel));
1030 if (kernel == (KernelInfo *) NULL)
1032 (void) memset(kernel,0,
sizeof(*kernel));
1033 kernel->minimum = kernel->maximum = kernel->angle = 0.0;
1034 kernel->negative_range = kernel->positive_range = 0.0;
1035 kernel->type = type;
1036 kernel->next = (KernelInfo *) NULL;
1037 kernel->signature=MagickCoreSignature;
1047 kernel->height = kernel->width = (size_t) 1;
1048 kernel->x = kernel->y = (ssize_t) 0;
1049 kernel->values=(MagickRealType *) MagickAssumeAligned(
1050 AcquireAlignedMemory(1,
sizeof(*kernel->values)));
1051 if (kernel->values == (MagickRealType *) NULL)
1052 return(DestroyKernelInfo(kernel));
1053 kernel->maximum = kernel->values[0] = args->rho;
1057 case GaussianKernel:
1061 sigma = fabs(args->sigma),
1062 sigma2 = fabs(args->xi),
1065 if ( args->rho >= 1.0 )
1066 kernel->width = CastDoubleToSizeT(args->rho)*2+1;
1067 else if ( (type != DoGKernel) || (sigma >= sigma2) )
1068 kernel->width = GetOptimalKernelWidth2D(args->rho,sigma);
1070 kernel->width = GetOptimalKernelWidth2D(args->rho,sigma2);
1071 kernel->height = kernel->width;
1072 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1073 if (AcquireKernelValues(kernel) == MagickFalse)
1074 return(DestroyKernelInfo(kernel));
1083 if ( type == GaussianKernel || type == DoGKernel )
1085 if ( sigma > MagickEpsilon )
1086 { A = 1.0/(2.0*sigma*sigma);
1087 B = (double) (1.0/(Magick2PI*sigma*sigma));
1088 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1089 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1090 kernel->values[i] = exp(-((
double)(u*u+v*v))*A)*B;
1093 { (void) memset(kernel->values,0, (
size_t)
1094 kernel->width*kernel->height*
sizeof(*kernel->values));
1095 kernel->values[kernel->x+kernel->y*(ssize_t) kernel->width] = 1.0;
1099 if ( type == DoGKernel )
1101 if ( sigma2 > MagickEpsilon )
1103 A = 1.0/(2.0*sigma*sigma);
1104 B = (double) (1.0/(Magick2PI*sigma*sigma));
1105 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1106 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1107 kernel->values[i] -= exp(-((
double)(u*u+v*v))*A)*B;
1110 kernel->values[kernel->x+kernel->y*(ssize_t) kernel->width] -= 1.0;
1113 if ( type == LoGKernel )
1115 if ( sigma > MagickEpsilon )
1116 { A = 1.0/(2.0*sigma*sigma);
1117 B = (double) (1.0/(MagickPI*sigma*sigma*sigma*sigma));
1118 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1119 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1120 { R = ((double)(u*u+v*v))*A;
1121 kernel->values[i] = (1-R)*exp(-R)*B;
1125 { (void) memset(kernel->values,0, (
size_t)
1126 kernel->width*kernel->height*
sizeof(*kernel->values));
1127 kernel->values[kernel->x+kernel->y*(ssize_t) kernel->width] = 1.0;
1144 CalcKernelMetaData(kernel);
1145 ScaleKernelInfo(kernel, 1.0, CorrelateNormalizeValue);
1151 sigma = fabs(args->sigma),
1154 if ( args->rho >= 1.0 )
1155 kernel->width = CastDoubleToSizeT(args->rho)*2+1;
1157 kernel->width = GetOptimalKernelWidth1D(args->rho,sigma);
1159 kernel->x = (ssize_t) (kernel->width-1)/2;
1161 kernel->negative_range = kernel->positive_range = 0.0;
1162 if (AcquireKernelValues(kernel) == MagickFalse)
1163 return(DestroyKernelInfo(kernel));
1181 v = (ssize_t) (kernel->width*KernelRank-1)/2;
1182 (void) memset(kernel->values,0, (
size_t)
1183 kernel->width*kernel->height*
sizeof(*kernel->values));
1185 if ( sigma > MagickEpsilon )
1186 { sigma *= KernelRank;
1187 alpha = 1.0/(2.0*sigma*sigma);
1188 beta= (double) (1.0/(MagickSQ2PI*sigma ));
1189 for ( u=-v; u <= v; u++) {
1190 kernel->values[(u+v)/KernelRank] +=
1191 exp(-((
double)(u*u))*alpha)*beta;
1195 kernel->values[kernel->x+kernel->y*(ssize_t) kernel->width] = 1.0;
1201 if ( sigma > MagickEpsilon )
1202 { alpha = 1.0/(2.0*sigma*sigma);
1203 beta = 1.0/(MagickSQ2PI*sigma);
1204 for ( i=0, u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1205 kernel->values[i] = exp(-((
double)(u*u))*alpha)*beta;
1208 { (void) memset(kernel->values,0, (
size_t)
1209 kernel->width*kernel->height*
sizeof(*kernel->values));
1210 kernel->values[kernel->x+kernel->y*kernel->width] = 1.0;
1227 CalcKernelMetaData(kernel);
1228 ScaleKernelInfo(kernel, 1.0, CorrelateNormalizeValue);
1231 RotateKernelInfo(kernel, args->xi );
1236 sigma = fabs(args->sigma),
1239 if ( args->rho < 1.0 )
1240 kernel->width = (GetOptimalKernelWidth1D(args->rho,sigma)-1)/2+1;
1242 kernel->width = CastDoubleToSizeT(args->rho);
1243 kernel->x = kernel->y = 0;
1245 kernel->negative_range = kernel->positive_range = 0.0;
1246 if (AcquireKernelValues(kernel) == MagickFalse)
1247 return(DestroyKernelInfo(kernel));
1259 if ( sigma > MagickEpsilon )
1263 v = (ssize_t) kernel->width*KernelRank;
1264 (void) memset(kernel->values,0, (
size_t)
1265 kernel->width*
sizeof(*kernel->values));
1266 sigma *= KernelRank;
1267 A = 1.0/(2.0*sigma*sigma);
1269 for ( u=0; u < v; u++) {
1270 kernel->values[u/KernelRank] +=
1271 exp(-((
double)(u*u))*A);
1274 for (i=0; i < (ssize_t) kernel->width; i++)
1275 kernel->positive_range += kernel->values[i];
1277 A = 1.0/(2.0*sigma*sigma);
1279 for ( i=0; i < (ssize_t) kernel->width; i++)
1280 kernel->positive_range +=
1281 kernel->values[i] = exp(-((
double)(i*i))*A);
1286 { (void) memset(kernel->values,0, (
size_t)
1287 kernel->width*kernel->height*
sizeof(*kernel->values));
1288 kernel->values[kernel->x+kernel->y*(ssize_t) kernel->width] = 1.0;
1289 kernel->positive_range = 1.0;
1292 kernel->minimum = 0.0;
1293 kernel->maximum = kernel->values[0];
1294 kernel->negative_range = 0.0;
1296 ScaleKernelInfo(kernel, 1.0, NormalizeValue);
1297 RotateKernelInfo(kernel, args->xi);
1300 case BinomialKernel:
1303 max_order = (
sizeof(size_t) > 4) ? 20 : 12;
1308 if (args->rho < 1.0)
1309 kernel->width = kernel->height = 3;
1311 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
1312 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1315 if ((kernel->width-1) > max_order)
1316 return(DestroyKernelInfo(kernel));
1318 order_f = fact(kernel->width-1);
1320 if (AcquireKernelValues(kernel) == MagickFalse)
1321 return(DestroyKernelInfo(kernel));
1324 for ( i=0, v=0; v < (ssize_t)kernel->height; v++)
1327 alpha = order_f / ( fact((
size_t) v) * fact(kernel->height-(
size_t) v-1) );
1329 for ( u=0; u < (ssize_t)kernel->width; u++, i++)
1330 kernel->positive_range += kernel->values[i] = (
double)
1331 (alpha * order_f / ( fact((
size_t) u) * fact(kernel->height-(
size_t) u-1) ));
1333 kernel->minimum = 1.0;
1334 kernel->maximum = kernel->values[kernel->x+kernel->y*(ssize_t) kernel->width];
1335 kernel->negative_range = 0.0;
1342 case LaplacianKernel:
1343 {
switch ( (
int) args->rho ) {
1346 kernel=ParseKernelArray(
"3: -1,-1,-1 -1,8,-1 -1,-1,-1");
1349 kernel=ParseKernelArray(
"3: 0,-1,0 -1,4,-1 0,-1,0");
1352 kernel=ParseKernelArray(
"3: -2,1,-2 1,4,1 -2,1,-2");
1355 kernel=ParseKernelArray(
"3: 1,-2,1 -2,4,-2 1,-2,1");
1358 kernel=ParseKernelArray(
1359 "5: -4,-1,0,-1,-4 -1,2,3,2,-1 0,3,4,3,0 -1,2,3,2,-1 -4,-1,0,-1,-4");
1362 kernel=ParseKernelArray(
1363 "7:-10,-5,-2,-1,-2,-5,-10 -5,0,3,4,3,0,-5 -2,3,6,7,6,3,-2 -1,4,7,8,7,4,-1 -2,3,6,7,6,3,-2 -5,0,3,4,3,0,-5 -10,-5,-2,-1,-2,-5,-10" );
1366 kernel=ParseKernelArray(
1367 "5: 0,0,-1,0,0 0,-1,-2,-1,0 -1,-2,16,-2,-1 0,-1,-2,-1,0 0,0,-1,0,0");
1371 kernel=ParseKernelArray(
1372 "9: 0,-1,-1,-2,-2,-2,-1,-1,0 -1,-2,-4,-5,-5,-5,-4,-2,-1 -1,-4,-5,-3,-0,-3,-5,-4,-1 -2,-5,-3,12,24,12,-3,-5,-2 -2,-5,-0,24,40,24,-0,-5,-2 -2,-5,-3,12,24,12,-3,-5,-2 -1,-4,-5,-3,-0,-3,-5,-4,-1 -1,-2,-4,-5,-5,-5,-4,-2,-1 0,-1,-1,-2,-2,-2,-1,-1,0");
1375 if (kernel == (KernelInfo *) NULL)
1377 kernel->type = type;
1382 kernel=ParseKernelArray(
"3: 1,0,-1 2,0,-2 1,0,-1");
1383 if (kernel == (KernelInfo *) NULL)
1385 kernel->type = type;
1386 RotateKernelInfo(kernel, args->rho);
1391 kernel=ParseKernelArray(
"3: 0,0,0 1,-1,0 0,0,0");
1392 if (kernel == (KernelInfo *) NULL)
1394 kernel->type = type;
1395 RotateKernelInfo(kernel, args->rho);
1400 kernel=ParseKernelArray(
"3: 1,0,-1 1,0,-1 1,0,-1");
1401 if (kernel == (KernelInfo *) NULL)
1403 kernel->type = type;
1404 RotateKernelInfo(kernel, args->rho);
1409 kernel=ParseKernelArray(
"3: 1,1,-1 1,-2,-1 1,1,-1");
1410 if (kernel == (KernelInfo *) NULL)
1412 kernel->type = type;
1413 RotateKernelInfo(kernel, args->rho);
1418 kernel=ParseKernelArray(
"3: 5,-3,-3 5,0,-3 5,-3,-3");
1419 if (kernel == (KernelInfo *) NULL)
1421 kernel->type = type;
1422 RotateKernelInfo(kernel, args->rho);
1425 case FreiChenKernel:
1429 {
switch ( (
int) args->rho ) {
1432 kernel=ParseKernelArray(
"3: 1,0,-1 2,0,-2 1,0,-1");
1433 if (kernel == (KernelInfo *) NULL)
1435 kernel->type = type;
1436 kernel->values[3] = +(MagickRealType) MagickSQ2;
1437 kernel->values[5] = -(MagickRealType) MagickSQ2;
1438 CalcKernelMetaData(kernel);
1441 kernel=ParseKernelArray(
"3: 1,2,0 2,0,-2 0,-2,-1");
1442 if (kernel == (KernelInfo *) NULL)
1444 kernel->type = type;
1445 kernel->values[1] = kernel->values[3]= +(MagickRealType) MagickSQ2;
1446 kernel->values[5] = kernel->values[7]= -(MagickRealType) MagickSQ2;
1447 CalcKernelMetaData(kernel);
1448 ScaleKernelInfo(kernel, (
double) (1.0/2.0*MagickSQ2), NoValue);
1452 kernel=AcquireKernelInfo(
"FreiChen:11;FreiChen:12;FreiChen:13;FreiChen:14;FreiChen:15;FreiChen:16;FreiChen:17;FreiChen:18;FreiChen:19",exception);
1453 if (kernel == (KernelInfo *) NULL)
1459 kernel=ParseKernelArray(
"3: 1,0,-1 2,0,-2 1,0,-1");
1460 if (kernel == (KernelInfo *) NULL)
1462 kernel->type = type;
1463 kernel->values[3] = +(MagickRealType) MagickSQ2;
1464 kernel->values[5] = -(MagickRealType) MagickSQ2;
1465 CalcKernelMetaData(kernel);
1466 ScaleKernelInfo(kernel, (
double) (1.0/2.0*MagickSQ2), NoValue);
1469 kernel=ParseKernelArray(
"3: 1,2,1 0,0,0 1,2,1");
1470 if (kernel == (KernelInfo *) NULL)
1472 kernel->type = type;
1473 kernel->values[1] = +(MagickRealType) MagickSQ2;
1474 kernel->values[7] = +(MagickRealType) MagickSQ2;
1475 CalcKernelMetaData(kernel);
1476 ScaleKernelInfo(kernel, (
double) (1.0/2.0*MagickSQ2), NoValue);
1479 kernel=ParseKernelArray(
"3: 2,-1,0 -1,0,1 0,1,-2");
1480 if (kernel == (KernelInfo *) NULL)
1482 kernel->type = type;
1483 kernel->values[0] = +(MagickRealType) MagickSQ2;
1484 kernel->values[8] = -(MagickRealType) MagickSQ2;
1485 CalcKernelMetaData(kernel);
1486 ScaleKernelInfo(kernel, (
double) (1.0/2.0*MagickSQ2), NoValue);
1489 kernel=ParseKernelArray(
"3: 0,1,-2 -1,0,1 2,-1,0");
1490 if (kernel == (KernelInfo *) NULL)
1492 kernel->type = type;
1493 kernel->values[2] = -(MagickRealType) MagickSQ2;
1494 kernel->values[6] = +(MagickRealType) MagickSQ2;
1495 CalcKernelMetaData(kernel);
1496 ScaleKernelInfo(kernel, (
double) (1.0/2.0*MagickSQ2), NoValue);
1499 kernel=ParseKernelArray(
"3: 0,-1,0 1,0,1 0,-1,0");
1500 if (kernel == (KernelInfo *) NULL)
1502 kernel->type = type;
1503 ScaleKernelInfo(kernel, 1.0/2.0, NoValue);
1506 kernel=ParseKernelArray(
"3: 1,0,-1 0,0,0 -1,0,1");
1507 if (kernel == (KernelInfo *) NULL)
1509 kernel->type = type;
1510 ScaleKernelInfo(kernel, 1.0/2.0, NoValue);
1513 kernel=ParseKernelArray(
"3: 1,-2,1 -2,4,-2 -1,-2,1");
1514 if (kernel == (KernelInfo *) NULL)
1516 kernel->type = type;
1517 ScaleKernelInfo(kernel, 1.0/6.0, NoValue);
1520 kernel=ParseKernelArray(
"3: -2,1,-2 1,4,1 -2,1,-2");
1521 if (kernel == (KernelInfo *) NULL)
1523 kernel->type = type;
1524 ScaleKernelInfo(kernel, 1.0/6.0, NoValue);
1527 kernel=ParseKernelArray(
"3: 1,1,1 1,1,1 1,1,1");
1528 if (kernel == (KernelInfo *) NULL)
1530 kernel->type = type;
1531 ScaleKernelInfo(kernel, 1.0/3.0, NoValue);
1534 if ( fabs(args->sigma) >= MagickEpsilon )
1536 RotateKernelInfo(kernel, args->sigma);
1537 else if ( args->rho > 30.0 || args->rho < -30.0 )
1539 RotateKernelInfo(kernel, args->rho);
1548 if (args->rho < 1.0)
1549 kernel->width = kernel->height = 3;
1551 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
1552 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1554 if (AcquireKernelValues(kernel) == MagickFalse)
1555 return(DestroyKernelInfo(kernel));
1558 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1559 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1560 if ( (labs((
long) u)+labs((
long) v)) <= (
long) kernel->x)
1561 kernel->positive_range += kernel->values[i] = args->sigma;
1563 kernel->values[i] = nan;
1564 kernel->minimum = kernel->maximum = args->sigma;
1568 case RectangleKernel:
1571 if ( type == SquareKernel )
1573 if (args->rho < 1.0)
1574 kernel->width = kernel->height = 3;
1576 kernel->width = kernel->height = CastDoubleToSizeT(args->rho*2+1);
1577 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1578 scale = args->sigma;
1582 if ( args->rho < 1.0 || args->sigma < 1.0 )
1583 return(DestroyKernelInfo(kernel));
1584 kernel->width = CastDoubleToSizeT(args->rho);
1585 kernel->height = CastDoubleToSizeT(args->sigma);
1586 if ((args->xi < 0.0) || (args->xi >= (
double) kernel->width) ||
1587 (args->psi < 0.0) || (args->psi >= (
double) kernel->height))
1588 return(DestroyKernelInfo(kernel));
1589 kernel->x = (ssize_t) args->xi;
1590 kernel->y = (ssize_t) args->psi;
1593 if (AcquireKernelValues(kernel) == MagickFalse)
1594 return(DestroyKernelInfo(kernel));
1597 u=(ssize_t) (kernel->width*kernel->height);
1598 for ( i=0; i < u; i++)
1599 kernel->values[i] = scale;
1600 kernel->minimum = kernel->maximum = scale;
1601 kernel->positive_range = scale*u;
1606 if (args->rho < 1.0)
1607 kernel->width = kernel->height = 5;
1609 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
1610 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1612 if (AcquireKernelValues(kernel) == MagickFalse)
1613 return(DestroyKernelInfo(kernel));
1615 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1616 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1617 if ( (labs((
long) u)+labs((
long) v)) <=
1618 ((
long)kernel->x + (
long)(kernel->x/2)) )
1619 kernel->positive_range += kernel->values[i] = args->sigma;
1621 kernel->values[i] = nan;
1622 kernel->minimum = kernel->maximum = args->sigma;
1628 limit = (ssize_t)(args->rho*args->rho);
1630 if (args->rho < 0.4)
1631 kernel->width = kernel->height = 9L, limit = 18L;
1633 kernel->width = kernel->height = CastDoubleToSizeT(fabs(args->rho))*2+1;
1634 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1636 if (AcquireKernelValues(kernel) == MagickFalse)
1637 return(DestroyKernelInfo(kernel));
1639 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1640 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1641 if ((u*u+v*v) <= limit)
1642 kernel->positive_range += kernel->values[i] = args->sigma;
1644 kernel->values[i] = nan;
1645 kernel->minimum = kernel->maximum = args->sigma;
1650 if (args->rho < 1.0)
1651 kernel->width = kernel->height = 5;
1653 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
1654 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1656 if (AcquireKernelValues(kernel) == MagickFalse)
1657 return(DestroyKernelInfo(kernel));
1660 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1661 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1662 kernel->values[i] = (u == 0 || v == 0) ? args->sigma : nan;
1663 kernel->minimum = kernel->maximum = args->sigma;
1664 kernel->positive_range = args->sigma*(kernel->width*2.0 - 1.0);
1669 if (args->rho < 1.0)
1670 kernel->width = kernel->height = 5;
1672 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
1673 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1675 if (AcquireKernelValues(kernel) == MagickFalse)
1676 return(DestroyKernelInfo(kernel));
1679 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1680 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1681 kernel->values[i] = (u == v || u == -v) ? args->sigma : nan;
1682 kernel->minimum = kernel->maximum = args->sigma;
1683 kernel->positive_range = args->sigma*(kernel->width*2.0 - 1.0);
1697 if (args->rho < args->sigma)
1699 kernel->width = CastDoubleToSizeT(args->sigma)*2+1;
1700 limit1 = (ssize_t)(args->rho*args->rho);
1701 limit2 = (ssize_t)(args->sigma*args->sigma);
1705 kernel->width = CastDoubleToSizeT(args->rho)*2+1;
1706 limit1 = (ssize_t)(args->sigma*args->sigma);
1707 limit2 = (ssize_t)(args->rho*args->rho);
1710 kernel->width = 7L, limit1 = 7L, limit2 = 11L;
1712 kernel->height = kernel->width;
1713 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1714 if (AcquireKernelValues(kernel) == MagickFalse)
1715 return(DestroyKernelInfo(kernel));
1718 scale = (ssize_t) (( type == PeaksKernel) ? 0.0 : args->xi);
1719 for ( i=0, v= -kernel->y; v <= (ssize_t)kernel->y; v++)
1720 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1721 { ssize_t radius=u*u+v*v;
1722 if (limit1 < radius && radius <= limit2)
1723 kernel->positive_range += kernel->values[i] = (double) scale;
1725 kernel->values[i] = nan;
1727 kernel->minimum = kernel->maximum = (double) scale;
1728 if ( type == PeaksKernel ) {
1730 kernel->values[kernel->x+kernel->y*(ssize_t) kernel->width] = 1.0;
1731 kernel->positive_range = 1.0;
1732 kernel->maximum = 1.0;
1738 kernel=AcquireKernelInfo(
"ThinSE:482",exception);
1739 if (kernel == (KernelInfo *) NULL)
1741 kernel->type = type;
1742 ExpandMirrorKernelInfo(kernel);
1747 kernel=AcquireKernelInfo(
"ThinSE:87",exception);
1748 if (kernel == (KernelInfo *) NULL)
1750 kernel->type = type;
1751 ExpandRotateKernelInfo(kernel, 90.0);
1754 case DiagonalsKernel:
1756 switch ( (
int) args->rho ) {
1761 kernel=ParseKernelArray(
"3: 0,0,0 0,-,1 1,1,-");
1762 if (kernel == (KernelInfo *) NULL)
1764 kernel->type = type;
1765 new_kernel=ParseKernelArray(
"3: 0,0,1 0,-,1 0,1,-");
1766 if (new_kernel == (KernelInfo *) NULL)
1767 return(DestroyKernelInfo(kernel));
1768 new_kernel->type = type;
1769 LastKernelInfo(kernel)->next = new_kernel;
1770 ExpandMirrorKernelInfo(kernel);
1774 kernel=ParseKernelArray(
"3: 0,0,0 0,-,1 1,1,-");
1777 kernel=ParseKernelArray(
"3: 0,0,1 0,-,1 0,1,-");
1780 if (kernel == (KernelInfo *) NULL)
1782 kernel->type = type;
1783 RotateKernelInfo(kernel, args->sigma);
1786 case LineEndsKernel:
1788 switch ( (
int) args->rho ) {
1792 return(AcquireKernelInfo(
"LineEnds:1>;LineEnds:2>",exception));
1795 kernel=ParseKernelArray(
"3: 0,0,- 0,1,1 0,0,-");
1799 kernel=ParseKernelArray(
"3: 0,0,0 0,1,0 0,0,1");
1803 kernel=ParseKernelArray(
"3: 0,0,0 0,1,1 0,0,0");
1807 kernel=ParseKernelArray(
"3: 0,0,0 0,1,- 0,0,-");
1810 if (kernel == (KernelInfo *) NULL)
1812 kernel->type = type;
1813 RotateKernelInfo(kernel, args->sigma);
1816 case LineJunctionsKernel:
1818 switch ( (
int) args->rho ) {
1822 return(AcquireKernelInfo(
"LineJunctions:1@;LineJunctions:2>",exception));
1825 kernel=ParseKernelArray(
"3: 1,-,1 -,1,- -,1,-");
1829 kernel=ParseKernelArray(
"3: 1,-,- -,1,- 1,-,1");
1833 kernel=ParseKernelArray(
"3: -,-,- 1,1,1 -,1,-");
1837 kernel=ParseKernelArray(
"3: 1,-,1 -,1,- 1,-,1");
1841 kernel=ParseKernelArray(
"3: -,1,- 1,1,1 -,1,-");
1844 if (kernel == (KernelInfo *) NULL)
1846 kernel->type = type;
1847 RotateKernelInfo(kernel, args->sigma);
1854 switch ( (
int) args->rho ) {
1857 kernel=ParseKernelArray(
"3x1:0,1,0");
1858 if (kernel == (KernelInfo *) NULL)
1860 kernel->type = type;
1861 ExpandRotateKernelInfo(kernel, 90.0);
1864 kernel=ParseKernelArray(
"4x1:0,1,1,0");
1865 if (kernel == (KernelInfo *) NULL)
1867 kernel->type = type;
1868 ExpandRotateKernelInfo(kernel, 90.0);
1873 new_kernel=ParseKernelArray(
"4x3+1+1:0,1,1,- -,1,1,- -,1,1,0");
1874 if (new_kernel == (KernelInfo *) NULL)
1875 return(DestroyKernelInfo(kernel));
1876 new_kernel->type = type;
1877 LastKernelInfo(kernel)->next = new_kernel;
1878 new_kernel=ParseKernelArray(
"4x3+2+1:0,1,1,- -,1,1,- -,1,1,0");
1879 if (new_kernel == (KernelInfo *) NULL)
1880 return(DestroyKernelInfo(kernel));
1881 new_kernel->type = type;
1882 LastKernelInfo(kernel)->next = new_kernel;
1883 new_kernel=ParseKernelArray(
"4x3+1+1:-,1,1,0 -,1,1,- 0,1,1,-");
1884 if (new_kernel == (KernelInfo *) NULL)
1885 return(DestroyKernelInfo(kernel));
1886 new_kernel->type = type;
1887 LastKernelInfo(kernel)->next = new_kernel;
1888 new_kernel=ParseKernelArray(
"4x3+2+1:-,1,1,0 -,1,1,- 0,1,1,-");
1889 if (new_kernel == (KernelInfo *) NULL)
1890 return(DestroyKernelInfo(kernel));
1891 new_kernel->type = type;
1892 LastKernelInfo(kernel)->next = new_kernel;
1893 new_kernel=ParseKernelArray(
"3x4+1+1:0,-,- 1,1,1 1,1,1 -,-,0");
1894 if (new_kernel == (KernelInfo *) NULL)
1895 return(DestroyKernelInfo(kernel));
1896 new_kernel->type = type;
1897 LastKernelInfo(kernel)->next = new_kernel;
1898 new_kernel=ParseKernelArray(
"3x4+1+2:0,-,- 1,1,1 1,1,1 -,-,0");
1899 if (new_kernel == (KernelInfo *) NULL)
1900 return(DestroyKernelInfo(kernel));
1901 new_kernel->type = type;
1902 LastKernelInfo(kernel)->next = new_kernel;
1903 new_kernel=ParseKernelArray(
"3x4+1+1:-,-,0 1,1,1 1,1,1 0,-,-");
1904 if (new_kernel == (KernelInfo *) NULL)
1905 return(DestroyKernelInfo(kernel));
1906 new_kernel->type = type;
1907 LastKernelInfo(kernel)->next = new_kernel;
1908 new_kernel=ParseKernelArray(
"3x4+1+2:-,-,0 1,1,1 1,1,1 0,-,-");
1909 if (new_kernel == (KernelInfo *) NULL)
1910 return(DestroyKernelInfo(kernel));
1911 new_kernel->type = type;
1912 LastKernelInfo(kernel)->next = new_kernel;
1917 case ConvexHullKernel:
1922 kernel=ParseKernelArray(
"3: 1,1,- 1,0,- 1,-,0");
1923 if (kernel == (KernelInfo *) NULL)
1925 kernel->type = type;
1926 ExpandRotateKernelInfo(kernel, 90.0);
1928 new_kernel=ParseKernelArray(
"3: 1,1,1 1,0,- -,-,0");
1929 if (new_kernel == (KernelInfo *) NULL)
1930 return(DestroyKernelInfo(kernel));
1931 new_kernel->type = type;
1932 ExpandRotateKernelInfo(new_kernel, 90.0);
1933 LastKernelInfo(kernel)->next = new_kernel;
1936 case SkeletonKernel:
1938 switch ( (
int) args->rho ) {
1944 kernel=AcquireKernelInfo(
"ThinSE:482",exception);
1945 if (kernel == (KernelInfo *) NULL)
1947 kernel->type = type;
1948 ExpandRotateKernelInfo(kernel, 45.0);
1955 kernel=AcquireKernelInfo(
"ThinSE:482; ThinSE:87x90;",exception);
1956 if (kernel == (KernelInfo *) NULL)
1958 if (kernel->next == (KernelInfo *) NULL)
1959 return(DestroyKernelInfo(kernel));
1960 kernel->type = type;
1961 kernel->next->type = type;
1962 ExpandRotateKernelInfo(kernel, 90.0);
1970 kernel=AcquireKernelInfo(
"ThinSE:41; ThinSE:42; ThinSE:43",
1972 if (kernel == (KernelInfo *) NULL)
1974 if (kernel->next == (KernelInfo *) NULL)
1975 return(DestroyKernelInfo(kernel));
1976 if (kernel->next->next == (KernelInfo *) NULL)
1977 return(DestroyKernelInfo(kernel));
1978 kernel->type = type;
1979 kernel->next->type = type;
1980 kernel->next->next->type = type;
1981 ExpandMirrorKernelInfo(kernel);
1997 switch ( (
int) args->rho ) {
2000 kernel=ParseKernelArray(
"3: -,-,1 0,-,1 -,-,1");
2003 kernel=ParseKernelArray(
"3: -,-,1 0,-,1 -,0,-");
2006 kernel=ParseKernelArray(
"3: -,0,- 0,-,1 -,-,1");
2009 kernel=ParseKernelArray(
"3: -,0,- 0,-,1 -,0,-");
2012 kernel=ParseKernelArray(
"3: -,0,1 0,-,1 -,0,-");
2015 kernel=ParseKernelArray(
"3: -,0,- 0,-,1 -,0,1");
2018 kernel=ParseKernelArray(
"3: -,1,1 0,-,1 -,0,-");
2021 kernel=ParseKernelArray(
"3: -,-,1 0,-,1 0,-,1");
2024 kernel=ParseKernelArray(
"3: 0,-,1 0,-,1 -,-,1");
2028 kernel=ParseKernelArray(
"3: -,1,- 0,-,1 -,1,-");
2031 kernel=ParseKernelArray(
"3: -,1,- 0,-,1 0,-,-");
2034 kernel=ParseKernelArray(
"3: 0,-,- 0,-,1 -,1,-");
2037 kernel=ParseKernelArray(
"3: 0,-,- 0,-,1 0,-,-");
2040 kernel=ParseKernelArray(
"3: 0,-,1 0,-,1 0,-,-");
2043 kernel=ParseKernelArray(
"3: 0,-,- 0,-,1 0,-,1");
2046 kernel=ParseKernelArray(
"3: -,1,- 0,-,1 0,0,-");
2049 kernel=ParseKernelArray(
"3: -,1,- 0,-,1 0,1,-");
2052 kernel=ParseKernelArray(
"3: 0,1,- 0,-,1 -,1,-");
2056 kernel=ParseKernelArray(
"3: -,-,1 0,-,- -,0,-");
2059 kernel=ParseKernelArray(
"3: -,1,- -,-,1 0,-,-");
2062 kernel=ParseKernelArray(
"3: -,1,1 0,-,1 0,0,-");
2066 kernel=ParseKernelArray(
"3: 0,-,1 0,-,1 0,-,1");
2069 if (kernel == (KernelInfo *) NULL)
2071 kernel->type = type;
2072 RotateKernelInfo(kernel, args->sigma);
2078 case ChebyshevKernel:
2080 if (args->rho < 1.0)
2081 kernel->width = kernel->height = 3;
2083 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
2084 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
2086 if (AcquireKernelValues(kernel) == MagickFalse)
2087 return(DestroyKernelInfo(kernel));
2089 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
2090 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
2091 kernel->positive_range += ( kernel->values[i] =
2092 args->sigma*MagickMax(fabs((
double)u),fabs((
double)v)) );
2093 kernel->maximum = kernel->values[0];
2096 case ManhattanKernel:
2098 if (args->rho < 1.0)
2099 kernel->width = kernel->height = 3;
2101 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
2102 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
2104 if (AcquireKernelValues(kernel) == MagickFalse)
2105 return(DestroyKernelInfo(kernel));
2107 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
2108 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
2109 kernel->positive_range += ( kernel->values[i] =
2110 args->sigma*(labs((
long) u)+labs((
long) v)) );
2111 kernel->maximum = kernel->values[0];
2114 case OctagonalKernel:
2116 if (args->rho < 2.0)
2117 kernel->width = kernel->height = 5;
2119 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
2120 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
2122 if (AcquireKernelValues(kernel) == MagickFalse)
2123 return(DestroyKernelInfo(kernel));
2125 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
2126 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
2129 r1 = MagickMax(fabs((
double)u),fabs((
double)v)),
2130 r2 = floor((
double)(labs((
long)u)+labs((
long)v)+1)/1.5);
2131 kernel->positive_range += kernel->values[i] =
2132 args->sigma*MagickMax(r1,r2);
2134 kernel->maximum = kernel->values[0];
2137 case EuclideanKernel:
2139 if (args->rho < 1.0)
2140 kernel->width = kernel->height = 3;
2142 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
2143 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
2145 if (AcquireKernelValues(kernel) == MagickFalse)
2146 return(DestroyKernelInfo(kernel));
2148 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
2149 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
2150 kernel->positive_range += ( kernel->values[i] =
2151 args->sigma*sqrt((
double) (u*u+v*v)) );
2152 kernel->maximum = kernel->values[0];
2158 kernel=ParseKernelArray(
"1:1");
2159 if (kernel == (KernelInfo *) NULL)
2161 kernel->type = UndefinedKernel;
2193MagickExport KernelInfo *CloneKernelInfo(
const KernelInfo *kernel)
2201 assert(kernel != (KernelInfo *) NULL);
2202 new_kernel=(KernelInfo *) AcquireMagickMemory(
sizeof(*kernel));
2203 if (new_kernel == (KernelInfo *) NULL)
2205 *new_kernel=(*kernel);
2208 if (AcquireKernelValues(new_kernel) == MagickFalse)
2209 return(DestroyKernelInfo(new_kernel));
2210 for (i=0; i < (ssize_t) (kernel->width*kernel->height); i++)
2211 new_kernel->values[i]=kernel->values[i];
2214 if ( kernel->next != (KernelInfo *) NULL ) {
2215 new_kernel->next = CloneKernelInfo(kernel->next);
2216 if ( new_kernel->next == (KernelInfo *) NULL )
2217 return(DestroyKernelInfo(new_kernel));
2246MagickExport KernelInfo *DestroyKernelInfo(KernelInfo *kernel)
2248 assert(kernel != (KernelInfo *) NULL);
2249 if (kernel->next != (KernelInfo *) NULL)
2250 kernel->next=DestroyKernelInfo(kernel->next);
2251 kernel->values=(MagickRealType *) RelinquishAlignedMemory(kernel->values);
2252 kernel=(KernelInfo *) RelinquishMagickMemory(kernel);
2288static void FlopKernelInfo(KernelInfo *kernel)
2297 for ( y=0, k=kernel->values; y < kernel->height; y++, k+=kernel->width)
2298 for ( x=0, r=kernel->width-1; x<kernel->width/2; x++, r--)
2299 t=k[x], k[x]=k[r], k[r]=t;
2301 kernel->x = kernel->width - kernel->x - 1;
2302 angle = fmod(angle+180.0, 360.0);
2306static void ExpandMirrorKernelInfo(KernelInfo *kernel)
2314 clone = CloneKernelInfo(last);
2315 if (clone == (KernelInfo *) NULL)
2317 RotateKernelInfo(clone, 180);
2318 LastKernelInfo(last)->next = clone;
2321 clone = CloneKernelInfo(last);
2322 if (clone == (KernelInfo *) NULL)
2324 RotateKernelInfo(clone, 90);
2325 LastKernelInfo(last)->next = clone;
2328 clone = CloneKernelInfo(last);
2329 if (clone == (KernelInfo *) NULL)
2331 RotateKernelInfo(clone, 180);
2332 LastKernelInfo(last)->next = clone;
2370static MagickBooleanType SameKernelInfo(
const KernelInfo *kernel1,
2371 const KernelInfo *kernel2)
2377 if ( kernel1->width != kernel2->width
2378 || kernel1->height != kernel2->height
2379 || kernel1->x != kernel2->x
2380 || kernel1->y != kernel2->y )
2384 for (i=0; i < (kernel1->width*kernel1->height); i++) {
2386 if ( IsNaN(kernel1->values[i]) && !IsNaN(kernel2->values[i]) )
2388 if ( IsNaN(kernel2->values[i]) && !IsNaN(kernel1->values[i]) )
2391 if ( fabs(kernel1->values[i] - kernel2->values[i]) >= MagickEpsilon )
2398static void ExpandRotateKernelInfo(KernelInfo *kernel,
const double angle)
2404 clone_info=(KernelInfo *) NULL;
2406DisableMSCWarning(4127)
2409 clone_info=CloneKernelInfo(last);
2410 if (clone_info == (KernelInfo *) NULL)
2412 RotateKernelInfo(clone_info,angle);
2413 if (SameKernelInfo(kernel,clone_info) != MagickFalse)
2415 LastKernelInfo(last)->next=clone_info;
2418 if (clone_info != (KernelInfo *) NULL)
2419 clone_info=DestroyKernelInfo(clone_info);
2459static void CalcKernelMetaData(KernelInfo *kernel)
2464 kernel->minimum = kernel->maximum = 0.0;
2465 kernel->negative_range = kernel->positive_range = 0.0;
2466 for (i=0; i < (kernel->width*kernel->height); i++)
2468 if ( fabs(kernel->values[i]) < MagickEpsilon )
2469 kernel->values[i] = 0.0;
2470 ( kernel->values[i] < 0)
2471 ? ( kernel->negative_range += kernel->values[i] )
2472 : ( kernel->positive_range += kernel->values[i] );
2473 Minimize(kernel->minimum, kernel->values[i]);
2474 Maximize(kernel->maximum, kernel->values[i]);
2540static ssize_t MorphologyPrimitive(
const Image *image,Image *morphology_image,
2541 const MorphologyMethod method,
const KernelInfo *kernel,
const double bias,
2542 ExceptionInfo *exception)
2544#define MorphologyTag "Morphology/Image"
2572 assert(image != (Image *) NULL);
2573 assert(image->signature == MagickCoreSignature);
2574 assert(morphology_image != (Image *) NULL);
2575 assert(morphology_image->signature == MagickCoreSignature);
2576 assert(kernel != (KernelInfo *) NULL);
2577 assert(kernel->signature == MagickCoreSignature);
2578 assert(exception != (ExceptionInfo *) NULL);
2579 assert(exception->signature == MagickCoreSignature);
2582 image_view=AcquireVirtualCacheView(image,exception);
2583 morphology_view=AcquireAuthenticCacheView(morphology_image,exception);
2584 width=image->columns+kernel->width-1;
2589 case ConvolveMorphology:
2590 case DilateMorphology:
2591 case DilateIntensityMorphology:
2592 case IterativeDistanceMorphology:
2597 offset.x=(ssize_t) kernel->width-kernel->x-1;
2598 offset.y=(ssize_t) kernel->height-kernel->y-1;
2601 case ErodeMorphology:
2602 case ErodeIntensityMorphology:
2603 case HitAndMissMorphology:
2604 case ThinningMorphology:
2605 case ThickenMorphology:
2616 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
2617 "InvalidOption",
"`%s'",
"not a primitive morphology method");
2622 changes=(
size_t *) AcquireQuantumMemory(GetOpenMPMaximumThreads(),
2624 if (changes == (
size_t *) NULL)
2625 ThrowFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed");
2626 for (j=0; j < (ssize_t) GetOpenMPMaximumThreads(); j++)
2628 if ((method == ConvolveMorphology) && (kernel->width == 1))
2639#if defined(MAGICKCORE_OPENMP_SUPPORT)
2640 #pragma omp parallel for schedule(static) shared(progress,status) \
2641 magick_number_threads(image,morphology_image,image->columns,1)
2643 for (x=0; x < (ssize_t) image->columns; x++)
2646 id = GetOpenMPThreadId();
2658 if (status == MagickFalse)
2660 p=GetCacheViewVirtualPixels(image_view,x,-offset.y,1,image->rows+
2661 kernel->height-1,exception);
2662 q=GetCacheViewAuthenticPixels(morphology_view,x,0,1,
2663 morphology_image->rows,exception);
2664 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
2669 center=(ssize_t) GetPixelChannels(image)*offset.y;
2670 for (r=0; r < (ssize_t) image->rows; r++)
2675 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2689 const MagickRealType
2693 *magick_restrict pixels;
2701 channel=GetPixelChannelChannel(image,i);
2702 traits=GetPixelChannelTraits(image,channel);
2703 morphology_traits=GetPixelChannelTraits(morphology_image,channel);
2704 if ((traits == UndefinedPixelTrait) ||
2705 (morphology_traits == UndefinedPixelTrait))
2707 if ((traits & CopyPixelTrait) != 0)
2709 SetPixelChannel(morphology_image,channel,p[center+i],q);
2712 k=(&kernel->values[kernel->height-1]);
2717 if (((image->alpha_trait & BlendPixelTrait) == 0) ||
2718 ((morphology_traits & BlendPixelTrait) == 0))
2719 for (v=0; v < (ssize_t) kernel->height; v++)
2723 pixel+=(*k)*(double) pixels[i];
2727 pixels+=(ptrdiff_t) GetPixelChannels(image);
2732 for (v=0; v < (ssize_t) kernel->height; v++)
2736 alpha=(double) (QuantumScale*(
double)
2737 GetPixelAlpha(image,pixels));
2738 pixel+=alpha*(*k)*(double) pixels[i];
2743 pixels+=(ptrdiff_t) GetPixelChannels(image);
2746 if (fabs(pixel-(
double) p[center+i]) >= MagickEpsilon)
2748 gamma=MagickSafeReciprocal(gamma);
2750 gamma*=(double) kernel->height/count;
2751 SetPixelChannel(morphology_image,channel,ClampToQuantum(gamma*
2754 p+=(ptrdiff_t) GetPixelChannels(image);
2755 q+=(ptrdiff_t) GetPixelChannels(morphology_image);
2757 if (SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse)
2759 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2764#if defined(MAGICKCORE_OPENMP_SUPPORT)
2768 proceed=SetImageProgress(image,MorphologyTag,progress,
2770 if (proceed == MagickFalse)
2774 morphology_image->type=image->type;
2775 morphology_view=DestroyCacheView(morphology_view);
2776 image_view=DestroyCacheView(image_view);
2777 for (j=0; j < (ssize_t) GetOpenMPMaximumThreads(); j++)
2778 changed+=changes[j];
2779 changes=(
size_t *) RelinquishMagickMemory(changes);
2780 return(status ? (ssize_t) (changed/GetImageChannels(image)) : 0);
2785#if defined(MAGICKCORE_OPENMP_SUPPORT)
2786 #pragma omp parallel for schedule(static) shared(progress,status) \
2787 magick_number_threads(image,morphology_image,image->rows,1)
2789 for (y=0; y < (ssize_t) image->rows; y++)
2792 id = GetOpenMPThreadId();
2806 if (status == MagickFalse)
2808 p=GetCacheViewVirtualPixels(image_view,-offset.x,y-offset.y,width,
2809 kernel->height,exception);
2810 q=GetCacheViewAuthenticPixels(morphology_view,0,y,morphology_image->columns,
2812 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
2817 center=(ssize_t) ((ssize_t) GetPixelChannels(image)*(ssize_t) width*
2818 offset.y+(ssize_t) GetPixelChannels(image)*offset.x);
2819 for (x=0; x < (ssize_t) image->columns; x++)
2824 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2841 const MagickRealType
2845 *magick_restrict pixels,
2846 *magick_restrict quantum_pixels;
2854 channel=GetPixelChannelChannel(image,i);
2855 traits=GetPixelChannelTraits(image,channel);
2856 morphology_traits=GetPixelChannelTraits(morphology_image,channel);
2857 if ((traits == UndefinedPixelTrait) ||
2858 (morphology_traits == UndefinedPixelTrait))
2860 if ((traits & CopyPixelTrait) != 0)
2862 SetPixelChannel(morphology_image,channel,p[center+i],q);
2866 quantum_pixels=(
const Quantum *) NULL;
2868 minimum=(double) QuantumRange;
2871 case ConvolveMorphology:
2876 case DilateMorphology:
2877 case ErodeIntensityMorphology:
2884 pixel=(double) p[center+i];
2891 case ConvolveMorphology:
2912 k=(&kernel->values[kernel->width*kernel->height-1]);
2913 if (((image->alpha_trait & BlendPixelTrait) == 0) ||
2914 ((morphology_traits & BlendPixelTrait) == 0))
2919 for (v=0; v < (ssize_t) kernel->height; v++)
2921 for (u=0; u < (ssize_t) kernel->width; u++)
2924 pixel+=(*k)*(double) pixels[i];
2926 pixels+=(ptrdiff_t) GetPixelChannels(image);
2928 pixels+=(image->columns-1)*GetPixelChannels(image);
2936 for (v=0; v < (ssize_t) kernel->height; v++)
2938 for (u=0; u < (ssize_t) kernel->width; u++)
2942 alpha=(double) (QuantumScale*(
double)
2943 GetPixelAlpha(image,pixels));
2944 pixel+=alpha*(*k)*(double) pixels[i];
2948 pixels+=(ptrdiff_t) GetPixelChannels(image);
2950 pixels+=(image->columns-1)*GetPixelChannels(image);
2954 case ErodeMorphology:
2965 for (v=0; v < (ssize_t) kernel->height; v++)
2967 for (u=0; u < (ssize_t) kernel->width; u++)
2969 if (!IsNaN(*k) && (*k >= 0.5))
2971 if ((
double) pixels[i] < pixel)
2972 pixel=(double) pixels[i];
2975 pixels+=(ptrdiff_t) GetPixelChannels(image);
2977 pixels+=(image->columns-1)*GetPixelChannels(image);
2981 case DilateMorphology:
2994 k=(&kernel->values[kernel->width*kernel->height-1]);
2995 for (v=0; v < (ssize_t) kernel->height; v++)
2997 for (u=0; u < (ssize_t) kernel->width; u++)
2999 if (!IsNaN(*k) && (*k > 0.5))
3001 if ((
double) pixels[i] > pixel)
3002 pixel=(double) pixels[i];
3005 pixels+=(ptrdiff_t) GetPixelChannels(image);
3007 pixels+=(image->columns-1)*GetPixelChannels(image);
3011 case HitAndMissMorphology:
3012 case ThinningMorphology:
3013 case ThickenMorphology:
3028 for (v=0; v < (ssize_t) kernel->height; v++)
3030 for (u=0; u < (ssize_t) kernel->width; u++)
3036 if ((
double) pixels[i] < minimum)
3037 minimum=(double) pixels[i];
3042 if ((
double) pixels[i] > maximum)
3043 maximum=(double) pixels[i];
3047 pixels+=(ptrdiff_t) GetPixelChannels(image);
3049 pixels+=(image->columns-1)*GetPixelChannels(image);
3055 if (method == ThinningMorphology)
3056 pixel=(double) p[center+i]-minimum;
3058 if (method == ThickenMorphology)
3059 pixel=(double) p[center+i]+minimum;
3062 case ErodeIntensityMorphology:
3070 for (v=0; v < (ssize_t) kernel->height; v++)
3072 for (u=0; u < (ssize_t) kernel->width; u++)
3074 if (!IsNaN(*k) && (*k >= 0.5))
3076 intensity=(double) GetPixelIntensity(image,pixels);
3077 if (intensity < minimum)
3079 quantum_pixels=pixels;
3080 pixel=(double) pixels[i];
3085 pixels+=(ptrdiff_t) GetPixelChannels(image);
3087 pixels+=(image->columns-1)*GetPixelChannels(image);
3091 case DilateIntensityMorphology:
3098 k=(&kernel->values[kernel->width*kernel->height-1]);
3099 for (v=0; v < (ssize_t) kernel->height; v++)
3101 for (u=0; u < (ssize_t) kernel->width; u++)
3103 if (!IsNaN(*k) && (*k >= 0.5))
3105 intensity=(double) GetPixelIntensity(image,pixels);
3106 if (intensity > maximum)
3108 pixel=(double) pixels[i];
3109 quantum_pixels=pixels;
3114 pixels+=(ptrdiff_t) GetPixelChannels(image);
3116 pixels+=(image->columns-1)*GetPixelChannels(image);
3120 case IterativeDistanceMorphology:
3145 k=(&kernel->values[kernel->width*kernel->height-1]);
3146 for (v=0; v < (ssize_t) kernel->height; v++)
3148 for (u=0; u < (ssize_t) kernel->width; u++)
3152 if (((
double) pixels[i]+(*k)) < pixel)
3153 pixel=(double) pixels[i]+(*k);
3156 pixels+=(ptrdiff_t) GetPixelChannels(image);
3158 pixels+=(image->columns-1)*GetPixelChannels(image);
3162 case UndefinedMorphology:
3166 if (quantum_pixels != (
const Quantum *) NULL)
3168 SetPixelChannel(morphology_image,channel,quantum_pixels[i],q);
3171 gamma=MagickSafeReciprocal(gamma);
3172 SetPixelChannel(morphology_image,channel,ClampToQuantum(gamma*pixel),q);
3173 if (fabs(pixel-(
double) p[center+i]) >= MagickEpsilon)
3176 p+=(ptrdiff_t) GetPixelChannels(image);
3177 q+=(ptrdiff_t) GetPixelChannels(morphology_image);
3179 if (SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse)
3181 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3186#if defined(MAGICKCORE_OPENMP_SUPPORT)
3190 proceed=SetImageProgress(image,MorphologyTag,progress,image->rows);
3191 if (proceed == MagickFalse)
3195 morphology_view=DestroyCacheView(morphology_view);
3196 image_view=DestroyCacheView(image_view);
3197 for (j=0; j < (ssize_t) GetOpenMPMaximumThreads(); j++)
3198 changed+=changes[j];
3199 changes=(
size_t *) RelinquishMagickMemory(changes);
3200 return(status ? (ssize_t) (changed/GetImageChannels(image)) : -1);
3216static ssize_t MorphologyPrimitiveDirect(Image *image,
3217 const MorphologyMethod method,
const KernelInfo *kernel,
3218 ExceptionInfo *exception)
3240 assert(image != (Image *) NULL);
3241 assert(image->signature == MagickCoreSignature);
3242 assert(kernel != (KernelInfo *) NULL);
3243 assert(kernel->signature == MagickCoreSignature);
3244 assert(exception != (ExceptionInfo *) NULL);
3245 assert(exception->signature == MagickCoreSignature);
3251 case DistanceMorphology:
3252 case VoronoiMorphology:
3257 offset.x=(ssize_t) kernel->width-kernel->x-1;
3258 offset.y=(ssize_t) kernel->height-kernel->y-1;
3271 image_view=AcquireVirtualCacheView(image,exception);
3272 morphology_view=AcquireAuthenticCacheView(image,exception);
3273 width=image->columns+kernel->width-1;
3274 for (y=0; y < (ssize_t) image->rows; y++)
3293 if (status == MagickFalse)
3295 p=GetCacheViewVirtualPixels(image_view,-offset.x,y-offset.y,width,(
size_t)
3296 offset.y+1,exception);
3297 q=GetCacheViewAuthenticPixels(morphology_view,0,y,image->columns,1,
3299 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3304 for (x=0; x < (ssize_t) image->columns; x++)
3309 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3320 const MagickRealType
3324 *magick_restrict pixels;
3332 channel=GetPixelChannelChannel(image,i);
3333 traits=GetPixelChannelTraits(image,channel);
3334 if (traits == UndefinedPixelTrait)
3336 if ((traits & CopyPixelTrait) != 0)
3339 pixel=(double) QuantumRange;
3342 case DistanceMorphology:
3344 k=(&kernel->values[kernel->width*kernel->height-1]);
3345 for (v=0; v <= offset.y; v++)
3347 for (u=0; u < (ssize_t) kernel->width; u++)
3351 if (((
double) pixels[i]+(*k)) < pixel)
3352 pixel=(double) pixels[i]+(*k);
3355 pixels+=(ptrdiff_t) GetPixelChannels(image);
3357 pixels+=(image->columns-1)*GetPixelChannels(image);
3359 k=(&kernel->values[(ssize_t) kernel->width*(kernel->y+1)-1]);
3360 pixels=q-offset.x*(ssize_t) GetPixelChannels(image);
3361 for (u=0; u < offset.x; u++)
3363 if (!IsNaN(*k) && ((x+u-offset.x) >= 0))
3365 if (((
double) pixels[i]+(*k)) < pixel)
3366 pixel=(double) pixels[i]+(*k);
3369 pixels+=(ptrdiff_t) GetPixelChannels(image);
3373 case VoronoiMorphology:
3375 k=(&kernel->values[kernel->width*kernel->height-1]);
3376 for (v=0; v < offset.y; v++)
3378 for (u=0; u < (ssize_t) kernel->width; u++)
3382 if (((
double) pixels[i]+(*k)) < pixel)
3383 pixel=(double) pixels[i]+(*k);
3386 pixels+=(ptrdiff_t) GetPixelChannels(image);
3388 pixels+=(image->columns-1)*GetPixelChannels(image);
3390 k=(&kernel->values[(ssize_t) kernel->width*(kernel->y+1)-1]);
3391 pixels=q-offset.x*(ssize_t) GetPixelChannels(image);
3392 for (u=0; u < offset.x; u++)
3394 if (!IsNaN(*k) && ((x+u-offset.x) >= 0))
3396 if (((
double) pixels[i]+(*k)) < pixel)
3397 pixel=(double) pixels[i]+(*k);
3400 pixels+=(ptrdiff_t) GetPixelChannels(image);
3407 if (fabs(pixel-(
double) q[i]) > MagickEpsilon)
3409 q[i]=ClampToQuantum(pixel);
3411 p+=(ptrdiff_t) GetPixelChannels(image);
3412 q+=(ptrdiff_t) GetPixelChannels(image);
3414 if (SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse)
3416 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3421#if defined(MAGICKCORE_OPENMP_SUPPORT)
3425 proceed=SetImageProgress(image,MorphologyTag,progress,2*image->rows);
3426 if (proceed == MagickFalse)
3430 morphology_view=DestroyCacheView(morphology_view);
3431 image_view=DestroyCacheView(image_view);
3435 image_view=AcquireVirtualCacheView(image,exception);
3436 morphology_view=AcquireAuthenticCacheView(image,exception);
3437 for (y=(ssize_t) image->rows-1; y >= 0; y--)
3455 if (status == MagickFalse)
3457 p=GetCacheViewVirtualPixels(image_view,-offset.x,y,width,(
size_t)
3458 kernel->y+1,exception);
3459 q=GetCacheViewAuthenticPixels(morphology_view,0,y,image->columns,1,
3461 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3466 p+=(ptrdiff_t) (image->columns-1)*GetPixelChannels(image);
3467 q+=(ptrdiff_t) (image->columns-1)*GetPixelChannels(image);
3468 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3473 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3484 const MagickRealType
3488 *magick_restrict pixels;
3496 channel=GetPixelChannelChannel(image,i);
3497 traits=GetPixelChannelTraits(image,channel);
3498 if (traits == UndefinedPixelTrait)
3500 if ((traits & CopyPixelTrait) != 0)
3503 pixel=(double) QuantumRange;
3506 case DistanceMorphology:
3508 k=(&kernel->values[(ssize_t) kernel->width*(kernel->y+1)-1]);
3509 for (v=offset.y; v < (ssize_t) kernel->height; v++)
3511 for (u=0; u < (ssize_t) kernel->width; u++)
3515 if (((
double) pixels[i]+(*k)) < pixel)
3516 pixel=(double) pixels[i]+(*k);
3519 pixels+=(ptrdiff_t) GetPixelChannels(image);
3521 pixels+=(image->columns-1)*GetPixelChannels(image);
3523 k=(&kernel->values[(ssize_t) kernel->width*kernel->y+kernel->x-1]);
3525 for (u=offset.x+1; u < (ssize_t) kernel->width; u++)
3527 pixels+=(ptrdiff_t) GetPixelChannels(image);
3528 if (!IsNaN(*k) && ((x+u-offset.x) < (ssize_t) image->columns))
3530 if (((
double) pixels[i]+(*k)) < pixel)
3531 pixel=(double) pixels[i]+(*k);
3537 case VoronoiMorphology:
3539 k=(&kernel->values[(ssize_t) kernel->width*(kernel->y+1)-1]);
3540 for (v=offset.y; v < (ssize_t) kernel->height; v++)
3542 for (u=0; u < (ssize_t) kernel->width; u++)
3546 if (((
double) pixels[i]+(*k)) < pixel)
3547 pixel=(double) pixels[i]+(*k);
3550 pixels+=(ptrdiff_t) GetPixelChannels(image);
3552 pixels+=(image->columns-1)*GetPixelChannels(image);
3554 k=(&kernel->values[(ssize_t) kernel->width*(kernel->y+1)-1]);
3556 for (u=offset.x+1; u < (ssize_t) kernel->width; u++)
3558 pixels+=(ptrdiff_t) GetPixelChannels(image);
3559 if (!IsNaN(*k) && ((x+u-offset.x) < (ssize_t) image->columns))
3561 if (((
double) pixels[i]+(*k)) < pixel)
3562 pixel=(double) pixels[i]+(*k);
3571 if (fabs(pixel-(
double) q[i]) > MagickEpsilon)
3573 q[i]=ClampToQuantum(pixel);
3575 p-=(ptrdiff_t)GetPixelChannels(image);
3576 q-=GetPixelChannels(image);
3578 if (SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse)
3580 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3585#if defined(MAGICKCORE_OPENMP_SUPPORT)
3589 proceed=SetImageProgress(image,MorphologyTag,progress,2*image->rows);
3590 if (proceed == MagickFalse)
3594 morphology_view=DestroyCacheView(morphology_view);
3595 image_view=DestroyCacheView(image_view);
3596 return(status ? (ssize_t) (changed/GetImageChannels(image)) : -1);
3608MagickPrivate Image *MorphologyApply(
const Image *image,
3609 const MorphologyMethod method,
const ssize_t iterations,
3610 const KernelInfo *kernel,
const CompositeOperator compose,
const double bias,
3611 ExceptionInfo *exception)
3654 v_info[MagickPathExtent];
3656 assert(image != (Image *) NULL);
3657 assert(image->signature == MagickCoreSignature);
3658 assert(kernel != (KernelInfo *) NULL);
3659 assert(kernel->signature == MagickCoreSignature);
3660 assert(exception != (ExceptionInfo *) NULL);
3661 assert(exception->signature == MagickCoreSignature);
3664 if ( iterations == 0 )
3665 return((Image *) NULL);
3667 kernel_limit = (size_t) iterations;
3668 if ( iterations < 0 )
3669 kernel_limit = image->columns>image->rows ? image->columns : image->rows;
3671 verbose = IsStringTrue(GetImageArtifact(image,
"debug"));
3674 curr_image = (Image *) image;
3675 curr_compose = image->compose;
3676 (void) curr_compose;
3677 work_image = save_image = rslt_image = (Image *) NULL;
3678 reflected_kernel = (KernelInfo *) NULL;
3687 special = MagickFalse;
3688 rslt_compose = compose;
3690 case SmoothMorphology:
3693 case OpenMorphology:
3694 case OpenIntensityMorphology:
3695 case TopHatMorphology:
3696 case CloseMorphology:
3697 case CloseIntensityMorphology:
3698 case BottomHatMorphology:
3699 case EdgeMorphology:
3702 case HitAndMissMorphology:
3703 rslt_compose = LightenCompositeOp;
3705 case ThinningMorphology:
3706 case ThickenMorphology:
3707 method_limit = kernel_limit;
3710 case DistanceMorphology:
3711 case VoronoiMorphology:
3712 special = MagickTrue;
3721 if ( special != MagickFalse )
3723 rslt_image=CloneImage(image,0,0,MagickTrue,exception);
3724 if (rslt_image == (Image *) NULL)
3726 if (SetImageStorageClass(rslt_image,DirectClass,exception) == MagickFalse)
3729 changed=MorphologyPrimitiveDirect(rslt_image,method,kernel,exception);
3731 if (verbose != MagickFalse)
3732 (void) (
void) FormatLocaleFile(stderr,
3733 "%s:%.20g.%.20g #%.20g => Changed %.20g\n",
3734 CommandOptionToMnemonic(MagickMorphologyOptions, method),
3735 1.0,0.0,1.0, (
double) changed);
3740 if ( method == VoronoiMorphology ) {
3742 (void) SetImageAlphaChannel(rslt_image, DeactivateAlphaChannel,
3744 (void) CompositeImage(rslt_image,image,CopyAlphaCompositeOp,
3745 MagickTrue,0,0,exception);
3746 (void) SetImageAlphaChannel(rslt_image, DeactivateAlphaChannel,
3753 if ( compose != UndefinedCompositeOp )
3754 rslt_compose = compose;
3755 if ( rslt_compose == UndefinedCompositeOp )
3756 rslt_compose = NoCompositeOp;
3761 case CorrelateMorphology:
3762 case CloseMorphology:
3763 case CloseIntensityMorphology:
3764 case BottomHatMorphology:
3765 case SmoothMorphology:
3766 reflected_kernel = CloneKernelInfo(kernel);
3767 if (reflected_kernel == (KernelInfo *) NULL)
3769 RotateKernelInfo(reflected_kernel,180);
3781 while ( method_loop < method_limit && method_changed > 0 ) {
3786 norm_kernel = (KernelInfo *) kernel;
3787 this_kernel = (KernelInfo *) kernel;
3788 rflt_kernel = reflected_kernel;
3791 while ( norm_kernel != NULL ) {
3795 while ( stage_loop < stage_limit ) {
3799 this_kernel = norm_kernel;
3802 case ErodeMorphology:
3803 case EdgeInMorphology:
3804 primitive = ErodeMorphology;
3806 case DilateMorphology:
3807 case EdgeOutMorphology:
3808 primitive = DilateMorphology;
3810 case OpenMorphology:
3811 case TopHatMorphology:
3812 primitive = ErodeMorphology;
3813 if ( stage_loop == 2 )
3814 primitive = DilateMorphology;
3816 case OpenIntensityMorphology:
3817 primitive = ErodeIntensityMorphology;
3818 if ( stage_loop == 2 )
3819 primitive = DilateIntensityMorphology;
3821 case CloseMorphology:
3822 case BottomHatMorphology:
3823 this_kernel = rflt_kernel;
3824 primitive = DilateMorphology;
3825 if ( stage_loop == 2 )
3826 primitive = ErodeMorphology;
3828 case CloseIntensityMorphology:
3829 this_kernel = rflt_kernel;
3830 primitive = DilateIntensityMorphology;
3831 if ( stage_loop == 2 )
3832 primitive = ErodeIntensityMorphology;
3834 case SmoothMorphology:
3835 switch ( stage_loop ) {
3837 primitive = ErodeMorphology;
3840 primitive = DilateMorphology;
3843 this_kernel = rflt_kernel;
3844 primitive = DilateMorphology;
3847 this_kernel = rflt_kernel;
3848 primitive = ErodeMorphology;
3852 case EdgeMorphology:
3853 primitive = DilateMorphology;
3854 if ( stage_loop == 2 ) {
3855 save_image = curr_image;
3856 curr_image = (Image *) image;
3857 primitive = ErodeMorphology;
3860 case CorrelateMorphology:
3870 this_kernel = rflt_kernel;
3871 primitive = ConvolveMorphology;
3876 assert( this_kernel != (KernelInfo *) NULL );
3879 if (verbose != MagickFalse) {
3880 if ( stage_limit > 1 )
3881 (void) FormatLocaleString(v_info,MagickPathExtent,
"%s:%.20g.%.20g -> ",
3882 CommandOptionToMnemonic(MagickMorphologyOptions,method),(
double)
3883 method_loop,(
double) stage_loop);
3884 else if ( primitive != method )
3885 (void) FormatLocaleString(v_info, MagickPathExtent,
"%s:%.20g -> ",
3886 CommandOptionToMnemonic(MagickMorphologyOptions, method),(
double)
3896 while ( kernel_loop < kernel_limit && changed > 0 ) {
3900 if ( work_image == (Image *) NULL )
3902 work_image=CloneImage(image,0,0,MagickTrue,exception);
3903 if (work_image == (Image *) NULL)
3905 if (SetImageStorageClass(work_image,DirectClass,exception) == MagickFalse)
3911 changed = MorphologyPrimitive(curr_image, work_image, primitive,
3912 this_kernel, bias, exception);
3913 if (verbose != MagickFalse) {
3914 if ( kernel_loop > 1 )
3915 (void) FormatLocaleFile(stderr,
"\n");
3916 (void) (
void) FormatLocaleFile(stderr,
3917 "%s%s%s:%.20g.%.20g #%.20g => Changed %.20g",
3918 v_info,CommandOptionToMnemonic(MagickMorphologyOptions,
3919 primitive),(this_kernel == rflt_kernel ) ?
"*" :
"",
3920 (
double) (method_loop+kernel_loop-1),(
double) kernel_number,
3921 (
double) count,(
double) changed);
3925 kernel_changed = (size_t) ((ssize_t) kernel_changed+changed);
3926 method_changed = (size_t) ((ssize_t) method_changed+changed);
3929 { Image *tmp = work_image;
3930 work_image = curr_image;
3933 if ( work_image == image )
3934 work_image = (Image *) NULL;
3938 if (verbose != MagickFalse && kernel_changed != (
size_t)changed)
3939 (void) FormatLocaleFile(stderr,
" Total %.20g",(
double) kernel_changed);
3940 if (verbose != MagickFalse && stage_loop < stage_limit)
3941 (void) FormatLocaleFile(stderr,
"\n");
3944 (void) FormatLocaleFile(stderr,
"--E-- image=0x%lx\n", (
unsigned long)image);
3945 (void) FormatLocaleFile(stderr,
" curr =0x%lx\n", (
unsigned long)curr_image);
3946 (void) FormatLocaleFile(stderr,
" work =0x%lx\n", (
unsigned long)work_image);
3947 (void) FormatLocaleFile(stderr,
" save =0x%lx\n", (
unsigned long)save_image);
3948 (void) FormatLocaleFile(stderr,
" union=0x%lx\n", (
unsigned long)rslt_image);
3961 case EdgeOutMorphology:
3962 case EdgeInMorphology:
3963 case TopHatMorphology:
3964 case BottomHatMorphology:
3965 if (verbose != MagickFalse)
3966 (void) FormatLocaleFile(stderr,
3967 "\n%s: Difference with original image",CommandOptionToMnemonic(
3968 MagickMorphologyOptions, method) );
3969 (void) CompositeImage(curr_image,image,DifferenceCompositeOp,
3970 MagickTrue,0,0,exception);
3972 case EdgeMorphology:
3973 if (verbose != MagickFalse)
3974 (void) FormatLocaleFile(stderr,
3975 "\n%s: Difference of Dilate and Erode",CommandOptionToMnemonic(
3976 MagickMorphologyOptions, method) );
3977 (void) CompositeImage(curr_image,save_image,DifferenceCompositeOp,
3978 MagickTrue,0,0,exception);
3979 save_image = DestroyImage(save_image);
3986 if ( kernel->next == (KernelInfo *) NULL )
3987 rslt_image = curr_image;
3988 else if ( rslt_compose == NoCompositeOp )
3989 {
if (verbose != MagickFalse) {
3990 if ( this_kernel->next != (KernelInfo *) NULL )
3991 (void) FormatLocaleFile(stderr,
" (re-iterate)");
3993 (
void) FormatLocaleFile(stderr,
" (done)");
3995 rslt_image = curr_image;
3997 else if ( rslt_image == (Image *) NULL)
3998 {
if (verbose != MagickFalse)
3999 (void) FormatLocaleFile(stderr,
" (save for compose)");
4000 rslt_image = curr_image;
4001 curr_image = (Image *) image;
4011 if (verbose != MagickFalse)
4012 (void) FormatLocaleFile(stderr,
" (compose \"%s\")",
4013 CommandOptionToMnemonic(MagickComposeOptions, rslt_compose) );
4014 (void) CompositeImage(rslt_image,curr_image,rslt_compose,MagickTrue,
4016 curr_image = DestroyImage(curr_image);
4017 curr_image = (Image *) image;
4019 if (verbose != MagickFalse)
4020 (void) FormatLocaleFile(stderr,
"\n");
4023 norm_kernel = norm_kernel->next;
4024 if ( rflt_kernel != (KernelInfo *) NULL )
4025 rflt_kernel = rflt_kernel->next;
4035 if ( curr_image == rslt_image )
4036 curr_image = (Image *) NULL;
4037 if ( rslt_image != (Image *) NULL )
4038 rslt_image = DestroyImage(rslt_image);
4040 if ( curr_image == rslt_image || curr_image == image )
4041 curr_image = (Image *) NULL;
4042 if ( curr_image != (Image *) NULL )
4043 curr_image = DestroyImage(curr_image);
4044 if ( work_image != (Image *) NULL )
4045 work_image = DestroyImage(work_image);
4046 if ( save_image != (Image *) NULL )
4047 save_image = DestroyImage(save_image);
4048 if ( reflected_kernel != (KernelInfo *) NULL )
4049 reflected_kernel = DestroyKernelInfo(reflected_kernel);
4103MagickExport Image *MorphologyImage(
const Image *image,
4104 const MorphologyMethod method,
const ssize_t iterations,
4105 const KernelInfo *kernel,ExceptionInfo *exception)
4122 assert(image != (
const Image *) NULL);
4123 assert(image->signature == MagickCoreSignature);
4124 assert(exception != (ExceptionInfo *) NULL);
4125 assert(exception->signature == MagickCoreSignature);
4126 if (IsEventLogging() != MagickFalse)
4127 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4128 curr_kernel = (KernelInfo *) kernel;
4130 compose = UndefinedCompositeOp;
4136 if ( method == ConvolveMorphology || method == CorrelateMorphology ) {
4138 artifact = GetImageArtifact(image,
"convolve:bias");
4139 if ( artifact != (
const char *) NULL) {
4140 if (IsGeometry(artifact) == MagickFalse)
4141 (void) ThrowMagickException(exception,GetMagickModule(),
4142 OptionWarning,
"InvalidSetting",
"'%s' '%s'",
4143 "convolve:bias",artifact);
4145 bias=StringToDoubleInterval(artifact,(
double) QuantumRange+1.0);
4149 artifact = GetImageArtifact(image,
"convolve:scale");
4150 if ( artifact != (
const char *) NULL ) {
4151 if (IsGeometry(artifact) == MagickFalse)
4152 (void) ThrowMagickException(exception,GetMagickModule(),
4153 OptionWarning,
"InvalidSetting",
"'%s' '%s'",
4154 "convolve:scale",artifact);
4156 if ( curr_kernel == kernel )
4157 curr_kernel = CloneKernelInfo(kernel);
4158 if (curr_kernel == (KernelInfo *) NULL)
4159 return((Image *) NULL);
4160 ScaleGeometryKernelInfo(curr_kernel, artifact);
4166 artifact=GetImageArtifact(image,
"morphology:showKernel");
4167 if (IsStringTrue(artifact) != MagickFalse)
4168 ShowKernelInfo(curr_kernel);
4180 artifact = GetImageArtifact(image,
"morphology:compose");
4181 if ( artifact != (
const char *) NULL) {
4182 parse=ParseCommandOption(MagickComposeOptions,
4183 MagickFalse,artifact);
4185 (void) ThrowMagickException(exception,GetMagickModule(),
4186 OptionWarning,
"UnrecognizedComposeOperator",
"'%s' '%s'",
4187 "morphology:compose",artifact);
4189 compose=(CompositeOperator)parse;
4193 morphology_image = MorphologyApply(image,method,iterations,
4194 curr_kernel,compose,bias,exception);
4197 if ( curr_kernel != kernel )
4198 curr_kernel=DestroyKernelInfo(curr_kernel);
4199 return(morphology_image);
4232static void RotateKernelInfo(KernelInfo *kernel,
double angle)
4235 if ( kernel->next != (KernelInfo *) NULL)
4236 RotateKernelInfo(kernel->next, angle);
4244 angle = fmod(angle, 360.0);
4248 if ( 337.5 < angle || angle <= 22.5 )
4252 switch (kernel->type) {
4254 case GaussianKernel:
4259 case LaplacianKernel:
4260 case ChebyshevKernel:
4261 case ManhattanKernel:
4262 case EuclideanKernel:
4276 if ( 135.0 < angle && angle <= 225.0 )
4278 if ( 225.0 < angle && angle <= 315.0 )
4286 if ( 22.5 < fmod(angle,90.0) && fmod(angle,90.0) <= 67.5 )
4288 if ( kernel->width == 3 && kernel->height == 3 )
4290 double t = kernel->values[0];
4291 kernel->values[0] = kernel->values[3];
4292 kernel->values[3] = kernel->values[6];
4293 kernel->values[6] = kernel->values[7];
4294 kernel->values[7] = kernel->values[8];
4295 kernel->values[8] = kernel->values[5];
4296 kernel->values[5] = kernel->values[2];
4297 kernel->values[2] = kernel->values[1];
4298 kernel->values[1] = t;
4300 if ( kernel->x != 1 || kernel->y != 1 ) {
4302 x = (ssize_t) kernel->x-1;
4303 y = (ssize_t) kernel->y-1;
4304 if ( x == y ) x = 0;
4305 else if ( x == 0 ) x = -y;
4306 else if ( x == -y ) y = 0;
4307 else if ( y == 0 ) y = x;
4308 kernel->x = (ssize_t) x+1;
4309 kernel->y = (ssize_t) y+1;
4311 angle = fmod(angle+315.0, 360.0);
4312 kernel->angle = fmod(kernel->angle+45.0, 360.0);
4315 perror(
"Unable to rotate non-3x3 kernel by 45 degrees");
4317 if ( 45.0 < fmod(angle, 180.0) && fmod(angle,180.0) <= 135.0 )
4319 if ( kernel->width == 1 || kernel->height == 1 )
4325 t = (ssize_t) kernel->width;
4326 kernel->width = kernel->height;
4327 kernel->height = (size_t) t;
4329 kernel->x = kernel->y;
4331 if ( kernel->width == 1 ) {
4332 angle = fmod(angle+270.0, 360.0);
4333 kernel->angle = fmod(kernel->angle+90.0, 360.0);
4335 angle = fmod(angle+90.0, 360.0);
4336 kernel->angle = fmod(kernel->angle+270.0, 360.0);
4339 else if ( kernel->width == kernel->height )
4348 for( i=0, x=(ssize_t) kernel->width-1; i<=x; i++, x--)
4349 for( j=0, y=(ssize_t) kernel->height-1; j<y; j++, y--)
4350 { t = k[i+j*(ssize_t) kernel->width];
4351 k[i+j*(ssize_t) kernel->width] = k[j+x*(ssize_t) kernel->width];
4352 k[j+x*(ssize_t) kernel->width] = k[x+y*(ssize_t) kernel->width];
4353 k[x+y*(ssize_t) kernel->width] = k[y+i*(ssize_t) kernel->width];
4354 k[y+i*(ssize_t) kernel->width] = t;
4359 x = (ssize_t) (kernel->x*2-(ssize_t) kernel->width+1);
4360 y = (ssize_t) (kernel->y*2-(ssize_t) kernel->height+1);
4361 kernel->x = (ssize_t) ( -y +(ssize_t) kernel->width-1)/2;
4362 kernel->y = (ssize_t) ( +x +(ssize_t) kernel->height-1)/2;
4364 angle = fmod(angle+270.0, 360.0);
4365 kernel->angle = fmod(kernel->angle+90.0, 360.0);
4368 perror(
"Unable to rotate a non-square, non-linear kernel 90 degrees");
4370 if ( 135.0 < angle && angle <= 225.0 )
4388 j=(ssize_t) (kernel->width*kernel->height-1);
4389 for (i=0; i < j; i++, j--)
4390 t=k[i], k[i]=k[j], k[j]=t;
4392 kernel->x = (ssize_t) kernel->width - kernel->x - 1;
4393 kernel->y = (ssize_t) kernel->height - kernel->y - 1;
4394 angle = fmod(angle-180.0, 360.0);
4395 kernel->angle = fmod(kernel->angle+180.0, 360.0);
4439MagickExport
void ScaleGeometryKernelInfo (KernelInfo *kernel,
4440 const char *geometry)
4448 SetGeometryInfo(&args);
4449 flags = ParseGeometry(geometry, &args);
4453 (void) FormatLocaleFile(stderr,
"Geometry = 0x%04X : %lg x %lg %+lg %+lg\n",
4454 flags, args.rho, args.sigma, args.xi, args.psi );
4457 if ( (flags & PercentValue) != 0 )
4458 args.rho *= 0.01, args.sigma *= 0.01;
4460 if ( (flags & RhoValue) == 0 )
4462 if ( (flags & SigmaValue) == 0 )
4466 ScaleKernelInfo(kernel, args.rho, (GeometryFlags) flags);
4469 if ( (flags & SigmaValue) != 0 )
4470 UnityAddKernelInfo(kernel, args.sigma);
4545MagickExport
void ScaleKernelInfo(KernelInfo *kernel,
4546 const double scaling_factor,
const GeometryFlags normalize_flags)
4556 if ( kernel->next != (KernelInfo *) NULL)
4557 ScaleKernelInfo(kernel->next, scaling_factor, normalize_flags);
4561 if ( (normalize_flags&NormalizeValue) != 0 ) {
4562 if ( fabs(kernel->positive_range + kernel->negative_range) >= MagickEpsilon )
4564 pos_scale = fabs(kernel->positive_range + kernel->negative_range);
4567 pos_scale = kernel->positive_range;
4570 if ( (normalize_flags&CorrelateNormalizeValue) != 0 ) {
4571 pos_scale = ( fabs(kernel->positive_range) >= MagickEpsilon )
4572 ? kernel->positive_range : 1.0;
4573 neg_scale = ( fabs(kernel->negative_range) >= MagickEpsilon )
4574 ? -kernel->negative_range : 1.0;
4577 neg_scale = pos_scale;
4580 pos_scale = scaling_factor/pos_scale;
4581 neg_scale = scaling_factor/neg_scale;
4583 for (i=0; i < (ssize_t) (kernel->width*kernel->height); i++)
4584 if (!IsNaN(kernel->values[i]))
4585 kernel->values[i] *= (kernel->values[i] >= 0) ? pos_scale : neg_scale;
4588 kernel->positive_range *= pos_scale;
4589 kernel->negative_range *= neg_scale;
4591 kernel->maximum *= (kernel->maximum >= 0.0) ? pos_scale : neg_scale;
4592 kernel->minimum *= (kernel->minimum >= 0.0) ? pos_scale : neg_scale;
4595 if ( scaling_factor < MagickEpsilon ) {
4597 t = kernel->positive_range;
4598 kernel->positive_range = kernel->negative_range;
4599 kernel->negative_range = t;
4600 t = kernel->maximum;
4601 kernel->maximum = kernel->minimum;
4602 kernel->minimum = 1;
4632MagickPrivate
void ShowKernelInfo(
const KernelInfo *kernel)
4640 for (c=0, k=kernel; k != (KernelInfo *) NULL; c++, k=k->next ) {
4642 (void) FormatLocaleFile(stderr,
"Kernel");
4643 if ( kernel->next != (KernelInfo *) NULL )
4644 (void) FormatLocaleFile(stderr,
" #%lu", (
unsigned long) c );
4645 (void) FormatLocaleFile(stderr,
" \"%s",
4646 CommandOptionToMnemonic(MagickKernelOptions, k->type) );
4647 if ( fabs(k->angle) >= MagickEpsilon )
4648 (void) FormatLocaleFile(stderr,
"@%lg", k->angle);
4649 (void) FormatLocaleFile(stderr,
"\" of size %lux%lu%+ld%+ld",(
unsigned long)
4650 k->width,(
unsigned long) k->height,(
long) k->x,(
long) k->y);
4651 (void) FormatLocaleFile(stderr,
4652 " with values from %.*lg to %.*lg\n",
4653 GetMagickPrecision(), k->minimum,
4654 GetMagickPrecision(), k->maximum);
4655 (void) FormatLocaleFile(stderr,
"Forming a output range from %.*lg to %.*lg",
4656 GetMagickPrecision(), k->negative_range,
4657 GetMagickPrecision(), k->positive_range);
4658 if ( fabs(k->positive_range+k->negative_range) < MagickEpsilon )
4659 (void) FormatLocaleFile(stderr,
" (Zero-Summing)\n");
4660 else if ( fabs(k->positive_range+k->negative_range-1.0) < MagickEpsilon )
4661 (void) FormatLocaleFile(stderr,
" (Normalized)\n");
4663 (
void) FormatLocaleFile(stderr,
" (Sum %.*lg)\n",
4664 GetMagickPrecision(), k->positive_range+k->negative_range);
4665 for (i=v=0; v < k->height; v++) {
4666 (void) FormatLocaleFile(stderr,
"%2lu:", (
unsigned long) v );
4667 for (u=0; u < k->width; u++, i++)
4668 if (IsNaN(k->values[i]))
4669 (void) FormatLocaleFile(stderr,
" %*s", GetMagickPrecision()+3,
"nan");
4671 (
void) FormatLocaleFile(stderr,
" %*.*lg", GetMagickPrecision()+3,
4672 GetMagickPrecision(), (
double) k->values[i]);
4673 (void) FormatLocaleFile(stderr,
"\n");
4711MagickExport
void UnityAddKernelInfo(KernelInfo *kernel,
4715 if ( kernel->next != (KernelInfo *) NULL)
4716 UnityAddKernelInfo(kernel->next, scale);
4719 kernel->values[kernel->x+kernel->y*(ssize_t) kernel->width] += scale;
4720 CalcKernelMetaData(kernel);
4750MagickPrivate
void ZeroKernelNans(KernelInfo *kernel)
4756 if (kernel->next != (KernelInfo *) NULL)
4757 ZeroKernelNans(kernel->next);
4759 for (i=0; i < (kernel->width*kernel->height); i++)
4760 if (IsNaN(kernel->values[i]))
4761 kernel->values[i]=0.0;