]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/segment.c
...
[imagemagick] / MagickCore / segment.c
index beb7e72b41b39acce99094a6daf8959fcc8d65eb..11e7276fd5b62f6d69a27d62b5c866fed6ca9e48 100644 (file)
 %    MagickCore Methods to Segment an Image with Thresholding Fuzzy c-Means   %
 %                                                                             %
 %                              Software Design                                %
-%                                John Cristy                                  %
+%                                   Cristy                                    %
 %                                April 1993                                   %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2017 ImageMagick Studio LLC, a non-profit organization      %
 %  dedicated to making software imaging solutions freely available.           %
 %                                                                             %
 %  You may not use this file except in compliance with the License.  You may  %
 %  obtain a copy of the License at                                            %
 %                                                                             %
-%    http://www.imagemagick.org/script/license.php                            %
+%    https://www.imagemagick.org/script/license.php                           %
 %                                                                             %
 %  Unless required by applicable law or agreed to in writing, software        %
 %  distributed under the License is distributed on an "AS IS" BASIS,          %
 %
 %    o For each histogram, successively apply the scale-space filter and
 %      build an interval tree of zero crossings in the second derivative
-%      at each scale.  Analyze this scale-space ``fingerprint'' to
+%      at each scale.  Analyze this scale-space ''fingerprint'' to
 %      determine which peaks and valleys in the histogram are most
 %      predominant.
 %
 %    o The fingerprint defines intervals on the axis of the histogram.
 %      Each interval contains either a minima or a maxima in the original
 %      signal.  If each color component lies within the maxima interval,
-%      that pixel is considered ``classified'' and is assigned an unique
+%      that pixel is considered ''classified'' and is assigned an unique
 %      class number.
 %
 %    o Any pixel that fails to be classified in the above thresholding
 #include "MagickCore/monitor.h"
 #include "MagickCore/monitor-private.h"
 #include "MagickCore/pixel-accessor.h"
+#include "MagickCore/pixel-private.h"
 #include "MagickCore/quantize.h"
 #include "MagickCore/quantum.h"
 #include "MagickCore/quantum-private.h"
+#include "MagickCore/resource_.h"
 #include "MagickCore/segment.h"
 #include "MagickCore/string_.h"
+#include "MagickCore/thread-private.h"
 \f
 /*
   Define declarations.
 */
 typedef struct _ExtentPacket
 {
-  MagickRealType
+  double
     center;
 
   ssize_t
@@ -147,14 +150,14 @@ typedef struct _Cluster
 
 typedef struct _IntervalTree
 {
-  MagickRealType
+  double
     tau;
 
   ssize_t
     left,
     right;
 
-  MagickRealType
+  double
     mean_stability,
     stability;
 
@@ -165,7 +168,7 @@ typedef struct _IntervalTree
 
 typedef struct _ZeroCrossing
 {
-  MagickRealType
+  double
     tau,
     histogram[256];
 
@@ -186,7 +189,7 @@ static const int
 /*
   Method prototypes.
 */
-static MagickRealType
+static double
   OptimalTau(const ssize_t *,const double,const double,const double,
     const double,short *);
 
@@ -195,8 +198,8 @@ static ssize_t
 
 static void
   InitializeHistogram(const Image *,ssize_t **,ExceptionInfo *),
-  ScaleSpace(const ssize_t *,const MagickRealType,MagickRealType *),
-  ZeroCrossHistogram(MagickRealType *,const MagickRealType,short *);
+  ScaleSpace(const ssize_t *,const double,double *),
+  ZeroCrossHistogram(double *,const double,short *);
 \f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -216,9 +219,9 @@ static void
 %  The format of the Classify method is:
 %
 %      MagickBooleanType Classify(Image *image,short **extrema,
-%        const MagickRealType cluster_threshold,
-%        const MagickRealType weighting_exponent,
-%        const MagickBooleanType verbose)
+%        const double cluster_threshold,
+%        const double weighting_exponent,
+%        const MagickBooleanType verbose,ExceptionInfo *exception)
 %
 %  A description of each parameter follows.
 %
@@ -228,7 +231,7 @@ static void
 %      represent the peaks and valleys of the histogram for each color
 %      component.
 %
-%    o cluster_threshold:  This MagickRealType represents the minimum number of
+%    o cluster_threshold:  This double represents the minimum number of
 %      pixels contained in a hexahedra before it can be considered valid
 %      (expressed as a percentage).
 %
@@ -237,10 +240,13 @@ static void
 %    o verbose:  A value greater than zero prints detailed information about
 %      the identified classes.
 %
+%    o exception: return any errors or warnings in this structure.
+%
 */
 static MagickBooleanType Classify(Image *image,short **extrema,
-  const MagickRealType cluster_threshold,
-  const MagickRealType weighting_exponent,const MagickBooleanType verbose)
+  const double cluster_threshold,
+  const double weighting_exponent,const MagickBooleanType verbose,
+  ExceptionInfo *exception)
 {
 #define SegmentImageTag  "Segment/Image"
 
@@ -253,9 +259,6 @@ static MagickBooleanType Classify(Image *image,short **extrema,
     *last_cluster,
     *next_cluster;
 
-  ExceptionInfo
-    *exception;
-
   ExtentPacket
     blue,
     green,
@@ -264,7 +267,7 @@ static MagickBooleanType Classify(Image *image,short **extrema,
   MagickOffsetType
     progress;
 
-  MagickRealType
+  double
     *free_squares;
 
   MagickStatusType
@@ -273,7 +276,7 @@ static MagickBooleanType Classify(Image *image,short **extrema,
   register ssize_t
     i;
 
-  register MagickRealType
+  register double
     *squares;
 
   size_t
@@ -352,8 +355,7 @@ static MagickBooleanType Classify(Image *image,short **extrema,
   status=MagickTrue;
   count=0;
   progress=0;
-  exception=(&image->exception);
-  image_view=AcquireCacheView(image);
+  image_view=AcquireVirtualCacheView(image,exception);
   for (y=0; y < (ssize_t) image->rows; y++)
   {
     register const Quantum
@@ -385,11 +387,11 @@ static MagickBooleanType Classify(Image *image,short **extrema,
               Count this pixel.
             */
             count++;
-            cluster->red.center+=(MagickRealType) ScaleQuantumToChar(
+            cluster->red.center+=(double) ScaleQuantumToChar(
               GetPixelRed(image,p));
-            cluster->green.center+=(MagickRealType) ScaleQuantumToChar(
+            cluster->green.center+=(double) ScaleQuantumToChar(
               GetPixelGreen(image,p));
-            cluster->blue.center+=(MagickRealType) ScaleQuantumToChar(
+            cluster->blue.center+=(double) ScaleQuantumToChar(
               GetPixelBlue(image,p));
             cluster->count++;
             break;
@@ -404,8 +406,8 @@ static MagickBooleanType Classify(Image *image,short **extrema,
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
         #pragma omp critical (MagickCore_Classify)
 #endif
-        proceed=SetImageProgress(image,SegmentImageTag,progress++,
-          2*image->rows);
+        proceed=SetImageProgress(image,SegmentImageTag,progress++,2*
+          image->rows);
         if (proceed == MagickFalse)
           status=MagickFalse;
       }
@@ -502,56 +504,56 @@ static MagickBooleanType Classify(Image *image,short **extrema,
   /*
     Speed up distance calculations.
   */
-  squares=(MagickRealType *) AcquireQuantumMemory(513UL,sizeof(*squares));
-  if (squares == (MagickRealType *) NULL)
+  squares=(double *) AcquireQuantumMemory(513UL,sizeof(*squares));
+  if (squares == (double *) NULL)
     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
       image->filename);
   squares+=255;
   for (i=(-255); i <= 255; i++)
-    squares[i]=(MagickRealType) i*(MagickRealType) i;
+    squares[i]=(double) i*(double) i;
   /*
     Allocate image colormap.
   */
-  if (AcquireImageColormap(image,number_clusters) == MagickFalse)
+  if (AcquireImageColormap(image,number_clusters,exception) == MagickFalse)
     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
       image->filename);
   i=0;
   for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
   {
-    image->colormap[i].red=ScaleCharToQuantum((unsigned char)
+    image->colormap[i].red=(double) ScaleCharToQuantum((unsigned char)
       (cluster->red.center+0.5));
-    image->colormap[i].green=ScaleCharToQuantum((unsigned char)
+    image->colormap[i].green=(double) ScaleCharToQuantum((unsigned char)
       (cluster->green.center+0.5));
-    image->colormap[i].blue=ScaleCharToQuantum((unsigned char)
+    image->colormap[i].blue=(double) ScaleCharToQuantum((unsigned char)
       (cluster->blue.center+0.5));
     i++;
   }
   /*
     Do course grain classes.
   */
-  exception=(&image->exception);
-  image_view=AcquireCacheView(image);
+  image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status) \
+    magick_threads(image,image,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
     Cluster
       *cluster;
 
-    register const PixelPacket
-      *restrict p;
+    register const PixelInfo
+      *magick_restrict p;
 
     register ssize_t
       x;
 
     register Quantum
-      *restrict q;
+      *magick_restrict q;
 
     if (status == MagickFalse)
       continue;
     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
-    if (q == (const Quantum *) NULL)
+    if (q == (Quantum *) NULL)
       {
         status=MagickFalse;
         continue;
@@ -583,7 +585,7 @@ static MagickBooleanType Classify(Image *image,short **extrema,
       }
       if (cluster == (Cluster *) NULL)
         {
-          MagickRealType
+          double
             distance_squared,
             local_minima,
             numerator,
@@ -604,22 +606,22 @@ static MagickBooleanType Classify(Image *image,short **extrema,
             p=image->colormap+j;
             distance_squared=squares[(ssize_t) ScaleQuantumToChar(
               GetPixelRed(image,q))-(ssize_t)
-              ScaleQuantumToChar(p->red)]+squares[(ssize_t)
+              ScaleQuantumToChar(ClampToQuantum(p->red))]+squares[(ssize_t)
               ScaleQuantumToChar(GetPixelGreen(image,q))-(ssize_t)
-              ScaleQuantumToChar(p->green)]+squares[(ssize_t)
+              ScaleQuantumToChar(ClampToQuantum(p->green))]+squares[(ssize_t)
               ScaleQuantumToChar(GetPixelBlue(image,q))-(ssize_t)
-              ScaleQuantumToChar(p->blue)];
+              ScaleQuantumToChar(ClampToQuantum(p->blue))];
             numerator=distance_squared;
             for (k=0; k < (ssize_t) image->colors; k++)
             {
               p=image->colormap+k;
                 distance_squared=squares[(ssize_t) ScaleQuantumToChar(
                   GetPixelRed(image,q))-(ssize_t)
-                  ScaleQuantumToChar(p->red)]+squares[(ssize_t)
-                  ScaleQuantumToChar(GetPixelGreen(image,q))-(ssize_t)
-                  ScaleQuantumToChar(p->green)]+squares[(ssize_t)
-                  ScaleQuantumToChar(GetPixelBlue(image,q))-(ssize_t)
-                  ScaleQuantumToChar(p->blue)];
+                  ScaleQuantumToChar(ClampToQuantum(p->red))]+squares[
+                  (ssize_t) ScaleQuantumToChar(GetPixelGreen(image,q))-(ssize_t)
+                  ScaleQuantumToChar(ClampToQuantum(p->green))]+squares[
+                  (ssize_t) ScaleQuantumToChar(GetPixelBlue(image,q))-(ssize_t)
+                  ScaleQuantumToChar(ClampToQuantum(p->blue))];
               ratio=numerator/distance_squared;
               sum+=SegmentPower(ratio);
             }
@@ -652,7 +654,7 @@ static MagickBooleanType Classify(Image *image,short **extrema,
       }
   }
   image_view=DestroyCacheView(image_view);
-  status&=SyncImage(image);
+  status&=SyncImage(image,exception);
   /*
     Relinquish resources.
   */
@@ -663,7 +665,7 @@ static MagickBooleanType Classify(Image *image,short **extrema,
   }
   squares-=255;
   free_squares=squares;
-  free_squares=(MagickRealType *) RelinquishMagickMemory(free_squares);
+  free_squares=(double *) RelinquishMagickMemory(free_squares);
   return(MagickTrue);
 }
 \f
@@ -694,28 +696,6 @@ static MagickBooleanType Classify(Image *image,short **extrema,
 %      in the zero_crossing array.
 %
 */
-
-static inline ssize_t MagickAbsoluteValue(const ssize_t x)
-{
-  if (x < 0)
-    return(-x);
-  return(x);
-}
-
-static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
-{
-  if (x > y)
-    return(x);
-  return(y);
-}
-
-static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
-{
-  if (x < y)
-    return(x);
-  return(y);
-}
-
 static void ConsolidateCrossings(ZeroCrossing *zero_crossing,
   const size_t number_crossings)
 {
@@ -876,21 +856,21 @@ static ssize_t DefineRegion(const short *extrema,ExtentPacket *extents)
 %
 %  The format of the DerivativeHistogram method is:
 %
-%      DerivativeHistogram(const MagickRealType *histogram,
-%        MagickRealType *derivative)
+%      DerivativeHistogram(const double *histogram,
+%        double *derivative)
 %
 %  A description of each parameter follows.
 %
-%    o histogram: Specifies an array of MagickRealTypes representing the number
+%    o histogram: Specifies an array of doubles representing the number
 %      of pixels for each intensity of a particular color component.
 %
-%    o derivative: This array of MagickRealTypes is initialized by
+%    o derivative: This array of doubles is initialized by
 %      DerivativeHistogram to the derivative of the histogram using central
 %      differencing.
 %
 */
-static void DerivativeHistogram(const MagickRealType *histogram,
-  MagickRealType *derivative)
+static void DerivativeHistogram(const double *histogram,
+  double *derivative)
 {
   register ssize_t
     i,
@@ -933,7 +913,7 @@ static void DerivativeHistogram(const MagickRealType *histogram,
 %
 %    o image: the image.
 %
-%    o cluster_threshold:  This MagickRealType represents the minimum number of
+%    o cluster_threshold:  This double represents the minimum number of
 %      pixels contained in a hexahedra before it can be considered valid
 %      (expressed as a percentage).
 %
@@ -966,7 +946,7 @@ MagickExport MagickBooleanType GetImageDynamicThreshold(const Image *image,
   MagickBooleanType
     proceed;
 
-  MagickRealType
+  double
     threshold;
 
   register const Quantum
@@ -988,7 +968,7 @@ MagickExport MagickBooleanType GetImageDynamicThreshold(const Image *image,
     Allocate histogram and extrema.
   */
   assert(image != (Image *) NULL);
-  assert(image->signature == MagickSignature);
+  assert(image->signature == MagickCoreSignature);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   GetPixelInfo(image,pixel);
@@ -1117,11 +1097,11 @@ MagickExport MagickBooleanType GetImageDynamicThreshold(const Image *image,
               Count this pixel.
             */
             count++;
-            cluster->red.center+=(MagickRealType) ScaleQuantumToChar(
+            cluster->red.center+=(double) ScaleQuantumToChar(
               GetPixelRed(image,p));
-            cluster->green.center+=(MagickRealType) ScaleQuantumToChar(
+            cluster->green.center+=(double) ScaleQuantumToChar(
               GetPixelGreen(image,p));
-            cluster->blue.center+=(MagickRealType) ScaleQuantumToChar(
+            cluster->blue.center+=(double) ScaleQuantumToChar(
               GetPixelBlue(image,p));
             cluster->count++;
             break;
@@ -1184,15 +1164,18 @@ MagickExport MagickBooleanType GetImageDynamicThreshold(const Image *image,
         cluster=cluster->next;
       }
     }
-  threshold=(background->red.center+object->red.center)/2.0;
-  pixel->red=(MagickRealType) ScaleCharToQuantum((unsigned char)
-    (threshold+0.5));
-  threshold=(background->green.center+object->green.center)/2.0;
-  pixel->green=(MagickRealType) ScaleCharToQuantum((unsigned char)
-    (threshold+0.5));
-  threshold=(background->blue.center+object->blue.center)/2.0;
-  pixel->blue=(MagickRealType) ScaleCharToQuantum((unsigned char)
-    (threshold+0.5));
+  if (background != (Cluster *) NULL)
+    {
+      threshold=(background->red.center+object->red.center)/2.0;
+      pixel->red=(double) ScaleCharToQuantum((unsigned char)
+        (threshold+0.5));
+      threshold=(background->green.center+object->green.center)/2.0;
+      pixel->green=(double) ScaleCharToQuantum((unsigned char)
+        (threshold+0.5));
+      threshold=(background->blue.center+object->blue.center)/2.0;
+      pixel->blue=(double) ScaleCharToQuantum((unsigned char)
+        (threshold+0.5));
+    }
   /*
     Relinquish resources.
   */
@@ -1325,7 +1308,7 @@ static void MeanStability(IntervalTree *node)
       register ssize_t
         count;
 
-      register MagickRealType
+      register double
         sum;
 
       sum=0.0;
@@ -1335,7 +1318,7 @@ static void MeanStability(IntervalTree *node)
         sum+=child->stability;
         count++;
       }
-      node->mean_stability=sum/(MagickRealType) count;
+      node->mean_stability=sum/(double) count;
     }
   MeanStability(node->sibling);
   MeanStability(node->child);
@@ -1463,7 +1446,7 @@ static IntervalTree *InitializeIntervalTree(const ZeroCrossing *zero_crossing,
 %
 %  The format of the OptimalTau method is:
 %
-%    MagickRealType OptimalTau(const ssize_t *histogram,const double max_tau,
+%    double OptimalTau(const ssize_t *histogram,const double max_tau,
 %      const double min_tau,const double delta_tau,
 %      const double smooth_threshold,short *extrema)
 %
@@ -1504,7 +1487,7 @@ static void FreeNodes(IntervalTree *node)
   node=(IntervalTree *) RelinquishMagickMemory(node);
 }
 
-static MagickRealType OptimalTau(const ssize_t *histogram,const double max_tau,
+static double OptimalTau(const ssize_t *histogram,const double max_tau,
   const double min_tau,const double delta_tau,const double smooth_threshold,
   short *extrema)
 {
@@ -1516,7 +1499,7 @@ static MagickRealType OptimalTau(const ssize_t *histogram,const double max_tau,
   MagickBooleanType
     peak;
 
-  MagickRealType
+  double
     average_tau,
     *derivative,
     *second_derivative,
@@ -1560,11 +1543,11 @@ static MagickRealType OptimalTau(const ssize_t *histogram,const double max_tau,
   /*
     Initialize zero crossing list.
   */
-  derivative=(MagickRealType *) AcquireQuantumMemory(256,sizeof(*derivative));
-  second_derivative=(MagickRealType *) AcquireQuantumMemory(256,
+  derivative=(double *) AcquireQuantumMemory(256,sizeof(*derivative));
+  second_derivative=(double *) AcquireQuantumMemory(256,
     sizeof(*second_derivative));
-  if ((derivative == (MagickRealType *) NULL) ||
-      (second_derivative == (MagickRealType *) NULL))
+  if ((derivative == (double *) NULL) ||
+      (second_derivative == (double *) NULL))
     ThrowFatalException(ResourceLimitFatalError,
       "UnableToAllocateDerivatives");
   i=0;
@@ -1583,14 +1566,14 @@ static MagickRealType OptimalTau(const ssize_t *histogram,const double max_tau,
   */
   zero_crossing[i].tau=0.0;
   for (j=0; j <= 255; j++)
-    zero_crossing[i].histogram[j]=(MagickRealType) histogram[j];
+    zero_crossing[i].histogram[j]=(double) histogram[j];
   DerivativeHistogram(zero_crossing[i].histogram,derivative);
   DerivativeHistogram(derivative,second_derivative);
   ZeroCrossHistogram(second_derivative,smooth_threshold,
     zero_crossing[i].crossings);
   number_crossings=(size_t) i;
-  derivative=(MagickRealType *) RelinquishMagickMemory(derivative);
-  second_derivative=(MagickRealType *)
+  derivative=(double *) RelinquishMagickMemory(derivative);
+  second_derivative=(double *)
     RelinquishMagickMemory(second_derivative);
   /*
     Ensure the scale-space fingerprints form lines in scale-space, not loops.
@@ -1677,7 +1660,7 @@ static MagickRealType OptimalTau(const ssize_t *histogram,const double max_tau,
   average_tau=0.0;
   for (i=0; i < number_nodes; i++)
     average_tau+=list[i]->tau;
-  average_tau/=(MagickRealType) number_nodes;
+  average_tau/=(double) number_nodes;
   /*
     Relinquish resources.
   */
@@ -1702,20 +1685,20 @@ static MagickRealType OptimalTau(const ssize_t *histogram,const double max_tau,
 %
 %  The format of the ScaleSpace method is:
 %
-%      ScaleSpace(const ssize_t *histogram,const MagickRealType tau,
-%        MagickRealType *scale_histogram)
+%      ScaleSpace(const ssize_t *histogram,const double tau,
+%        double *scale_histogram)
 %
 %  A description of each parameter follows.
 %
-%    o histogram: Specifies an array of MagickRealTypes representing the number
+%    o histogram: Specifies an array of doubles representing the number
 %      of pixels for each intensity of a particular color component.
 %
 */
 
-static void ScaleSpace(const ssize_t *histogram,const MagickRealType tau,
-  MagickRealType *scale_histogram)
+static void ScaleSpace(const ssize_t *histogram,const double tau,
+  double *scale_histogram)
 {
-  MagickRealType
+  double
     alpha,
     beta,
     *gamma,
@@ -1725,12 +1708,12 @@ static void ScaleSpace(const ssize_t *histogram,const MagickRealType tau,
     u,
     x;
 
-  gamma=(MagickRealType *) AcquireQuantumMemory(256,sizeof(*gamma));
-  if (gamma == (MagickRealType *) NULL)
+  gamma=(double *) AcquireQuantumMemory(256,sizeof(*gamma));
+  if (gamma == (double *) NULL)
     ThrowFatalException(ResourceLimitFatalError,
       "UnableToAllocateGammaMap");
-  alpha=1.0/(tau*sqrt(2.0*MagickPI));
-  beta=(-1.0/(2.0*tau*tau));
+  alpha=PerceptibleReciprocal(tau*sqrt(2.0*MagickPI));
+  beta=(-1.0*PerceptibleReciprocal(2.0*tau*tau));
   for (x=0; x <= 255; x++)
     gamma[x]=0.0;
   for (x=0; x <= 255; x++)
@@ -1743,10 +1726,10 @@ static void ScaleSpace(const ssize_t *histogram,const MagickRealType tau,
   {
     sum=0.0;
     for (u=0; u <= 255; u++)
-      sum+=(MagickRealType) histogram[u]*gamma[MagickAbsoluteValue(x-u)];
+      sum+=(double) histogram[u]*gamma[MagickAbsoluteValue(x-u)];
     scale_histogram[x]=alpha*sum;
   }
-  gamma=(MagickRealType *) RelinquishMagickMemory(gamma);
+  gamma=(double *) RelinquishMagickMemory(gamma);
 }
 \f
 /*
@@ -1768,7 +1751,8 @@ static void ScaleSpace(const ssize_t *histogram,const MagickRealType tau,
 %
 %      MagickBooleanType SegmentImage(Image *image,
 %        const ColorspaceType colorspace,const MagickBooleanType verbose,
-%        const double cluster_threshold,const double smooth_threshold)
+%        const double cluster_threshold,const double smooth_threshold,
+%        ExceptionInfo *exception)
 %
 %  A description of each parameter follows.
 %
@@ -1787,11 +1771,17 @@ static void ScaleSpace(const ssize_t *histogram,const MagickRealType tau,
 %      derivative of the histogram.  As the value is increased, you can expect a
 %      smoother second derivative.
 %
+%    o exception: return any errors or warnings in this structure.
+%
 */
 MagickExport MagickBooleanType SegmentImage(Image *image,
   const ColorspaceType colorspace,const MagickBooleanType verbose,
-  const double cluster_threshold,const double smooth_threshold)
+  const double cluster_threshold,const double smooth_threshold,
+  ExceptionInfo *exception)
 {
+  ColorspaceType
+    previous_colorspace;
+
   MagickBooleanType
     status;
 
@@ -1808,7 +1798,7 @@ MagickExport MagickBooleanType SegmentImage(Image *image,
     Allocate histogram and extrema.
   */
   assert(image != (Image *) NULL);
-  assert(image->signature == MagickSignature);
+  assert(image->signature == MagickCoreSignature);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   for (i=0; i < MaxDimension; i++)
@@ -1826,12 +1816,12 @@ MagickExport MagickBooleanType SegmentImage(Image *image,
           image->filename)
       }
   }
-  if (IsRGBColorspace(colorspace) == MagickFalse)
-    (void) TransformImageColorspace(image,colorspace);
   /*
     Initialize histogram.
   */
-  InitializeHistogram(image,histogram,&image->exception);
+  previous_colorspace=image->colorspace;
+  (void) TransformImageColorspace(image,colorspace,exception);
+  InitializeHistogram(image,histogram,exception);
   (void) OptimalTau(histogram[Red],Tau,0.2,DeltaTau,
     smooth_threshold == 0.0 ? 1.0 : smooth_threshold,extrema[Red]);
   (void) OptimalTau(histogram[Green],Tau,0.2,DeltaTau,
@@ -1841,9 +1831,9 @@ MagickExport MagickBooleanType SegmentImage(Image *image,
   /*
     Classify using the fuzzy c-Means technique.
   */
-  status=Classify(image,extrema,cluster_threshold,WeightingExponent,verbose);
-  if (IsRGBColorspace(colorspace) == MagickFalse)
-    (void) TransformImageColorspace(image,colorspace);
+  status=Classify(image,extrema,cluster_threshold,WeightingExponent,verbose,
+    exception);
+  (void) TransformImageColorspace(image,previous_colorspace,exception);
   /*
     Relinquish resources.
   */
@@ -1872,12 +1862,12 @@ MagickExport MagickBooleanType SegmentImage(Image *image,
 %
 %  The format of the ZeroCrossHistogram method is:
 %
-%      ZeroCrossHistogram(MagickRealType *second_derivative,
-%        const MagickRealType smooth_threshold,short *crossings)
+%      ZeroCrossHistogram(double *second_derivative,
+%        const double smooth_threshold,short *crossings)
 %
 %  A description of each parameter follows.
 %
-%    o second_derivative: Specifies an array of MagickRealTypes representing the
+%    o second_derivative: Specifies an array of doubles representing the
 %      second derivative of the histogram of a particular color component.
 %
 %    o crossings:  This array of integers is initialized with
@@ -1885,8 +1875,8 @@ MagickExport MagickBooleanType SegmentImage(Image *image,
 %      of a particular color component.
 %
 */
-static void ZeroCrossHistogram(MagickRealType *second_derivative,
-  const MagickRealType smooth_threshold,short *crossings)
+static void ZeroCrossHistogram(double *second_derivative,
+  const double smooth_threshold,short *crossings)
 {
   register ssize_t
     i;