MagickCore  6.7.5
segment.c
Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %               SSSSS  EEEEE   GGGG  M   M  EEEEE  N   N  TTTTT               %
00007 %               SS     E      G      MM MM  E      NN  N    T                 %
00008 %                SSS   EEE    G GGG  M M M  EEE    N N N    T                 %
00009 %                  SS  E      G   G  M   M  E      N  NN    T                 %
00010 %               SSSSS  EEEEE   GGGG  M   M  EEEEE  N   N    T                 %
00011 %                                                                             %
00012 %                                                                             %
00013 %    MagickCore Methods to Segment an Image with Thresholding Fuzzy c-Means   %
00014 %                                                                             %
00015 %                              Software Design                                %
00016 %                                John Cristy                                  %
00017 %                                April 1993                                   %
00018 %                                                                             %
00019 %                                                                             %
00020 %  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
00021 %  dedicated to making software imaging solutions freely available.           %
00022 %                                                                             %
00023 %  You may not use this file except in compliance with the License.  You may  %
00024 %  obtain a copy of the License at                                            %
00025 %                                                                             %
00026 %    http://www.imagemagick.org/script/license.php                            %
00027 %                                                                             %
00028 %  Unless required by applicable law or agreed to in writing, software        %
00029 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00030 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00031 %  See the License for the specific language governing permissions and        %
00032 %  limitations under the License.                                             %
00033 %                                                                             %
00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00035 %
00036 %  Segment segments an image by analyzing the histograms of the color
00037 %  components and identifying units that are homogeneous with the fuzzy
00038 %  c-means technique.  The scale-space filter analyzes the histograms of
00039 %  the three color components of the image and identifies a set of
00040 %  classes.  The extents of each class is used to coarsely segment the
00041 %  image with thresholding.  The color associated with each class is
00042 %  determined by the mean color of all pixels within the extents of a
00043 %  particular class.  Finally, any unclassified pixels are assigned to
00044 %  the closest class with the fuzzy c-means technique.
00045 %
00046 %  The fuzzy c-Means algorithm can be summarized as follows:
00047 %
00048 %    o Build a histogram, one for each color component of the image.
00049 %
00050 %    o For each histogram, successively apply the scale-space filter and
00051 %      build an interval tree of zero crossings in the second derivative
00052 %      at each scale.  Analyze this scale-space ``fingerprint'' to
00053 %      determine which peaks and valleys in the histogram are most
00054 %      predominant.
00055 %
00056 %    o The fingerprint defines intervals on the axis of the histogram.
00057 %      Each interval contains either a minima or a maxima in the original
00058 %      signal.  If each color component lies within the maxima interval,
00059 %      that pixel is considered ``classified'' and is assigned an unique
00060 %      class number.
00061 %
00062 %    o Any pixel that fails to be classified in the above thresholding
00063 %      pass is classified using the fuzzy c-Means technique.  It is
00064 %      assigned to one of the classes discovered in the histogram analysis
00065 %      phase.
00066 %
00067 %  The fuzzy c-Means technique attempts to cluster a pixel by finding
00068 %  the local minima of the generalized within group sum of squared error
00069 %  objective function.  A pixel is assigned to the closest class of
00070 %  which the fuzzy membership has a maximum value.
00071 %
00072 %  Segment is strongly based on software written by Andy Gallo,
00073 %  University of Delaware.
00074 %
00075 %  The following reference was used in creating this program:
00076 %
00077 %    Young Won Lim, Sang Uk Lee, "On The Color Image Segmentation
00078 %    Algorithm Based on the Thresholding and the Fuzzy c-Means
00079 %    Techniques", Pattern Recognition, Volume 23, Number 9, pages
00080 %    935-952, 1990.
00081 %
00082 %
00083 */
00084 
00085 #include "MagickCore/studio.h"
00086 #include "MagickCore/cache.h"
00087 #include "MagickCore/color.h"
00088 #include "MagickCore/colormap.h"
00089 #include "MagickCore/colorspace.h"
00090 #include "MagickCore/colorspace-private.h"
00091 #include "MagickCore/exception.h"
00092 #include "MagickCore/exception-private.h"
00093 #include "MagickCore/image.h"
00094 #include "MagickCore/image-private.h"
00095 #include "MagickCore/memory_.h"
00096 #include "MagickCore/monitor.h"
00097 #include "MagickCore/monitor-private.h"
00098 #include "MagickCore/pixel-accessor.h"
00099 #include "MagickCore/quantize.h"
00100 #include "MagickCore/quantum.h"
00101 #include "MagickCore/quantum-private.h"
00102 #include "MagickCore/segment.h"
00103 #include "MagickCore/string_.h"
00104 
00105 /*
00106   Define declarations.
00107 */
00108 #define MaxDimension  3
00109 #define DeltaTau  0.5f
00110 #if defined(FastClassify)
00111 #define WeightingExponent  2.0
00112 #define SegmentPower(ratio) (ratio)
00113 #else
00114 #define WeightingExponent  2.5
00115 #define SegmentPower(ratio) pow(ratio,(double) (1.0/(weighting_exponent-1.0)));
00116 #endif
00117 #define Tau  5.2f
00118 
00119 /*
00120   Typedef declarations.
00121 */
00122 typedef struct _ExtentPacket
00123 {
00124   MagickRealType
00125     center;
00126 
00127   ssize_t
00128     index,
00129     left,
00130     right;
00131 } ExtentPacket;
00132 
00133 typedef struct _Cluster
00134 {
00135   struct _Cluster
00136     *next;
00137 
00138   ExtentPacket
00139     red,
00140     green,
00141     blue;
00142 
00143   ssize_t
00144     count,
00145     id;
00146 } Cluster;
00147 
00148 typedef struct _IntervalTree
00149 {
00150   MagickRealType
00151     tau;
00152 
00153   ssize_t
00154     left,
00155     right;
00156 
00157   MagickRealType
00158     mean_stability,
00159     stability;
00160 
00161   struct _IntervalTree
00162     *sibling,
00163     *child;
00164 } IntervalTree;
00165 
00166 typedef struct _ZeroCrossing
00167 {
00168   MagickRealType
00169     tau,
00170     histogram[256];
00171 
00172   short
00173     crossings[256];
00174 } ZeroCrossing;
00175 
00176 /*
00177   Constant declarations.
00178 */
00179 static const int
00180   Blue = 2,
00181   Green = 1,
00182   Red = 0,
00183   SafeMargin = 3,
00184   TreeLength = 600;
00185 
00186 /*
00187   Method prototypes.
00188 */
00189 static MagickRealType
00190   OptimalTau(const ssize_t *,const double,const double,const double,
00191     const double,short *);
00192 
00193 static ssize_t
00194   DefineRegion(const short *,ExtentPacket *);
00195 
00196 static void
00197   InitializeHistogram(const Image *,ssize_t **,ExceptionInfo *),
00198   ScaleSpace(const ssize_t *,const MagickRealType,MagickRealType *),
00199   ZeroCrossHistogram(MagickRealType *,const MagickRealType,short *);
00200 
00201 /*
00202 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00203 %                                                                             %
00204 %                                                                             %
00205 %                                                                             %
00206 +   C l a s s i f y                                                           %
00207 %                                                                             %
00208 %                                                                             %
00209 %                                                                             %
00210 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00211 %
00212 %  Classify() defines one or more classes.  Each pixel is thresholded to
00213 %  determine which class it belongs to.  If the class is not identified it is
00214 %  assigned to the closest class based on the fuzzy c-Means technique.
00215 %
00216 %  The format of the Classify method is:
00217 %
00218 %      MagickBooleanType Classify(Image *image,short **extrema,
00219 %        const MagickRealType cluster_threshold,
00220 %        const MagickRealType weighting_exponent,
00221 %        const MagickBooleanType verbose,ExceptionInfo *exception)
00222 %
00223 %  A description of each parameter follows.
00224 %
00225 %    o image: the image.
00226 %
00227 %    o extrema:  Specifies a pointer to an array of integers.  They
00228 %      represent the peaks and valleys of the histogram for each color
00229 %      component.
00230 %
00231 %    o cluster_threshold:  This MagickRealType represents the minimum number of
00232 %      pixels contained in a hexahedra before it can be considered valid
00233 %      (expressed as a percentage).
00234 %
00235 %    o weighting_exponent: Specifies the membership weighting exponent.
00236 %
00237 %    o verbose:  A value greater than zero prints detailed information about
00238 %      the identified classes.
00239 %
00240 %    o exception: return any errors or warnings in this structure.
00241 %
00242 */
00243 static MagickBooleanType Classify(Image *image,short **extrema,
00244   const MagickRealType cluster_threshold,
00245   const MagickRealType weighting_exponent,const MagickBooleanType verbose,
00246   ExceptionInfo *exception)
00247 {
00248 #define SegmentImageTag  "Segment/Image"
00249 
00250   CacheView
00251     *image_view;
00252 
00253   Cluster
00254     *cluster,
00255     *head,
00256     *last_cluster,
00257     *next_cluster;
00258 
00259   ExtentPacket
00260     blue,
00261     green,
00262     red;
00263 
00264   MagickOffsetType
00265     progress;
00266 
00267   MagickRealType
00268     *free_squares;
00269 
00270   MagickStatusType
00271     status;
00272 
00273   register ssize_t
00274     i;
00275 
00276   register MagickRealType
00277     *squares;
00278 
00279   size_t
00280     number_clusters;
00281 
00282   ssize_t
00283     count,
00284     y;
00285 
00286   /*
00287     Form clusters.
00288   */
00289   cluster=(Cluster *) NULL;
00290   head=(Cluster *) NULL;
00291   (void) ResetMagickMemory(&red,0,sizeof(red));
00292   (void) ResetMagickMemory(&green,0,sizeof(green));
00293   (void) ResetMagickMemory(&blue,0,sizeof(blue));
00294   while (DefineRegion(extrema[Red],&red) != 0)
00295   {
00296     green.index=0;
00297     while (DefineRegion(extrema[Green],&green) != 0)
00298     {
00299       blue.index=0;
00300       while (DefineRegion(extrema[Blue],&blue) != 0)
00301       {
00302         /*
00303           Allocate a new class.
00304         */
00305         if (head != (Cluster *) NULL)
00306           {
00307             cluster->next=(Cluster *) AcquireMagickMemory(
00308               sizeof(*cluster->next));
00309             cluster=cluster->next;
00310           }
00311         else
00312           {
00313             cluster=(Cluster *) AcquireMagickMemory(sizeof(*cluster));
00314             head=cluster;
00315           }
00316         if (cluster == (Cluster *) NULL)
00317           ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
00318             image->filename);
00319         /*
00320           Initialize a new class.
00321         */
00322         cluster->count=0;
00323         cluster->red=red;
00324         cluster->green=green;
00325         cluster->blue=blue;
00326         cluster->next=(Cluster *) NULL;
00327       }
00328     }
00329   }
00330   if (head == (Cluster *) NULL)
00331     {
00332       /*
00333         No classes were identified-- create one.
00334       */
00335       cluster=(Cluster *) AcquireMagickMemory(sizeof(*cluster));
00336       if (cluster == (Cluster *) NULL)
00337         ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
00338           image->filename);
00339       /*
00340         Initialize a new class.
00341       */
00342       cluster->count=0;
00343       cluster->red=red;
00344       cluster->green=green;
00345       cluster->blue=blue;
00346       cluster->next=(Cluster *) NULL;
00347       head=cluster;
00348     }
00349   /*
00350     Count the pixels for each cluster.
00351   */
00352   status=MagickTrue;
00353   count=0;
00354   progress=0;
00355   image_view=AcquireCacheView(image);
00356   for (y=0; y < (ssize_t) image->rows; y++)
00357   {
00358     register const Quantum
00359       *p;
00360 
00361     register ssize_t
00362       x;
00363 
00364     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
00365     if (p == (const Quantum *) NULL)
00366       break;
00367     for (x=0; x < (ssize_t) image->columns; x++)
00368     {
00369       for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
00370         if (((ssize_t) ScaleQuantumToChar(GetPixelRed(image,p)) >=
00371              (cluster->red.left-SafeMargin)) &&
00372             ((ssize_t) ScaleQuantumToChar(GetPixelRed(image,p)) <=
00373              (cluster->red.right+SafeMargin)) &&
00374             ((ssize_t) ScaleQuantumToChar(GetPixelGreen(image,p)) >=
00375              (cluster->green.left-SafeMargin)) &&
00376             ((ssize_t) ScaleQuantumToChar(GetPixelGreen(image,p)) <=
00377              (cluster->green.right+SafeMargin)) &&
00378             ((ssize_t) ScaleQuantumToChar(GetPixelBlue(image,p)) >=
00379              (cluster->blue.left-SafeMargin)) &&
00380             ((ssize_t) ScaleQuantumToChar(GetPixelBlue(image,p)) <=
00381              (cluster->blue.right+SafeMargin)))
00382           {
00383             /*
00384               Count this pixel.
00385             */
00386             count++;
00387             cluster->red.center+=(MagickRealType) ScaleQuantumToChar(
00388               GetPixelRed(image,p));
00389             cluster->green.center+=(MagickRealType) ScaleQuantumToChar(
00390               GetPixelGreen(image,p));
00391             cluster->blue.center+=(MagickRealType) ScaleQuantumToChar(
00392               GetPixelBlue(image,p));
00393             cluster->count++;
00394             break;
00395           }
00396       p+=GetPixelChannels(image);
00397     }
00398     if (image->progress_monitor != (MagickProgressMonitor) NULL)
00399       {
00400         MagickBooleanType
00401           proceed;
00402 
00403 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00404         #pragma omp critical (MagickCore_Classify)
00405 #endif
00406         proceed=SetImageProgress(image,SegmentImageTag,progress++,2*
00407           image->rows);
00408         if (proceed == MagickFalse)
00409           status=MagickFalse;
00410       }
00411   }
00412   image_view=DestroyCacheView(image_view);
00413   /*
00414     Remove clusters that do not meet minimum cluster threshold.
00415   */
00416   count=0;
00417   last_cluster=head;
00418   next_cluster=head;
00419   for (cluster=head; cluster != (Cluster *) NULL; cluster=next_cluster)
00420   {
00421     next_cluster=cluster->next;
00422     if ((cluster->count > 0) &&
00423         (cluster->count >= (count*cluster_threshold/100.0)))
00424       {
00425         /*
00426           Initialize cluster.
00427         */
00428         cluster->id=count;
00429         cluster->red.center/=cluster->count;
00430         cluster->green.center/=cluster->count;
00431         cluster->blue.center/=cluster->count;
00432         count++;
00433         last_cluster=cluster;
00434         continue;
00435       }
00436     /*
00437       Delete cluster.
00438     */
00439     if (cluster == head)
00440       head=next_cluster;
00441     else
00442       last_cluster->next=next_cluster;
00443     cluster=(Cluster *) RelinquishMagickMemory(cluster);
00444   }
00445   number_clusters=(size_t) count;
00446   if (verbose != MagickFalse)
00447     {
00448       /*
00449         Print cluster statistics.
00450       */
00451       (void) FormatLocaleFile(stdout,"Fuzzy C-means Statistics\n");
00452       (void) FormatLocaleFile(stdout,"===================\n\n");
00453       (void) FormatLocaleFile(stdout,"\tCluster Threshold = %g\n",(double)
00454         cluster_threshold);
00455       (void) FormatLocaleFile(stdout,"\tWeighting Exponent = %g\n",(double)
00456         weighting_exponent);
00457       (void) FormatLocaleFile(stdout,"\tTotal Number of Clusters = %.20g\n\n",
00458         (double) number_clusters);
00459       /*
00460         Print the total number of points per cluster.
00461       */
00462       (void) FormatLocaleFile(stdout,"\n\nNumber of Vectors Per Cluster\n");
00463       (void) FormatLocaleFile(stdout,"=============================\n\n");
00464       for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
00465         (void) FormatLocaleFile(stdout,"Cluster #%.20g = %.20g\n",(double)
00466           cluster->id,(double) cluster->count);
00467       /*
00468         Print the cluster extents.
00469       */
00470       (void) FormatLocaleFile(stdout,
00471         "\n\n\nCluster Extents:        (Vector Size: %d)\n",MaxDimension);
00472       (void) FormatLocaleFile(stdout,"================");
00473       for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
00474       {
00475         (void) FormatLocaleFile(stdout,"\n\nCluster #%.20g\n\n",(double)
00476           cluster->id);
00477         (void) FormatLocaleFile(stdout,
00478           "%.20g-%.20g  %.20g-%.20g  %.20g-%.20g\n",(double)
00479           cluster->red.left,(double) cluster->red.right,(double)
00480           cluster->green.left,(double) cluster->green.right,(double)
00481           cluster->blue.left,(double) cluster->blue.right);
00482       }
00483       /*
00484         Print the cluster center values.
00485       */
00486       (void) FormatLocaleFile(stdout,
00487         "\n\n\nCluster Center Values:        (Vector Size: %d)\n",MaxDimension);
00488       (void) FormatLocaleFile(stdout,"=====================");
00489       for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
00490       {
00491         (void) FormatLocaleFile(stdout,"\n\nCluster #%.20g\n\n",(double)
00492           cluster->id);
00493         (void) FormatLocaleFile(stdout,"%g  %g  %g\n",(double)
00494           cluster->red.center,(double) cluster->green.center,(double)
00495           cluster->blue.center);
00496       }
00497       (void) FormatLocaleFile(stdout,"\n");
00498     }
00499   if (number_clusters > 256)
00500     ThrowBinaryException(ImageError,"TooManyClusters",image->filename);
00501   /*
00502     Speed up distance calculations.
00503   */
00504   squares=(MagickRealType *) AcquireQuantumMemory(513UL,sizeof(*squares));
00505   if (squares == (MagickRealType *) NULL)
00506     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
00507       image->filename);
00508   squares+=255;
00509   for (i=(-255); i <= 255; i++)
00510     squares[i]=(MagickRealType) i*(MagickRealType) i;
00511   /*
00512     Allocate image colormap.
00513   */
00514   if (AcquireImageColormap(image,number_clusters,exception) == MagickFalse)
00515     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
00516       image->filename);
00517   i=0;
00518   for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
00519   {
00520     image->colormap[i].red=ScaleCharToQuantum((unsigned char)
00521       (cluster->red.center+0.5));
00522     image->colormap[i].green=ScaleCharToQuantum((unsigned char)
00523       (cluster->green.center+0.5));
00524     image->colormap[i].blue=ScaleCharToQuantum((unsigned char)
00525       (cluster->blue.center+0.5));
00526     i++;
00527   }
00528   /*
00529     Do course grain classes.
00530   */
00531   image_view=AcquireCacheView(image);
00532 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00533   #pragma omp parallel for schedule(static,4) shared(progress,status)
00534 #endif
00535   for (y=0; y < (ssize_t) image->rows; y++)
00536   {
00537     Cluster
00538       *cluster;
00539 
00540     register const PixelInfo
00541       *restrict p;
00542 
00543     register ssize_t
00544       x;
00545 
00546     register Quantum
00547       *restrict q;
00548 
00549     if (status == MagickFalse)
00550       continue;
00551     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
00552     if (q == (Quantum *) NULL)
00553       {
00554         status=MagickFalse;
00555         continue;
00556       }
00557     for (x=0; x < (ssize_t) image->columns; x++)
00558     {
00559       SetPixelIndex(image,0,q);
00560       for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
00561       {
00562         if (((ssize_t) ScaleQuantumToChar(GetPixelRed(image,q)) >=
00563              (cluster->red.left-SafeMargin)) &&
00564             ((ssize_t) ScaleQuantumToChar(GetPixelRed(image,q)) <=
00565              (cluster->red.right+SafeMargin)) &&
00566             ((ssize_t) ScaleQuantumToChar(GetPixelGreen(image,q)) >=
00567              (cluster->green.left-SafeMargin)) &&
00568             ((ssize_t) ScaleQuantumToChar(GetPixelGreen(image,q)) <=
00569              (cluster->green.right+SafeMargin)) &&
00570             ((ssize_t) ScaleQuantumToChar(GetPixelBlue(image,q)) >=
00571              (cluster->blue.left-SafeMargin)) &&
00572             ((ssize_t) ScaleQuantumToChar(GetPixelBlue(image,q)) <=
00573              (cluster->blue.right+SafeMargin)))
00574           {
00575             /*
00576               Classify this pixel.
00577             */
00578             SetPixelIndex(image,(Quantum) cluster->id,q);
00579             break;
00580           }
00581       }
00582       if (cluster == (Cluster *) NULL)
00583         {
00584           MagickRealType
00585             distance_squared,
00586             local_minima,
00587             numerator,
00588             ratio,
00589             sum;
00590 
00591           register ssize_t
00592             j,
00593             k;
00594 
00595           /*
00596             Compute fuzzy membership.
00597           */
00598           local_minima=0.0;
00599           for (j=0; j < (ssize_t) image->colors; j++)
00600           {
00601             sum=0.0;
00602             p=image->colormap+j;
00603             distance_squared=squares[(ssize_t) ScaleQuantumToChar(
00604               GetPixelRed(image,q))-(ssize_t)
00605               ScaleQuantumToChar(p->red)]+squares[(ssize_t)
00606               ScaleQuantumToChar(GetPixelGreen(image,q))-(ssize_t)
00607               ScaleQuantumToChar(p->green)]+squares[(ssize_t)
00608               ScaleQuantumToChar(GetPixelBlue(image,q))-(ssize_t)
00609               ScaleQuantumToChar(p->blue)];
00610             numerator=distance_squared;
00611             for (k=0; k < (ssize_t) image->colors; k++)
00612             {
00613               p=image->colormap+k;
00614                 distance_squared=squares[(ssize_t) ScaleQuantumToChar(
00615                   GetPixelRed(image,q))-(ssize_t)
00616                   ScaleQuantumToChar(p->red)]+squares[(ssize_t)
00617                   ScaleQuantumToChar(GetPixelGreen(image,q))-(ssize_t)
00618                   ScaleQuantumToChar(p->green)]+squares[(ssize_t)
00619                   ScaleQuantumToChar(GetPixelBlue(image,q))-(ssize_t)
00620                   ScaleQuantumToChar(p->blue)];
00621               ratio=numerator/distance_squared;
00622               sum+=SegmentPower(ratio);
00623             }
00624             if ((sum != 0.0) && ((1.0/sum) > local_minima))
00625               {
00626                 /*
00627                   Classify this pixel.
00628                 */
00629                 local_minima=1.0/sum;
00630                 SetPixelIndex(image,(Quantum) j,q);
00631               }
00632           }
00633         }
00634       q+=GetPixelChannels(image);
00635     }
00636     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
00637       status=MagickFalse;
00638     if (image->progress_monitor != (MagickProgressMonitor) NULL)
00639       {
00640         MagickBooleanType
00641           proceed;
00642 
00643 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00644         #pragma omp critical (MagickCore_Classify)
00645 #endif
00646         proceed=SetImageProgress(image,SegmentImageTag,progress++,
00647           2*image->rows);
00648         if (proceed == MagickFalse)
00649           status=MagickFalse;
00650       }
00651   }
00652   image_view=DestroyCacheView(image_view);
00653   status&=SyncImage(image,exception);
00654   /*
00655     Relinquish resources.
00656   */
00657   for (cluster=head; cluster != (Cluster *) NULL; cluster=next_cluster)
00658   {
00659     next_cluster=cluster->next;
00660     cluster=(Cluster *) RelinquishMagickMemory(cluster);
00661   }
00662   squares-=255;
00663   free_squares=squares;
00664   free_squares=(MagickRealType *) RelinquishMagickMemory(free_squares);
00665   return(MagickTrue);
00666 }
00667 
00668 /*
00669 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00670 %                                                                             %
00671 %                                                                             %
00672 %                                                                             %
00673 +   C o n s o l i d a t e C r o s s i n g s                                   %
00674 %                                                                             %
00675 %                                                                             %
00676 %                                                                             %
00677 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00678 %
00679 %  ConsolidateCrossings() guarantees that an even number of zero crossings
00680 %  always lie between two crossings.
00681 %
00682 %  The format of the ConsolidateCrossings method is:
00683 %
00684 %      ConsolidateCrossings(ZeroCrossing *zero_crossing,
00685 %        const size_t number_crossings)
00686 %
00687 %  A description of each parameter follows.
00688 %
00689 %    o zero_crossing: Specifies an array of structures of type ZeroCrossing.
00690 %
00691 %    o number_crossings: This size_t specifies the number of elements
00692 %      in the zero_crossing array.
00693 %
00694 */
00695 
00696 static inline ssize_t MagickAbsoluteValue(const ssize_t x)
00697 {
00698   if (x < 0)
00699     return(-x);
00700   return(x);
00701 }
00702 
00703 static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
00704 {
00705   if (x > y)
00706     return(x);
00707   return(y);
00708 }
00709 
00710 static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
00711 {
00712   if (x < y)
00713     return(x);
00714   return(y);
00715 }
00716 
00717 static void ConsolidateCrossings(ZeroCrossing *zero_crossing,
00718   const size_t number_crossings)
00719 {
00720   register ssize_t
00721     i,
00722     j,
00723     k,
00724     l;
00725 
00726   ssize_t
00727     center,
00728     correct,
00729     count,
00730     left,
00731     right;
00732 
00733   /*
00734     Consolidate zero crossings.
00735   */
00736   for (i=(ssize_t) number_crossings-1; i >= 0; i--)
00737     for (j=0; j <= 255; j++)
00738     {
00739       if (zero_crossing[i].crossings[j] == 0)
00740         continue;
00741       /*
00742         Find the entry that is closest to j and still preserves the
00743         property that there are an even number of crossings between
00744         intervals.
00745       */
00746       for (k=j-1; k > 0; k--)
00747         if (zero_crossing[i+1].crossings[k] != 0)
00748           break;
00749       left=MagickMax(k,0);
00750       center=j;
00751       for (k=j+1; k < 255; k++)
00752         if (zero_crossing[i+1].crossings[k] != 0)
00753           break;
00754       right=MagickMin(k,255);
00755       /*
00756         K is the zero crossing just left of j.
00757       */
00758       for (k=j-1; k > 0; k--)
00759         if (zero_crossing[i].crossings[k] != 0)
00760           break;
00761       if (k < 0)
00762         k=0;
00763       /*
00764         Check center for an even number of crossings between k and j.
00765       */
00766       correct=(-1);
00767       if (zero_crossing[i+1].crossings[j] != 0)
00768         {
00769           count=0;
00770           for (l=k+1; l < center; l++)
00771             if (zero_crossing[i+1].crossings[l] != 0)
00772               count++;
00773           if (((count % 2) == 0) && (center != k))
00774             correct=center;
00775         }
00776       /*
00777         Check left for an even number of crossings between k and j.
00778       */
00779       if (correct == -1)
00780         {
00781           count=0;
00782           for (l=k+1; l < left; l++)
00783             if (zero_crossing[i+1].crossings[l] != 0)
00784               count++;
00785           if (((count % 2) == 0) && (left != k))
00786             correct=left;
00787         }
00788       /*
00789         Check right for an even number of crossings between k and j.
00790       */
00791       if (correct == -1)
00792         {
00793           count=0;
00794           for (l=k+1; l < right; l++)
00795             if (zero_crossing[i+1].crossings[l] != 0)
00796               count++;
00797           if (((count % 2) == 0) && (right != k))
00798             correct=right;
00799         }
00800       l=(ssize_t) zero_crossing[i].crossings[j];
00801       zero_crossing[i].crossings[j]=0;
00802       if (correct != -1)
00803         zero_crossing[i].crossings[correct]=(short) l;
00804     }
00805 }
00806 
00807 /*
00808 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00809 %                                                                             %
00810 %                                                                             %
00811 %                                                                             %
00812 +   D e f i n e R e g i o n                                                   %
00813 %                                                                             %
00814 %                                                                             %
00815 %                                                                             %
00816 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00817 %
00818 %  DefineRegion() defines the left and right boundaries of a peak region.
00819 %
00820 %  The format of the DefineRegion method is:
00821 %
00822 %      ssize_t DefineRegion(const short *extrema,ExtentPacket *extents)
00823 %
00824 %  A description of each parameter follows.
00825 %
00826 %    o extrema:  Specifies a pointer to an array of integers.  They
00827 %      represent the peaks and valleys of the histogram for each color
00828 %      component.
00829 %
00830 %    o extents:  This pointer to an ExtentPacket represent the extends
00831 %      of a particular peak or valley of a color component.
00832 %
00833 */
00834 static ssize_t DefineRegion(const short *extrema,ExtentPacket *extents)
00835 {
00836   /*
00837     Initialize to default values.
00838   */
00839   extents->left=0;
00840   extents->center=0.0;
00841   extents->right=255;
00842   /*
00843     Find the left side (maxima).
00844   */
00845   for ( ; extents->index <= 255; extents->index++)
00846     if (extrema[extents->index] > 0)
00847       break;
00848   if (extents->index > 255)
00849     return(MagickFalse);  /* no left side - no region exists */
00850   extents->left=extents->index;
00851   /*
00852     Find the right side (minima).
00853   */
00854   for ( ; extents->index <= 255; extents->index++)
00855     if (extrema[extents->index] < 0)
00856       break;
00857   extents->right=extents->index-1;
00858   return(MagickTrue);
00859 }
00860 
00861 /*
00862 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00863 %                                                                             %
00864 %                                                                             %
00865 %                                                                             %
00866 +   D e r i v a t i v e H i s t o g r a m                                     %
00867 %                                                                             %
00868 %                                                                             %
00869 %                                                                             %
00870 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00871 %
00872 %  DerivativeHistogram() determines the derivative of the histogram using
00873 %  central differencing.
00874 %
00875 %  The format of the DerivativeHistogram method is:
00876 %
00877 %      DerivativeHistogram(const MagickRealType *histogram,
00878 %        MagickRealType *derivative)
00879 %
00880 %  A description of each parameter follows.
00881 %
00882 %    o histogram: Specifies an array of MagickRealTypes representing the number
00883 %      of pixels for each intensity of a particular color component.
00884 %
00885 %    o derivative: This array of MagickRealTypes is initialized by
00886 %      DerivativeHistogram to the derivative of the histogram using central
00887 %      differencing.
00888 %
00889 */
00890 static void DerivativeHistogram(const MagickRealType *histogram,
00891   MagickRealType *derivative)
00892 {
00893   register ssize_t
00894     i,
00895     n;
00896 
00897   /*
00898     Compute endpoints using second order polynomial interpolation.
00899   */
00900   n=255;
00901   derivative[0]=(-1.5*histogram[0]+2.0*histogram[1]-0.5*histogram[2]);
00902   derivative[n]=(0.5*histogram[n-2]-2.0*histogram[n-1]+1.5*histogram[n]);
00903   /*
00904     Compute derivative using central differencing.
00905   */
00906   for (i=1; i < n; i++)
00907     derivative[i]=(histogram[i+1]-histogram[i-1])/2.0;
00908   return;
00909 }
00910 
00911 /*
00912 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00913 %                                                                             %
00914 %                                                                             %
00915 %                                                                             %
00916 +  G e t I m a g e D y n a m i c T h r e s h o l d                            %
00917 %                                                                             %
00918 %                                                                             %
00919 %                                                                             %
00920 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00921 %
00922 %  GetImageDynamicThreshold() returns the dynamic threshold for an image.
00923 %
00924 %  The format of the GetImageDynamicThreshold method is:
00925 %
00926 %      MagickBooleanType GetImageDynamicThreshold(const Image *image,
00927 %        const double cluster_threshold,const double smooth_threshold,
00928 %        PixelInfo *pixel,ExceptionInfo *exception)
00929 %
00930 %  A description of each parameter follows.
00931 %
00932 %    o image: the image.
00933 %
00934 %    o cluster_threshold:  This MagickRealType represents the minimum number of
00935 %      pixels contained in a hexahedra before it can be considered valid
00936 %      (expressed as a percentage).
00937 %
00938 %    o smooth_threshold: the smoothing threshold eliminates noise in the second
00939 %      derivative of the histogram.  As the value is increased, you can expect a
00940 %      smoother second derivative.
00941 %
00942 %    o pixel: return the dynamic threshold here.
00943 %
00944 %    o exception: return any errors or warnings in this structure.
00945 %
00946 */
00947 MagickExport MagickBooleanType GetImageDynamicThreshold(const Image *image,
00948   const double cluster_threshold,const double smooth_threshold,
00949   PixelInfo *pixel,ExceptionInfo *exception)
00950 {
00951   Cluster
00952     *background,
00953     *cluster,
00954     *object,
00955     *head,
00956     *last_cluster,
00957     *next_cluster;
00958 
00959   ExtentPacket
00960     blue,
00961     green,
00962     red;
00963 
00964   MagickBooleanType
00965     proceed;
00966 
00967   MagickRealType
00968     threshold;
00969 
00970   register const Quantum
00971     *p;
00972 
00973   register ssize_t
00974     i,
00975     x;
00976 
00977   short
00978     *extrema[MaxDimension];
00979 
00980   ssize_t
00981     count,
00982     *histogram[MaxDimension],
00983     y;
00984 
00985   /*
00986     Allocate histogram and extrema.
00987   */
00988   assert(image != (Image *) NULL);
00989   assert(image->signature == MagickSignature);
00990   if (image->debug != MagickFalse)
00991     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00992   GetPixelInfo(image,pixel);
00993   for (i=0; i < MaxDimension; i++)
00994   {
00995     histogram[i]=(ssize_t *) AcquireQuantumMemory(256UL,sizeof(**histogram));
00996     extrema[i]=(short *) AcquireQuantumMemory(256UL,sizeof(**histogram));
00997     if ((histogram[i] == (ssize_t *) NULL) || (extrema[i] == (short *) NULL))
00998       {
00999         for (i-- ; i >= 0; i--)
01000         {
01001           extrema[i]=(short *) RelinquishMagickMemory(extrema[i]);
01002           histogram[i]=(ssize_t *) RelinquishMagickMemory(histogram[i]);
01003         }
01004         (void) ThrowMagickException(exception,GetMagickModule(),
01005           ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
01006         return(MagickFalse);
01007       }
01008   }
01009   /*
01010     Initialize histogram.
01011   */
01012   InitializeHistogram(image,histogram,exception);
01013   (void) OptimalTau(histogram[Red],Tau,0.2f,DeltaTau,
01014     (smooth_threshold == 0.0f ? 1.0f : smooth_threshold),extrema[Red]);
01015   (void) OptimalTau(histogram[Green],Tau,0.2f,DeltaTau,
01016     (smooth_threshold == 0.0f ? 1.0f : smooth_threshold),extrema[Green]);
01017   (void) OptimalTau(histogram[Blue],Tau,0.2f,DeltaTau,
01018     (smooth_threshold == 0.0f ? 1.0f : smooth_threshold),extrema[Blue]);
01019   /*
01020     Form clusters.
01021   */
01022   cluster=(Cluster *) NULL;
01023   head=(Cluster *) NULL;
01024   (void) ResetMagickMemory(&red,0,sizeof(red));
01025   (void) ResetMagickMemory(&green,0,sizeof(green));
01026   (void) ResetMagickMemory(&blue,0,sizeof(blue));
01027   while (DefineRegion(extrema[Red],&red) != 0)
01028   {
01029     green.index=0;
01030     while (DefineRegion(extrema[Green],&green) != 0)
01031     {
01032       blue.index=0;
01033       while (DefineRegion(extrema[Blue],&blue) != 0)
01034       {
01035         /*
01036           Allocate a new class.
01037         */
01038         if (head != (Cluster *) NULL)
01039           {
01040             cluster->next=(Cluster *) AcquireMagickMemory(
01041               sizeof(*cluster->next));
01042             cluster=cluster->next;
01043           }
01044         else
01045           {
01046             cluster=(Cluster *) AcquireMagickMemory(sizeof(*cluster));
01047             head=cluster;
01048           }
01049         if (cluster == (Cluster *) NULL)
01050           {
01051             (void) ThrowMagickException(exception,GetMagickModule(),
01052               ResourceLimitError,"MemoryAllocationFailed","`%s'",
01053               image->filename);
01054             return(MagickFalse);
01055           }
01056         /*
01057           Initialize a new class.
01058         */
01059         cluster->count=0;
01060         cluster->red=red;
01061         cluster->green=green;
01062         cluster->blue=blue;
01063         cluster->next=(Cluster *) NULL;
01064       }
01065     }
01066   }
01067   if (head == (Cluster *) NULL)
01068     {
01069       /*
01070         No classes were identified-- create one.
01071       */
01072       cluster=(Cluster *) AcquireMagickMemory(sizeof(*cluster));
01073       if (cluster == (Cluster *) NULL)
01074         {
01075           (void) ThrowMagickException(exception,GetMagickModule(),
01076             ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
01077           return(MagickFalse);
01078         }
01079       /*
01080         Initialize a new class.
01081       */
01082       cluster->count=0;
01083       cluster->red=red;
01084       cluster->green=green;
01085       cluster->blue=blue;
01086       cluster->next=(Cluster *) NULL;
01087       head=cluster;
01088     }
01089   /*
01090     Count the pixels for each cluster.
01091   */
01092   count=0;
01093   for (y=0; y < (ssize_t) image->rows; y++)
01094   {
01095     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
01096     if (p == (const Quantum *) NULL)
01097       break;
01098     for (x=0; x < (ssize_t) image->columns; x++)
01099     {
01100       for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
01101         if (((ssize_t) ScaleQuantumToChar(GetPixelRed(image,p)) >=
01102              (cluster->red.left-SafeMargin)) &&
01103             ((ssize_t) ScaleQuantumToChar(GetPixelRed(image,p)) <=
01104              (cluster->red.right+SafeMargin)) &&
01105             ((ssize_t) ScaleQuantumToChar(GetPixelGreen(image,p)) >=
01106              (cluster->green.left-SafeMargin)) &&
01107             ((ssize_t) ScaleQuantumToChar(GetPixelGreen(image,p)) <=
01108              (cluster->green.right+SafeMargin)) &&
01109             ((ssize_t) ScaleQuantumToChar(GetPixelBlue(image,p)) >=
01110              (cluster->blue.left-SafeMargin)) &&
01111             ((ssize_t) ScaleQuantumToChar(GetPixelBlue(image,p)) <=
01112              (cluster->blue.right+SafeMargin)))
01113           {
01114             /*
01115               Count this pixel.
01116             */
01117             count++;
01118             cluster->red.center+=(MagickRealType) ScaleQuantumToChar(
01119               GetPixelRed(image,p));
01120             cluster->green.center+=(MagickRealType) ScaleQuantumToChar(
01121               GetPixelGreen(image,p));
01122             cluster->blue.center+=(MagickRealType) ScaleQuantumToChar(
01123               GetPixelBlue(image,p));
01124             cluster->count++;
01125             break;
01126           }
01127       p+=GetPixelChannels(image);
01128     }
01129     proceed=SetImageProgress(image,SegmentImageTag,(MagickOffsetType) y,
01130       2*image->rows);
01131     if (proceed == MagickFalse)
01132       break;
01133   }
01134   /*
01135     Remove clusters that do not meet minimum cluster threshold.
01136   */
01137   count=0;
01138   last_cluster=head;
01139   next_cluster=head;
01140   for (cluster=head; cluster != (Cluster *) NULL; cluster=next_cluster)
01141   {
01142     next_cluster=cluster->next;
01143     if ((cluster->count > 0) &&
01144         (cluster->count >= (count*cluster_threshold/100.0)))
01145       {
01146         /*
01147           Initialize cluster.
01148         */
01149         cluster->id=count;
01150         cluster->red.center/=cluster->count;
01151         cluster->green.center/=cluster->count;
01152         cluster->blue.center/=cluster->count;
01153         count++;
01154         last_cluster=cluster;
01155         continue;
01156       }
01157     /*
01158       Delete cluster.
01159     */
01160     if (cluster == head)
01161       head=next_cluster;
01162     else
01163       last_cluster->next=next_cluster;
01164     cluster=(Cluster *) RelinquishMagickMemory(cluster);
01165   }
01166   object=head;
01167   background=head;
01168   if (count > 1)
01169     {
01170       object=head->next;
01171       for (cluster=object; cluster->next != (Cluster *) NULL; )
01172       {
01173         if (cluster->count < object->count)
01174           object=cluster;
01175         cluster=cluster->next;
01176       }
01177       background=head->next;
01178       for (cluster=background; cluster->next != (Cluster *) NULL; )
01179       {
01180         if (cluster->count > background->count)
01181           background=cluster;
01182         cluster=cluster->next;
01183       }
01184     }
01185   threshold=(background->red.center+object->red.center)/2.0;
01186   pixel->red=(MagickRealType) ScaleCharToQuantum((unsigned char)
01187     (threshold+0.5));
01188   threshold=(background->green.center+object->green.center)/2.0;
01189   pixel->green=(MagickRealType) ScaleCharToQuantum((unsigned char)
01190     (threshold+0.5));
01191   threshold=(background->blue.center+object->blue.center)/2.0;
01192   pixel->blue=(MagickRealType) ScaleCharToQuantum((unsigned char)
01193     (threshold+0.5));
01194   /*
01195     Relinquish resources.
01196   */
01197   for (cluster=head; cluster != (Cluster *) NULL; cluster=next_cluster)
01198   {
01199     next_cluster=cluster->next;
01200     cluster=(Cluster *) RelinquishMagickMemory(cluster);
01201   }
01202   for (i=0; i < MaxDimension; i++)
01203   {
01204     extrema[i]=(short *) RelinquishMagickMemory(extrema[i]);
01205     histogram[i]=(ssize_t *) RelinquishMagickMemory(histogram[i]);
01206   }
01207   return(MagickTrue);
01208 }
01209 
01210 /*
01211 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01212 %                                                                             %
01213 %                                                                             %
01214 %                                                                             %
01215 +  I n i t i a l i z e H i s t o g r a m                                      %
01216 %                                                                             %
01217 %                                                                             %
01218 %                                                                             %
01219 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01220 %
01221 %  InitializeHistogram() computes the histogram for an image.
01222 %
01223 %  The format of the InitializeHistogram method is:
01224 %
01225 %      InitializeHistogram(const Image *image,ssize_t **histogram)
01226 %
01227 %  A description of each parameter follows.
01228 %
01229 %    o image: Specifies a pointer to an Image structure;  returned from
01230 %      ReadImage.
01231 %
01232 %    o histogram: Specifies an array of integers representing the number
01233 %      of pixels for each intensity of a particular color component.
01234 %
01235 */
01236 static void InitializeHistogram(const Image *image,ssize_t **histogram,
01237   ExceptionInfo *exception)
01238 {
01239   register const Quantum
01240     *p;
01241 
01242   register ssize_t
01243     i,
01244     x;
01245 
01246   ssize_t
01247     y;
01248 
01249   /*
01250     Initialize histogram.
01251   */
01252   for (i=0; i <= 255; i++)
01253   {
01254     histogram[Red][i]=0;
01255     histogram[Green][i]=0;
01256     histogram[Blue][i]=0;
01257   }
01258   for (y=0; y < (ssize_t) image->rows; y++)
01259   {
01260     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
01261     if (p == (const Quantum *) NULL)
01262       break;
01263     for (x=0; x < (ssize_t) image->columns; x++)
01264     {
01265       histogram[Red][(ssize_t) ScaleQuantumToChar(GetPixelRed(image,p))]++;
01266       histogram[Green][(ssize_t) ScaleQuantumToChar(GetPixelGreen(image,p))]++;
01267       histogram[Blue][(ssize_t) ScaleQuantumToChar(GetPixelBlue(image,p))]++;
01268       p+=GetPixelChannels(image);
01269     }
01270   }
01271 }
01272 
01273 /*
01274 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01275 %                                                                             %
01276 %                                                                             %
01277 %                                                                             %
01278 +   I n i t i a l i z e I n t e r v a l T r e e                               %
01279 %                                                                             %
01280 %                                                                             %
01281 %                                                                             %
01282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01283 %
01284 %  InitializeIntervalTree() initializes an interval tree from the lists of
01285 %  zero crossings.
01286 %
01287 %  The format of the InitializeIntervalTree method is:
01288 %
01289 %      InitializeIntervalTree(IntervalTree **list,ssize_t *number_nodes,
01290 %        IntervalTree *node)
01291 %
01292 %  A description of each parameter follows.
01293 %
01294 %    o zero_crossing: Specifies an array of structures of type ZeroCrossing.
01295 %
01296 %    o number_crossings: This size_t specifies the number of elements
01297 %      in the zero_crossing array.
01298 %
01299 */
01300 
01301 static void InitializeList(IntervalTree **list,ssize_t *number_nodes,
01302   IntervalTree *node)
01303 {
01304   if (node == (IntervalTree *) NULL)
01305     return;
01306   if (node->child == (IntervalTree *) NULL)
01307     list[(*number_nodes)++]=node;
01308   InitializeList(list,number_nodes,node->sibling);
01309   InitializeList(list,number_nodes,node->child);
01310 }
01311 
01312 static void MeanStability(IntervalTree *node)
01313 {
01314   register IntervalTree
01315     *child;
01316 
01317   if (node == (IntervalTree *) NULL)
01318     return;
01319   node->mean_stability=0.0;
01320   child=node->child;
01321   if (child != (IntervalTree *) NULL)
01322     {
01323       register ssize_t
01324         count;
01325 
01326       register MagickRealType
01327         sum;
01328 
01329       sum=0.0;
01330       count=0;
01331       for ( ; child != (IntervalTree *) NULL; child=child->sibling)
01332       {
01333         sum+=child->stability;
01334         count++;
01335       }
01336       node->mean_stability=sum/(MagickRealType) count;
01337     }
01338   MeanStability(node->sibling);
01339   MeanStability(node->child);
01340 }
01341 
01342 static void Stability(IntervalTree *node)
01343 {
01344   if (node == (IntervalTree *) NULL)
01345     return;
01346   if (node->child == (IntervalTree *) NULL)
01347     node->stability=0.0;
01348   else
01349     node->stability=node->tau-(node->child)->tau;
01350   Stability(node->sibling);
01351   Stability(node->child);
01352 }
01353 
01354 static IntervalTree *InitializeIntervalTree(const ZeroCrossing *zero_crossing,
01355   const size_t number_crossings)
01356 {
01357   IntervalTree
01358     *head,
01359     **list,
01360     *node,
01361     *root;
01362 
01363   register ssize_t
01364     i;
01365 
01366   ssize_t
01367     j,
01368     k,
01369     left,
01370     number_nodes;
01371 
01372   /*
01373     Allocate interval tree.
01374   */
01375   list=(IntervalTree **) AcquireQuantumMemory((size_t) TreeLength,
01376     sizeof(*list));
01377   if (list == (IntervalTree **) NULL)
01378     return((IntervalTree *) NULL);
01379   /*
01380     The root is the entire histogram.
01381   */
01382   root=(IntervalTree *) AcquireMagickMemory(sizeof(*root));
01383   root->child=(IntervalTree *) NULL;
01384   root->sibling=(IntervalTree *) NULL;
01385   root->tau=0.0;
01386   root->left=0;
01387   root->right=255;
01388   for (i=(-1); i < (ssize_t) number_crossings; i++)
01389   {
01390     /*
01391       Initialize list with all nodes with no children.
01392     */
01393     number_nodes=0;
01394     InitializeList(list,&number_nodes,root);
01395     /*
01396       Split list.
01397     */
01398     for (j=0; j < number_nodes; j++)
01399     {
01400       head=list[j];
01401       left=head->left;
01402       node=head;
01403       for (k=head->left+1; k < head->right; k++)
01404       {
01405         if (zero_crossing[i+1].crossings[k] != 0)
01406           {
01407             if (node == head)
01408               {
01409                 node->child=(IntervalTree *) AcquireMagickMemory(
01410                   sizeof(*node->child));
01411                 node=node->child;
01412               }
01413             else
01414               {
01415                 node->sibling=(IntervalTree *) AcquireMagickMemory(
01416                   sizeof(*node->sibling));
01417                 node=node->sibling;
01418               }
01419             node->tau=zero_crossing[i+1].tau;
01420             node->child=(IntervalTree *) NULL;
01421             node->sibling=(IntervalTree *) NULL;
01422             node->left=left;
01423             node->right=k;
01424             left=k;
01425           }
01426         }
01427       if (left != head->left)
01428         {
01429           node->sibling=(IntervalTree *) AcquireMagickMemory(
01430             sizeof(*node->sibling));
01431           node=node->sibling;
01432           node->tau=zero_crossing[i+1].tau;
01433           node->child=(IntervalTree *) NULL;
01434           node->sibling=(IntervalTree *) NULL;
01435           node->left=left;
01436           node->right=head->right;
01437         }
01438     }
01439   }
01440   /*
01441     Determine the stability: difference between a nodes tau and its child.
01442   */
01443   Stability(root->child);
01444   MeanStability(root->child);
01445   list=(IntervalTree **) RelinquishMagickMemory(list);
01446   return(root);
01447 }
01448 
01449 /*
01450 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01451 %                                                                             %
01452 %                                                                             %
01453 %                                                                             %
01454 +   O p t i m a l T a u                                                       %
01455 %                                                                             %
01456 %                                                                             %
01457 %                                                                             %
01458 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01459 %
01460 %  OptimalTau() finds the optimal tau for each band of the histogram.
01461 %
01462 %  The format of the OptimalTau method is:
01463 %
01464 %    MagickRealType OptimalTau(const ssize_t *histogram,const double max_tau,
01465 %      const double min_tau,const double delta_tau,
01466 %      const double smooth_threshold,short *extrema)
01467 %
01468 %  A description of each parameter follows.
01469 %
01470 %    o histogram: Specifies an array of integers representing the number
01471 %      of pixels for each intensity of a particular color component.
01472 %
01473 %    o extrema:  Specifies a pointer to an array of integers.  They
01474 %      represent the peaks and valleys of the histogram for each color
01475 %      component.
01476 %
01477 */
01478 
01479 static void ActiveNodes(IntervalTree **list,ssize_t *number_nodes,
01480   IntervalTree *node)
01481 {
01482   if (node == (IntervalTree *) NULL)
01483     return;
01484   if (node->stability >= node->mean_stability)
01485     {
01486       list[(*number_nodes)++]=node;
01487       ActiveNodes(list,number_nodes,node->sibling);
01488     }
01489   else
01490     {
01491       ActiveNodes(list,number_nodes,node->sibling);
01492       ActiveNodes(list,number_nodes,node->child);
01493     }
01494 }
01495 
01496 static void FreeNodes(IntervalTree *node)
01497 {
01498   if (node == (IntervalTree *) NULL)
01499     return;
01500   FreeNodes(node->sibling);
01501   FreeNodes(node->child);
01502   node=(IntervalTree *) RelinquishMagickMemory(node);
01503 }
01504 
01505 static MagickRealType OptimalTau(const ssize_t *histogram,const double max_tau,
01506   const double min_tau,const double delta_tau,const double smooth_threshold,
01507   short *extrema)
01508 {
01509   IntervalTree
01510     **list,
01511     *node,
01512     *root;
01513 
01514   MagickBooleanType
01515     peak;
01516 
01517   MagickRealType
01518     average_tau,
01519     *derivative,
01520     *second_derivative,
01521     tau,
01522     value;
01523 
01524   register ssize_t
01525     i,
01526     x;
01527 
01528   size_t
01529     count,
01530     number_crossings;
01531 
01532   ssize_t
01533     index,
01534     j,
01535     k,
01536     number_nodes;
01537 
01538   ZeroCrossing
01539     *zero_crossing;
01540 
01541   /*
01542     Allocate interval tree.
01543   */
01544   list=(IntervalTree **) AcquireQuantumMemory((size_t) TreeLength,
01545     sizeof(*list));
01546   if (list == (IntervalTree **) NULL)
01547     return(0.0);
01548   /*
01549     Allocate zero crossing list.
01550   */
01551   count=(size_t) ((max_tau-min_tau)/delta_tau)+2;
01552   zero_crossing=(ZeroCrossing *) AcquireQuantumMemory((size_t) count,
01553     sizeof(*zero_crossing));
01554   if (zero_crossing == (ZeroCrossing *) NULL)
01555     return(0.0);
01556   for (i=0; i < (ssize_t) count; i++)
01557     zero_crossing[i].tau=(-1.0);
01558   /*
01559     Initialize zero crossing list.
01560   */
01561   derivative=(MagickRealType *) AcquireQuantumMemory(256,sizeof(*derivative));
01562   second_derivative=(MagickRealType *) AcquireQuantumMemory(256,
01563     sizeof(*second_derivative));
01564   if ((derivative == (MagickRealType *) NULL) ||
01565       (second_derivative == (MagickRealType *) NULL))
01566     ThrowFatalException(ResourceLimitFatalError,
01567       "UnableToAllocateDerivatives");
01568   i=0;
01569   for (tau=max_tau; tau >= min_tau; tau-=delta_tau)
01570   {
01571     zero_crossing[i].tau=tau;
01572     ScaleSpace(histogram,tau,zero_crossing[i].histogram);
01573     DerivativeHistogram(zero_crossing[i].histogram,derivative);
01574     DerivativeHistogram(derivative,second_derivative);
01575     ZeroCrossHistogram(second_derivative,smooth_threshold,
01576       zero_crossing[i].crossings);
01577     i++;
01578   }
01579   /*
01580     Add an entry for the original histogram.
01581   */
01582   zero_crossing[i].tau=0.0;
01583   for (j=0; j <= 255; j++)
01584     zero_crossing[i].histogram[j]=(MagickRealType) histogram[j];
01585   DerivativeHistogram(zero_crossing[i].histogram,derivative);
01586   DerivativeHistogram(derivative,second_derivative);
01587   ZeroCrossHistogram(second_derivative,smooth_threshold,
01588     zero_crossing[i].crossings);
01589   number_crossings=(size_t) i;
01590   derivative=(MagickRealType *) RelinquishMagickMemory(derivative);
01591   second_derivative=(MagickRealType *)
01592     RelinquishMagickMemory(second_derivative);
01593   /*
01594     Ensure the scale-space fingerprints form lines in scale-space, not loops.
01595   */
01596   ConsolidateCrossings(zero_crossing,number_crossings);
01597   /*
01598     Force endpoints to be included in the interval.
01599   */
01600   for (i=0; i <= (ssize_t) number_crossings; i++)
01601   {
01602     for (j=0; j < 255; j++)
01603       if (zero_crossing[i].crossings[j] != 0)
01604         break;
01605     zero_crossing[i].crossings[0]=(-zero_crossing[i].crossings[j]);
01606     for (j=255; j > 0; j--)
01607       if (zero_crossing[i].crossings[j] != 0)
01608         break;
01609     zero_crossing[i].crossings[255]=(-zero_crossing[i].crossings[j]);
01610   }
01611   /*
01612     Initialize interval tree.
01613   */
01614   root=InitializeIntervalTree(zero_crossing,number_crossings);
01615   if (root == (IntervalTree *) NULL)
01616     return(0.0);
01617   /*
01618     Find active nodes:  stability is greater (or equal) to the mean stability of
01619     its children.
01620   */
01621   number_nodes=0;
01622   ActiveNodes(list,&number_nodes,root->child);
01623   /*
01624     Initialize extrema.
01625   */
01626   for (i=0; i <= 255; i++)
01627     extrema[i]=0;
01628   for (i=0; i < number_nodes; i++)
01629   {
01630     /*
01631       Find this tau in zero crossings list.
01632     */
01633     k=0;
01634     node=list[i];
01635     for (j=0; j <= (ssize_t) number_crossings; j++)
01636       if (zero_crossing[j].tau == node->tau)
01637         k=j;
01638     /*
01639       Find the value of the peak.
01640     */
01641     peak=zero_crossing[k].crossings[node->right] == -1 ? MagickTrue :
01642       MagickFalse;
01643     index=node->left;
01644     value=zero_crossing[k].histogram[index];
01645     for (x=node->left; x <= node->right; x++)
01646     {
01647       if (peak != MagickFalse)
01648         {
01649           if (zero_crossing[k].histogram[x] > value)
01650             {
01651               value=zero_crossing[k].histogram[x];
01652               index=x;
01653             }
01654         }
01655       else
01656         if (zero_crossing[k].histogram[x] < value)
01657           {
01658             value=zero_crossing[k].histogram[x];
01659             index=x;
01660           }
01661     }
01662     for (x=node->left; x <= node->right; x++)
01663     {
01664       if (index == 0)
01665         index=256;
01666       if (peak != MagickFalse)
01667         extrema[x]=(short) index;
01668       else
01669         extrema[x]=(short) (-index);
01670     }
01671   }
01672   /*
01673     Determine the average tau.
01674   */
01675   average_tau=0.0;
01676   for (i=0; i < number_nodes; i++)
01677     average_tau+=list[i]->tau;
01678   average_tau/=(MagickRealType) number_nodes;
01679   /*
01680     Relinquish resources.
01681   */
01682   FreeNodes(root);
01683   zero_crossing=(ZeroCrossing *) RelinquishMagickMemory(zero_crossing);
01684   list=(IntervalTree **) RelinquishMagickMemory(list);
01685   return(average_tau);
01686 }
01687 
01688 /*
01689 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01690 %                                                                             %
01691 %                                                                             %
01692 %                                                                             %
01693 +   S c a l e S p a c e                                                       %
01694 %                                                                             %
01695 %                                                                             %
01696 %                                                                             %
01697 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01698 %
01699 %  ScaleSpace() performs a scale-space filter on the 1D histogram.
01700 %
01701 %  The format of the ScaleSpace method is:
01702 %
01703 %      ScaleSpace(const ssize_t *histogram,const MagickRealType tau,
01704 %        MagickRealType *scale_histogram)
01705 %
01706 %  A description of each parameter follows.
01707 %
01708 %    o histogram: Specifies an array of MagickRealTypes representing the number
01709 %      of pixels for each intensity of a particular color component.
01710 %
01711 */
01712 
01713 static void ScaleSpace(const ssize_t *histogram,const MagickRealType tau,
01714   MagickRealType *scale_histogram)
01715 {
01716   MagickRealType
01717     alpha,
01718     beta,
01719     *gamma,
01720     sum;
01721 
01722   register ssize_t
01723     u,
01724     x;
01725 
01726   gamma=(MagickRealType *) AcquireQuantumMemory(256,sizeof(*gamma));
01727   if (gamma == (MagickRealType *) NULL)
01728     ThrowFatalException(ResourceLimitFatalError,
01729       "UnableToAllocateGammaMap");
01730   alpha=1.0/(tau*sqrt(2.0*MagickPI));
01731   beta=(-1.0/(2.0*tau*tau));
01732   for (x=0; x <= 255; x++)
01733     gamma[x]=0.0;
01734   for (x=0; x <= 255; x++)
01735   {
01736     gamma[x]=exp((double) beta*x*x);
01737     if (gamma[x] < MagickEpsilon)
01738       break;
01739   }
01740   for (x=0; x <= 255; x++)
01741   {
01742     sum=0.0;
01743     for (u=0; u <= 255; u++)
01744       sum+=(MagickRealType) histogram[u]*gamma[MagickAbsoluteValue(x-u)];
01745     scale_histogram[x]=alpha*sum;
01746   }
01747   gamma=(MagickRealType *) RelinquishMagickMemory(gamma);
01748 }
01749 
01750 /*
01751 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01752 %                                                                             %
01753 %                                                                             %
01754 %                                                                             %
01755 %  S e g m e n t I m a g e                                                    %
01756 %                                                                             %
01757 %                                                                             %
01758 %                                                                             %
01759 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01760 %
01761 %  SegmentImage() segment an image by analyzing the histograms of the color
01762 %  components and identifying units that are homogeneous with the fuzzy
01763 %  C-means technique.
01764 %
01765 %  The format of the SegmentImage method is:
01766 %
01767 %      MagickBooleanType SegmentImage(Image *image,
01768 %        const ColorspaceType colorspace,const MagickBooleanType verbose,
01769 %        const double cluster_threshold,const double smooth_threshold,
01770 %        ExceptionInfo *exception)
01771 %
01772 %  A description of each parameter follows.
01773 %
01774 %    o image: the image.
01775 %
01776 %    o colorspace: Indicate the colorspace.
01777 %
01778 %    o verbose:  Set to MagickTrue to print detailed information about the
01779 %      identified classes.
01780 %
01781 %    o cluster_threshold:  This represents the minimum number of pixels
01782 %      contained in a hexahedra before it can be considered valid (expressed
01783 %      as a percentage).
01784 %
01785 %    o smooth_threshold: the smoothing threshold eliminates noise in the second
01786 %      derivative of the histogram.  As the value is increased, you can expect a
01787 %      smoother second derivative.
01788 %
01789 %    o exception: return any errors or warnings in this structure.
01790 %
01791 */
01792 MagickExport MagickBooleanType SegmentImage(Image *image,
01793   const ColorspaceType colorspace,const MagickBooleanType verbose,
01794   const double cluster_threshold,const double smooth_threshold,
01795   ExceptionInfo *exception)
01796 {
01797   MagickBooleanType
01798     status;
01799 
01800   register ssize_t
01801     i;
01802 
01803   short
01804     *extrema[MaxDimension];
01805 
01806   ssize_t
01807     *histogram[MaxDimension];
01808 
01809   /*
01810     Allocate histogram and extrema.
01811   */
01812   assert(image != (Image *) NULL);
01813   assert(image->signature == MagickSignature);
01814   if (image->debug != MagickFalse)
01815     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01816   for (i=0; i < MaxDimension; i++)
01817   {
01818     histogram[i]=(ssize_t *) AcquireQuantumMemory(256,sizeof(**histogram));
01819     extrema[i]=(short *) AcquireQuantumMemory(256,sizeof(**extrema));
01820     if ((histogram[i] == (ssize_t *) NULL) || (extrema[i] == (short *) NULL))
01821       {
01822         for (i-- ; i >= 0; i--)
01823         {
01824           extrema[i]=(short *) RelinquishMagickMemory(extrema[i]);
01825           histogram[i]=(ssize_t *) RelinquishMagickMemory(histogram[i]);
01826         }
01827         ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
01828           image->filename)
01829       }
01830   }
01831   if (IsRGBColorspace(colorspace) == MagickFalse)
01832     (void) TransformImageColorspace(image,colorspace,exception);
01833   /*
01834     Initialize histogram.
01835   */
01836   InitializeHistogram(image,histogram,exception);
01837   (void) OptimalTau(histogram[Red],Tau,0.2,DeltaTau,
01838     smooth_threshold == 0.0 ? 1.0 : smooth_threshold,extrema[Red]);
01839   (void) OptimalTau(histogram[Green],Tau,0.2,DeltaTau,
01840     smooth_threshold == 0.0 ? 1.0 : smooth_threshold,extrema[Green]);
01841   (void) OptimalTau(histogram[Blue],Tau,0.2,DeltaTau,
01842     smooth_threshold == 0.0 ? 1.0 : smooth_threshold,extrema[Blue]);
01843   /*
01844     Classify using the fuzzy c-Means technique.
01845   */
01846   status=Classify(image,extrema,cluster_threshold,WeightingExponent,verbose,
01847     exception);
01848   if (IsRGBColorspace(colorspace) == MagickFalse)
01849     (void) TransformImageColorspace(image,colorspace,exception);
01850   /*
01851     Relinquish resources.
01852   */
01853   for (i=0; i < MaxDimension; i++)
01854   {
01855     extrema[i]=(short *) RelinquishMagickMemory(extrema[i]);
01856     histogram[i]=(ssize_t *) RelinquishMagickMemory(histogram[i]);
01857   }
01858   return(status);
01859 }
01860 
01861 /*
01862 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01863 %                                                                             %
01864 %                                                                             %
01865 %                                                                             %
01866 +   Z e r o C r o s s H i s t o g r a m                                       %
01867 %                                                                             %
01868 %                                                                             %
01869 %                                                                             %
01870 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01871 %
01872 %  ZeroCrossHistogram() find the zero crossings in a histogram and marks
01873 %  directions as:  1 is negative to positive; 0 is zero crossing; and -1
01874 %  is positive to negative.
01875 %
01876 %  The format of the ZeroCrossHistogram method is:
01877 %
01878 %      ZeroCrossHistogram(MagickRealType *second_derivative,
01879 %        const MagickRealType smooth_threshold,short *crossings)
01880 %
01881 %  A description of each parameter follows.
01882 %
01883 %    o second_derivative: Specifies an array of MagickRealTypes representing the
01884 %      second derivative of the histogram of a particular color component.
01885 %
01886 %    o crossings:  This array of integers is initialized with
01887 %      -1, 0, or 1 representing the slope of the first derivative of the
01888 %      of a particular color component.
01889 %
01890 */
01891 static void ZeroCrossHistogram(MagickRealType *second_derivative,
01892   const MagickRealType smooth_threshold,short *crossings)
01893 {
01894   register ssize_t
01895     i;
01896 
01897   ssize_t
01898     parity;
01899 
01900   /*
01901     Merge low numbers to zero to help prevent noise.
01902   */
01903   for (i=0; i <= 255; i++)
01904     if ((second_derivative[i] < smooth_threshold) &&
01905         (second_derivative[i] >= -smooth_threshold))
01906       second_derivative[i]=0.0;
01907   /*
01908     Mark zero crossings.
01909   */
01910   parity=0;
01911   for (i=0; i <= 255; i++)
01912   {
01913     crossings[i]=0;
01914     if (second_derivative[i] < 0.0)
01915       {
01916         if (parity > 0)
01917           crossings[i]=(-1);
01918         parity=1;
01919       }
01920     else
01921       if (second_derivative[i] > 0.0)
01922         {
01923           if (parity < 0)
01924             crossings[i]=1;
01925           parity=(-1);
01926         }
01927   }
01928 }