当前位置:网站首页>opencv学习笔记八--答题卡识别
opencv学习笔记八--答题卡识别
2022-07-06 07:30:00 【Cloudy_to_sunny】
opencv学习笔记八--答题卡识别
导入工具包
#导入工具包
import numpy as np
import argparse
import imutils
import cv2
import matplotlib.pyplot as plt#Matplotlib是RGB
# 正确答案
ANSWER_KEY = {
0: 1, 1: 4, 2: 0, 3: 3, 4: 1}
定义函数
def order_points(pts):
# 一共4个坐标点
rect = np.zeros((4, 2), dtype = "float32")
# 按顺序找到对应坐标0123分别是 左上,右上,右下,左下
# 计算左上,右下
s = pts.sum(axis = 1)
rect[0] = pts[np.argmin(s)]
rect[2] = pts[np.argmax(s)]
# 计算右上和左下
diff = np.diff(pts, axis = 1)
rect[1] = pts[np.argmin(diff)]
rect[3] = pts[np.argmax(diff)]
return rect
def four_point_transform(image, pts):
# 获取输入坐标点
rect = order_points(pts)
(tl, tr, br, bl) = rect
# 计算输入的w和h值
widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
maxWidth = max(int(widthA), int(widthB))
heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
maxHeight = max(int(heightA), int(heightB))
# 变换后对应坐标位置
dst = np.array([
[0, 0],
[maxWidth - 1, 0],
[maxWidth - 1, maxHeight - 1],
[0, maxHeight - 1]], dtype = "float32")
# 计算变换矩阵
M = cv2.getPerspectiveTransform(rect, dst)
warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))
# 返回变换后结果
return warped
def sort_contours(cnts, method="left-to-right"):
reverse = False
i = 0
if method == "right-to-left" or method == "bottom-to-top":
reverse = True
if method == "top-to-bottom" or method == "bottom-to-top":
i = 1
boundingBoxes = [cv2.boundingRect(c) for c in cnts]
(cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),
key=lambda b: b[1][i], reverse=reverse))
return cnts, boundingBoxes
#显示函数
def cv_show(name,img):
b,g,r = cv2.split(img)
img_rgb = cv2.merge((r,g,b))
plt.imshow(img_rgb)
plt.show()
def cv_show1(name,img):
plt.imshow(img)
plt.show()
cv2.imshow(name,img)
cv2.waitKey()
cv2.destroyAllWindows()
扫描
# 预处理
image = cv2.imread("./images/test_01.png")
contours_img = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0) #高斯滤波
cv_show1('blurred',blurred)
edged = cv2.Canny(blurred, 75, 200) #边缘检测
cv_show1('edged',edged)
# 轮廓检测
cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)[1]
cv2.drawContours(contours_img,cnts,-1,(0,0,255),3)
cv_show('contours_img',contours_img)
docCnt = None
# 确保检测到了
if len(cnts) > 0:
# 根据轮廓大小进行排序
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
# 遍历每一个轮廓
for c in cnts:
# 近似
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.02 * peri, True)
# 准备做透视变换
if len(approx) == 4:
docCnt = approx
break
# 执行透视变换
warped = four_point_transform(gray, docCnt.reshape(4, 2))
cv_show1('warped',warped)
自适应阈值处理
# Otsu's 阈值处理
thresh = cv2.threshold(warped, 0, 255,
cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
thresh_Contours = thresh.copy()
cv_show1('thresh_Contours',thresh_Contours)
检测每一个选项的轮廓
# 找到每一个圆圈轮廓
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)[1]
cv2.drawContours(thresh_Contours,cnts,-1,(0,0,255),3) #因为是二值化的图像,所以只要不是255,255,255都会变成黑色
print(len(cnts))
cv_show1('thresh_Contours',thresh_Contours)
questionCnts = []
82
# 遍历
for c in cnts:
# 计算比例和大小
(x, y, w, h) = cv2.boundingRect(c)
ar = w / float(h)
# 根据实际情况指定标准
if w >= 20 and h >= 20 and ar >= 0.9 and ar <= 1.1:
questionCnts.append(c)
对轮廓进行排序以获取序号
# 按照从上到下进行排序
questionCnts = sort_contours(questionCnts,
method="top-to-bottom")[0]
correct = 0
# 每排有5个选项
for (q, i) in enumerate(np.arange(0, len(questionCnts), 5)):
# 排序
cnts = sort_contours(questionCnts[i:i + 5])[0]
bubbled = None
# 遍历每一个结果
for (j, c) in enumerate(cnts):
# 使用mask来判断结果
mask = np.zeros(thresh.shape, dtype="uint8")
cv2.drawContours(mask, [c], -1, 255, -1) #-1表示填充
# 通过计算非零点数量来算是否选择这个答案
mask = cv2.bitwise_and(thresh, thresh, mask=mask)
total = cv2.countNonZero(mask)
cv_show1('mask',mask)
# 通过阈值判断
if bubbled is None or total > bubbled[0]:
bubbled = (total, j)
# 对比正确答案
color = (0, 0, 255)
k = ANSWER_KEY[q]
# 判断正确
if k == bubbled[1]:
color = (0, 255, 0)
correct += 1
# 绘图
cv2.drawContours(warped, [cnts[k]], -1, color, 3)
打印结果
score = (correct / 5.0) * 100
print("[INFO] score: {:.2f}%".format(score))
cv2.putText(warped, "{:.2f}%".format(score), (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 0, 255), 2)
cv_show("Original", image)
cv_show1("Exam", warped)
[INFO] score: 80.00%
参考
边栏推荐
- chrome查看页面fps
- 洛谷P1836 数页码 题解
- Oracle column to row -- a field is converted to multiple rows according to the specified separator
- How Navicat imports MySQL scripts
- JDBC learning notes
- ORACLE列转行--某字段按指定分隔符转多行
- Simulation of holographic interferogram and phase reconstruction of Fourier transform based on MATLAB
- #systemverilog# 可綜合模型的結構總結
- Full Score composition generator: living on code
- 智能终端设备加密防护的意义和措施
猜你喜欢
Simulation of holographic interferogram and phase reconstruction of Fourier transform based on MATLAB
The way to learn go (I) the basic introduction of go to the first HelloWorld
Detailed explanation | detailed explanation of internal mechanism of industrial robot
Typescript interface and the use of generics
Simulation of Michelson interferometer based on MATLAB
The ECU of 21 Audi q5l 45tfsi brushes is upgraded to master special adjustment, and the horsepower is safely and stably increased to 305 horsepower
数字IC设计笔试题汇总(一)
Oracle column to row -- a field is converted to multiple rows according to the specified separator
Seriously recommend several machine learning official account
Excel的相关操作
随机推荐
Relevant introduction of clip image
杰理之BLE【篇】
Supervisor usage document
Go learning -- implementing generics based on reflection and empty interfaces
[CF Gym101196-I] Waif Until Dark 网络最大流
TypeScript 变量作用域
word中如何删除某符号前面或后面所有的文字
Sélectionnez toutes les lignes avec un symbole dans Word et changez - les en titre
The way to learn go (I) the basic introduction of go to the first HelloWorld
Bloom taxonomy
The differences and advantages and disadvantages between cookies, seeion and token
http缓存,强制缓存,协商缓存
学go之路(一)go的基本介绍到第一个helloworld
OpenJudge NOI 2.1 1749:数字方格
Uni app practical project
Simulation of holographic interferogram and phase reconstruction of Fourier transform based on MATLAB
TypeScript void 基础类型
How to delete all the words before or after a symbol in word
位运算异或
可变参数重载时的内存错误