-
Notifications
You must be signed in to change notification settings - Fork 30
/
Copy pathsheet_scan_example01.py
160 lines (104 loc) · 5.33 KB
/
sheet_scan_example01.py
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
# -*- coding:utf-8 -*-
from imutils.perspective import four_point_transform
from imutils import contours
import numpy as np
import imutils
import cv2 as cv
ANSWER_KEY_SCORE = {0: 1, 1: 4, 2: 0, 3: 3, 4: 1}
ANSWER_KEY = {0: "A", 1: "B", 2: "C", 3: "D", 4: "E"}
# 加载一个图片到opencv中
img = cv.imread('E:\\tmp\\t1.png')
cv.imshow("orgin",img)
#转化成灰度图片
gray=cv.cvtColor(img,cv.COLOR_BGR2GRAY)
cv.imshow("gray",gray)
gaussian_bulr = cv.GaussianBlur(gray, (5, 5), 0) # 高斯模糊
cv.imshow("gaussian",gaussian_bulr)
edged=cv.Canny(gaussian_bulr,75,200) # 边缘检测,灰度值小于2参这个值的会被丢弃,大于3参这个值会被当成边缘,在中间的部分,自动检测
cv.imshow("edged",edged)
# 寻找轮廓
image, cts, hierarchy = cv.findContours( edged.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
# 给轮廓加标记,便于我们在原图里面观察,注意必须是原图才能画出红色,灰度图是没有颜色的
# cv.drawContours(img, cts, -1, (0,0,255), 3)
# 按面积大小对所有的轮廓排序
list=sorted(cts,key=cv.contourArea,reverse=True)
print("寻找轮廓的个数:",len(cts))
cv.imshow("draw_contours",img)
# 正确题的个数
correct_count=0
for c in list:
# 周长,第1个参数是轮廓,第二个参数代表是否是闭环的图形
peri=0.01*cv.arcLength(c,True)
# 获取多边形的所有定点,如果是四个定点,就代表是矩形
approx=cv.approxPolyDP(c,peri,True)
# 打印定点个数
print("顶点个数:",len(approx))
if len(approx)==4: #矩形
# 透视变换提取原图内容部分
ox_sheet = four_point_transform(img, approx.reshape(4, 2))
# 透视变换提取灰度图内容部分
tx_sheet = four_point_transform(gray, approx.reshape(4, 2))
cv.imshow("ox", ox_sheet)
cv.imshow("tx", tx_sheet)
# 使用ostu二值化算法对灰度图做一个二值化处理
ret,thresh2 = cv.threshold(tx_sheet, 0, 255,cv.THRESH_BINARY_INV | cv.THRESH_OTSU)
cv.imshow("ostu", thresh2)
# 继续寻找轮廓
r_image, r_cnt, r_hierarchy = cv.findContours(thresh2.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
print("找到轮廓个数:",len(r_cnt))
# 使用红色标记所有的轮廓
# cv.drawContours(ox_sheet,r_cnt,-1,(0,0,255),2)
# 把所有找到的轮廓,给标记出来
questionCnts = []
for cxx in r_cnt:
# 通过矩形,标记每一个指定的轮廓
x, y, w, h = cv.boundingRect(cxx)
ar = w / float(h)
if w >= 20 and h >= 20 and ar >= 0.9 and ar <= 1.1:
# 使用红色标记,满足指定条件的图形
# cv.rectangle(ox_sheet, (x, y), (x + w, y + h), (0, 0, 255), 2)
# 把每个选项,保存下来
questionCnts.append(cxx)
cv.imshow("ox_1", ox_sheet)
# 按坐标从上到下排序
questionCnts = contours.sort_contours(questionCnts, method="top-to-bottom")[0]
# 使用np函数,按5个元素,生成一个集合
for (q, i) in enumerate(np.arange(0, len(questionCnts), 5)):
# 获取按从左到右的排序后的5个元素
cnts = contours.sort_contours(questionCnts[i:i + 5])[0]
bubble_rows=[]
# 遍历每一个选项
for (j, c) in enumerate(cnts):
# 生成一个大小与透视图一样的全黑背景图布
mask = np.zeros(tx_sheet.shape, dtype="uint8")
# 将指定的轮廓+白色的填充写到画板上,255代表亮度值,亮度=255的时候,颜色是白色,等于0的时候是黑色
cv.drawContours(mask, [c], -1, 255, -1)
# 做两个图片做位运算,把每个选项独自显示到画布上,为了统计非0像素值使用,这部分像素最大的其实就是答案
mask = cv.bitwise_and(thresh2, thresh2, mask=mask)
# cv.imshow("c" + str(i), mask)
# 获取每个答案的像素值
total = cv.countNonZero(mask)
# 存到一个数组里面,tuple里面的参数分别是,像素大小和答案的序号值
# print(total,j)
bubble_rows.append((total,j))
bubble_rows=sorted(bubble_rows,key=lambda x: x[0],reverse=True)
# 选择的答案序号
choice_num=bubble_rows[0][1]
print("答案:{} 数据: {}".format(ANSWER_KEY.get(choice_num),bubble_rows))
fill_color=None
# 如果做对就加1
if ANSWER_KEY_SCORE.get(q) == choice_num:
fill_color = (0, 255, 0) #正确 绿色
correct_count = correct_count+1
else:
fill_color = (0, 0, 255) #错误 红色
cv.drawContours(ox_sheet, cnts[choice_num], -1, fill_color, 2)
cv.imshow("answer_flagged", ox_sheet)
text1 = "total: " + str(len(ANSWER_KEY)) + ""
text2 = "right: " + str(correct_count)
text3 = "score: " + str(correct_count*1.0/len(ANSWER_KEY)*100)+""
font = cv.FONT_HERSHEY_SIMPLEX
cv.putText(ox_sheet, text1 + " " + text2+" "+text3, (10, 30), font, 0.5, (0, 0, 255), 2)
cv.imshow("score", ox_sheet)
break
cv.waitKey(0)