原图
结果
代码
// Load source image
cv::Mat src = cv::imread("answer_card.jpg", cv::IMREAD_COLOR);
if (src.empty())
{
return;
}
cv::Mat gray;
cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);
cv::Mat binary;
double value = cv::threshold(gray, binary, 0, 255, cv::THRESH_BINARY_INV + cv::THRESH_OTSU);
std::vector<cv::Point2f> imgCorners{ cv::Point2f(0, 0), cv::Point2f(src.cols, 0),
cv::Point2f(src.cols, src.rows), cv::Point2f(0, src.rows) };
cv::Mat dilate;
cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(1, 7));
cv::dilate(binary, dilate, kernel);
std::vector<std::vector<cv::Point>> contours;
cv::findContours(dilate, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
std::vector<cv::Point2f> corners;
for (size_t i = 0; i < contours.size(); i++)
{
cv::RotatedRect minRect = cv::minAreaRect(contours[i]);
// rotated rectangle
cv::Point2f sz[4];
minRect.points(sz);
if (cv::Rect(minRect.boundingRect()).width > src.cols / 2) // should be improved
{
for (int j = 0; j < 4; ++j) //找到与图像四点最近的对应四点
{
cv::Point2f pt = imgCorners[j];
cv::Point2f nearest_pt = sz[0];
float dist = cv::norm(pt - nearest_pt); //求两点的距离
for (int k = 1; k < 4; ++k)
{
if (cv::norm(pt - sz[k]) < dist)
{
dist = cv::norm(pt - sz[k]); //更新两点距离
nearest_pt = sz[k];
}
}
corners.push_back(nearest_pt);
}
}
}
//提取涂抹的黑色小圆
cv::Mat erode0;
cv::erode(binary, erode0, cv::Mat(), cv::Point(-1, -1), 10); //should be improved
cv::Mat dilat;
cv::dilate(erode0, dilat, cv::Mat(), cv::Point(-1, -1), 5); //should be improved
cv::Mat results(src.size(), CV_8UC3);
cv::Mat transform = cv::getPerspectiveTransform(corners, imgCorners);
cv::warpPerspective(src, results, transform, src.size()); // Create a Mat To Show results
cv::Mat warp(src.size(), CV_8UC1); // should be improved
cv::warpPerspective(dilat, warp, transform, src.size());
//试卷答题卡选项数目
cv::Size size(20, 5); // this variable should be changed according input
cv::Mat resize;
cv::resize(warp, resize, size);
for (int i = 0; i < resize.cols; ++i)
{
std::string answer = "";
answer += resize.at<uchar>(1, i) == 0 ? "" : "A";
answer += resize.at<uchar>(2, i) == 0 ? "" : "B";
answer += resize.at<uchar>(3, i) == 0 ? "" : "C";
answer += resize.at<uchar>(4, i) == 0 ? "" : "D";
if (answer.length() > 1) answer = "X"; // Double mark
int y = 0;
if (answer == "A") y = results.rows / size.height;
if (answer == "B") y = results.rows / size.height * 2;
if (answer == "C") y = results.rows / size.height * 3;
if (answer == "D") y = results.rows / size.height * 4;
if (answer == "") answer = "[-]";
cv::putText(results, answer, cv::Point(50 * i + 15, 30 + y), cv::FONT_HERSHEY_PLAIN, 2, CV_RGB(0, 0, 255), 2);
}
imshow("results", results);
cv::waitKey();