机读卡的识别

#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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值