85#include "magick/studio.h"
86#include "magick/cache.h"
87#include "magick/color.h"
88#include "magick/colormap.h"
89#include "magick/colorspace.h"
90#include "magick/colorspace-private.h"
91#include "magick/exception.h"
92#include "magick/exception-private.h"
93#include "magick/image.h"
94#include "magick/image-private.h"
95#include "magick/memory_.h"
96#include "magick/memory-private.h"
97#include "magick/monitor.h"
98#include "magick/monitor-private.h"
99#include "magick/quantize.h"
100#include "magick/quantum.h"
101#include "magick/quantum-private.h"
102#include "magick/resource_.h"
103#include "magick/segment.h"
104#include "magick/string_.h"
105#include "magick/thread-private.h"
110#define MaxDimension 3
112#if defined(FastClassify)
113#define WeightingExponent 2.0
114#define SegmentPower(ratio) (ratio)
116#define WeightingExponent 2.5
117#define SegmentPower(ratio) pow(ratio,(double) (1.0/(weighting_exponent-1.0)));
192 OptimalTau(
const ssize_t *,
const double,
const double,
const double,
193 const double,
short *);
201 ScaleSpace(
const ssize_t *,
const MagickRealType,MagickRealType *),
202 ZeroCrossHistogram(MagickRealType *,
const MagickRealType,
short *);
244static MagickBooleanType Classify(
Image *image,
short **extrema,
245 const MagickRealType cluster_threshold,
246 const MagickRealType weighting_exponent,
const MagickBooleanType verbose)
248#define SegmentImageTag "Segment/Image"
249#define ThrowClassifyException(severity,tag,label) \
251 for (cluster=head; cluster != (Cluster *) NULL; cluster=next_cluster) \
253 next_cluster=cluster->next; \
254 cluster=(Cluster *) RelinquishMagickMemory(cluster); \
256 if (squares != (MagickRealType *) NULL) \
259 free_squares=squares; \
260 free_squares=(MagickRealType *) RelinquishMagickMemory(free_squares); \
262 ThrowBinaryException(severity,tag,label); \
309 squares=(MagickRealType *) NULL;
310 (void) memset(&red,0,
sizeof(red));
311 (void) memset(&green,0,
sizeof(green));
312 (void) memset(&blue,0,
sizeof(blue));
313 exception=(&image->exception);
314 while (DefineRegion(extrema[Red],&red) != 0)
317 while (DefineRegion(extrema[Green],&green) != 0)
320 while (DefineRegion(extrema[Blue],&blue) != 0)
327 cluster->next=(
Cluster *) AcquireQuantumMemory(1,
328 sizeof(*cluster->next));
329 cluster=cluster->next;
333 cluster=(
Cluster *) AcquireQuantumMemory(1,
sizeof(*cluster));
336 if (cluster == (
Cluster *) NULL)
337 ThrowClassifyException(ResourceLimitError,
"MemoryAllocationFailed",
342 (void) memset(cluster,0,
sizeof(*cluster));
344 cluster->green=green;
354 cluster=(
Cluster *) AcquireQuantumMemory(1,
sizeof(*cluster));
355 if (cluster == (
Cluster *) NULL)
356 ThrowClassifyException(ResourceLimitError,
"MemoryAllocationFailed",
361 (void) memset(cluster,0,
sizeof(*cluster));
363 cluster->green=green;
373 image_view=AcquireVirtualCacheView(image,exception);
374 for (y=0; y < (ssize_t) image->rows; y++)
382 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
385 for (x=0; x < (ssize_t) image->columns; x++)
390 pixel.red=(double) ScaleQuantumToChar(p->red);
391 pixel.green=(double) ScaleQuantumToChar(p->green);
392 pixel.blue=(double) ScaleQuantumToChar(p->blue);
393 for (cluster=head; cluster != (
Cluster *) NULL; cluster=cluster->next)
394 if ((pixel.red >= (
double) (cluster->red.left-SafeMargin)) &&
395 (pixel.red <= (
double) (cluster->red.right+SafeMargin)) &&
396 (pixel.green >= (
double) (cluster->green.left-SafeMargin)) &&
397 (pixel.green <= (
double) (cluster->green.right+SafeMargin)) &&
398 (pixel.blue >= (
double) (cluster->blue.left-SafeMargin)) &&
399 (pixel.blue <= (
double) (cluster->blue.right+SafeMargin)))
405 cluster->red.center+=pixel.red;
406 cluster->green.center+=pixel.green;
407 cluster->blue.center+=pixel.blue;
413 if (image->progress_monitor != (MagickProgressMonitor) NULL)
418#if defined(MAGICKCORE_OPENMP_SUPPORT)
422 proceed=SetImageProgress(image,SegmentImageTag,progress,2*image->rows);
423 if (proceed == MagickFalse)
427 image_view=DestroyCacheView(image_view);
434 for (cluster=head; cluster != (
Cluster *) NULL; cluster=next_cluster)
436 next_cluster=cluster->next;
437 if ((cluster->count > 0) &&
438 (cluster->count >= (count*cluster_threshold/100.0)))
444 cluster->red.center/=cluster->count;
445 cluster->green.center/=cluster->count;
446 cluster->blue.center/=cluster->count;
448 last_cluster=cluster;
457 last_cluster->next=next_cluster;
458 cluster=(
Cluster *) RelinquishMagickMemory(cluster);
460 number_clusters=(size_t) count;
461 if (verbose != MagickFalse)
466 (void) FormatLocaleFile(stdout,
"Fuzzy C-means Statistics\n");
467 (void) FormatLocaleFile(stdout,
"===================\n\n");
468 (void) FormatLocaleFile(stdout,
"\tCluster Threshold = %g\n",(
double)
470 (void) FormatLocaleFile(stdout,
"\tWeighting Exponent = %g\n",(
double)
472 (void) FormatLocaleFile(stdout,
"\tTotal Number of Clusters = %.20g\n\n",
473 (
double) number_clusters);
477 (void) FormatLocaleFile(stdout,
"\n\nNumber of Vectors Per Cluster\n");
478 (void) FormatLocaleFile(stdout,
"=============================\n\n");
479 for (cluster=head; cluster != (
Cluster *) NULL; cluster=cluster->next)
480 (
void) FormatLocaleFile(stdout,
"Cluster #%.20g = %.20g\n",(
double)
481 cluster->id,(
double) cluster->count);
485 (void) FormatLocaleFile(stdout,
486 "\n\n\nCluster Extents: (Vector Size: %d)\n",MaxDimension);
487 (void) FormatLocaleFile(stdout,
"================");
488 for (cluster=head; cluster != (
Cluster *) NULL; cluster=cluster->next)
490 (void) FormatLocaleFile(stdout,
"\n\nCluster #%.20g\n\n",(
double)
492 (void) FormatLocaleFile(stdout,
493 "%.20g-%.20g %.20g-%.20g %.20g-%.20g\n",(
double)
494 cluster->red.left,(
double) cluster->red.right,(
double)
495 cluster->green.left,(
double) cluster->green.right,(
double)
496 cluster->blue.left,(
double) cluster->blue.right);
501 (void) FormatLocaleFile(stdout,
502 "\n\n\nCluster Center Values: (Vector Size: %d)\n",MaxDimension);
503 (void) FormatLocaleFile(stdout,
"=====================");
504 for (cluster=head; cluster != (
Cluster *) NULL; cluster=cluster->next)
506 (void) FormatLocaleFile(stdout,
"\n\nCluster #%.20g\n\n",(
double)
508 (void) FormatLocaleFile(stdout,
"%g %g %g\n",(
double)
509 cluster->red.center,(
double) cluster->green.center,(
double)
510 cluster->blue.center);
512 (void) FormatLocaleFile(stdout,
"\n");
514 if (number_clusters > 256)
515 ThrowClassifyException(ImageError,
"TooManyClusters",image->filename);
519 squares=(MagickRealType *) AcquireQuantumMemory(513UL,
sizeof(*squares));
520 if (squares == (MagickRealType *) NULL)
521 ThrowClassifyException(ResourceLimitError,
"MemoryAllocationFailed",
524 for (i=(-255); i <= 255; i++)
525 squares[i]=(MagickRealType) i*(MagickRealType) i;
529 if (AcquireImageColormap(image,number_clusters) == MagickFalse)
530 ThrowClassifyException(ResourceLimitError,
"MemoryAllocationFailed",
533 for (cluster=head; cluster != (
Cluster *) NULL; cluster=cluster->next)
535 image->colormap[i].red=ScaleCharToQuantum((
unsigned char)
536 (cluster->red.center+0.5));
537 image->colormap[i].green=ScaleCharToQuantum((
unsigned char)
538 (cluster->green.center+0.5));
539 image->colormap[i].blue=ScaleCharToQuantum((
unsigned char)
540 (cluster->blue.center+0.5));
546 exception=(&image->exception);
547 image_view=AcquireAuthenticCacheView(image,exception);
548#if defined(MAGICKCORE_OPENMP_SUPPORT)
549 #pragma omp parallel for schedule(static) shared(progress,status) \
550 magick_number_threads(image,image,image->rows,1)
552 for (y=0; y < (ssize_t) image->rows; y++)
561 *magick_restrict indexes;
569 if (status == MagickFalse)
571 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
577 indexes=GetCacheViewAuthenticIndexQueue(image_view);
578 for (x=0; x < (ssize_t) image->columns; x++)
583 SetPixelIndex(indexes+x,0);
584 pixel.red=(double) ScaleQuantumToChar(q->red);
585 pixel.green=(double) ScaleQuantumToChar(q->green);
586 pixel.blue=(double) ScaleQuantumToChar(q->blue);
587 for (cluster=head; cluster != (
Cluster *) NULL; cluster=cluster->next)
589 if ((pixel.red >= (
double) (cluster->red.left-SafeMargin)) &&
590 (pixel.red <= (
double) (cluster->red.right+SafeMargin)) &&
591 (pixel.green >= (
double) (cluster->green.left-SafeMargin)) &&
592 (pixel.green <= (
double) (cluster->green.right+SafeMargin)) &&
593 (pixel.blue >= (
double) (cluster->blue.left-SafeMargin)) &&
594 (pixel.blue <= (
double) (cluster->blue.right+SafeMargin)))
599 SetPixelIndex(indexes+x,cluster->id);
603 if (cluster == (
Cluster *) NULL)
620 for (j=0; j < (ssize_t) image->colors; j++)
625 squares[(ssize_t) (pixel.red-ScaleQuantumToChar(p->red))]+
626 squares[(ssize_t) (pixel.green-ScaleQuantumToChar(p->green))]+
627 squares[(ssize_t) (pixel.blue-ScaleQuantumToChar(p->blue))];
628 numerator=distance_squared;
629 for (k=0; k < (ssize_t) image->colors; k++)
633 squares[(ssize_t) (pixel.red-ScaleQuantumToChar(p->red))]+
634 squares[(ssize_t) (pixel.green-ScaleQuantumToChar(p->green))]+
635 squares[(ssize_t) (pixel.blue-ScaleQuantumToChar(p->blue))];
636 ratio=numerator/distance_squared;
637 sum+=SegmentPower(ratio);
639 if ((sum != 0.0) && ((1.0/sum) > local_minima))
644 local_minima=1.0/sum;
645 SetPixelIndex(indexes+x,j);
651 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
653 if (image->progress_monitor != (MagickProgressMonitor) NULL)
658#if defined(MAGICKCORE_OPENMP_SUPPORT)
662 proceed=SetImageProgress(image,SegmentImageTag,progress,2*image->rows);
663 if (proceed == MagickFalse)
667 image_view=DestroyCacheView(image_view);
668 status&=SyncImage(image);
672 for (cluster=head; cluster != (
Cluster *) NULL; cluster=next_cluster)
674 next_cluster=cluster->next;
675 cluster=(
Cluster *) RelinquishMagickMemory(cluster);
678 free_squares=squares;
679 free_squares=(MagickRealType *) RelinquishMagickMemory(free_squares);
710static void ConsolidateCrossings(
ZeroCrossing *zero_crossing,
711 const size_t number_crossings)
729 for (i=(ssize_t) number_crossings-1; i >= 0; i--)
730 for (j=0; j <= 255; j++)
732 if (zero_crossing[i].crossings[j] == 0)
739 for (k=j-1; k > 0; k--)
740 if (zero_crossing[i+1].crossings[k] != 0)
744 for (k=j+1; k < 255; k++)
745 if (zero_crossing[i+1].crossings[k] != 0)
747 right=MagickMin(k,255);
751 for (k=j-1; k > 0; k--)
752 if (zero_crossing[i].crossings[k] != 0)
760 if (zero_crossing[i+1].crossings[j] != 0)
763 for (l=k+1; l < center; l++)
764 if (zero_crossing[i+1].crossings[l] != 0)
766 if (((count % 2) == 0) && (center != k))
775 for (l=k+1; l < left; l++)
776 if (zero_crossing[i+1].crossings[l] != 0)
778 if (((count % 2) == 0) && (left != k))
787 for (l=k+1; l < right; l++)
788 if (zero_crossing[i+1].crossings[l] != 0)
790 if (((count % 2) == 0) && (right != k))
793 l=(ssize_t) zero_crossing[i].crossings[j];
794 zero_crossing[i].crossings[j]=0;
796 zero_crossing[i].crossings[correct]=(short) l;
827static ssize_t DefineRegion(
const short *extrema,
ExtentPacket *extents)
838 for ( ; extents->index <= 255; extents->index++)
839 if (extrema[extents->index] > 0)
841 if (extents->index > 255)
843 extents->left=extents->index;
847 for ( ; extents->index <= 255; extents->index++)
848 if (extrema[extents->index] < 0)
850 extents->right=extents->index-1;
883static void DerivativeHistogram(
const MagickRealType *histogram,
884 MagickRealType *derivative)
894 derivative[0]=(-1.5*histogram[0]+2.0*histogram[1]-0.5*histogram[2]);
895 derivative[n]=(0.5*histogram[n-2]-2.0*histogram[n-1]+1.5*histogram[n]);
899 for (i=1; i < n; i++)
900 derivative[i]=(histogram[i+1]-histogram[i-1])/2.0;
940MagickExport MagickBooleanType GetImageDynamicThreshold(
const Image *image,
941 const double cluster_threshold,
const double smooth_threshold,
971 *extrema[MaxDimension];
975 *histogram[MaxDimension],
981 assert(image != (
Image *) NULL);
982 assert(image->signature == MagickCoreSignature);
983 if (IsEventLogging() != MagickFalse)
984 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
985 GetMagickPixelPacket(image,pixel);
986 for (i=0; i < MaxDimension; i++)
988 histogram[i]=(ssize_t *) AcquireQuantumMemory(256UL,
sizeof(**histogram));
989 extrema[i]=(
short *) AcquireQuantumMemory(256UL,
sizeof(**histogram));
990 if ((histogram[i] == (ssize_t *) NULL) || (extrema[i] == (
short *) NULL))
992 for (i-- ; i >= 0; i--)
994 extrema[i]=(
short *) RelinquishMagickMemory(extrema[i]);
995 histogram[i]=(ssize_t *) RelinquishMagickMemory(histogram[i]);
997 (void) ThrowMagickException(exception,GetMagickModule(),
998 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",image->filename);
1005 InitializeHistogram(image,histogram,exception);
1006 (void) OptimalTau(histogram[Red],Tau,0.2f,DeltaTau,
1007 (smooth_threshold == 0.0 ? 1.0 : smooth_threshold),extrema[Red]);
1008 (void) OptimalTau(histogram[Green],Tau,0.2f,DeltaTau,
1009 (smooth_threshold == 0.0 ? 1.0 : smooth_threshold),extrema[Green]);
1010 (void) OptimalTau(histogram[Blue],Tau,0.2f,DeltaTau,
1011 (smooth_threshold == 0.0 ? 1.0 : smooth_threshold),extrema[Blue]);
1017 (void) memset(&red,0,
sizeof(red));
1018 (void) memset(&green,0,
sizeof(green));
1019 (void) memset(&blue,0,
sizeof(blue));
1020 while (DefineRegion(extrema[Red],&red) != 0)
1023 while (DefineRegion(extrema[Green],&green) != 0)
1026 while (DefineRegion(extrema[Blue],&blue) != 0)
1033 cluster->next=(
Cluster *) AcquireQuantumMemory(1,
1034 sizeof(*cluster->next));
1035 cluster=cluster->next;
1039 cluster=(
Cluster *) AcquireQuantumMemory(1,
sizeof(*cluster));
1042 if (cluster == (
Cluster *) NULL)
1044 (void) ThrowMagickException(exception,GetMagickModule(),
1045 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",
1047 return(MagickFalse);
1054 cluster->green=green;
1056 cluster->next=(
Cluster *) NULL;
1065 cluster=(
Cluster *) AcquireQuantumMemory(1,
sizeof(*cluster));
1066 if (cluster == (
Cluster *) NULL)
1068 (void) ThrowMagickException(exception,GetMagickModule(),
1069 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",image->filename);
1070 return(MagickFalse);
1077 cluster->green=green;
1079 cluster->next=(
Cluster *) NULL;
1086 for (y=0; y < (ssize_t) image->rows; y++)
1088 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1091 for (x=0; x < (ssize_t) image->columns; x++)
1096 pixel.red=(double) ScaleQuantumToChar(p->red);
1097 pixel.green=(double) ScaleQuantumToChar(p->green);
1098 pixel.blue=(double) ScaleQuantumToChar(p->blue);
1099 for (cluster=head; cluster != (
Cluster *) NULL; cluster=cluster->next)
1100 if ((pixel.red >= (
double) (cluster->red.left-SafeMargin)) &&
1101 (pixel.red <= (
double) (cluster->red.right+SafeMargin)) &&
1102 (pixel.green >= (
double) (cluster->green.left-SafeMargin)) &&
1103 (pixel.green <= (
double) (cluster->green.right+SafeMargin)) &&
1104 (pixel.blue >= (
double) (cluster->blue.left-SafeMargin)) &&
1105 (pixel.blue <= (
double) (cluster->blue.right+SafeMargin)))
1111 cluster->red.center+=pixel.red;
1112 cluster->green.center+=pixel.green;
1113 cluster->blue.center+=pixel.blue;
1119 proceed=SetImageProgress(image,SegmentImageTag,(MagickOffsetType) y,
1121 if (proceed == MagickFalse)
1130 for (cluster=head; cluster != (
Cluster *) NULL; cluster=next_cluster)
1132 next_cluster=cluster->next;
1133 if ((cluster->count > 0) &&
1134 (cluster->count >= (count*cluster_threshold/100.0)))
1140 cluster->red.center/=cluster->count;
1141 cluster->green.center/=cluster->count;
1142 cluster->blue.center/=cluster->count;
1144 last_cluster=cluster;
1150 if (cluster == head)
1153 last_cluster->next=next_cluster;
1154 cluster=(
Cluster *) RelinquishMagickMemory(cluster);
1158 if ((count > 1) && (head != (
Cluster *) NULL) &&
1159 (head->next != (
Cluster *) NULL))
1162 for (cluster=
object; cluster->next != (
Cluster *) NULL; )
1164 if (cluster->count < object->count)
1166 cluster=cluster->next;
1168 background=head->next;
1169 for (cluster=background; cluster->next != (
Cluster *) NULL; )
1171 if (cluster->count > background->count)
1173 cluster=cluster->next;
1176 if (background != (
Cluster *) NULL)
1178 threshold=(background->red.center+
object->red.center)/2.0;
1179 pixel->red=(MagickRealType) ScaleCharToQuantum((
unsigned char)
1181 threshold=(background->green.center+
object->green.center)/2.0;
1182 pixel->green=(MagickRealType) ScaleCharToQuantum((
unsigned char)
1184 threshold=(background->blue.center+
object->blue.center)/2.0;
1185 pixel->blue=(MagickRealType) ScaleCharToQuantum((
unsigned char)
1191 for (cluster=head; cluster != (
Cluster *) NULL; cluster=next_cluster)
1193 next_cluster=cluster->next;
1194 cluster=(
Cluster *) RelinquishMagickMemory(cluster);
1196 for (i=0; i < MaxDimension; i++)
1198 extrema[i]=(
short *) RelinquishMagickMemory(extrema[i]);
1199 histogram[i]=(ssize_t *) RelinquishMagickMemory(histogram[i]);
1230static void InitializeHistogram(
const Image *image,ssize_t **histogram,
1246 for (i=0; i <= 255; i++)
1248 histogram[Red][i]=0;
1249 histogram[Green][i]=0;
1250 histogram[Blue][i]=0;
1252 for (y=0; y < (ssize_t) image->rows; y++)
1254 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1257 for (x=0; x < (ssize_t) image->columns; x++)
1259 histogram[Red][(ssize_t) ScaleQuantumToChar(GetPixelRed(p))]++;
1260 histogram[Green][(ssize_t) ScaleQuantumToChar(GetPixelGreen(p))]++;
1261 histogram[Blue][(ssize_t) ScaleQuantumToChar(GetPixelBlue(p))]++;
1295static void InitializeList(
IntervalTree **list,ssize_t *number_nodes,
1301 list[(*number_nodes)++]=node;
1302 InitializeList(list,number_nodes,node->sibling);
1303 InitializeList(list,number_nodes,node->child);
1313 node->mean_stability=0.0;
1325 for ( ; child != (
IntervalTree *) NULL; child=child->sibling)
1327 sum+=child->stability;
1330 node->mean_stability=sum/(MagickRealType) count;
1332 MeanStability(node->sibling);
1333 MeanStability(node->child);
1341 node->stability=0.0;
1343 node->stability=node->tau-(node->child)->tau;
1344 Stability(node->sibling);
1345 Stability(node->child);
1349 const size_t number_crossings)
1369 list=(
IntervalTree **) AcquireQuantumMemory((
size_t) TreeLength,
1376 root=(
IntervalTree *) AcquireCriticalMemory(
sizeof(*root));
1382 root->mean_stability=0.0;
1383 root->stability=0.0;
1384 (void) memset(list,0,TreeLength*
sizeof(*list));
1385 for (i=(-1); i < (ssize_t) number_crossings; i++)
1391 InitializeList(list,&number_nodes,root);
1395 for (j=0; j < number_nodes; j++)
1400 for (k=head->left+1; k < head->right; k++)
1402 if (zero_crossing[i+1].crossings[k] != 0)
1407 sizeof(*node->child));
1413 sizeof(*node->sibling));
1422 node->tau=zero_crossing[i+1].tau;
1430 if (left != head->left)
1433 sizeof(*node->sibling));
1441 node->tau=zero_crossing[i+1].tau;
1445 node->right=head->right;
1452 Stability(root->child);
1453 MeanStability(root->child);
1488static void ActiveNodes(
IntervalTree **list,ssize_t *number_nodes,
1493 if (node->stability >= node->mean_stability)
1495 list[(*number_nodes)++]=node;
1496 ActiveNodes(list,number_nodes,node->sibling);
1500 ActiveNodes(list,number_nodes,node->sibling);
1501 ActiveNodes(list,number_nodes,node->child);
1509 FreeNodes(node->sibling);
1510 FreeNodes(node->child);
1514static MagickRealType OptimalTau(
const ssize_t *histogram,
const double max_tau,
1515 const double min_tau,
const double delta_tau,
const double smooth_threshold,
1553 list=(
IntervalTree **) AcquireQuantumMemory((
size_t) TreeLength,
1560 count=(size_t) ((max_tau-min_tau)/delta_tau)+2;
1561 zero_crossing=(
ZeroCrossing *) AcquireQuantumMemory((
size_t) count,
1562 sizeof(*zero_crossing));
1568 for (i=0; i < (ssize_t) count; i++)
1569 zero_crossing[i].tau=(-1.0);
1573 derivative=(MagickRealType *) AcquireCriticalMemory(256*
sizeof(*derivative));
1574 second_derivative=(MagickRealType *) AcquireCriticalMemory(256*
1575 sizeof(*second_derivative));
1577 for (tau=max_tau; tau >= min_tau; tau-=delta_tau)
1579 zero_crossing[i].tau=tau;
1580 ScaleSpace(histogram,tau,zero_crossing[i].histogram);
1581 DerivativeHistogram(zero_crossing[i].histogram,derivative);
1582 DerivativeHistogram(derivative,second_derivative);
1583 ZeroCrossHistogram(second_derivative,smooth_threshold,
1584 zero_crossing[i].crossings);
1590 zero_crossing[i].tau=0.0;
1591 for (j=0; j <= 255; j++)
1592 zero_crossing[i].histogram[j]=(MagickRealType) histogram[j];
1593 DerivativeHistogram(zero_crossing[i].histogram,derivative);
1594 DerivativeHistogram(derivative,second_derivative);
1595 ZeroCrossHistogram(second_derivative,smooth_threshold,
1596 zero_crossing[i].crossings);
1597 number_crossings=(size_t) i;
1598 derivative=(MagickRealType *) RelinquishMagickMemory(derivative);
1599 second_derivative=(MagickRealType *)
1600 RelinquishMagickMemory(second_derivative);
1604 ConsolidateCrossings(zero_crossing,number_crossings);
1608 for (i=0; i <= (ssize_t) number_crossings; i++)
1610 for (j=0; j < 255; j++)
1611 if (zero_crossing[i].crossings[j] != 0)
1613 zero_crossing[i].crossings[0]=(-zero_crossing[i].crossings[j]);
1614 for (j=255; j > 0; j--)
1615 if (zero_crossing[i].crossings[j] != 0)
1617 zero_crossing[i].crossings[255]=(-zero_crossing[i].crossings[j]);
1622 root=InitializeIntervalTree(zero_crossing,number_crossings);
1625 zero_crossing=(
ZeroCrossing *) RelinquishMagickMemory(zero_crossing);
1634 ActiveNodes(list,&number_nodes,root->child);
1638 for (i=0; i <= 255; i++)
1640 for (i=0; i < number_nodes; i++)
1647 for (j=0; j <= (ssize_t) number_crossings; j++)
1648 if (zero_crossing[j].tau == node->tau)
1653 peak=zero_crossing[k].crossings[node->right] == -1 ? MagickTrue :
1656 value=zero_crossing[k].histogram[index];
1657 for (x=node->left; x <= node->right; x++)
1659 if (peak != MagickFalse)
1661 if (zero_crossing[k].histogram[x] > value)
1663 value=zero_crossing[k].histogram[x];
1668 if (zero_crossing[k].histogram[x] < value)
1670 value=zero_crossing[k].histogram[x];
1674 for (x=node->left; x <= node->right; x++)
1678 if (peak != MagickFalse)
1679 extrema[x]=(short) index;
1681 extrema[x]=(short) (-index);
1688 for (i=0; i < number_nodes; i++)
1689 average_tau+=list[i]->tau;
1690 average_tau*=PerceptibleReciprocal((MagickRealType) number_nodes);
1695 zero_crossing=(
ZeroCrossing *) RelinquishMagickMemory(zero_crossing);
1697 return(average_tau);
1724static void ScaleSpace(
const ssize_t *histogram,
const MagickRealType tau,
1725 MagickRealType *scale_histogram)
1737 gamma=(
double *) AcquireQuantumMemory(256,
sizeof(*gamma));
1738 if (gamma == (
double *) NULL)
1739 ThrowFatalException(ResourceLimitFatalError,
"UnableToAllocateGammaMap");
1740 alpha=1.0/(tau*sqrt(2.0*MagickPI));
1741 beta=(-1.0/(2.0*tau*tau));
1742 for (x=0; x <= 255; x++)
1744 for (x=0; x <= 255; x++)
1746 gamma[x]=exp((
double) beta*x*x);
1747 if (gamma[x] < MagickEpsilon)
1750 for (x=0; x <= 255; x++)
1753 for (u=0; u <= 255; u++)
1754 sum+=(
double) histogram[u]*gamma[MagickAbsoluteValue(x-u)];
1755 scale_histogram[x]=(MagickRealType) (alpha*sum);
1757 gamma=(
double *) RelinquishMagickMemory(gamma);
1799MagickExport MagickBooleanType SegmentImage(
Image *image,
1800 const ColorspaceType colorspace,
const MagickBooleanType verbose,
1801 const double cluster_threshold,
const double smooth_threshold)
1804 previous_colorspace;
1813 *extrema[MaxDimension];
1816 *histogram[MaxDimension];
1821 assert(image != (
Image *) NULL);
1822 assert(image->signature == MagickCoreSignature);
1823 if (IsEventLogging() != MagickFalse)
1824 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1825 for (i=0; i < MaxDimension; i++)
1827 histogram[i]=(ssize_t *) AcquireQuantumMemory(256,
sizeof(**histogram));
1828 extrema[i]=(
short *) AcquireQuantumMemory(256,
sizeof(**extrema));
1829 if ((histogram[i] == (ssize_t *) NULL) || (extrema[i] == (
short *) NULL))
1831 for (i-- ; i >= 0; i--)
1833 extrema[i]=(
short *) RelinquishMagickMemory(extrema[i]);
1834 histogram[i]=(ssize_t *) RelinquishMagickMemory(histogram[i]);
1836 ThrowBinaryImageException(ResourceLimitError,
"MemoryAllocationFailed",
1843 previous_colorspace=image->colorspace;
1844 (void) TransformImageColorspace(image,colorspace);
1845 InitializeHistogram(image,histogram,&image->exception);
1846 (void) OptimalTau(histogram[Red],Tau,0.2,DeltaTau,smooth_threshold == 0.0 ?
1847 1.0 : smooth_threshold,extrema[Red]);
1848 (void) OptimalTau(histogram[Green],Tau,0.2,DeltaTau,smooth_threshold == 0.0 ?
1849 1.0 : smooth_threshold,extrema[Green]);
1850 (void) OptimalTau(histogram[Blue],Tau,0.2,DeltaTau,smooth_threshold == 0.0 ?
1851 1.0 : smooth_threshold,extrema[Blue]);
1855 status=Classify(image,extrema,cluster_threshold,WeightingExponent,verbose);
1856 (void) TransformImageColorspace(image,previous_colorspace);
1860 for (i=0; i < MaxDimension; i++)
1862 extrema[i]=(
short *) RelinquishMagickMemory(extrema[i]);
1863 histogram[i]=(ssize_t *) RelinquishMagickMemory(histogram[i]);
1898static void ZeroCrossHistogram(MagickRealType *second_derivative,
1899 const MagickRealType smooth_threshold,
short *crossings)
1910 for (i=0; i <= 255; i++)
1911 if ((second_derivative[i] < smooth_threshold) &&
1912 (second_derivative[i] >= -smooth_threshold))
1913 second_derivative[i]=0.0;
1918 for (i=0; i <= 255; i++)
1921 if (second_derivative[i] < 0.0)
1928 if (second_derivative[i] > 0.0)