53 #include "magick/studio.h" 54 #include "magick/artifact.h" 55 #include "magick/cache-view.h" 56 #include "magick/color-private.h" 57 #include "magick/channel.h" 58 #include "magick/enhance.h" 59 #include "magick/exception.h" 60 #include "magick/exception-private.h" 61 #include "magick/gem.h" 62 #include "magick/hashmap.h" 63 #include "magick/image.h" 64 #include "magick/image-private.h" 65 #include "magick/list.h" 66 #include "magick/magick.h" 67 #include "magick/memory_.h" 68 #include "magick/memory-private.h" 69 #include "magick/monitor-private.h" 70 #include "magick/morphology.h" 71 #include "magick/morphology-private.h" 72 #include "magick/option.h" 73 #include "magick/pixel-private.h" 74 #include "magick/prepress.h" 75 #include "magick/quantize.h" 76 #include "magick/registry.h" 77 #include "magick/resource_.h" 78 #include "magick/semaphore.h" 79 #include "magick/splay-tree.h" 80 #include "magick/statistic.h" 81 #include "magick/string_.h" 82 #include "magick/string-private.h" 83 #include "magick/thread-private.h" 84 #include "magick/token.h" 85 #include "magick/utility.h" 91 #define Minimize(assign,value) assign=MagickMin(assign,value) 92 #define Maximize(assign,value) assign=MagickMax(assign,value) 95 static inline size_t fact(
size_t n)
98 for(f=1, l=2; l <= n; f=f*l, l++);
106 ExpandRotateKernelInfo(
KernelInfo *,
const double),
204 static inline MagickBooleanType AcquireKernelValues(
KernelInfo *kernel)
209 kernel->values=(
double *) NULL;
210 if (HeapOverflowSanityCheckGetSize(kernel->width,kernel->height,&elements) != MagickFalse)
212 kernel->values=(
double *) MagickAssumeAligned(AcquireAlignedMemory(
213 elements,
sizeof(*kernel->values)));
214 return(kernel->values == (
double *) NULL ? MagickFalse : MagickTrue);
220 static KernelInfo *ParseKernelArray(
const char *kernel_string)
226 token[MaxTextExtent];
247 kernel=(
KernelInfo *) AcquireMagickMemory(
sizeof(*kernel));
250 (void) memset(kernel,0,
sizeof(*kernel));
251 kernel->minimum = kernel->maximum = kernel->angle = 0.0;
252 kernel->negative_range = kernel->positive_range = 0.0;
253 kernel->type = UserDefinedKernel;
255 kernel->signature = MagickCoreSignature;
256 if (kernel_string == (
const char *) NULL)
260 end = strchr(kernel_string,
';');
261 if ( end == (
char *) NULL )
262 end = strchr(kernel_string,
'\0');
270 p = strchr(kernel_string,
':');
271 if ( p != (
char *) NULL && p < end)
274 length=MagickMin((
size_t) (p-kernel_string),
sizeof(token)-1);
275 (void) memcpy(token, kernel_string, length);
276 token[length] =
'\0';
277 SetGeometryInfo(&args);
278 flags = ParseGeometry(token, &args);
281 if ( (flags & WidthValue) == 0 )
282 args.rho = args.sigma;
283 if ( args.rho < 1.0 )
285 if ( args.sigma < 1.0 )
286 args.sigma = args.rho;
287 kernel->width = CastDoubleToSizeT(args.rho);
288 kernel->height = CastDoubleToSizeT(args.sigma);
291 if ( args.xi < 0.0 || args.psi < 0.0 )
292 return(DestroyKernelInfo(kernel));
293 kernel->x = ((flags & XValue)!=0) ? (ssize_t)args.xi
294 : (ssize_t) (kernel->width-1)/2;
295 kernel->y = ((flags & YValue)!=0) ? (ssize_t)args.psi
296 : (ssize_t) (kernel->height-1)/2;
297 if ( kernel->x >= (ssize_t) kernel->width ||
298 kernel->y >= (ssize_t) kernel->height )
299 return(DestroyKernelInfo(kernel));
306 p=(
const char *) kernel_string;
307 while ((isspace((
int) ((
unsigned char) *p)) != 0) || (*p ==
'\''))
309 for (i=0; p < end; i++)
311 (void) GetNextToken(p,&p,MaxTextExtent,token);
313 (void) GetNextToken(p,&p,MaxTextExtent,token);
316 kernel->width = kernel->height= CastDoubleToSizeT(sqrt((
double) i+1.0));
317 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
318 p=(
const char *) kernel_string;
319 while ((isspace((
int) ((
unsigned char) *p)) != 0) || (*p ==
'\''))
324 if (AcquireKernelValues(kernel) == MagickFalse)
325 return(DestroyKernelInfo(kernel));
326 kernel->minimum=MagickMaximumValue;
327 kernel->maximum=(-MagickMaximumValue);
328 kernel->negative_range = kernel->positive_range = 0.0;
329 for (i=0; (i < (ssize_t) (kernel->width*kernel->height)) && (p < end); i++)
331 (void) GetNextToken(p,&p,MaxTextExtent,token);
333 (void) GetNextToken(p,&p,MaxTextExtent,token);
334 if ( LocaleCompare(
"nan",token) == 0
335 || LocaleCompare(
"-",token) == 0 ) {
336 kernel->values[i] = nan;
339 kernel->values[i] = StringToDouble(token,(
char **) NULL);
340 ( kernel->values[i] < 0)
341 ? ( kernel->negative_range += kernel->values[i] )
342 : ( kernel->positive_range += kernel->values[i] );
343 Minimize(kernel->minimum, kernel->values[i]);
344 Maximize(kernel->maximum, kernel->values[i]);
349 (void) GetNextToken(p,&p,MaxTextExtent,token);
350 if ( *token !=
'\0' && *token !=
';' && *token !=
'\'' )
351 return(DestroyKernelInfo(kernel));
355 if ( i < (ssize_t) (kernel->width*kernel->height) ) {
356 Minimize(kernel->minimum, kernel->values[i]);
357 Maximize(kernel->maximum, kernel->values[i]);
358 for ( ; i < (ssize_t) (kernel->width*kernel->height); i++)
359 kernel->values[i]=0.0;
363 if ( i < (ssize_t) (kernel->width*kernel->height) )
364 return(DestroyKernelInfo(kernel));
368 if (kernel->minimum == MagickMaximumValue)
369 return(DestroyKernelInfo(kernel));
371 if ( (flags & AreaValue) != 0 )
372 ExpandRotateKernelInfo(kernel, 45.0);
373 else if ( (flags & GreaterValue) != 0 )
374 ExpandRotateKernelInfo(kernel, 90.0);
375 else if ( (flags & LessValue) != 0 )
376 ExpandMirrorKernelInfo(kernel);
381 static KernelInfo *ParseKernelName(
const char *kernel_string)
384 token[MaxTextExtent] =
"";
406 (void) GetNextToken(kernel_string,&p,MaxTextExtent,token);
407 type=ParseCommandOption(MagickKernelOptions,MagickFalse,token);
408 if ( type < 0 || type == UserDefinedKernel )
411 while (((isspace((
int) ((
unsigned char) *p)) != 0) ||
412 (*p ==
',') || (*p ==
':' )) && (*p !=
'\0') && (*p !=
';'))
415 end = strchr(p,
';');
416 if ( end == (
char *) NULL )
417 end = strchr(p,
'\0');
420 length=MagickMin((
size_t) (end-p),
sizeof(token)-1);
421 (void) memcpy(token, p, length);
422 token[length] =
'\0';
423 SetGeometryInfo(&args);
424 flags = ParseGeometry(token, &args);
428 (void) FormatLocaleFile(stderr,
"Geometry = 0x%04X : %lg x %lg %+lg %+lg\n",
429 flags, args.rho, args.sigma, args.xi, args.psi );
436 if ( (flags & WidthValue) == 0 )
445 if ( (flags & HeightValue) == 0 )
449 if ( (flags & XValue) == 0 )
452 case RectangleKernel:
453 if ( (flags & WidthValue) == 0 )
454 args.rho = args.sigma;
455 if ( args.rho < 1.0 )
457 if ( args.sigma < 1.0 )
458 args.sigma = args.rho;
459 if ( (flags & XValue) == 0 )
460 args.xi = (
double)(((ssize_t)args.rho-1)/2);
461 if ( (flags & YValue) == 0 )
462 args.psi = (
double)(((ssize_t)args.sigma-1)/2);
465 case ChebyshevKernel:
466 case ManhattanKernel:
467 case OctagonalKernel:
468 case EuclideanKernel:
469 if ( (flags & HeightValue) == 0 )
471 else if ( (flags & AspectValue ) != 0 )
472 args.sigma = (
double) QuantumRange/(args.sigma+1);
473 else if ( (flags & PercentValue ) != 0 )
474 args.sigma *= (
double) QuantumRange/100.0;
480 kernel = AcquireKernelBuiltIn((KernelInfoType)type, &args);
486 if ( (flags & AreaValue) != 0 )
487 ExpandRotateKernelInfo(kernel, 45.0);
488 else if ( (flags & GreaterValue) != 0 )
489 ExpandRotateKernelInfo(kernel, 90.0);
490 else if ( (flags & LessValue) != 0 )
491 ExpandMirrorKernelInfo(kernel);
497 MagickExport
KernelInfo *AcquireKernelInfo(
const char *kernel_string)
505 token[MaxTextExtent];
510 if (kernel_string == (
const char *) NULL)
511 return(ParseKernelArray(kernel_string));
513 kernel_cache=(
char *) NULL;
514 if (*kernel_string ==
'@')
517 kernel_cache=FileToString(kernel_string,~0UL,exception);
518 exception=DestroyExceptionInfo(exception);
519 if (kernel_cache == (
char *) NULL)
521 p=(
const char *) kernel_cache;
525 while (GetNextToken(p,(
const char **) NULL,MaxTextExtent,token), *token !=
'\0')
531 if (isalpha((
int) ((
unsigned char) *token)) != 0)
532 new_kernel=ParseKernelName(p);
534 new_kernel=ParseKernelArray(p);
540 kernel=DestroyKernelInfo(kernel);
548 LastKernelInfo(kernel)->next=new_kernel;
553 if (p == (
char *) NULL)
557 if (kernel_cache != (
char *) NULL)
558 kernel_cache=DestroyString(kernel_cache);
963 MagickExport
KernelInfo *AcquireKernelBuiltIn(
const KernelInfoType type,
982 case UndefinedKernel:
983 case UserDefinedKernel:
984 assert(
"Should not call this function" != (
char *) NULL);
986 case LaplacianKernel:
995 case DiagonalsKernel:
997 case LineJunctionsKernel:
999 case ConvexHullKernel:
1000 case SkeletonKernel:
1006 case GaussianKernel:
1011 case BinomialKernel:
1014 case RectangleKernel:
1021 case ChebyshevKernel:
1022 case ManhattanKernel:
1023 case OctagonalKernel:
1024 case EuclideanKernel:
1029 kernel=(
KernelInfo *) AcquireMagickMemory(
sizeof(*kernel));
1032 (void) memset(kernel,0,
sizeof(*kernel));
1033 kernel->minimum = kernel->maximum = kernel->angle = 0.0;
1034 kernel->negative_range = kernel->positive_range = 0.0;
1035 kernel->type = type;
1037 kernel->signature = MagickCoreSignature;
1047 kernel->height = kernel->width = (size_t) 1;
1048 kernel->x = kernel->y = (ssize_t) 0;
1049 kernel->values=(
double *) MagickAssumeAligned(AcquireAlignedMemory(1,
1050 sizeof(*kernel->values)));
1051 if (kernel->values == (
double *) NULL)
1052 return(DestroyKernelInfo(kernel));
1053 kernel->maximum = kernel->values[0] = args->rho;
1057 case GaussianKernel:
1061 sigma = fabs(args->sigma),
1062 sigma2 = fabs(args->xi),
1065 if ( args->rho >= 1.0 )
1066 kernel->width = CastDoubleToSizeT(args->rho)*2+1;
1067 else if ( (type != DoGKernel) || (sigma >= sigma2) )
1068 kernel->width = GetOptimalKernelWidth2D(args->rho,sigma);
1070 kernel->width = GetOptimalKernelWidth2D(args->rho,sigma2);
1071 kernel->height = kernel->width;
1072 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1073 if (AcquireKernelValues(kernel) == MagickFalse)
1074 return(DestroyKernelInfo(kernel));
1083 if ( type == GaussianKernel || type == DoGKernel )
1085 if ( sigma > MagickEpsilon )
1086 { A = 1.0/(2.0*sigma*sigma);
1087 B = (double) (1.0/(Magick2PI*sigma*sigma));
1088 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1089 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1090 kernel->values[i] = exp(-((
double)(u*u+v*v))*A)*B;
1093 { (void) memset(kernel->values,0, (
size_t)
1094 kernel->width*kernel->height*
sizeof(*kernel->values));
1095 kernel->values[kernel->x+kernel->y*kernel->width] = 1.0;
1099 if ( type == DoGKernel )
1101 if ( sigma2 > MagickEpsilon )
1103 A = 1.0/(2.0*sigma*sigma);
1104 B = (double) (1.0/(Magick2PI*sigma*sigma));
1105 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1106 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1107 kernel->values[i] -= exp(-((
double)(u*u+v*v))*A)*B;
1110 kernel->values[kernel->x+kernel->y*kernel->width] -= 1.0;
1113 if ( type == LoGKernel )
1115 if ( sigma > MagickEpsilon )
1116 { A = 1.0/(2.0*sigma*sigma);
1117 B = (double) (1.0/(MagickPI*sigma*sigma*sigma*sigma));
1118 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1119 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1120 { R = ((double)(u*u+v*v))*A;
1121 kernel->values[i] = (1-R)*exp(-R)*B;
1125 { (void) memset(kernel->values,0, (
size_t)
1126 kernel->width*kernel->height*
sizeof(*kernel->values));
1127 kernel->values[kernel->x+kernel->y*kernel->width] = 1.0;
1144 CalcKernelMetaData(kernel);
1145 ScaleKernelInfo(kernel, 1.0, CorrelateNormalizeValue);
1151 sigma = fabs(args->sigma),
1154 if ( args->rho >= 1.0 )
1155 kernel->width = CastDoubleToSizeT(args->rho)*2+1;
1157 kernel->width = GetOptimalKernelWidth1D(args->rho,sigma);
1159 kernel->x = (ssize_t) (kernel->width-1)/2;
1161 kernel->negative_range = kernel->positive_range = 0.0;
1162 if (AcquireKernelValues(kernel) == MagickFalse)
1163 return(DestroyKernelInfo(kernel));
1166 #define KernelRank 3 1181 v = (ssize_t) (kernel->width*KernelRank-1)/2;
1182 (void) memset(kernel->values,0, (
size_t)
1183 kernel->width*kernel->height*
sizeof(*kernel->values));
1185 if ( sigma > MagickEpsilon )
1186 { sigma *= KernelRank;
1187 alpha = 1.0/(2.0*sigma*sigma);
1188 beta= (double) (1.0/(MagickSQ2PI*sigma ));
1189 for ( u=-v; u <= v; u++) {
1190 kernel->values[(u+v)/KernelRank] +=
1191 exp(-((
double)(u*u))*alpha)*beta;
1195 kernel->values[kernel->x+kernel->y*kernel->width] = 1.0;
1201 if ( sigma > MagickEpsilon )
1202 { alpha = 1.0/(2.0*sigma*sigma);
1203 beta = 1.0/(MagickSQ2PI*sigma);
1204 for ( i=0, u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1205 kernel->values[i] = exp(-((
double)(u*u))*alpha)*beta;
1208 { (void) memset(kernel->values,0, (
size_t)
1209 kernel->width*kernel->height*
sizeof(*kernel->values));
1210 kernel->values[kernel->x+kernel->y*kernel->width] = 1.0;
1227 CalcKernelMetaData(kernel);
1228 ScaleKernelInfo(kernel, 1.0, CorrelateNormalizeValue);
1231 RotateKernelInfo(kernel, args->xi );
1236 sigma = fabs(args->sigma),
1239 if ( args->rho < 1.0 )
1240 kernel->width = (GetOptimalKernelWidth1D(args->rho,sigma)-1)/2+1;
1242 kernel->width = CastDoubleToSizeT(args->rho);
1243 kernel->x = kernel->y = 0;
1245 kernel->negative_range = kernel->positive_range = 0.0;
1246 if (AcquireKernelValues(kernel) == MagickFalse)
1247 return(DestroyKernelInfo(kernel));
1259 if ( sigma > MagickEpsilon )
1262 #define KernelRank 3 1263 v = (ssize_t) kernel->width*KernelRank;
1264 (
void) memset(kernel->values,0, (
size_t)
1265 kernel->width*
sizeof(*kernel->values));
1266 sigma *= KernelRank;
1267 A = 1.0/(2.0*sigma*sigma);
1269 for ( u=0; u < v; u++) {
1270 kernel->values[u/KernelRank] +=
1271 exp(-((
double)(u*u))*A);
1274 for (i=0; i < (ssize_t) kernel->width; i++)
1275 kernel->positive_range += kernel->values[i];
1277 A = 1.0/(2.0*sigma*sigma);
1279 for ( i=0; i < (ssize_t) kernel->width; i++)
1280 kernel->positive_range +=
1281 kernel->values[i] = exp(-((
double)(i*i))*A);
1286 { (void) memset(kernel->values,0, (
size_t)
1287 kernel->width*kernel->height*
sizeof(*kernel->values));
1288 kernel->values[kernel->x+kernel->y*kernel->width] = 1.0;
1289 kernel->positive_range = 1.0;
1292 kernel->minimum = 0.0;
1293 kernel->maximum = kernel->values[0];
1294 kernel->negative_range = 0.0;
1296 ScaleKernelInfo(kernel, 1.0, NormalizeValue);
1297 RotateKernelInfo(kernel, args->xi);
1300 case BinomialKernel:
1303 max_order = (
sizeof(size_t) > 4) ? 20 : 12;
1308 if (args->rho < 1.0)
1309 kernel->width = kernel->height = 3;
1311 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
1312 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1315 if ((kernel->width-1) > max_order)
1316 return(DestroyKernelInfo(kernel));
1318 order_f = fact(kernel->width-1);
1320 if (AcquireKernelValues(kernel) == MagickFalse)
1321 return(DestroyKernelInfo(kernel));
1324 for ( i=0, v=0; v < (ssize_t)kernel->height; v++)
1326 alpha = order_f / ( fact((
size_t) v) * fact(kernel->height-v-1) );
1327 for ( u=0; u < (ssize_t)kernel->width; u++, i++)
1328 kernel->positive_range += kernel->values[i] = (double)
1329 (alpha * order_f / ( fact((
size_t) u) * fact(kernel->height-u-1) ));
1331 kernel->minimum = 1.0;
1332 kernel->maximum = kernel->values[kernel->x+kernel->y*kernel->width];
1333 kernel->negative_range = 0.0;
1340 case LaplacianKernel:
1341 {
switch ( (
int) args->rho ) {
1344 kernel=ParseKernelArray(
"3: -1,-1,-1 -1,8,-1 -1,-1,-1");
1347 kernel=ParseKernelArray(
"3: 0,-1,0 -1,4,-1 0,-1,0");
1350 kernel=ParseKernelArray(
"3: -2,1,-2 1,4,1 -2,1,-2");
1353 kernel=ParseKernelArray(
"3: 1,-2,1 -2,4,-2 1,-2,1");
1356 kernel=ParseKernelArray(
1357 "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");
1360 kernel=ParseKernelArray(
1361 "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" );
1364 kernel=ParseKernelArray(
1365 "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");
1369 kernel=ParseKernelArray(
1370 "9: 0,-1,-1,-2,-2,-2,-1,-1,0 -1,-2,-4,-5,-5,-5,-4,-2,-1 -1,-4,-5,-3,-0,-3,-5,-4,-1 -2,-5,-3,12,24,12,-3,-5,-2 -2,-5,-0,24,40,24,-0,-5,-2 -2,-5,-3,12,24,12,-3,-5,-2 -1,-4,-5,-3,-0,-3,-5,-4,-1 -1,-2,-4,-5,-5,-5,-4,-2,-1 0,-1,-1,-2,-2,-2,-1,-1,0");
1375 kernel->type = type;
1380 kernel=ParseKernelArray(
"3: 1,0,-1 2,0,-2 1,0,-1");
1383 kernel->type = type;
1384 RotateKernelInfo(kernel, args->rho);
1389 kernel=ParseKernelArray(
"3: 0,0,0 1,-1,0 0,0,0");
1392 kernel->type = type;
1393 RotateKernelInfo(kernel, args->rho);
1398 kernel=ParseKernelArray(
"3: 1,0,-1 1,0,-1 1,0,-1");
1401 kernel->type = type;
1402 RotateKernelInfo(kernel, args->rho);
1407 kernel=ParseKernelArray(
"3: 1,1,-1 1,-2,-1 1,1,-1");
1410 kernel->type = type;
1411 RotateKernelInfo(kernel, args->rho);
1416 kernel=ParseKernelArray(
"3: 5,-3,-3 5,0,-3 5,-3,-3");
1419 kernel->type = type;
1420 RotateKernelInfo(kernel, args->rho);
1423 case FreiChenKernel:
1427 {
switch ( (
int) args->rho ) {
1430 kernel=ParseKernelArray(
"3: 1,0,-1 2,0,-2 1,0,-1");
1433 kernel->type = type;
1434 kernel->values[3] = +MagickSQ2;
1435 kernel->values[5] = -MagickSQ2;
1436 CalcKernelMetaData(kernel);
1439 kernel=ParseKernelArray(
"3: 1,2,0 2,0,-2 0,-2,-1");
1442 kernel->type = type;
1443 kernel->values[1] = kernel->values[3]= +MagickSQ2;
1444 kernel->values[5] = kernel->values[7]= -MagickSQ2;
1445 CalcKernelMetaData(kernel);
1446 ScaleKernelInfo(kernel, (
double) (1.0/2.0*MagickSQ2), NoValue);
1449 kernel=AcquireKernelInfo(
"FreiChen:11;FreiChen:12;FreiChen:13;FreiChen:14;FreiChen:15;FreiChen:16;FreiChen:17;FreiChen:18;FreiChen:19");
1455 kernel=ParseKernelArray(
"3: 1,0,-1 2,0,-2 1,0,-1");
1458 kernel->type = type;
1459 kernel->values[3] = +MagickSQ2;
1460 kernel->values[5] = -MagickSQ2;
1461 CalcKernelMetaData(kernel);
1462 ScaleKernelInfo(kernel, (
double) (1.0/2.0*MagickSQ2), NoValue);
1465 kernel=ParseKernelArray(
"3: 1,2,1 0,0,0 1,2,1");
1468 kernel->type = type;
1469 kernel->values[1] = +MagickSQ2;
1470 kernel->values[7] = +MagickSQ2;
1471 CalcKernelMetaData(kernel);
1472 ScaleKernelInfo(kernel, (
double) (1.0/2.0*MagickSQ2), NoValue);
1475 kernel=ParseKernelArray(
"3: 2,-1,0 -1,0,1 0,1,-2");
1478 kernel->type = type;
1479 kernel->values[0] = +MagickSQ2;
1480 kernel->values[8] = -MagickSQ2;
1481 CalcKernelMetaData(kernel);
1482 ScaleKernelInfo(kernel, (
double) (1.0/2.0*MagickSQ2), NoValue);
1485 kernel=ParseKernelArray(
"3: 0,1,-2 -1,0,1 2,-1,0");
1488 kernel->type = type;
1489 kernel->values[2] = -MagickSQ2;
1490 kernel->values[6] = +MagickSQ2;
1491 CalcKernelMetaData(kernel);
1492 ScaleKernelInfo(kernel, (
double) (1.0/2.0*MagickSQ2), NoValue);
1495 kernel=ParseKernelArray(
"3: 0,-1,0 1,0,1 0,-1,0");
1498 kernel->type = type;
1499 ScaleKernelInfo(kernel, 1.0/2.0, NoValue);
1502 kernel=ParseKernelArray(
"3: 1,0,-1 0,0,0 -1,0,1");
1505 kernel->type = type;
1506 ScaleKernelInfo(kernel, 1.0/2.0, NoValue);
1509 kernel=ParseKernelArray(
"3: 1,-2,1 -2,4,-2 -1,-2,1");
1512 kernel->type = type;
1513 ScaleKernelInfo(kernel, 1.0/6.0, NoValue);
1516 kernel=ParseKernelArray(
"3: -2,1,-2 1,4,1 -2,1,-2");
1519 kernel->type = type;
1520 ScaleKernelInfo(kernel, 1.0/6.0, NoValue);
1523 kernel=ParseKernelArray(
"3: 1,1,1 1,1,1 1,1,1");
1526 kernel->type = type;
1527 ScaleKernelInfo(kernel, 1.0/3.0, NoValue);
1530 if ( fabs(args->sigma) >= MagickEpsilon )
1532 RotateKernelInfo(kernel, args->sigma);
1533 else if ( args->rho > 30.0 || args->rho < -30.0 )
1535 RotateKernelInfo(kernel, args->rho);
1544 if (args->rho < 1.0)
1545 kernel->width = kernel->height = 3;
1547 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
1548 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1550 if (AcquireKernelValues(kernel) == MagickFalse)
1551 return(DestroyKernelInfo(kernel));
1554 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1555 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1556 if ( (labs((
long) u)+labs((
long) v)) <= (long) kernel->x)
1557 kernel->positive_range += kernel->values[i] = args->sigma;
1559 kernel->values[i] = nan;
1560 kernel->minimum = kernel->maximum = args->sigma;
1564 case RectangleKernel:
1567 if ( type == SquareKernel )
1569 if (args->rho < 1.0)
1570 kernel->width = kernel->height = 3;
1572 kernel->width = kernel->height = CastDoubleToSizeT(2*args->rho+1);
1573 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1574 scale = args->sigma;
1578 if ( args->rho < 1.0 || args->sigma < 1.0 )
1579 return(DestroyKernelInfo(kernel));
1580 kernel->width = CastDoubleToSizeT(args->rho);
1581 kernel->height = CastDoubleToSizeT(args->sigma);
1582 if ((args->xi < 0.0) || (args->xi >= (
double) kernel->width) ||
1583 (args->psi < 0.0) || (args->psi >= (
double) kernel->height))
1584 return(DestroyKernelInfo(kernel));
1585 kernel->x = (ssize_t) args->xi;
1586 kernel->y = (ssize_t) args->psi;
1589 if (AcquireKernelValues(kernel) == MagickFalse)
1590 return(DestroyKernelInfo(kernel));
1593 u=(ssize_t) (kernel->width*kernel->height);
1594 for ( i=0; i < u; i++)
1595 kernel->values[i] = scale;
1596 kernel->minimum = kernel->maximum = scale;
1597 kernel->positive_range = scale*u;
1602 if (args->rho < 1.0)
1603 kernel->width = kernel->height = 5;
1605 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
1606 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1608 if (AcquireKernelValues(kernel) == MagickFalse)
1609 return(DestroyKernelInfo(kernel));
1611 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1612 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1613 if ( (labs((
long) u)+labs((
long) v)) <=
1614 ((long)kernel->x + (
long)(kernel->x/2)) )
1615 kernel->positive_range += kernel->values[i] = args->sigma;
1617 kernel->values[i] = nan;
1618 kernel->minimum = kernel->maximum = args->sigma;
1624 limit = (ssize_t)(args->rho*args->rho);
1626 if (args->rho < 0.4)
1627 kernel->width = kernel->height = 9L, limit = 18L;
1629 kernel->width = kernel->height = CastDoubleToSizeT(fabs(args->rho)*2+1);
1630 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1632 if (AcquireKernelValues(kernel) == MagickFalse)
1633 return(DestroyKernelInfo(kernel));
1635 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1636 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1637 if ((u*u+v*v) <= limit)
1638 kernel->positive_range += kernel->values[i] = args->sigma;
1640 kernel->values[i] = nan;
1641 kernel->minimum = kernel->maximum = args->sigma;
1646 if (args->rho < 1.0)
1647 kernel->width = kernel->height = 5;
1649 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
1650 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1652 if (AcquireKernelValues(kernel) == MagickFalse)
1653 return(DestroyKernelInfo(kernel));
1656 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1657 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1658 kernel->values[i] = (u == 0 || v == 0) ? args->sigma : nan;
1659 kernel->minimum = kernel->maximum = args->sigma;
1660 kernel->positive_range = args->sigma*(kernel->width*2.0 - 1.0);
1665 if (args->rho < 1.0)
1666 kernel->width = kernel->height = 5;
1668 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
1669 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1671 if (AcquireKernelValues(kernel) == MagickFalse)
1672 return(DestroyKernelInfo(kernel));
1675 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
1676 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1677 kernel->values[i] = (u == v || u == -v) ? args->sigma : nan;
1678 kernel->minimum = kernel->maximum = args->sigma;
1679 kernel->positive_range = args->sigma*(kernel->width*2.0 - 1.0);
1693 if (args->rho < args->sigma)
1695 kernel->width = CastDoubleToSizeT(args->sigma)*2+1;
1696 limit1 = (ssize_t)(args->rho*args->rho);
1697 limit2 = (ssize_t)(args->sigma*args->sigma);
1701 kernel->width = CastDoubleToSizeT(args->rho)*2+1;
1702 limit1 = (ssize_t)(args->sigma*args->sigma);
1703 limit2 = (ssize_t)(args->rho*args->rho);
1706 kernel->width = 7L, limit1 = 7L, limit2 = 11L;
1708 kernel->height = kernel->width;
1709 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
1710 if (AcquireKernelValues(kernel) == MagickFalse)
1711 return(DestroyKernelInfo(kernel));
1714 scale = (ssize_t) (( type == PeaksKernel) ? 0.0 : args->xi);
1715 for ( i=0, v= -kernel->y; v <= (ssize_t)kernel->y; v++)
1716 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
1717 { ssize_t radius=u*u+v*v;
1718 if (limit1 < radius && radius <= limit2)
1719 kernel->positive_range += kernel->values[i] = (double) scale;
1721 kernel->values[i] = nan;
1723 kernel->minimum = kernel->maximum = (double) scale;
1724 if ( type == PeaksKernel ) {
1726 kernel->values[kernel->x+kernel->y*kernel->width] = 1.0;
1727 kernel->positive_range = 1.0;
1728 kernel->maximum = 1.0;
1734 kernel=AcquireKernelInfo(
"ThinSE:482");
1737 kernel->type = type;
1738 ExpandMirrorKernelInfo(kernel);
1743 kernel=AcquireKernelInfo(
"ThinSE:87");
1746 kernel->type = type;
1747 ExpandRotateKernelInfo(kernel, 90.0);
1750 case DiagonalsKernel:
1752 switch ( (
int) args->rho ) {
1757 kernel=ParseKernelArray(
"3: 0,0,0 0,-,1 1,1,-");
1760 kernel->type = type;
1761 new_kernel=ParseKernelArray(
"3: 0,0,1 0,-,1 0,1,-");
1763 return(DestroyKernelInfo(kernel));
1764 new_kernel->type = type;
1765 LastKernelInfo(kernel)->next = new_kernel;
1766 ExpandMirrorKernelInfo(kernel);
1770 kernel=ParseKernelArray(
"3: 0,0,0 0,-,1 1,1,-");
1773 kernel=ParseKernelArray(
"3: 0,0,1 0,-,1 0,1,-");
1778 kernel->type = type;
1779 RotateKernelInfo(kernel, args->sigma);
1782 case LineEndsKernel:
1784 switch ( (
int) args->rho ) {
1788 return(AcquireKernelInfo(
"LineEnds:1>;LineEnds:2>"));
1791 kernel=ParseKernelArray(
"3: 0,0,- 0,1,1 0,0,-");
1795 kernel=ParseKernelArray(
"3: 0,0,0 0,1,0 0,0,1");
1799 kernel=ParseKernelArray(
"3: 0,0,0 0,1,1 0,0,0");
1803 kernel=ParseKernelArray(
"3: 0,0,0 0,1,- 0,0,-");
1808 kernel->type = type;
1809 RotateKernelInfo(kernel, args->sigma);
1812 case LineJunctionsKernel:
1814 switch ( (
int) args->rho ) {
1818 return(AcquireKernelInfo(
"LineJunctions:1@;LineJunctions:2>"));
1821 kernel=ParseKernelArray(
"3: 1,-,1 -,1,- -,1,-");
1825 kernel=ParseKernelArray(
"3: 1,-,- -,1,- 1,-,1");
1829 kernel=ParseKernelArray(
"3: -,-,- 1,1,1 -,1,-");
1833 kernel=ParseKernelArray(
"3: 1,-,1 -,1,- 1,-,1");
1837 kernel=ParseKernelArray(
"3: -,1,- 1,1,1 -,1,-");
1842 kernel->type = type;
1843 RotateKernelInfo(kernel, args->sigma);
1850 switch ( (
int) args->rho ) {
1853 kernel=ParseKernelArray(
"3x1:0,1,0");
1856 kernel->type = type;
1857 ExpandRotateKernelInfo(kernel, 90.0);
1860 kernel=ParseKernelArray(
"4x1:0,1,1,0");
1863 kernel->type = type;
1864 ExpandRotateKernelInfo(kernel, 90.0);
1869 new_kernel=ParseKernelArray(
"4x3+1+1:0,1,1,- -,1,1,- -,1,1,0");
1871 return(DestroyKernelInfo(kernel));
1872 new_kernel->type = type;
1873 LastKernelInfo(kernel)->next = new_kernel;
1874 new_kernel=ParseKernelArray(
"4x3+2+1:0,1,1,- -,1,1,- -,1,1,0");
1876 return(DestroyKernelInfo(kernel));
1877 new_kernel->type = type;
1878 LastKernelInfo(kernel)->next = new_kernel;
1879 new_kernel=ParseKernelArray(
"4x3+1+1:-,1,1,0 -,1,1,- 0,1,1,-");
1881 return(DestroyKernelInfo(kernel));
1882 new_kernel->type = type;
1883 LastKernelInfo(kernel)->next = new_kernel;
1884 new_kernel=ParseKernelArray(
"4x3+2+1:-,1,1,0 -,1,1,- 0,1,1,-");
1886 return(DestroyKernelInfo(kernel));
1887 new_kernel->type = type;
1888 LastKernelInfo(kernel)->next = new_kernel;
1889 new_kernel=ParseKernelArray(
"3x4+1+1:0,-,- 1,1,1 1,1,1 -,-,0");
1891 return(DestroyKernelInfo(kernel));
1892 new_kernel->type = type;
1893 LastKernelInfo(kernel)->next = new_kernel;
1894 new_kernel=ParseKernelArray(
"3x4+1+2:0,-,- 1,1,1 1,1,1 -,-,0");
1896 return(DestroyKernelInfo(kernel));
1897 new_kernel->type = type;
1898 LastKernelInfo(kernel)->next = new_kernel;
1899 new_kernel=ParseKernelArray(
"3x4+1+1:-,-,0 1,1,1 1,1,1 0,-,-");
1901 return(DestroyKernelInfo(kernel));
1902 new_kernel->type = type;
1903 LastKernelInfo(kernel)->next = new_kernel;
1904 new_kernel=ParseKernelArray(
"3x4+1+2:-,-,0 1,1,1 1,1,1 0,-,-");
1906 return(DestroyKernelInfo(kernel));
1907 new_kernel->type = type;
1908 LastKernelInfo(kernel)->next = new_kernel;
1913 case ConvexHullKernel:
1918 kernel=ParseKernelArray(
"3: 1,1,- 1,0,- 1,-,0");
1921 kernel->type = type;
1922 ExpandRotateKernelInfo(kernel, 90.0);
1924 new_kernel=ParseKernelArray(
"3: 1,1,1 1,0,- -,-,0");
1926 return(DestroyKernelInfo(kernel));
1927 new_kernel->type = type;
1928 ExpandRotateKernelInfo(new_kernel, 90.0);
1929 LastKernelInfo(kernel)->next = new_kernel;
1932 case SkeletonKernel:
1934 switch ( (
int) args->rho ) {
1940 kernel=AcquireKernelInfo(
"ThinSE:482");
1943 kernel->type = type;
1944 ExpandRotateKernelInfo(kernel, 45.0);
1951 kernel=AcquireKernelInfo(
"ThinSE:482; ThinSE:87x90;");
1955 return(DestroyKernelInfo(kernel));
1956 kernel->type = type;
1957 kernel->next->type = type;
1958 ExpandRotateKernelInfo(kernel, 90.0);
1966 kernel=AcquireKernelInfo(
1967 "ThinSE:41; ThinSE:42; ThinSE:43");
1971 return(DestroyKernelInfo(kernel));
1972 if (kernel->next->next == (
KernelInfo *) NULL)
1973 return(DestroyKernelInfo(kernel));
1974 kernel->type = type;
1975 kernel->next->type = type;
1976 kernel->next->next->type = type;
1977 ExpandMirrorKernelInfo(kernel);
1993 switch ( (
int) args->rho ) {
1996 kernel=ParseKernelArray(
"3: -,-,1 0,-,1 -,-,1");
1999 kernel=ParseKernelArray(
"3: -,-,1 0,-,1 -,0,-");
2002 kernel=ParseKernelArray(
"3: -,0,- 0,-,1 -,-,1");
2005 kernel=ParseKernelArray(
"3: -,0,- 0,-,1 -,0,-");
2008 kernel=ParseKernelArray(
"3: -,0,1 0,-,1 -,0,-");
2011 kernel=ParseKernelArray(
"3: -,0,- 0,-,1 -,0,1");
2014 kernel=ParseKernelArray(
"3: -,1,1 0,-,1 -,0,-");
2017 kernel=ParseKernelArray(
"3: -,-,1 0,-,1 0,-,1");
2020 kernel=ParseKernelArray(
"3: 0,-,1 0,-,1 -,-,1");
2024 kernel=ParseKernelArray(
"3: -,1,- 0,-,1 -,1,-");
2027 kernel=ParseKernelArray(
"3: -,1,- 0,-,1 0,-,-");
2030 kernel=ParseKernelArray(
"3: 0,-,- 0,-,1 -,1,-");
2033 kernel=ParseKernelArray(
"3: 0,-,- 0,-,1 0,-,-");
2036 kernel=ParseKernelArray(
"3: 0,-,1 0,-,1 0,-,-");
2039 kernel=ParseKernelArray(
"3: 0,-,- 0,-,1 0,-,1");
2042 kernel=ParseKernelArray(
"3: -,1,- 0,-,1 0,0,-");
2045 kernel=ParseKernelArray(
"3: -,1,- 0,-,1 0,1,-");
2048 kernel=ParseKernelArray(
"3: 0,1,- 0,-,1 -,1,-");
2052 kernel=ParseKernelArray(
"3: -,-,1 0,-,- -,0,-");
2055 kernel=ParseKernelArray(
"3: -,1,- -,-,1 0,-,-");
2058 kernel=ParseKernelArray(
"3: -,1,1 0,-,1 0,0,-");
2062 kernel=ParseKernelArray(
"3: 0,-,1 0,-,1 0,-,1");
2067 kernel->type = type;
2068 RotateKernelInfo(kernel, args->sigma);
2074 case ChebyshevKernel:
2076 if (args->rho < 1.0)
2077 kernel->width = kernel->height = 3;
2079 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
2080 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
2082 if (AcquireKernelValues(kernel) == MagickFalse)
2083 return(DestroyKernelInfo(kernel));
2085 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
2086 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
2087 kernel->positive_range += ( kernel->values[i] =
2088 args->sigma*MagickMax(fabs((
double)u),fabs((
double)v)) );
2089 kernel->maximum = kernel->values[0];
2092 case ManhattanKernel:
2094 if (args->rho < 1.0)
2095 kernel->width = kernel->height = 3;
2097 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
2098 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
2100 if (AcquireKernelValues(kernel) == MagickFalse)
2101 return(DestroyKernelInfo(kernel));
2103 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
2104 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
2105 kernel->positive_range += ( kernel->values[i] =
2106 args->sigma*(labs((
long) u)+labs((
long) v)) );
2107 kernel->maximum = kernel->values[0];
2110 case OctagonalKernel:
2112 if (args->rho < 2.0)
2113 kernel->width = kernel->height = 5;
2115 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
2116 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
2118 if (AcquireKernelValues(kernel) == MagickFalse)
2119 return(DestroyKernelInfo(kernel));
2121 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
2122 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
2125 r1 = MagickMax(fabs((
double)u),fabs((
double)v)),
2126 r2 = floor((
double)(labs((
long)u)+labs((
long)v)+1)/1.5);
2127 kernel->positive_range += kernel->values[i] =
2128 args->sigma*MagickMax(r1,r2);
2130 kernel->maximum = kernel->values[0];
2133 case EuclideanKernel:
2135 if (args->rho < 1.0)
2136 kernel->width = kernel->height = 3;
2138 kernel->width = kernel->height = CastDoubleToSizeT(args->rho)*2+1;
2139 kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
2141 if (AcquireKernelValues(kernel) == MagickFalse)
2142 return(DestroyKernelInfo(kernel));
2144 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
2145 for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
2146 kernel->positive_range += ( kernel->values[i] =
2147 args->sigma*sqrt((
double) (u*u+v*v)) );
2148 kernel->maximum = kernel->values[0];
2154 kernel=ParseKernelArray(
"1:1");
2157 kernel->type = UndefinedKernel;
2199 new_kernel=(
KernelInfo *) AcquireMagickMemory(
sizeof(*kernel));
2202 *new_kernel=(*kernel);
2205 if (AcquireKernelValues(new_kernel) == MagickFalse)
2206 return(DestroyKernelInfo(new_kernel));
2207 for (i=0; i < (ssize_t) (kernel->width*kernel->height); i++)
2208 new_kernel->values[i]=kernel->values[i];
2212 new_kernel->next = CloneKernelInfo(kernel->next);
2213 if ( new_kernel->next == (
KernelInfo *) NULL )
2214 return(DestroyKernelInfo(new_kernel));
2248 kernel->next=DestroyKernelInfo(kernel->next);
2249 kernel->values=(
double *) RelinquishAlignedMemory(kernel->values);
2250 kernel=(
KernelInfo *) RelinquishMagickMemory(kernel);
2286 static void FlopKernelInfo(
KernelInfo *kernel)
2295 for ( y=0, k=kernel->values; y < kernel->height; y++, k+=kernel->width)
2296 for ( x=0, r=kernel->width-1; x<kernel->width/2; x++, r--)
2297 t=k[x], k[x]=k[r], k[r]=t;
2299 kernel->x = kernel->width - kernel->x - 1;
2300 angle = fmod(angle+180.0, 360.0);
2304 static void ExpandMirrorKernelInfo(
KernelInfo *kernel)
2312 clone = CloneKernelInfo(last);
2315 RotateKernelInfo(clone, 180);
2316 LastKernelInfo(last)->next = clone;
2319 clone = CloneKernelInfo(last);
2322 RotateKernelInfo(clone, 90);
2323 LastKernelInfo(last)->next = clone;
2326 clone = CloneKernelInfo(last);
2329 RotateKernelInfo(clone, 180);
2330 LastKernelInfo(last)->next = clone;
2369 static MagickBooleanType SameKernelInfo(
const KernelInfo *kernel1,
2376 if ( kernel1->width != kernel2->width
2377 || kernel1->height != kernel2->height
2378 || kernel1->x != kernel2->x
2379 || kernel1->y != kernel2->y )
2383 for (i=0; i < (kernel1->width*kernel1->height); i++) {
2385 if ( IsNaN(kernel1->values[i]) && !IsNaN(kernel2->values[i]) )
2387 if ( IsNaN(kernel2->values[i]) && !IsNaN(kernel1->values[i]) )
2390 if ( fabs(kernel1->values[i] - kernel2->values[i]) >= MagickEpsilon )
2397 static void ExpandRotateKernelInfo(
KernelInfo *kernel,
const double angle)
2405 DisableMSCWarning(4127)
2408 clone_info=CloneKernelInfo(last);
2411 RotateKernelInfo(clone_info,angle);
2412 if (SameKernelInfo(kernel,clone_info) != MagickFalse)
2414 LastKernelInfo(last)->next=clone_info;
2418 clone_info=DestroyKernelInfo(clone_info);
2459 static void CalcKernelMetaData(
KernelInfo *kernel)
2464 kernel->minimum = kernel->maximum = 0.0;
2465 kernel->negative_range = kernel->positive_range = 0.0;
2466 for (i=0; i < (kernel->width*kernel->height); i++)
2468 if ( fabs(kernel->values[i]) < MagickEpsilon )
2469 kernel->values[i] = 0.0;
2470 ( kernel->values[i] < 0)
2471 ? ( kernel->negative_range += kernel->values[i] )
2472 : ( kernel->positive_range += kernel->values[i] );
2473 Minimize(kernel->minimum, kernel->values[i]);
2474 Maximize(kernel->maximum, kernel->values[i]);
2551 static ssize_t MorphologyPrimitive(
const Image *image,
Image *result_image,
2552 const MorphologyMethod method,
const ChannelType channel,
2555 #define MorphologyTag "Morphology/Image" 2580 assert(image != (
Image *) NULL);
2581 assert(image->signature == MagickCoreSignature);
2582 assert(result_image != (
Image *) NULL);
2583 assert(result_image->signature == MagickCoreSignature);
2585 assert(kernel->signature == MagickCoreSignature);
2587 assert(exception->signature == MagickCoreSignature);
2592 p_view=AcquireVirtualCacheView(image,exception);
2593 q_view=AcquireAuthenticCacheView(result_image,exception);
2594 virt_width=image->columns+kernel->width-1;
2602 case ConvolveMorphology:
2603 case DilateMorphology:
2604 case DilateIntensityMorphology:
2605 case IterativeDistanceMorphology:
2607 offx = (ssize_t) kernel->width-offx-1;
2608 offy = (ssize_t) kernel->height-offy-1;
2610 case ErodeMorphology:
2611 case ErodeIntensityMorphology:
2612 case HitAndMissMorphology:
2613 case ThinningMorphology:
2614 case ThickenMorphology:
2618 assert(
"Not a Primitive Morphology Method" != (
char *) NULL);
2622 changes=(
size_t *) AcquireQuantumMemory(GetOpenMPMaximumThreads(),
2624 if (changes == (
size_t *) NULL)
2625 ThrowFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed");
2626 for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
2628 if ( method == ConvolveMorphology && kernel->width == 1 )
2647 #if defined(MAGICKCORE_OPENMP_SUPPORT) 2648 #pragma omp parallel for schedule(static) shared(progress,status) \ 2649 magick_number_threads(image,result_image,image->columns,1) 2651 for (x=0; x < (ssize_t) image->columns; x++)
2654 id = GetOpenMPThreadId();
2660 *magick_restrict p_indexes;
2666 *magick_restrict q_indexes;
2674 if (status == MagickFalse)
2676 p=GetCacheViewVirtualPixels(p_view,x,-offy,1,image->rows+kernel->height-1,
2678 q=GetCacheViewAuthenticPixels(q_view,x,0,1,result_image->rows,exception);
2684 p_indexes=GetCacheViewVirtualIndexQueue(p_view);
2685 q_indexes=GetCacheViewAuthenticIndexQueue(q_view);
2690 for (y=0; y < (ssize_t) image->rows; y++)
2702 *magick_restrict k_pixels;
2705 *magick_restrict k_indexes;
2711 if (image->colorspace == CMYKColorspace)
2712 SetPixelIndex(q_indexes+y,GetPixelIndex(p_indexes+y+r));
2719 result.index = bias;
2728 k = &kernel->values[ kernel->height-1 ];
2730 k_indexes = p_indexes+y;
2731 if ( ((channel & SyncChannels) == 0 ) ||
2732 (image->matte == MagickFalse) )
2736 for (v=0; v < (ssize_t) kernel->height; v++) {
2737 if ( IsNaN(*k) )
continue;
2738 result.red += (*k)*(double) GetPixelRed(k_pixels);
2739 result.green += (*k)*(double) GetPixelGreen(k_pixels);
2740 result.blue += (*k)*(double) GetPixelBlue(k_pixels);
2741 result.opacity += (*k)*(double) GetPixelOpacity(k_pixels);
2742 if ( image->colorspace == CMYKColorspace)
2743 result.index += (*k)*(double) (*k_indexes);
2748 if ((channel & RedChannel) != 0)
2749 SetPixelRed(q,ClampToQuantum(result.red));
2750 if ((channel & GreenChannel) != 0)
2751 SetPixelGreen(q,ClampToQuantum(result.green));
2752 if ((channel & BlueChannel) != 0)
2753 SetPixelBlue(q,ClampToQuantum(result.blue));
2754 if (((channel & OpacityChannel) != 0) &&
2755 (image->matte != MagickFalse))
2756 SetPixelOpacity(q,ClampToQuantum(result.opacity));
2757 if (((channel & IndexChannel) != 0) &&
2758 (image->colorspace == CMYKColorspace))
2759 SetPixelIndex(q_indexes+y,ClampToQuantum(result.index));
2777 for (v=0; v < (ssize_t) kernel->height; v++) {
2778 if ( IsNaN(*k) )
continue;
2779 alpha=QuantumScale*((double) QuantumRange-(
double)
2780 GetPixelOpacity(k_pixels));
2784 result.red += alpha*(double) GetPixelRed(k_pixels);
2785 result.green += alpha*(double) GetPixelGreen(k_pixels);
2786 result.blue += alpha*(double) GetPixelBlue(k_pixels);
2787 result.opacity += (*k)*(double) GetPixelOpacity(k_pixels);
2788 if ( image->colorspace == CMYKColorspace)
2789 result.index += alpha*(double) (*k_indexes);
2795 gamma=MagickSafeReciprocal(gamma);
2797 gamma*=(double) kernel->height/count;
2798 SetPixelRed(q,ClampToQuantum(gamma*result.red));
2799 SetPixelGreen(q,ClampToQuantum(gamma*result.green));
2800 SetPixelBlue(q,ClampToQuantum(gamma*result.blue));
2801 SetPixelOpacity(q,ClampToQuantum(result.opacity));
2802 if (image->colorspace == CMYKColorspace)
2803 SetPixelIndex(q_indexes+y,ClampToQuantum(gamma*result.index));
2807 if ( ( p[r].red != GetPixelRed(q))
2808 || ( p[r].green != GetPixelGreen(q))
2809 || ( p[r].blue != GetPixelBlue(q))
2810 || ( (image->matte != MagickFalse) &&
2811 (p[r].opacity != GetPixelOpacity(q)))
2812 || ( (image->colorspace == CMYKColorspace) &&
2813 (GetPixelIndex(p_indexes+y+r) != GetPixelIndex(q_indexes+y))) )
2818 if ( SyncCacheViewAuthenticPixels(q_view,exception) == MagickFalse)
2820 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2825 #if defined(MAGICKCORE_OPENMP_SUPPORT) 2829 proceed=SetImageProgress(image,MorphologyTag,progress,image->columns);
2830 if (proceed == MagickFalse)
2834 result_image->type=image->type;
2835 q_view=DestroyCacheView(q_view);
2836 p_view=DestroyCacheView(p_view);
2837 for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
2838 changed+=changes[i];
2839 changes=(
size_t *) RelinquishMagickMemory(changes);
2840 return(status ? (ssize_t) changed : 0);
2846 #if defined(MAGICKCORE_OPENMP_SUPPORT) 2847 #pragma omp parallel for schedule(static) shared(progress,status) \ 2848 magick_number_threads(image,result_image,image->rows,1) 2850 for (y=0; y < (ssize_t) image->rows; y++)
2853 id = GetOpenMPThreadId();
2859 *magick_restrict p_indexes;
2865 *magick_restrict q_indexes;
2873 if (status == MagickFalse)
2875 p=GetCacheViewVirtualPixels(p_view, -offx, y-offy, virt_width,
2876 kernel->height, exception);
2877 q=GetCacheViewAuthenticPixels(q_view,0,y,result_image->columns,1,
2884 p_indexes=GetCacheViewVirtualIndexQueue(p_view);
2885 q_indexes=GetCacheViewAuthenticIndexQueue(q_view);
2888 r = virt_width*offy + offx;
2890 for (x=0; x < (ssize_t) image->columns; x++)
2902 *magick_restrict k_pixels;
2905 *magick_restrict k_indexes;
2916 if (image->colorspace == CMYKColorspace)
2917 SetPixelIndex(q_indexes+x,GetPixelIndex(p_indexes+x+r));
2924 min.index = (double) QuantumRange;
2931 result.red = (double) p[r].red;
2932 result.green = (double) p[r].green;
2933 result.blue = (double) p[r].blue;
2934 result.opacity = (double) QuantumRange - (
double) p[r].opacity;
2936 if ( image->colorspace == CMYKColorspace)
2937 result.index = (double) GetPixelIndex(p_indexes+x+r);
2940 case ConvolveMorphology:
2946 result.index = bias;
2948 case DilateIntensityMorphology:
2949 case ErodeIntensityMorphology:
2958 case ConvolveMorphology:
2977 k = &kernel->values[ kernel->width*kernel->height-1 ];
2979 k_indexes = p_indexes+x;
2980 if ( ((channel & SyncChannels) == 0 ) ||
2981 (image->matte == MagickFalse) )
2985 for (v=0; v < (ssize_t) kernel->height; v++) {
2986 for (u=0; u < (ssize_t) kernel->width; u++, k--) {
2987 if ( IsNaN(*k) )
continue;
2988 result.red += (*k)*(double) k_pixels[u].red;
2989 result.green += (*k)*(double) k_pixels[u].green;
2990 result.blue += (*k)*(double) k_pixels[u].blue;
2991 result.opacity += (*k)*(double) k_pixels[u].opacity;
2992 if ( image->colorspace == CMYKColorspace)
2993 result.index += (*k)*(double) GetPixelIndex(k_indexes+u);
2995 k_pixels += virt_width;
2996 k_indexes += virt_width;
2998 if ((channel & RedChannel) != 0)
2999 SetPixelRed(q,ClampToQuantum((MagickRealType) result.red));
3000 if ((channel & GreenChannel) != 0)
3001 SetPixelGreen(q,ClampToQuantum((MagickRealType) result.green));
3002 if ((channel & BlueChannel) != 0)
3003 SetPixelBlue(q,ClampToQuantum((MagickRealType) result.blue));
3004 if (((channel & OpacityChannel) != 0) &&
3005 (image->matte != MagickFalse))
3006 SetPixelOpacity(q,ClampToQuantum((MagickRealType) result.opacity));
3007 if (((channel & IndexChannel) != 0) &&
3008 (image->colorspace == CMYKColorspace))
3009 SetPixelIndex(q_indexes+x,ClampToQuantum(result.index));
3025 for (v=0; v < (ssize_t) kernel->height; v++) {
3026 for (u=0; u < (ssize_t) kernel->width; u++, k--) {
3027 if ( IsNaN(*k) )
continue;
3028 alpha=QuantumScale*((double) QuantumRange-(
double)
3029 k_pixels[u].opacity);
3033 result.red += alpha*(double) k_pixels[u].red;
3034 result.green += alpha*(double) k_pixels[u].green;
3035 result.blue += alpha*(double) k_pixels[u].blue;
3036 result.opacity += (*k)*(double) k_pixels[u].opacity;
3037 if ( image->colorspace == CMYKColorspace)
3038 result.index+=alpha*(double) GetPixelIndex(k_indexes+u);
3040 k_pixels += virt_width;
3041 k_indexes += virt_width;
3044 gamma=MagickSafeReciprocal(gamma);
3046 gamma*=(double) kernel->height*kernel->width/count;
3047 SetPixelRed(q,ClampToQuantum((MagickRealType) (gamma*result.red)));
3048 SetPixelGreen(q,ClampToQuantum((MagickRealType) (gamma*result.green)));
3049 SetPixelBlue(q,ClampToQuantum((MagickRealType) (gamma*result.blue)));
3050 SetPixelOpacity(q,ClampToQuantum(result.opacity));
3051 if (image->colorspace == CMYKColorspace)
3052 SetPixelIndex(q_indexes+x,ClampToQuantum((MagickRealType) (gamma*
3057 case ErodeMorphology:
3068 k_indexes = p_indexes+x;
3069 for (v=0; v < (ssize_t) kernel->height; v++) {
3070 for (u=0; u < (ssize_t) kernel->width; u++, k++) {
3071 if ( IsNaN(*k) || (*k) < 0.5 )
continue;
3072 Minimize(min.red, (
double) k_pixels[u].red);
3073 Minimize(min.green, (
double) k_pixels[u].green);
3074 Minimize(min.blue, (
double) k_pixels[u].blue);
3075 Minimize(min.opacity,(
double) QuantumRange-(
double)
3076 k_pixels[u].opacity);
3077 if ( image->colorspace == CMYKColorspace)
3078 Minimize(min.index,(
double) GetPixelIndex(k_indexes+u));
3080 k_pixels += virt_width;
3081 k_indexes += virt_width;
3085 case DilateMorphology:
3097 k = &kernel->values[ kernel->width*kernel->height-1 ];
3099 k_indexes = p_indexes+x;
3100 for (v=0; v < (ssize_t) kernel->height; v++) {
3101 for (u=0; u < (ssize_t) kernel->width; u++, k--) {
3102 if ( IsNaN(*k) || (*k) < 0.5 )
continue;
3103 Maximize(max.red, (
double) k_pixels[u].red);
3104 Maximize(max.green, (
double) k_pixels[u].green);
3105 Maximize(max.blue, (
double) k_pixels[u].blue);
3106 Maximize(max.opacity,(
double) QuantumRange-(
double)
3107 k_pixels[u].opacity);
3108 if ( image->colorspace == CMYKColorspace)
3109 Maximize(max.index, (
double) GetPixelIndex(
3112 k_pixels += virt_width;
3113 k_indexes += virt_width;
3117 case HitAndMissMorphology:
3118 case ThinningMorphology:
3119 case ThickenMorphology:
3133 k_indexes = p_indexes+x;
3134 for (v=0; v < (ssize_t) kernel->height; v++) {
3135 for (u=0; u < (ssize_t) kernel->width; u++, k++) {
3136 if ( IsNaN(*k) )
continue;
3139 Minimize(min.red, (
double) k_pixels[u].red);
3140 Minimize(min.green, (
double) k_pixels[u].green);
3141 Minimize(min.blue, (
double) k_pixels[u].blue);
3142 Minimize(min.opacity, (
double) QuantumRange-(
double)
3143 k_pixels[u].opacity);
3144 if ( image->colorspace == CMYKColorspace)
3145 Minimize(min.index,(
double) GetPixelIndex(
3148 else if ( (*k) < 0.3 )
3150 Maximize(max.red, (
double) k_pixels[u].red);
3151 Maximize(max.green, (
double) k_pixels[u].green);
3152 Maximize(max.blue, (
double) k_pixels[u].blue);
3153 Maximize(max.opacity,(
double) QuantumRange-(
double)
3154 k_pixels[u].opacity);
3155 if ( image->colorspace == CMYKColorspace)
3156 Maximize(max.index, (
double) GetPixelIndex(
3160 k_pixels += virt_width;
3161 k_indexes += virt_width;
3164 min.red -= max.red; Maximize( min.red, 0.0 );
3165 min.green -= max.green; Maximize( min.green, 0.0 );
3166 min.blue -= max.blue; Maximize( min.blue, 0.0 );
3167 min.opacity -= max.opacity; Maximize( min.opacity, 0.0 );
3168 min.index -= max.index; Maximize( min.index, 0.0 );
3171 case ErodeIntensityMorphology:
3182 k_indexes = p_indexes+x;
3183 for (v=0; v < (ssize_t) kernel->height; v++) {
3184 for (u=0; u < (ssize_t) kernel->width; u++, k++) {
3185 if ( IsNaN(*k) || (*k) < 0.5 )
continue;
3186 if ( result.red == 0.0 ||
3187 GetPixelIntensity(image,&(k_pixels[u])) < GetPixelIntensity(result_image,q) ) {
3191 if ( result.red > 0.0 ) changes[id]++;
3195 k_pixels += virt_width;
3196 k_indexes += virt_width;
3200 case DilateIntensityMorphology:
3211 k = &kernel->values[ kernel->width*kernel->height-1 ];
3213 k_indexes = p_indexes+x;
3214 for (v=0; v < (ssize_t) kernel->height; v++) {
3215 for (u=0; u < (ssize_t) kernel->width; u++, k--) {
3216 if ( IsNaN(*k) || (*k) < 0.5 )
continue;
3217 if ( result.red == 0.0 ||
3218 GetPixelIntensity(image,&(k_pixels[u])) > GetPixelIntensity(result_image,q) ) {
3221 if ( result.red > 0.0 ) changes[id]++;
3225 k_pixels += virt_width;
3226 k_indexes += virt_width;
3230 case IterativeDistanceMorphology:
3254 k = &kernel->values[ kernel->width*kernel->height-1 ];
3256 k_indexes = p_indexes+x;
3257 for (v=0; v < (ssize_t) kernel->height; v++) {
3258 for (u=0; u < (ssize_t) kernel->width; u++, k--) {
3259 if ( IsNaN(*k) )
continue;
3260 Minimize(result.red, (*k)+(
double) k_pixels[u].red);
3261 Minimize(result.green, (*k)+(
double) k_pixels[u].green);
3262 Minimize(result.blue, (*k)+(
double) k_pixels[u].blue);
3263 Minimize(result.opacity, (*k)+(
double) QuantumRange-(
double)
3264 k_pixels[u].opacity);
3265 if ( image->colorspace == CMYKColorspace)
3266 Minimize(result.index,(*k)+(
double) GetPixelIndex(k_indexes+u));
3268 k_pixels += virt_width;
3269 k_indexes += virt_width;
3273 case UndefinedMorphology:
3285 case HitAndMissMorphology:
3286 case ErodeMorphology:
3289 case DilateMorphology:
3292 case ThinningMorphology:
3294 result.red -= min.red;
3295 result.green -= min.green;
3296 result.blue -= min.blue;
3297 result.opacity -= min.opacity;
3298 result.index -= min.index;
3300 case ThickenMorphology:
3302 result.red += min.red;
3303 result.green += min.green;
3304 result.blue += min.blue;
3305 result.opacity += min.opacity;
3306 result.index += min.index;
3314 case UndefinedMorphology:
3315 case ConvolveMorphology:
3316 case DilateIntensityMorphology:
3317 case ErodeIntensityMorphology:
3320 if ((channel & RedChannel) != 0)
3321 SetPixelRed(q,ClampToQuantum(result.red));
3322 if ((channel & GreenChannel) != 0)
3323 SetPixelGreen(q,ClampToQuantum(result.green));
3324 if ((channel & BlueChannel) != 0)
3325 SetPixelBlue(q,ClampToQuantum(result.blue));
3326 if ((channel & OpacityChannel) != 0
3327 && image->matte != MagickFalse )
3328 SetPixelAlpha(q,ClampToQuantum(result.opacity));
3329 if (((channel & IndexChannel) != 0) &&
3330 (image->colorspace == CMYKColorspace))
3331 SetPixelIndex(q_indexes+x,ClampToQuantum(result.index));
3335 if ( ( p[r].red != GetPixelRed(q) )
3336 || ( p[r].green != GetPixelGreen(q) )
3337 || ( p[r].blue != GetPixelBlue(q) )
3338 || ( (image->matte != MagickFalse) &&
3339 (p[r].opacity != GetPixelOpacity(q)))
3340 || ( (image->colorspace == CMYKColorspace) &&
3341 (GetPixelIndex(p_indexes+x+r) != GetPixelIndex(q_indexes+x))) )
3346 if ( SyncCacheViewAuthenticPixels(q_view,exception) == MagickFalse)
3348 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3353 #if defined(MAGICKCORE_OPENMP_SUPPORT) 3357 proceed=SetImageProgress(image,MorphologyTag,progress,image->rows);
3358 if (proceed == MagickFalse)
3362 q_view=DestroyCacheView(q_view);
3363 p_view=DestroyCacheView(p_view);
3364 for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
3365 changed+=changes[i];
3366 changes=(
size_t *) RelinquishMagickMemory(changes);
3367 return(status ? (ssize_t)changed : -1);
3382 static ssize_t MorphologyPrimitiveDirect(
Image *image,
3383 const MorphologyMethod method,
const ChannelType channel,
3407 assert(image != (
Image *) NULL);
3408 assert(image->signature == MagickCoreSignature);
3410 assert(kernel->signature == MagickCoreSignature);
3412 assert(exception->signature == MagickCoreSignature);
3420 case DistanceMorphology:
3421 case VoronoiMorphology:
3423 offx = (ssize_t) kernel->width-offx-1;
3424 offy = (ssize_t) kernel->height-offy-1;
3427 case ?????Morphology:
3432 assert(
"Not a PrimativeDirect Morphology Method" != (
char *) NULL);
3438 virt_view=AcquireVirtualCacheView(image,exception);
3439 auth_view=AcquireAuthenticCacheView(image,exception);
3440 virt_width=image->columns+kernel->width-1;
3442 for (y=0; y < (ssize_t) image->rows; y++)
3448 *magick_restrict p_indexes;
3454 *magick_restrict q_indexes;
3469 if (status == MagickFalse)
3471 p=GetCacheViewVirtualPixels(virt_view, -offx, y-offy, virt_width, (
size_t) offy+1,
3473 q=GetCacheViewAuthenticPixels(auth_view, 0, y, image->columns, 1,
3477 if (status == MagickFalse)
3479 p_indexes=GetCacheViewVirtualIndexQueue(virt_view);
3480 q_indexes=GetCacheViewAuthenticIndexQueue(auth_view);
3483 r = (ssize_t) virt_width*offy + offx;
3485 for (x=0; x < (ssize_t) image->columns; x++)
3497 *magick_restrict k_pixels;
3500 *magick_restrict k_indexes;
3506 GetMagickPixelPacket(image,&result);
3507 SetMagickPixelPacket(image,q,q_indexes,&result);
3508 if ( method != VoronoiMorphology )
3509 result.opacity = (MagickRealType) QuantumRange - (MagickRealType)
3513 case DistanceMorphology:
3515 k = &kernel->values[ kernel->width*kernel->height-1 ];
3517 k_indexes = p_indexes+x;
3518 for (v=0; v <= (ssize_t) offy; v++) {
3519 for (u=0; u < (ssize_t) kernel->width; u++, k--) {
3520 if ( IsNaN(*k) )
continue;
3521 Minimize(result.red, (*k)+(
double) k_pixels[u].red);
3522 Minimize(result.green, (*k)+(
double) k_pixels[u].green);
3523 Minimize(result.blue, (*k)+(
double) k_pixels[u].blue);
3524 Minimize(result.opacity, (*k)+(
double) QuantumRange-(
double)
3525 k_pixels[u].opacity);
3526 if ( image->colorspace == CMYKColorspace)
3527 Minimize(result.index, (*k)+(
double)
3528 GetPixelIndex(k_indexes+u));
3530 k_pixels += virt_width;
3531 k_indexes += virt_width;
3534 k = &kernel->values[ kernel->width*(kernel->y+1)-1 ];
3536 k_indexes = q_indexes-offx;
3537 for (u=0; u < (ssize_t) offx; u++, k--) {
3538 if ( x+u-offx < 0 )
continue;
3539 if ( IsNaN(*k) )
continue;
3540 Minimize(result.red, (*k)+(
double) k_pixels[u].red);
3541 Minimize(result.green, (*k)+(
double) k_pixels[u].green);
3542 Minimize(result.blue, (*k)+(
double) k_pixels[u].blue);
3543 Minimize(result.opacity, (*k)+(
double) QuantumRange-(
double)
3544 k_pixels[u].opacity);
3545 if ( image->colorspace == CMYKColorspace)
3546 Minimize(result.index, (*k)+(
double)
3547 GetPixelIndex(k_indexes+u));
3550 case VoronoiMorphology:
3558 k = &kernel->values[ kernel->width*kernel->height-1 ];
3560 k_indexes = p_indexes+x;
3561 for (v=0; v <= (ssize_t) offy; v++) {
3562 for (u=0; u < (ssize_t) kernel->width; u++, k--) {
3563 if ( IsNaN(*k) )
continue;
3564 if( result.opacity > (*k)+(double) k_pixels[u].opacity )
3566 SetMagickPixelPacket(image,&k_pixels[u],&k_indexes[u],
3568 result.opacity += *k;
3571 k_pixels += virt_width;
3572 k_indexes += virt_width;
3575 k = &kernel->values[ kernel->width*(kernel->y+1)-1 ];
3577 k_indexes = q_indexes-offx;
3578 for (u=0; u < (ssize_t) offx; u++, k--) {
3579 if ( x+u-offx < 0 )
continue;
3580 if ( IsNaN(*k) )
continue;
3581 if( result.opacity > (*k)+(double) k_pixels[u].opacity )
3583 SetMagickPixelPacket(image,&k_pixels[u],&k_indexes[u],
3585 result.opacity += *k;
3595 case VoronoiMorphology:
3596 SetPixelPacket(image,&result,q,q_indexes);
3599 if ((channel & RedChannel) != 0)
3600 SetPixelRed(q,ClampToQuantum(result.red));
3601 if ((channel & GreenChannel) != 0)
3602 SetPixelGreen(q,ClampToQuantum(result.green));
3603 if ((channel & BlueChannel) != 0)
3604 SetPixelBlue(q,ClampToQuantum(result.blue));
3605 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
3606 SetPixelAlpha(q,ClampToQuantum(result.opacity));
3607 if (((channel & IndexChannel) != 0) &&
3608 (image->colorspace == CMYKColorspace))
3609 SetPixelIndex(q_indexes+x,ClampToQuantum(result.index));
3613 if ( ( p[r].red != GetPixelRed(q) )
3614 || ( p[r].green != GetPixelGreen(q) )
3615 || ( p[r].blue != GetPixelBlue(q) )
3616 || ( (image->matte != MagickFalse) &&
3617 (p[r].opacity != GetPixelOpacity(q)))
3618 || ( (image->colorspace == CMYKColorspace) &&
3619 (GetPixelIndex(p_indexes+x+r) != GetPixelIndex(q_indexes+x))) )
3626 if ( SyncCacheViewAuthenticPixels(auth_view,exception) == MagickFalse)
3628 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3630 #if defined(MAGICKCORE_OPENMP_SUPPORT) 3634 if (SetImageProgress(image,MorphologyTag,progress,image->rows) == MagickFalse )
3641 for (y=(ssize_t)image->rows-1; y >= 0; y--)
3647 *magick_restrict p_indexes;
3653 *magick_restrict q_indexes;
3661 if (status == MagickFalse)
3670 p=GetCacheViewVirtualPixels(virt_view, -offx, y, virt_width, (
size_t) kernel->y+1,
3672 q=GetCacheViewAuthenticPixels(auth_view, 0, y, image->columns, 1,
3676 if (status == MagickFalse)
3678 p_indexes=GetCacheViewVirtualIndexQueue(virt_view);
3679 q_indexes=GetCacheViewAuthenticIndexQueue(auth_view);
3682 p += image->columns-1;
3683 q += image->columns-1;
3688 for (x=(ssize_t)image->columns-1; x >= 0; x--)
3694 *magick_restrict k_pixels;
3697 *magick_restrict k_indexes;
3707 GetMagickPixelPacket(image,&result);
3708 SetMagickPixelPacket(image,q,q_indexes,&result);
3709 if ( method != VoronoiMorphology )
3710 result.opacity = (double) QuantumRange - (
double) result.opacity;
3713 case DistanceMorphology:
3715 k = &kernel->values[ kernel->width*(kernel->y+1)-1 ];
3717 k_indexes = p_indexes+x;
3718 for (v=offy; v < (ssize_t) kernel->height; v++) {
3719 for (u=0; u < (ssize_t) kernel->width; u++, k--) {
3720 if ( IsNaN(*k) )
continue;
3721 Minimize(result.red, (*k)+(
double) k_pixels[u].red);
3722 Minimize(result.green, (*k)+(
double) k_pixels[u].green);
3723 Minimize(result.blue, (*k)+(
double) k_pixels[u].blue);
3724 Minimize(result.opacity, (*k)+(
double) QuantumRange-(
double)
3725 k_pixels[u].opacity);
3726 if ( image->colorspace == CMYKColorspace)
3727 Minimize(result.index,(*k)+(
double)
3728 GetPixelIndex(k_indexes+u));
3730 k_pixels += virt_width;
3731 k_indexes += virt_width;
3734 k = &kernel->values[ kernel->width*(kernel->y)+kernel->x-1 ];
3736 k_indexes = q_indexes-offx;
3737 for (u=offx+1; u < (ssize_t) kernel->width; u++, k--) {
3738 if ( (x+u-offx) >= (ssize_t)image->columns )
continue;
3739 if ( IsNaN(*k) )
continue;
3740 Minimize(result.red, (*k)+(
double) k_pixels[u].red);
3741 Minimize(result.green, (*k)+(
double) k_pixels[u].green);
3742 Minimize(result.blue, (*k)+(
double) k_pixels[u].blue);
3743 Minimize(result.opacity, (*k)+(
double) QuantumRange-(
double)
3744 k_pixels[u].opacity);
3745 if ( image->colorspace == CMYKColorspace)
3746 Minimize(result.index, (*k)+(
double)
3747 GetPixelIndex(k_indexes+u));
3750 case VoronoiMorphology:
3756 k = &kernel->values[ kernel->width*(kernel->y+1)-1 ];
3758 k_indexes = p_indexes+x;
3759 for (v=offy; v < (ssize_t) kernel->height; v++) {
3760 for (u=0; u < (ssize_t) kernel->width; u++, k--) {
3761 if ( IsNaN(*k) )
continue;
3762 if( result.opacity > (*k)+(double) k_pixels[u].opacity )
3764 SetMagickPixelPacket(image,&k_pixels[u],&k_indexes[u],
3766 result.opacity += *k;
3769 k_pixels += virt_width;
3770 k_indexes += virt_width;
3773 k = &kernel->values[ kernel->width*(kernel->y)+kernel->x-1 ];
3775 k_indexes = q_indexes-offx;
3776 for (u=offx+1; u < (ssize_t) kernel->width; u++, k--) {
3777 if ( (x+u-offx) >= (ssize_t)image->columns )
continue;
3778 if ( IsNaN(*k) )
continue;
3779 if( result.opacity > (*k)+(double) k_pixels[u].opacity )
3781 SetMagickPixelPacket(image,&k_pixels[u],&k_indexes[u],
3783 result.opacity += *k;
3793 case VoronoiMorphology:
3794 SetPixelPacket(image,&result,q,q_indexes);
3797 if ((channel & RedChannel) != 0)
3798 SetPixelRed(q,ClampToQuantum(result.red));
3799 if ((channel & GreenChannel) != 0)
3800 SetPixelGreen(q,ClampToQuantum(result.green));
3801 if ((channel & BlueChannel) != 0)
3802 SetPixelBlue(q,ClampToQuantum(result.blue));
3803 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
3804 SetPixelAlpha(q,ClampToQuantum(result.opacity));
3805 if (((channel & IndexChannel) != 0) &&
3806 (image->colorspace == CMYKColorspace))
3807 SetPixelIndex(q_indexes+x,ClampToQuantum(result.index));
3811 if ( ( p[r].red != GetPixelRed(q) )
3812 || ( p[r].green != GetPixelGreen(q) )
3813 || ( p[r].blue != GetPixelBlue(q) )
3814 || ( (image->matte != MagickFalse) &&
3815 (p[r].opacity != GetPixelOpacity(q)))
3816 || ( (image->colorspace == CMYKColorspace) &&
3817 (GetPixelIndex(p_indexes+x+r) != GetPixelIndex(q_indexes+x))) )
3823 if ( SyncCacheViewAuthenticPixels(auth_view,exception) == MagickFalse)
3825 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3827 #if defined(MAGICKCORE_OPENMP_SUPPORT) 3831 if ( SetImageProgress(image,MorphologyTag,progress,image->rows) == MagickFalse )
3837 auth_view=DestroyCacheView(auth_view);
3838 virt_view=DestroyCacheView(virt_view);
3839 return(status ? (ssize_t) changed : -1);
3850 MagickExport
Image *MorphologyApply(
const Image *image,
const ChannelType
3851 channel,
const MorphologyMethod method,
const ssize_t iterations,
3852 const KernelInfo *kernel,
const CompositeOperator compose,
3896 v_info[MaxTextExtent];
3898 assert(image != (
Image *) NULL);
3899 assert(image->signature == MagickCoreSignature);
3901 assert(kernel->signature == MagickCoreSignature);
3903 assert(exception->signature == MagickCoreSignature);
3906 if ( iterations == 0 )
3907 return((
Image *) NULL);
3909 kernel_limit = (size_t) iterations;
3910 if ( iterations < 0 )
3911 kernel_limit = image->columns>image->rows ? image->columns : image->rows;
3913 verbose = IsMagickTrue(GetImageArtifact(image,
"debug"));
3916 curr_image = (
Image *) image;
3917 curr_compose = image->compose;
3918 (void) curr_compose;
3919 work_image = save_image = rslt_image = (
Image *) NULL;
3929 special = MagickFalse;
3930 rslt_compose = compose;
3932 case SmoothMorphology:
3935 case OpenMorphology:
3936 case OpenIntensityMorphology:
3937 case TopHatMorphology:
3938 case CloseMorphology:
3939 case CloseIntensityMorphology:
3940 case BottomHatMorphology:
3941 case EdgeMorphology:
3944 case HitAndMissMorphology:
3945 rslt_compose = LightenCompositeOp;
3947 case ThinningMorphology:
3948 case ThickenMorphology:
3949 method_limit = kernel_limit;
3952 case DistanceMorphology:
3953 case VoronoiMorphology:
3954 special = MagickTrue;
3963 if ( special != MagickFalse )
3965 rslt_image=CloneImage(image,0,0,MagickTrue,exception);
3966 if (rslt_image == (
Image *) NULL)
3968 if (SetImageStorageClass(rslt_image,DirectClass) == MagickFalse)
3970 InheritException(exception,&rslt_image->exception);
3974 changed = MorphologyPrimitiveDirect(rslt_image, method,
3975 channel, kernel, exception);
3977 if ( verbose != MagickFalse )
3978 (void) (
void) FormatLocaleFile(stderr,
3979 "%s:%.20g.%.20g #%.20g => Changed %.20g\n",
3980 CommandOptionToMnemonic(MagickMorphologyOptions, method),
3981 1.0,0.0,1.0, (
double) changed);
3986 if ( method == VoronoiMorphology ) {
3988 (void) SetImageAlphaChannel(rslt_image, DeactivateAlphaChannel);
3989 (void) CompositeImageChannel(rslt_image, DefaultChannels,
3990 CopyOpacityCompositeOp, image, 0, 0);
3991 (void) SetImageAlphaChannel(rslt_image, DeactivateAlphaChannel);
3997 if ( compose != UndefinedCompositeOp )
3998 rslt_compose = compose;
3999 if ( rslt_compose == UndefinedCompositeOp )
4000 rslt_compose = NoCompositeOp;
4005 case CorrelateMorphology:
4006 case CloseMorphology:
4007 case CloseIntensityMorphology:
4008 case BottomHatMorphology:
4009 case SmoothMorphology:
4010 reflected_kernel = CloneKernelInfo(kernel);
4013 RotateKernelInfo(reflected_kernel,180);
4025 while ( method_loop < method_limit && method_changed > 0 ) {
4032 rflt_kernel = reflected_kernel;
4035 while ( norm_kernel != NULL ) {
4039 while ( stage_loop < stage_limit ) {
4043 this_kernel = norm_kernel;
4046 case ErodeMorphology:
4047 case EdgeInMorphology:
4048 primitive = ErodeMorphology;
4050 case DilateMorphology:
4051 case EdgeOutMorphology:
4052 primitive = DilateMorphology;
4054 case OpenMorphology:
4055 case TopHatMorphology:
4056 primitive = ErodeMorphology;
4057 if ( stage_loop == 2 )
4058 primitive = DilateMorphology;
4060 case OpenIntensityMorphology:
4061 primitive = ErodeIntensityMorphology;
4062 if ( stage_loop == 2 )
4063 primitive = DilateIntensityMorphology;
4065 case CloseMorphology:
4066 case BottomHatMorphology:
4067 this_kernel = rflt_kernel;
4068 primitive = DilateMorphology;
4069 if ( stage_loop == 2 )
4070 primitive = ErodeMorphology;
4072 case CloseIntensityMorphology:
4073 this_kernel = rflt_kernel;
4074 primitive = DilateIntensityMorphology;
4075 if ( stage_loop == 2 )
4076 primitive = ErodeIntensityMorphology;
4078 case SmoothMorphology:
4079 switch ( stage_loop ) {
4081 primitive = ErodeMorphology;
4084 primitive = DilateMorphology;
4087 this_kernel = rflt_kernel;
4088 primitive = DilateMorphology;
4091 this_kernel = rflt_kernel;
4092 primitive = ErodeMorphology;
4096 case EdgeMorphology:
4097 primitive = DilateMorphology;
4098 if ( stage_loop == 2 ) {
4099 save_image = curr_image;
4100 curr_image = (
Image *) image;
4101 primitive = ErodeMorphology;
4104 case CorrelateMorphology:
4114 this_kernel = rflt_kernel;
4115 primitive = ConvolveMorphology;
4120 assert( this_kernel != (
KernelInfo *) NULL );
4123 if ( verbose != MagickFalse ) {
4124 if ( stage_limit > 1 )
4125 (void) FormatLocaleString(v_info,MaxTextExtent,
"%s:%.20g.%.20g -> ",
4126 CommandOptionToMnemonic(MagickMorphologyOptions,method),(double)
4127 method_loop,(
double) stage_loop);
4128 else if ( primitive != method )
4129 (void) FormatLocaleString(v_info, MaxTextExtent,
"%s:%.20g -> ",
4130 CommandOptionToMnemonic(MagickMorphologyOptions, method),(double)
4140 while ( kernel_loop < kernel_limit && changed > 0 ) {
4144 if ( work_image == (
Image *) NULL )
4146 work_image=CloneImage(image,0,0,MagickTrue,exception);
4147 if (work_image == (
Image *) NULL)
4149 if (SetImageStorageClass(work_image,DirectClass) == MagickFalse)
4151 InheritException(exception,&work_image->exception);
4159 changed = MorphologyPrimitive(curr_image, work_image, primitive,
4160 channel, this_kernel, bias, exception);
4162 if ( verbose != MagickFalse ) {
4163 if ( kernel_loop > 1 )
4164 (void) FormatLocaleFile(stderr,
"\n");
4165 (void) (
void) FormatLocaleFile(stderr,
4166 "%s%s%s:%.20g.%.20g #%.20g => Changed %.20g",
4167 v_info,CommandOptionToMnemonic(MagickMorphologyOptions,
4168 primitive),(this_kernel == rflt_kernel ) ?
"*" :
"",
4169 (
double) (method_loop+kernel_loop-1),(
double) kernel_number,
4170 (
double) count,(
double) changed);
4174 kernel_changed += changed;
4175 method_changed += changed;
4178 {
Image *tmp = work_image;
4179 work_image = curr_image;
4182 if ( work_image == image )
4183 work_image = (
Image *) NULL;
4187 if ( verbose != MagickFalse && kernel_changed != (
size_t)changed )
4188 (
void) FormatLocaleFile(stderr,
" Total %.20g",(
double) kernel_changed);
4189 if ( verbose != MagickFalse && stage_loop < stage_limit )
4190 (void) FormatLocaleFile(stderr,
"\n");
4193 (void) FormatLocaleFile(stderr,
"--E-- image=0x%lx\n", (
unsigned long)image);
4194 (void) FormatLocaleFile(stderr,
" curr =0x%lx\n", (
unsigned long)curr_image);
4195 (void) FormatLocaleFile(stderr,
" work =0x%lx\n", (
unsigned long)work_image);
4196 (void) FormatLocaleFile(stderr,
" save =0x%lx\n", (
unsigned long)save_image);
4197 (void) FormatLocaleFile(stderr,
" union=0x%lx\n", (
unsigned long)rslt_image);
4210 case EdgeOutMorphology:
4211 case EdgeInMorphology:
4212 case TopHatMorphology:
4213 case BottomHatMorphology:
4214 if ( verbose != MagickFalse )
4215 (void) FormatLocaleFile(stderr,
4216 "\n%s: Difference with original image",
4217 CommandOptionToMnemonic(MagickMorphologyOptions,method));
4218 (void) CompositeImageChannel(curr_image,(ChannelType)
4219 (channel & ~SyncChannels),DifferenceCompositeOp,image,0,0);
4221 case EdgeMorphology:
4222 if ( verbose != MagickFalse )
4223 (void) FormatLocaleFile(stderr,
4224 "\n%s: Difference of Dilate and Erode",
4225 CommandOptionToMnemonic(MagickMorphologyOptions,method));
4226 (void) CompositeImageChannel(curr_image,(ChannelType)
4227 (channel & ~SyncChannels),DifferenceCompositeOp,save_image,0,0);
4228 save_image = DestroyImage(save_image);
4236 rslt_image = curr_image;
4237 else if ( rslt_compose == NoCompositeOp )
4238 {
if ( verbose != MagickFalse ) {
4239 if ( this_kernel->next != (
KernelInfo *) NULL )
4240 (void) FormatLocaleFile(stderr,
" (re-iterate)");
4242 (
void) FormatLocaleFile(stderr,
" (done)");
4244 rslt_image = curr_image;
4246 else if ( rslt_image == (
Image *) NULL)
4247 {
if ( verbose != MagickFalse )
4248 (void) FormatLocaleFile(stderr,
" (save for compose)");
4249 rslt_image = curr_image;
4250 curr_image = (
Image *) image;
4260 if ( verbose != MagickFalse )
4261 (void) FormatLocaleFile(stderr,
" (compose \"%s\")",
4262 CommandOptionToMnemonic(MagickComposeOptions, rslt_compose) );
4263 (void) CompositeImageChannel(rslt_image,
4264 (ChannelType) (channel & ~SyncChannels), rslt_compose,
4266 curr_image = DestroyImage(curr_image);
4267 curr_image = (
Image *) image;
4269 if ( verbose != MagickFalse )
4270 (void) FormatLocaleFile(stderr,
"\n");
4273 norm_kernel = norm_kernel->next;
4275 rflt_kernel = rflt_kernel->next;
4285 if ( curr_image == rslt_image )
4286 curr_image = (
Image *) NULL;
4287 if ( rslt_image != (
Image *) NULL )
4288 rslt_image = DestroyImage(rslt_image);
4290 if ( curr_image == rslt_image || curr_image == image )
4291 curr_image = (
Image *) NULL;
4292 if ( curr_image != (
Image *) NULL )
4293 curr_image = DestroyImage(curr_image);
4294 if ( work_image != (
Image *) NULL )
4295 work_image = DestroyImage(work_image);
4296 if ( save_image != (
Image *) NULL )
4297 save_image = DestroyImage(save_image);
4298 if ( reflected_kernel != (
KernelInfo *) NULL )
4299 reflected_kernel = DestroyKernelInfo(reflected_kernel);
4358 MagickExport
Image *MorphologyImage(
const Image *image,
4359 const MorphologyMethod method,
const ssize_t iterations,
4365 morphology_image=MorphologyImageChannel(image,DefaultChannels,method,
4366 iterations,kernel,exception);
4367 return(morphology_image);
4370 MagickExport
Image *MorphologyImageChannel(
const Image *image,
4371 const ChannelType channel,
const MorphologyMethod method,
4390 assert(image != (
const Image *) NULL);
4391 assert(image->signature == MagickCoreSignature);
4393 assert(exception->signature == MagickCoreSignature);
4394 if (IsEventLogging() != MagickFalse)
4395 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4398 if ((method == ConvolveMorphology) || (method == CorrelateMorphology))
4403 artifact = GetImageArtifact(image,
"convolve:bias");
4404 if (artifact != (
const char *) NULL)
4405 bias=StringToDoubleInterval(artifact,(
double) QuantumRange+1.0);
4407 artifact = GetImageArtifact(image,
"convolve:scale");
4408 if ( artifact != (
const char *) NULL ) {
4409 if ( curr_kernel == kernel )
4410 curr_kernel = CloneKernelInfo(kernel);
4412 curr_kernel=DestroyKernelInfo(curr_kernel);
4413 return((
Image *) NULL);
4415 ScaleGeometryKernelInfo(curr_kernel, artifact);
4420 if ( IsMagickTrue(GetImageArtifact(image,
"showKernel"))
4421 || IsMagickTrue(GetImageArtifact(image,
"convolve:showKernel"))
4422 || IsMagickTrue(GetImageArtifact(image,
"morphology:showKernel")) )
4423 ShowKernelInfo(curr_kernel);
4433 compose = UndefinedCompositeOp;
4434 artifact = GetImageArtifact(image,
"morphology:compose");
4435 if ( artifact != (
const char *) NULL)
4436 compose = (CompositeOperator) ParseCommandOption(
4437 MagickComposeOptions,MagickFalse,artifact);
4440 morphology_image = MorphologyApply(image, channel, method, iterations,
4441 curr_kernel, compose, bias, exception);
4444 if ( curr_kernel != kernel )
4445 curr_kernel=DestroyKernelInfo(curr_kernel);
4446 return(morphology_image);
4479 static void RotateKernelInfo(
KernelInfo *kernel,
double angle)
4483 RotateKernelInfo(kernel->next, angle);
4491 angle = fmod(angle, 360.0);
4495 if ( 337.5 < angle || angle <= 22.5 )
4499 switch (kernel->type) {
4501 case GaussianKernel:
4506 case LaplacianKernel:
4507 case ChebyshevKernel:
4508 case ManhattanKernel:
4509 case EuclideanKernel:
4523 if ( 135.0 < angle && angle <= 225.0 )
4525 if ( 225.0 < angle && angle <= 315.0 )
4533 if ( 22.5 < fmod(angle,90.0) && fmod(angle,90.0) <= 67.5 )
4535 if ( kernel->width == 3 && kernel->height == 3 )
4537 double t = kernel->values[0];
4538 kernel->values[0] = kernel->values[3];
4539 kernel->values[3] = kernel->values[6];
4540 kernel->values[6] = kernel->values[7];
4541 kernel->values[7] = kernel->values[8];
4542 kernel->values[8] = kernel->values[5];
4543 kernel->values[5] = kernel->values[2];
4544 kernel->values[2] = kernel->values[1];
4545 kernel->values[1] = t;
4547 if ( kernel->x != 1 || kernel->y != 1 ) {
4549 x = (ssize_t) kernel->x-1;
4550 y = (ssize_t) kernel->y-1;
4551 if ( x == y ) x = 0;
4552 else if ( x == 0 ) x = -y;
4553 else if ( x == -y ) y = 0;
4554 else if ( y == 0 ) y = x;
4555 kernel->x = (ssize_t) x+1;
4556 kernel->y = (ssize_t) y+1;
4558 angle = fmod(angle+315.0, 360.0);
4559 kernel->angle = fmod(kernel->angle+45.0, 360.0);
4562 perror(
"Unable to rotate non-3x3 kernel by 45 degrees");
4564 if ( 45.0 < fmod(angle, 180.0) && fmod(angle,180.0) <= 135.0 )
4566 if ( kernel->width == 1 || kernel->height == 1 )
4572 t = (ssize_t) kernel->width;
4573 kernel->width = kernel->height;
4574 kernel->height = (
size_t) t;
4576 kernel->x = kernel->y;
4578 if ( kernel->width == 1 ) {
4579 angle = fmod(angle+270.0, 360.0);
4580 kernel->angle = fmod(kernel->angle+90.0, 360.0);
4582 angle = fmod(angle+90.0, 360.0);
4583 kernel->angle = fmod(kernel->angle+270.0, 360.0);
4586 else if ( kernel->width == kernel->height )
4593 for( i=0, x=kernel->width-1; i<=x; i++, x--)
4594 for( j=0, y=kernel->height-1; j<y; j++, y--)
4595 { t = k[i+j*kernel->width];
4596 k[i+j*kernel->width] = k[j+x*kernel->width];
4597 k[j+x*kernel->width] = k[x+y*kernel->width];
4598 k[x+y*kernel->width] = k[y+i*kernel->width];
4599 k[y+i*kernel->width] = t;
4604 x = (ssize_t) (kernel->x*2-kernel->width+1);
4605 y = (ssize_t) (kernel->y*2-kernel->height+1);
4606 kernel->x = (ssize_t) ( -y +(ssize_t) kernel->width-1)/2;
4607 kernel->y = (ssize_t) ( +x +(ssize_t) kernel->height-1)/2;
4609 angle = fmod(angle+270.0, 360.0);
4610 kernel->angle = fmod(kernel->angle+90.0, 360.0);
4613 perror(
"Unable to rotate a non-square, non-linear kernel 90 degrees");
4615 if ( 135.0 < angle && angle <= 225.0 )
4633 for ( i=0, j=kernel->width*kernel->height-1; i<j; i++, j--)
4634 t=k[i], k[i]=k[j], k[j]=t;
4636 kernel->x = (ssize_t) kernel->width - kernel->x - 1;
4637 kernel->y = (ssize_t) kernel->height - kernel->y - 1;
4638 angle = fmod(angle-180.0, 360.0);
4639 kernel->angle = fmod(kernel->angle+180.0, 360.0);
4684 MagickExport
void ScaleGeometryKernelInfo (
KernelInfo *kernel,
4685 const char *geometry)
4692 SetGeometryInfo(&args);
4693 flags = (GeometryFlags) ParseGeometry(geometry, &args);
4697 (void) FormatLocaleFile(stderr,
"Geometry = 0x%04X : %lg x %lg %+lg %+lg\n",
4698 flags, args.rho, args.sigma, args.xi, args.psi );
4701 if ( (flags & PercentValue) != 0 )
4702 args.rho *= 0.01, args.sigma *= 0.01;
4704 if ( (flags & RhoValue) == 0 )
4706 if ( (flags & SigmaValue) == 0 )
4710 ScaleKernelInfo(kernel, args.rho, flags);
4713 if ( (flags & SigmaValue) != 0 )
4714 UnityAddKernelInfo(kernel, args.sigma);
4789 MagickExport
void ScaleKernelInfo(
KernelInfo *kernel,
4790 const double scaling_factor,
const GeometryFlags normalize_flags)
4801 ScaleKernelInfo(kernel->next, scaling_factor, normalize_flags);
4805 if ( (normalize_flags&NormalizeValue) != 0 ) {
4806 if ( fabs(kernel->positive_range + kernel->negative_range) >= MagickEpsilon )
4808 pos_scale = fabs(kernel->positive_range + kernel->negative_range);
4811 pos_scale = kernel->positive_range;
4814 if ( (normalize_flags&CorrelateNormalizeValue) != 0 ) {
4815 pos_scale = ( fabs(kernel->positive_range) >= MagickEpsilon )
4816 ? kernel->positive_range : 1.0;
4817 neg_scale = ( fabs(kernel->negative_range) >= MagickEpsilon )
4818 ? -kernel->negative_range : 1.0;
4821 neg_scale = pos_scale;
4824 pos_scale = scaling_factor/pos_scale;
4825 neg_scale = scaling_factor/neg_scale;
4827 for (i=0; i < (ssize_t) (kernel->width*kernel->height); i++)
4828 if ( ! IsNaN(kernel->values[i]) )
4829 kernel->values[i] *= (kernel->values[i] >= 0) ? pos_scale : neg_scale;
4832 kernel->positive_range *= pos_scale;
4833 kernel->negative_range *= neg_scale;
4835 kernel->maximum *= (kernel->maximum >= 0.0) ? pos_scale : neg_scale;
4836 kernel->minimum *= (kernel->minimum >= 0.0) ? pos_scale : neg_scale;
4839 if ( scaling_factor < MagickEpsilon ) {
4841 t = kernel->positive_range;
4842 kernel->positive_range = kernel->negative_range;
4843 kernel->negative_range = t;
4844 t = kernel->maximum;
4845 kernel->maximum = kernel->minimum;
4846 kernel->minimum = 1;
4876 MagickExport
void ShowKernelInfo(
const KernelInfo *kernel)
4884 for (c=0, k=kernel; k != (
KernelInfo *) NULL; c++, k=k->next ) {
4886 (void) FormatLocaleFile(stderr,
"Kernel");
4888 (
void) FormatLocaleFile(stderr,
" #%lu", (
unsigned long) c );
4889 (void) FormatLocaleFile(stderr,
" \"%s",
4890 CommandOptionToMnemonic(MagickKernelOptions, k->type) );
4891 if ( fabs(k->angle) >= MagickEpsilon )
4892 (
void) FormatLocaleFile(stderr,
"@%lg", k->angle);
4893 (void) FormatLocaleFile(stderr,
"\" of size %lux%lu%+ld%+ld",(
unsigned long)
4894 k->width,(
unsigned long) k->height,(
long) k->x,(long) k->y);
4895 (void) FormatLocaleFile(stderr,
4896 " with values from %.*lg to %.*lg\n",
4897 GetMagickPrecision(), k->minimum,
4898 GetMagickPrecision(), k->maximum);
4899 (void) FormatLocaleFile(stderr,
"Forming a output range from %.*lg to %.*lg",
4900 GetMagickPrecision(), k->negative_range,
4901 GetMagickPrecision(), k->positive_range);
4902 if ( fabs(k->positive_range+k->negative_range) < MagickEpsilon )
4903 (
void) FormatLocaleFile(stderr,
" (Zero-Summing)\n");
4904 else if ( fabs(k->positive_range+k->negative_range-1.0) < MagickEpsilon )
4905 (void) FormatLocaleFile(stderr,
" (Normalized)\n");
4907 (
void) FormatLocaleFile(stderr,
" (Sum %.*lg)\n",
4908 GetMagickPrecision(), k->positive_range+k->negative_range);
4909 for (i=v=0; v < k->height; v++) {
4910 (void) FormatLocaleFile(stderr,
"%2lu:", (
unsigned long) v );
4911 for (u=0; u < k->width; u++, i++)
4912 if ( IsNaN(k->values[i]) )
4913 (
void) FormatLocaleFile(stderr,
" %*s", GetMagickPrecision()+3,
"nan");
4915 (
void) FormatLocaleFile(stderr,
" %*.*lg", GetMagickPrecision()+3,
4916 GetMagickPrecision(), k->values[i]);
4917 (void) FormatLocaleFile(stderr,
"\n");
4956 MagickExport
void UnityAddKernelInfo(
KernelInfo *kernel,
4961 UnityAddKernelInfo(kernel->next, scale);
4964 kernel->values[kernel->x+kernel->y*kernel->width] += scale;
4965 CalcKernelMetaData(kernel);
4996 MagickExport
void ZeroKernelNans(
KernelInfo *kernel)
5003 ZeroKernelNans(kernel->next);
5005 for (i=0; i < (kernel->width*kernel->height); i++)
5006 if ( IsNaN(kernel->values[i]) )
5007 kernel->values[i] = 0.0;