赞
踩
记一篇python-opencv 完成答题卡识别 项目的学习笔记
输入一张特定格式的答题卡图片(答题卡中题目数量和选项个数是固定的),能够输出此答题卡中答案的准确率。运行效果如下:
输入一张答题卡图片
输出结果
对于这类任务,先整理一下图像处理的思路。
我们输入的是一张答题卡的拍摄图片,而我们要处理的是这张答题卡的内容,需要用到透视变换将答题卡的内容单独拿出来;
提取答题卡中填涂区域的轮廓,并进行二值化处理,利用掩模与二值化后的答题卡进行对比处理。(灰度化处理、二值化、边缘检测)
在一个两层循环中遍历每一道题目的每一个选项,得出准确率。最后将准确率显示在图片上。
image = cv2.imread(args["image"])
contours_img = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
cv_show('GaussianBlured',blurred)
edged = cv2.Canny(blurred, 75, 200)
cv_show('Canny',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)
读取图片,防止原图片被更改,通常复制该图片
把图片(转化为灰度图、高斯滤波滤除噪声、Canny边缘检测),检测轮廓并在图片上绘制轮廓。
Canny边缘检测的具体步骤:
高斯滤波是一种线性平滑滤波,对于滤除图片中的高斯噪声效果显著。
滤波是对整张图像进行加权平均的过程。高斯滤波的具体操作是用一个模板扫描图像中的每一个像素点,用模板确定的邻域内像素的加权平均灰度值去替代模板中心像素点的值。
高斯滤波器是一类根据高斯函数的形状来选择权值的线性平滑滤波器。
比较当前点和周围点之间的梯度幅值大小,如果该店的梯度幅值最大,则保留该点位边界点。否则将该点抑制掉
对于函数中的两个参数,如果梯度值>maxval,则按边界处理;
如果minval<梯度值<maxval,且该点与边界点连接,则将该点视为边界点。否则舍弃该点;
如果梯度值<minval,则判断该点不是边界点
Canny边缘检测结果如图所示:
接着检测图片中的轮廓
cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[1]
检测外轮廓,参数cv2.CHAIN_APPROX_SIMPLE
表示图像轮廓的逼近方式。
该函数的返回值是存放轮廓的list结构。
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)
print('approx', approx)
if len(approx) == 4:
docCnt = approx
break
遍历所有检测到的轮廓,根据轮廓面积大小进行排序。求近似轮廓,精度为轮廓周长的2%。取函数cv2.approxPolyDP
的前四个返回值,这四个点围成了图片中最大的轮廓。
返回approx
结果为:
def four_point_transform(image, pts):
rect = order_points(pts)
(bl, br, tr, tl) = rect
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((
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。