Canny Edge Detection Auto Thresholding

In the example I gave in “Interfacing IPP with Magick++“, I illustrated how to use Intel’s Integrated Performance Primitives (IPP) to perform edge detection. One issue with Canny edge detection algorithm is that we need to specify a high threshold and a low threshold. How to select those threshold values affect the quality of the detected edge greatly. And in my previous example, the threshold values were chosen manually. In this blog post, I will examine a couple of simple methods that can be used to automatically determine the threshold values.

The simplest way is to use the mean value of the gray scale image pixel values. As a rule of thumb, we set the low threshold to 0.66*[mean value] and set the high threshold to 1.33*[mean value]. Another way is to use the median color in the gray scale image and uses 0.66*[median value] and 1.33*[median value] accordingly. For typical images, these two methods achieve comparable results.

For example, the following shows the picture of a building along with its histogram (original image from Microsoft Research Digital Image. Please see Microsoft Research Digital Image License Agreement for more information):

 Building Building Histogram

The following shows the edge detection results using Canny algorithm (left image uses mean value auto-thresholding, right image uses median value auto-thresholding) and the results exhibit very little visible differences.

 Building (Canny Mean) Building (Canny Median)

However, for images has non-equalized histogram (see the picture of cloud and its histogram below):

 Cloud Cloud Histogram

Canny Edge detection result based on mean value auto-thresholding is pretty poor (see image on the left below), while edge detection based on median value auto-thresholding achieved much better result (see image on the right below)

 Cloud (Canny Mean) Cloud (Canny Median)

Alternatively, we could have performed histogram equalization on the image first before applying Canny edge detection with mean auto-thresholding:

 Cloud Equalized Cloud Equalized Histogram

And after image equalization, both mean and median value auto-thresholding achieved similar results.

 Cloud Equalized (Canny Mean) Cloud Equalized (Canny Median)

So the Canny edge detection using median value auto-thresholding seems to adapt to different types of images very well (note selecting the median value selection can be thought as equalizing the histogram, except that the pixel values are not changed during such operation).

The following is the code listing for the histogram calculation using IPP (based on the image class I created earlier)

```/** @brief Get the min max mean value statistics for the current image
*   @param min, max, mean: these are output parameters that are passed
*         back by reference.
*/
void IPPGrayImage::MinMaxMean(float& min, float& max, double& mean)
{
IppStatus sts;
IppiSize origImgSize = {_width, _height};

sts = ippiMinMax_32f_C1R(_imgBuffer, _width * PIXEL_SIZE, origImgSize, &min, &max);
assert(sts == ippStsNoErr);
sts = ippiMean_32f_C1R(_imgBuffer, _width * PIXEL_SIZE, origImgSize, &mean, ippAlgHintFast);
assert(sts == ippStsNoErr);
}

/** @brief Calculate the histogram of the image
*   @param nLevel: the number of bins in the histogram
*        levels: this is the optional levels user can pass in (histogram will be then
*                calculated with these levels instead of the uniform levels by default.
*   @return an integer array which contains the histogram.
*   @note the histogram is by default calculated using uniform bins across the color range.
*/
unsigned int * IPPGrayImage::GetHistogram(unsigned int nLevel, float levels[])
{
IppStatus sts;
Ipp32f* l = new Ipp32f[nLevel];
IppiSize origImgSize = {_width, _height};

unsigned int* bins = new unsigned int[nLevel - 1];

float minVal = 0, maxVal = 0, stepVal = 0;
double meanVal = 0;
if (levels != NULL)
{
for (unsigned int i = 0; i < nLevel; i++)
{
l[i] = levels[i];
}
}
else
{
MinMaxMean(minVal, maxVal, meanVal);
stepVal = (maxVal - minVal) / (float) nLevel;

for (unsigned int i = 0; i < nLevel; i++)
{
l[i] = minVal + stepVal * i;
}
}

sts = ippiHistogramRange_32f_C1R(_imgBuffer, _width * PIXEL_SIZE, origImgSize, (Ipp32s*) bins, (Ipp32f*) l, nLevel);
return bins;
}
```
Be Sociable, Share!

1. rob says:

is there any vb6 code for canny autothresholding? tnx!

2. mehdi says:

i need canny edge detection in vb(source code )
tnx

• lily says:

#include”stdafx.h”
#include “cv.h”
#include “cxcore.h”
#include”cvaux.h”
#include “highgui.h”
int main()
{
IplImage* newImg = NULL;
IplImage* grayImg = NULL;
IplImage* contourImg = NULL;
IplImage* cannyImg;
//parameters for the contour detection
CvMemStorage * storage = cvCreateMemStorage(0);
CvSeq * contour = 0;
int mode = CV_RETR_EXTERNAL;
mode = CV_RETR_CCOMP; //detect both outside and inside contour
cvNamedWindow(“src”, 1);
cvNamedWindow(“contour”,1);
//create a single channel 1 byte image (i.e. gray-level image)
grayImg = cvCreateImage( cvSize(newImg->width, newImg->height), IPL_DEPTH_8U, 1 );
//convert original color image (3 channel rgb color image) to gray-level image
cvCvtColor( newImg, grayImg, CV_BGR2GRAY );
cvShowImage( “src”, newImg );

cannyImg = cvCreateImage(cvGetSize(newImg), IPL_DEPTH_8U, 1);
// canny edge detection
cvCanny(grayImg, cannyImg, 50, 150, 3);
cvNamedWindow(“src”, 1);
cvNamedWindow(“canny”,1);
cvShowImage( “src”, newImg );
cvShowImage( “canny”, cannyImg );
cvReleaseImage( &newImg ); cvReleaseImage( &grayImg ); cvReleaseImage( &contourImg );
cvReleaseMemStorage(&storage);
return 0;
}

• lily says:

this code should be pasted in visual studio and also run opencv on ur sys to run the code. contact me on my e-mail if u hve any doubts, i did as my proj this sem so i can help u..

3. Gustav says:

Your code will miss the values in the last bin i.e (maxVal-stepVal)->maxVal. your array only assigns bins between minVal and minVal+stepVal*(nLevel-1).
If you had 20 bins, a min of 20 a max of 220 you would have a step of 10 which would give you a max bin value of (20+10*(19))=210 so your histogram would never have any values for the bin between 210 and 220. The ippiHistogramRange_32f_C1R function requires the max value to be the last pLevels array.

try

unsigned int* bins = new unsigned int[nLevel];

for (unsigned int i = 0; i <= nLevel; i++)
{
l[i] = minVal + stepVal * i;
}

4. Gustav says:

Ipp32f* l = new Ipp32f[nLevel+1];

5. ruchi says:

hello sir/mam,
I am trying to detect blink in my project. I have thresholded the image and extracted the eye part. Now i want to count the number of pixels in sclera so that when i close my eyes i get reduced number of pixels and conclude that my eye is closed and apply blink function. But i am not able to do it. Could you please help me regarding this or suggest me any other way to implememnt it..
THANKYOU :)

6. […] http://www.kerrywong.com/2009/05/07/canny-edge-detection-auto-thresholding/ is one of the few resources that shows how to choose thresholds Tlow and […]

7. hassan says:

i need the full code for canny and auto thresholding

8. Parth says:

Hi,
I would like to know if there is any reference you can cite. I need to reference this method in a paper that I am writing.

9. Harold says:

This can’t work, you are using the mean of the image signal range when you are threshold a gradient information.

Kind regards,
Harold

10. supraja says:

hi sir,
I’m working on plant disease detection can you plz help me which algorithm is suitable for image processing
to extract features and how to pass these features to classification methods