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)
206static KernelInfo *ParseKernelArray(
const char *kernel_string)
212 token[MagickPathExtent];
233 kernel=(KernelInfo *) AcquireMagickMemory(
sizeof(*kernel));
234 if (kernel == (KernelInfo *) NULL)
236 (void) memset(kernel,0,
sizeof(*kernel));
237 kernel->minimum = kernel->maximum = kernel->angle = 0.0;
238 kernel->negative_range = kernel->positive_range = 0.0;
239 kernel->type = UserDefinedKernel;
240 kernel->next = (KernelInfo *) NULL;
241 kernel->signature=MagickCoreSignature;
242 if (kernel_string == (
const char *) NULL)
246 end = strchr(kernel_string,
';');
247 if ( end == (
char *) NULL )
248 end = strchr(kernel_string,
'\0');
256 p = strchr(kernel_string,
':');
257 if ( p != (
char *) NULL && p < end)
260 length=MagickMin((
size_t) (p-kernel_string),
sizeof(token)-1);
261 (void) memcpy(token, kernel_string, length);
262 token[length] =
'\0';
263 SetGeometryInfo(&args);
264 flags = ParseGeometry(token, &args);
267 if ( (flags & WidthValue) == 0 )
268 args.rho = args.sigma;
269 if ( args.rho < 1.0 )
271 if ( args.sigma < 1.0 )
272 args.sigma = args.rho;
273 kernel->width = CastDoubleToSizeT(args.rho);
274 kernel->height = CastDoubleToSizeT(args.sigma);
277 if ( args.xi < 0.0 || args.psi < 0.0 )
278 return(DestroyKernelInfo(kernel));
279 kernel->x = ((flags & XValue)!=0) ? (ssize_t)args.xi
280 : (ssize_t) (kernel->width-1)/2;
281 kernel->y = ((flags & YValue)!=0) ? (ssize_t)args.psi
282 : (ssize_t) (kernel->height-1)/2;
283 if ( kernel->x >= (ssize_t) kernel->width ||
284 kernel->y >= (ssize_t) kernel->height )
285 return(DestroyKernelInfo(kernel));
292 p=(
const char *) kernel_string;
293 while ((isspace((
int) ((
unsigned char) *p)) != 0) || (*p ==
'\''))
295 for (i=0; p < end; i++)
297 (void) GetNextToken(p,&p,MagickPathExtent,token);
299 (void) GetNextToken(p,&p,MagickPathExtent,token);
302 kernel->width = kernel->height=CastDoubleToSizeT(sqrt((
double) i+1.0));
303 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
304 p=(
const char *) kernel_string;
305 while ((isspace((
int) ((
unsigned char) *p)) != 0) || (*p ==
'\''))
310 kernel->values=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory(
311 kernel->width,kernel->height*
sizeof(*kernel->values)));
312 if (kernel->values == (MagickRealType *) NULL)
313 return(DestroyKernelInfo(kernel));
314 kernel->minimum=MagickMaximumValue;
315 kernel->maximum=(-MagickMaximumValue);
316 kernel->negative_range = kernel->positive_range = 0.0;
317 for (i=0; (i < (ssize_t) (kernel->width*kernel->height)) && (p < end); i++)
319 (void) GetNextToken(p,&p,MagickPathExtent,token);
321 (void) GetNextToken(p,&p,MagickPathExtent,token);
322 if ( LocaleCompare(
"nan",token) == 0
323 || LocaleCompare(
"-",token) == 0 ) {
324 kernel->values[i] = nan;
327 kernel->values[i] = StringToDouble(token,(
char **) NULL);
328 ( kernel->values[i] < 0)
329 ? ( kernel->negative_range += kernel->values[i] )
330 : ( kernel->positive_range += kernel->values[i] );
331 Minimize(kernel->minimum, kernel->values[i]);
332 Maximize(kernel->maximum, kernel->values[i]);
337 (void) GetNextToken(p,&p,MagickPathExtent,token);
338 if ( *token !=
'\0' && *token !=
';' && *token !=
'\'' )
339 return(DestroyKernelInfo(kernel));
343 if ( i < (ssize_t) (kernel->width*kernel->height) ) {
344 Minimize(kernel->minimum, kernel->values[i]);
345 Maximize(kernel->maximum, kernel->values[i]);
346 for ( ; i < (ssize_t) (kernel->width*kernel->height); i++)
347 kernel->values[i]=0.0;
351 if ( i < (ssize_t) (kernel->width*kernel->height) )
352 return(DestroyKernelInfo(kernel));
356 if (kernel->minimum == MagickMaximumValue)
357 return(DestroyKernelInfo(kernel));
359 if ( (flags & AreaValue) != 0 )
360 ExpandRotateKernelInfo(kernel, 45.0);
361 else if ( (flags & GreaterValue) != 0 )
362 ExpandRotateKernelInfo(kernel, 90.0);
363 else if ( (flags & LessValue) != 0 )
364 ExpandMirrorKernelInfo(kernel);
369static KernelInfo *ParseKernelName(
const char *kernel_string,
370 ExceptionInfo *exception)
373 token[MagickPathExtent] =
"";
395 (void) GetNextToken(kernel_string,&p,MagickPathExtent,token);
396 type=ParseCommandOption(MagickKernelOptions,MagickFalse,token);
397 if ( type < 0 || type == UserDefinedKernel )
398 return((KernelInfo *) NULL);
400 while (((isspace((
int) ((
unsigned char) *p)) != 0) ||
401 (*p ==
',') || (*p ==
':' )) && (*p !=
'\0') && (*p !=
';'))
404 end = strchr(p,
';');
405 if ( end == (
char *) NULL )
406 end = strchr(p,
'\0');
409 length=MagickMin((
size_t) (end-p),
sizeof(token)-1);
410 (void) memcpy(token, p, length);
411 token[length] =
'\0';
412 SetGeometryInfo(&args);
413 flags = ParseGeometry(token, &args);
417 (void) FormatLocaleFile(stderr,
"Geometry = 0x%04X : %lg x %lg %+lg %+lg\n",
418 flags, args.rho, args.sigma, args.xi, args.psi );
425 if ( (flags & WidthValue) == 0 )
434 if ( (flags & HeightValue) == 0 )
438 if ( (flags & XValue) == 0 )
441 case RectangleKernel:
442 if ( (flags & WidthValue) == 0 )
443 args.rho = args.sigma;
444 if ( args.rho < 1.0 )
446 if ( args.sigma < 1.0 )
447 args.sigma = args.rho;
448 if ( (flags & XValue) == 0 )
449 args.xi = (double)(((ssize_t)args.rho-1)/2);
450 if ( (flags & YValue) == 0 )
451 args.psi = (double)(((ssize_t)args.sigma-1)/2);
454 case ChebyshevKernel:
455 case ManhattanKernel:
456 case OctagonalKernel:
457 case EuclideanKernel:
458 if ( (flags & HeightValue) == 0 )
460 else if ( (flags & AspectValue ) != 0 )
461 args.sigma = (double) QuantumRange/(args.sigma+1);
462 else if ( (flags & PercentValue ) != 0 )
463 args.sigma *= (double) QuantumRange/100.0;
469 kernel = AcquireKernelBuiltIn((KernelInfoType)type, &args, exception);
470 if ( kernel == (KernelInfo *) NULL )
474 if ( kernel->next == (KernelInfo *) NULL ) {
475 if ( (flags & AreaValue) != 0 )
476 ExpandRotateKernelInfo(kernel, 45.0);
477 else if ( (flags & GreaterValue) != 0 )
478 ExpandRotateKernelInfo(kernel, 90.0);
479 else if ( (flags & LessValue) != 0 )
480 ExpandMirrorKernelInfo(kernel);
486MagickExport KernelInfo *AcquireKernelInfo(
const char *kernel_string,
487 ExceptionInfo *exception)
495 token[MagickPathExtent];
500 if (kernel_string == (
const char *) NULL)
501 return(ParseKernelArray(kernel_string));
503 kernel_cache=(
char *) NULL;
504 if (*kernel_string ==
'@')
506 kernel_cache=FileToString(kernel_string,~0UL,exception);
507 if (kernel_cache == (
char *) NULL)
508 return((KernelInfo *) NULL);
509 p=(
const char *) kernel_cache;
512 while (GetNextToken(p,(
const char **) NULL,MagickPathExtent,token), *token !=
'\0')
518 if (isalpha((
int) ((
unsigned char) *token)) != 0)
519 new_kernel=ParseKernelName(p,exception);
521 new_kernel=ParseKernelArray(p);
524 if (new_kernel == (KernelInfo *) NULL)
526 if (kernel != (KernelInfo *) NULL)
527 kernel=DestroyKernelInfo(kernel);
528 return((KernelInfo *) NULL);
532 if (kernel == (KernelInfo *) NULL)
535 LastKernelInfo(kernel)->next=new_kernel;
540 if (p == (
char *) NULL)
544 if (kernel_cache != (
char *) NULL)
545 kernel_cache=DestroyString(kernel_cache);
951MagickExport KernelInfo *AcquireKernelBuiltIn(
const KernelInfoType type,
952 const GeometryInfo *args,ExceptionInfo *exception)
968 kernel=(KernelInfo *) NULL;
970 case UndefinedKernel:
971 case UserDefinedKernel:
972 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
973 "InvalidOption",
"`%s'",
"Should not call this function");
974 return((KernelInfo *) NULL);
975 case LaplacianKernel:
984 case DiagonalsKernel:
986 case LineJunctionsKernel:
988 case ConvexHullKernel:
1000 case BinomialKernel:
1003 case RectangleKernel:
1010 case ChebyshevKernel:
1011 case ManhattanKernel:
1012 case OctagonalKernel:
1013 case EuclideanKernel:
1018 kernel=(KernelInfo *) AcquireMagickMemory(
sizeof(*kernel));
1019 if (kernel == (KernelInfo *) NULL)
1021 (void) memset(kernel,0,
sizeof(*kernel));
1022 kernel->minimum = kernel->maximum = kernel->angle = 0.0;
1023 kernel->negative_range = kernel->positive_range = 0.0;
1024 kernel->type = type;
1025 kernel->next = (KernelInfo *) NULL;
1026 kernel->signature=MagickCoreSignature;
1036 kernel->height = kernel->width = (size_t) 1;
1037 kernel->x = kernel->y = (ssize_t) 0;
1038 kernel->values=(MagickRealType *) MagickAssumeAligned(
1039 AcquireAlignedMemory(1,
sizeof(*kernel->values)));
1040 if (kernel->values == (MagickRealType *) NULL)
1041 return(DestroyKernelInfo(kernel));
1042 kernel->maximum = kernel->values[0] = args->rho;
1046 case GaussianKernel:
1050 sigma = fabs(args->sigma),
1051 sigma2 = fabs(args->xi),
1054 if ( args->rho >= 1.0 )
1055 kernel->width = CastDoubleToSizeT(args->rho)*2+1;
1056 else if ( (type != DoGKernel) || (sigma >= sigma2) )
1057 kernel->width = GetOptimalKernelWidth2D(args->rho,sigma);
1059 kernel->width = GetOptimalKernelWidth2D(args->rho,sigma2);
1060 kernel->height = kernel->width;
1061 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1062 kernel->values=(MagickRealType *) MagickAssumeAligned(
1063 AcquireAlignedMemory(kernel->width,kernel->height*
1064 sizeof(*kernel->values)));
1065 if (kernel->values == (MagickRealType *) NULL)
1066 return(DestroyKernelInfo(kernel));
1075 if ( type == GaussianKernel || type == DoGKernel )
1077 if ( sigma > MagickEpsilon )
1078 { A = 1.0/(2.0*sigma*sigma);
1079 B = (double) (1.0/(Magick2PI*sigma*sigma));
1080 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1081 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1082 kernel->values[i] = exp(-((
double)(u*u+v*v))*A)*B;
1085 { (void) memset(kernel->values,0, (
size_t)
1086 kernel->width*kernel->height*
sizeof(*kernel->values));
1087 kernel->values[kernel->x+kernel->y*(ssize_t) kernel->width] = 1.0;
1091 if ( type == DoGKernel )
1093 if ( sigma2 > MagickEpsilon )
1095 A = 1.0/(2.0*sigma*sigma);
1096 B = (double) (1.0/(Magick2PI*sigma*sigma));
1097 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1098 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1099 kernel->values[i] -= exp(-((
double)(u*u+v*v))*A)*B;
1102 kernel->values[kernel->x+kernel->y*(ssize_t) kernel->width] -= 1.0;
1105 if ( type == LoGKernel )
1107 if ( sigma > MagickEpsilon )
1108 { A = 1.0/(2.0*sigma*sigma);
1109 B = (double) (1.0/(MagickPI*sigma*sigma*sigma*sigma));
1110 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1111 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1112 { R = ((double)(u*u+v*v))*A;
1113 kernel->values[i] = (1-R)*exp(-R)*B;
1117 { (void) memset(kernel->values,0, (
size_t)
1118 kernel->width*kernel->height*
sizeof(*kernel->values));
1119 kernel->values[kernel->x+kernel->y*(ssize_t) kernel->width] = 1.0;
1136 CalcKernelMetaData(kernel);
1137 ScaleKernelInfo(kernel, 1.0, CorrelateNormalizeValue);
1143 sigma = fabs(args->sigma),
1146 if ( args->rho >= 1.0 )
1147 kernel->width = CastDoubleToSizeT(args->rho)*2+1;
1149 kernel->width = GetOptimalKernelWidth1D(args->rho,sigma);
1151 kernel->x = (ssize_t) (kernel->width-1)/2;
1153 kernel->negative_range = kernel->positive_range = 0.0;
1154 kernel->values=(MagickRealType *) MagickAssumeAligned(
1155 AcquireAlignedMemory(kernel->width,kernel->height*
1156 sizeof(*kernel->values)));
1157 if (kernel->values == (MagickRealType *) NULL)
1158 return(DestroyKernelInfo(kernel));
1176 v = (ssize_t) (kernel->width*KernelRank-1)/2;
1177 (void) memset(kernel->values,0, (
size_t)
1178 kernel->width*kernel->height*
sizeof(*kernel->values));
1180 if ( sigma > MagickEpsilon )
1181 { sigma *= KernelRank;
1182 alpha = 1.0/(2.0*sigma*sigma);
1183 beta= (double) (1.0/(MagickSQ2PI*sigma ));
1184 for ( u=-v; u <= v; u++) {
1185 kernel->values[(u+v)/KernelRank] +=
1186 exp(-((
double)(u*u))*alpha)*beta;
1190 kernel->values[kernel->x+kernel->y*(ssize_t) kernel->width] = 1.0;
1196 if ( sigma > MagickEpsilon )
1197 { alpha = 1.0/(2.0*sigma*sigma);
1198 beta = 1.0/(MagickSQ2PI*sigma);
1199 for ( i=0, u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1200 kernel->values[i] = exp(-((
double)(u*u))*alpha)*beta;
1203 { (void) memset(kernel->values,0, (
size_t)
1204 kernel->width*kernel->height*
sizeof(*kernel->values));
1205 kernel->values[kernel->x+kernel->y*kernel->width] = 1.0;
1222 CalcKernelMetaData(kernel);
1223 ScaleKernelInfo(kernel, 1.0, CorrelateNormalizeValue);
1226 RotateKernelInfo(kernel, args->xi );
1231 sigma = fabs(args->sigma),
1234 if ( args->rho < 1.0 )
1235 kernel->width = (GetOptimalKernelWidth1D(args->rho,sigma)-1)/2+1;
1237 kernel->width = CastDoubleToSizeT(args->rho);
1238 kernel->x = kernel->y = 0;
1240 kernel->negative_range = kernel->positive_range = 0.0;
1241 kernel->values=(MagickRealType *) MagickAssumeAligned(
1242 AcquireAlignedMemory(kernel->width,kernel->height*
1243 sizeof(*kernel->values)));
1244 if (kernel->values == (MagickRealType *) NULL)
1245 return(DestroyKernelInfo(kernel));
1257 if ( sigma > MagickEpsilon )
1261 v = (ssize_t) kernel->width*KernelRank;
1262 (void) memset(kernel->values,0, (
size_t)
1263 kernel->width*
sizeof(*kernel->values));
1264 sigma *= KernelRank;
1265 A = 1.0/(2.0*sigma*sigma);
1267 for ( u=0; u < v; u++) {
1268 kernel->values[u/KernelRank] +=
1269 exp(-((
double)(u*u))*A);
1272 for (i=0; i < (ssize_t) kernel->width; i++)
1273 kernel->positive_range += kernel->values[i];
1275 A = 1.0/(2.0*sigma*sigma);
1277 for ( i=0; i < (ssize_t) kernel->width; i++)
1278 kernel->positive_range +=
1279 kernel->values[i] = exp(-((
double)(i*i))*A);
1284 { (void) memset(kernel->values,0, (
size_t)
1285 kernel->width*kernel->height*
sizeof(*kernel->values));
1286 kernel->values[kernel->x+kernel->y*(ssize_t) kernel->width] = 1.0;
1287 kernel->positive_range = 1.0;
1290 kernel->minimum = 0.0;
1291 kernel->maximum = kernel->values[0];
1292 kernel->negative_range = 0.0;
1294 ScaleKernelInfo(kernel, 1.0, NormalizeValue);
1295 RotateKernelInfo(kernel, args->xi);
1298 case BinomialKernel:
1301 max_order = (
sizeof(size_t) > 4) ? 20 : 12;
1306 if (args->rho < 1.0)
1307 kernel->width = kernel->height = 3;
1309 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
1310 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1313 if ((kernel->width-1) > max_order)
1314 return(DestroyKernelInfo(kernel));
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++)
1328 alpha = order_f / ( fact((
size_t) v) * fact(kernel->height-(
size_t) v-1) );
1330 for ( u=0; u < (ssize_t)kernel->width; u++, i++)
1331 kernel->positive_range += kernel->values[i] = (
double)
1332 (alpha * order_f / ( fact((
size_t) u) * fact(kernel->height-(
size_t) u-1) ));
1334 kernel->minimum = 1.0;
1335 kernel->maximum = kernel->values[kernel->x+kernel->y*(ssize_t) kernel->width];
1336 kernel->negative_range = 0.0;
1343 case LaplacianKernel:
1344 {
switch ( (
int) args->rho ) {
1347 kernel=ParseKernelArray(
"3: -1,-1,-1 -1,8,-1 -1,-1,-1");
1350 kernel=ParseKernelArray(
"3: 0,-1,0 -1,4,-1 0,-1,0");
1353 kernel=ParseKernelArray(
"3: -2,1,-2 1,4,1 -2,1,-2");
1356 kernel=ParseKernelArray(
"3: 1,-2,1 -2,4,-2 1,-2,1");
1359 kernel=ParseKernelArray(
1360 "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");
1363 kernel=ParseKernelArray(
1364 "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" );
1367 kernel=ParseKernelArray(
1368 "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");
1372 kernel=ParseKernelArray(
1373 "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");
1376 if (kernel == (KernelInfo *) NULL)
1378 kernel->type = type;
1383 kernel=ParseKernelArray(
"3: 1,0,-1 2,0,-2 1,0,-1");
1384 if (kernel == (KernelInfo *) NULL)
1386 kernel->type = type;
1387 RotateKernelInfo(kernel, args->rho);
1392 kernel=ParseKernelArray(
"3: 0,0,0 1,-1,0 0,0,0");
1393 if (kernel == (KernelInfo *) NULL)
1395 kernel->type = type;
1396 RotateKernelInfo(kernel, args->rho);
1401 kernel=ParseKernelArray(
"3: 1,0,-1 1,0,-1 1,0,-1");
1402 if (kernel == (KernelInfo *) NULL)
1404 kernel->type = type;
1405 RotateKernelInfo(kernel, args->rho);
1410 kernel=ParseKernelArray(
"3: 1,1,-1 1,-2,-1 1,1,-1");
1411 if (kernel == (KernelInfo *) NULL)
1413 kernel->type = type;
1414 RotateKernelInfo(kernel, args->rho);
1419 kernel=ParseKernelArray(
"3: 5,-3,-3 5,0,-3 5,-3,-3");
1420 if (kernel == (KernelInfo *) NULL)
1422 kernel->type = type;
1423 RotateKernelInfo(kernel, args->rho);
1426 case FreiChenKernel:
1430 {
switch ( (
int) args->rho ) {
1433 kernel=ParseKernelArray(
"3: 1,0,-1 2,0,-2 1,0,-1");
1434 if (kernel == (KernelInfo *) NULL)
1436 kernel->type = type;
1437 kernel->values[3] = +(MagickRealType) MagickSQ2;
1438 kernel->values[5] = -(MagickRealType) MagickSQ2;
1439 CalcKernelMetaData(kernel);
1442 kernel=ParseKernelArray(
"3: 1,2,0 2,0,-2 0,-2,-1");
1443 if (kernel == (KernelInfo *) NULL)
1445 kernel->type = type;
1446 kernel->values[1] = kernel->values[3]= +(MagickRealType) MagickSQ2;
1447 kernel->values[5] = kernel->values[7]= -(MagickRealType) MagickSQ2;
1448 CalcKernelMetaData(kernel);
1449 ScaleKernelInfo(kernel, (
double) (1.0/2.0*MagickSQ2), NoValue);
1453 kernel=AcquireKernelInfo(
"FreiChen:11;FreiChen:12;FreiChen:13;FreiChen:14;FreiChen:15;FreiChen:16;FreiChen:17;FreiChen:18;FreiChen:19",exception);
1454 if (kernel == (KernelInfo *) NULL)
1460 kernel=ParseKernelArray(
"3: 1,0,-1 2,0,-2 1,0,-1");
1461 if (kernel == (KernelInfo *) NULL)
1463 kernel->type = type;
1464 kernel->values[3] = +(MagickRealType) MagickSQ2;
1465 kernel->values[5] = -(MagickRealType) MagickSQ2;
1466 CalcKernelMetaData(kernel);
1467 ScaleKernelInfo(kernel, (
double) (1.0/2.0*MagickSQ2), NoValue);
1470 kernel=ParseKernelArray(
"3: 1,2,1 0,0,0 1,2,1");
1471 if (kernel == (KernelInfo *) NULL)
1473 kernel->type = type;
1474 kernel->values[1] = +(MagickRealType) MagickSQ2;
1475 kernel->values[7] = +(MagickRealType) MagickSQ2;
1476 CalcKernelMetaData(kernel);
1477 ScaleKernelInfo(kernel, (
double) (1.0/2.0*MagickSQ2), NoValue);
1480 kernel=ParseKernelArray(
"3: 2,-1,0 -1,0,1 0,1,-2");
1481 if (kernel == (KernelInfo *) NULL)
1483 kernel->type = type;
1484 kernel->values[0] = +(MagickRealType) MagickSQ2;
1485 kernel->values[8] = -(MagickRealType) MagickSQ2;
1486 CalcKernelMetaData(kernel);
1487 ScaleKernelInfo(kernel, (
double) (1.0/2.0*MagickSQ2), NoValue);
1490 kernel=ParseKernelArray(
"3: 0,1,-2 -1,0,1 2,-1,0");
1491 if (kernel == (KernelInfo *) NULL)
1493 kernel->type = type;
1494 kernel->values[2] = -(MagickRealType) MagickSQ2;
1495 kernel->values[6] = +(MagickRealType) MagickSQ2;
1496 CalcKernelMetaData(kernel);
1497 ScaleKernelInfo(kernel, (
double) (1.0/2.0*MagickSQ2), NoValue);
1500 kernel=ParseKernelArray(
"3: 0,-1,0 1,0,1 0,-1,0");
1501 if (kernel == (KernelInfo *) NULL)
1503 kernel->type = type;
1504 ScaleKernelInfo(kernel, 1.0/2.0, NoValue);
1507 kernel=ParseKernelArray(
"3: 1,0,-1 0,0,0 -1,0,1");
1508 if (kernel == (KernelInfo *) NULL)
1510 kernel->type = type;
1511 ScaleKernelInfo(kernel, 1.0/2.0, NoValue);
1514 kernel=ParseKernelArray(
"3: 1,-2,1 -2,4,-2 -1,-2,1");
1515 if (kernel == (KernelInfo *) NULL)
1517 kernel->type = type;
1518 ScaleKernelInfo(kernel, 1.0/6.0, NoValue);
1521 kernel=ParseKernelArray(
"3: -2,1,-2 1,4,1 -2,1,-2");
1522 if (kernel == (KernelInfo *) NULL)
1524 kernel->type = type;
1525 ScaleKernelInfo(kernel, 1.0/6.0, NoValue);
1528 kernel=ParseKernelArray(
"3: 1,1,1 1,1,1 1,1,1");
1529 if (kernel == (KernelInfo *) NULL)
1531 kernel->type = type;
1532 ScaleKernelInfo(kernel, 1.0/3.0, NoValue);
1535 if ( fabs(args->sigma) >= MagickEpsilon )
1537 RotateKernelInfo(kernel, args->sigma);
1538 else if ( args->rho > 30.0 || args->rho < -30.0 )
1540 RotateKernelInfo(kernel, args->rho);
1549 if (args->rho < 1.0)
1550 kernel->width = kernel->height = 3;
1552 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
1553 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1555 kernel->values=(MagickRealType *) MagickAssumeAligned(
1556 AcquireAlignedMemory(kernel->width,kernel->height*
1557 sizeof(*kernel->values)));
1558 if (kernel->values == (MagickRealType *) NULL)
1559 return(DestroyKernelInfo(kernel));
1562 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1563 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1564 if ( (labs((
long) u)+labs((
long) v)) <= (
long) kernel->x)
1565 kernel->positive_range += kernel->values[i] = args->sigma;
1567 kernel->values[i] = nan;
1568 kernel->minimum = kernel->maximum = args->sigma;
1572 case RectangleKernel:
1575 if ( type == SquareKernel )
1577 if (args->rho < 1.0)
1578 kernel->width = kernel->height = 3;
1580 kernel->width = kernel->height = CastDoubleToSizeT(args->rho*2+1);
1581 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1582 scale = args->sigma;
1586 if ( args->rho < 1.0 || args->sigma < 1.0 )
1587 return(DestroyKernelInfo(kernel));
1588 kernel->width = CastDoubleToSizeT(args->rho);
1589 kernel->height = CastDoubleToSizeT(args->sigma);
1590 if ((args->xi < 0.0) || (args->xi >= (
double) kernel->width) ||
1591 (args->psi < 0.0) || (args->psi >= (
double) kernel->height))
1592 return(DestroyKernelInfo(kernel));
1593 kernel->x = (ssize_t) args->xi;
1594 kernel->y = (ssize_t) args->psi;
1597 kernel->values=(MagickRealType *) MagickAssumeAligned(
1598 AcquireAlignedMemory(kernel->width,kernel->height*
1599 sizeof(*kernel->values)));
1600 if (kernel->values == (MagickRealType *) NULL)
1601 return(DestroyKernelInfo(kernel));
1604 u=(ssize_t) (kernel->width*kernel->height);
1605 for ( i=0; i < u; i++)
1606 kernel->values[i] = scale;
1607 kernel->minimum = kernel->maximum = scale;
1608 kernel->positive_range = scale*u;
1613 if (args->rho < 1.0)
1614 kernel->width = kernel->height = 5;
1616 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
1617 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1619 kernel->values=(MagickRealType *) MagickAssumeAligned(
1620 AcquireAlignedMemory(kernel->width,kernel->height*
1621 sizeof(*kernel->values)));
1622 if (kernel->values == (MagickRealType *) NULL)
1623 return(DestroyKernelInfo(kernel));
1625 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1626 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1627 if ( (labs((
long) u)+labs((
long) v)) <=
1628 ((
long)kernel->x + (
long)(kernel->x/2)) )
1629 kernel->positive_range += kernel->values[i] = args->sigma;
1631 kernel->values[i] = nan;
1632 kernel->minimum = kernel->maximum = args->sigma;
1638 limit = (ssize_t)(args->rho*args->rho);
1640 if (args->rho < 0.4)
1641 kernel->width = kernel->height = 9L, limit = 18L;
1643 kernel->width = kernel->height = CastDoubleToSizeT(fabs(args->rho))*2+1;
1644 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1646 kernel->values=(MagickRealType *) MagickAssumeAligned(
1647 AcquireAlignedMemory(kernel->width,kernel->height*
1648 sizeof(*kernel->values)));
1649 if (kernel->values == (MagickRealType *) NULL)
1650 return(DestroyKernelInfo(kernel));
1652 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1653 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1654 if ((u*u+v*v) <= limit)
1655 kernel->positive_range += kernel->values[i] = args->sigma;
1657 kernel->values[i] = nan;
1658 kernel->minimum = kernel->maximum = args->sigma;
1663 if (args->rho < 1.0)
1664 kernel->width = kernel->height = 5;
1666 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
1667 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1669 kernel->values=(MagickRealType *) MagickAssumeAligned(
1670 AcquireAlignedMemory(kernel->width,kernel->height*
1671 sizeof(*kernel->values)));
1672 if (kernel->values == (MagickRealType *) NULL)
1673 return(DestroyKernelInfo(kernel));
1676 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1677 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1678 kernel->values[i] = (u == 0 || v == 0) ? args->sigma : nan;
1679 kernel->minimum = kernel->maximum = args->sigma;
1680 kernel->positive_range = args->sigma*(kernel->width*2.0 - 1.0);
1685 if (args->rho < 1.0)
1686 kernel->width = kernel->height = 5;
1688 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
1689 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1691 kernel->values=(MagickRealType *) MagickAssumeAligned(
1692 AcquireAlignedMemory(kernel->width,kernel->height*
1693 sizeof(*kernel->values)));
1694 if (kernel->values == (MagickRealType *) NULL)
1695 return(DestroyKernelInfo(kernel));
1698 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1699 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1700 kernel->values[i] = (u == v || u == -v) ? args->sigma : nan;
1701 kernel->minimum = kernel->maximum = args->sigma;
1702 kernel->positive_range = args->sigma*(kernel->width*2.0 - 1.0);
1716 if (args->rho < args->sigma)
1718 kernel->width = CastDoubleToSizeT(args->sigma)*2+1;
1719 limit1 = (ssize_t)(args->rho*args->rho);
1720 limit2 = (ssize_t)(args->sigma*args->sigma);
1724 kernel->width = CastDoubleToSizeT(args->rho)*2+1;
1725 limit1 = (ssize_t)(args->sigma*args->sigma);
1726 limit2 = (ssize_t)(args->rho*args->rho);
1729 kernel->width = 7L, limit1 = 7L, limit2 = 11L;
1731 kernel->height = kernel->width;
1732 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1733 kernel->values=(MagickRealType *) MagickAssumeAligned(
1734 AcquireAlignedMemory(kernel->width,kernel->height*
1735 sizeof(*kernel->values)));
1736 if (kernel->values == (MagickRealType *) NULL)
1737 return(DestroyKernelInfo(kernel));
1740 scale = (ssize_t) (( type == PeaksKernel) ? 0.0 : args->xi);
1741 for ( i=0, v= -kernel->y; v <= (ssize_t)kernel->y; v++)
1742 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1743 { ssize_t radius=u*u+v*v;
1744 if (limit1 < radius && radius <= limit2)
1745 kernel->positive_range += kernel->values[i] = (double) scale;
1747 kernel->values[i] = nan;
1749 kernel->minimum = kernel->maximum = (double) scale;
1750 if ( type == PeaksKernel ) {
1752 kernel->values[kernel->x+kernel->y*(ssize_t) kernel->width] = 1.0;
1753 kernel->positive_range = 1.0;
1754 kernel->maximum = 1.0;
1760 kernel=AcquireKernelInfo(
"ThinSE:482",exception);
1761 if (kernel == (KernelInfo *) NULL)
1763 kernel->type = type;
1764 ExpandMirrorKernelInfo(kernel);
1769 kernel=AcquireKernelInfo(
"ThinSE:87",exception);
1770 if (kernel == (KernelInfo *) NULL)
1772 kernel->type = type;
1773 ExpandRotateKernelInfo(kernel, 90.0);
1776 case DiagonalsKernel:
1778 switch ( (
int) args->rho ) {
1783 kernel=ParseKernelArray(
"3: 0,0,0 0,-,1 1,1,-");
1784 if (kernel == (KernelInfo *) NULL)
1786 kernel->type = type;
1787 new_kernel=ParseKernelArray(
"3: 0,0,1 0,-,1 0,1,-");
1788 if (new_kernel == (KernelInfo *) NULL)
1789 return(DestroyKernelInfo(kernel));
1790 new_kernel->type = type;
1791 LastKernelInfo(kernel)->next = new_kernel;
1792 ExpandMirrorKernelInfo(kernel);
1796 kernel=ParseKernelArray(
"3: 0,0,0 0,-,1 1,1,-");
1799 kernel=ParseKernelArray(
"3: 0,0,1 0,-,1 0,1,-");
1802 if (kernel == (KernelInfo *) NULL)
1804 kernel->type = type;
1805 RotateKernelInfo(kernel, args->sigma);
1808 case LineEndsKernel:
1810 switch ( (
int) args->rho ) {
1814 return(AcquireKernelInfo(
"LineEnds:1>;LineEnds:2>",exception));
1817 kernel=ParseKernelArray(
"3: 0,0,- 0,1,1 0,0,-");
1821 kernel=ParseKernelArray(
"3: 0,0,0 0,1,0 0,0,1");
1825 kernel=ParseKernelArray(
"3: 0,0,0 0,1,1 0,0,0");
1829 kernel=ParseKernelArray(
"3: 0,0,0 0,1,- 0,0,-");
1832 if (kernel == (KernelInfo *) NULL)
1834 kernel->type = type;
1835 RotateKernelInfo(kernel, args->sigma);
1838 case LineJunctionsKernel:
1840 switch ( (
int) args->rho ) {
1844 return(AcquireKernelInfo(
"LineJunctions:1@;LineJunctions:2>",exception));
1847 kernel=ParseKernelArray(
"3: 1,-,1 -,1,- -,1,-");
1851 kernel=ParseKernelArray(
"3: 1,-,- -,1,- 1,-,1");
1855 kernel=ParseKernelArray(
"3: -,-,- 1,1,1 -,1,-");
1859 kernel=ParseKernelArray(
"3: 1,-,1 -,1,- 1,-,1");
1863 kernel=ParseKernelArray(
"3: -,1,- 1,1,1 -,1,-");
1866 if (kernel == (KernelInfo *) NULL)
1868 kernel->type = type;
1869 RotateKernelInfo(kernel, args->sigma);
1876 switch ( (
int) args->rho ) {
1879 kernel=ParseKernelArray(
"3x1:0,1,0");
1880 if (kernel == (KernelInfo *) NULL)
1882 kernel->type = type;
1883 ExpandRotateKernelInfo(kernel, 90.0);
1886 kernel=ParseKernelArray(
"4x1:0,1,1,0");
1887 if (kernel == (KernelInfo *) NULL)
1889 kernel->type = type;
1890 ExpandRotateKernelInfo(kernel, 90.0);
1895 new_kernel=ParseKernelArray(
"4x3+1+1:0,1,1,- -,1,1,- -,1,1,0");
1896 if (new_kernel == (KernelInfo *) NULL)
1897 return(DestroyKernelInfo(kernel));
1898 new_kernel->type = type;
1899 LastKernelInfo(kernel)->next = new_kernel;
1900 new_kernel=ParseKernelArray(
"4x3+2+1:0,1,1,- -,1,1,- -,1,1,0");
1901 if (new_kernel == (KernelInfo *) NULL)
1902 return(DestroyKernelInfo(kernel));
1903 new_kernel->type = type;
1904 LastKernelInfo(kernel)->next = new_kernel;
1905 new_kernel=ParseKernelArray(
"4x3+1+1:-,1,1,0 -,1,1,- 0,1,1,-");
1906 if (new_kernel == (KernelInfo *) NULL)
1907 return(DestroyKernelInfo(kernel));
1908 new_kernel->type = type;
1909 LastKernelInfo(kernel)->next = new_kernel;
1910 new_kernel=ParseKernelArray(
"4x3+2+1:-,1,1,0 -,1,1,- 0,1,1,-");
1911 if (new_kernel == (KernelInfo *) NULL)
1912 return(DestroyKernelInfo(kernel));
1913 new_kernel->type = type;
1914 LastKernelInfo(kernel)->next = new_kernel;
1915 new_kernel=ParseKernelArray(
"3x4+1+1:0,-,- 1,1,1 1,1,1 -,-,0");
1916 if (new_kernel == (KernelInfo *) NULL)
1917 return(DestroyKernelInfo(kernel));
1918 new_kernel->type = type;
1919 LastKernelInfo(kernel)->next = new_kernel;
1920 new_kernel=ParseKernelArray(
"3x4+1+2:0,-,- 1,1,1 1,1,1 -,-,0");
1921 if (new_kernel == (KernelInfo *) NULL)
1922 return(DestroyKernelInfo(kernel));
1923 new_kernel->type = type;
1924 LastKernelInfo(kernel)->next = new_kernel;
1925 new_kernel=ParseKernelArray(
"3x4+1+1:-,-,0 1,1,1 1,1,1 0,-,-");
1926 if (new_kernel == (KernelInfo *) NULL)
1927 return(DestroyKernelInfo(kernel));
1928 new_kernel->type = type;
1929 LastKernelInfo(kernel)->next = new_kernel;
1930 new_kernel=ParseKernelArray(
"3x4+1+2:-,-,0 1,1,1 1,1,1 0,-,-");
1931 if (new_kernel == (KernelInfo *) NULL)
1932 return(DestroyKernelInfo(kernel));
1933 new_kernel->type = type;
1934 LastKernelInfo(kernel)->next = new_kernel;
1939 case ConvexHullKernel:
1944 kernel=ParseKernelArray(
"3: 1,1,- 1,0,- 1,-,0");
1945 if (kernel == (KernelInfo *) NULL)
1947 kernel->type = type;
1948 ExpandRotateKernelInfo(kernel, 90.0);
1950 new_kernel=ParseKernelArray(
"3: 1,1,1 1,0,- -,-,0");
1951 if (new_kernel == (KernelInfo *) NULL)
1952 return(DestroyKernelInfo(kernel));
1953 new_kernel->type = type;
1954 ExpandRotateKernelInfo(new_kernel, 90.0);
1955 LastKernelInfo(kernel)->next = new_kernel;
1958 case SkeletonKernel:
1960 switch ( (
int) args->rho ) {
1966 kernel=AcquireKernelInfo(
"ThinSE:482",exception);
1967 if (kernel == (KernelInfo *) NULL)
1969 kernel->type = type;
1970 ExpandRotateKernelInfo(kernel, 45.0);
1977 kernel=AcquireKernelInfo(
"ThinSE:482; ThinSE:87x90;",exception);
1978 if (kernel == (KernelInfo *) NULL)
1980 if (kernel->next == (KernelInfo *) NULL)
1981 return(DestroyKernelInfo(kernel));
1982 kernel->type = type;
1983 kernel->next->type = type;
1984 ExpandRotateKernelInfo(kernel, 90.0);
1992 kernel=AcquireKernelInfo(
"ThinSE:41; ThinSE:42; ThinSE:43",
1994 if (kernel == (KernelInfo *) NULL)
1996 if (kernel->next == (KernelInfo *) NULL)
1997 return(DestroyKernelInfo(kernel));
1998 if (kernel->next->next == (KernelInfo *) NULL)
1999 return(DestroyKernelInfo(kernel));
2000 kernel->type = type;
2001 kernel->next->type = type;
2002 kernel->next->next->type = type;
2003 ExpandMirrorKernelInfo(kernel);
2019 switch ( (
int) args->rho ) {
2022 kernel=ParseKernelArray(
"3: -,-,1 0,-,1 -,-,1");
2025 kernel=ParseKernelArray(
"3: -,-,1 0,-,1 -,0,-");
2028 kernel=ParseKernelArray(
"3: -,0,- 0,-,1 -,-,1");
2031 kernel=ParseKernelArray(
"3: -,0,- 0,-,1 -,0,-");
2034 kernel=ParseKernelArray(
"3: -,0,1 0,-,1 -,0,-");
2037 kernel=ParseKernelArray(
"3: -,0,- 0,-,1 -,0,1");
2040 kernel=ParseKernelArray(
"3: -,1,1 0,-,1 -,0,-");
2043 kernel=ParseKernelArray(
"3: -,-,1 0,-,1 0,-,1");
2046 kernel=ParseKernelArray(
"3: 0,-,1 0,-,1 -,-,1");
2050 kernel=ParseKernelArray(
"3: -,1,- 0,-,1 -,1,-");
2053 kernel=ParseKernelArray(
"3: -,1,- 0,-,1 0,-,-");
2056 kernel=ParseKernelArray(
"3: 0,-,- 0,-,1 -,1,-");
2059 kernel=ParseKernelArray(
"3: 0,-,- 0,-,1 0,-,-");
2062 kernel=ParseKernelArray(
"3: 0,-,1 0,-,1 0,-,-");
2065 kernel=ParseKernelArray(
"3: 0,-,- 0,-,1 0,-,1");
2068 kernel=ParseKernelArray(
"3: -,1,- 0,-,1 0,0,-");
2071 kernel=ParseKernelArray(
"3: -,1,- 0,-,1 0,1,-");
2074 kernel=ParseKernelArray(
"3: 0,1,- 0,-,1 -,1,-");
2078 kernel=ParseKernelArray(
"3: -,-,1 0,-,- -,0,-");
2081 kernel=ParseKernelArray(
"3: -,1,- -,-,1 0,-,-");
2084 kernel=ParseKernelArray(
"3: -,1,1 0,-,1 0,0,-");
2088 kernel=ParseKernelArray(
"3: 0,-,1 0,-,1 0,-,1");
2091 if (kernel == (KernelInfo *) NULL)
2093 kernel->type = type;
2094 RotateKernelInfo(kernel, args->sigma);
2100 case ChebyshevKernel:
2102 if (args->rho < 1.0)
2103 kernel->width = kernel->height = 3;
2105 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
2106 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
2108 kernel->values=(MagickRealType *) MagickAssumeAligned(
2109 AcquireAlignedMemory(kernel->width,kernel->height*
2110 sizeof(*kernel->values)));
2111 if (kernel->values == (MagickRealType *) NULL)
2112 return(DestroyKernelInfo(kernel));
2114 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
2115 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
2116 kernel->positive_range += ( kernel->values[i] =
2117 args->sigma*MagickMax(fabs((
double)u),fabs((
double)v)) );
2118 kernel->maximum = kernel->values[0];
2121 case ManhattanKernel:
2123 if (args->rho < 1.0)
2124 kernel->width = kernel->height = 3;
2126 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
2127 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
2129 kernel->values=(MagickRealType *) MagickAssumeAligned(
2130 AcquireAlignedMemory(kernel->width,kernel->height*
2131 sizeof(*kernel->values)));
2132 if (kernel->values == (MagickRealType *) NULL)
2133 return(DestroyKernelInfo(kernel));
2135 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
2136 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
2137 kernel->positive_range += ( kernel->values[i] =
2138 args->sigma*(labs((
long) u)+labs((
long) v)) );
2139 kernel->maximum = kernel->values[0];
2142 case OctagonalKernel:
2144 if (args->rho < 2.0)
2145 kernel->width = kernel->height = 5;
2147 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
2148 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
2150 kernel->values=(MagickRealType *) MagickAssumeAligned(
2151 AcquireAlignedMemory(kernel->width,kernel->height*
2152 sizeof(*kernel->values)));
2153 if (kernel->values == (MagickRealType *) NULL)
2154 return(DestroyKernelInfo(kernel));
2156 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
2157 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
2160 r1 = MagickMax(fabs((
double)u),fabs((
double)v)),
2161 r2 = floor((
double)(labs((
long)u)+labs((
long)v)+1)/1.5);
2162 kernel->positive_range += kernel->values[i] =
2163 args->sigma*MagickMax(r1,r2);
2165 kernel->maximum = kernel->values[0];
2168 case EuclideanKernel:
2170 if (args->rho < 1.0)
2171 kernel->width = kernel->height = 3;
2173 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
2174 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
2176 kernel->values=(MagickRealType *) MagickAssumeAligned(
2177 AcquireAlignedMemory(kernel->width,kernel->height*
2178 sizeof(*kernel->values)));
2179 if (kernel->values == (MagickRealType *) NULL)
2180 return(DestroyKernelInfo(kernel));
2182 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
2183 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
2184 kernel->positive_range += ( kernel->values[i] =
2185 args->sigma*sqrt((
double) (u*u+v*v)) );
2186 kernel->maximum = kernel->values[0];
2192 kernel=ParseKernelArray(
"1:1");
2193 if (kernel == (KernelInfo *) NULL)
2195 kernel->type = UndefinedKernel;
2227MagickExport KernelInfo *CloneKernelInfo(
const KernelInfo *kernel)
2235 assert(kernel != (KernelInfo *) NULL);
2236 new_kernel=(KernelInfo *) AcquireMagickMemory(
sizeof(*kernel));
2237 if (new_kernel == (KernelInfo *) NULL)
2239 *new_kernel=(*kernel);
2242 new_kernel->values=(MagickRealType *) MagickAssumeAligned(
2243 AcquireAlignedMemory(kernel->width,kernel->height*
sizeof(*kernel->values)));
2244 if (new_kernel->values == (MagickRealType *) NULL)
2245 return(DestroyKernelInfo(new_kernel));
2246 for (i=0; i < (ssize_t) (kernel->width*kernel->height); i++)
2247 new_kernel->values[i]=kernel->values[i];
2250 if ( kernel->next != (KernelInfo *) NULL ) {
2251 new_kernel->next = CloneKernelInfo(kernel->next);
2252 if ( new_kernel->next == (KernelInfo *) NULL )
2253 return(DestroyKernelInfo(new_kernel));
2282MagickExport KernelInfo *DestroyKernelInfo(KernelInfo *kernel)
2284 assert(kernel != (KernelInfo *) NULL);
2285 if (kernel->next != (KernelInfo *) NULL)
2286 kernel->next=DestroyKernelInfo(kernel->next);
2287 kernel->values=(MagickRealType *) RelinquishAlignedMemory(kernel->values);
2288 kernel=(KernelInfo *) RelinquishMagickMemory(kernel);
2324static void FlopKernelInfo(KernelInfo *kernel)
2333 for ( y=0, k=kernel->values; y < kernel->height; y++, k+=kernel->width)
2334 for ( x=0, r=kernel->width-1; x<kernel->width/2; x++, r--)
2335 t=k[x], k[x]=k[r], k[r]=t;
2337 kernel->x = kernel->width - kernel->x - 1;
2338 angle = fmod(angle+180.0, 360.0);
2342static void ExpandMirrorKernelInfo(KernelInfo *kernel)
2350 clone = CloneKernelInfo(last);
2351 if (clone == (KernelInfo *) NULL)
2353 RotateKernelInfo(clone, 180);
2354 LastKernelInfo(last)->next = clone;
2357 clone = CloneKernelInfo(last);
2358 if (clone == (KernelInfo *) NULL)
2360 RotateKernelInfo(clone, 90);
2361 LastKernelInfo(last)->next = clone;
2364 clone = CloneKernelInfo(last);
2365 if (clone == (KernelInfo *) NULL)
2367 RotateKernelInfo(clone, 180);
2368 LastKernelInfo(last)->next = clone;
2406static MagickBooleanType SameKernelInfo(
const KernelInfo *kernel1,
2407 const KernelInfo *kernel2)
2413 if ( kernel1->width != kernel2->width
2414 || kernel1->height != kernel2->height
2415 || kernel1->x != kernel2->x
2416 || kernel1->y != kernel2->y )
2420 for (i=0; i < (kernel1->width*kernel1->height); i++) {
2422 if ( IsNaN(kernel1->values[i]) && !IsNaN(kernel2->values[i]) )
2424 if ( IsNaN(kernel2->values[i]) && !IsNaN(kernel1->values[i]) )
2427 if ( fabs(kernel1->values[i] - kernel2->values[i]) >= MagickEpsilon )
2434static void ExpandRotateKernelInfo(KernelInfo *kernel,
const double angle)
2440 clone_info=(KernelInfo *) NULL;
2442DisableMSCWarning(4127)
2445 clone_info=CloneKernelInfo(last);
2446 if (clone_info == (KernelInfo *) NULL)
2448 RotateKernelInfo(clone_info,angle);
2449 if (SameKernelInfo(kernel,clone_info) != MagickFalse)
2451 LastKernelInfo(last)->next=clone_info;
2454 if (clone_info != (KernelInfo *) NULL)
2455 clone_info=DestroyKernelInfo(clone_info);
2495static void CalcKernelMetaData(KernelInfo *kernel)
2500 kernel->minimum = kernel->maximum = 0.0;
2501 kernel->negative_range = kernel->positive_range = 0.0;
2502 for (i=0; i < (kernel->width*kernel->height); i++)
2504 if ( fabs(kernel->values[i]) < MagickEpsilon )
2505 kernel->values[i] = 0.0;
2506 ( kernel->values[i] < 0)
2507 ? ( kernel->negative_range += kernel->values[i] )
2508 : ( kernel->positive_range += kernel->values[i] );
2509 Minimize(kernel->minimum, kernel->values[i]);
2510 Maximize(kernel->maximum, kernel->values[i]);
2576static ssize_t MorphologyPrimitive(
const Image *image,Image *morphology_image,
2577 const MorphologyMethod method,
const KernelInfo *kernel,
const double bias,
2578 ExceptionInfo *exception)
2580#define MorphologyTag "Morphology/Image"
2608 assert(image != (Image *) NULL);
2609 assert(image->signature == MagickCoreSignature);
2610 assert(morphology_image != (Image *) NULL);
2611 assert(morphology_image->signature == MagickCoreSignature);
2612 assert(kernel != (KernelInfo *) NULL);
2613 assert(kernel->signature == MagickCoreSignature);
2614 assert(exception != (ExceptionInfo *) NULL);
2615 assert(exception->signature == MagickCoreSignature);
2618 image_view=AcquireVirtualCacheView(image,exception);
2619 morphology_view=AcquireAuthenticCacheView(morphology_image,exception);
2620 width=image->columns+kernel->width-1;
2625 case ConvolveMorphology:
2626 case DilateMorphology:
2627 case DilateIntensityMorphology:
2628 case IterativeDistanceMorphology:
2633 offset.x=(ssize_t) kernel->width-kernel->x-1;
2634 offset.y=(ssize_t) kernel->height-kernel->y-1;
2637 case ErodeMorphology:
2638 case ErodeIntensityMorphology:
2639 case HitAndMissMorphology:
2640 case ThinningMorphology:
2641 case ThickenMorphology:
2652 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
2653 "InvalidOption",
"`%s'",
"not a primitive morphology method");
2658 changes=(
size_t *) AcquireQuantumMemory(GetOpenMPMaximumThreads(),
2660 if (changes == (
size_t *) NULL)
2661 ThrowFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed");
2662 for (j=0; j < (ssize_t) GetOpenMPMaximumThreads(); j++)
2664 if ((method == ConvolveMorphology) && (kernel->width == 1))
2675#if defined(MAGICKCORE_OPENMP_SUPPORT)
2676 #pragma omp parallel for schedule(static) shared(progress,status) \
2677 magick_number_threads(image,morphology_image,image->columns,1)
2679 for (x=0; x < (ssize_t) image->columns; x++)
2682 id = GetOpenMPThreadId();
2694 if (status == MagickFalse)
2696 p=GetCacheViewVirtualPixels(image_view,x,-offset.y,1,image->rows+
2697 kernel->height-1,exception);
2698 q=GetCacheViewAuthenticPixels(morphology_view,x,0,1,
2699 morphology_image->rows,exception);
2700 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
2705 center=(ssize_t) GetPixelChannels(image)*offset.y;
2706 for (r=0; r < (ssize_t) image->rows; r++)
2711 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2725 const MagickRealType
2729 *magick_restrict pixels;
2737 channel=GetPixelChannelChannel(image,i);
2738 traits=GetPixelChannelTraits(image,channel);
2739 morphology_traits=GetPixelChannelTraits(morphology_image,channel);
2740 if ((traits == UndefinedPixelTrait) ||
2741 (morphology_traits == UndefinedPixelTrait))
2743 if ((traits & CopyPixelTrait) != 0)
2745 SetPixelChannel(morphology_image,channel,p[center+i],q);
2748 k=(&kernel->values[kernel->height-1]);
2753 if (((image->alpha_trait & BlendPixelTrait) == 0) ||
2754 ((morphology_traits & BlendPixelTrait) == 0))
2755 for (v=0; v < (ssize_t) kernel->height; v++)
2759 pixel+=(*k)*(double) pixels[i];
2763 pixels+=(ptrdiff_t) GetPixelChannels(image);
2768 for (v=0; v < (ssize_t) kernel->height; v++)
2772 alpha=(double) (QuantumScale*(
double)
2773 GetPixelAlpha(image,pixels));
2774 pixel+=alpha*(*k)*(double) pixels[i];
2779 pixels+=(ptrdiff_t) GetPixelChannels(image);
2782 if (fabs(pixel-(
double) p[center+i]) >= MagickEpsilon)
2784 gamma=MagickSafeReciprocal(gamma);
2786 gamma*=(double) kernel->height/count;
2787 SetPixelChannel(morphology_image,channel,ClampToQuantum(gamma*
2790 p+=(ptrdiff_t) GetPixelChannels(image);
2791 q+=(ptrdiff_t) GetPixelChannels(morphology_image);
2793 if (SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse)
2795 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2800#if defined(MAGICKCORE_OPENMP_SUPPORT)
2804 proceed=SetImageProgress(image,MorphologyTag,progress,
2806 if (proceed == MagickFalse)
2810 morphology_image->type=image->type;
2811 morphology_view=DestroyCacheView(morphology_view);
2812 image_view=DestroyCacheView(image_view);
2813 for (j=0; j < (ssize_t) GetOpenMPMaximumThreads(); j++)
2814 changed+=changes[j];
2815 changes=(
size_t *) RelinquishMagickMemory(changes);
2816 return(status ? (ssize_t) (changed/GetImageChannels(image)) : 0);
2821#if defined(MAGICKCORE_OPENMP_SUPPORT)
2822 #pragma omp parallel for schedule(static) shared(progress,status) \
2823 magick_number_threads(image,morphology_image,image->rows,1)
2825 for (y=0; y < (ssize_t) image->rows; y++)
2828 id = GetOpenMPThreadId();
2842 if (status == MagickFalse)
2844 p=GetCacheViewVirtualPixels(image_view,-offset.x,y-offset.y,width,
2845 kernel->height,exception);
2846 q=GetCacheViewAuthenticPixels(morphology_view,0,y,morphology_image->columns,
2848 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
2853 center=(ssize_t) ((ssize_t) GetPixelChannels(image)*(ssize_t) width*
2854 offset.y+(ssize_t) GetPixelChannels(image)*offset.x);
2855 for (x=0; x < (ssize_t) image->columns; x++)
2860 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2877 const MagickRealType
2881 *magick_restrict pixels,
2882 *magick_restrict quantum_pixels;
2890 channel=GetPixelChannelChannel(image,i);
2891 traits=GetPixelChannelTraits(image,channel);
2892 morphology_traits=GetPixelChannelTraits(morphology_image,channel);
2893 if ((traits == UndefinedPixelTrait) ||
2894 (morphology_traits == UndefinedPixelTrait))
2896 if ((traits & CopyPixelTrait) != 0)
2898 SetPixelChannel(morphology_image,channel,p[center+i],q);
2902 quantum_pixels=(
const Quantum *) NULL;
2904 minimum=(double) QuantumRange;
2907 case ConvolveMorphology:
2912 case DilateMorphology:
2913 case ErodeIntensityMorphology:
2920 pixel=(double) p[center+i];
2927 case ConvolveMorphology:
2948 k=(&kernel->values[kernel->width*kernel->height-1]);
2949 if (((image->alpha_trait & BlendPixelTrait) == 0) ||
2950 ((morphology_traits & BlendPixelTrait) == 0))
2955 for (v=0; v < (ssize_t) kernel->height; v++)
2957 for (u=0; u < (ssize_t) kernel->width; u++)
2960 pixel+=(*k)*(double) pixels[i];
2962 pixels+=(ptrdiff_t) GetPixelChannels(image);
2964 pixels+=(image->columns-1)*GetPixelChannels(image);
2972 for (v=0; v < (ssize_t) kernel->height; v++)
2974 for (u=0; u < (ssize_t) kernel->width; u++)
2978 alpha=(double) (QuantumScale*(
double)
2979 GetPixelAlpha(image,pixels));
2980 pixel+=alpha*(*k)*(double) pixels[i];
2984 pixels+=(ptrdiff_t) GetPixelChannels(image);
2986 pixels+=(image->columns-1)*GetPixelChannels(image);
2990 case ErodeMorphology:
3001 for (v=0; v < (ssize_t) kernel->height; v++)
3003 for (u=0; u < (ssize_t) kernel->width; u++)
3005 if (!IsNaN(*k) && (*k >= 0.5))
3007 if ((
double) pixels[i] < pixel)
3008 pixel=(double) pixels[i];
3011 pixels+=(ptrdiff_t) GetPixelChannels(image);
3013 pixels+=(image->columns-1)*GetPixelChannels(image);
3017 case DilateMorphology:
3030 k=(&kernel->values[kernel->width*kernel->height-1]);
3031 for (v=0; v < (ssize_t) kernel->height; v++)
3033 for (u=0; u < (ssize_t) kernel->width; u++)
3035 if (!IsNaN(*k) && (*k > 0.5))
3037 if ((
double) pixels[i] > pixel)
3038 pixel=(double) pixels[i];
3041 pixels+=(ptrdiff_t) GetPixelChannels(image);
3043 pixels+=(image->columns-1)*GetPixelChannels(image);
3047 case HitAndMissMorphology:
3048 case ThinningMorphology:
3049 case ThickenMorphology:
3064 for (v=0; v < (ssize_t) kernel->height; v++)
3066 for (u=0; u < (ssize_t) kernel->width; u++)
3072 if ((
double) pixels[i] < minimum)
3073 minimum=(double) pixels[i];
3078 if ((
double) pixels[i] > maximum)
3079 maximum=(double) pixels[i];
3083 pixels+=(ptrdiff_t) GetPixelChannels(image);
3085 pixels+=(image->columns-1)*GetPixelChannels(image);
3091 if (method == ThinningMorphology)
3092 pixel=(double) p[center+i]-minimum;
3094 if (method == ThickenMorphology)
3095 pixel=(double) p[center+i]+minimum;
3098 case ErodeIntensityMorphology:
3106 for (v=0; v < (ssize_t) kernel->height; v++)
3108 for (u=0; u < (ssize_t) kernel->width; u++)
3110 if (!IsNaN(*k) && (*k >= 0.5))
3112 intensity=(double) GetPixelIntensity(image,pixels);
3113 if (intensity < minimum)
3115 quantum_pixels=pixels;
3116 pixel=(double) pixels[i];
3121 pixels+=(ptrdiff_t) GetPixelChannels(image);
3123 pixels+=(image->columns-1)*GetPixelChannels(image);
3127 case DilateIntensityMorphology:
3134 k=(&kernel->values[kernel->width*kernel->height-1]);
3135 for (v=0; v < (ssize_t) kernel->height; v++)
3137 for (u=0; u < (ssize_t) kernel->width; u++)
3139 if (!IsNaN(*k) && (*k >= 0.5))
3141 intensity=(double) GetPixelIntensity(image,pixels);
3142 if (intensity > maximum)
3144 pixel=(double) pixels[i];
3145 quantum_pixels=pixels;
3150 pixels+=(ptrdiff_t) GetPixelChannels(image);
3152 pixels+=(image->columns-1)*GetPixelChannels(image);
3156 case IterativeDistanceMorphology:
3181 k=(&kernel->values[kernel->width*kernel->height-1]);
3182 for (v=0; v < (ssize_t) kernel->height; v++)
3184 for (u=0; u < (ssize_t) kernel->width; u++)
3188 if (((
double) pixels[i]+(*k)) < pixel)
3189 pixel=(double) pixels[i]+(*k);
3192 pixels+=(ptrdiff_t) GetPixelChannels(image);
3194 pixels+=(image->columns-1)*GetPixelChannels(image);
3198 case UndefinedMorphology:
3202 if (quantum_pixels != (
const Quantum *) NULL)
3204 SetPixelChannel(morphology_image,channel,quantum_pixels[i],q);
3207 gamma=MagickSafeReciprocal(gamma);
3208 SetPixelChannel(morphology_image,channel,ClampToQuantum(gamma*pixel),q);
3209 if (fabs(pixel-(
double) p[center+i]) >= MagickEpsilon)
3212 p+=(ptrdiff_t) GetPixelChannels(image);
3213 q+=(ptrdiff_t) GetPixelChannels(morphology_image);
3215 if (SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse)
3217 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3222#if defined(MAGICKCORE_OPENMP_SUPPORT)
3226 proceed=SetImageProgress(image,MorphologyTag,progress,image->rows);
3227 if (proceed == MagickFalse)
3231 morphology_view=DestroyCacheView(morphology_view);
3232 image_view=DestroyCacheView(image_view);
3233 for (j=0; j < (ssize_t) GetOpenMPMaximumThreads(); j++)
3234 changed+=changes[j];
3235 changes=(
size_t *) RelinquishMagickMemory(changes);
3236 return(status ? (ssize_t) (changed/GetImageChannels(image)) : -1);
3252static ssize_t MorphologyPrimitiveDirect(Image *image,
3253 const MorphologyMethod method,
const KernelInfo *kernel,
3254 ExceptionInfo *exception)
3276 assert(image != (Image *) NULL);
3277 assert(image->signature == MagickCoreSignature);
3278 assert(kernel != (KernelInfo *) NULL);
3279 assert(kernel->signature == MagickCoreSignature);
3280 assert(exception != (ExceptionInfo *) NULL);
3281 assert(exception->signature == MagickCoreSignature);
3287 case DistanceMorphology:
3288 case VoronoiMorphology:
3293 offset.x=(ssize_t) kernel->width-kernel->x-1;
3294 offset.y=(ssize_t) kernel->height-kernel->y-1;
3307 image_view=AcquireVirtualCacheView(image,exception);
3308 morphology_view=AcquireAuthenticCacheView(image,exception);
3309 width=image->columns+kernel->width-1;
3310 for (y=0; y < (ssize_t) image->rows; y++)
3329 if (status == MagickFalse)
3331 p=GetCacheViewVirtualPixels(image_view,-offset.x,y-offset.y,width,(
size_t)
3332 offset.y+1,exception);
3333 q=GetCacheViewAuthenticPixels(morphology_view,0,y,image->columns,1,
3335 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3340 for (x=0; x < (ssize_t) image->columns; x++)
3345 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3356 const MagickRealType
3360 *magick_restrict pixels;
3368 channel=GetPixelChannelChannel(image,i);
3369 traits=GetPixelChannelTraits(image,channel);
3370 if (traits == UndefinedPixelTrait)
3372 if ((traits & CopyPixelTrait) != 0)
3375 pixel=(double) QuantumRange;
3378 case DistanceMorphology:
3380 k=(&kernel->values[kernel->width*kernel->height-1]);
3381 for (v=0; v <= offset.y; v++)
3383 for (u=0; u < (ssize_t) kernel->width; u++)
3387 if (((
double) pixels[i]+(*k)) < pixel)
3388 pixel=(double) pixels[i]+(*k);
3391 pixels+=(ptrdiff_t) GetPixelChannels(image);
3393 pixels+=(image->columns-1)*GetPixelChannels(image);
3395 k=(&kernel->values[(ssize_t) kernel->width*(kernel->y+1)-1]);
3396 pixels=q-offset.x*(ssize_t) GetPixelChannels(image);
3397 for (u=0; u < offset.x; u++)
3399 if (!IsNaN(*k) && ((x+u-offset.x) >= 0))
3401 if (((
double) pixels[i]+(*k)) < pixel)
3402 pixel=(double) pixels[i]+(*k);
3405 pixels+=(ptrdiff_t) GetPixelChannels(image);
3409 case VoronoiMorphology:
3411 k=(&kernel->values[kernel->width*kernel->height-1]);
3412 for (v=0; v < offset.y; v++)
3414 for (u=0; u < (ssize_t) kernel->width; u++)
3418 if (((
double) pixels[i]+(*k)) < pixel)
3419 pixel=(double) pixels[i]+(*k);
3422 pixels+=(ptrdiff_t) GetPixelChannels(image);
3424 pixels+=(image->columns-1)*GetPixelChannels(image);
3426 k=(&kernel->values[(ssize_t) kernel->width*(kernel->y+1)-1]);
3427 pixels=q-offset.x*(ssize_t) GetPixelChannels(image);
3428 for (u=0; u < offset.x; u++)
3430 if (!IsNaN(*k) && ((x+u-offset.x) >= 0))
3432 if (((
double) pixels[i]+(*k)) < pixel)
3433 pixel=(double) pixels[i]+(*k);
3436 pixels+=(ptrdiff_t) GetPixelChannels(image);
3443 if (fabs(pixel-(
double) q[i]) > MagickEpsilon)
3445 q[i]=ClampToQuantum(pixel);
3447 p+=(ptrdiff_t) GetPixelChannels(image);
3448 q+=(ptrdiff_t) GetPixelChannels(image);
3450 if (SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse)
3452 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3457#if defined(MAGICKCORE_OPENMP_SUPPORT)
3461 proceed=SetImageProgress(image,MorphologyTag,progress,2*image->rows);
3462 if (proceed == MagickFalse)
3466 morphology_view=DestroyCacheView(morphology_view);
3467 image_view=DestroyCacheView(image_view);
3471 image_view=AcquireVirtualCacheView(image,exception);
3472 morphology_view=AcquireAuthenticCacheView(image,exception);
3473 for (y=(ssize_t) image->rows-1; y >= 0; y--)
3491 if (status == MagickFalse)
3493 p=GetCacheViewVirtualPixels(image_view,-offset.x,y,width,(
size_t)
3494 kernel->y+1,exception);
3495 q=GetCacheViewAuthenticPixels(morphology_view,0,y,image->columns,1,
3497 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3502 p+=(ptrdiff_t) (image->columns-1)*GetPixelChannels(image);
3503 q+=(ptrdiff_t) (image->columns-1)*GetPixelChannels(image);
3504 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3509 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3520 const MagickRealType
3524 *magick_restrict pixels;
3532 channel=GetPixelChannelChannel(image,i);
3533 traits=GetPixelChannelTraits(image,channel);
3534 if (traits == UndefinedPixelTrait)
3536 if ((traits & CopyPixelTrait) != 0)
3539 pixel=(double) QuantumRange;
3542 case DistanceMorphology:
3544 k=(&kernel->values[(ssize_t) kernel->width*(kernel->y+1)-1]);
3545 for (v=offset.y; v < (ssize_t) kernel->height; v++)
3547 for (u=0; u < (ssize_t) kernel->width; u++)
3551 if (((
double) pixels[i]+(*k)) < pixel)
3552 pixel=(double) pixels[i]+(*k);
3555 pixels+=(ptrdiff_t) GetPixelChannels(image);
3557 pixels+=(image->columns-1)*GetPixelChannels(image);
3559 k=(&kernel->values[(ssize_t) kernel->width*kernel->y+kernel->x-1]);
3561 for (u=offset.x+1; u < (ssize_t) kernel->width; u++)
3563 pixels+=(ptrdiff_t) GetPixelChannels(image);
3564 if (!IsNaN(*k) && ((x+u-offset.x) < (ssize_t) image->columns))
3566 if (((
double) pixels[i]+(*k)) < pixel)
3567 pixel=(double) pixels[i]+(*k);
3573 case VoronoiMorphology:
3575 k=(&kernel->values[(ssize_t) kernel->width*(kernel->y+1)-1]);
3576 for (v=offset.y; v < (ssize_t) kernel->height; v++)
3578 for (u=0; u < (ssize_t) kernel->width; u++)
3582 if (((
double) pixels[i]+(*k)) < pixel)
3583 pixel=(double) pixels[i]+(*k);
3586 pixels+=(ptrdiff_t) GetPixelChannels(image);
3588 pixels+=(image->columns-1)*GetPixelChannels(image);
3590 k=(&kernel->values[(ssize_t) kernel->width*(kernel->y+1)-1]);
3592 for (u=offset.x+1; u < (ssize_t) kernel->width; u++)
3594 pixels+=(ptrdiff_t) GetPixelChannels(image);
3595 if (!IsNaN(*k) && ((x+u-offset.x) < (ssize_t) image->columns))
3597 if (((
double) pixels[i]+(*k)) < pixel)
3598 pixel=(double) pixels[i]+(*k);
3607 if (fabs(pixel-(
double) q[i]) > MagickEpsilon)
3609 q[i]=ClampToQuantum(pixel);
3611 p-=(ptrdiff_t)GetPixelChannels(image);
3612 q-=GetPixelChannels(image);
3614 if (SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse)
3616 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3621#if defined(MAGICKCORE_OPENMP_SUPPORT)
3625 proceed=SetImageProgress(image,MorphologyTag,progress,2*image->rows);
3626 if (proceed == MagickFalse)
3630 morphology_view=DestroyCacheView(morphology_view);
3631 image_view=DestroyCacheView(image_view);
3632 return(status ? (ssize_t) (changed/GetImageChannels(image)) : -1);
3644MagickPrivate Image *MorphologyApply(
const Image *image,
3645 const MorphologyMethod method,
const ssize_t iterations,
3646 const KernelInfo *kernel,
const CompositeOperator compose,
const double bias,
3647 ExceptionInfo *exception)
3690 v_info[MagickPathExtent];
3692 assert(image != (Image *) NULL);
3693 assert(image->signature == MagickCoreSignature);
3694 assert(kernel != (KernelInfo *) NULL);
3695 assert(kernel->signature == MagickCoreSignature);
3696 assert(exception != (ExceptionInfo *) NULL);
3697 assert(exception->signature == MagickCoreSignature);
3700 if ( iterations == 0 )
3701 return((Image *) NULL);
3703 kernel_limit = (size_t) iterations;
3704 if ( iterations < 0 )
3705 kernel_limit = image->columns>image->rows ? image->columns : image->rows;
3707 verbose = IsStringTrue(GetImageArtifact(image,
"debug"));
3710 curr_image = (Image *) image;
3711 curr_compose = image->compose;
3712 (void) curr_compose;
3713 work_image = save_image = rslt_image = (Image *) NULL;
3714 reflected_kernel = (KernelInfo *) NULL;
3723 special = MagickFalse;
3724 rslt_compose = compose;
3726 case SmoothMorphology:
3729 case OpenMorphology:
3730 case OpenIntensityMorphology:
3731 case TopHatMorphology:
3732 case CloseMorphology:
3733 case CloseIntensityMorphology:
3734 case BottomHatMorphology:
3735 case EdgeMorphology:
3738 case HitAndMissMorphology:
3739 rslt_compose = LightenCompositeOp;
3741 case ThinningMorphology:
3742 case ThickenMorphology:
3743 method_limit = kernel_limit;
3746 case DistanceMorphology:
3747 case VoronoiMorphology:
3748 special = MagickTrue;
3757 if ( special != MagickFalse )
3759 rslt_image=CloneImage(image,0,0,MagickTrue,exception);
3760 if (rslt_image == (Image *) NULL)
3762 if (SetImageStorageClass(rslt_image,DirectClass,exception) == MagickFalse)
3765 changed=MorphologyPrimitiveDirect(rslt_image,method,kernel,exception);
3767 if (verbose != MagickFalse)
3768 (void) (
void) FormatLocaleFile(stderr,
3769 "%s:%.20g.%.20g #%.20g => Changed %.20g\n",
3770 CommandOptionToMnemonic(MagickMorphologyOptions, method),
3771 1.0,0.0,1.0, (
double) changed);
3776 if ( method == VoronoiMorphology ) {
3778 (void) SetImageAlphaChannel(rslt_image, DeactivateAlphaChannel,
3780 (void) CompositeImage(rslt_image,image,CopyAlphaCompositeOp,
3781 MagickTrue,0,0,exception);
3782 (void) SetImageAlphaChannel(rslt_image, DeactivateAlphaChannel,
3789 if ( compose != UndefinedCompositeOp )
3790 rslt_compose = compose;
3791 if ( rslt_compose == UndefinedCompositeOp )
3792 rslt_compose = NoCompositeOp;
3797 case CorrelateMorphology:
3798 case CloseMorphology:
3799 case CloseIntensityMorphology:
3800 case BottomHatMorphology:
3801 case SmoothMorphology:
3802 reflected_kernel = CloneKernelInfo(kernel);
3803 if (reflected_kernel == (KernelInfo *) NULL)
3805 RotateKernelInfo(reflected_kernel,180);
3817 while ( method_loop < method_limit && method_changed > 0 ) {
3822 norm_kernel = (KernelInfo *) kernel;
3823 this_kernel = (KernelInfo *) kernel;
3824 rflt_kernel = reflected_kernel;
3827 while ( norm_kernel != NULL ) {
3831 while ( stage_loop < stage_limit ) {
3835 this_kernel = norm_kernel;
3838 case ErodeMorphology:
3839 case EdgeInMorphology:
3840 primitive = ErodeMorphology;
3842 case DilateMorphology:
3843 case EdgeOutMorphology:
3844 primitive = DilateMorphology;
3846 case OpenMorphology:
3847 case TopHatMorphology:
3848 primitive = ErodeMorphology;
3849 if ( stage_loop == 2 )
3850 primitive = DilateMorphology;
3852 case OpenIntensityMorphology:
3853 primitive = ErodeIntensityMorphology;
3854 if ( stage_loop == 2 )
3855 primitive = DilateIntensityMorphology;
3857 case CloseMorphology:
3858 case BottomHatMorphology:
3859 this_kernel = rflt_kernel;
3860 primitive = DilateMorphology;
3861 if ( stage_loop == 2 )
3862 primitive = ErodeMorphology;
3864 case CloseIntensityMorphology:
3865 this_kernel = rflt_kernel;
3866 primitive = DilateIntensityMorphology;
3867 if ( stage_loop == 2 )
3868 primitive = ErodeIntensityMorphology;
3870 case SmoothMorphology:
3871 switch ( stage_loop ) {
3873 primitive = ErodeMorphology;
3876 primitive = DilateMorphology;
3879 this_kernel = rflt_kernel;
3880 primitive = DilateMorphology;
3883 this_kernel = rflt_kernel;
3884 primitive = ErodeMorphology;
3888 case EdgeMorphology:
3889 primitive = DilateMorphology;
3890 if ( stage_loop == 2 ) {
3891 save_image = curr_image;
3892 curr_image = (Image *) image;
3893 primitive = ErodeMorphology;
3896 case CorrelateMorphology:
3906 this_kernel = rflt_kernel;
3907 primitive = ConvolveMorphology;
3912 assert( this_kernel != (KernelInfo *) NULL );
3915 if (verbose != MagickFalse) {
3916 if ( stage_limit > 1 )
3917 (void) FormatLocaleString(v_info,MagickPathExtent,
"%s:%.20g.%.20g -> ",
3918 CommandOptionToMnemonic(MagickMorphologyOptions,method),(
double)
3919 method_loop,(
double) stage_loop);
3920 else if ( primitive != method )
3921 (void) FormatLocaleString(v_info, MagickPathExtent,
"%s:%.20g -> ",
3922 CommandOptionToMnemonic(MagickMorphologyOptions, method),(
double)
3932 while ( kernel_loop < kernel_limit && changed > 0 ) {
3936 if ( work_image == (Image *) NULL )
3938 work_image=CloneImage(image,0,0,MagickTrue,exception);
3939 if (work_image == (Image *) NULL)
3941 if (SetImageStorageClass(work_image,DirectClass,exception) == MagickFalse)
3947 changed = MorphologyPrimitive(curr_image, work_image, primitive,
3948 this_kernel, bias, exception);
3949 if (verbose != MagickFalse) {
3950 if ( kernel_loop > 1 )
3951 (void) FormatLocaleFile(stderr,
"\n");
3952 (void) (
void) FormatLocaleFile(stderr,
3953 "%s%s%s:%.20g.%.20g #%.20g => Changed %.20g",
3954 v_info,CommandOptionToMnemonic(MagickMorphologyOptions,
3955 primitive),(this_kernel == rflt_kernel ) ?
"*" :
"",
3956 (
double) (method_loop+kernel_loop-1),(
double) kernel_number,
3957 (
double) count,(
double) changed);
3961 kernel_changed = (size_t) ((ssize_t) kernel_changed+changed);
3962 method_changed = (size_t) ((ssize_t) method_changed+changed);
3965 { Image *tmp = work_image;
3966 work_image = curr_image;
3969 if ( work_image == image )
3970 work_image = (Image *) NULL;
3974 if (verbose != MagickFalse && kernel_changed != (
size_t)changed)
3975 (void) FormatLocaleFile(stderr,
" Total %.20g",(
double) kernel_changed);
3976 if (verbose != MagickFalse && stage_loop < stage_limit)
3977 (void) FormatLocaleFile(stderr,
"\n");
3980 (void) FormatLocaleFile(stderr,
"--E-- image=0x%lx\n", (
unsigned long)image);
3981 (void) FormatLocaleFile(stderr,
" curr =0x%lx\n", (
unsigned long)curr_image);
3982 (void) FormatLocaleFile(stderr,
" work =0x%lx\n", (
unsigned long)work_image);
3983 (void) FormatLocaleFile(stderr,
" save =0x%lx\n", (
unsigned long)save_image);
3984 (void) FormatLocaleFile(stderr,
" union=0x%lx\n", (
unsigned long)rslt_image);
3997 case EdgeOutMorphology:
3998 case EdgeInMorphology:
3999 case TopHatMorphology:
4000 case BottomHatMorphology:
4001 if (verbose != MagickFalse)
4002 (void) FormatLocaleFile(stderr,
4003 "\n%s: Difference with original image",CommandOptionToMnemonic(
4004 MagickMorphologyOptions, method) );
4005 (void) CompositeImage(curr_image,image,DifferenceCompositeOp,
4006 MagickTrue,0,0,exception);
4008 case EdgeMorphology:
4009 if (verbose != MagickFalse)
4010 (void) FormatLocaleFile(stderr,
4011 "\n%s: Difference of Dilate and Erode",CommandOptionToMnemonic(
4012 MagickMorphologyOptions, method) );
4013 (void) CompositeImage(curr_image,save_image,DifferenceCompositeOp,
4014 MagickTrue,0,0,exception);
4015 save_image = DestroyImage(save_image);
4022 if ( kernel->next == (KernelInfo *) NULL )
4023 rslt_image = curr_image;
4024 else if ( rslt_compose == NoCompositeOp )
4025 {
if (verbose != MagickFalse) {
4026 if ( this_kernel->next != (KernelInfo *) NULL )
4027 (void) FormatLocaleFile(stderr,
" (re-iterate)");
4029 (
void) FormatLocaleFile(stderr,
" (done)");
4031 rslt_image = curr_image;
4033 else if ( rslt_image == (Image *) NULL)
4034 {
if (verbose != MagickFalse)
4035 (void) FormatLocaleFile(stderr,
" (save for compose)");
4036 rslt_image = curr_image;
4037 curr_image = (Image *) image;
4047 if (verbose != MagickFalse)
4048 (void) FormatLocaleFile(stderr,
" (compose \"%s\")",
4049 CommandOptionToMnemonic(MagickComposeOptions, rslt_compose) );
4050 (void) CompositeImage(rslt_image,curr_image,rslt_compose,MagickTrue,
4052 curr_image = DestroyImage(curr_image);
4053 curr_image = (Image *) image;
4055 if (verbose != MagickFalse)
4056 (void) FormatLocaleFile(stderr,
"\n");
4059 norm_kernel = norm_kernel->next;
4060 if ( rflt_kernel != (KernelInfo *) NULL )
4061 rflt_kernel = rflt_kernel->next;
4071 if ( curr_image == rslt_image )
4072 curr_image = (Image *) NULL;
4073 if ( rslt_image != (Image *) NULL )
4074 rslt_image = DestroyImage(rslt_image);
4076 if ( curr_image == rslt_image || curr_image == image )
4077 curr_image = (Image *) NULL;
4078 if ( curr_image != (Image *) NULL )
4079 curr_image = DestroyImage(curr_image);
4080 if ( work_image != (Image *) NULL )
4081 work_image = DestroyImage(work_image);
4082 if ( save_image != (Image *) NULL )
4083 save_image = DestroyImage(save_image);
4084 if ( reflected_kernel != (KernelInfo *) NULL )
4085 reflected_kernel = DestroyKernelInfo(reflected_kernel);
4139MagickExport Image *MorphologyImage(
const Image *image,
4140 const MorphologyMethod method,
const ssize_t iterations,
4141 const KernelInfo *kernel,ExceptionInfo *exception)
4158 assert(image != (
const Image *) NULL);
4159 assert(image->signature == MagickCoreSignature);
4160 assert(exception != (ExceptionInfo *) NULL);
4161 assert(exception->signature == MagickCoreSignature);
4162 if (IsEventLogging() != MagickFalse)
4163 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4164 curr_kernel = (KernelInfo *) kernel;
4166 compose = UndefinedCompositeOp;
4172 if ( method == ConvolveMorphology || method == CorrelateMorphology ) {
4174 artifact = GetImageArtifact(image,
"convolve:bias");
4175 if ( artifact != (
const char *) NULL) {
4176 if (IsGeometry(artifact) == MagickFalse)
4177 (void) ThrowMagickException(exception,GetMagickModule(),
4178 OptionWarning,
"InvalidSetting",
"'%s' '%s'",
4179 "convolve:bias",artifact);
4181 bias=StringToDoubleInterval(artifact,(
double) QuantumRange+1.0);
4185 artifact = GetImageArtifact(image,
"convolve:scale");
4186 if ( artifact != (
const char *) NULL ) {
4187 if (IsGeometry(artifact) == MagickFalse)
4188 (void) ThrowMagickException(exception,GetMagickModule(),
4189 OptionWarning,
"InvalidSetting",
"'%s' '%s'",
4190 "convolve:scale",artifact);
4192 if ( curr_kernel == kernel )
4193 curr_kernel = CloneKernelInfo(kernel);
4194 if (curr_kernel == (KernelInfo *) NULL)
4195 return((Image *) NULL);
4196 ScaleGeometryKernelInfo(curr_kernel, artifact);
4202 artifact=GetImageArtifact(image,
"morphology:showKernel");
4203 if (IsStringTrue(artifact) != MagickFalse)
4204 ShowKernelInfo(curr_kernel);
4216 artifact = GetImageArtifact(image,
"morphology:compose");
4217 if ( artifact != (
const char *) NULL) {
4218 parse=ParseCommandOption(MagickComposeOptions,
4219 MagickFalse,artifact);
4221 (void) ThrowMagickException(exception,GetMagickModule(),
4222 OptionWarning,
"UnrecognizedComposeOperator",
"'%s' '%s'",
4223 "morphology:compose",artifact);
4225 compose=(CompositeOperator)parse;
4229 morphology_image = MorphologyApply(image,method,iterations,
4230 curr_kernel,compose,bias,exception);
4233 if ( curr_kernel != kernel )
4234 curr_kernel=DestroyKernelInfo(curr_kernel);
4235 return(morphology_image);
4268static void RotateKernelInfo(KernelInfo *kernel,
double angle)
4271 if ( kernel->next != (KernelInfo *) NULL)
4272 RotateKernelInfo(kernel->next, angle);
4280 angle = fmod(angle, 360.0);
4284 if ( 337.5 < angle || angle <= 22.5 )
4288 switch (kernel->type) {
4290 case GaussianKernel:
4295 case LaplacianKernel:
4296 case ChebyshevKernel:
4297 case ManhattanKernel:
4298 case EuclideanKernel:
4312 if ( 135.0 < angle && angle <= 225.0 )
4314 if ( 225.0 < angle && angle <= 315.0 )
4322 if ( 22.5 < fmod(angle,90.0) && fmod(angle,90.0) <= 67.5 )
4324 if ( kernel->width == 3 && kernel->height == 3 )
4326 double t = kernel->values[0];
4327 kernel->values[0] = kernel->values[3];
4328 kernel->values[3] = kernel->values[6];
4329 kernel->values[6] = kernel->values[7];
4330 kernel->values[7] = kernel->values[8];
4331 kernel->values[8] = kernel->values[5];
4332 kernel->values[5] = kernel->values[2];
4333 kernel->values[2] = kernel->values[1];
4334 kernel->values[1] = t;
4336 if ( kernel->x != 1 || kernel->y != 1 ) {
4338 x = (ssize_t) kernel->x-1;
4339 y = (ssize_t) kernel->y-1;
4340 if ( x == y ) x = 0;
4341 else if ( x == 0 ) x = -y;
4342 else if ( x == -y ) y = 0;
4343 else if ( y == 0 ) y = x;
4344 kernel->x = (ssize_t) x+1;
4345 kernel->y = (ssize_t) y+1;
4347 angle = fmod(angle+315.0, 360.0);
4348 kernel->angle = fmod(kernel->angle+45.0, 360.0);
4351 perror(
"Unable to rotate non-3x3 kernel by 45 degrees");
4353 if ( 45.0 < fmod(angle, 180.0) && fmod(angle,180.0) <= 135.0 )
4355 if ( kernel->width == 1 || kernel->height == 1 )
4361 t = (ssize_t) kernel->width;
4362 kernel->width = kernel->height;
4363 kernel->height = (size_t) t;
4365 kernel->x = kernel->y;
4367 if ( kernel->width == 1 ) {
4368 angle = fmod(angle+270.0, 360.0);
4369 kernel->angle = fmod(kernel->angle+90.0, 360.0);
4371 angle = fmod(angle+90.0, 360.0);
4372 kernel->angle = fmod(kernel->angle+270.0, 360.0);
4375 else if ( kernel->width == kernel->height )
4384 for( i=0, x=(ssize_t) kernel->width-1; i<=x; i++, x--)
4385 for( j=0, y=(ssize_t) kernel->height-1; j<y; j++, y--)
4386 { t = k[i+j*(ssize_t) kernel->width];
4387 k[i+j*(ssize_t) kernel->width] = k[j+x*(ssize_t) kernel->width];
4388 k[j+x*(ssize_t) kernel->width] = k[x+y*(ssize_t) kernel->width];
4389 k[x+y*(ssize_t) kernel->width] = k[y+i*(ssize_t) kernel->width];
4390 k[y+i*(ssize_t) kernel->width] = t;
4395 x = (ssize_t) (kernel->x*2-(ssize_t) kernel->width+1);
4396 y = (ssize_t) (kernel->y*2-(ssize_t) kernel->height+1);
4397 kernel->x = (ssize_t) ( -y +(ssize_t) kernel->width-1)/2;
4398 kernel->y = (ssize_t) ( +x +(ssize_t) kernel->height-1)/2;
4400 angle = fmod(angle+270.0, 360.0);
4401 kernel->angle = fmod(kernel->angle+90.0, 360.0);
4404 perror(
"Unable to rotate a non-square, non-linear kernel 90 degrees");
4406 if ( 135.0 < angle && angle <= 225.0 )
4424 j=(ssize_t) (kernel->width*kernel->height-1);
4425 for (i=0; i < j; i++, j--)
4426 t=k[i], k[i]=k[j], k[j]=t;
4428 kernel->x = (ssize_t) kernel->width - kernel->x - 1;
4429 kernel->y = (ssize_t) kernel->height - kernel->y - 1;
4430 angle = fmod(angle-180.0, 360.0);
4431 kernel->angle = fmod(kernel->angle+180.0, 360.0);
4475MagickExport
void ScaleGeometryKernelInfo (KernelInfo *kernel,
4476 const char *geometry)
4484 SetGeometryInfo(&args);
4485 flags = ParseGeometry(geometry, &args);
4489 (void) FormatLocaleFile(stderr,
"Geometry = 0x%04X : %lg x %lg %+lg %+lg\n",
4490 flags, args.rho, args.sigma, args.xi, args.psi );
4493 if ( (flags & PercentValue) != 0 )
4494 args.rho *= 0.01, args.sigma *= 0.01;
4496 if ( (flags & RhoValue) == 0 )
4498 if ( (flags & SigmaValue) == 0 )
4502 ScaleKernelInfo(kernel, args.rho, (GeometryFlags) flags);
4505 if ( (flags & SigmaValue) != 0 )
4506 UnityAddKernelInfo(kernel, args.sigma);
4581MagickExport
void ScaleKernelInfo(KernelInfo *kernel,
4582 const double scaling_factor,
const GeometryFlags normalize_flags)
4592 if ( kernel->next != (KernelInfo *) NULL)
4593 ScaleKernelInfo(kernel->next, scaling_factor, normalize_flags);
4597 if ( (normalize_flags&NormalizeValue) != 0 ) {
4598 if ( fabs(kernel->positive_range + kernel->negative_range) >= MagickEpsilon )
4600 pos_scale = fabs(kernel->positive_range + kernel->negative_range);
4603 pos_scale = kernel->positive_range;
4606 if ( (normalize_flags&CorrelateNormalizeValue) != 0 ) {
4607 pos_scale = ( fabs(kernel->positive_range) >= MagickEpsilon )
4608 ? kernel->positive_range : 1.0;
4609 neg_scale = ( fabs(kernel->negative_range) >= MagickEpsilon )
4610 ? -kernel->negative_range : 1.0;
4613 neg_scale = pos_scale;
4616 pos_scale = scaling_factor/pos_scale;
4617 neg_scale = scaling_factor/neg_scale;
4619 for (i=0; i < (ssize_t) (kernel->width*kernel->height); i++)
4620 if (!IsNaN(kernel->values[i]))
4621 kernel->values[i] *= (kernel->values[i] >= 0) ? pos_scale : neg_scale;
4624 kernel->positive_range *= pos_scale;
4625 kernel->negative_range *= neg_scale;
4627 kernel->maximum *= (kernel->maximum >= 0.0) ? pos_scale : neg_scale;
4628 kernel->minimum *= (kernel->minimum >= 0.0) ? pos_scale : neg_scale;
4631 if ( scaling_factor < MagickEpsilon ) {
4633 t = kernel->positive_range;
4634 kernel->positive_range = kernel->negative_range;
4635 kernel->negative_range = t;
4636 t = kernel->maximum;
4637 kernel->maximum = kernel->minimum;
4638 kernel->minimum = 1;
4668MagickPrivate
void ShowKernelInfo(
const KernelInfo *kernel)
4676 for (c=0, k=kernel; k != (KernelInfo *) NULL; c++, k=k->next ) {
4678 (void) FormatLocaleFile(stderr,
"Kernel");
4679 if ( kernel->next != (KernelInfo *) NULL )
4680 (void) FormatLocaleFile(stderr,
" #%lu", (
unsigned long) c );
4681 (void) FormatLocaleFile(stderr,
" \"%s",
4682 CommandOptionToMnemonic(MagickKernelOptions, k->type) );
4683 if ( fabs(k->angle) >= MagickEpsilon )
4684 (void) FormatLocaleFile(stderr,
"@%lg", k->angle);
4685 (void) FormatLocaleFile(stderr,
"\" of size %lux%lu%+ld%+ld",(
unsigned long)
4686 k->width,(
unsigned long) k->height,(
long) k->x,(
long) k->y);
4687 (void) FormatLocaleFile(stderr,
4688 " with values from %.*lg to %.*lg\n",
4689 GetMagickPrecision(), k->minimum,
4690 GetMagickPrecision(), k->maximum);
4691 (void) FormatLocaleFile(stderr,
"Forming a output range from %.*lg to %.*lg",
4692 GetMagickPrecision(), k->negative_range,
4693 GetMagickPrecision(), k->positive_range);
4694 if ( fabs(k->positive_range+k->negative_range) < MagickEpsilon )
4695 (void) FormatLocaleFile(stderr,
" (Zero-Summing)\n");
4696 else if ( fabs(k->positive_range+k->negative_range-1.0) < MagickEpsilon )
4697 (void) FormatLocaleFile(stderr,
" (Normalized)\n");
4699 (
void) FormatLocaleFile(stderr,
" (Sum %.*lg)\n",
4700 GetMagickPrecision(), k->positive_range+k->negative_range);
4701 for (i=v=0; v < k->height; v++) {
4702 (void) FormatLocaleFile(stderr,
"%2lu:", (
unsigned long) v );
4703 for (u=0; u < k->width; u++, i++)
4704 if (IsNaN(k->values[i]))
4705 (void) FormatLocaleFile(stderr,
" %*s", GetMagickPrecision()+3,
"nan");
4707 (
void) FormatLocaleFile(stderr,
" %*.*lg", GetMagickPrecision()+3,
4708 GetMagickPrecision(), (
double) k->values[i]);
4709 (void) FormatLocaleFile(stderr,
"\n");
4747MagickExport
void UnityAddKernelInfo(KernelInfo *kernel,
4751 if ( kernel->next != (KernelInfo *) NULL)
4752 UnityAddKernelInfo(kernel->next, scale);
4755 kernel->values[kernel->x+kernel->y*(ssize_t) kernel->width] += scale;
4756 CalcKernelMetaData(kernel);
4786MagickPrivate
void ZeroKernelNans(KernelInfo *kernel)
4792 if (kernel->next != (KernelInfo *) NULL)
4793 ZeroKernelNans(kernel->next);
4795 for (i=0; i < (kernel->width*kernel->height); i++)
4796 if (IsNaN(kernel->values[i]))
4797 kernel->values[i]=0.0;