脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Python - opencv实现答题卡识别

opencv实现答题卡识别

2022-08-31 10:36qq_36008031 Python

这篇文章主要为大家详细介绍了opencv实现答题卡识别,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了opencv实现答题卡识别的具体代码,供大家参考,具体内容如下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
"""
识别答题卡
"""
 
import cv2
import numpy as np
 
def showImg(img_name, img):
cv2.imshow(img_name, img)
cv2.waitKey()
cv2.destroyAllWindows()
 
def get_max_rect(sorted_cnts):
for cnt in sorted_cnts:
# 轮廓近似
possible_cnts = []
epsilon = 0.1 * cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, epsilon, True)
if len(approx) == 4:
possible_cnts.append(cnt)
possible_cnts = sorted(possible_cnts, key=lambda x: cv2.arcLength(x, True))
return possible_cnts
 
def get_max_bounding_rect(possible_cnts):
# for cnt in possible_cnts:
# x, y, w, h = cv2.boundingRect(cnt)
 
sorted_cnts = sorted(possible_cnts, key=lambda cnt: cv2.boundingRect(cnt)[2]*cv2.boundingRect(cnt)[3], reverse=True)
print(sorted_cnts[0])
 
def show_countour(img, cnt):
img_copy = img.copy()
cv2.drawContours(img_copy, cnt, -1, (0,255, 0), 3)
showImg("img_copy", img_copy)
 
 
# 读取答题卡图片,并显示
answer_sheet_img = cv2.imread("t1.jpg")
print(answer_sheet_img.shape)
showImg("answer_sheet_img", answer_sheet_img)
 
# 高斯滤波,去除噪音
blur = cv2.GaussianBlur(answer_sheet_img,(5,5),0)
showImg("blur", blur)
 
# 图像转灰度值
sheet_gray = cv2.cvtColor(blur, cv2.COLOR_BGR2GRAY)
showImg("sheet_gray", sheet_gray)
 
# 二值化
retval, sheet_threshold = cv2.threshold(sheet_gray,177, 255, cv2.THRESH_BINARY)
# print(type(sheet_threshold), sheet_threshold)
showImg("sheet_threshold", sheet_threshold)
 
# 边界检测
edges = cv2.Canny(sheet_threshold, 100, 200)
showImg("edges", edges)
# print(type(edges))
 
# 寻找轮廓
copy_edges = edges.copy()
img_copy = answer_sheet_img.copy()
img, cnts, hierarchy = cv2.findContours(copy_edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img_copy, cnts, -1, (0,0,255), 1)
showImg("img_copy", img_copy)
 
# 对所有轮廓加一个外接矩形,找最大的外接矩形
max_area_index = None
area = 0
for index, cnt in enumerate(cnts):
x, y, w, h = cv2.boundingRect(cnt)
if w*h > area:
max_area_index = index
show_countour(answer_sheet_img, cnts[max_area_index])
 
# 仿射,拿到答题卡主要部位
x, y, w, h = cv2.boundingRect(cnts[max_area_index]) # 最大的边界
cv2.rectangle(answer_sheet_img, (x, y),(x+w, y+h), (0,0,255), 2)
showImg("answer_sheet_img", answer_sheet_img)
pts1 = np.float32([[x,y], [x+w, y], [x+w, y+h]])
pts2 = np.float32([[0,0], [w, 0], [w, h]])
 
M = cv2.getAffineTransform(pts1, pts2)
sheet_threshold_copy = sheet_threshold.copy()
dst = cv2.warpAffine(sheet_threshold_copy, M, (w, h))
showImg("dst", dst)
print(answer_sheet_img.shape)
part_sheet_img = answer_sheet_img[y:y+h, x:x+w]
showImg("part_sheet_img", part_sheet_img)
 
# 对答案区域灰度,二值,找轮廓
part_answer_gray = cv2.cvtColor(part_sheet_img, cv2.COLOR_BGR2GRAY) # 灰度
ret, threshold_answer = cv2.threshold(part_answer_gray, 175, 255, cv2.THRESH_BINARY)
showImg("threshold_answer", threshold_answer)
 
img, answer_cnts, x = cv2.findContours(threshold_answer, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
part_sheet_img_copy = part_sheet_img.copy()
cv2.drawContours(part_sheet_img_copy, answer_cnts, -1, (0, 0, 255), 1)
showImg("dst_copy", part_sheet_img_copy)
 
# 对所有轮廓找外接矩形,想过滤掉不合适的矩形
print("画矩形")
answer_filter_cnts = []
answer_circles = []
img_ = part_sheet_img.copy()
for cnt in answer_cnts:
x, y, w, h = cv2.boundingRect(cnt)
if 30<w<40 and 30<h<40:
print(x, y, w, h)
circle_x = int(x + w/2)
circle_y = int(y+h/2)
r = int((w+h)/4)
answer_circles.append((circle_x, circle_y, r))
answer_filter_cnts.append(cnt)
 
answer_filter_cnts = np.array(answer_filter_cnts)
cv2.drawContours(img_, answer_filter_cnts, -1, (0, 0, 255), 1)
# cv2.rectangle(img, (x, y), (x+w, y+h), (0,255,0), 2)
showImg("img_", img_)
print("geshu", len(answer_circles))
 
 
# 从answer_circles中取25个
mask_dict = {1:[],2:[], 3:[], 4:[],5:[]} # 一共不一定是25个圆,将圆按照题目行分类,
sorted_y_answer_circles = sorted(answer_circles, key=lambda circle: circle[1])
print("sorted_y_answer_circles", sorted_y_answer_circles)
set_num = 1
for index, circle in enumerate(sorted_y_answer_circles):
if index == 0:
mask_dict[1].append(circle)
else:
if circle[1] - sorted_y_answer_circles[index-1][1] > 30:
set_num += 1
mask_dict[set_num].append(circle)
else:
mask_dict[set_num].append(circle)
 
print("mask_dict", mask_dict)
 
for k, mask_circle_list in mask_dict.items(): # 对每一个题目,保留五个答案,多余的舍去
if len(mask_circle_list) == 5:
sorted_x_mask_circle_list = sorted(mask_circle_list, key=lambda x:x[0])
mask_dict[k]=sorted_x_mask_circle_list
else:
sorted_x_mask_circle_list = sorted(mask_circle_list, key=lambda x: x[0])
sorted_x_mask_circle_list_5 = []
for i, c in enumerate(sorted_x_mask_circle_list):
if i == 0:
sorted_x_mask_circle_list_5.append(c)
else:
if abs(c[0] - sorted_x_mask_circle_list[i-1][0]) < 10:
pass
else:
sorted_x_mask_circle_list_5.append(c)
mask_dict[k] = sorted_x_mask_circle_list_5
 
print("mask_dict", mask_dict)
 
# mask_dict 分好组的按照顺序的圈圈
 
# 做掩码
mask_img = np.zeros_like(part_sheet_img, dtype='uint8') # 全黑图
showImg("threshold_answer", threshold_answer)
threshold_answer = np.array(threshold_answer)
# mask_dict = sorted(mask_dict, key=lambda x: mask_dict.keys())
all_scores = [] # 所有答案处的评分
for exercise_num, circle_mask_list in mask_dict.items():
# 对于每一题
score_list = [] # 每一题的每个选项的评分,涂黑的为选择的,值越接近0, 评分较低
for circle_mask in circle_mask_list:
mask_img_copy = cv2.cvtColor(mask_img, cv2.COLOR_BGR2GRAY)
# 做一个当前圆的掩码:
cv2.circle(mask_img_copy, (circle_mask[0], circle_mask[1]), circle_mask[2], (255, 255, 255), -1)
print(threshold_answer.shape, mask_img_copy.shape)
mask_img_ = cv2.bitwise_and(threshold_answer, threshold_answer, mask=mask_img_copy)
score = mask_img_.sum()
score_list.append(score)
# showImg("mask_img_", mask_img_)
all_scores.append(score_list)
 
 
all_score_np = np.array(all_scores)
s = np.argmin(all_score_np, axis=1) # 找评分最低处即为选择项
 
answer_dict = {
0: "A",
1: "B",
2: "C",
3: "D",
4: "E"
}
 
for index, v in enumerate(s):
print("第%s题的答案是%s" %(index+1, answer_dict[v]))

效果图:

opencv实现答题卡识别

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/qq_36008031/article/details/104464227

延伸 · 阅读

精彩推荐
  • Pythonpython3实现全角和半角字符转换的方法示例

    python3实现全角和半角字符转换的方法示例

    在自然语言处理过程中,全角、半角的的不一致会导致信息抽取不一致,因此需要统一,下面这篇文章主要给大家介绍了关于python3中全角和半角字符转换的...

    陈鹏5272020-12-08
  • PythonPython使用matplotlib和pandas实现的画图操作【经典示例】

    Python使用matplotlib和pandas实现的画图操作【经典示例】

    这篇文章主要介绍了Python使用matplotlib和pandas实现的画图操作,结合实例形式分析了Python基于matplotlib和pandas的数值运算与图形显示操作相关实现技巧,并对部分...

    旭旭_哥9802021-03-04
  • PythonPython游戏开发实例之graphics实现AI五子棋

    Python游戏开发实例之graphics实现AI五子棋

    五子棋是经典的棋牌类游戏,很多人都玩过,那么如何用Python实现五子棋呢,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们...

    小雁子学Python6182022-02-22
  • Pythonmatplotlib事件处理基础(事件绑定、事件属性)

    matplotlib事件处理基础(事件绑定、事件属性)

    这篇文章主要介绍了matplotlib事件处理基础(事件绑定、事件属性),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需...

    mighty134632021-09-01
  • PythonPython lxml模块安装教程

    Python lxml模块安装教程

    这篇文章主要介绍了Python lxml模块安装教程,本文分别讲解了Windows系统和Linux系统下的安装教程,需要的朋友可以参考下 ...

    Python教程网15872020-07-11
  • Python详解Python中类的定义与使用

    详解Python中类的定义与使用

    本篇文章主要介绍了详解Python中类的定义与使用,介绍了什么叫做类和如何使用,具有一定的参考价值,想要学习Python的同学可以了解一下。...

    chenxiaoyong13422020-09-29
  • PythonPython zip()函数用法实例分析

    Python zip()函数用法实例分析

    这篇文章主要介绍了Python zip()函数用法,结合实例形式较为详细的分析了Python zip()函数的功能、使用方法及相关操作注意事项,需要的朋友可以参考下...

    快递小可10512021-01-22
  • Pythonpycharm中TensorFlow调试常见问题小结

    pycharm中TensorFlow调试常见问题小结

    本文主要介绍了在pycharm下调用tensorflow库时会出现的问题,在本文做个小结,也给自己留个笔记,感兴趣的可以了解一下...

    呆呆的猫7142021-12-08