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-2008 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 "magick/studio.h"
00086 #include "magick/cache.h"
00087 #include "magick/color.h"
00088 #include "magick/colorspace.h"
00089 #include "magick/exception.h"
00090 #include "magick/exception-private.h"
00091 #include "magick/image.h"
00092 #include "magick/image-private.h"
00093 #include "magick/memory_.h"
00094 #include "magick/monitor.h"
00095 #include "magick/monitor-private.h"
00096 #include "magick/quantize.h"
00097 #include "magick/quantum.h"
00098 #include "magick/quantum-private.h"
00099 #include "magick/segment.h"
00100 #include "magick/string_.h"
00101 
00102 /*
00103   Define declarations.
00104 */
00105 #define MaxDimension  3
00106 #define DeltaTau  0.5f
00107 #if defined(FastClassify)
00108 #define WeightingExponent  2.0
00109 #define SegmentPower(ratio) (ratio)
00110 #else
00111 #define WeightingExponent  2.5
00112 #define SegmentPower(ratio) pow(ratio,(double) (1.0/(weighting_exponent-1.0)));
00113 #endif
00114 #define Tau  5.2f
00115 
00116 /*
00117   Typedef declarations.
00118 */
00119 typedef struct _ExtentPacket
00120 {
00121   MagickRealType
00122     center;
00123 
00124   long
00125     index,
00126     left,
00127     right;
00128 } ExtentPacket;
00129 
00130 typedef struct _Cluster
00131 {
00132   struct _Cluster
00133     *next;
00134 
00135   ExtentPacket
00136     red,
00137     green,
00138     blue;
00139 
00140   long
00141     count,
00142     id;
00143 } Cluster;
00144 
00145 typedef struct _IntervalTree
00146 {
00147   MagickRealType
00148     tau;
00149 
00150   long
00151     left,
00152     right;
00153 
00154   MagickRealType
00155     mean_stability,
00156     stability;
00157 
00158   struct _IntervalTree
00159     *sibling,
00160     *child;
00161 } IntervalTree;
00162 
00163 typedef struct _ZeroCrossing
00164 {
00165   MagickRealType
00166     tau,
00167     histogram[256];
00168 
00169   short
00170     crossings[256];
00171 } ZeroCrossing;
00172 
00173 /*
00174   Constant declarations.
00175 */
00176 static const int
00177   Blue = 2,
00178   Green = 1,
00179   Red = 0,
00180   SafeMargin = 3,
00181   TreeLength = 600;
00182 
00183 /*
00184   Method prototypes.
00185 */
00186 static MagickRealType
00187   OptimalTau(const long *,const double,const double,const double,
00188     const double,short *);
00189 
00190 static long
00191   DefineRegion(const short *,ExtentPacket *);
00192 
00193 static void
00194   InitializeHistogram(const Image *,long **,ExceptionInfo *),
00195   ScaleSpace(const long *,const MagickRealType,MagickRealType *),
00196   ZeroCrossHistogram(MagickRealType *,const MagickRealType,short *);
00197 
00198 /*
00199 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00200 %                                                                             %
00201 %                                                                             %
00202 %                                                                             %
00203 +   C l a s s i f y                                                           %
00204 %                                                                             %
00205 %                                                                             %
00206 %                                                                             %
00207 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00208 %
00209 %  Classify() defines one or more classes.  Each pixel is thresholded to
00210 %  determine which class it belongs to.  If the class is not identified it is
00211 %  assigned to the closest class based on the fuzzy c-Means technique.
00212 %
00213 %  The format of the Classify method is:
00214 %
00215 %      MagickBooleanType Classify(Image *image,short **extrema,
00216 %        const MagickRealType cluster_threshold,
00217 %        const MagickRealType weighting_exponent,
00218 %        const MagickBooleanType verbose)
00219 %
00220 %  A description of each parameter follows.
00221 %
00222 %    o image: the image.
00223 %
00224 %    o extrema:  Specifies a pointer to an array of integers.  They
00225 %      represent the peaks and valleys of the histogram for each color
00226 %      component.
00227 %
00228 %    o cluster_threshold:  This MagickRealType represents the minimum number of
00229 %      pixels contained in a hexahedra before it can be considered valid
00230 %      (expressed as a percentage).
00231 %
00232 %    o weighting_exponent: Specifies the membership weighting exponent.
00233 %
00234 %    o verbose:  A value greater than zero prints detailed information about
00235 %      the identified classes.
00236 %
00237 */
00238 static MagickBooleanType Classify(Image *image,short **extrema,
00239   const MagickRealType cluster_threshold,
00240   const MagickRealType weighting_exponent,const MagickBooleanType verbose)
00241 {
00242 #define SegmentImageTag  "Segment/Image"
00243 
00244   Cluster
00245     *cluster,
00246     *head,
00247     *last_cluster,
00248     *next_cluster;
00249 
00250   ExceptionInfo
00251     *exception;
00252 
00253   ExtentPacket
00254     blue,
00255     green,
00256     red;
00257 
00258   IndexPacket
00259     index;
00260 
00261   long
00262     count,
00263     j,
00264     k,
00265     y;
00266 
00267   MagickBooleanType
00268     proceed;
00269 
00270   MagickRealType
00271     distance_squared,
00272     *free_squares,
00273     local_minima,
00274     numerator,
00275     ratio,
00276     sum;
00277 
00278   register const PixelPacket
00279     *p;
00280 
00281   register IndexPacket
00282     *indexes;
00283 
00284   register long
00285     i,
00286     x;
00287 
00288   register MagickRealType
00289     *squares;
00290 
00291   register PixelPacket
00292     *q;
00293 
00294   unsigned long
00295     number_clusters;
00296 
00297   /*
00298     Form clusters.
00299   */
00300   cluster=(Cluster *) NULL;
00301   head=(Cluster *) NULL;
00302   (void) ResetMagickMemory(&red,0,sizeof(red));
00303   (void) ResetMagickMemory(&green,0,sizeof(green));
00304   (void) ResetMagickMemory(&blue,0,sizeof(blue));
00305   while (DefineRegion(extrema[Red],&red) != 0)
00306   {
00307     green.index=0;
00308     while (DefineRegion(extrema[Green],&green) != 0)
00309     {
00310       blue.index=0;
00311       while (DefineRegion(extrema[Blue],&blue) != 0)
00312       {
00313         /*
00314           Allocate a new class.
00315         */
00316         if (head != (Cluster *) NULL)
00317           {
00318             cluster->next=(Cluster *) AcquireMagickMemory(
00319               sizeof(*cluster->next));
00320             cluster=cluster->next;
00321           }
00322         else
00323           {
00324             cluster=(Cluster *) AcquireMagickMemory(sizeof(*cluster));
00325             head=cluster;
00326           }
00327         if (cluster == (Cluster *) NULL)
00328           ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
00329             image->filename);
00330         /*
00331           Initialize a new class.
00332         */
00333         cluster->count=0;
00334         cluster->red=red;
00335         cluster->green=green;
00336         cluster->blue=blue;
00337         cluster->next=(Cluster *) NULL;
00338       }
00339     }
00340   }
00341   if (head == (Cluster *) NULL)
00342     {
00343       /*
00344         No classes were identified-- create one.
00345       */
00346       cluster=(Cluster *) AcquireMagickMemory(sizeof(*cluster));
00347       if (cluster == (Cluster *) NULL)
00348         ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
00349           image->filename);
00350       /*
00351         Initialize a new class.
00352       */
00353       cluster->count=0;
00354       cluster->red=red;
00355       cluster->green=green;
00356       cluster->blue=blue;
00357       cluster->next=(Cluster *) NULL;
00358       head=cluster;
00359     }
00360   /*
00361     Count the pixels for each cluster.
00362   */
00363   count=0;
00364   exception=(&image->exception);
00365   for (y=0; y < (long) image->rows; y++)
00366   {
00367     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
00368     if (p == (const PixelPacket *) NULL)
00369       break;
00370     for (x=0; x < (long) image->columns; x++)
00371     {
00372       for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
00373         if (((long) ScaleQuantumToChar(p->red) >=
00374              (cluster->red.left-SafeMargin)) &&
00375             ((long) ScaleQuantumToChar(p->red) <=
00376              (cluster->red.right+SafeMargin)) &&
00377             ((long) ScaleQuantumToChar(p->green) >=
00378              (cluster->green.left-SafeMargin)) &&
00379             ((long) ScaleQuantumToChar(p->green) <=
00380              (cluster->green.right+SafeMargin)) &&
00381             ((long) ScaleQuantumToChar(p->blue) >=
00382              (cluster->blue.left-SafeMargin)) &&
00383             ((long) ScaleQuantumToChar(p->blue) <=
00384              (cluster->blue.right+SafeMargin)))
00385           {
00386             /*
00387               Count this pixel.
00388             */
00389             count++;
00390             cluster->red.center+=(MagickRealType) ScaleQuantumToChar(p->red);
00391             cluster->green.center+=(MagickRealType)
00392               ScaleQuantumToChar(p->green);
00393             cluster->blue.center+=(MagickRealType) ScaleQuantumToChar(p->blue);
00394             cluster->count++;
00395             break;
00396           }
00397       p++;
00398     }
00399     proceed=SetImageProgress(image,SegmentImageTag,y,2*image->rows);
00400     if (proceed == MagickFalse)
00401       break;
00402   }
00403   /*
00404     Remove clusters that do not meet minimum cluster threshold.
00405   */
00406   count=0;
00407   last_cluster=head;
00408   next_cluster=head;
00409   for (cluster=head; cluster != (Cluster *) NULL; cluster=next_cluster)
00410   {
00411     next_cluster=cluster->next;
00412     if ((cluster->count > 0) &&
00413         (cluster->count >= (count*cluster_threshold/100.0)))
00414       {
00415         /*
00416           Initialize cluster.
00417         */
00418         cluster->id=count;
00419         cluster->red.center/=cluster->count;
00420         cluster->green.center/=cluster->count;
00421         cluster->blue.center/=cluster->count;
00422         count++;
00423         last_cluster=cluster;
00424         continue;
00425       }
00426     /*
00427       Delete cluster.
00428     */
00429     if (cluster == head)
00430       head=next_cluster;
00431     else
00432       last_cluster->next=next_cluster;
00433     cluster=(Cluster *) RelinquishMagickMemory(cluster);
00434   }
00435   number_clusters=(unsigned long) count;
00436   if (verbose != MagickFalse)
00437     {
00438       /*
00439         Print cluster statistics.
00440       */
00441       (void) fprintf(stdout,"Fuzzy C-means Statistics\n");
00442       (void) fprintf(stdout,"===================\n\n");
00443       (void) fprintf(stdout,"\tTotal Number of Clusters = %lu\n\n",
00444         number_clusters);
00445       /*
00446         Print the total number of points per cluster.
00447       */
00448       (void) fprintf(stdout,"\n\nNumber of Vectors Per Cluster\n");
00449       (void) fprintf(stdout,"=============================\n\n");
00450       for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
00451         (void) fprintf(stdout,"Cluster #%ld = %ld\n",cluster->id,
00452           cluster->count);
00453       /*
00454         Print the cluster extents.
00455       */
00456       (void) fprintf(stdout,
00457         "\n\n\nCluster Extents:        (Vector Size: %d)\n",MaxDimension);
00458       (void) fprintf(stdout,"================");
00459       for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
00460       {
00461         (void) fprintf(stdout,"\n\nCluster #%ld\n\n",cluster->id);
00462         (void) fprintf(stdout,"%ld-%ld  %ld-%ld  %ld-%ld\n",cluster->red.left,
00463           cluster->red.right,cluster->green.left,cluster->green.right,
00464           cluster->blue.left,cluster->blue.right);
00465       }
00466       /*
00467         Print the cluster center values.
00468       */
00469       (void) fprintf(stdout,
00470         "\n\n\nCluster Center Values:        (Vector Size: %d)\n",MaxDimension);
00471       (void) fprintf(stdout,"=====================");
00472       for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
00473       {
00474         (void) fprintf(stdout,"\n\nCluster #%ld\n\n",cluster->id);
00475         (void) fprintf(stdout,"%g  %g  %g\n",(double) cluster->red.center,
00476           (double) cluster->green.center,(double) cluster->blue.center);
00477       }
00478       (void) fprintf(stdout,"\n");
00479     }
00480   if (number_clusters > 256)
00481     ThrowBinaryException(ImageError,"TooManyClusters",image->filename);
00482   /*
00483     Speed up distance calculations.
00484   */
00485   squares=(MagickRealType *) AcquireQuantumMemory(513UL,sizeof(*squares));
00486   if (squares == (MagickRealType *) NULL)
00487     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
00488       image->filename);
00489   squares+=255;
00490   for (i=(-255); i <= 255; i++)
00491     squares[i]=(MagickRealType) i*(MagickRealType) i;
00492   /*
00493     Allocate image colormap.
00494   */
00495   if (AcquireImageColormap(image,number_clusters) == MagickFalse)
00496     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
00497       image->filename);
00498   cluster=head;
00499   for (i=0; i < (long) number_clusters; i++)
00500   {
00501     image->colormap[i].red=ScaleCharToQuantum((unsigned char)
00502       (cluster->red.center+0.5));
00503     image->colormap[i].green=ScaleCharToQuantum((unsigned char)
00504       (cluster->green.center+0.5));
00505     image->colormap[i].blue=ScaleCharToQuantum((unsigned char)
00506        (cluster->blue.center+0.5));
00507     cluster=cluster->next;
00508   }
00509   /*
00510     Do course grain classes.
00511   */
00512   exception=(&image->exception);
00513   for (y=0; y < (long) image->rows; y++)
00514   {
00515     q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
00516     if (q == (PixelPacket *) NULL)
00517       break;
00518     indexes=GetAuthenticIndexQueue(image);
00519     for (x=0; x < (long) image->columns; x++)
00520     {
00521       index=(IndexPacket) 0;
00522       cluster=head;
00523       for (i=0; i < (long) number_clusters; i++)
00524       {
00525         if (((long) ScaleQuantumToChar(q->red) >=
00526              (cluster->red.left-SafeMargin)) &&
00527             ((long) ScaleQuantumToChar(q->red) <=
00528              (cluster->red.right+SafeMargin)) &&
00529             ((long) ScaleQuantumToChar(q->green) >=
00530              (cluster->green.left-SafeMargin)) &&
00531             ((long) ScaleQuantumToChar(q->green) <=
00532              (cluster->green.right+SafeMargin)) &&
00533             ((long) ScaleQuantumToChar(q->blue) >=
00534              (cluster->blue.left-SafeMargin)) &&
00535             ((long) ScaleQuantumToChar(q->blue) <=
00536              (cluster->blue.right+SafeMargin)))
00537           {
00538             /*
00539               Classify this pixel.
00540             */
00541             index=(IndexPacket) cluster->id;
00542             break;
00543           }
00544         cluster=cluster->next;
00545       }
00546       if (cluster == (Cluster *) NULL)
00547         {
00548           /*
00549             Compute fuzzy membership.
00550           */
00551           local_minima=0.0;
00552           for (j=0; j < (long) image->colors; j++)
00553           {
00554             sum=0.0;
00555             p=image->colormap+j;
00556             distance_squared=squares[(long) ScaleQuantumToChar(q->red)-
00557               (long) ScaleQuantumToChar(p->red)]+
00558               squares[(long) ScaleQuantumToChar(q->green)-
00559               (long) ScaleQuantumToChar(p->green)]+
00560               squares[(long) ScaleQuantumToChar(q->blue)-
00561               (long) ScaleQuantumToChar(p->blue)];
00562             numerator=distance_squared;
00563             for (k=0; k < (long) image->colors; k++)
00564             {
00565               p=image->colormap+k;
00566               distance_squared=squares[(long) ScaleQuantumToChar(q->red)-
00567                 (long) ScaleQuantumToChar(p->red)]+
00568                 squares[(long) ScaleQuantumToChar(q->green)-
00569                 (long) ScaleQuantumToChar(p->green)]+
00570                 squares[(long) ScaleQuantumToChar(q->blue)-
00571                 (long) ScaleQuantumToChar(p->blue)];
00572               ratio=numerator/distance_squared;
00573               sum+=SegmentPower(ratio);
00574             }
00575             if ((sum != 0.0) && ((1.0/sum) > local_minima))
00576               {
00577                 /*
00578                   Classify this pixel.
00579                 */
00580                 local_minima=1.0/sum;
00581                 index=(IndexPacket) j;
00582               }
00583           }
00584         }
00585       indexes[x]=index;
00586       *q=image->colormap[(long) index];
00587       q++;
00588     }
00589     if (SyncAuthenticPixels(image,exception) == MagickFalse)
00590       break;
00591     proceed=SetImageProgress(image,SegmentImageTag,y,2*image->rows);
00592     if (proceed == MagickFalse)
00593       break;
00594   }
00595   /*
00596     Relinquish resources.
00597   */
00598   for (cluster=head; cluster != (Cluster *) NULL; cluster=next_cluster)
00599   {
00600     next_cluster=cluster->next;
00601     cluster=(Cluster *) RelinquishMagickMemory(cluster);
00602   }
00603   squares-=255;
00604   free_squares=squares;
00605   free_squares=(MagickRealType *) RelinquishMagickMemory(free_squares);
00606   return(MagickTrue);
00607 }
00608 
00609 /*
00610 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00611 %                                                                             %
00612 %                                                                             %
00613 %                                                                             %
00614 +   C o n s o l i d a t e C r o s s i n g s                                   %
00615 %                                                                             %
00616 %                                                                             %
00617 %                                                                             %
00618 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00619 %
00620 %  ConsolidateCrossings() guarantees that an even number of zero crossings
00621 %  always lie between two crossings.
00622 %
00623 %  The format of the ConsolidateCrossings method is:
00624 %
00625 %      ConsolidateCrossings(ZeroCrossing *zero_crossing,
00626 %        const unsigned long number_crossings)
00627 %
00628 %  A description of each parameter follows.
00629 %
00630 %    o zero_crossing: Specifies an array of structures of type ZeroCrossing.
00631 %
00632 %    o number_crossings: This unsigned long specifies the number of elements
00633 %      in the zero_crossing array.
00634 %
00635 */
00636 
00637 static inline long MagickAbsoluteValue(const long x)
00638 {
00639   if (x < 0)
00640     return(-x);
00641   return(x);
00642 }
00643 
00644 static inline long MagickMax(const long x,const long y)
00645 {
00646   if (x > y)
00647     return(x);
00648   return(y);
00649 }
00650 
00651 static inline long MagickMin(const long x,const long y)
00652 {
00653   if (x < y)
00654     return(x);
00655   return(y);
00656 }
00657 
00658 static void ConsolidateCrossings(ZeroCrossing *zero_crossing,
00659   const unsigned long number_crossings)
00660 {
00661   long
00662     center,
00663     correct,
00664     count,
00665     left,
00666     right;
00667 
00668   register long
00669     i,
00670     j,
00671     k,
00672     l;
00673 
00674   /*
00675     Consolidate zero crossings.
00676   */
00677   for (i=(long) number_crossings-1; i >= 0; i--)
00678     for (j=0; j <= 255; j++)
00679     {
00680       if (zero_crossing[i].crossings[j] == 0)
00681         continue;
00682       /*
00683         Find the entry that is closest to j and still preserves the
00684         property that there are an even number of crossings between
00685         intervals.
00686       */
00687       for (k=j-1; k > 0; k--)
00688         if (zero_crossing[i+1].crossings[k] != 0)
00689           break;
00690       left=MagickMax(k,0);
00691       center=j;
00692       for (k=j+1; k < 255; k++)
00693         if (zero_crossing[i+1].crossings[k] != 0)
00694           break;
00695       right=MagickMin(k,255);
00696       /*
00697         K is the zero crossing just left of j.
00698       */
00699       for (k=j-1; k > 0; k--)
00700         if (zero_crossing[i].crossings[k] != 0)
00701           break;
00702       if (k < 0)
00703         k=0;
00704       /*
00705         Check center for an even number of crossings between k and j.
00706       */
00707       correct=(-1);
00708       if (zero_crossing[i+1].crossings[j] != 0)
00709         {
00710           count=0;
00711           for (l=k+1; l < center; l++)
00712             if (zero_crossing[i+1].crossings[l] != 0)
00713               count++;
00714           if (((count % 2) == 0) && (center != k))
00715             correct=center;
00716         }
00717       /*
00718         Check left for an even number of crossings between k and j.
00719       */
00720       if (correct == -1)
00721         {
00722           count=0;
00723           for (l=k+1; l < left; l++)
00724             if (zero_crossing[i+1].crossings[l] != 0)
00725               count++;
00726           if (((count % 2) == 0) && (left != k))
00727             correct=left;
00728         }
00729       /*
00730         Check right for an even number of crossings between k and j.
00731       */
00732       if (correct == -1)
00733         {
00734           count=0;
00735           for (l=k+1; l < right; l++)
00736             if (zero_crossing[i+1].crossings[l] != 0)
00737               count++;
00738           if (((count % 2) == 0) && (right != k))
00739             correct=right;
00740         }
00741       l=zero_crossing[i].crossings[j];
00742       zero_crossing[i].crossings[j]=0;
00743       if (correct != -1)
00744         zero_crossing[i].crossings[correct]=(short) l;
00745     }
00746 }
00747 
00748 /*
00749 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00750 %                                                                             %
00751 %                                                                             %
00752 %                                                                             %
00753 +   D e f i n e R e g i o n                                                   %
00754 %                                                                             %
00755 %                                                                             %
00756 %                                                                             %
00757 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00758 %
00759 %  DefineRegion() defines the left and right boundaries of a peak region.
00760 %
00761 %  The format of the DefineRegion method is:
00762 %
00763 %      long DefineRegion(const short *extrema,ExtentPacket *extents)
00764 %
00765 %  A description of each parameter follows.
00766 %
00767 %    o extrema:  Specifies a pointer to an array of integers.  They
00768 %      represent the peaks and valleys of the histogram for each color
00769 %      component.
00770 %
00771 %    o extents:  This pointer to an ExtentPacket represent the extends
00772 %      of a particular peak or valley of a color component.
00773 %
00774 */
00775 static long DefineRegion(const short *extrema,ExtentPacket *extents)
00776 {
00777   /*
00778     Initialize to default values.
00779   */
00780   extents->left=0;
00781   extents->center=0.0;
00782   extents->right=255;
00783   /*
00784     Find the left side (maxima).
00785   */
00786   for ( ; extents->index <= 255; extents->index++)
00787     if (extrema[extents->index] > 0)
00788       break;
00789   if (extents->index > 255)
00790     return(MagickFalse);  /* no left side - no region exists */
00791   extents->left=extents->index;
00792   /*
00793     Find the right side (minima).
00794   */
00795   for ( ; extents->index <= 255; extents->index++)
00796     if (extrema[extents->index] < 0)
00797       break;
00798   extents->right=extents->index-1;
00799   return(MagickTrue);
00800 }
00801 
00802 /*
00803 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00804 %                                                                             %
00805 %                                                                             %
00806 %                                                                             %
00807 +   D e r i v a t i v e H i s t o g r a m                                     %
00808 %                                                                             %
00809 %                                                                             %
00810 %                                                                             %
00811 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00812 %
00813 %  DerivativeHistogram() determines the derivative of the histogram using
00814 %  central differencing.
00815 %
00816 %  The format of the DerivativeHistogram method is:
00817 %
00818 %      DerivativeHistogram(const MagickRealType *histogram,
00819 %        MagickRealType *derivative)
00820 %
00821 %  A description of each parameter follows.
00822 %
00823 %    o histogram: Specifies an array of MagickRealTypes representing the number
00824 %      of pixels for each intensity of a particular color component.
00825 %
00826 %    o derivative: This array of MagickRealTypes is initialized by
00827 %      DerivativeHistogram to the derivative of the histogram using central
00828 %      differencing.
00829 %
00830 */
00831 static void DerivativeHistogram(const MagickRealType *histogram,
00832   MagickRealType *derivative)
00833 {
00834   register long
00835     i,
00836     n;
00837 
00838   /*
00839     Compute endpoints using second order polynomial interpolation.
00840   */
00841   n=255;
00842   derivative[0]=(-1.5*histogram[0]+2.0*histogram[1]-0.5*histogram[2]);
00843   derivative[n]=(0.5*histogram[n-2]-2.0*histogram[n-1]+1.5*histogram[n]);
00844   /*
00845     Compute derivative using central differencing.
00846   */
00847   for (i=1; i < n; i++)
00848     derivative[i]=(histogram[i+1]-histogram[i-1])/2.0;
00849   return;
00850 }
00851 
00852 /*
00853 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00854 %                                                                             %
00855 %                                                                             %
00856 %                                                                             %
00857 +  G e t I m a g e D y n a m i c T h r e s h o l d                            %
00858 %                                                                             %
00859 %                                                                             %
00860 %                                                                             %
00861 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00862 %
00863 %  GetImageDynamicThreshold() returns the dynamic threshold for an image.
00864 %
00865 %  The format of the GetImageDynamicThreshold method is:
00866 %
00867 %      MagickBooleanType GetImageDynamicThreshold(const Image *image,
00868 %        const double cluster_threshold,const double smooth_threshold,
00869 %        MagickPixelPacket *pixel,ExceptionInfo *exception)
00870 %
00871 %  A description of each parameter follows.
00872 %
00873 %    o image: the image.
00874 %
00875 %    o cluster_threshold:  This MagickRealType represents the minimum number of
00876 %      pixels contained in a hexahedra before it can be considered valid
00877 %      (expressed as a percentage).
00878 %
00879 %    o smooth_threshold: the smoothing threshold eliminates noise in the second
00880 %      derivative of the histogram.  As the value is increased, you can expect a
00881 %      smoother second derivative.
00882 %
00883 %    o pixel: return the dynamic threshold here.
00884 %
00885 %    o exception: return any errors or warnings in this structure.
00886 %
00887 */
00888 MagickExport MagickBooleanType GetImageDynamicThreshold(const Image *image,
00889   const double cluster_threshold,const double smooth_threshold,
00890   MagickPixelPacket *pixel,ExceptionInfo *exception)
00891 {
00892   Cluster
00893     *background,
00894     *cluster,
00895     *object,
00896     *head,
00897     *last_cluster,
00898     *next_cluster;
00899 
00900   ExtentPacket
00901     blue,
00902     green,
00903     red;
00904 
00905   long
00906     count,
00907     *histogram[MaxDimension],
00908     y;
00909 
00910   MagickBooleanType
00911     proceed;
00912 
00913   MagickRealType
00914     threshold;
00915 
00916   register const PixelPacket
00917     *p;
00918 
00919   register long
00920     i,
00921     x;
00922 
00923   short
00924     *extrema[MaxDimension];
00925 
00926   /*
00927     Allocate histogram and extrema.
00928   */
00929   assert(image != (Image *) NULL);
00930   assert(image->signature == MagickSignature);
00931   if (image->debug != MagickFalse)
00932     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00933   GetMagickPixelPacket(image,pixel);
00934   for (i=0; i < MaxDimension; i++)
00935   {
00936     histogram[i]=(long *) AcquireQuantumMemory(256UL,sizeof(**histogram));
00937     extrema[i]=(short *) AcquireQuantumMemory(256UL,sizeof(**histogram));
00938     if ((histogram[i] == (long *) NULL) || (extrema[i] == (short *) NULL))
00939       {
00940         for (i-- ; i >= 0; i--)
00941         {
00942           extrema[i]=(short *) RelinquishMagickMemory(extrema[i]);
00943           histogram[i]=(long *) RelinquishMagickMemory(histogram[i]);
00944         }
00945         (void) ThrowMagickException(exception,GetMagickModule(),
00946           ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
00947         return(MagickFalse);
00948       }
00949   }
00950   /*
00951     Initialize histogram.
00952   */
00953   InitializeHistogram(image,histogram,exception);
00954   (void) OptimalTau(histogram[Red],Tau,0.2f,DeltaTau,
00955     (smooth_threshold == 0.0f ? 1.0f : smooth_threshold),extrema[Red]);
00956   (void) OptimalTau(histogram[Green],Tau,0.2f,DeltaTau,
00957     (smooth_threshold == 0.0f ? 1.0f : smooth_threshold),extrema[Green]);
00958   (void) OptimalTau(histogram[Blue],Tau,0.2f,DeltaTau,
00959     (smooth_threshold == 0.0f ? 1.0f : smooth_threshold),extrema[Blue]);
00960   /*
00961     Form clusters.
00962   */
00963   cluster=(Cluster *) NULL;
00964   head=(Cluster *) NULL;
00965   (void) ResetMagickMemory(&red,0,sizeof(red));
00966   (void) ResetMagickMemory(&green,0,sizeof(green));
00967   (void) ResetMagickMemory(&blue,0,sizeof(blue));
00968   while (DefineRegion(extrema[Red],&red) != 0)
00969   {
00970     green.index=0;
00971     while (DefineRegion(extrema[Green],&green) != 0)
00972     {
00973       blue.index=0;
00974       while (DefineRegion(extrema[Blue],&blue) != 0)
00975       {
00976         /*
00977           Allocate a new class.
00978         */
00979         if (head != (Cluster *) NULL)
00980           {
00981             cluster->next=(Cluster *) AcquireMagickMemory(
00982               sizeof(*cluster->next));
00983             cluster=cluster->next;
00984           }
00985         else
00986           {
00987             cluster=(Cluster *) AcquireMagickMemory(sizeof(*cluster));
00988             head=cluster;
00989           }
00990         if (cluster == (Cluster *) NULL)
00991           {
00992             (void) ThrowMagickException(exception,GetMagickModule(),
00993               ResourceLimitError,"MemoryAllocationFailed","`%s'",
00994               image->filename);
00995             return(MagickFalse);
00996           }
00997         /*
00998           Initialize a new class.
00999         */
01000         cluster->count=0;
01001         cluster->red=red;
01002         cluster->green=green;
01003         cluster->blue=blue;
01004         cluster->next=(Cluster *) NULL;
01005       }
01006     }
01007   }
01008   if (head == (Cluster *) NULL)
01009     {
01010       /*
01011         No classes were identified-- create one.
01012       */
01013       cluster=(Cluster *) AcquireMagickMemory(sizeof(*cluster));
01014       if (cluster == (Cluster *) NULL)
01015         {
01016           (void) ThrowMagickException(exception,GetMagickModule(),
01017             ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
01018           return(MagickFalse);
01019         }
01020       /*
01021         Initialize a new class.
01022       */
01023       cluster->count=0;
01024       cluster->red=red;
01025       cluster->green=green;
01026       cluster->blue=blue;
01027       cluster->next=(Cluster *) NULL;
01028       head=cluster;
01029     }
01030   /*
01031     Count the pixels for each cluster.
01032   */
01033   count=0;
01034   for (y=0; y < (long) image->rows; y++)
01035   {
01036     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
01037     if (p == (const PixelPacket *) NULL)
01038       break;
01039     for (x=0; x < (long) image->columns; x++)
01040     {
01041       for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
01042         if (((long) ScaleQuantumToChar(p->red) >=
01043              (cluster->red.left-SafeMargin)) &&
01044             ((long) ScaleQuantumToChar(p->red) <=
01045              (cluster->red.right+SafeMargin)) &&
01046             ((long) ScaleQuantumToChar(p->green) >=
01047              (cluster->green.left-SafeMargin)) &&
01048             ((long) ScaleQuantumToChar(p->green) <=
01049              (cluster->green.right+SafeMargin)) &&
01050             ((long) ScaleQuantumToChar(p->blue) >=
01051              (cluster->blue.left-SafeMargin)) &&
01052             ((long) ScaleQuantumToChar(p->blue) <=
01053              (cluster->blue.right+SafeMargin)))
01054           {
01055             /*
01056               Count this pixel.
01057             */
01058             count++;
01059             cluster->red.center+=(MagickRealType)
01060               ScaleQuantumToChar(p->red);
01061             cluster->green.center+=(MagickRealType)
01062               ScaleQuantumToChar(p->green);
01063             cluster->blue.center+=(MagickRealType)
01064               ScaleQuantumToChar(p->blue);
01065             cluster->count++;
01066             break;
01067           }
01068       p++;
01069     }
01070     proceed=SetImageProgress(image,SegmentImageTag,y,2*image->rows);
01071     if (proceed == MagickFalse)
01072       break;
01073   }
01074   /*
01075     Remove clusters that do not meet minimum cluster threshold.
01076   */
01077   count=0;
01078   last_cluster=head;
01079   next_cluster=head;
01080   for (cluster=head; cluster != (Cluster *) NULL; cluster=next_cluster)
01081   {
01082     next_cluster=cluster->next;
01083     if ((cluster->count > 0) &&
01084         (cluster->count >= (count*cluster_threshold/100.0)))
01085       {
01086         /*
01087           Initialize cluster.
01088         */
01089         cluster->id=count;
01090         cluster->red.center/=cluster->count;
01091         cluster->green.center/=cluster->count;
01092         cluster->blue.center/=cluster->count;
01093         count++;
01094         last_cluster=cluster;
01095         continue;
01096       }
01097     /*
01098       Delete cluster.
01099     */
01100     if (cluster == head)
01101       head=next_cluster;
01102     else
01103       last_cluster->next=next_cluster;
01104     cluster=(Cluster *) RelinquishMagickMemory(cluster);
01105   }
01106   object=head;
01107   background=head;
01108