opencv simple digital recognition

foreword

Use opencv for simple digital recognition

Note: The number recognition in this case is only used as a learning reference. If you want to realize the number recognition, the actual situation is much more complicated

train of thought

① Image preprocessing, convert the image to grayscale and then binarize it to make it white and black

②Find the circumscribed rectangle, find the outermost contour of the number in the original picture, and find the circumscribed rectangle according to the outermost contour

③Template matching, the circumscribed rectangle is the ROI area, the digital area is intercepted, and the template is matched

④ output result

Specific steps

First read in an original image, back it up (needed later), convert it to grayscale, then binarize it, and then back it up (needed later), because finding the outline will destroy the original image, so it needs to be backed up, and then I make this material The original image is a very simple black background with white characters written on it. There is no other noise, so it only needs to be converted to grayscale and binarized. If it is another image, it may need to be filtered, corroded and expanded to remove noise. If the removal is not clean , we need to filter it, because we only need to get the outline of the number, and finally it will become white and black, as shown in the figure below

Mat img = imread("kk.png");  
Mat clone_img = img.clone(); //原图备份
cvtColor(img, img, COLOR_BGR2GRAY); //图片转灰度
threshold(img, img, 100, 255, THRESH_BINARY); //二值化
Mat clone_img1 = img.clone(); //备份二值化后的原图

Then start to find the contour. After finding the contour (you can not draw the contour and the circumscribing rectangle), find the circumscribing rectangle according to the contour. At this time, we define a container to store the effective number area in the original image, because after you find the circumscribing rectangle, The number can be intercepted directly by ROI. Note that we need to intercept the ROI in the original binarized image backed up before, and reset the size to the size of our template image. Then we save the number for later use. identification

vector<vector<Point>> contours; //存储原图轮廓
vector<Vec4i> hierarcy;
findContours(img, contours, hierarcy, RETR_EXTERNAL, CHAIN_APPROX_NONE);//查找轮廓
drawContours(clone_img, contours, -1, Scalar(0, 255, 0), 1, 8);//绘制轮廓
vector<Rect> sort_rect(contours.size()); //外接矩形
vector<Mat> img_mat;//存储原图中的有效数字区域
for (int i = 0; i < contours.size(); i++)
{
	sort_rect[i] = boundingRect(contours[i]); //外接矩形
	Mat roi = clone_img1(sort_rect[i]);
	Mat dstroi;
	resize(roi, dstroi, Size(40, 50), 0, 0); //重设大小
	img_mat.push_back(dstroi);
    //绘制外接矩形
	rectangle(clone_img, Point(sort_rect[i].x, sort_rect[i].y),
	Point(sort_rect[i].x + sort_rect[i].width, sort_rect[i].y + sort_rect[i].height), 
     Scalar(0, 0, 255), 1, 8);
}

Then we need to sort the contours, because the contours searched by opencv are not in order, but random, but we must recognize the numbers in order, otherwise the recognition result must be wrong, we can use the circumscribed rectangle of the contour The x coordinates are sorted, and the x coordinates increase from left to right. Bubble sorting is used here. The sorted order is the correct order of the numbers in the original picture.

//对矩形进行排序,因为轮廓的顺序不一定是数字真正的顺序
for (int i = 0; i < sort_rect.size(); i++)
{
	for (int j = i + 1; j < sort_rect.size(); j++)
	{
		int j_x = sort_rect[j].x;
		int i_x = sort_rect[i].x;
		if (j_x < i_x)
		{
			Mat temps = img_mat[i];
			img_mat[i] = img_mat[j];
			img_mat[j] = temps;
		}
	}
}

 Load the template. The template is prepared by yourself. You can draw a 0123456789 by yourself, and then save the roi according to the search outline and the circumscribed rectangle. After saving, we will create a container to store the template image. Note that this template image also needs to be converted to grayscale Binary processing for easy matching and identification

vector<Mat> myTemplate; //模板容器
for (int i = 0; i < 10; i++)
{
	string name = format("%d.png", i);
	Mat temp = imread(name);
	cvtColor(temp, temp, COLOR_BGR2GRAY);
	threshold(temp, temp, 100, 255, THRESH_BINARY);
	myTemplate.push_back(temp);
}

Finally, there is template matching. There are many ways to match. Here, we use pixel matching between numbers and templates, and draw conclusions based on the percentage of the same pixels. The more identical pixels, the matching similarity The higher the value, the one with the highest matching degree will be used as the final recognition result

double compare(Mat &img, Mat &temp)               
{
	Mat my_temp;
	resize(temp, my_temp, img.size());
	int rows, cols;
	uchar *img_point, *temp_point; //像素类型uchar
	rows = my_temp.rows;
	cols = my_temp.cols*img.channels();
	double result, same = 0.0, different = 0.0;
	for (int i = 0; i < rows; i++)       //遍历图像像素
	{
        //获取像素值
		img_point = img.ptr<uchar>(i); 
		temp_point = my_temp.ptr<uchar>(i);
		for (int j = 0; j < cols; j++)
		{
			if (img_point[j] == temp_point[j])
				same++;         //记录像素相同的个数
			else
				different++;    //记录像素不同的个数
		}
	}
	result = same / (same + different);
	return result;                     //返回匹配结果
}
vector<int> seq;//顺序存放识别结果
for (int i = 0; i < img_mat.size(); i++)
{
	double com = 0;
	double min = 0;
	int min_seq = 0;//记录识别结果
	for (int j = 0; j < myTemplate.size(); j++)
	{
		com = compare(img_mat[i], myTemplate[j]);
		if (com > min)
		{
			min = com;
			min_seq = j;
		}
		com = 0;
	}
	seq.push_back(min_seq);
}
//输出结果
cout << "识别结果为:";
for (int i = 0; i < seq.size(); i++)
cout << seq[i];
	

Recognition results, correct recognition, even if the size is zoomed, the recognition can be successful

The above is the simple digital recognition of opencv

Like it if you like it~

Likes, collections and attention are the biggest support for me~

Guess you like

Origin blog.csdn.net/m0_71741835/article/details/127937354