]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/effect.c
(no commit message)
[imagemagick] / MagickCore / effect.c
index 49b04ebd880cd4017f84ab55a789ea50e2b1f398..cf6d59439350ade463233d6cf5fbadac0865854b 100644 (file)
@@ -862,16 +862,13 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
 %  The format of the EdgeImage method is:
 %
 %      Image *CannyEdgeImage(const Image *image,const double radius,
-%        const double sigma,const double lower_precent,
-%        const double upper_percent,const size_t threshold,
-%        ExceptionInfo *exception)
+%        const double sigma,const double lower_percent,
+%        const double upper_percent,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
 %    o image: the image.
 %
-%    o channel: the channel type.
-%
 %    o radius: the radius of the gaussian smoothing filter.
 %
 %    o sigma: the sigma of the gaussian smoothing filter.
@@ -908,39 +905,45 @@ static inline MagickBooleanType IsAuthenticPixel(const Image *image,
   return(MagickTrue);
 }
 
-static MagickBooleanType TraceEdges(Image *edge_image,CacheView *trace_view,
-  MatrixInfo *pixel_cache,const ssize_t x,const ssize_t y,
+static MagickBooleanType TraceEdges(Image *edge_image,CacheView *edge_view,
+  MatrixInfo *canny_cache,const ssize_t x,const ssize_t y,
   const double lower_threshold,ExceptionInfo *exception)
 {
   CannyInfo
+    edge,
     pixel;
 
-  size_t
-    number_edges;
+  MagickBooleanType
+    status;
 
-  if (GetMatrixElement(pixel_cache,0,0,&pixel) == MagickFalse)
+  register Quantum
+    *q;
+
+  register ssize_t
+    i;
+
+  q=GetCacheViewAuthenticPixels(edge_view,x,y,1,1,exception);
+  if (q == (Quantum *) NULL)
+    return(MagickFalse);
+  *q=QuantumRange;
+  status=SyncCacheViewAuthenticPixels(edge_view,exception);
+  if (status == MagickFalse)
+    return(MagickFalse);;
+  if (GetMatrixElement(canny_cache,0,0,&edge) == MagickFalse)
     return(MagickFalse);
-  pixel.x=x;
-  pixel.y=y;
-  if (SetMatrixElement(pixel_cache,0,0,&pixel) == MagickFalse)
+  edge.x=x;
+  edge.y=y;
+  if (SetMatrixElement(canny_cache,0,0,&edge) == MagickFalse)
     return(MagickFalse);
-  number_edges=1;
-  do
+  for (i=1; i != 0; )
   {
-    MagickBooleanType
-      status;
-
     ssize_t
-      v,
-      x_offset,
-      y_offset;
+      v;
 
-    number_edges--;
-    status=GetMatrixElement(pixel_cache,(ssize_t) number_edges,0,&pixel);
+    i--;
+    status=GetMatrixElement(canny_cache,i,0,&edge);
     if (status == MagickFalse)
       return(MagickFalse);
-    x_offset=pixel.x;
-    y_offset=pixel.y;
     for (v=(-1); v <= 1; v++)
     {
       ssize_t
@@ -948,62 +951,57 @@ static MagickBooleanType TraceEdges(Image *edge_image,CacheView *trace_view,
 
       for (u=(-1); u <= 1; u++)
       {
-        Quantum
-          *q;
-
         if ((u == 0) && (v == 0))
           continue;
-        if (IsAuthenticPixel(edge_image,x_offset+u,y_offset+v) == MagickFalse)
+        if (IsAuthenticPixel(edge_image,edge.x+u,edge.y+v) == MagickFalse)
           continue;
         /*
           Not an edge if gradient value is below the lower threshold.
         */
-        q=GetCacheViewAuthenticPixels(trace_view,x_offset+u,y_offset+v,1,1,
+        q=GetCacheViewAuthenticPixels(edge_view,edge.x+u,edge.y+v,1,1,
           exception);
         if (q == (Quantum *) NULL)
           return(MagickFalse);
-        status=GetMatrixElement(pixel_cache,x_offset+u,y_offset+v,&pixel);
+        status=GetMatrixElement(canny_cache,edge.x+u,edge.y+v,&pixel);
         if (status == MagickFalse)
           return(MagickFalse);
-        if ((pixel.intensity >= lower_threshold) &&
-            (GetPixelIntensity(edge_image,q) == 0))
+        if ((GetPixelIntensity(edge_image,q) == 0.0) &&
+            (pixel.intensity >= lower_threshold))
           {
             *q=QuantumRange;
-            status=SyncCacheViewAuthenticPixels(trace_view,exception);
-            if (status == MagickFalse)
-              return(MagickFalse);
-            status=GetMatrixElement(pixel_cache,(ssize_t) number_edges,0,
-              &pixel);
+            status=SyncCacheViewAuthenticPixels(edge_view,exception);
             if (status == MagickFalse)
               return(MagickFalse);
-            pixel.x=x_offset+u;
-            pixel.y=y_offset+v;
-            status=SetMatrixElement(pixel_cache,(ssize_t) number_edges,0,
-              &pixel);
+            edge.x+=u;
+            edge.y+=v;
+            status=SetMatrixElement(canny_cache,i,0,&edge);
             if (status == MagickFalse)
               return(MagickFalse);
-            number_edges++;
+            i++;
           }
       }
     }
-  } while (number_edges != 0);
+  }
   return(MagickTrue);
 }
 
-
 MagickExport Image *CannyEdgeImage(const Image *image,const double radius,
-  const double sigma,const double lower_precent,const double upper_percent,
+  const double sigma,const double lower_percent,const double upper_percent,
   ExceptionInfo *exception)
 {
   CacheView
-    *edge_view,
-    *trace_view;
+    *edge_view;
+
+  CannyInfo
+    pixel;
 
   char
     geometry[MaxTextExtent];
 
   double
     lower_threshold,
+    max,
+    min,
     upper_threshold;
 
   Image
@@ -1016,17 +1014,9 @@ MagickExport Image *CannyEdgeImage(const Image *image,const double radius,
     status;
 
   MatrixInfo
-    *pixel_cache;
-
-  register ssize_t
-    i;
-
-  size_t
-    *histogram,
-    number_pixels;
+    *canny_cache;
 
   ssize_t
-    count,
     y;
 
   assert(image != (const Image *) NULL);
@@ -1056,9 +1046,9 @@ MagickExport Image *CannyEdgeImage(const Image *image,const double radius,
   /*
     Find the intensity gradient of the image.
   */
-  pixel_cache=AcquireMatrixInfo(edge_image->columns,edge_image->rows,
+  canny_cache=AcquireMatrixInfo(edge_image->columns,edge_image->rows,
     sizeof(CannyInfo),exception);
-  if (pixel_cache == (MatrixInfo *) NULL)
+  if (canny_cache == (MatrixInfo *) NULL)
     {
       edge_image=DestroyImage(edge_image);
       return((Image *) NULL);
@@ -1095,9 +1085,6 @@ MagickExport Image *CannyEdgeImage(const Image *image,const double radius,
         dx,
         dy;
 
-      int
-        orientation;
-
       register const Quantum
         *restrict kernel_pixels;
 
@@ -1131,41 +1118,41 @@ MagickExport Image *CannyEdgeImage(const Image *image,const double radius,
             intensity;
 
           intensity=GetPixelIntensity(edge_image,kernel_pixels+u);
-          dx+=3.0*Gx[v][u]*intensity/2.0;
-          dy+=3.0*Gy[v][u]*intensity/2.0;
+          dx+=0.5*Gx[v][u]*intensity;
+          dy+=0.5*Gy[v][u]*intensity;
         }
         kernel_pixels+=edge_image->columns+1;
       }
-      pixel.magnitude=sqrt(dx*dx+dy*dy);
+      pixel.magnitude=hypot(dx,dy);
       pixel.orientation=0;
-      if (dx != 0.0)
+      if (fabs(dx) > MagickEpsilon)
         {
           double
-            theta;
+            slope;
 
-          theta=dy/dx;
-          if (theta < 0.0)
+          slope=dy/dx;
+          if (slope < 0.0)
             {
-              if (theta < -2.41421356237)
-                pixel.orientation=2;
+              if (slope < -2.41421356237)
+                pixel.orientation=0;
               else
-                if (theta < -0.414213562373)
+                if (slope < -0.414213562373)
                   pixel.orientation=1;
                 else
-                  pixel.orientation=0;
+                  pixel.orientation=2;
             }
           else
             {
-              if (theta > 2.41421356237)
-                pixel.orientation=2;
+              if (slope > 2.41421356237)
+                pixel.orientation=0;
               else
-                if (theta > 0.414213562373)
+                if (slope > 0.414213562373)
                   pixel.orientation=3;
                 else
-                  pixel.orientation=0;
+                  pixel.orientation=2;
             }
         }
-      if (SetMatrixElement(pixel_cache,x,y,&pixel) == MagickFalse)
+      if (SetMatrixElement(canny_cache,x,y,&pixel) == MagickFalse)
         continue;
       p+=GetPixelChannels(edge_image);
     }
@@ -1175,14 +1162,9 @@ MagickExport Image *CannyEdgeImage(const Image *image,const double radius,
     Non-maxima suppression, remove pixels that are not considered to be part
     of an edge.
   */
-  histogram=(size_t *) AcquireQuantumMemory(65536,sizeof(*histogram));
-  if (histogram == (size_t *) NULL)
-    {
-      pixel_cache=DestroyMatrixInfo(pixel_cache);
-      edge_image=DestroyImage(edge_image);
-      return((Image *) NULL);
-    }
-  (void) ResetMagickMemory(histogram,0,65536*sizeof(*histogram));
+  (void) GetMatrixElement(canny_cache,0,0,&pixel);
+  max=pixel.intensity;
+  min=pixel.intensity;
   edge_view=AcquireAuthenticCacheView(edge_image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   #pragma omp parallel for schedule(static,4) shared(status) \
@@ -1212,43 +1194,43 @@ MagickExport Image *CannyEdgeImage(const Image *image,const double radius,
         beta_pixel,
         pixel;
 
-      (void) GetMatrixElement(pixel_cache,x,y,&pixel);
+      (void) GetMatrixElement(canny_cache,x,y,&pixel);
       switch (pixel.orientation)
       {
         case 0:
         {
           /*
-            0 degrees.
+            0 degrees, north and south.
           */
-          (void) GetMatrixElement(pixel_cache,x-1,y,&alpha_pixel);
-          (void) GetMatrixElement(pixel_cache,x+1,y,&beta_pixel);
+          (void) GetMatrixElement(canny_cache,x,y-1,&alpha_pixel);
+          (void) GetMatrixElement(canny_cache,x,y+1,&beta_pixel);
           break;
         }
         case 1:
         {
           /*
-            45 degrees.
+            45 degrees, northwest and southeast.
           */
-          (void) GetMatrixElement(pixel_cache,x-1,y-1,&alpha_pixel);
-          (void) GetMatrixElement(pixel_cache,x+1,y+1,&beta_pixel);
+          (void) GetMatrixElement(canny_cache,x-1,y-1,&alpha_pixel);
+          (void) GetMatrixElement(canny_cache,x+1,y+1,&beta_pixel);
           break;
         }
         case 2:
         {
           /*
-            90 degrees.
+            90 degrees, east and west.
           */
-          (void) GetMatrixElement(pixel_cache,x,y-1,&alpha_pixel);
-          (void) GetMatrixElement(pixel_cache,x,y+1,&beta_pixel);
+          (void) GetMatrixElement(canny_cache,x-1,y,&alpha_pixel);
+          (void) GetMatrixElement(canny_cache,x+1,y,&beta_pixel);
           break;
         }
         case 3:
         {
           /*
-            135 degrees.
+            135 degrees, northeast and southwest.
           */
-          (void) GetMatrixElement(pixel_cache,x-1,y+1,&alpha_pixel);
-          (void) GetMatrixElement(pixel_cache,x+1,y-1,&beta_pixel);
+          (void) GetMatrixElement(canny_cache,x+1,y-1,&beta_pixel);
+          (void) GetMatrixElement(canny_cache,x-1,y+1,&alpha_pixel);
           break;
         }
       }
@@ -1256,14 +1238,16 @@ MagickExport Image *CannyEdgeImage(const Image *image,const double radius,
       if ((pixel.magnitude < alpha_pixel.magnitude) ||
           (pixel.magnitude < beta_pixel.magnitude))
         pixel.intensity=0;
-      else
-        if (pixel.magnitude > QuantumRange)
-          pixel.intensity=QuantumRange;
-      (void) SetMatrixElement(pixel_cache,x,y,&pixel);
+      (void) SetMatrixElement(canny_cache,x,y,&pixel);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
       #pragma omp critical (MagickCore_CannyEdgeImage)
 #endif
-      histogram[ScaleQuantumToShort(ClampToQuantum(pixel.intensity))]++;
+      {
+        if (pixel.intensity < min)
+          min=pixel.intensity;
+        if (pixel.intensity > max)
+          max=pixel.intensity;
+      }
       *q=0;
       q+=GetPixelChannels(edge_image);
     }
@@ -1274,70 +1258,47 @@ MagickExport Image *CannyEdgeImage(const Image *image,const double radius,
   /*
     Estimate hysteresis threshold.
   */
-  number_pixels=(size_t) (lower_precent*(image->columns*image->rows-
-    histogram[0]));
-  count=0;
-  for (i=65535; count < (ssize_t) number_pixels; i--)
-    count+=histogram[i];
-  upper_threshold=(double) ScaleShortToQuantum((unsigned short) i);
-  for (i=0; histogram[i] == 0; i++) ;
-  lower_threshold=upper_percent*(upper_threshold+
-    ScaleShortToQuantum((unsigned short) i));
-  histogram=(size_t *) RelinquishMagickMemory(histogram);
+  lower_threshold=lower_percent*(max-min)+min;
+  upper_threshold=upper_percent*(max-min)+min;
   /*
     Hysteresis threshold.
   */
   edge_view=AcquireAuthenticCacheView(edge_image,exception);
-  trace_view=AcquireAuthenticCacheView(edge_image,exception);
-#if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(static,4) shared(status) \
-    magick_threads(edge_image,edge_image,edge_image->rows,1)
-#endif
   for (y=0; y < (ssize_t) edge_image->rows; y++)
   {
-    register Quantum
-      *restrict q;
-
     register ssize_t
       x;
 
     if (status == MagickFalse)
       continue;
-    q=GetCacheViewAuthenticPixels(edge_view,0,y,edge_image->columns,1,
-      exception);
-    if (q == (Quantum *) NULL)
-      {
-        status=MagickFalse;
-        continue;
-      }
     for (x=0; x < (ssize_t) edge_image->columns; x++)
     {
       CannyInfo
         pixel;
 
+      register const Quantum
+        *restrict p;
+
       /*
         Edge if pixel gradient higher than upper threshold.
       */
-      status=GetMatrixElement(pixel_cache,x,y,&pixel);
+      p=GetCacheViewVirtualPixels(edge_view,x,y,1,1,exception);
+      if (p == (const Quantum *) NULL)
+        continue;
+      status=GetMatrixElement(canny_cache,x,y,&pixel);
       if (status == MagickFalse)
-        break;
-      if ((pixel.intensity >= upper_threshold) &&
-          (GetPixelIntensity(edge_image,q) == 0))
-        {
-          *q=QuantumRange;
-          status=TraceEdges(edge_image,trace_view,pixel_cache,x,y,
-            lower_threshold,exception);
-          if (status == MagickFalse)
-            break;
-        }
-      q+=GetPixelChannels(edge_image);
+        continue;
+      if ((GetPixelIntensity(edge_image,p) == 0.0) &&
+          (pixel.intensity >= upper_threshold))
+        status=TraceEdges(edge_image,edge_view,canny_cache,x,y,lower_threshold,
+          exception);
     }
-    if (SyncCacheViewAuthenticPixels(edge_view,exception) == MagickFalse)
-      status=MagickFalse;
   }
-  trace_view=DestroyCacheView(trace_view);
   edge_view=DestroyCacheView(edge_view);
-  pixel_cache=DestroyMatrixInfo(pixel_cache);
+  /*
+    Free resources.
+  */
+  canny_cache=DestroyMatrixInfo(canny_cache);
   return(edge_image);
 }
 \f