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)
96static inline size_t fact(
size_t n)
99 for(f=1, l=2; l <= n; f=f*l, l++);
103#define fact(n) (CastDoubleToSizeT(tgamma((double) n+1)))
105#define fact(n) (CastDoubleToSizeT(lgamma((double) n+1)))
111 CalcKernelMetaData(KernelInfo *),
112 ExpandMirrorKernelInfo(KernelInfo *),
113 ExpandRotateKernelInfo(KernelInfo *,
const double),
114 RotateKernelInfo(KernelInfo *,
double);
118static inline KernelInfo *LastKernelInfo(KernelInfo *kernel)
120 while (kernel->next != (KernelInfo *) NULL)
213static KernelInfo *ParseKernelArray(
const char *kernel_string)
219 token[MagickPathExtent];
240 kernel=(KernelInfo *) AcquireMagickMemory(
sizeof(*kernel));
241 if (kernel == (KernelInfo *) NULL)
243 (void) memset(kernel,0,
sizeof(*kernel));
244 kernel->minimum = kernel->maximum = kernel->angle = 0.0;
245 kernel->negative_range = kernel->positive_range = 0.0;
246 kernel->type = UserDefinedKernel;
247 kernel->next = (KernelInfo *) NULL;
248 kernel->signature=MagickCoreSignature;
249 if (kernel_string == (
const char *) NULL)
253 end = strchr(kernel_string,
';');
254 if ( end == (
char *) NULL )
255 end = strchr(kernel_string,
'\0');
263 p = strchr(kernel_string,
':');
264 if ( p != (
char *) NULL && p < end)
267 length=MagickMin((
size_t) (p-kernel_string),
sizeof(token)-1);
268 (void) memcpy(token, kernel_string, length);
269 token[length] =
'\0';
270 SetGeometryInfo(&args);
271 flags = ParseGeometry(token, &args);
274 if ( (flags & WidthValue) == 0 )
275 args.rho = args.sigma;
276 if ( args.rho < 1.0 )
278 if ( args.sigma < 1.0 )
279 args.sigma = args.rho;
280 kernel->width = CastDoubleToSizeT(args.rho);
281 kernel->height = CastDoubleToSizeT(args.sigma);
284 if ( args.xi < 0.0 || args.psi < 0.0 )
285 return(DestroyKernelInfo(kernel));
286 kernel->x = ((flags & XValue)!=0) ? (ssize_t)args.xi
287 : (ssize_t) (kernel->width-1)/2;
288 kernel->y = ((flags & YValue)!=0) ? (ssize_t)args.psi
289 : (ssize_t) (kernel->height-1)/2;
290 if ( kernel->x >= (ssize_t) kernel->width ||
291 kernel->y >= (ssize_t) kernel->height )
292 return(DestroyKernelInfo(kernel));
299 p=(
const char *) kernel_string;
300 while ((isspace((
int) ((
unsigned char) *p)) != 0) || (*p ==
'\''))
302 for (i=0; p < end; i++)
304 (void) GetNextToken(p,&p,MagickPathExtent,token);
306 (void) GetNextToken(p,&p,MagickPathExtent,token);
309 kernel->width = kernel->height=CastDoubleToSizeT(sqrt((
double) i+1.0));
310 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
311 p=(
const char *) kernel_string;
312 while ((isspace((
int) ((
unsigned char) *p)) != 0) || (*p ==
'\''))
317 kernel->values=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory(
318 kernel->width,kernel->height*
sizeof(*kernel->values)));
319 if (kernel->values == (MagickRealType *) NULL)
320 return(DestroyKernelInfo(kernel));
321 kernel->minimum=MagickMaximumValue;
322 kernel->maximum=(-MagickMaximumValue);
323 kernel->negative_range = kernel->positive_range = 0.0;
324 for (i=0; (i < (ssize_t) (kernel->width*kernel->height)) && (p < end); i++)
326 (void) GetNextToken(p,&p,MagickPathExtent,token);
328 (void) GetNextToken(p,&p,MagickPathExtent,token);
329 if ( LocaleCompare(
"nan",token) == 0
330 || LocaleCompare(
"-",token) == 0 ) {
331 kernel->values[i] = nan;
334 kernel->values[i] = StringToDouble(token,(
char **) NULL);
335 ( kernel->values[i] < 0)
336 ? ( kernel->negative_range += kernel->values[i] )
337 : ( kernel->positive_range += kernel->values[i] );
338 Minimize(kernel->minimum, kernel->values[i]);
339 Maximize(kernel->maximum, kernel->values[i]);
344 (void) GetNextToken(p,&p,MagickPathExtent,token);
345 if ( *token !=
'\0' && *token !=
';' && *token !=
'\'' )
346 return(DestroyKernelInfo(kernel));
350 if ( i < (ssize_t) (kernel->width*kernel->height) ) {
351 Minimize(kernel->minimum, kernel->values[i]);
352 Maximize(kernel->maximum, kernel->values[i]);
353 for ( ; i < (ssize_t) (kernel->width*kernel->height); i++)
354 kernel->values[i]=0.0;
358 if ( i < (ssize_t) (kernel->width*kernel->height) )
359 return(DestroyKernelInfo(kernel));
363 if (kernel->minimum == MagickMaximumValue)
364 return(DestroyKernelInfo(kernel));
366 if ( (flags & AreaValue) != 0 )
367 ExpandRotateKernelInfo(kernel, 45.0);
368 else if ( (flags & GreaterValue) != 0 )
369 ExpandRotateKernelInfo(kernel, 90.0);
370 else if ( (flags & LessValue) != 0 )
371 ExpandMirrorKernelInfo(kernel);
376static KernelInfo *ParseKernelName(
const char *kernel_string,
377 ExceptionInfo *exception)
380 token[MagickPathExtent] =
"";
402 (void) GetNextToken(kernel_string,&p,MagickPathExtent,token);
403 type=ParseCommandOption(MagickKernelOptions,MagickFalse,token);
404 if ( type < 0 || type == UserDefinedKernel )
405 return((KernelInfo *) NULL);
407 while (((isspace((
int) ((
unsigned char) *p)) != 0) ||
408 (*p ==
',') || (*p ==
':' )) && (*p !=
'\0') && (*p !=
';'))
411 end = strchr(p,
';');
412 if ( end == (
char *) NULL )
413 end = strchr(p,
'\0');
416 length=MagickMin((
size_t) (end-p),
sizeof(token)-1);
417 (void) memcpy(token, p, length);
418 token[length] =
'\0';
419 SetGeometryInfo(&args);
420 flags = ParseGeometry(token, &args);
424 (void) FormatLocaleFile(stderr,
"Geometry = 0x%04X : %lg x %lg %+lg %+lg\n",
425 flags, args.rho, args.sigma, args.xi, args.psi );
432 if ( (flags & WidthValue) == 0 )
441 if ( (flags & HeightValue) == 0 )
445 if ( (flags & XValue) == 0 )
448 case RectangleKernel:
449 if ( (flags & WidthValue) == 0 )
450 args.rho = args.sigma;
451 if ( args.rho < 1.0 )
453 if ( args.sigma < 1.0 )
454 args.sigma = args.rho;
455 if ( (flags & XValue) == 0 )
456 args.xi = (double)(((ssize_t)args.rho-1)/2);
457 if ( (flags & YValue) == 0 )
458 args.psi = (double)(((ssize_t)args.sigma-1)/2);
461 case ChebyshevKernel:
462 case ManhattanKernel:
463 case OctagonalKernel:
464 case EuclideanKernel:
465 if ( (flags & HeightValue) == 0 )
467 else if ( (flags & AspectValue ) != 0 )
468 args.sigma = (double) QuantumRange/(args.sigma+1);
469 else if ( (flags & PercentValue ) != 0 )
470 args.sigma *= (double) QuantumRange/100.0;
476 kernel = AcquireKernelBuiltIn((KernelInfoType)type, &args, exception);
477 if ( kernel == (KernelInfo *) NULL )
481 if ( kernel->next == (KernelInfo *) NULL ) {
482 if ( (flags & AreaValue) != 0 )
483 ExpandRotateKernelInfo(kernel, 45.0);
484 else if ( (flags & GreaterValue) != 0 )
485 ExpandRotateKernelInfo(kernel, 90.0);
486 else if ( (flags & LessValue) != 0 )
487 ExpandMirrorKernelInfo(kernel);
493MagickExport KernelInfo *AcquireKernelInfo(
const char *kernel_string,
494 ExceptionInfo *exception)
502 token[MagickPathExtent];
507 if (kernel_string == (
const char *) NULL)
508 return(ParseKernelArray(kernel_string));
510 kernel_cache=(
char *) NULL;
511 if (*kernel_string ==
'@')
513 kernel_cache=FileToString(kernel_string,~0UL,exception);
514 if (kernel_cache == (
char *) NULL)
515 return((KernelInfo *) NULL);
516 p=(
const char *) kernel_cache;
519 while (GetNextToken(p,(
const char **) NULL,MagickPathExtent,token), *token !=
'\0')
525 if (isalpha((
int) ((
unsigned char) *token)) != 0)
526 new_kernel=ParseKernelName(p,exception);
528 new_kernel=ParseKernelArray(p);
531 if (new_kernel == (KernelInfo *) NULL)
533 if (kernel != (KernelInfo *) NULL)
534 kernel=DestroyKernelInfo(kernel);
535 return((KernelInfo *) NULL);
539 if (kernel == (KernelInfo *) NULL)
542 LastKernelInfo(kernel)->next=new_kernel;
547 if (p == (
char *) NULL)
551 if (kernel_cache != (
char *) NULL)
552 kernel_cache=DestroyString(kernel_cache);
958MagickExport KernelInfo *AcquireKernelBuiltIn(
const KernelInfoType type,
959 const GeometryInfo *args,ExceptionInfo *exception)
975 kernel=(KernelInfo *) NULL;
977 case UndefinedKernel:
978 case UserDefinedKernel:
979 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
980 "InvalidOption",
"`%s'",
"Should not call this function");
981 return((KernelInfo *) NULL);
982 case LaplacianKernel:
991 case DiagonalsKernel:
993 case LineJunctionsKernel:
995 case ConvexHullKernel:
1002 case GaussianKernel:
1007 case BinomialKernel:
1010 case RectangleKernel:
1017 case ChebyshevKernel:
1018 case ManhattanKernel:
1019 case OctagonalKernel:
1020 case EuclideanKernel:
1025 kernel=(KernelInfo *) AcquireMagickMemory(
sizeof(*kernel));
1026 if (kernel == (KernelInfo *) NULL)
1028 (void) memset(kernel,0,
sizeof(*kernel));
1029 kernel->minimum = kernel->maximum = kernel->angle = 0.0;
1030 kernel->negative_range = kernel->positive_range = 0.0;
1031 kernel->type = type;
1032 kernel->next = (KernelInfo *) NULL;
1033 kernel->signature=MagickCoreSignature;
1043 kernel->height = kernel->width = (size_t) 1;
1044 kernel->x = kernel->y = (ssize_t) 0;
1045 kernel->values=(MagickRealType *) MagickAssumeAligned(
1046 AcquireAlignedMemory(1,
sizeof(*kernel->values)));
1047 if (kernel->values == (MagickRealType *) NULL)
1048 return(DestroyKernelInfo(kernel));
1049 kernel->maximum = kernel->values[0] = args->rho;
1053 case GaussianKernel:
1057 sigma = fabs(args->sigma),
1058 sigma2 = fabs(args->xi),
1061 if ( args->rho >= 1.0 )
1062 kernel->width = CastDoubleToSizeT(args->rho)*2+1;
1063 else if ( (type != DoGKernel) || (sigma >= sigma2) )
1064 kernel->width = GetOptimalKernelWidth2D(args->rho,sigma);
1066 kernel->width = GetOptimalKernelWidth2D(args->rho,sigma2);
1067 kernel->height = kernel->width;
1068 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1069 kernel->values=(MagickRealType *) MagickAssumeAligned(
1070 AcquireAlignedMemory(kernel->width,kernel->height*
1071 sizeof(*kernel->values)));
1072 if (kernel->values == (MagickRealType *) NULL)
1073 return(DestroyKernelInfo(kernel));
1082 if ( type == GaussianKernel || type == DoGKernel )
1084 if ( sigma > MagickEpsilon )
1085 { A = 1.0/(2.0*sigma*sigma);
1086 B = (double) (1.0/(Magick2PI*sigma*sigma));
1087 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1088 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1089 kernel->values[i] = exp(-((
double)(u*u+v*v))*A)*B;
1092 { (void) memset(kernel->values,0, (
size_t)
1093 kernel->width*kernel->height*
sizeof(*kernel->values));
1094 kernel->values[kernel->x+kernel->y*(ssize_t) kernel->width] = 1.0;
1098 if ( type == DoGKernel )
1100 if ( sigma2 > MagickEpsilon )
1102 A = 1.0/(2.0*sigma*sigma);
1103 B = (double) (1.0/(Magick2PI*sigma*sigma));
1104 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1105 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1106 kernel->values[i] -= exp(-((
double)(u*u+v*v))*A)*B;
1109 kernel->values[kernel->x+kernel->y*(ssize_t) kernel->width] -= 1.0;
1112 if ( type == LoGKernel )
1114 if ( sigma > MagickEpsilon )
1115 { A = 1.0/(2.0*sigma*sigma);
1116 B = (double) (1.0/(MagickPI*sigma*sigma*sigma*sigma));
1117 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1118 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1119 { R = ((double)(u*u+v*v))*A;
1120 kernel->values[i] = (1-R)*exp(-R)*B;
1124 { (void) memset(kernel->values,0, (
size_t)
1125 kernel->width*kernel->height*
sizeof(*kernel->values));
1126 kernel->values[kernel->x+kernel->y*(ssize_t) kernel->width] = 1.0;
1143 CalcKernelMetaData(kernel);
1144 ScaleKernelInfo(kernel, 1.0, CorrelateNormalizeValue);
1150 sigma = fabs(args->sigma),
1153 if ( args->rho >= 1.0 )
1154 kernel->width = CastDoubleToSizeT(args->rho)*2+1;
1156 kernel->width = GetOptimalKernelWidth1D(args->rho,sigma);
1158 kernel->x = (ssize_t) (kernel->width-1)/2;
1160 kernel->negative_range = kernel->positive_range = 0.0;
1161 kernel->values=(MagickRealType *) MagickAssumeAligned(
1162 AcquireAlignedMemory(kernel->width,kernel->height*
1163 sizeof(*kernel->values)));
1164 if (kernel->values == (MagickRealType *) NULL)
1165 return(DestroyKernelInfo(kernel));
1183 v = (ssize_t) (kernel->width*KernelRank-1)/2;
1184 (void) memset(kernel->values,0, (
size_t)
1185 kernel->width*kernel->height*
sizeof(*kernel->values));
1187 if ( sigma > MagickEpsilon )
1188 { sigma *= KernelRank;
1189 alpha = 1.0/(2.0*sigma*sigma);
1190 beta= (double) (1.0/(MagickSQ2PI*sigma ));
1191 for ( u=-v; u <= v; u++) {
1192 kernel->values[(u+v)/KernelRank] +=
1193 exp(-((
double)(u*u))*alpha)*beta;
1197 kernel->values[kernel->x+kernel->y*(ssize_t) kernel->width] = 1.0;
1203 if ( sigma > MagickEpsilon )
1204 { alpha = 1.0/(2.0*sigma*sigma);
1205 beta = 1.0/(MagickSQ2PI*sigma);
1206 for ( i=0, u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1207 kernel->values[i] = exp(-((
double)(u*u))*alpha)*beta;
1210 { (void) memset(kernel->values,0, (
size_t)
1211 kernel->width*kernel->height*
sizeof(*kernel->values));
1212 kernel->values[kernel->x+kernel->y*kernel->width] = 1.0;
1229 CalcKernelMetaData(kernel);
1230 ScaleKernelInfo(kernel, 1.0, CorrelateNormalizeValue);
1233 RotateKernelInfo(kernel, args->xi );
1238 sigma = fabs(args->sigma),
1241 if ( args->rho < 1.0 )
1242 kernel->width = (GetOptimalKernelWidth1D(args->rho,sigma)-1)/2+1;
1244 kernel->width = CastDoubleToSizeT(args->rho);
1245 kernel->x = kernel->y = 0;
1247 kernel->negative_range = kernel->positive_range = 0.0;
1248 kernel->values=(MagickRealType *) MagickAssumeAligned(
1249 AcquireAlignedMemory(kernel->width,kernel->height*
1250 sizeof(*kernel->values)));
1251 if (kernel->values == (MagickRealType *) NULL)
1252 return(DestroyKernelInfo(kernel));
1264 if ( sigma > MagickEpsilon )
1268 v = (ssize_t) kernel->width*KernelRank;
1269 (void) memset(kernel->values,0, (
size_t)
1270 kernel->width*
sizeof(*kernel->values));
1271 sigma *= KernelRank;
1272 A = 1.0/(2.0*sigma*sigma);
1274 for ( u=0; u < v; u++) {
1275 kernel->values[u/KernelRank] +=
1276 exp(-((
double)(u*u))*A);
1279 for (i=0; i < (ssize_t) kernel->width; i++)
1280 kernel->positive_range += kernel->values[i];
1282 A = 1.0/(2.0*sigma*sigma);
1284 for ( i=0; i < (ssize_t) kernel->width; i++)
1285 kernel->positive_range +=
1286 kernel->values[i] = exp(-((
double)(i*i))*A);
1291 { (void) memset(kernel->values,0, (
size_t)
1292 kernel->width*kernel->height*
sizeof(*kernel->values));
1293 kernel->values[kernel->x+kernel->y*(ssize_t) kernel->width] = 1.0;
1294 kernel->positive_range = 1.0;
1297 kernel->minimum = 0.0;
1298 kernel->maximum = kernel->values[0];
1299 kernel->negative_range = 0.0;
1301 ScaleKernelInfo(kernel, 1.0, NormalizeValue);
1302 RotateKernelInfo(kernel, args->xi);
1305 case BinomialKernel:
1310 if (args->rho < 1.0)
1311 kernel->width = kernel->height = 3;
1313 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
1314 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1316 order_f = fact(kernel->width-1);
1318 kernel->values=(MagickRealType *) MagickAssumeAligned(
1319 AcquireAlignedMemory(kernel->width,kernel->height*
1320 sizeof(*kernel->values)));
1321 if (kernel->values == (MagickRealType *) NULL)
1322 return(DestroyKernelInfo(kernel));
1325 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) );
1328 for ( u=0; u < (ssize_t)kernel->width; u++, i++)
1329 kernel->positive_range += kernel->values[i] = (
double)
1330 (alpha * order_f / ( fact((
size_t) u) * fact(kernel->height-(
size_t) u-1) ));
1332 kernel->minimum = 1.0;
1333 kernel->maximum = kernel->values[kernel->x+kernel->y*(ssize_t) kernel->width];
1334 kernel->negative_range = 0.0;
1341 case LaplacianKernel:
1342 {
switch ( (
int) args->rho ) {
1345 kernel=ParseKernelArray(
"3: -1,-1,-1 -1,8,-1 -1,-1,-1");
1348 kernel=ParseKernelArray(
"3: 0,-1,0 -1,4,-1 0,-1,0");
1351 kernel=ParseKernelArray(
"3: -2,1,-2 1,4,1 -2,1,-2");
1354 kernel=ParseKernelArray(
"3: 1,-2,1 -2,4,-2 1,-2,1");
1357 kernel=ParseKernelArray(
1358 "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");
1361 kernel=ParseKernelArray(
1362 "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" );
1365 kernel=ParseKernelArray(
1366 "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");
1370 kernel=ParseKernelArray(
1371 "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");
1374 if (kernel == (KernelInfo *) NULL)
1376 kernel->type = type;
1381 kernel=ParseKernelArray(
"3: 1,0,-1 2,0,-2 1,0,-1");
1382 if (kernel == (KernelInfo *) NULL)
1384 kernel->type = type;
1385 RotateKernelInfo(kernel, args->rho);
1390 kernel=ParseKernelArray(
"3: 0,0,0 1,-1,0 0,0,0");
1391 if (kernel == (KernelInfo *) NULL)
1393 kernel->type = type;
1394 RotateKernelInfo(kernel, args->rho);
1399 kernel=ParseKernelArray(
"3: 1,0,-1 1,0,-1 1,0,-1");
1400 if (kernel == (KernelInfo *) NULL)
1402 kernel->type = type;
1403 RotateKernelInfo(kernel, args->rho);
1408 kernel=ParseKernelArray(
"3: 1,1,-1 1,-2,-1 1,1,-1");
1409 if (kernel == (KernelInfo *) NULL)
1411 kernel->type = type;
1412 RotateKernelInfo(kernel, args->rho);
1417 kernel=ParseKernelArray(
"3: 5,-3,-3 5,0,-3 5,-3,-3");
1418 if (kernel == (KernelInfo *) NULL)
1420 kernel->type = type;
1421 RotateKernelInfo(kernel, args->rho);
1424 case FreiChenKernel:
1428 {
switch ( (
int) args->rho ) {
1431 kernel=ParseKernelArray(
"3: 1,0,-1 2,0,-2 1,0,-1");
1432 if (kernel == (KernelInfo *) NULL)
1434 kernel->type = type;
1435 kernel->values[3] = +(MagickRealType) MagickSQ2;
1436 kernel->values[5] = -(MagickRealType) MagickSQ2;
1437 CalcKernelMetaData(kernel);
1440 kernel=ParseKernelArray(
"3: 1,2,0 2,0,-2 0,-2,-1");
1441 if (kernel == (KernelInfo *) NULL)
1443 kernel->type = type;
1444 kernel->values[1] = kernel->values[3]= +(MagickRealType) MagickSQ2;
1445 kernel->values[5] = kernel->values[7]= -(MagickRealType) MagickSQ2;
1446 CalcKernelMetaData(kernel);
1447 ScaleKernelInfo(kernel, (
double) (1.0/2.0*MagickSQ2), NoValue);
1451 kernel=AcquireKernelInfo(
"FreiChen:11;FreiChen:12;FreiChen:13;FreiChen:14;FreiChen:15;FreiChen:16;FreiChen:17;FreiChen:18;FreiChen:19",exception);
1452 if (kernel == (KernelInfo *) NULL)
1458 kernel=ParseKernelArray(
"3: 1,0,-1 2,0,-2 1,0,-1");
1459 if (kernel == (KernelInfo *) NULL)
1461 kernel->type = type;
1462 kernel->values[3] = +(MagickRealType) MagickSQ2;
1463 kernel->values[5] = -(MagickRealType) MagickSQ2;
1464 CalcKernelMetaData(kernel);
1465 ScaleKernelInfo(kernel, (
double) (1.0/2.0*MagickSQ2), NoValue);
1468 kernel=ParseKernelArray(
"3: 1,2,1 0,0,0 1,2,1");
1469 if (kernel == (KernelInfo *) NULL)
1471 kernel->type = type;
1472 kernel->values[1] = +(MagickRealType) MagickSQ2;
1473 kernel->values[7] = +(MagickRealType) MagickSQ2;
1474 CalcKernelMetaData(kernel);
1475 ScaleKernelInfo(kernel, (
double) (1.0/2.0*MagickSQ2), NoValue);
1478 kernel=ParseKernelArray(
"3: 2,-1,0 -1,0,1 0,1,-2");
1479 if (kernel == (KernelInfo *) NULL)
1481 kernel->type = type;
1482 kernel->values[0] = +(MagickRealType) MagickSQ2;
1483 kernel->values[8] = -(MagickRealType) MagickSQ2;
1484 CalcKernelMetaData(kernel);
1485 ScaleKernelInfo(kernel, (
double) (1.0/2.0*MagickSQ2), NoValue);
1488 kernel=ParseKernelArray(
"3: 0,1,-2 -1,0,1 2,-1,0");
1489 if (kernel == (KernelInfo *) NULL)
1491 kernel->type = type;
1492 kernel->values[2] = -(MagickRealType) MagickSQ2;
1493 kernel->values[6] = +(MagickRealType) MagickSQ2;
1494 CalcKernelMetaData(kernel);
1495 ScaleKernelInfo(kernel, (
double) (1.0/2.0*MagickSQ2), NoValue);
1498 kernel=ParseKernelArray(
"3: 0,-1,0 1,0,1 0,-1,0");
1499 if (kernel == (KernelInfo *) NULL)
1501 kernel->type = type;
1502 ScaleKernelInfo(kernel, 1.0/2.0, NoValue);
1505 kernel=ParseKernelArray(
"3: 1,0,-1 0,0,0 -1,0,1");
1506 if (kernel == (KernelInfo *) NULL)
1508 kernel->type = type;
1509 ScaleKernelInfo(kernel, 1.0/2.0, NoValue);
1512 kernel=ParseKernelArray(
"3: 1,-2,1 -2,4,-2 -1,-2,1");
1513 if (kernel == (KernelInfo *) NULL)
1515 kernel->type = type;
1516 ScaleKernelInfo(kernel, 1.0/6.0, NoValue);
1519 kernel=ParseKernelArray(
"3: -2,1,-2 1,4,1 -2,1,-2");
1520 if (kernel == (KernelInfo *) NULL)
1522 kernel->type = type;
1523 ScaleKernelInfo(kernel, 1.0/6.0, NoValue);
1526 kernel=ParseKernelArray(
"3: 1,1,1 1,1,1 1,1,1");
1527 if (kernel == (KernelInfo *) NULL)
1529 kernel->type = type;
1530 ScaleKernelInfo(kernel, 1.0/3.0, NoValue);
1533 if ( fabs(args->sigma) >= MagickEpsilon )
1535 RotateKernelInfo(kernel, args->sigma);
1536 else if ( args->rho > 30.0 || args->rho < -30.0 )
1538 RotateKernelInfo(kernel, args->rho);
1547 if (args->rho < 1.0)
1548 kernel->width = kernel->height = 3;
1550 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
1551 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1553 kernel->values=(MagickRealType *) MagickAssumeAligned(
1554 AcquireAlignedMemory(kernel->width,kernel->height*
1555 sizeof(*kernel->values)));
1556 if (kernel->values == (MagickRealType *) NULL)
1557 return(DestroyKernelInfo(kernel));
1560 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1561 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1562 if ( (labs((
long) u)+labs((
long) v)) <= (
long) kernel->x)
1563 kernel->positive_range += kernel->values[i] = args->sigma;
1565 kernel->values[i] = nan;
1566 kernel->minimum = kernel->maximum = args->sigma;
1570 case RectangleKernel:
1573 if ( type == SquareKernel )
1575 if (args->rho < 1.0)
1576 kernel->width = kernel->height = 3;
1578 kernel->width = kernel->height = CastDoubleToSizeT(args->rho*2+1);
1579 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1580 scale = args->sigma;
1584 if ( args->rho < 1.0 || args->sigma < 1.0 )
1585 return(DestroyKernelInfo(kernel));
1586 kernel->width = CastDoubleToSizeT(args->rho);
1587 kernel->height = CastDoubleToSizeT(args->sigma);
1588 if ( args->xi < 0.0 || args->xi > (
double)kernel->width ||
1589 args->psi < 0.0 || args->psi > (
double)kernel->height )
1590 return(DestroyKernelInfo(kernel));
1591 kernel->x = (ssize_t) args->xi;
1592 kernel->y = (ssize_t) args->psi;
1595 kernel->values=(MagickRealType *) MagickAssumeAligned(
1596 AcquireAlignedMemory(kernel->width,kernel->height*
1597 sizeof(*kernel->values)));
1598 if (kernel->values == (MagickRealType *) NULL)
1599 return(DestroyKernelInfo(kernel));
1602 u=(ssize_t) (kernel->width*kernel->height);
1603 for ( i=0; i < u; i++)
1604 kernel->values[i] = scale;
1605 kernel->minimum = kernel->maximum = scale;
1606 kernel->positive_range = scale*u;
1611 if (args->rho < 1.0)
1612 kernel->width = kernel->height = 5;
1614 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
1615 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1617 kernel->values=(MagickRealType *) MagickAssumeAligned(
1618 AcquireAlignedMemory(kernel->width,kernel->height*
1619 sizeof(*kernel->values)));
1620 if (kernel->values == (MagickRealType *) NULL)
1621 return(DestroyKernelInfo(kernel));
1623 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1624 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1625 if ( (labs((
long) u)+labs((
long) v)) <=
1626 ((
long)kernel->x + (
long)(kernel->x/2)) )
1627 kernel->positive_range += kernel->values[i] = args->sigma;
1629 kernel->values[i] = nan;
1630 kernel->minimum = kernel->maximum = args->sigma;
1636 limit = (ssize_t)(args->rho*args->rho);
1638 if (args->rho < 0.4)
1639 kernel->width = kernel->height = 9L, limit = 18L;
1641 kernel->width = kernel->height = CastDoubleToSizeT(fabs(args->rho))*2+1;
1642 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1644 kernel->values=(MagickRealType *) MagickAssumeAligned(
1645 AcquireAlignedMemory(kernel->width,kernel->height*
1646 sizeof(*kernel->values)));
1647 if (kernel->values == (MagickRealType *) NULL)
1648 return(DestroyKernelInfo(kernel));
1650 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1651 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1652 if ((u*u+v*v) <= limit)
1653 kernel->positive_range += kernel->values[i] = args->sigma;
1655 kernel->values[i] = nan;
1656 kernel->minimum = kernel->maximum = args->sigma;
1661 if (args->rho < 1.0)
1662 kernel->width = kernel->height = 5;
1664 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
1665 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1667 kernel->values=(MagickRealType *) MagickAssumeAligned(
1668 AcquireAlignedMemory(kernel->width,kernel->height*
1669 sizeof(*kernel->values)));
1670 if (kernel->values == (MagickRealType *) NULL)
1671 return(DestroyKernelInfo(kernel));
1674 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1675 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1676 kernel->values[i] = (u == 0 || v == 0) ? args->sigma : nan;
1677 kernel->minimum = kernel->maximum = args->sigma;
1678 kernel->positive_range = args->sigma*(kernel->width*2.0 - 1.0);
1683 if (args->rho < 1.0)
1684 kernel->width = kernel->height = 5;
1686 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
1687 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1689 kernel->values=(MagickRealType *) MagickAssumeAligned(
1690 AcquireAlignedMemory(kernel->width,kernel->height*
1691 sizeof(*kernel->values)));
1692 if (kernel->values == (MagickRealType *) NULL)
1693 return(DestroyKernelInfo(kernel));
1696 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1697 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1698 kernel->values[i] = (u == v || u == -v) ? args->sigma : nan;
1699 kernel->minimum = kernel->maximum = args->sigma;
1700 kernel->positive_range = args->sigma*(kernel->width*2.0 - 1.0);
1714 if (args->rho < args->sigma)
1716 kernel->width = CastDoubleToSizeT(args->sigma)*2+1;
1717 limit1 = (ssize_t)(args->rho*args->rho);
1718 limit2 = (ssize_t)(args->sigma*args->sigma);
1722 kernel->width = CastDoubleToSizeT(args->rho)*2+1;
1723 limit1 = (ssize_t)(args->sigma*args->sigma);
1724 limit2 = (ssize_t)(args->rho*args->rho);
1727 kernel->width = 7L, limit1 = 7L, limit2 = 11L;
1729 kernel->height = kernel->width;
1730 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1731 kernel->values=(MagickRealType *) MagickAssumeAligned(
1732 AcquireAlignedMemory(kernel->width,kernel->height*
1733 sizeof(*kernel->values)));
1734 if (kernel->values == (MagickRealType *) NULL)
1735 return(DestroyKernelInfo(kernel));
1738 scale = (ssize_t) (( type == PeaksKernel) ? 0.0 : args->xi);
1739 for ( i=0, v= -kernel->y; v <= (ssize_t)kernel->y; v++)
1740 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1741 { ssize_t radius=u*u+v*v;
1742 if (limit1 < radius && radius <= limit2)
1743 kernel->positive_range += kernel->values[i] = (double) scale;
1745 kernel->values[i] = nan;
1747 kernel->minimum = kernel->maximum = (double) scale;
1748 if ( type == PeaksKernel ) {
1750 kernel->values[kernel->x+kernel->y*(ssize_t) kernel->width] = 1.0;
1751 kernel->positive_range = 1.0;
1752 kernel->maximum = 1.0;
1758 kernel=AcquireKernelInfo(
"ThinSE:482",exception);
1759 if (kernel == (KernelInfo *) NULL)
1761 kernel->type = type;
1762 ExpandMirrorKernelInfo(kernel);
1767 kernel=AcquireKernelInfo(
"ThinSE:87",exception);
1768 if (kernel == (KernelInfo *) NULL)
1770 kernel->type = type;
1771 ExpandRotateKernelInfo(kernel, 90.0);
1774 case DiagonalsKernel:
1776 switch ( (
int) args->rho ) {
1781 kernel=ParseKernelArray(
"3: 0,0,0 0,-,1 1,1,-");
1782 if (kernel == (KernelInfo *) NULL)
1784 kernel->type = type;
1785 new_kernel=ParseKernelArray(
"3: 0,0,1 0,-,1 0,1,-");
1786 if (new_kernel == (KernelInfo *) NULL)
1787 return(DestroyKernelInfo(kernel));
1788 new_kernel->type = type;
1789 LastKernelInfo(kernel)->next = new_kernel;
1790 ExpandMirrorKernelInfo(kernel);
1794 kernel=ParseKernelArray(
"3: 0,0,0 0,-,1 1,1,-");
1797 kernel=ParseKernelArray(
"3: 0,0,1 0,-,1 0,1,-");
1800 if (kernel == (KernelInfo *) NULL)
1802 kernel->type = type;
1803 RotateKernelInfo(kernel, args->sigma);
1806 case LineEndsKernel:
1808 switch ( (
int) args->rho ) {
1812 return(AcquireKernelInfo(
"LineEnds:1>;LineEnds:2>",exception));
1815 kernel=ParseKernelArray(
"3: 0,0,- 0,1,1 0,0,-");
1819 kernel=ParseKernelArray(
"3: 0,0,0 0,1,0 0,0,1");
1823 kernel=ParseKernelArray(
"3: 0,0,0 0,1,1 0,0,0");
1827 kernel=ParseKernelArray(
"3: 0,0,0 0,1,- 0,0,-");
1830 if (kernel == (KernelInfo *) NULL)
1832 kernel->type = type;
1833 RotateKernelInfo(kernel, args->sigma);
1836 case LineJunctionsKernel:
1838 switch ( (
int) args->rho ) {
1842 return(AcquireKernelInfo(
"LineJunctions:1@;LineJunctions:2>",exception));
1845 kernel=ParseKernelArray(
"3: 1,-,1 -,1,- -,1,-");
1849 kernel=ParseKernelArray(
"3: 1,-,- -,1,- 1,-,1");
1853 kernel=ParseKernelArray(
"3: -,-,- 1,1,1 -,1,-");
1857 kernel=ParseKernelArray(
"3: 1,-,1 -,1,- 1,-,1");
1861 kernel=ParseKernelArray(
"3: -,1,- 1,1,1 -,1,-");
1864 if (kernel == (KernelInfo *) NULL)
1866 kernel->type = type;
1867 RotateKernelInfo(kernel, args->sigma);
1874 switch ( (
int) args->rho ) {
1877 kernel=ParseKernelArray(
"3x1:0,1,0");
1878 if (kernel == (KernelInfo *) NULL)
1880 kernel->type = type;
1881 ExpandRotateKernelInfo(kernel, 90.0);
1884 kernel=ParseKernelArray(
"4x1:0,1,1,0");
1885 if (kernel == (KernelInfo *) NULL)
1887 kernel->type = type;
1888 ExpandRotateKernelInfo(kernel, 90.0);
1893 new_kernel=ParseKernelArray(
"4x3+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(
"4x3+2+1: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(
"4x3+1+1:-,1,1,0 -,1,1,- 0,1,1,-");
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(
"4x3+2+1:-,1,1,0 -,1,1,- 0,1,1,-");
1909 if (new_kernel == (KernelInfo *) NULL)
1910 return(DestroyKernelInfo(kernel));
1911 new_kernel->type = type;
1912 LastKernelInfo(kernel)->next = new_kernel;
1913 new_kernel=ParseKernelArray(
"3x4+1+1:0,-,- 1,1,1 1,1,1 -,-,0");
1914 if (new_kernel == (KernelInfo *) NULL)
1915 return(DestroyKernelInfo(kernel));
1916 new_kernel->type = type;
1917 LastKernelInfo(kernel)->next = new_kernel;
1918 new_kernel=ParseKernelArray(
"3x4+1+2:0,-,- 1,1,1 1,1,1 -,-,0");
1919 if (new_kernel == (KernelInfo *) NULL)
1920 return(DestroyKernelInfo(kernel));
1921 new_kernel->type = type;
1922 LastKernelInfo(kernel)->next = new_kernel;
1923 new_kernel=ParseKernelArray(
"3x4+1+1:-,-,0 1,1,1 1,1,1 0,-,-");
1924 if (new_kernel == (KernelInfo *) NULL)
1925 return(DestroyKernelInfo(kernel));
1926 new_kernel->type = type;
1927 LastKernelInfo(kernel)->next = new_kernel;
1928 new_kernel=ParseKernelArray(
"3x4+1+2:-,-,0 1,1,1 1,1,1 0,-,-");
1929 if (new_kernel == (KernelInfo *) NULL)
1930 return(DestroyKernelInfo(kernel));
1931 new_kernel->type = type;
1932 LastKernelInfo(kernel)->next = new_kernel;
1937 case ConvexHullKernel:
1942 kernel=ParseKernelArray(
"3: 1,1,- 1,0,- 1,-,0");
1943 if (kernel == (KernelInfo *) NULL)
1945 kernel->type = type;
1946 ExpandRotateKernelInfo(kernel, 90.0);
1948 new_kernel=ParseKernelArray(
"3: 1,1,1 1,0,- -,-,0");
1949 if (new_kernel == (KernelInfo *) NULL)
1950 return(DestroyKernelInfo(kernel));
1951 new_kernel->type = type;
1952 ExpandRotateKernelInfo(new_kernel, 90.0);
1953 LastKernelInfo(kernel)->next = new_kernel;
1956 case SkeletonKernel:
1958 switch ( (
int) args->rho ) {
1964 kernel=AcquireKernelInfo(
"ThinSE:482",exception);
1965 if (kernel == (KernelInfo *) NULL)
1967 kernel->type = type;
1968 ExpandRotateKernelInfo(kernel, 45.0);
1975 kernel=AcquireKernelInfo(
"ThinSE:482; ThinSE:87x90;",exception);
1976 if (kernel == (KernelInfo *) NULL)
1978 if (kernel->next == (KernelInfo *) NULL)
1979 return(DestroyKernelInfo(kernel));
1980 kernel->type = type;
1981 kernel->next->type = type;
1982 ExpandRotateKernelInfo(kernel, 90.0);
1990 kernel=AcquireKernelInfo(
"ThinSE:41; ThinSE:42; ThinSE:43",
1992 if (kernel == (KernelInfo *) NULL)
1994 if (kernel->next == (KernelInfo *) NULL)
1995 return(DestroyKernelInfo(kernel));
1996 if (kernel->next->next == (KernelInfo *) NULL)
1997 return(DestroyKernelInfo(kernel));
1998 kernel->type = type;
1999 kernel->next->type = type;
2000 kernel->next->next->type = type;
2001 ExpandMirrorKernelInfo(kernel);
2017 switch ( (
int) args->rho ) {
2020 kernel=ParseKernelArray(
"3: -,-,1 0,-,1 -,-,1");
2023 kernel=ParseKernelArray(
"3: -,-,1 0,-,1 -,0,-");
2026 kernel=ParseKernelArray(
"3: -,0,- 0,-,1 -,-,1");
2029 kernel=ParseKernelArray(
"3: -,0,- 0,-,1 -,0,-");
2032 kernel=ParseKernelArray(
"3: -,0,1 0,-,1 -,0,-");
2035 kernel=ParseKernelArray(
"3: -,0,- 0,-,1 -,0,1");
2038 kernel=ParseKernelArray(
"3: -,1,1 0,-,1 -,0,-");
2041 kernel=ParseKernelArray(
"3: -,-,1 0,-,1 0,-,1");
2044 kernel=ParseKernelArray(
"3: 0,-,1 0,-,1 -,-,1");
2048 kernel=ParseKernelArray(
"3: -,1,- 0,-,1 -,1,-");
2051 kernel=ParseKernelArray(
"3: -,1,- 0,-,1 0,-,-");
2054 kernel=ParseKernelArray(
"3: 0,-,- 0,-,1 -,1,-");
2057 kernel=ParseKernelArray(
"3: 0,-,- 0,-,1 0,-,-");
2060 kernel=ParseKernelArray(
"3: 0,-,1 0,-,1 0,-,-");
2063 kernel=ParseKernelArray(
"3: 0,-,- 0,-,1 0,-,1");
2066 kernel=ParseKernelArray(
"3: -,1,- 0,-,1 0,0,-");
2069 kernel=ParseKernelArray(
"3: -,1,- 0,-,1 0,1,-");
2072 kernel=ParseKernelArray(
"3: 0,1,- 0,-,1 -,1,-");
2076 kernel=ParseKernelArray(
"3: -,-,1 0,-,- -,0,-");
2079 kernel=ParseKernelArray(
"3: -,1,- -,-,1 0,-,-");
2082 kernel=ParseKernelArray(
"3: -,1,1 0,-,1 0,0,-");
2086 kernel=ParseKernelArray(
"3: 0,-,1 0,-,1 0,-,1");
2089 if (kernel == (KernelInfo *) NULL)
2091 kernel->type = type;
2092 RotateKernelInfo(kernel, args->sigma);
2098 case ChebyshevKernel:
2100 if (args->rho < 1.0)
2101 kernel->width = kernel->height = 3;
2103 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
2104 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
2106 kernel->values=(MagickRealType *) MagickAssumeAligned(
2107 AcquireAlignedMemory(kernel->width,kernel->height*
2108 sizeof(*kernel->values)));
2109 if (kernel->values == (MagickRealType *) NULL)
2110 return(DestroyKernelInfo(kernel));
2112 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
2113 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
2114 kernel->positive_range += ( kernel->values[i] =
2115 args->sigma*MagickMax(fabs((
double)u),fabs((
double)v)) );
2116 kernel->maximum = kernel->values[0];
2119 case ManhattanKernel:
2121 if (args->rho < 1.0)
2122 kernel->width = kernel->height = 3;
2124 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
2125 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
2127 kernel->values=(MagickRealType *) MagickAssumeAligned(
2128 AcquireAlignedMemory(kernel->width,kernel->height*
2129 sizeof(*kernel->values)));
2130 if (kernel->values == (MagickRealType *) NULL)
2131 return(DestroyKernelInfo(kernel));
2133 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
2134 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
2135 kernel->positive_range += ( kernel->values[i] =
2136 args->sigma*(labs((
long) u)+labs((
long) v)) );
2137 kernel->maximum = kernel->values[0];
2140 case OctagonalKernel:
2142 if (args->rho < 2.0)
2143 kernel->width = kernel->height = 5;
2145 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
2146 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
2148 kernel->values=(MagickRealType *) MagickAssumeAligned(
2149 AcquireAlignedMemory(kernel->width,kernel->height*
2150 sizeof(*kernel->values)));
2151 if (kernel->values == (MagickRealType *) NULL)
2152 return(DestroyKernelInfo(kernel));
2154 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
2155 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
2158 r1 = MagickMax(fabs((
double)u),fabs((
double)v)),
2159 r2 = floor((
double)(labs((
long)u)+labs((
long)v)+1)/1.5);
2160 kernel->positive_range += kernel->values[i] =
2161 args->sigma*MagickMax(r1,r2);
2163 kernel->maximum = kernel->values[0];
2166 case EuclideanKernel:
2168 if (args->rho < 1.0)
2169 kernel->width = kernel->height = 3;
2171 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
2172 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
2174 kernel->values=(MagickRealType *) MagickAssumeAligned(
2175 AcquireAlignedMemory(kernel->width,kernel->height*
2176 sizeof(*kernel->values)));
2177 if (kernel->values == (MagickRealType *) NULL)
2178 return(DestroyKernelInfo(kernel));
2180 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
2181 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
2182 kernel->positive_range += ( kernel->values[i] =
2183 args->sigma*sqrt((
double) (u*u+v*v)) );
2184 kernel->maximum = kernel->values[0];
2190 kernel=ParseKernelArray(
"1:1");
2191 if (kernel == (KernelInfo *) NULL)
2193 kernel->type = UndefinedKernel;
2225MagickExport KernelInfo *CloneKernelInfo(
const KernelInfo *kernel)
2233 assert(kernel != (KernelInfo *) NULL);
2234 new_kernel=(KernelInfo *) AcquireMagickMemory(
sizeof(*kernel));
2235 if (new_kernel == (KernelInfo *) NULL)
2237 *new_kernel=(*kernel);
2240 new_kernel->values=(MagickRealType *) MagickAssumeAligned(
2241 AcquireAlignedMemory(kernel->width,kernel->height*
sizeof(*kernel->values)));
2242 if (new_kernel->values == (MagickRealType *) NULL)
2243 return(DestroyKernelInfo(new_kernel));
2244 for (i=0; i < (ssize_t) (kernel->width*kernel->height); i++)
2245 new_kernel->values[i]=kernel->values[i];
2248 if ( kernel->next != (KernelInfo *) NULL ) {
2249 new_kernel->next = CloneKernelInfo(kernel->next);
2250 if ( new_kernel->next == (KernelInfo *) NULL )
2251 return(DestroyKernelInfo(new_kernel));
2280MagickExport KernelInfo *DestroyKernelInfo(KernelInfo *kernel)
2282 assert(kernel != (KernelInfo *) NULL);
2283 if (kernel->next != (KernelInfo *) NULL)
2284 kernel->next=DestroyKernelInfo(kernel->next);
2285 kernel->values=(MagickRealType *) RelinquishAlignedMemory(kernel->values);
2286 kernel=(KernelInfo *) RelinquishMagickMemory(kernel);
2322static void FlopKernelInfo(KernelInfo *kernel)
2331 for ( y=0, k=kernel->values; y < kernel->height; y++, k+=kernel->width)
2332 for ( x=0, r=kernel->width-1; x<kernel->width/2; x++, r--)
2333 t=k[x], k[x]=k[r], k[r]=t;
2335 kernel->x = kernel->width - kernel->x - 1;
2336 angle = fmod(angle+180.0, 360.0);
2340static void ExpandMirrorKernelInfo(KernelInfo *kernel)
2348 clone = CloneKernelInfo(last);
2349 if (clone == (KernelInfo *) NULL)
2351 RotateKernelInfo(clone, 180);
2352 LastKernelInfo(last)->next = clone;
2355 clone = CloneKernelInfo(last);
2356 if (clone == (KernelInfo *) NULL)
2358 RotateKernelInfo(clone, 90);
2359 LastKernelInfo(last)->next = clone;
2362 clone = CloneKernelInfo(last);
2363 if (clone == (KernelInfo *) NULL)
2365 RotateKernelInfo(clone, 180);
2366 LastKernelInfo(last)->next = clone;
2404static MagickBooleanType SameKernelInfo(
const KernelInfo *kernel1,
2405 const KernelInfo *kernel2)
2411 if ( kernel1->width != kernel2->width
2412 || kernel1->height != kernel2->height
2413 || kernel1->x != kernel2->x
2414 || kernel1->y != kernel2->y )
2418 for (i=0; i < (kernel1->width*kernel1->height); i++) {
2420 if ( IsNaN(kernel1->values[i]) && !IsNaN(kernel2->values[i]) )
2422 if ( IsNaN(kernel2->values[i]) && !IsNaN(kernel1->values[i]) )
2425 if ( fabs(kernel1->values[i] - kernel2->values[i]) >= MagickEpsilon )
2432static void ExpandRotateKernelInfo(KernelInfo *kernel,
const double angle)
2438 clone_info=(KernelInfo *) NULL;
2440DisableMSCWarning(4127)
2443 clone_info=CloneKernelInfo(last);
2444 if (clone_info == (KernelInfo *) NULL)
2446 RotateKernelInfo(clone_info,angle);
2447 if (SameKernelInfo(kernel,clone_info) != MagickFalse)
2449 LastKernelInfo(last)->next=clone_info;
2452 if (clone_info != (KernelInfo *) NULL)
2453 clone_info=DestroyKernelInfo(clone_info);
2493static void CalcKernelMetaData(KernelInfo *kernel)
2498 kernel->minimum = kernel->maximum = 0.0;
2499 kernel->negative_range = kernel->positive_range = 0.0;
2500 for (i=0; i < (kernel->width*kernel->height); i++)
2502 if ( fabs(kernel->values[i]) < MagickEpsilon )
2503 kernel->values[i] = 0.0;
2504 ( kernel->values[i] < 0)
2505 ? ( kernel->negative_range += kernel->values[i] )
2506 : ( kernel->positive_range += kernel->values[i] );
2507 Minimize(kernel->minimum, kernel->values[i]);
2508 Maximize(kernel->maximum, kernel->values[i]);
2574static ssize_t MorphologyPrimitive(
const Image *image,Image *morphology_image,
2575 const MorphologyMethod method,
const KernelInfo *kernel,
const double bias,
2576 ExceptionInfo *exception)
2578#define MorphologyTag "Morphology/Image"
2606 assert(image != (Image *) NULL);
2607 assert(image->signature == MagickCoreSignature);
2608 assert(morphology_image != (Image *) NULL);
2609 assert(morphology_image->signature == MagickCoreSignature);
2610 assert(kernel != (KernelInfo *) NULL);
2611 assert(kernel->signature == MagickCoreSignature);
2612 assert(exception != (ExceptionInfo *) NULL);
2613 assert(exception->signature == MagickCoreSignature);
2616 image_view=AcquireVirtualCacheView(image,exception);
2617 morphology_view=AcquireAuthenticCacheView(morphology_image,exception);
2618 width=image->columns+kernel->width-1;
2623 case ConvolveMorphology:
2624 case DilateMorphology:
2625 case DilateIntensityMorphology:
2626 case IterativeDistanceMorphology:
2631 offset.x=(ssize_t) kernel->width-kernel->x-1;
2632 offset.y=(ssize_t) kernel->height-kernel->y-1;
2635 case ErodeMorphology:
2636 case ErodeIntensityMorphology:
2637 case HitAndMissMorphology:
2638 case ThinningMorphology:
2639 case ThickenMorphology:
2650 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
2651 "InvalidOption",
"`%s'",
"not a primitive morphology method");
2656 changes=(
size_t *) AcquireQuantumMemory(GetOpenMPMaximumThreads(),
2658 if (changes == (
size_t *) NULL)
2659 ThrowFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed");
2660 for (j=0; j < (ssize_t) GetOpenMPMaximumThreads(); j++)
2662 if ((method == ConvolveMorphology) && (kernel->width == 1))
2673#if defined(MAGICKCORE_OPENMP_SUPPORT)
2674 #pragma omp parallel for schedule(static) shared(progress,status) \
2675 magick_number_threads(image,morphology_image,image->columns,1)
2677 for (x=0; x < (ssize_t) image->columns; x++)
2680 id = GetOpenMPThreadId();
2692 if (status == MagickFalse)
2694 p=GetCacheViewVirtualPixels(image_view,x,-offset.y,1,image->rows+
2695 kernel->height-1,exception);
2696 q=GetCacheViewAuthenticPixels(morphology_view,x,0,1,
2697 morphology_image->rows,exception);
2698 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
2703 center=(ssize_t) GetPixelChannels(image)*offset.y;
2704 for (r=0; r < (ssize_t) image->rows; r++)
2709 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2723 const MagickRealType
2727 *magick_restrict pixels;
2735 channel=GetPixelChannelChannel(image,i);
2736 traits=GetPixelChannelTraits(image,channel);
2737 morphology_traits=GetPixelChannelTraits(morphology_image,channel);
2738 if ((traits == UndefinedPixelTrait) ||
2739 (morphology_traits == UndefinedPixelTrait))
2741 if ((traits & CopyPixelTrait) != 0)
2743 SetPixelChannel(morphology_image,channel,p[center+i],q);
2746 k=(&kernel->values[kernel->height-1]);
2751 if (((image->alpha_trait & BlendPixelTrait) == 0) ||
2752 ((morphology_traits & BlendPixelTrait) == 0))
2753 for (v=0; v < (ssize_t) kernel->height; v++)
2757 pixel+=(*k)*(double) pixels[i];
2761 pixels+=(ptrdiff_t) GetPixelChannels(image);
2766 for (v=0; v < (ssize_t) kernel->height; v++)
2770 alpha=(double) (QuantumScale*(
double)
2771 GetPixelAlpha(image,pixels));
2772 pixel+=alpha*(*k)*(double) pixels[i];
2777 pixels+=(ptrdiff_t) GetPixelChannels(image);
2780 if (fabs(pixel-(
double) p[center+i]) >= MagickEpsilon)
2782 gamma=MagickSafeReciprocal(gamma);
2784 gamma*=(double) kernel->height/count;
2785 SetPixelChannel(morphology_image,channel,ClampToQuantum(gamma*
2788 p+=(ptrdiff_t) GetPixelChannels(image);
2789 q+=(ptrdiff_t) GetPixelChannels(morphology_image);
2791 if (SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse)
2793 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2798#if defined(MAGICKCORE_OPENMP_SUPPORT)
2802 proceed=SetImageProgress(image,MorphologyTag,progress,
2804 if (proceed == MagickFalse)
2808 morphology_image->type=image->type;
2809 morphology_view=DestroyCacheView(morphology_view);
2810 image_view=DestroyCacheView(image_view);
2811 for (j=0; j < (ssize_t) GetOpenMPMaximumThreads(); j++)
2812 changed+=changes[j];
2813 changes=(
size_t *) RelinquishMagickMemory(changes);
2814 return(status ? (ssize_t) (changed/GetImageChannels(image)) : 0);
2819#if defined(MAGICKCORE_OPENMP_SUPPORT)
2820 #pragma omp parallel for schedule(static) shared(progress,status) \
2821 magick_number_threads(image,morphology_image,image->rows,1)
2823 for (y=0; y < (ssize_t) image->rows; y++)
2826 id = GetOpenMPThreadId();
2840 if (status == MagickFalse)
2842 p=GetCacheViewVirtualPixels(image_view,-offset.x,y-offset.y,width,
2843 kernel->height,exception);
2844 q=GetCacheViewAuthenticPixels(morphology_view,0,y,morphology_image->columns,
2846 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
2851 center=(ssize_t) ((ssize_t) GetPixelChannels(image)*(ssize_t) width*
2852 offset.y+(ssize_t) GetPixelChannels(image)*offset.x);
2853 for (x=0; x < (ssize_t) image->columns; x++)
2858 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2875 const MagickRealType
2879 *magick_restrict pixels,
2880 *magick_restrict quantum_pixels;
2888 channel=GetPixelChannelChannel(image,i);
2889 traits=GetPixelChannelTraits(image,channel);
2890 morphology_traits=GetPixelChannelTraits(morphology_image,channel);
2891 if ((traits == UndefinedPixelTrait) ||
2892 (morphology_traits == UndefinedPixelTrait))
2894 if ((traits & CopyPixelTrait) != 0)
2896 SetPixelChannel(morphology_image,channel,p[center+i],q);
2900 quantum_pixels=(
const Quantum *) NULL;
2902 minimum=(double) QuantumRange;
2905 case ConvolveMorphology:
2910 case DilateMorphology:
2911 case ErodeIntensityMorphology:
2918 pixel=(double) p[center+i];
2925 case ConvolveMorphology:
2946 k=(&kernel->values[kernel->width*kernel->height-1]);
2947 if (((image->alpha_trait & BlendPixelTrait) == 0) ||
2948 ((morphology_traits & BlendPixelTrait) == 0))
2953 for (v=0; v < (ssize_t) kernel->height; v++)
2955 for (u=0; u < (ssize_t) kernel->width; u++)
2958 pixel+=(*k)*(double) pixels[i];
2960 pixels+=(ptrdiff_t) GetPixelChannels(image);
2962 pixels+=(image->columns-1)*GetPixelChannels(image);
2970 for (v=0; v < (ssize_t) kernel->height; v++)
2972 for (u=0; u < (ssize_t) kernel->width; u++)
2976 alpha=(double) (QuantumScale*(
double)
2977 GetPixelAlpha(image,pixels));
2978 pixel+=alpha*(*k)*(double) pixels[i];
2982 pixels+=(ptrdiff_t) GetPixelChannels(image);
2984 pixels+=(image->columns-1)*GetPixelChannels(image);
2988 case ErodeMorphology:
2999 for (v=0; v < (ssize_t) kernel->height; v++)
3001 for (u=0; u < (ssize_t) kernel->width; u++)
3003 if (!IsNaN(*k) && (*k >= 0.5))
3005 if ((
double) pixels[i] < pixel)
3006 pixel=(double) pixels[i];
3009 pixels+=(ptrdiff_t) GetPixelChannels(image);
3011 pixels+=(image->columns-1)*GetPixelChannels(image);
3015 case DilateMorphology:
3028 k=(&kernel->values[kernel->width*kernel->height-1]);
3029 for (v=0; v < (ssize_t) kernel->height; v++)
3031 for (u=0; u < (ssize_t) kernel->width; u++)
3033 if (!IsNaN(*k) && (*k > 0.5))
3035 if ((
double) pixels[i] > pixel)
3036 pixel=(double) pixels[i];
3039 pixels+=(ptrdiff_t) GetPixelChannels(image);
3041 pixels+=(image->columns-1)*GetPixelChannels(image);
3045 case HitAndMissMorphology:
3046 case ThinningMorphology:
3047 case ThickenMorphology:
3062 for (v=0; v < (ssize_t) kernel->height; v++)
3064 for (u=0; u < (ssize_t) kernel->width; u++)
3070 if ((
double) pixels[i] < minimum)
3071 minimum=(double) pixels[i];
3076 if ((
double) pixels[i] > maximum)
3077 maximum=(double) pixels[i];
3081 pixels+=(ptrdiff_t) GetPixelChannels(image);
3083 pixels+=(image->columns-1)*GetPixelChannels(image);
3089 if (method == ThinningMorphology)
3090 pixel=(double) p[center+i]-minimum;
3092 if (method == ThickenMorphology)
3093 pixel=(double) p[center+i]+minimum;
3096 case ErodeIntensityMorphology:
3104 for (v=0; v < (ssize_t) kernel->height; v++)
3106 for (u=0; u < (ssize_t) kernel->width; u++)
3108 if (!IsNaN(*k) && (*k >= 0.5))
3110 intensity=(double) GetPixelIntensity(image,pixels);
3111 if (intensity < minimum)
3113 quantum_pixels=pixels;
3114 pixel=(double) pixels[i];
3119 pixels+=(ptrdiff_t) GetPixelChannels(image);
3121 pixels+=(image->columns-1)*GetPixelChannels(image);
3125 case DilateIntensityMorphology:
3132 k=(&kernel->values[kernel->width*kernel->height-1]);
3133 for (v=0; v < (ssize_t) kernel->height; v++)
3135 for (u=0; u < (ssize_t) kernel->width; u++)
3137 if (!IsNaN(*k) && (*k >= 0.5))
3139 intensity=(double) GetPixelIntensity(image,pixels);
3140 if (intensity > maximum)
3142 pixel=(double) pixels[i];
3143 quantum_pixels=pixels;
3148 pixels+=(ptrdiff_t) GetPixelChannels(image);
3150 pixels+=(image->columns-1)*GetPixelChannels(image);
3154 case IterativeDistanceMorphology:
3179 k=(&kernel->values[kernel->width*kernel->height-1]);
3180 for (v=0; v < (ssize_t) kernel->height; v++)
3182 for (u=0; u < (ssize_t) kernel->width; u++)
3186 if (((
double) pixels[i]+(*k)) < pixel)
3187 pixel=(double) pixels[i]+(*k);
3190 pixels+=(ptrdiff_t) GetPixelChannels(image);
3192 pixels+=(image->columns-1)*GetPixelChannels(image);
3196 case UndefinedMorphology:
3200 if (quantum_pixels != (
const Quantum *) NULL)
3202 SetPixelChannel(morphology_image,channel,quantum_pixels[i],q);
3205 gamma=MagickSafeReciprocal(gamma);
3206 SetPixelChannel(morphology_image,channel,ClampToQuantum(gamma*pixel),q);
3207 if (fabs(pixel-(
double) p[center+i]) >= MagickEpsilon)
3210 p+=(ptrdiff_t) GetPixelChannels(image);
3211 q+=(ptrdiff_t) GetPixelChannels(morphology_image);
3213 if (SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse)
3215 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3220#if defined(MAGICKCORE_OPENMP_SUPPORT)
3224 proceed=SetImageProgress(image,MorphologyTag,progress,image->rows);
3225 if (proceed == MagickFalse)
3229 morphology_view=DestroyCacheView(morphology_view);
3230 image_view=DestroyCacheView(image_view);
3231 for (j=0; j < (ssize_t) GetOpenMPMaximumThreads(); j++)
3232 changed+=changes[j];
3233 changes=(
size_t *) RelinquishMagickMemory(changes);
3234 return(status ? (ssize_t) (changed/GetImageChannels(image)) : -1);
3250static ssize_t MorphologyPrimitiveDirect(Image *image,
3251 const MorphologyMethod method,
const KernelInfo *kernel,
3252 ExceptionInfo *exception)
3274 assert(image != (Image *) NULL);
3275 assert(image->signature == MagickCoreSignature);
3276 assert(kernel != (KernelInfo *) NULL);
3277 assert(kernel->signature == MagickCoreSignature);
3278 assert(exception != (ExceptionInfo *) NULL);
3279 assert(exception->signature == MagickCoreSignature);
3285 case DistanceMorphology:
3286 case VoronoiMorphology:
3291 offset.x=(ssize_t) kernel->width-kernel->x-1;
3292 offset.y=(ssize_t) kernel->height-kernel->y-1;
3305 image_view=AcquireVirtualCacheView(image,exception);
3306 morphology_view=AcquireAuthenticCacheView(image,exception);
3307 width=image->columns+kernel->width-1;
3308 for (y=0; y < (ssize_t) image->rows; y++)
3327 if (status == MagickFalse)
3329 p=GetCacheViewVirtualPixels(image_view,-offset.x,y-offset.y,width,(
size_t)
3330 offset.y+1,exception);
3331 q=GetCacheViewAuthenticPixels(morphology_view,0,y,image->columns,1,
3333 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3338 for (x=0; x < (ssize_t) image->columns; x++)
3343 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3354 const MagickRealType
3358 *magick_restrict pixels;
3366 channel=GetPixelChannelChannel(image,i);
3367 traits=GetPixelChannelTraits(image,channel);
3368 if (traits == UndefinedPixelTrait)
3370 if ((traits & CopyPixelTrait) != 0)
3373 pixel=(double) QuantumRange;
3376 case DistanceMorphology:
3378 k=(&kernel->values[kernel->width*kernel->height-1]);
3379 for (v=0; v <= offset.y; v++)
3381 for (u=0; u < (ssize_t) kernel->width; u++)
3385 if (((
double) pixels[i]+(*k)) < pixel)
3386 pixel=(double) pixels[i]+(*k);
3389 pixels+=(ptrdiff_t) GetPixelChannels(image);
3391 pixels+=(image->columns-1)*GetPixelChannels(image);
3393 k=(&kernel->values[(ssize_t) kernel->width*(kernel->y+1)-1]);
3394 pixels=q-offset.x*(ssize_t) GetPixelChannels(image);
3395 for (u=0; u < offset.x; u++)
3397 if (!IsNaN(*k) && ((x+u-offset.x) >= 0))
3399 if (((
double) pixels[i]+(*k)) < pixel)
3400 pixel=(double) pixels[i]+(*k);
3403 pixels+=(ptrdiff_t) GetPixelChannels(image);
3407 case VoronoiMorphology:
3409 k=(&kernel->values[kernel->width*kernel->height-1]);
3410 for (v=0; v < offset.y; v++)
3412 for (u=0; u < (ssize_t) kernel->width; u++)
3416 if (((
double) pixels[i]+(*k)) < pixel)
3417 pixel=(double) pixels[i]+(*k);
3420 pixels+=(ptrdiff_t) GetPixelChannels(image);
3422 pixels+=(image->columns-1)*GetPixelChannels(image);
3424 k=(&kernel->values[(ssize_t) kernel->width*(kernel->y+1)-1]);
3425 pixels=q-offset.x*(ssize_t) GetPixelChannels(image);
3426 for (u=0; u < offset.x; u++)
3428 if (!IsNaN(*k) && ((x+u-offset.x) >= 0))
3430 if (((
double) pixels[i]+(*k)) < pixel)
3431 pixel=(double) pixels[i]+(*k);
3434 pixels+=(ptrdiff_t) GetPixelChannels(image);
3441 if (fabs(pixel-(
double) q[i]) > MagickEpsilon)
3443 q[i]=ClampToQuantum(pixel);
3445 p+=(ptrdiff_t) GetPixelChannels(image);
3446 q+=(ptrdiff_t) GetPixelChannels(image);
3448 if (SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse)
3450 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3455#if defined(MAGICKCORE_OPENMP_SUPPORT)
3459 proceed=SetImageProgress(image,MorphologyTag,progress,2*image->rows);
3460 if (proceed == MagickFalse)
3464 morphology_view=DestroyCacheView(morphology_view);
3465 image_view=DestroyCacheView(image_view);
3469 image_view=AcquireVirtualCacheView(image,exception);
3470 morphology_view=AcquireAuthenticCacheView(image,exception);
3471 for (y=(ssize_t) image->rows-1; y >= 0; y--)
3489 if (status == MagickFalse)
3491 p=GetCacheViewVirtualPixels(image_view,-offset.x,y,width,(
size_t)
3492 kernel->y+1,exception);
3493 q=GetCacheViewAuthenticPixels(morphology_view,0,y,image->columns,1,
3495 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3500 p+=(ptrdiff_t) (image->columns-1)*GetPixelChannels(image);
3501 q+=(ptrdiff_t) (image->columns-1)*GetPixelChannels(image);
3502 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3507 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3518 const MagickRealType
3522 *magick_restrict pixels;
3530 channel=GetPixelChannelChannel(image,i);
3531 traits=GetPixelChannelTraits(image,channel);
3532 if (traits == UndefinedPixelTrait)
3534 if ((traits & CopyPixelTrait) != 0)
3537 pixel=(double) QuantumRange;
3540 case DistanceMorphology:
3542 k=(&kernel->values[(ssize_t) kernel->width*(kernel->y+1)-1]);
3543 for (v=offset.y; v < (ssize_t) kernel->height; v++)
3545 for (u=0; u < (ssize_t) kernel->width; u++)
3549 if (((
double) pixels[i]+(*k)) < pixel)
3550 pixel=(double) pixels[i]+(*k);
3553 pixels+=(ptrdiff_t) GetPixelChannels(image);
3555 pixels+=(image->columns-1)*GetPixelChannels(image);
3557 k=(&kernel->values[(ssize_t) kernel->width*kernel->y+kernel->x-1]);
3559 for (u=offset.x+1; u < (ssize_t) kernel->width; u++)
3561 pixels+=(ptrdiff_t) GetPixelChannels(image);
3562 if (!IsNaN(*k) && ((x+u-offset.x) < (ssize_t) image->columns))
3564 if (((
double) pixels[i]+(*k)) < pixel)
3565 pixel=(double) pixels[i]+(*k);
3571 case VoronoiMorphology:
3573 k=(&kernel->values[(ssize_t) kernel->width*(kernel->y+1)-1]);
3574 for (v=offset.y; v < (ssize_t) kernel->height; v++)
3576 for (u=0; u < (ssize_t) kernel->width; u++)
3580 if (((
double) pixels[i]+(*k)) < pixel)
3581 pixel=(double) pixels[i]+(*k);
3584 pixels+=(ptrdiff_t) GetPixelChannels(image);
3586 pixels+=(image->columns-1)*GetPixelChannels(image);
3588 k=(&kernel->values[(ssize_t) kernel->width*(kernel->y+1)-1]);
3590 for (u=offset.x+1; u < (ssize_t) kernel->width; u++)
3592 pixels+=(ptrdiff_t) GetPixelChannels(image);
3593 if (!IsNaN(*k) && ((x+u-offset.x) < (ssize_t) image->columns))
3595 if (((
double) pixels[i]+(*k)) < pixel)
3596 pixel=(double) pixels[i]+(*k);
3605 if (fabs(pixel-(
double) q[i]) > MagickEpsilon)
3607 q[i]=ClampToQuantum(pixel);
3609 p-=(ptrdiff_t)GetPixelChannels(image);
3610 q-=GetPixelChannels(image);
3612 if (SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse)
3614 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3619#if defined(MAGICKCORE_OPENMP_SUPPORT)
3623 proceed=SetImageProgress(image,MorphologyTag,progress,2*image->rows);
3624 if (proceed == MagickFalse)
3628 morphology_view=DestroyCacheView(morphology_view);
3629 image_view=DestroyCacheView(image_view);
3630 return(status ? (ssize_t) (changed/GetImageChannels(image)) : -1);
3642MagickPrivate Image *MorphologyApply(
const Image *image,
3643 const MorphologyMethod method,
const ssize_t iterations,
3644 const KernelInfo *kernel,
const CompositeOperator compose,
const double bias,
3645 ExceptionInfo *exception)
3688 v_info[MagickPathExtent];
3690 assert(image != (Image *) NULL);
3691 assert(image->signature == MagickCoreSignature);
3692 assert(kernel != (KernelInfo *) NULL);
3693 assert(kernel->signature == MagickCoreSignature);
3694 assert(exception != (ExceptionInfo *) NULL);
3695 assert(exception->signature == MagickCoreSignature);
3698 if ( iterations == 0 )
3699 return((Image *) NULL);
3701 kernel_limit = (size_t) iterations;
3702 if ( iterations < 0 )
3703 kernel_limit = image->columns>image->rows ? image->columns : image->rows;
3705 verbose = IsStringTrue(GetImageArtifact(image,
"debug"));
3708 curr_image = (Image *) image;
3709 curr_compose = image->compose;
3710 (void) curr_compose;
3711 work_image = save_image = rslt_image = (Image *) NULL;
3712 reflected_kernel = (KernelInfo *) NULL;
3721 special = MagickFalse;
3722 rslt_compose = compose;
3724 case SmoothMorphology:
3727 case OpenMorphology:
3728 case OpenIntensityMorphology:
3729 case TopHatMorphology:
3730 case CloseMorphology:
3731 case CloseIntensityMorphology:
3732 case BottomHatMorphology:
3733 case EdgeMorphology:
3736 case HitAndMissMorphology:
3737 rslt_compose = LightenCompositeOp;
3739 case ThinningMorphology:
3740 case ThickenMorphology:
3741 method_limit = kernel_limit;
3744 case DistanceMorphology:
3745 case VoronoiMorphology:
3746 special = MagickTrue;
3755 if ( special != MagickFalse )
3757 rslt_image=CloneImage(image,0,0,MagickTrue,exception);
3758 if (rslt_image == (Image *) NULL)
3760 if (SetImageStorageClass(rslt_image,DirectClass,exception) == MagickFalse)
3763 changed=MorphologyPrimitiveDirect(rslt_image,method,kernel,exception);
3765 if (verbose != MagickFalse)
3766 (void) (
void) FormatLocaleFile(stderr,
3767 "%s:%.20g.%.20g #%.20g => Changed %.20g\n",
3768 CommandOptionToMnemonic(MagickMorphologyOptions, method),
3769 1.0,0.0,1.0, (
double) changed);
3774 if ( method == VoronoiMorphology ) {
3776 (void) SetImageAlphaChannel(rslt_image, DeactivateAlphaChannel,
3778 (void) CompositeImage(rslt_image,image,CopyAlphaCompositeOp,
3779 MagickTrue,0,0,exception);
3780 (void) SetImageAlphaChannel(rslt_image, DeactivateAlphaChannel,
3787 if ( compose != UndefinedCompositeOp )
3788 rslt_compose = compose;
3789 if ( rslt_compose == UndefinedCompositeOp )
3790 rslt_compose = NoCompositeOp;
3795 case CorrelateMorphology:
3796 case CloseMorphology:
3797 case CloseIntensityMorphology:
3798 case BottomHatMorphology:
3799 case SmoothMorphology:
3800 reflected_kernel = CloneKernelInfo(kernel);
3801 if (reflected_kernel == (KernelInfo *) NULL)
3803 RotateKernelInfo(reflected_kernel,180);
3815 while ( method_loop < method_limit && method_changed > 0 ) {
3820 norm_kernel = (KernelInfo *) kernel;
3821 this_kernel = (KernelInfo *) kernel;
3822 rflt_kernel = reflected_kernel;
3825 while ( norm_kernel != NULL ) {
3829 while ( stage_loop < stage_limit ) {
3833 this_kernel = norm_kernel;
3836 case ErodeMorphology:
3837 case EdgeInMorphology:
3838 primitive = ErodeMorphology;
3840 case DilateMorphology:
3841 case EdgeOutMorphology:
3842 primitive = DilateMorphology;
3844 case OpenMorphology:
3845 case TopHatMorphology:
3846 primitive = ErodeMorphology;
3847 if ( stage_loop == 2 )
3848 primitive = DilateMorphology;
3850 case OpenIntensityMorphology:
3851 primitive = ErodeIntensityMorphology;
3852 if ( stage_loop == 2 )
3853 primitive = DilateIntensityMorphology;
3855 case CloseMorphology:
3856 case BottomHatMorphology:
3857 this_kernel = rflt_kernel;
3858 primitive = DilateMorphology;
3859 if ( stage_loop == 2 )
3860 primitive = ErodeMorphology;
3862 case CloseIntensityMorphology:
3863 this_kernel = rflt_kernel;
3864 primitive = DilateIntensityMorphology;
3865 if ( stage_loop == 2 )
3866 primitive = ErodeIntensityMorphology;
3868 case SmoothMorphology:
3869 switch ( stage_loop ) {
3871 primitive = ErodeMorphology;
3874 primitive = DilateMorphology;
3877 this_kernel = rflt_kernel;
3878 primitive = DilateMorphology;
3881 this_kernel = rflt_kernel;
3882 primitive = ErodeMorphology;
3886 case EdgeMorphology:
3887 primitive = DilateMorphology;
3888 if ( stage_loop == 2 ) {
3889 save_image = curr_image;
3890 curr_image = (Image *) image;
3891 primitive = ErodeMorphology;
3894 case CorrelateMorphology:
3904 this_kernel = rflt_kernel;
3905 primitive = ConvolveMorphology;
3910 assert( this_kernel != (KernelInfo *) NULL );
3913 if (verbose != MagickFalse) {
3914 if ( stage_limit > 1 )
3915 (void) FormatLocaleString(v_info,MagickPathExtent,
"%s:%.20g.%.20g -> ",
3916 CommandOptionToMnemonic(MagickMorphologyOptions,method),(
double)
3917 method_loop,(
double) stage_loop);
3918 else if ( primitive != method )
3919 (void) FormatLocaleString(v_info, MagickPathExtent,
"%s:%.20g -> ",
3920 CommandOptionToMnemonic(MagickMorphologyOptions, method),(
double)
3930 while ( kernel_loop < kernel_limit && changed > 0 ) {
3934 if ( work_image == (Image *) NULL )
3936 work_image=CloneImage(image,0,0,MagickTrue,exception);
3937 if (work_image == (Image *) NULL)
3939 if (SetImageStorageClass(work_image,DirectClass,exception) == MagickFalse)
3945 changed = MorphologyPrimitive(curr_image, work_image, primitive,
3946 this_kernel, bias, exception);
3947 if (verbose != MagickFalse) {
3948 if ( kernel_loop > 1 )
3949 (void) FormatLocaleFile(stderr,
"\n");
3950 (void) (
void) FormatLocaleFile(stderr,
3951 "%s%s%s:%.20g.%.20g #%.20g => Changed %.20g",
3952 v_info,CommandOptionToMnemonic(MagickMorphologyOptions,
3953 primitive),(this_kernel == rflt_kernel ) ?
"*" :
"",
3954 (
double) (method_loop+kernel_loop-1),(
double) kernel_number,
3955 (
double) count,(
double) changed);
3959 kernel_changed = (size_t) ((ssize_t) kernel_changed+changed);
3960 method_changed = (size_t) ((ssize_t) method_changed+changed);
3963 { Image *tmp = work_image;
3964 work_image = curr_image;
3967 if ( work_image == image )
3968 work_image = (Image *) NULL;
3972 if (verbose != MagickFalse && kernel_changed != (
size_t)changed)
3973 (void) FormatLocaleFile(stderr,
" Total %.20g",(
double) kernel_changed);
3974 if (verbose != MagickFalse && stage_loop < stage_limit)
3975 (void) FormatLocaleFile(stderr,
"\n");
3978 (void) FormatLocaleFile(stderr,
"--E-- image=0x%lx\n", (
unsigned long)image);
3979 (void) FormatLocaleFile(stderr,
" curr =0x%lx\n", (
unsigned long)curr_image);
3980 (void) FormatLocaleFile(stderr,
" work =0x%lx\n", (
unsigned long)work_image);
3981 (void) FormatLocaleFile(stderr,
" save =0x%lx\n", (
unsigned long)save_image);
3982 (void) FormatLocaleFile(stderr,
" union=0x%lx\n", (
unsigned long)rslt_image);
3995 case EdgeOutMorphology:
3996 case EdgeInMorphology:
3997 case TopHatMorphology:
3998 case BottomHatMorphology:
3999 if (verbose != MagickFalse)
4000 (void) FormatLocaleFile(stderr,
4001 "\n%s: Difference with original image",CommandOptionToMnemonic(
4002 MagickMorphologyOptions, method) );
4003 (void) CompositeImage(curr_image,image,DifferenceCompositeOp,
4004 MagickTrue,0,0,exception);
4006 case EdgeMorphology:
4007 if (verbose != MagickFalse)
4008 (void) FormatLocaleFile(stderr,
4009 "\n%s: Difference of Dilate and Erode",CommandOptionToMnemonic(
4010 MagickMorphologyOptions, method) );
4011 (void) CompositeImage(curr_image,save_image,DifferenceCompositeOp,
4012 MagickTrue,0,0,exception);
4013 save_image = DestroyImage(save_image);
4020 if ( kernel->next == (KernelInfo *) NULL )
4021 rslt_image = curr_image;
4022 else if ( rslt_compose == NoCompositeOp )
4023 {
if (verbose != MagickFalse) {
4024 if ( this_kernel->next != (KernelInfo *) NULL )
4025 (void) FormatLocaleFile(stderr,
" (re-iterate)");
4027 (
void) FormatLocaleFile(stderr,
" (done)");
4029 rslt_image = curr_image;
4031 else if ( rslt_image == (Image *) NULL)
4032 {
if (verbose != MagickFalse)
4033 (void) FormatLocaleFile(stderr,
" (save for compose)");
4034 rslt_image = curr_image;
4035 curr_image = (Image *) image;
4045 if (verbose != MagickFalse)
4046 (void) FormatLocaleFile(stderr,
" (compose \"%s\")",
4047 CommandOptionToMnemonic(MagickComposeOptions, rslt_compose) );
4048 (void) CompositeImage(rslt_image,curr_image,rslt_compose,MagickTrue,
4050 curr_image = DestroyImage(curr_image);
4051 curr_image = (Image *) image;
4053 if (verbose != MagickFalse)
4054 (void) FormatLocaleFile(stderr,
"\n");
4057 norm_kernel = norm_kernel->next;
4058 if ( rflt_kernel != (KernelInfo *) NULL )
4059 rflt_kernel = rflt_kernel->next;
4069 if ( curr_image == rslt_image )
4070 curr_image = (Image *) NULL;
4071 if ( rslt_image != (Image *) NULL )
4072 rslt_image = DestroyImage(rslt_image);
4074 if ( curr_image == rslt_image || curr_image == image )
4075 curr_image = (Image *) NULL;
4076 if ( curr_image != (Image *) NULL )
4077 curr_image = DestroyImage(curr_image);
4078 if ( work_image != (Image *) NULL )
4079 work_image = DestroyImage(work_image);
4080 if ( save_image != (Image *) NULL )
4081 save_image = DestroyImage(save_image);
4082 if ( reflected_kernel != (KernelInfo *) NULL )
4083 reflected_kernel = DestroyKernelInfo(reflected_kernel);
4137MagickExport Image *MorphologyImage(
const Image *image,
4138 const MorphologyMethod method,
const ssize_t iterations,
4139 const KernelInfo *kernel,ExceptionInfo *exception)
4156 assert(image != (
const Image *) NULL);
4157 assert(image->signature == MagickCoreSignature);
4158 assert(exception != (ExceptionInfo *) NULL);
4159 assert(exception->signature == MagickCoreSignature);
4160 if (IsEventLogging() != MagickFalse)
4161 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4162 curr_kernel = (KernelInfo *) kernel;
4164 compose = UndefinedCompositeOp;
4170 if ( method == ConvolveMorphology || method == CorrelateMorphology ) {
4172 artifact = GetImageArtifact(image,
"convolve:bias");
4173 if ( artifact != (
const char *) NULL) {
4174 if (IsGeometry(artifact) == MagickFalse)
4175 (void) ThrowMagickException(exception,GetMagickModule(),
4176 OptionWarning,
"InvalidSetting",
"'%s' '%s'",
4177 "convolve:bias",artifact);
4179 bias=StringToDoubleInterval(artifact,(
double) QuantumRange+1.0);
4183 artifact = GetImageArtifact(image,
"convolve:scale");
4184 if ( artifact != (
const char *) NULL ) {
4185 if (IsGeometry(artifact) == MagickFalse)
4186 (void) ThrowMagickException(exception,GetMagickModule(),
4187 OptionWarning,
"InvalidSetting",
"'%s' '%s'",
4188 "convolve:scale",artifact);
4190 if ( curr_kernel == kernel )
4191 curr_kernel = CloneKernelInfo(kernel);
4192 if (curr_kernel == (KernelInfo *) NULL)
4193 return((Image *) NULL);
4194 ScaleGeometryKernelInfo(curr_kernel, artifact);
4200 artifact=GetImageArtifact(image,
"morphology:showKernel");
4201 if (IsStringTrue(artifact) != MagickFalse)
4202 ShowKernelInfo(curr_kernel);
4214 artifact = GetImageArtifact(image,
"morphology:compose");
4215 if ( artifact != (
const char *) NULL) {
4216 parse=ParseCommandOption(MagickComposeOptions,
4217 MagickFalse,artifact);
4219 (void) ThrowMagickException(exception,GetMagickModule(),
4220 OptionWarning,
"UnrecognizedComposeOperator",
"'%s' '%s'",
4221 "morphology:compose",artifact);
4223 compose=(CompositeOperator)parse;
4227 morphology_image = MorphologyApply(image,method,iterations,
4228 curr_kernel,compose,bias,exception);
4231 if ( curr_kernel != kernel )
4232 curr_kernel=DestroyKernelInfo(curr_kernel);
4233 return(morphology_image);
4266static void RotateKernelInfo(KernelInfo *kernel,
double angle)
4269 if ( kernel->next != (KernelInfo *) NULL)
4270 RotateKernelInfo(kernel->next, angle);
4278 angle = fmod(angle, 360.0);
4282 if ( 337.5 < angle || angle <= 22.5 )
4286 switch (kernel->type) {
4288 case GaussianKernel:
4293 case LaplacianKernel:
4294 case ChebyshevKernel:
4295 case ManhattanKernel:
4296 case EuclideanKernel:
4310 if ( 135.0 < angle && angle <= 225.0 )
4312 if ( 225.0 < angle && angle <= 315.0 )
4320 if ( 22.5 < fmod(angle,90.0) && fmod(angle,90.0) <= 67.5 )
4322 if ( kernel->width == 3 && kernel->height == 3 )
4324 double t = kernel->values[0];
4325 kernel->values[0] = kernel->values[3];
4326 kernel->values[3] = kernel->values[6];
4327 kernel->values[6] = kernel->values[7];
4328 kernel->values[7] = kernel->values[8];
4329 kernel->values[8] = kernel->values[5];
4330 kernel->values[5] = kernel->values[2];
4331 kernel->values[2] = kernel->values[1];
4332 kernel->values[1] = t;
4334 if ( kernel->x != 1 || kernel->y != 1 ) {
4336 x = (ssize_t) kernel->x-1;
4337 y = (ssize_t) kernel->y-1;
4338 if ( x == y ) x = 0;
4339 else if ( x == 0 ) x = -y;
4340 else if ( x == -y ) y = 0;
4341 else if ( y == 0 ) y = x;
4342 kernel->x = (ssize_t) x+1;
4343 kernel->y = (ssize_t) y+1;
4345 angle = fmod(angle+315.0, 360.0);
4346 kernel->angle = fmod(kernel->angle+45.0, 360.0);
4349 perror(
"Unable to rotate non-3x3 kernel by 45 degrees");
4351 if ( 45.0 < fmod(angle, 180.0) && fmod(angle,180.0) <= 135.0 )
4353 if ( kernel->width == 1 || kernel->height == 1 )
4359 t = (ssize_t) kernel->width;
4360 kernel->width = kernel->height;
4361 kernel->height = (size_t) t;
4363 kernel->x = kernel->y;
4365 if ( kernel->width == 1 ) {
4366 angle = fmod(angle+270.0, 360.0);
4367 kernel->angle = fmod(kernel->angle+90.0, 360.0);
4369 angle = fmod(angle+90.0, 360.0);
4370 kernel->angle = fmod(kernel->angle+270.0, 360.0);
4373 else if ( kernel->width == kernel->height )
4382 for( i=0, x=(ssize_t) kernel->width-1; i<=x; i++, x--)
4383 for( j=0, y=(ssize_t) kernel->height-1; j<y; j++, y--)
4384 { t = k[i+j*(ssize_t) kernel->width];
4385 k[i+j*(ssize_t) kernel->width] = k[j+x*(ssize_t) kernel->width];
4386 k[j+x*(ssize_t) kernel->width] = k[x+y*(ssize_t) kernel->width];
4387 k[x+y*(ssize_t) kernel->width] = k[y+i*(ssize_t) kernel->width];
4388 k[y+i*(ssize_t) kernel->width] = t;
4393 x = (ssize_t) (kernel->x*2-(ssize_t) kernel->width+1);
4394 y = (ssize_t) (kernel->y*2-(ssize_t) kernel->height+1);
4395 kernel->x = (ssize_t) ( -y +(ssize_t) kernel->width-1)/2;
4396 kernel->y = (ssize_t) ( +x +(ssize_t) kernel->height-1)/2;
4398 angle = fmod(angle+270.0, 360.0);
4399 kernel->angle = fmod(kernel->angle+90.0, 360.0);
4402 perror(
"Unable to rotate a non-square, non-linear kernel 90 degrees");
4404 if ( 135.0 < angle && angle <= 225.0 )
4422 j=(ssize_t) (kernel->width*kernel->height-1);
4423 for (i=0; i < j; i++, j--)
4424 t=k[i], k[i]=k[j], k[j]=t;
4426 kernel->x = (ssize_t) kernel->width - kernel->x - 1;
4427 kernel->y = (ssize_t) kernel->height - kernel->y - 1;
4428 angle = fmod(angle-180.0, 360.0);
4429 kernel->angle = fmod(kernel->angle+180.0, 360.0);
4473MagickExport
void ScaleGeometryKernelInfo (KernelInfo *kernel,
4474 const char *geometry)
4482 SetGeometryInfo(&args);
4483 flags = ParseGeometry(geometry, &args);
4487 (void) FormatLocaleFile(stderr,
"Geometry = 0x%04X : %lg x %lg %+lg %+lg\n",
4488 flags, args.rho, args.sigma, args.xi, args.psi );
4491 if ( (flags & PercentValue) != 0 )
4492 args.rho *= 0.01, args.sigma *= 0.01;
4494 if ( (flags & RhoValue) == 0 )
4496 if ( (flags & SigmaValue) == 0 )
4500 ScaleKernelInfo(kernel, args.rho, (GeometryFlags) flags);
4503 if ( (flags & SigmaValue) != 0 )
4504 UnityAddKernelInfo(kernel, args.sigma);
4579MagickExport
void ScaleKernelInfo(KernelInfo *kernel,
4580 const double scaling_factor,
const GeometryFlags normalize_flags)
4590 if ( kernel->next != (KernelInfo *) NULL)
4591 ScaleKernelInfo(kernel->next, scaling_factor, normalize_flags);
4595 if ( (normalize_flags&NormalizeValue) != 0 ) {
4596 if ( fabs(kernel->positive_range + kernel->negative_range) >= MagickEpsilon )
4598 pos_scale = fabs(kernel->positive_range + kernel->negative_range);
4601 pos_scale = kernel->positive_range;
4604 if ( (normalize_flags&CorrelateNormalizeValue) != 0 ) {
4605 pos_scale = ( fabs(kernel->positive_range) >= MagickEpsilon )
4606 ? kernel->positive_range : 1.0;
4607 neg_scale = ( fabs(kernel->negative_range) >= MagickEpsilon )
4608 ? -kernel->negative_range : 1.0;
4611 neg_scale = pos_scale;
4614 pos_scale = scaling_factor/pos_scale;
4615 neg_scale = scaling_factor/neg_scale;
4617 for (i=0; i < (ssize_t) (kernel->width*kernel->height); i++)
4618 if (!IsNaN(kernel->values[i]))
4619 kernel->values[i] *= (kernel->values[i] >= 0) ? pos_scale : neg_scale;
4622 kernel->positive_range *= pos_scale;
4623 kernel->negative_range *= neg_scale;
4625 kernel->maximum *= (kernel->maximum >= 0.0) ? pos_scale : neg_scale;
4626 kernel->minimum *= (kernel->minimum >= 0.0) ? pos_scale : neg_scale;
4629 if ( scaling_factor < MagickEpsilon ) {
4631 t = kernel->positive_range;
4632 kernel->positive_range = kernel->negative_range;
4633 kernel->negative_range = t;
4634 t = kernel->maximum;
4635 kernel->maximum = kernel->minimum;
4636 kernel->minimum = 1;
4666MagickPrivate
void ShowKernelInfo(
const KernelInfo *kernel)
4674 for (c=0, k=kernel; k != (KernelInfo *) NULL; c++, k=k->next ) {
4676 (void) FormatLocaleFile(stderr,
"Kernel");
4677 if ( kernel->next != (KernelInfo *) NULL )
4678 (void) FormatLocaleFile(stderr,
" #%lu", (
unsigned long) c );
4679 (void) FormatLocaleFile(stderr,
" \"%s",
4680 CommandOptionToMnemonic(MagickKernelOptions, k->type) );
4681 if ( fabs(k->angle) >= MagickEpsilon )
4682 (void) FormatLocaleFile(stderr,
"@%lg", k->angle);
4683 (void) FormatLocaleFile(stderr,
"\" of size %lux%lu%+ld%+ld",(
unsigned long)
4684 k->width,(
unsigned long) k->height,(
long) k->x,(
long) k->y);
4685 (void) FormatLocaleFile(stderr,
4686 " with values from %.*lg to %.*lg\n",
4687 GetMagickPrecision(), k->minimum,
4688 GetMagickPrecision(), k->maximum);
4689 (void) FormatLocaleFile(stderr,
"Forming a output range from %.*lg to %.*lg",
4690 GetMagickPrecision(), k->negative_range,
4691 GetMagickPrecision(), k->positive_range);
4692 if ( fabs(k->positive_range+k->negative_range) < MagickEpsilon )
4693 (void) FormatLocaleFile(stderr,
" (Zero-Summing)\n");
4694 else if ( fabs(k->positive_range+k->negative_range-1.0) < MagickEpsilon )
4695 (void) FormatLocaleFile(stderr,
" (Normalized)\n");
4697 (
void) FormatLocaleFile(stderr,
" (Sum %.*lg)\n",
4698 GetMagickPrecision(), k->positive_range+k->negative_range);
4699 for (i=v=0; v < k->height; v++) {
4700 (void) FormatLocaleFile(stderr,
"%2lu:", (
unsigned long) v );
4701 for (u=0; u < k->width; u++, i++)
4702 if (IsNaN(k->values[i]))
4703 (void) FormatLocaleFile(stderr,
" %*s", GetMagickPrecision()+3,
"nan");
4705 (
void) FormatLocaleFile(stderr,
" %*.*lg", GetMagickPrecision()+3,
4706 GetMagickPrecision(), (
double) k->values[i]);
4707 (void) FormatLocaleFile(stderr,
"\n");
4745MagickExport
void UnityAddKernelInfo(KernelInfo *kernel,
4749 if ( kernel->next != (KernelInfo *) NULL)
4750 UnityAddKernelInfo(kernel->next, scale);
4753 kernel->values[kernel->x+kernel->y*(ssize_t) kernel->width] += scale;
4754 CalcKernelMetaData(kernel);
4784MagickPrivate
void ZeroKernelNans(KernelInfo *kernel)
4790 if (kernel->next != (KernelInfo *) NULL)
4791 ZeroKernelNans(kernel->next);
4793 for (i=0; i < (kernel->width*kernel->height); i++)
4794 if (IsNaN(kernel->values[i]))
4795 kernel->values[i]=0.0;