Wednesday, April 11, 2012

Automatic Threshold

Threshold plays an important role in image segmentation. The threshold value in an image can be manually or automatically set. Manual threshold is not always suitable for all situation because different image may have different intensity distribution.

There are some developed automatic threshold algorithm that have been developed. In this article we are going to use the triangle algorithm, one of the simplest method that I know. It's quite old but still effective to be used under certain image conditions. The one we are going to write here is a slightly modified version from the one written in this reference:

Zack GW, Rogers WE, Latt SA (1977), "Automatic measurement of sister chromatid exchange frequency", J. Histochem. Cytochem. 25 (7): 741–53, PMID 70454

In order to follow these steps, we need to set up our compiler, in this example I use Visual Studio 2008 and OpenCV 2.1.

Ok, let's get our hands dirty, just make sure that OpenCV has been setup properly in your system:
1. Declare some IplImage objects:

 IplImage* image(0);     
IplImage* imageGrey(0);
IplImage* imageBin(0);

2. Load the image from a file:
 image     = cvLoadImage((char*)(void*)Marshal::StringToHGlobalAnsi(openFileDialog1->FileName), 1);    
imageGrey = cvCreateImage(cvSize(image->width, image->height), 8, 1); imageBin = cvCreateImage(cvSize(image->width, image->height), 8, 1);

3. Convert the color image into grayscale image, we're going to perform the threshold in grayscale value. We can also perform threshold for all the channels afterwards.

cvCvtColor(image, imageGrey, CV_BGR2GRAY );

4. Create the histogram of the image, there's a trick in histogram calculation here, hope you understand the trick:

int histogramGrey[256] = {0};
for(int row=0;rowheight;row++)
for(int col=0;colwidth;col++)
CvScalar m, n;
m = cvGet2D(imageGrey, row, col);

5. There's an assumption in this algorithm, the background and the foreground must be separated, so we're going to find out the peak of the background and the foreground. The simplest way is to calculate the center of mass of the histogram and find the peak in each region (left a nd right).

float Iz = 0;
float I = 0;
float peak = 0;

for(int i=0;i<256;i++)
Iz += (i * histogramGrey[i]);
I += histogramGrey[i];

peak = Iz / I;
6. Then the next step is to find the left peak (background) and the right peak (foreground). A simple peak search will do.

// finding the left peak
for(int i=0;i<(int)peak;i++)
if(peakL < histogramGrey[i])
peakL = i;
//finding the right peak
for(int j=(int)peak;j<256;j++)
if(peakR < histogramGrey[j])
peakR = j;
7. Ok, now we have a line con necting the left and the right peak. Then the next thing to do is to find a point in the histogram with the maximum distance from t he line. The code is a little bit dirty with typecasting but it works.
for(int i=peakL+dist;i<peakR-dist;i++)
float distance = (((peakR - peakL)*(histogramGrey[peakL] - histogramGrey[i])) - ((peakL - i)*(histogramGrey[peakR] - histogramGrey[peakL])) )/
sqrt( ((float)peakR - (float)peakL) * ((float)peakR - (float)peakL) + (((float)histogramGrey[peakR] - (float)histogramGrey[peakL]) * ((float)histogramGrey[peakR] - (float)histogramGrey[peakL])));

if(minDist > distance)
autoThresholdVal = i;
8. Finally we got the threshold valu e and then we can call cvThreshold() function.

cvThreshold( imageGrey, imageBin, autoThresholdVal, 255, CV_THRESH_BINARY );

With a little modification, the algorithm can be implemented real time by adding it into the webcam callback.

Et Voila! Here is the screen shot of the result. The left image is the live image from a webcam and the right image is the image after performing auto threshold.

Hope it's useful!

Labels: , , , ,


Post a Comment

<< Home