cover_image

2021008期:答题卡识别优化—边框识别

nestor 梅沙技术团队
2021年03月18日 10:05


保护私人版权,尊重他人版权。转载请注明出处并附带页面链接

问题

在上一篇答题卡识别中我们是通过边缘检测之后用findContours提取边框的,只要控制好边缘检测的阈值看起来识别效果都很好,但是实际使用中发现一旦边框有干扰findContours就无法直接识别边框出来

比如原图:

图片

通过边缘检测处理来识别:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

import cv2
import imutils
from imutils.perspective import four_point_transform
import matplotlib.pyplot as plt

# 读入图片
image = cv2.imread("/Users/xxx/Downloads/56112723-6a82-462c-96ad-df832a31f039.png")

# 转换为灰阶,轻度模糊
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
edged = imutils.auto_canny(blurred)

# 从边缘图中寻找轮廓,然后初始化答题卡对应的轮廓
cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)

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

# 对原始图像和灰度图都进行四点透视变换
paper = four_point_transform(image, docCnt.reshape(4, 2))
warped = four_point_transform(gray, docCnt.reshape(4, 2))

plt.figure('paper')
plt.imshow(imutils.opencv2matplotlib(paper))
plt.show()

识别结果:

图片

可见最外层边框被干扰后无法识别,只识别到了里面没被干扰的边框

解决思路

  1. 二值化图像

  2. 检测水平直线

  3. 检测垂直直线

  4. 对仅剩下直线的图像提取轮廓

实现代码



import cv2
import imutils
from imutils.perspective import four_point_transform
import matplotlib.pyplot as plt
import numpy as np

# 读入图片
image = cv2.imread("/Users/xxx/Downloads/56112723-6a82-462c-96ad-df832a31f039.png")

mask = np.zeros(image.shape, dtype=np.uint8)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5, 5), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# 检测水平直线
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (50, 1))
detect_horizontal = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)
cnts = cv2.findContours(detect_horizontal, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
for c in cnts:
cv2.drawContours(mask, [c], -1, (255, 255, 255), 3)

# 检测垂直直线
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 50))
detect_vertical = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel, iterations=2)
cnts = cv2.findContours(detect_vertical, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
for c in cnts:
cv2.drawContours(mask, [c], -1, (255, 255, 255), 3)

mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)

# 寻找轮廓
cnts = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)

= 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:
doc_cnt = approx
break

# 对原始图像和灰度图都进行四点透视变换
paper = four_point_transform(image, doc_cnt.reshape(4, 2))
warped = four_point_transform(gray, doc_cnt.reshape(4, 2))

plt.figure('paper')
plt.imshow(imutils.opencv2matplotlib(paper))
plt.show()

thresh

图片

mask

图片

paper

图片

继续滑动看下一个
梅沙技术团队
向上滑动看下一个