Opencv识别答题卡

转自:http://blog.csdn.net/cp562090732/article/details/47804003#comments

OpenCV处理答题卡的软件,用于统计答题卡中选择题的得分。

1. 主要步骤

  •     读取图片
  •     图片转化为灰度图
  •     图片设定阈值
  •     开运算(先腐蚀,后膨胀)
  •     指定答题区域
  •     找到涂选框
  •     根据涂选框的坐标确定所涂选的选项及题号

2. 具体实现

#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include "opencv2/imgproc.hpp"
#include <opencv2/highgui.hpp>
#include <iostream>

using namespace cv;
using namespace std;

#include <map>

class RectComp
{  
public:
	Rect rm;  
	RectComp(Rect rms)  
	{  
		rm = rms;  
	}  
	bool operator < (const RectComp& ti) const  
	{  
		return rm.x< ti.rm.x;  
	}  
};

int main()  
{  
	//装载图片  
	Mat srcImage1= imread("D:\\opencv_image\\images\\20150820103614491.png");   
	namedWindow("hello-1", 1);  
	imshow("hello-1", srcImage1 ); 
	Mat srcImage2,srcImage3,srcImage4,srcImage5;  

	//图片变成灰度图片  
	cvtColor(srcImage1,srcImage2,CV_BGR2GRAY);  
	//图片二值化  
	threshold(srcImage2,srcImage3,200,255,THRESH_BINARY_INV);  

	//确定腐蚀和膨胀核的大小  
	Mat element = getStructuringElement(MORPH_RECT, Size(4, 4));  
	//腐蚀操作  
	erode(srcImage3,srcImage4,element);  
	//膨胀操作  
	dilate(srcImage4,srcImage5,element);  

	namedWindow("hello-5", 1);  
	imshow("hello-5", srcImage5 );  

	//确定每张答题卡的ROI区域  
	Mat imag_ch1 = srcImage5(Rect(0,30,100,60));  
	namedWindow("img1", 1);  
	imshow("img1",imag_ch1);  

	//提取已经涂好了的选项  
	std::vector<std::vector<cv::Point> > chapter1;  
	findContours(imag_ch1,chapter1,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE);  
	Mat result(imag_ch1.size(), CV_8U , cv::Scalar(255)) ;  
	cv::drawContours(result,chapter1,-1,cv::Scalar(0),2);  
	namedWindow("resultImage", 1);  
	cv::imshow("resultImage" , result);  

	vector<RectComp>RectCompList;  
	for(int i = 0;i<chapter1.size();i++)  
	{  
		Rect rm= cv::boundingRect(cv::Mat(chapter1[i]));  
		RectComp *ti = new RectComp(rm);  
		RectCompList.push_back(*ti);  
		//         printf("Rect %d x = %d,y = %d \n",i,rm.x,rm.y);  
	}  
	sort(RectCompList.begin(),RectCompList.end());  
	map<int,string>listenAnswer;  
	//判断这部分的答题卡是否都已涂上  
	for(int t = 0;t<RectCompList.size();t++)  
	{  
		if(RectCompList.at(t).rm.y<=22)  
		{  
			listenAnswer[t] = "A";  
		}  
		else if((RectCompList.at(t).rm.y>22)&&(RectCompList.at(t).rm.y<=34))  
		{  
			listenAnswer[t] = "B";  
		}  
		else if(RectCompList.at(t).rm.y>34)  
		{  
			listenAnswer[t] = "C";  
		}  
		printf("sorted %d x = %d,y = %d \n",t,RectCompList.at(t).rm.x,RectCompList.at(t).rm.y);  
	}  
	for(map<int,string>::iterator it = listenAnswer.begin();it!=listenAnswer.end();++it)  
	{  
		cout<<"num:"<<it->first+1<<","<<"answer:"<<it->second<<endl;  
	}  

	waitKey(0);  
	return 0;  
}  


3. 结果



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值