%
% 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 upper_percent,ExceptionInfo *exception)
%
% A description of each parameter follows:
%
*edge_view,
*trace_view;
+ CannyInfo
+ pixel;
+
char
geometry[MaxTextExtent];
double
- upper_threshold,
- lower_threshold;
+ lower_threshold,
+ upper_threshold;
Image
*edge_image;
if (status == MagickFalse)
continue;
- p=GetCacheViewVirtualPixels(edge_view,-1,y-1,edge_image->columns+2,3,
+ p=GetCacheViewVirtualPixels(edge_view,0,y,edge_image->columns+1,2,
exception);
if (p == (const Quantum *) NULL)
{
dx,
dy;
+ int
+ orientation;
+
register const Quantum
*restrict kernel_pixels;
v;
static double
- Gx[3][3] =
+ Gx[2][2] =
{
- { -1.0, 0.0, +1.0 },
- { -2.0, 0.0, +2.0 },
- { -1.0, 0.0, +1.0 }
+ { -1.0, +1.0 },
+ { -1.0, +1.0 }
},
- Gy[3][3] =
+ Gy[2][2] =
{
- { +1.0, +2.0, +1.0 },
- { 0.0, 0.0, 0.0 },
- { -1.0, -2.0, -1.0 }
+ { +1.0, +1.0 },
+ { -1.0, -1.0 }
};
(void) ResetMagickMemory(&pixel,0,sizeof(pixel));
dx=0.0;
dy=0.0;
kernel_pixels=p;
- for (v=0; v < 3; v++)
+ for (v=0; v < 2; v++)
{
ssize_t
u;
- for (u=0; u < 3; u++)
+ for (u=0; u < 2; u++)
{
double
intensity;
intensity=GetPixelIntensity(edge_image,kernel_pixels+u);
- dx+=Gx[v][u]*intensity;
- dy+=Gy[v][u]*intensity;
+ dx+=0.5*Gx[v][u]*intensity;
+ dy+=0.5*Gy[v][u]*intensity;
}
- kernel_pixels+=edge_image->columns+2;
+ kernel_pixels+=edge_image->columns+1;
}
pixel.magnitude=sqrt(dx*dx+dy*dy);
pixel.orientation=2;
- if (dx != 0.0)
+ if (fabs(dx) > MagickEpsilon)
{
double
theta;
if (theta < 0.0)
{
if (theta < -2.41421356237)
- pixel.orientation=0;
+ pixel.orientation=2;
else
if (theta < -0.414213562373)
pixel.orientation=1;
else
- pixel.orientation=2;
+ pixel.orientation=0;
}
else
{
if (theta > 2.41421356237)
- pixel.orientation=0;
+ pixel.orientation=2;
else
if (theta > 0.414213562373)
pixel.orientation=3;
else
- pixel.orientation=2;
+ pixel.orientation=0;
}
}
if (SetMatrixElement(pixel_cache,x,y,&pixel) == MagickFalse)
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(pixel_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) \
/*
0 degrees.
*/
- (void) GetMatrixElement(pixel_cache,x,y-1,&alpha_pixel);
- (void) GetMatrixElement(pixel_cache,x,y+1,&beta_pixel);
+ (void) GetMatrixElement(pixel_cache,x-1,y,&alpha_pixel);
+ (void) GetMatrixElement(pixel_cache,x+1,y,&beta_pixel);
break;
}
case 1:
/*
90 degrees.
*/
- (void) GetMatrixElement(pixel_cache,x-1,y,&alpha_pixel);
- (void) GetMatrixElement(pixel_cache,x+1,y,&beta_pixel);
+ (void) GetMatrixElement(pixel_cache,x,y-1,&alpha_pixel);
+ (void) GetMatrixElement(pixel_cache,x,y+1,&beta_pixel);
+ break;
}
case 3:
{
/*
135 degrees.
*/
- (void) GetMatrixElement(pixel_cache,x+1,y-1,&alpha_pixel);
- (void) GetMatrixElement(pixel_cache,x-1,y+1,&beta_pixel);
+ (void) GetMatrixElement(pixel_cache,x-1,y+1,&alpha_pixel);
+ (void) GetMatrixElement(pixel_cache,x+1,y-1,&beta_pixel);
+ break;
}
}
pixel.intensity=pixel.magnitude;
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);
#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);
}
/*
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.
*/
#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 Quantum
+ *restrict q;
+
/*
Edge if pixel gradient higher than upper threshold.
*/
status=GetMatrixElement(pixel_cache,x,y,&pixel);
if (status == MagickFalse)
break;
+ q=GetCacheViewAuthenticPixels(edge_view,x,y,1,1,exception);
+ if (q == (PixelPacket *) NULL)
+ {
+ status=MagickFalse;
+ continue;
+ }
if ((pixel.intensity >= upper_threshold) &&
(GetPixelIntensity(edge_image,q) == 0))
{
*q=QuantumRange;
+ status=SyncCacheViewAuthenticPixels(edge_view,exception);
+ if (status == MagickFalse)
+ continue;
status=TraceEdges(edge_image,trace_view,pixel_cache,x,y,
lower_threshold,exception);
if (status == MagickFalse)
- break;
+ continue;
}
- q+=GetPixelChannels(edge_image);
}
if (SyncCacheViewAuthenticPixels(edge_view,exception) == MagickFalse)
status=MagickFalse;
}
- trace_view=DestroyCacheView(edge_view);
+ trace_view=DestroyCacheView(trace_view);
edge_view=DestroyCacheView(edge_view);
pixel_cache=DestroyMatrixInfo(pixel_cache);
return(edge_image);