答题卡识别任务--opencv python(附代码)

答题卡识别

项目理论和源码来自唐宇迪opencv项目实战

记一篇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边缘检测

Canny边缘检测的具体步骤:

  1. 使用高斯滤波器平滑图像,去除噪声。
    高斯滤波
    https://blog.csdn.net/keith_bb/article/details/54412493

高斯滤波是一种线性平滑滤波,对于滤除图片中的高斯噪声效果显著
滤波是对整张图像进行加权平均的过程。高斯滤波的具体操作是用一个模板扫描图像中的每一个像素点,用模板确定的邻域内像素的加权平均灰度值去替代模板中心像素点的值。
高斯滤波器是一类根据高斯函数的形状来选择权值的线性平滑滤波器。

  1. 计算图片中每个像素点的强度和方向
  2. 非极大值抑制(NMS)消除边缘检测带来的杂散相应

比较当前点和周围点之间的梯度幅值大小,如果该店的梯度幅值最大,则保留该点位边界点。否则将该点抑制掉

  1. 用双阈值检测来确定真实的和潜在的边缘

对于函数中的两个参数,如果梯度值>maxval,则按边界处理;
如果minval<梯度值<maxval,且该点与边界点连接,则将该点视为边界点。否则舍弃该点;
如果梯度值<minval,则判断该点不是边界点

  1. 通过抑制孤立的弱边缘完成边缘检测

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(((tl[0] - bl[
  • 9
    点赞
  • 68
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值