]> granicus.if.org Git - imagemagick/commitdiff
(no commit message)
authorcristy <urban-warrior@git.imagemagick.org>
Wed, 23 Apr 2014 00:20:40 +0000 (00:20 +0000)
committercristy <urban-warrior@git.imagemagick.org>
Wed, 23 Apr 2014 00:20:40 +0000 (00:20 +0000)
MagickCore/feature.c
MagickCore/matrix.c
MagickCore/matrix.h

index 6f90952a6a1b2c35fa5f0107951044047fc10cbc..9eb62ee1815362adf444045bdf3378df3a180035 100644 (file)
@@ -41,8 +41,8 @@
   Include declarations.
 */
 #include "MagickCore/studio.h"
-#include "MagickCore/property.h"
 #include "MagickCore/animate.h"
+#include "MagickCore/artifact.h"
 #include "MagickCore/blob.h"
 #include "MagickCore/blob-private.h"
 #include "MagickCore/cache.h"
@@ -79,6 +79,7 @@
 #include "MagickCore/paint.h"
 #include "MagickCore/pixel-accessor.h"
 #include "MagickCore/profile.h"
+#include "MagickCore/property.h"
 #include "MagickCore/quantize.h"
 #include "MagickCore/quantum-private.h"
 #include "MagickCore/random_.h"
@@ -561,7 +562,7 @@ MagickExport Image *CannyEdgeImage(const Image *image,const double radius,
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  HoughLinesImage() identifies lines in an image.
+%  HoughLinesImage() identifies lines in the image.
 %
 %  The format of the HoughLinesImage method is:
 %
@@ -579,10 +580,272 @@ MagickExport Image *CannyEdgeImage(const Image *image,const double radius,
 %    o exception: return any errors or warnings in this structure.
 %
 */
+
+static inline double MagickRound(double x)
+{
+  /*
+    Round the fraction to nearest integer.
+  */
+  if ((x-floor(x)) < (ceil(x)-x))
+    return(floor(x));
+  return(ceil(x));
+}
+
 MagickExport Image *HoughLinesImage(const Image *image,const size_t width,
   const size_t height,const size_t threshold,ExceptionInfo *exception)
 {
-  return((Image *) NULL);
+  CacheView
+    *image_view;
+
+  char
+    message[MaxTextExtent],
+    path[MaxTextExtent];
+
+  const char
+    *artifact;
+
+  double
+    hough_height;
+
+  Image
+    *lines_image = NULL;
+
+  ImageInfo
+    *image_info;
+
+  int
+    file;
+
+  MagickBooleanType
+    status;
+
+  MatrixInfo
+    *accumulator;
+
+  PointInfo
+    center;
+
+  register ssize_t
+    y;
+
+  size_t
+    accumulator_height,
+    accumulator_width,
+    line_count;
+
+  /*
+    Create the accumulator.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  accumulator_width=180;
+  hough_height=((sqrt(2.0)*(double) (image->rows > image->columns ?
+    image->rows : image->columns))/2.0);
+  accumulator_height=(size_t) (2.0*hough_height);
+  accumulator=AcquireMatrixInfo(accumulator_width,accumulator_height,
+    sizeof(double),exception);
+  if (accumulator == (MatrixInfo *) NULL)
+    ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+  if (NullMatrix(accumulator) == MagickFalse)
+    {
+      accumulator=DestroyMatrixInfo(accumulator);
+      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+    }
+  /*
+    Populate the accumulator.
+  */
+  status=MagickTrue;
+  center.x=(double) image->columns/2.0;
+  center.y=(double) image->rows/2.0;
+  image_view=AcquireVirtualCacheView(image,exception);
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if (GetPixelIntensity(image,p) > (QuantumRange/2))
+        {
+          register ssize_t
+            i;
+
+          for (i=0; i < 180; i++)
+          {
+            double
+              count,
+              radius;
+
+            radius=(((double) x-center.x)*cos(DegreesToRadians((double) i)))+
+              (((double) y-center.y)*sin(DegreesToRadians((double) i)));
+            (void) GetMatrixElement(accumulator,i,(ssize_t)
+              MagickRound(radius+hough_height),&count);
+            count++;
+            (void) SetMatrixElement(accumulator,i,(ssize_t)
+              MagickRound(radius+hough_height),&count);
+          }
+        }
+      p+=GetPixelChannels(image);
+    }
+  }
+  image_view=DestroyCacheView(image_view);
+  if (status == MagickFalse)
+    {
+      accumulator=DestroyMatrixInfo(accumulator);
+      return((Image *) NULL);
+    }
+  /*
+    Generate line segments from accumulator.
+  */
+  file=AcquireUniqueFileResource(path);
+  if (file == -1)
+    {
+      accumulator=DestroyMatrixInfo(accumulator);
+      return((Image *) NULL);
+    }
+  (void) FormatLocaleString(message,MaxTextExtent,"viewbox 0 0 %.20g %.20g\n",
+    (double) image->columns,(double) image->rows);
+  (void) write(file,message,strlen(message));
+  line_count=image->columns > image->rows ? image->columns/4 : image->rows/4;
+  if (threshold != 0)
+    line_count=threshold;
+  for (y=0; y < (ssize_t) accumulator_height; y++)
+  {
+    register ssize_t
+      x;
+
+    for (x=0; x < (ssize_t) accumulator_width; x++)
+    {
+      double
+        count;
+
+      (void) GetMatrixElement(accumulator,x,y,&count);
+      if (count >= (double) line_count)
+        {
+          double
+            maxima,
+            x1,
+            x2,
+            y1,
+            y2;
+
+          ssize_t
+            v;
+
+          /*
+            Is point a local maxima?
+          */
+          maxima=count;
+          for (v=((ssize_t) -(height/2)); v < ((ssize_t) (height/2)); v++)
+          {
+            ssize_t
+              u;
+
+            for (u=((ssize_t) -(width/2)); u < ((ssize_t) (width/2)); u++)
+            {
+              if ((u != 0) || (v !=0))
+                {
+                  (void) GetMatrixElement(accumulator,x+u,y+v,&count);
+                  if (count > maxima)
+                    {
+                      maxima=count;
+                      break;
+                    }
+                }
+            }
+            if (u < (ssize_t) (width/2))
+              break;
+          }
+          (void) GetMatrixElement(accumulator,x,y,&count);
+          if (maxima > count)
+            continue;
+          if ((x >= 45) && (x <= 135))
+            {
+              /*
+                y = (r-x cos(t))/sin(t)
+              */
+              x1=0.0;
+              y1=(double) ((y-(accumulator_height/2.0))-((x1-(image->columns/
+                2.0))*cos(DegreesToRadians((double) x))))/
+                sin(DegreesToRadians((double) x))+(image->rows/2.0);
+              x2=(double) image->columns;
+              y2=(double) ((y-(accumulator_height/2.0))-((x2-(image->columns/
+                2.0))*cos(DegreesToRadians((double) x))))/
+                sin(DegreesToRadians((double) x))+(image->rows/2.0);
+            }
+          else
+            {
+              /*
+                x = (r-y cos(t))/sin(t)
+              */
+              y1=0.0;
+              x1=(double) ((y-(accumulator_height/2.0))-((y1-(image->rows/2.0))*
+                sin(DegreesToRadians((double) x))))/cos(DegreesToRadians(
+                (double) x))+(image->columns/2.0);
+              y2=(double) image->rows;
+              x2=(double) ((y-(accumulator_height/2.0))-((y2-(image->rows/2.0))*
+                sin(DegreesToRadians((double) x))))/cos(DegreesToRadians(
+                (double) x))+(image->columns/2.0);
+            }
+          (void) FormatLocaleString(message,MaxTextExtent,"line %g,%g %g,%g\n",
+            x1,y1,x2,y2);
+          (void) write(file,message,strlen(message));
+        }
+    }
+  }
+  (void) close(file);
+  /*
+    Render lines to image canvas.
+  */
+  image_info=AcquireImageInfo();
+  image_info->background_color=image->background_color;
+  (void) FormatLocaleString(image_info->filename,MaxTextExtent,"mvg:%s",path);
+  artifact=GetImageArtifact(image,"background");
+  if (artifact != (const char *) NULL)
+    (void) SetImageOption(image_info,"background",artifact);
+  artifact=GetImageArtifact(image,"fill");
+  if (artifact != (const char *) NULL)
+    (void) SetImageOption(image_info,"fill",artifact);
+  artifact=GetImageArtifact(image,"stroke");
+  if (artifact != (const char *) NULL)
+    (void) SetImageOption(image_info,"stroke",artifact);
+  artifact=GetImageArtifact(image,"strokewidth");
+  if (artifact != (const char *) NULL)
+    (void) SetImageOption(image_info,"strokewidth",artifact);
+  lines_image=ReadImage(image_info,exception);
+  artifact=GetImageArtifact(image,"hough-lines:accumulator");
+  if ((lines_image != (Image *) NULL) &&
+      (IsStringTrue(artifact) != MagickFalse))
+    {
+      Image
+        *accumulator_image;
+
+      accumulator_image=MatrixToImage(accumulator,exception);
+      if (accumulator_image != (Image *) NULL)
+        AppendImageToList(&lines_image,accumulator_image);
+    }
+  /*
+    Free resources.
+  */
+  accumulator=DestroyMatrixInfo(accumulator);
+  image_info=DestroyImageInfo(image_info);
+  (void) RelinquishUniqueFileResource(path);
+  return(GetFirstImageInList(lines_image));
 }
 \f
 /*
index d0752e4a3f80a02d11814c51aea1bb2f2ff8cc58..b19dc2eb9ed7ead327edbb9bbce50313deed9731 100644 (file)
@@ -47,6 +47,7 @@
 #include "MagickCore/exception-private.h"
 #include "MagickCore/matrix.h"
 #include "MagickCore/memory_.h"
+#include "MagickCore/pixel-accessor.h"
 #include "MagickCore/pixel-private.h"
 #include "MagickCore/resource_.h"
 #include "MagickCore/semaphore.h"
@@ -871,7 +872,8 @@ MagickExport void LeastSquaresAddTerms(double **matrix,double **vectors,
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  MatrixToImage() returns a matrix as an image.
+%  MatrixToImage() returns a matrix as an image.  The matrix elements must be
+%  of type double otherwise nonsense is returned.
 %
 %  The format of the MatrixToImage method is:
 %
@@ -888,7 +890,109 @@ MagickExport void LeastSquaresAddTerms(double **matrix,double **vectors,
 MagickExport Image *MatrixToImage(const MatrixInfo *matrix_info,
   ExceptionInfo *exception)
 {
-  return((Image *) NULL);
+  CacheView
+    *image_view;
+
+  double
+    max_value,
+    min_value,
+    scale_factor,
+    value;
+
+  Image
+    *image;
+
+  MagickBooleanType
+    status;
+
+  ssize_t
+    y;
+
+  assert(matrix_info != (const MatrixInfo *) NULL);
+  assert(matrix_info->signature == MagickSignature);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  if (matrix_info->stride < sizeof(double))
+    return((Image *) NULL);
+  /*
+    Determine range of matrix.
+  */
+  (void) GetMatrixElement(matrix_info,0,0,&value);
+  min_value=value;
+  max_value=value;
+  for (y=0; y < (ssize_t) matrix_info->rows; y++)
+  {
+    register ssize_t
+      x;
+
+    for (x=0; x < (ssize_t) matrix_info->columns; x++)
+    {
+      if (GetMatrixElement(matrix_info,x,y,&value) == MagickFalse)
+        continue;
+      if (value < min_value)
+        min_value=value;
+      else
+        if (value > max_value)
+          max_value=value;
+    }
+  }
+  if ((min_value == 0.0) && (max_value == 0.0))
+    scale_factor=0;
+  else
+    if (min_value == max_value)
+      {
+        scale_factor=(double) QuantumRange/min_value;
+        min_value=0;
+      }
+    else
+      scale_factor=(double) QuantumRange/(max_value-min_value);
+  /*
+    Convert matrix to image.
+  */
+  image=AcquireImage((ImageInfo *) NULL,exception);
+  image->columns=matrix_info->columns;
+  image->rows=matrix_info->rows;
+  image->colorspace=GRAYColorspace;
+  status=MagickTrue;
+  image_view=AcquireAuthenticCacheView(image,exception);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(static,4) shared(status) \
+    magick_threads(image,image,image->rows,1)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    double
+      value;
+
+    register Quantum
+      *q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if (GetMatrixElement(matrix_info,x,y,&value) == MagickFalse)
+        continue;
+      value=scale_factor*(value-min_value);
+      *q=ClampToQuantum(value);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+  }
+  image_view=DestroyCacheView(image_view);
+  if (status == MagickFalse)
+    image=DestroyImage(image);
+  return(image);
 }
 \f
 /*
index 97c9afdc16ca1af6b3c4adfad1a74a4c440ecb21..ac4e702df5c3598e074ec65808d03d2d1dd658c4 100644 (file)
@@ -30,7 +30,7 @@ extern MagickExport double
   **RelinquishMagickMatrix(double **,const size_t);
 
 extern MagickExport Image
-  *MatrixToImage(const MatrixInfo *,ExceptionInfo *));
+  *MatrixToImage(const MatrixInfo *,ExceptionInfo *);
 
 extern MagickExport MagickBooleanType
   GetMatrixElement(const MatrixInfo *,const ssize_t,const ssize_t,void *),