Opencv识别答题卡

帮朋友做了一个用OpenCV处理答题卡的软件,用于统计答题卡中选择题的得分,当作作业,简要记录一下用到的知识。

1. 主要步骤

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

2. 具体实现

class RectComp<span style="white-space:pre">		</span>//Rect排序
{
    Rect rm;
    RectComp(Rect rms)
    {
        rm = rms;
    }
    bool operator < (const RectComp& ti) const
    {
        return rm.x < ti.rm.x;
    }
};

int main()
{
    //装载图片
     Mat srcImage1= imread("13.jpg");
     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(60,135,400,60));
     Mat imag_ch2 = srcImage5(Rect(60,225,400,105));
     Mat imag_ch3 = srcImage5(Rect(60,360,400,70));

     namedWindow("img1", 1);
     imshow("img1",imag_ch1);

     namedWindow("img2", 1);
     imshow("img2",imag_ch2);

     namedWindow("img3", 1);
     imshow("img3",imag_ch3);

     //提取已经涂好了的选项
     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<20)
         {
             listenAnswer[t] = "A";
         }
         else if((RectCompList.at(t).rm.y>20)&&(RectCompList.at(t).rm.y<35))
         {
             listenAnswer[t] = "B";
         }
         else if(RectCompList.at(t).rm.y>35)
         {
             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. 结果






  • 9
    点赞
  • 63
    收藏
    觉得还不错? 一键收藏
  • 17
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值