First, we will obtain a plate image patch as an input to the OCR segmentation function with an equalized histogram. We then need to apply only a threshold filter and use this threshold image as the input of a Find contours algorithm. We can observe this process in the following image:
This segmentation process is coded as follows:
Mat img_threshold;
threshold(input, img_threshold, 60, 255, CV_THRESH_BINARY_INV);
if(DEBUG)
imshow("Threshold plate", img_threshold);
Mat img_contours;
img_threshold.copyTo(img_contours);
//Find contours of possibles characters
vector< vector< Point>> contours;
findContours(img_contours, contours, // a vector of contours
CV_RETR_EXTERNAL, // retrieve the external contours
CV_CHAIN_APPROX_NONE); // all pixels of each contours
We used the CV_THRESH_BINARY_INV parameter to invert the threshold output by turning the white input values black and the black input values white. This is needed to get the contours of each character, because the contours algorithm searches for white pixels.
For each detected contour, we can make a size verification and remove all regions where the size is smaller or the aspect is not correct. In our case, the characters have a 45/77 aspect, and we can accept a 35% error of aspect for rotated or distorted characters. If an area is higher than 80%, we will consider that region to be a black block and not a character. For counting the area, we can use the countNonZero function, which counts the number of pixels with a value higher than zero:
bool OCR::verifySizes(Mat r){
//Char sizes 45x77
float aspect=45.0f/77.0f;
float charAspect= (float)r.cols/(float)r.rows;
float error=0.35;
float minHeight=15;
float maxHeight=28;
//We have a different aspect ratio for number 1, and it can be ~0.2
float minAspect=0.2;
float maxAspect=aspect+aspect*error;
//area of pixels
float area=countNonZero(r);
//bb area
float bbArea=r.cols*r.rows;
//% of pixel in area
float percPixels=area/bbArea;
if(percPixels < 0.8 && charAspect > minAspect && charAspect <
maxAspect && r.rows >= minHeight && r.rows < maxHeight)
return true;
else
return false;
}
If a segmented character is verified, we have to preprocess it to set the same size and position for all characters, and save it in a vector with the auxiliary CharSegment class. This class saves the segmented character image and the position that we need to order the characters, because the find contour algorithm does not return the contours in the correct order required.