模拟考试答题卡的识别:如下图所示的一张答题卡,需要自动识别并标记出考生选择的选项,以及标记出正确答案。考生选择的选项用蓝色标记,标准答案用绿色标记。
//用相机拍一张答题卡
VideoCapture cap(0);
if (!cap.isOpened())
{
cout << "open failed !";
}
Mat frame, gray;
cap.read(frame);
cvtColor(frame, gray, COLOR_BGR2GRAY);
imwrite("C:\\Users\\86176\\Downloads\\visionimage\\testdetect.jpg", gray);
imshow("frame", frame);
waitKey(0);
颜色空间转换--------直方图均衡进行图像增强------高斯模糊去噪------canny边缘检测
Mat img = imread("C:\\Users\\86176\\Downloads\\visionimage\\testdetect.jpg");
Mat binary, gry, equalhist;
cvtColor(img, gry, COLOR_BGR2GRAY);
equalizeHist(gry, equalhist);
//imshow("eq", equalhist);
GaussianBlur(equalhist, equalhist, Size(3, 3),10,20);
Canny(equalhist, binary, 50, 300);
imshow("can", binary);
vector> bigcontour;
vectorareas;
double max = 0;
int index = -1;
findContours(binary, bigcontour, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
cout << bigcontour.size() << endl;
for (int i = 0; i < bigcontour.size(); ++i)
{
double area = contourArea(bigcontour[i]);
if (area > max)
{
max = area;
index = i;
}
areas.push_back(area);
//drawContours(img, bigcontour, i, Scalar( 0,0,200), 2);
}
cout << max << endl;
cout << index << endl;
Mat result;
Rect rec=boundingRect(bigcontour[index]);
vectorapp;
approxPolyDP(bigcontour[index], app, 10, true);
//cout << app << endl;
int curwidth = sqrt(
pow((app[0].x - app[3].x), 2) + pow((app[0].y - app[3].y), 2)
);
int curheight = sqrt(
pow((app[0].x - app[1].x), 2) + pow((app[0].y - app[1].y), 2)
);
vectorcurrs;
currs.emplace_back(Point(55, 30));
currs.emplace_back(Point(55, 30+curheight));
currs.emplace_back(Point(55+curwidth, 30+curheight));
currs.emplace_back(Point(55 + curwidth, 30));
Mat pers = getPerspectiveTransform(app, currs);
Mat perspect;
warpPerspective(img, perspect, pers, img.size());
Mat out;
Rect roi = Rect(55, 30, curwidth, curheight);
perspect(roi).copyTo(out);
Mat otsu, outgray, outdial;
cvtColor(out, outgray,COLOR_BGR2GRAY);
threshold(outgray, otsu, 100, 220, THRESH_OTSU|THRESH_BINARY_INV);
imshow("otsu", otsu);
//对图像进行膨胀
Mat mod = getStructuringElement(MorphShapes::MORPH_RECT, Size(5, 5));
morphologyEx(otsu, outdial, MORPH_DILATE, mod);
膨胀后的图形区域:
2.5再进行轮廓筛选,筛选出答题区域:
//再进行轮廓检测
vector>contoursagin, selectcontours;
findContours(outdial, contoursagin, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
for (auto m : contoursagin)
{
Rect bound = boundingRect(m);
if ((bound.height < 45 && bound.height>20) && (bound.width < 45 && bound.width>20))
{
selectcontours.push_back(m);
}
}
vectorcirclecenters;
vectorline1center;
vectorline2center;
vectorline3center;
vectorline4center;
vectorline5center;
vector>line1contour;
vector>line2contour;
vector>line3contour;
vector>line4contour;
vector>line5contour;
vectorcirciers;
for (int n=0;n
//对每一行排序
sort(line1center.begin(), line1center.end(), [](const Point2f& center1, const Point2f& center2)
{
return (center1.x < center2.x);
});
sort(line2center.begin(), line2center.end(), [](const Point2f& center1, const Point2f& center2)
{
return (center1.x < center2.x);
});
sort(line3center.begin(), line3center.end(), [](const Point2f& center1, const Point2f& center2)
{
return (center1.x < center2.x);
});
sort(line4center.begin(), line4center.end(), [](const Point2f& center1, const Point2f& center2)
{
return (center1.x < center2.x);
});
sort(line5center.begin(), line5center.end(), [](const Point2f& center1, const Point2f& center2)
{
return (center1.x < center2.x);
});
vectorsortedcenter;
sortedcenter.insert(sortedcenter.end(), line1center.begin(), line1center.end());
sortedcenter.insert(sortedcenter.end(), line2center.begin(), line2center.end());
sortedcenter.insert(sortedcenter.end(), line3center.begin(), line3center.end());
sortedcenter.insert(sortedcenter.end(), line4center.begin(), line4center.end());
sortedcenter.insert(sortedcenter.end(), line5center.begin(), line5center.end());
float meanrr=0;
float tempr=0;
for (int k=0;k
//答题卡答案A,DE,BE,C,D
int answer[5][5] = {
1,0,0,0,0,
0,0,0,1,1,
0,1,0,0,1,
0,0,1,0,0,
0,0,0,1,0
};
//用绿色标记处标准答案
Mat resultout, selectout,studentsel;
perspect(roi).copyTo(resultout);
perspect(roi).copyTo(selectout);
perspect(roi).copyTo( studentsel);
for (int ii = 0; ii < 5; ++ii)
{
for (int jj = 0; jj < 5; ++jj)
{
if (answer[ii][jj] == 1)
{
Point2f temp = sortedcenter[ii * 5 + jj];
circle(resultout, temp, meanrr, Scalar(0, 200, 0), 2);
}
}
}
//用蓝色标记考生答案
Mat erodM = getStructuringElement(0, Size(17,17));
erode(outdial, selectout, erodM);
vector>contours;
vectortempcenters;
findContours(selectout, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
for (int t = 0; t < contours.size(); ++t)
{
Point2f tempcenter;
float tempr;
minEnclosingCircle(contours[t], tempcenter, tempr);
circle(studentsel, tempcenter, meanrr, Scalar(200, 0, 0),2);
}
//cout << contours.size() << endl;
//cout << selectcontours.size();
imshow("outdial", outdial);
imshow("out", out);
imshow("res", resultout);
imshow("studentsel" , studentsel);
//imshow("img", img);
//imshow("gry", gry);
waitKey(0);
}
void VisionTest:: testdetect()
{
//用相机拍一张答题卡
/*
VideoCapture cap(0);
if (!cap.isOpened())
{
cout << "open failed !";
}
Mat frame, gray;
cap.read(frame);
cvtColor(frame, gray, COLOR_BGR2GRAY);
imwrite("C:\\Users\\86176\\Downloads\\visionimage\\testdetect.jpg", gray);
imshow("frame", frame);
waitKey(0);*/
Mat img = imread("C:\\Users\\86176\\Downloads\\visionimage\\testdetect.jpg");
Mat binary, gry, equalhist;
cvtColor(img, gry, COLOR_BGR2GRAY);
equalizeHist(gry, equalhist);
//imshow("eq", equalhist);
GaussianBlur(equalhist, equalhist, Size(3, 3),10,20);
Canny(equalhist, binary, 50, 300);
imshow("can", binary);
vector> bigcontour;
vectorareas;
double max = 0;
int index = -1;
findContours(binary, bigcontour, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
cout << bigcontour.size() << endl;
for (int i = 0; i < bigcontour.size(); ++i)
{
double area = contourArea(bigcontour[i]);
if (area > max)
{
max = area;
index = i;
}
areas.push_back(area);
//drawContours(img, bigcontour, i, Scalar( 0,0,200), 2);
}
cout << max << endl;
cout << index << endl;
Mat result;
Rect rec=boundingRect(bigcontour[index]);
vectorapp;
approxPolyDP(bigcontour[index], app, 10, true);
//cout << app << endl;
int curwidth = sqrt(
pow((app[0].x - app[3].x), 2) + pow((app[0].y - app[3].y), 2)
);
int curheight = sqrt(
pow((app[0].x - app[1].x), 2) + pow((app[0].y - app[1].y), 2)
);
vectorcurrs;
currs.emplace_back(Point(55, 30));
currs.emplace_back(Point(55, 30+curheight));
currs.emplace_back(Point(55+curwidth, 30+curheight));
currs.emplace_back(Point(55 + curwidth, 30));
Mat pers = getPerspectiveTransform(app, currs);
Mat perspect;
warpPerspective(img, perspect, pers, img.size());
Mat out;
Rect roi = Rect(55, 30, curwidth, curheight);
perspect(roi).copyTo(out);
imshow("roi", perspect(roi));
Mat otsu, outgray, outdial;
cvtColor(out, outgray,COLOR_BGR2GRAY);
threshold(outgray, otsu, 100, 220, THRESH_OTSU|THRESH_BINARY_INV);
imshow("otsu", otsu);
//对图像进行膨胀
Mat mod = getStructuringElement(MorphShapes::MORPH_RECT, Size(5, 5));
morphologyEx(otsu, outdial, MORPH_DILATE, mod);
//再进行轮廓检测
vector>contoursagin, selectcontours;
findContours(outdial, contoursagin, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
for (auto m : contoursagin)
{
Rect bound = boundingRect(m);
if ((bound.height < 45 && bound.height>20) && (bound.width < 45 && bound.width>20))
{
selectcontours.push_back(m);
}
}
vectorcirclecenters;
vectorline1center;
vectorline2center;
vectorline3center;
vectorline4center;
vectorline5center;
vector>line1contour;
vector>line2contour;
vector>line3contour;
vector>line4contour;
vector>line5contour;
vectorcirciers;
for (int n=0;nsortedcenter;
sortedcenter.insert(sortedcenter.end(), line1center.begin(), line1center.end());
sortedcenter.insert(sortedcenter.end(), line2center.begin(), line2center.end());
sortedcenter.insert(sortedcenter.end(), line3center.begin(), line3center.end());
sortedcenter.insert(sortedcenter.end(), line4center.begin(), line4center.end());
sortedcenter.insert(sortedcenter.end(), line5center.begin(), line5center.end());
float meanrr=0;
float tempr=0;
for (int k=0;k>contours;
vectortempcenters;
findContours(selectout, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
for (int t = 0; t < contours.size(); ++t)
{
Point2f tempcenter;
float tempr;
minEnclosingCircle(contours[t], tempcenter, tempr);
circle(studentsel, tempcenter, meanrr, Scalar(200, 0, 0),2);
}
cout << contours.size() << endl;
imshow("outdial", outdial);
imshow("out", out);
imshow("res", resultout);
imshow("studentsel" , studentsel);
waitKey(0);
}