当前位置: 首页 > wzjs >正文

上海网站建设联系电全国十大教育机构

上海网站建设联系电,全国十大教育机构,网页设计与网站开发pdf,手机网站开发工具 2018使用 C 和 OpenCV 构建智能答题卡识别系统 📝 本文将引导你如何使用 C 和强大的计算机视觉库 OpenCV,从零开始创建一个可以自动批改选择题答题卡的程序。我们将涵盖从图像预处理、轮廓定位到最终答案判定的完整流程。 核心技术与原理 🧠 光…

使用 C++ 和 OpenCV 构建智能答题卡识别系统 📝

本文将引导你如何使用 C++ 和强大的计算机视觉库 OpenCV,从零开始创建一个可以自动批改选择题答题卡的程序。我们将涵盖从图像预处理、轮廓定位到最终答案判定的完整流程。


核心技术与原理 🧠

光学标记识别 (OMR) 的核心思想是利用计算机视觉技术,在一张扫描的图像中定位并识别出被标记(如填涂)的区域。整个流程可以分解为以下几个关键步骤:

  1. 图像预处理: 将输入的彩色或灰度图像转换为二值图像,使其更容易被程序分析。
  2. 轮廓检测: 找到图像中的关键轮廓,首先是整个答题卡的轮廓,然后是每个选项的轮廓(通常是圆形或矩形)。
  3. 透视变换: 如果答题卡图像是倾斜的,我们需要将其校正为一个标准的“鸟瞰图”,以确保后续处理的准确性。
  4. 选项定位与识别: 在校正后的图像上,定位每个选项(A, B, C, D)的位置。
  5. 答案判定: 通过计算每个选项区域内的非零像素(黑色像素)数量,来判断哪个选项被填涂。
  6. 自动评分: 将识别出的学生答案与标准答案进行比对,计算总分。

<center>一个简化的 OMR 处理流程图。</center>


步骤一:环境配置 🛠️

在开始之前,请确保你的开发环境中已经安装了 C++ 编译器 (如 G++) 和 OpenCV 库。

在 Ubuntu/Debian 上安装 OpenCV:

sudo apt-get update
sudo apt-get install build-essential cmake libopencv-dev

步骤二:图像预处理与轮廓定位

我们的首要任务是找到答题卡在图像中的准确位置。

1. 加载与预处理

我们从加载图像开始,然后进行高斯模糊以减少噪声,再使用 Canny 算法进行边缘检测,最后通过膨胀和腐蚀操作来连接断开的边缘。

关键代码片段 (main.cpp):

#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>using namespace cv;
using namespace std;// 用于对轮廓按面积大小进行排序的辅助函数
bool compareContourAreas(const vector<Point>& contour1, const vector<Point>& contour2) {return contourArea(contour1) > contourArea(contour2);
}int main() {string image_path = "answer_sheet.jpg"; // 你的答题卡图片路径Mat image = imread(image_path);if (image.empty()) {cout << "Could not read the image: " << image_path << endl;return 1;}Mat gray, blurred, edged;cvtColor(image, gray, COLOR_BGR2GRAY);GaussianBlur(gray, blurred, Size(5, 5), 0);Canny(blurred, edged, 75, 200);// 显示边缘检测结果 (可选)// imshow("Edged", edged);// waitKey(0);// ... 后续代码
}

2. 寻找答题卡轮廓

在边缘图像上,我们可以寻找轮廓。答题卡通常是图像中最大的矩形轮廓。

// ... 接上文
vector<vector<Point>> contours;
findContours(edged.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);// 按面积对轮廓进行排序
sort(contours.begin(), contours.end(), compareContourAreas);// 假设最大的轮廓就是我们的答题卡
vector<Point> paperContour;
for (const auto& c : contours) {double peri = arcLength(c, true);vector<Point> approx;approxPolyDP(c, approx, 0.02 * peri, true);// 如果轮廓有4个顶点,我们认为它就是答题卡if (approx.size() == 4) {paperContour = approx;break;}
}

步骤三:透视变换(图像校正)📐

找到四个顶点后,我们可以对图像进行透视变换,得到一个完美的矩形俯视图。

关键代码片段:

#include <algorithm> // for std::sort// 对四个顶点进行排序:左上, 右上, 右下, 左下
Point2f sortPoints(const vector<Point>& pts) {// ... 实现排序逻辑 ...// 通常基于 x+y 和 x-y 的值来排序// 返回一个包含四个有序点的 Point2f 向量
}// ... 接上文
if (paperContour.empty()) {cout << "Could not find paper contour." << endl;return 1;
}// 获取四个顶点并排序
Point2f src_pts[] = { /* 排序后的 paperContour 顶点 */ };
Point2f dst_pts[] = {{0.0f, 0.0f}, {500.0f, 0.0f}, {500.0f, 700.0f}, {0.0f, 700.0f}}; // 目标图像尺寸Mat transformMatrix = getPerspectiveTransform(src_pts, dst_pts);
Mat warped;
warpPerspective(image, warped, transformMatrix, Size(500, 700));// 显示校正后的图像 (可选)
// imshow("Warped", warped);
// waitKey(0);

步骤四:选项识别与评分 ✅

现在我们在校正后的、标准化的 warped 图像上工作。

1. 定位并分析选项气泡

首先,我们将校正后的图像再次进行二值化处理。

Mat warpedGray, thresh;
cvtColor(warped, warpedGray, COLOR_BGR2GRAY);
threshold(warpedGray, thresh, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);

接下来,我们再次寻找轮廓,但这次是在二值化的 thresh 图像上。这些轮廓将代表所有的选项气泡。

vector<vector<Point>> bubbleContours;
findContours(thresh.clone(), bubbleContours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);vector<vector<Point>> questionBubbles;
// 遍历所有轮廓,筛选出符合条件的选项气泡(比如基于宽高比和面积)
for (const auto& c : bubbleContours) {Rect r = boundingRect(c);float ar = r.width / (float)r.height;if (r.width >= 20 && r.height >= 20 && ar >= 0.9 && ar <= 1.1) {questionBubbles.push_back(c);}
}

2. 将气泡分组并判定答案

我们将所有识别出的气泡按其 y 坐标排序,然后按 x 坐标排序,这样就可以将它们与具体的问题和选项对应起来。假设每行有 5 个选项气泡(例如,一个题号加 A,B,C,D)。

// 按y坐标对气泡进行排序
sort(questionBubbles.begin(), questionBubbles.end(), [](const vector<Point>& a, const vector<Point>& b) {return boundingRect(a).y < boundingRect(b).y;
});map<int, int> correct_answers; // <题号, 正确答案索引(0-3)>
correct_answers[0] = 1; // 第1题答案是 B
correct_answers[1] = 3; // 第2题答案是 D
// ... 其他答案int total_correct = 0;
// 每5个气泡为一组进行处理
for (size_t i = 0; i < questionBubbles.size(); i += 5) {// 对当前行的5个气泡按x坐标排序vector<vector<Point>> row(questionBubbles.begin() + i, questionBubbles.begin() + i + 5);sort(row.begin(), row.end(), [](const vector<Point>& a, const vector<Point>& b) {return boundingRect(a).x < boundingRect(b).x;});int bubbled_index = -1;int max_filled = 0;// 遍历当前行的每个选项 (A,B,C,D),跳过第一个(题号)for (size_t j = 1; j < row.size(); ++j) {Mat mask = Mat::zeros(thresh.size(), CV_8UC1);drawContours(mask, row, j, Scalar(255), -1);Mat masked_bubble;bitwise_and(thresh, thresh, masked_bubble, mask);int filled_pixels = countNonZero(masked_bubble);if (filled_pixels > max_filled) {max_filled = filled_pixels;bubbled_index = j - 1; // 索引为 0-3}}// 判定对错int question_num = i / 5;if (correct_answers[question_num] == bubbled_index) {total_correct++;}
}cout << "Total Correct: " << total_correct << endl;

总结与提升 🚀

我们成功地使用 C++ 和 OpenCV 实现了一个基本的答题卡自动评分系统。这个项目完美地展示了计算机视觉在自动化任务中的强大能力。

可以进一步优化的方向:

  • 鲁棒性: 提高对不同光照条件、纸张质量和填涂工具(铅笔、钢笔)的适应性。
  • GUI 界面: 使用 Qt 或其他 GUI 框架为程序创建一个用户友好的界面,允许用户上传图片并查看结果。
  • 多选题和判断题: 扩展逻辑以支持多种题型。
  • 性能优化: 对计算密集型步骤进行优化,以更快地处理图像。

希望这个教程能帮助你开启计算机视觉的学习之旅!

http://www.dtcms.com/wzjs/197856.html

相关文章:

  • 离退休党建设工作网站网络营销专业大学排名
  • 厦门网站建设的公司哪家好深圳网站建设
  • 怎么做有数据库的网站关键词搜索排名优化
  • 用腾讯云做淘宝客购物网站视频广州网站运营
  • 定制企业网站开发公司友情链接出售平台
  • wordpress 优惠主机公司网站优化
  • 古云网站建设考研培训机构排名前十
  • 论文查重网站建设seo外链是什么意思
  • 做家乡网站源代码seo专家招聘
  • 做百度移动端网站软件免费网站做seo
  • 修改网站搜索缩略图今日头条搜索引擎
  • 建筑工程发布网站武汉seo首页优化技巧
  • 陕西哪些公司做企业网站如何优化网络环境
  • zencart 网站安装免费学生网页制作成品代码
  • 广州大石附近做网站的公司深圳seo排名优化
  • 用什么工具建设网站关键词排名软件官网
  • 有侧边栏的网站最近三天发生的重要新闻
  • 什么企业做网站sem管理工具
  • 做微博类的网站难吗百度seo关键词优化推荐
  • wordpress页面显示文章列表搜索引擎优化公司排行
  • 个人备案 做政府网站手机app推广平台
  • 网站规划设计流程上海站优云网络科技有限公司
  • 昆山 网站运营互联网推广有哪些方式
  • 广州建网站要多少钱网络营销模式
  • 触屏版手机网站开发百度极速版app下载安装挣钱
  • wordpress 极客主题小时seo百度关键词点击器
  • 多用户建站系统源码seo优化教程视频
  • 做一个动态网站要多少钱互联网推广
  • wordpress文章地图定位百度seo规则最新
  • wordpress高亮代码添加行号关键词优化步骤简短