機讀卡的識別

#include <opencv2\opencv.hpp>
#include<cmath>
#include<iostream>
using namespace std;
using namespace cv;

int mark[4][2][2];
Mat image;  //原圖
Mat image1;  //灰度圖
Mat image2;    //二值圖
Mat imagebox2;//最大域二值圖
Rect maxRect;    //最大域大小
Rect maxAbcRect;//填圖區
Mat imagebox;//最大域原圖
Mat imageabc2;//選擇題二值圖
Mat imageabc;//選擇題原圖
Mat imageblank2;//填空題二值圖
Mat imageblank;//填空題原圖
char answer[1000];
void abc()
{
	Mat imageboxtest = imagebox.clone();
	vector<Vec4i> lines;
	HoughLinesP(imagebox2, lines, 1, CV_PI / 2, 100, 300, 12);
	for (size_t i = 0; i < lines.size(); i++)
	{
		Vec4i l = lines[i];
		line(imageboxtest, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255), 1, 8);
		line(imageboxtest, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255), 1, 8);
	}
	cvtColor(imageboxtest, imageboxtest, CV_RGB2GRAY);
	adaptiveThreshold(imageboxtest, imageboxtest, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY_INV, 21, 10);   //自適應二值化

	maxAbcRect.x = lines[0][0]; maxAbcRect.y = lines[0][1] + 8;  //選擇題
	maxAbcRect.width = lines[0][2] - lines[0][0];
	maxAbcRect.height = lines[1][1] - lines[0][1] - 8;
	imageabc2 = imageboxtest(maxAbcRect);
	imageabc = imagebox(maxAbcRect);

	maxAbcRect.x = lines[1][0]; maxAbcRect.y = lines[1][1];  //填空題
	maxAbcRect.width = lines[1][2] - lines[1][0];
	maxAbcRect.height = imageboxtest.rows - lines[1][1];
	imageblank2 = imageboxtest(maxAbcRect);
	imageblank = imagebox(maxAbcRect);
	imwrite("2.jpg", imageblank);
}
void showabc()
{
	Mat abctest = imageabc2.clone();
	vector<vector<Point> > contours;
	vector<Vec4i> hierarchy;
	findContours(abctest, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
	Mat image(abctest.rows, abctest.cols, CV_8UC1, Scalar(0));
	double maxArea = 0;
	vector<Point> maxContour;
	for (size_t i = 0; i < contours.size(); i++)
	{
		double area = contourArea(contours[i]);
		if (area > 20)
		{
			drawContours(image, contours, i, Scalar(255), CV_FILLED);//畫出圖像輪廓
			int locaX = (contours[i][0].x + 3) % (abctest.cols / 4);
			int X = (contours[i][0].x) / (abctest.cols / 4);
			int Y = (contours[i][0].y) / (abctest.rows / 10);
			int choose = locaX / (abctest.cols / 20);
			answer[(Y / 5) * 20 + Y % 5 + 1 + 5 * X] = 'a' + choose - 1;
			char c[2];
			c[0] = 'a' + choose - 1;
			c[1] = 0;
			contours[i][0].y += 5;
			contours[i][0].x -= 5;
			putText(imageabc, c, contours[i][0], FONT_HERSHEY_PLAIN, 2, Scalar(0, 0, 255), 1, 8);
		}
	}

}
int returnmath(Mat pic)
{
	int one = 0, two = 0, three = 0;
	for (size_t i = pic.rows / 4; i > 0; i--)
	{
		uchar o = pic.at<uchar>(i, pic.cols / 2);
		if (o< 100)
		{
			++one; break;
		}
	}
	for (size_t i = pic.rows / 4; i < pic.rows * 3 / 4; i++)
	{
		if (pic.at<uchar>(i, pic.cols / 2)< 100)
		{
			++one; break;
		}
	}
	for (size_t i = pic.rows * 3 / 4; i < pic.rows; i++)
	{

		uchar p = pic.at<uchar>(i, pic.cols / 2);
		if (p< 100)
		{
			++one; break;
		}
	}
	for (size_t i = pic.cols / 2; i >0; i--)
	{
		if (pic.at<uchar>(pic.rows / 4, i)< 100)
		{
			two = 1; break;
		}
	}
	for (size_t i = pic.cols / 2; i >0; i--)
	{
		if (pic.at<uchar>(pic.rows * 3 / 4, i)< 100)
		{
			three = 1; break;
		}
	}
	int math = mark[one][two][three];
	if (math > 9)
	{
		math = 6;
		for (size_t i = pic.cols / 2; i <pic.cols; i++)
		{
			if (pic.at<uchar>(pic.rows / 4, i)< 100)
			{
				math = 8; break;
			}
		}
	}
	return math;
}
void showmath()
{
	Mat  mathtest = imageblank2.clone();
	vector<vector<Point> > contours;
	vector<Vec4i> hierarchy;

	findContours(mathtest, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
	Mat image(mathtest.rows, mathtest.cols, CV_8UC1, Scalar(0));
	double maxArea = 0;
	vector<Point> maxContour;
	vector<char>m;
	for (size_t i = 0; i < contours.size(); i++)
	{
		double area = contourArea(contours[i]);
		if (area > 50)
		{
			drawContours(image, contours, i, Scalar(255), CV_FILLED);
			int minx = 9999999, miny = 99999, maxx = 0, maxy = 0;
			for (size_t j = 0; j < contours[i].capacity(); j++)
			{
				if (contours[i][j].x > maxx)maxx = contours[i][j].x;
				if (contours[i][j].x < minx)minx = contours[i][j].x;
				if (contours[i][j].y > maxy)maxy = contours[i][j].y;
				if (contours[i][j].y < maxy)miny = contours[i][j].y;
			}
			Rect p;
			p.x = minx; p.y = miny; p.width = maxx - minx; p.height = maxy - miny;
			Mat pic = mathtest(p);

			bitwise_not(pic, pic);
			vector<vector<Point> > contour_math;
			findContours(pic, contour_math, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
			for (size_t k = 0; k < contour_math.size(); k++)
			{
				double area_math = contourArea(contour_math[k]);

				if (area_math >(pic.cols*pic.rows) / 3 && contour_math[k][0].x > pic.cols / 2)
				{
					int minx = 9999999, miny = 99999, maxx = 0, maxy = 0;
					for (size_t l = 0; l < contour_math[k].capacity(); l++)
					{
						if (contour_math[k][l].x > maxx)maxx = contour_math[k][l].x;
						if (contour_math[k][l].x < minx)minx = contour_math[k][l].x;
						if (contour_math[k][l].y > maxy)maxy = contour_math[k][l].y;
						if (contour_math[k][l].y < maxy)miny = contour_math[k][l].y;
					}
					Rect q;
					q.x = minx; q.y = miny; q.width = maxx - minx; q.height = maxy - miny;
					Mat pic_math = pic(q);
					int math = returnmath(pic_math);
					char c[2];
					c[0] = '0' + math;
					c[1] = 0;
					contours[i][k].y += 20;
					putText(imageblank, c, contours[i][k], FONT_HERSHEY_PLAIN, 2, Scalar(0, 0, 255), 1, 8, 0);
					contours[i][k].y -= 20;
					int X = contours[i][k].x / (imageblank.cols / 5);
					int Y = contours[i][k].y / (imageblank.rows / 3);
					answer[40 + 5 * Y + X + 1] = math + '0';
				}

			}
		}
	}
}
int main()
{
	memset(mark, -1, sizeof(mark));
	mark[0][0][0] = 1; mark[3][0][1] = 2; mark[3][0][0] = 3; mark[1][1][0] = 4; mark[3][1][0] = 5;
	mark[3][1][1] = 6; mark[1][0][0] = 7; mark[3][1][1] = 8; mark[2][1][0] = 9; mark[2][1][1] = 0;
	image = imread("D://1.jpg");
	imshow("原圖", image);
	cvtColor(image, image1, CV_RGB2GRAY);
	adaptiveThreshold(image1, image2, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY_INV, 21, 10);   //自適應二值化

	Mat imagecanny;
	image2.copyTo(imagecanny);//將image2粘貼到image canny;
	vector<vector<Point> > contours;
	vector<Vec4i> hierarchy;
	findContours(imagecanny, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));//得到答題卡的輪廓
	double maxArea = 0;
	vector<Point> maxContour;
	for (size_t i = 0; i < contours.size(); i++)
	{
		double area = contourArea(contours[i]);
		if (area > maxArea)
		{
			maxArea = area;
			maxContour = contours[i];
		}
	}//找到最大的連通域
	maxRect = boundingRect(maxContour);//計算外圍的矩形邊框
	imagebox = image(maxRect);//得到最大域的原圖
	imagebox2 = imagecanny(maxRect);//得到最大域的二值圖


	Mat imageboxtest = imagebox.clone();//創建一個和imagebox相同的圖像
	vector<Vec4i> lines;
	HoughLinesP(imagebox2, lines, 1, CV_PI / 180, 190, 100, 13);
	for (size_t i = 0; i < lines.size(); i++)
	{
		Vec4i l = lines[i];
		line(imageboxtest, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255), 1, 8);
		//line(imageboxtest, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255), 1, 8);
	}//使用霍夫變換進行劃線
	cvtColor(imageboxtest, imageboxtest, CV_RGB2GRAY);
	adaptiveThreshold(imageboxtest, imageboxtest, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY_INV, 21, 10);   //自適應二值化
	vector<Point>corners;
	vector<Point2f>cornerPos(4);
	vector<Point2f>cornerTrans(4);//四個角點
	int j = 0;
	Point center;
	center.x = cvRound(maxRect.width / 2);
	center.y = cvRound(maxRect.height / 2);//對邊界取整
	goodFeaturesToTrack(imageboxtest, corners, 2000, 0.01, 10, Mat(), 3, true, 0.04);//角點搜尋
	int maxline;
	maxline = sqrt(center.x*center.x + center.y*center.y) + 1;
	for (unsigned int i = 0; i < corners.size(); i++)
	{
		int t = abs(center.x - corners[i].x)*abs(center.x - corners[i].x) + abs(center.y - corners[i].y)*abs(center.y - corners[i].y);
		if (t > 48400)
		{
			circle(imagebox, corners[i], 5, Scalar(0, 0, 255), -1, 8, 0);
			cornerPos[j++] = corners[i];
		}
	}
	cornerTrans[0].x = imagebox.cols; cornerTrans[0].y = 0;
	cornerTrans[1].x = 0; cornerTrans[1].y = imagebox.rows;
	cornerTrans[2].x = imagebox.cols; cornerTrans[2].y = imagebox.rows;
	cornerTrans[3].x = 0; cornerTrans[3].y = 0;//根據圖片的座標確定角點
	Mat transform = getPerspectiveTransform(cornerPos, cornerTrans); //獲得透視變換矩陣
	warpPerspective(imagebox, imagebox, transform, imageboxtest.size(), INTER_LINEAR);//進行透視變換
	cvtColor(imagebox, imagebox2, CV_RGB2GRAY);
	adaptiveThreshold(imagebox2, imagebox2, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY_INV, 21, 10);   //自適應二值化



	abc();//摳出塗改區域
	showabc();   //找塗抹區
	showmath();
	imshow("識別後的圖片", image);
	cout << "題號    答案" << endl << endl << "選擇題:" << endl;
	for (int i = 1; i < 53; i++)
	{
		cout << i << "   :   " << answer[i] << endl;
	}
	waitKey(0);
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章