图像练习-答题卡opencv(02)

原图
结果
代码
cpp 复制代码
	// 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();
相关推荐
用户2991422196803 分钟前
GitHub 热榜项目:周榜(2026-11-08)
人工智能·开源·github
天天被压力8 分钟前
【A股分钟级高频数据完全手册 #07】北交所历史分钟K线接口:京市Pro版分时批量
java·人工智能·python
用户29914221968012 分钟前
AI 日报(2026年11月8日)
人工智能
天天被压力14 分钟前
【A股分钟级高频数据完全手册 #08】股票日、分时数据接口对比:普通分时与Pro版差异实测
java·人工智能·python
miofly15 分钟前
NVIDIA 开源 Cosmos 3 四款模型,用于交互式世界模拟与自动驾驶场景生成
人工智能
用户29914221968018 分钟前
GitHub 热榜项目:日榜(2026-11-08)
人工智能·开源·github
Dawson Zhu1 小时前
【LLM推理与Serving⑤】Prefix Cache前缀缓存:让重复prompt不再重复计算
人工智能·语言模型·架构·aigc·agi
Rocky Ding*1 小时前
深入浅出IDM-VTON论文精读:虚拟试衣怎样同时保住服装语义与局部细节
论文阅读·人工智能·深度学习·机器学习·aigc·ai-native·idm-vton
严肃小白兔1 小时前
MATLAB 数值计算中的精度与误差问题:浮点运算、误差传播与数值稳定性
人工智能·算法·matlab
AI导出鸭PC端1 小时前
Perplexity批量导出没有PDF模式?AI导出鸭插件补上最后一块拼图
人工智能·pdf·c#·ai导出鸭