Simple digit recognition based on opencv

Posted by txmedic03 on Wed, 08 Sep 2021 11:40:04 +0200

Because my knowledge is still shallow, I can't use python deep learning to identify the numbers here, so I completely use opencv to identify the numbers, and then share and record what I saw and thought in the learning process here

Problems to be solved
This is a number to be recognized. I first extract the ROI of the image, and only the number is left in the extraction result, excluding other unimportant elements,

This is the ROI picture. All we have to do is identify the numbers in the picture,
Ideas for solving problems
1. First, divide the numbers in this picture into five small pictures. Each picture contains a number. Why do you want to divide it? Because we can't let the computer know how much this number is, we can only let the computer identify the features according to the features, and then each feature corresponds to a value. First, post the program for dividing the picture, and then there will be a section of thought explanation below the program

#include <opencv2/core/core.hpp>
#include <opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <ctime>
using namespace std ;
using namespace cv;
#include <map>
Mat src_threshold;
Mat src_dil;
int sunImage(Mat &image);
vector<Mat>ROI_image;//Picture to be tested
int main() 
{
	clock_t start ,finish;
	start=clock();
	Mat src;
	src=imread("D:\\vspic\\picture\\number6.jpg");
	resize(src,src,Size(src.cols/7,src.rows/7));
	imshow("src",src);
	Mat src_gray;
	cvtColor(src,src_gray,COLOR_BGR2GRAY);
	//imshow("gsrc_ray",src_gray);
	Mat src_blur;
	blur(src_gray,src_blur,Size(9,9));
	//GaussianBlur(src_gray,src_blur,Size(11,11),1,1);
	Mat src_threshold;
	threshold(src_blur,src_threshold,150,255,THRESH_OTSU);
	//imshow("src_threshold",src_threshold);
	Mat src_canny;
	Canny(src_threshold,src_canny,125,255,3);
	//imshow("src_canny",src_canny);
	vector<vector<Point>>contours_src;
	vector<Vec4i>hierarchy_src(contours_src.size());
	findContours(src_canny,contours_src,hierarchy_src,RETR_EXTERNAL,CHAIN_APPROX_NONE);
	Rect rect_s;
	Rect choose_rect;
	for (size_t i=0;i<contours_src.size();i++)
	{
		rect_s=boundingRect(contours_src[i]);
		double width=rect_s.width;
		double height= rect_s.height;
		double bizhi=width/height;
		if (bizhi>1.5&&height>50)
		{
			/*rectangle(src,rect_s.tl(),rect_s.br(),Scalar(255,255,255),1,1,0);*/
			choose_rect=Rect(rect_s.x+20,rect_s.y+30,rect_s.x-30,rect_s.y-108);
		}
	}
	Mat roi;
	roi=src(choose_rect);
	//imshow("src_",roi);
	Mat img =roi;
	Mat gray_img;
	// Generate gray image
	cvtColor(img, gray_img, CV_BGR2GRAY);
	// Gaussian blur
	Mat img_gau;
	GaussianBlur(gray_img, img_gau, Size(3, 3), 0, 0);
	// Threshold segmentation
	Mat img_seg;
	threshold(img_gau, img_seg, 0, 255, THRESH_BINARY + THRESH_OTSU);
	Mat element;
	element=getStructuringElement(MORPH_RECT,Size(8,8));
	erode(img_seg,src_dil,element);
	//imshow("src_dil",src_dil);
	// Edge detection, contour extraction
	Mat img_canny;
	Canny(src_dil, img_canny, 200, 100);
	//imshow("canny",img_canny);
	vector<vector<Point>> contours;
	vector<Vec4i> hierarchy(contours.size());
	findContours(img_canny, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE, Point());//Find contour
	int size = (int)(contours.size());//Number of contours
	//cout<<size<<endl; 6
	// Saves the sequence number of the symbol border
	vector<int> num_order;//Define an integer int container
	map<int, int> num_map;//Container requires two template parameters: keyword and template object. Here, an int is defined as the index and has an associated pointer to int
	for (int i = 0; i < size; i++)
   {
		// Get border data
		Rect number_rect = boundingRect(contours[i]);
		int width = number_rect.width;//Gets the width of the rectangle
		int height = number_rect.height;//Gets the height of the rectangle
		// Remove the small interference frame and filter out the appropriate area
		if (width > img.cols/20 )
		{
			rectangle(img,number_rect.tl(),number_rect.br(),Scalar(255,255,255),1,1,0);//draw rectangle
			imshow("img",img);//Show rectangle
			num_order.push_back(number_rect.x);//Put the x coordinate of the rectangle into number_ In the order container, add a new element to the end of the vector,
			//The position is the next element of the current element
			num_map[number_rect.x] = i;//Store the key value pair, number, into the map_ Rect. X is the keyword and i is the value
			/*Put the x coordinate of the rectangular box together with the corresponding i value into the map container to form a one-to-one corresponding key value pair
			*/
		}
	}
	// Extract in symbolic order
	sort(num_order.begin(), num_order.end());/*Put number_ The contents of the order container are arranged from small to large, which is the coordinate of X*/
	for (int i = 0; i < num_order.size(); i++) {
		Rect number_rect = boundingRect(contours[num_map.find(num_order[i])->second]);//num_ There are coordinates in order
		//cout<<"num_ The value of map is: "< < num"_ map.find(num_ order[i])->second<<endl;
		Rect choose_rect(number_rect.x, 0, number_rect.width, img.rows);//The coordinates of X and Y in the upper left corner of the rectangle and the width and height of the rectangle
		Mat number_img = img(choose_rect);
		resize(number_img,number_img,Size(30,100));//Normalized size
		ROI_image.push_back(number_img);//Save as picture to be tested
		//imshow("number" + to_string(i), number_img);
		char name[50];
		sprintf_s(name,"D:\\vs2012\\model\\%d.jpg",i);//Save template
		imwrite(name, number_img);	
	}
	cout<<"Image segmentation completed"<<endl;
	//Load template
	vector<Mat>temptImage;//Storage template
	for (int i=0;i<4;i++)
	{
		char name[50];
		sprintf_s(name,"D:\\vs2012\\model\\%d.jpg",i);
		Mat temp;
		temp=imread(name);
		//Cout < < number of channels to load template pictures: < < temp. Channels() < < endl;
		temptImage.push_back(temp);
	}
	vector<int>seq;//Storage sequence results
	for (int i=0;i<ROI_image.size();i++)
	{
		Mat subImage;
		int sum=0;
		int min=50000;
		int seq_min=0;//Record the smallest and corresponding numbers
		for (int j=0;j<4;j++)
		{
			absdiff(ROI_image[i],temptImage[j],subImage);//Subtract template picture pixels from picture pixels to be tested
			sum=sunImage(subImage);//Statistical pixel sum
			if (sum<min)
			{
				min=sum;
			    seq_min=j;
			}
			sum=0;
		}
		seq.push_back(seq_min);
	}
	cout<<"Output digital matching results:";//endl means line feed
	for (int i=0;i<seq.size();i++)//Output the result with the decimal point fixed in the third place
	{
		cout<<seq[i];
		if (i==1)
		{
			cout<<".";
		}
	}
	finish=clock();
	double all_time=double(finish-start)/CLOCKS_PER_SEC;
	/*cout<<"The total running time is: "< < all"_ time<<endl;*/
	waitKey(0);
	return 0;
}
//Calculate pixel sum
int sunImage(Mat &image)
{
	int sum=0;
	for (int i=0;i<image.cols;i++)
	{
		for (int j=0;j<image.rows;j++)
		{
			sum+=image.at<uchar>(j,i);
		}
	}
	return sum;
}

The overall idea is like this: the 10 numbers 0-9 have been segmented and saved, that is, the template. Then we segment the pictures to be tested, and then read the template pictures from the 0-9 template folder. Let the segmented pictures to be tested be subtracted from the 10 templates one by one, and then count their pixels and, If this is the lowest of the 10, then they are the same number, and then the output value can be. After segmentation, it is probably like this

The above is the first method, and then there is the second method, which is the threading method, which is identified according to the digital characteristics of transistors

This is the characteristic of transistor numbers. Each 0-9 number is different. We will introduce it in detail in the next article

Topics: Python OpenCV Deep Learning