This section focuses on the implementation of image processing algorithms. The ingenious feature of this example is the selection of threshold values in the gray-scale transformation. It does not use any operators such as the well-ware and sobel operators in the OpenCV library, these operators are classic, but they all have their own limitations. The image must not have shadows. Otherwise, the error may be very large during contour extraction after the transformation, or even exceed the permitted range, in this example, the average brightness is obtained based on the image brightness and used as the threshold value. In practice, this algorithm has achieved good results with an error of about 1%.
There is not much nonsense. Let's look at the Code directly. First, create an Otsu (IplImage * src) function of the int type under the dlg class. the return value is the available Threshold value. The function parameter is the loaded source image:
Int I, j;
Int height = src-> height;
Int width = src-> width;
Float histogram [256] = {0 };
For (I = 0; I
{
Unsigned char * p = (unsigned char *) src-> imageData + src-> widthStep * I;
For (j = 0; j <width; j ++)
{
Histogram [* p ++] ++;
}
}
Int size = height * width;
For (I = 0; I <256; I ++)
{
Histogram [I] = histogram [I]/size;
}
Float avgValue = 0;
For (I = 0; I <256; I ++)
{
AvgValue + = I * histogram [I]; // average gray scale of the entire image
}
Int threshold;
Float maxVariance = 0;
Float w = 0, u = 0;
For (I = 0; I <256; I ++)
{
W + = histogram [I];
// Assume that the current grayscale I is the threshold value, and the ratio of pixels in 0-i gray scale to the entire Graph
U + = I * histogram [I];
Float t = avgValue * w-u;
Float variance = t * t/(w * (1-w ));
If (variance> maxVariance)
{
MaxVariance = variance;
Threshold = I;
}
}
Return threshold;
The above code is the focus of this example, which can improve the accuracy. The following is a number of branch node issues. We use the cvThreshold function provided by OpenCV to extract the contour, but this will produce many outlines, many things are not needed, so we need to fill in the filter box of the contour below. The function used is voidl FillInternalCintours, which has two parameters, one is the image pointer and the other is the filter threshold value, this threshold value is the key to filtering the contour. When the contour is smaller than this threshold value, it is filled with white and filtered out. The remaining value is the contour of the large black area, then, use the function provided by OpenCV to calculate the contour area to calculate the area. The code is as follows:
Double dConArea, MaxArea = 0, SecMaxArea = 0;
CvSeq * pContour = 0;
CvSeq * pConlnner = 0;
CvMemStorage * pStorage = 0;
If (pBinary)
{
// Search for all outlines
PStorage = cvcreatemstorage (0 );
CvFindContours (pBinary, pStorage, & pContour, sizeof (CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
// Fill all outlines
CvDrawContours (pBinary, pContour, CV_RGB (255,255,255), CV_RGB (255,255,255), 2, CV_FILLED, 8 );
// External contour Loop
Int wai = 0, nei = 0;
For (; pContour! = NULL; pContour = pContour-> h_next)
{
Wai ++;
// Inner contour Loop
For (pConlnner = pContour-> v_next; pConlnner! = NULL; pConlnner = pConlnner-> h_next)
{
Nei ++; // The number of inner outlines, which can be used later to scan the number of unconnected individuals in the image. Of course, the inner includes external images.
DConArea = fabs (cv1_area (pConlnner, CV_WHOLE_SEQ); // calculates the contour Area
// Printf ("% f \ n", dConArea );
If (dConArea <= dAreaThre) // fill if it is smaller than the filter Threshold Value
{
CvDrawContours (pBinary, pConlnner, CV_RGB (255,255,255), CV_RGB (255,255,255), 0, CV_FILLED, 8 );
}
SecMaxArea = dConArea;
If (MaxArea <dConArea) // This is used to extract the largest image area and the second largest image area. Generally, the reference object is a coin.
// Appears as the second largest area
{
SecMaxArea = MaxArea; // the second largest area
MaxArea = dConArea;
}
// If (SecMaxArea <dConArea) & (dConArea <MaxArea ))
// SecMaxArea = dConArea;
}
}
Char limit [20], ch2 [20];
Itoa (MaxArea, period, 10); // 10 indicates the converted hexadecimal number.
Itoa (SecMaxArea, ch2, 10 );
GetDlgItem (IDC_EDIT1)-> SetWindowText (plaintext );
GetDlgItem (IDC_EDIT2)-> SetWindowText (ch2 );
CvReleaseMemStorage (& pStorage );
// ShowImage (pBinary, IDC_ShowImg); // call the image display function. This function is intended to implement multiple views in a single box, but it is insufficient to support it.
// Call the display function to overwrite the original image. You can only create another window to display and filter the filled image. This is easier to compare and can be improved later.
// CvReleaseMemStorage (& pStorage );
PStorage = NULL;
}
The most critical code has been implemented. The following describes how to complete the remaining functions and add the Combo Box control to select the filter threshold value. In this example, 1000-6000 is added. Generally, 5000 is the most appropriate one, of course, the image size must be determined. The code for selecting the filter threshold value is relatively simple. Add it to the OnButton1ReadImg function. Before loading the image code, the code is as follows:
Int thresh;
CString str;
Int m;
M_down.GetWindowText (str );
If (str = "")
{
AfxMessageBox ("select the filter threshold! ");
Return;
}
M = atoi (str );
In addition, it refers to the call of some image processing functions and the closure of multiple device descriptors and device handles. Add them to the end of the loaded image to complete the program. The code is as follows:
IplImage * bin = cvCreateImage (cvGetSize (pic), 8, 1 );
Thresh = Otsu (pic );
CvThreshold (pic, bin, thresh, 255, CV_THRESH_BINARY );
FillInternalCintours (bin, m );
CvNamedWindow ("Result", CV_WINDOW_AUTOSIZE );
CvShowImage ("Result", bin );
// CvWaitKey (-1 );
// ResizeImage (pic); // scale the read image so that the maximum length and width are exactly 256, and then copy it to TheImage.
// ShowImage (TheImage, IDC_ShowImg); // call the image display function
// Read the image and cache it to the local variable ipl.
CvWaitKey (-1 );
CvReleaseImage (& ipl );
CvReleaseImage (& bin );
CvReleaseImage (& pic );
At this point, the entire procedure is completed. The reference object of the procedure is a coin with a fixed reference area. Of course, there are still many shortcomings in the program. The actual image extracted from the contour is not scaled. When a large image is opened, it is not displayed completely, which may be improved in the future.