1

Recognition of speed signs on one image by means of OpenCV

1. Finding the location of the sign

Let there be an image:

 

The simplest, but effective way to detect the sign of velocity is the contour analysis. To do this, you first need to binarize the image from either gray or full color. When working with a gray image, you can use adaptive binarization:

 

cv::Mat mat;

cv::adaptiveThreshold(image8, mat, 255, CV_ADAPTIVE_THRESH_MEAN_C,
 CV_THRESH_BINARY, 15, -5);

 

 

After that, the contours are:

 

std::vector<std::vector<cv::Point>> contours;

cv::findContours(mat, contours, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE);

 

The found outlines must be checked. And the candidate for the road sign will be like the one that fits in the square and which is similar to the circle

 

 int size = int(contours.size());			
for (int idx = 0; idx < size; idx++)
{
	double area = cv::contourArea(contours[idx]);
	if (area < min_area || area > max_area)
		continue;
	cv::Point2f center;
	float r;
	cv::minEnclosingCircle(contours[idx], center, r);
	if (fabs(CV_PI * r * r - area) < CV_PI * r * r * 0.3f)
	{
		// Add candidate
		//...
	}
}

 

In this case there was only one candidate

 

2. Candidate recognition

 

In this case, the candidates received from the previous stage are transferred to the entrance. The values of cv :: Rect

 

 cv::boundingRect(contours[idx])

 

There are many methods of character recognition, but here the simplest is shown – a comparison with the template.

The templates are set as follows:

 

 #define WIDTHDIGIT		5
#define HEIGHTDIGIT		10

const float Digits_Template[10*WIDTHDIGIT*HEIGHTDIGIT] =
{
	// 0
	0.0f,0.6f,1.0f,0.6f,0.0f,
	0.2f,0.6f,0.2f,0.6f,0.2f,
	0.6f,0.6f,0.0f,0.6f,0.6f,
	0.8f,0.4f,0.0f,0.4f,0.8f,
	1.0f,0.2f,0.0f,0.2f,1.0f,
	1.0f,0.2f,0.0f,0.2f,1.0f,
	0.8f,0.4f,0.0f,0.4f,0.8f,
	0.6f,0.6f,0.0f,0.6f,0.6f,
	0.2f,0.6f,0.2f,0.6f,0.2f,
	0.0f,0.6f,1.0f,0.6f,0.0f,
	// 1
	0.0f,0.0f,1.0f,1.0f,1.0f,
	0.6f,1.0f,1.0f,1.0f,1.0f,
	0.8f,0.4f,0.8f,1.0f,1.0f,
	0.0f,0.0f,0.5f,1.0f,1.0f,
	0.0f,0.0f,0.5f,1.0f,1.0f,
	0.0f,0.0f,0.5f,1.0f,1.0f,
	0.0f,0.0f,0.5f,1.0f,1.0f,
	0.0f,0.0f,0.5f,1.0f,1.0f,
	0.0f,0.0f,0.5f,1.0f,1.0f,
	0.0f,0.0f,0.5f,1.0f,1.0f,
	// 2
... and others digits

 

To compare with the template, it is better to binarize not by the adaptive method, but by the threshold method. Therefore, the original image is binarized using

cv::threshold(image8(rect), binary, t, 255, CV_THRESH_BINARY_INV);

where t is the threshold set by some criterion (Otsu for example)

 

 

After that, the contours are also:

 

std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;


cv::findContours(countImage, contours, hierarchy, 
cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);

 

And look for the location of the characters

 

	int all_rects = 0;
	cv::Rect Rects[2];


	for (size_t idx = 0; idx < contours.size(); idx++)
	{
		// Here we believe that the speed limit signs consist of one or two characters
		if (hierarchy[idx][3] != -1)
			continue;

		cv::Rect r = cv::boundingRect(contours[idx]);
		if (r.width > rect.width * 0.5 || r.height > rect.height * 0.9 ||
			r.width < rect.width * 0.1 || r.height < rect.height * 0.4)
			continue;
		all_rects++;
		if (all_rects > 2)
			break;
		Rects[all_rects - 1] = r;
	}

After that for each found zone there is a comparison with the template

 

As a result, the road sign is recognized.

Aleksandr Kruchinin

One Comment

Leave a Reply

Your email address will not be published. Required fields are marked *