#include <opencv2/opencv.hpp>
#include <iostream>
#include <string.h>
#include <vector>
using namespace std;
using namespace cv;
string pathname = "D:\\Microsoft VS Code\\OpenCV\\cpp\\omr3.jpg";
Mat img, imgGray, imgBlur, imgCanny, imgContours, imgWarp, imgWarpGrade, imgThre, imgWarpGray, imgWarpGradeGray, imgGradeThre;
vector<Point> docPoint_max, docPoint_grade;
vector<Mat> boxes;
vector<vector<Point>> getContours(Mat imgage) {
// 四个角点,闭合轮廓
// 怎样让涂卡区从众多矩形中脱颖而出,面积,周长
// 两个ROI,1.涂卡区 2.成绩
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(imgage, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_NONE);
vector<vector<Point>> biggest; // 涂卡区
// vector<vector<Point>> greade; // 成绩区
vector<vector<Point>> recCon(contours.size()); // 轮廓的角点坐标
int maxArea = 0;
for (int i = 0; i < contours.size(); ++i) {
// 遍历每一个轮廓
double area = contourArea(contours[i], false);
if (area > 300) {
double peri = arcLength(contours[i], true);
approxPolyDP(contours[i], recCon[i], 0.1 * peri, true);
if (recCon[i].size() == 4 && area > maxArea) {
// drawContours(img, recCon, i, Scalar(0, 255, 0));
// imshow("drawContours", img);
maxArea = area;
biggest.push_back(recCon[i]);
}
}
}
return biggest;
}
// 画点
void drawPoints(Mat image, vector<Point> cPoint, Scalar color) {
for (int i = 0; i < cPoint.size(); ++i) {
circle(image, cPoint[i], 5, color, FILLED);
putText(image, to_string(i), cPoint[i], FONT_HERSHEY_PLAIN, 5, color, 3);
}
return ;
}
// 给点重新排序
vector<Point> reorder(vector<Point> points) {
vector<Point> newPoints;
vector<int> sumPoints, subPoints;
for (int i = 0; i < points.size(); ++i) {
sumPoints.push_back(points[i].x + points[i].y);
subPoints.push_back(points[i].x - points[i].y);
}
newPoints.push_back(points[min_element(sumPoints.begin(), sumPoints.end()) - sumPoints.begin()]);
newPoints.push_back(points[max_element(subPoints.begin(), subPoints.end()) - subPoints.begin()]);
newPoints.push_back(points[min_element(subPoints.begin(), subPoints.end()) - subPoints.begin()]);
newPoints.push_back(points[max_element(sumPoints.begin(), sumPoints.end()) - sumPoints.begin()]);
return newPoints;
}
// 仿射变换
Mat getWarp(Mat image, vector<Point> points, float w, float h) {
Mat imgWarp;
Point2f src[4] = {points[0], points[1], points[2], points[3]};
Point2f dst[4] = {{0.0f, 0.0f}, {w, 0.0f}, {0.0f, h}, {w, h}};
Mat matrix = getPerspectiveTransform(src, dst);
warpPerspective(image, imgWarp, matrix, Point(w, h));
return imgWarp;
}
Mat getreWarp(Mat image, vector<Point> points, float w, float h, float sizew, float sizeh) {
Mat imgWarp;
Point2f src[4] = {points[0], points[1], points[2], points[3]};
Point2f dst[4] = {{0.0f, 0.0f}, {w, 0.0f}, {0.0f, h}, {w, h}};
Mat matrix = getPerspectiveTransform(dst, src);
warpPerspective(image, imgWarp, matrix, Point(sizew, sizeh));
return imgWarp;
}
// 图像分割
vector<Mat> splitBox(Mat img) {
vector<Mat> boxes;
Mat img_cut, rio_img;
int m = img.cols / 5; // 宽度
int n = img.rows / 5; // 高度
for (int i = 0; i < 5; ++i) {
for (int j = 0; j < 5; ++j) {
Rect rect(i * n, j * n, 60, 60);
img_cut = Mat(img, rect);
rio_img = img_cut.clone();
boxes.push_back(rio_img);
}
}
// for (int i = 0; i < boxes.size(); ++i) {
// string num = to_string(i);
// imshow(num, boxes[i]);
// }
return boxes;
}
// 答案展示
Mat showAnswer(Mat img, vector<int> index, vector<int> grading, vector<int> ans, int question, int choice) {
int secW = img.cols / choice;
int secH = img.rows / question;
Scalar color;
for (int i = 0; i < question; ++i) {
int sx = (index[i] * secW) + (secW / 2);
int sy = (i * secH) + (secH / 2);
if (grading[i] == 1) {
color = Scalar(0, 255, 0);
} else {
color = Scalar(0, 0, 255);
circle(img, Point((ans[i] * secW) + (secW / 2), sy), 10, Scalar(0, 255, 0), FILLED);
}
circle(img, Point(sx, sy), 20, color, FILLED);
}
return img;
}
#define CAM_BEGIN {
#define CAM_END }
int main() {
// 从摄像头读
// bool cam = true;
// VideoCapture cap(1);
// while(true) CAM_BEGIN
// if (cam) {
// cap.read(img);
// } else {
// img = imread(pathname);
// }
// 从图片中读
img = imread(pathname);
resize(img, img, Size(500, 500));
cvtColor(img, imgGray, COLOR_BGR2GRAY);
GaussianBlur(imgGray, imgBlur, Size(5, 5), 0, 0);
Canny(imgBlur, imgCanny, 50, 25, 3);
imshow("img", img);
// imshow("imgGray", imgGray);
// imshow("imgBlur", imgBlur);
// imshow("imgCanny", imgCanny);
// threshold(imgBlur, imgThre, 180, 255, THRESH_BINARY);
// imshow("imgThre", imgThre);
// Mat temp;
// threshold(imgBlur, temp, 180, 255, THRESH_BINARY_INV);
// imshow("temp", temp);
vector<vector<Point>> contours;
vector<vector<Point>> cPoint;
vector<Vec4i> hierarchy;
imgContours = img.clone();
// findContours(imgCanny, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_NONE);
// drawContours(imgContours, contours, -1, Scalar(0, 255, 0), 2);
// 如何找到涂卡区的矩形轮廓
cPoint = getContours(imgCanny);
/* 读图片模式下将下四行注释 */
// if (cPoint.size() < 2) {
// waitKey(1);
// continue;
// }
drawContours(imgContours, cPoint, -1, Scalar(0, 255, 0), 2);
// imshow("imgContours", imgContours);
/* 0.重新排序四个角点 */
// drawPoints(img, cPoint[0], Scalar(0, 0, 200));
// drawPoints(img, cPoint[1], Scalar(0, 0, 200));
// imshow("img", img);
docPoint_grade = reorder(cPoint[0]);
docPoint_max = reorder(cPoint[1]);
drawPoints(imgContours, docPoint_max, Scalar(0, 0, 200));
drawPoints(imgContours, docPoint_grade, Scalar(0, 0, 200));
// imshow("imgContours", imgContours);
/* 1.仿射变换 */
imgWarp = getWarp(img, docPoint_max, 300, 300);
// imshow("imgWarp", imgWarp);
imgWarpGrade = getWarp(img, docPoint_grade, 180, 100);
// imshow("imgWarpGrade", imgWarpGrade);
/* 2.二值化处理 */
cvtColor(imgWarp, imgWarpGray, COLOR_BGR2GRAY);
threshold(imgWarpGray, imgThre, 180, 255, THRESH_BINARY_INV);
// imshow("imgThre", imgThre);
cvtColor(imgWarpGrade, imgWarpGradeGray, COLOR_BGR2GRAY);
threshold(imgWarpGradeGray, imgGradeThre, 180, 255, THRESH_BINARY_INV);
// imshow("imgGradeThre", imgGradeThre);
/* 3.图形分割 */
boxes = splitBox(imgThre);
/* 4.计算答案下标,对比正确答案 */
int totalPixels;
int myPixelVal[5][5] = {0};
for (int i = 0; i < 25; ++i) {
totalPixels = countNonZero(boxes[i]);
myPixelVal[i % 5][i / 5] = totalPixels;
}
for (int i = 0; i < 5; ++i) {
for (int j = 0; j < 5; ++j) {
cout << "[" << i << "," << j << "] " << myPixelVal[i][j] << " ";
}
cout << endl;
}
vector<vector<int>> brr;
for (int i = 0; i < 5; ++i) {
vector<int> arr;
for (int j = 0; j < 5; ++j) {
arr.push_back(myPixelVal[i][j]);
}
brr.push_back(arr);
}
vector<int> index;
for (int i = 0; i < brr.size(); ++i) {
auto location = max_element(brr[i].begin(), brr[i].end());
index.push_back((int)(location - brr[i].begin()));
cout << *location << " " << index[i] << endl;
}
vector<int> ans = {0, 1, 2, 3, 4};
没有合适的资源?快使用搜索试试~ 我知道了~
温馨提示
【资源说明】 基于OpenCV+C++的答题卡识别系统源码+使用文档+全部资料(优秀项目).zip基于OpenCV+C++的答题卡识别系统源码+使用文档+全部资料(优秀项目).zip基于OpenCV+C++的答题卡识别系统源码+使用文档+全部资料(优秀项目).zip 【备注】 1、该项目是个人高分毕业设计项目源码,已获导师指导认可通过,答辩评审分达到95分 2、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 3、本项目适合计算机相关专业(如软件工程、计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载使用,也可作为毕业设计、课程设计、作业、项目初期立项演示等,当然也适合小白学习进阶。 4、如果基础还行,可以在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!
资源推荐
资源详情
资源评论
收起资源包目录
基于OpenCV+C++的答题卡识别系统源码+使用文档+全部资料(优秀项目).zip (17个子文件)
Answer_card_recognition_system-main
.vscode
c_cpp_properties.json 505B
settings.json 63B
tasks.json 967B
launch.json 1024B
cpp
omr2.jpg 1.59MB
omr1.jpg 1.41MB
答题卡.jpg 103KB
test.cpp 9KB
omr3.jpg 163KB
G.png 387KB
Debugger
test.exe 1.07MB
openh264-1.8.0-win64.dll 806KB
openh264-1.7.0-win64.dll 787KB
libopencv_core452.dll 7.19MB
opencv_videoio_ffmpeg452_64.dll 19.97MB
libopencv_world452.dll 51.48MB
171265889347208773632.zip 416B
共 17 条
- 1
资源评论
不走小道
- 粉丝: 3199
- 资源: 4969
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- 基于 SpringCloud 和 Vue3 的OA系统
- 软考高级项目管理师-项目采购管理思维导图
- WordsVector (1).ipynb
- yolov7 车牌检测 车牌识别 中文车牌识别 检测 支持双层车牌 支持12种中文车牌
- 20240429_112025.m4a
- "麦嘟学编程"似乎是一个与编程学习相关的品牌或社区名称,它可能是一个在线教育平台、博客、论坛或社交媒体群组等,旨在帮助人们学习编
- OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习软件库,由
- Redis入门基础篇+源码(springboot、maven)
- ChatGPT-4是由OpenAI开发的人工智能模型,是GPT(Generative Pre-trained Transform
- 91fdd461elb59a4ce8dfcfc46bc283a7.msi
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功