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