背景:.对于填涂类型的准考证号或则答案,用传统的边框检测,使用合适的阈值,将对象检测出来,然后根据排列,可以得到学号或则填涂的选项。
不足:挺依赖印刷的质量和填涂的规范性,对于大批量的识别,不能保证识别的准确性。
#include <iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat img = imread("d:\\Images\\stucard\\2.jpg", cv::IMREAD_UNCHANGED);
if (img.empty())
{
printf("图像无法正常加载\n");
return 0;
}
Mat gray;
if (img.channels() > 1)
cv::cvtColor(img, gray, COLOR_RGB2GRAY);
else
gray = img.clone();
Mat result_Color_img;
cvtColor(gray, result_Color_img, COLOR_GRAY2BGR);
cv::Ptr<cv::CLAHE> clahe = cv::createCLAHE(2.0, cv::Size(8, 8));
cv::Mat tmpresult;
clahe->apply(gray, tmpresult);
cv::GaussianBlur(tmpresult, tmpresult, cv::Size(3, 3), 0);
cv::Mat binary;
cv::threshold(tmpresult, binary, 0, 255, cv::THRESH_BINARY_INV | cv::THRESH_OTSU);
std::vector<std::vector<cv::Point>> contours;
cv::findContours(binary, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
std::vector<cv::Rect> rectarray;
double epsilon = 0.02;
for (const auto& contour : contours) {
cv::Rect rect = cv::boundingRect(contour);
int rectsize = 0;
if (rect.width < 60 && rect.height < 36 && rect.width>12 && rect.height >12) {
double contourArea = cv::contourArea(contour);
double rectArea = rect.width * rect.height;
if (contourArea / rectArea > 0.4) {
std::vector<cv::Point> approx;
cv::approxPolyDP(contour, approx, epsilon * cv::arcLength(contour, true), true);
if (approx.size() >= 4) {
rectarray.push_back(rect);
cv::rectangle(result_Color_img, rect, Scalar(0, 0, 255), 2);
}
}
}
}
namedWindow("original", WINDOW_FREERATIO);
int window_width = 400;
resizeWindow("original", Size(window_width, window_width * img.rows / img.cols));
imshow("original", result_Color_img);
waitKey(0);
destroyAllWindows();
return 0;
}
结果:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。