From 0f09a8ceb30556f22c8800ed7ff8faa260e4f6dc Mon Sep 17 00:00:00 2001 From: cristy Date: Wed, 23 Apr 2014 00:20:40 +0000 Subject: [PATCH] --- MagickCore/feature.c | 269 ++++++++++++++++++++++++++++++++++++++++++- MagickCore/matrix.c | 108 ++++++++++++++++- MagickCore/matrix.h | 2 +- 3 files changed, 373 insertions(+), 6 deletions(-) diff --git a/MagickCore/feature.c b/MagickCore/feature.c index 6f90952a6..9eb62ee18 100644 --- a/MagickCore/feature.c +++ b/MagickCore/feature.c @@ -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)); } /* diff --git a/MagickCore/matrix.c b/MagickCore/matrix.c index d0752e4a3..b19dc2eb9 100644 --- a/MagickCore/matrix.c +++ b/MagickCore/matrix.c @@ -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); } /* diff --git a/MagickCore/matrix.h b/MagickCore/matrix.h index 97c9afdc1..ac4e702df 100644 --- a/MagickCore/matrix.h +++ b/MagickCore/matrix.h @@ -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 *), -- 2.40.0