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