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

Generated on 19 Nov 2009 for MagickCore by  doxygen 1.6.1