使用Python OpenCV旋转QR码到正确位置

4

我是Python的初学者,目前正在学习QR码的检测和解码。我发现将检测到的QR码旋转到正确的位置很困难。我已经使用了minAreaRect()来旋转我的QR码,但它并没有起作用。有没有任何解决方法或正确的方法可以做到这一点?谢谢!

ROI2 = cv2.imread('ROI.png')
gray2 = cv2.cvtColor(ROI2, cv2.COLOR_BGR2GRAY)
blur2 = cv2.GaussianBlur(gray2, (9, 9), 0)
thresh2 = cv2.threshold(blur2, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# Morph close
# kernel2 = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
# close2 = cv2.morphologyEx(thresh2, cv2.MORPH_CLOSE, kernel2, iterations=10)

# Find contours and filter for QR code
cnts2 = cv2.findContours(thresh2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts2 = cnts2[0] if len(cnts2) == 2 else cnts2[1]
c = sorted(cnts2, key=cv2.contourArea, reverse=True)[0]

draw = cv2.cvtColor(thresh2, cv2.COLOR_GRAY2BGR)
cv2.drawContours(draw, [c], 0, (0, 255, 0), 2)

rotrect = cv2.minAreaRect(c)
box = cv2.boxPoints(rotrect)
box = numpy.int0(box)
cv2.drawContours(draw, [box], 0, (0, 0, 255), 2)

cv2.imshow('thresh', thresh2)
cv2.imshow('ROI', ROI2)
cv2.imshow('minarearect', draw)

thresh ROI minAreaRect output


如果我没记错的话,在 PyImageSearch 的博客上有一篇文章,它使用了一个循环来旋转图像并检查是否有垂直线。但我认为你可以使用红色矩形来计算角度(tan(angle) = dy/dx)。 - furas
检测代码(QRCodeDetector),然后从提取的模块(像素)中重新绘制它,这些模块已经由QRCodeDetector::detectAndDecodestraight_qrcode值给出。或者使用检测结果,其中包含代码的角落,并将其用于仿射或透视变换,但这可能会给您四个可能的旋转之一。 - Christoph Rackwitz
2个回答

6
根据我的理解,您正在尝试矫正图像。为此,我们需要先计算旋转边界框的角度,然后执行线性变换。思路是使用cv2.minAreaRectcv2.warpAffine。根据文档,cv2.minAreaRect返回旋转边界框的信息。
(center(x, y), (width, height), angle of rotation) = cv2.minAreaRect(...)

第三个参数给出了我们需要矫正图像的角度。
输入图像 -> 输出结果
Skew angle: -39.99416732788086

代码

import cv2
import numpy as np

# Load image, grayscale, Otsu's threshold
image = cv2.imread('2.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = 255 - gray
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]

# Compute rotated bounding box
coords = np.column_stack(np.where(thresh > 0))
angle = cv2.minAreaRect(coords)[-1]

if angle < -45:
    angle = -(90 + angle)
else:
    angle = -angle
print("Skew angle: ", angle)

# Rotate image to deskew
(h, w) = image.shape[:2]
center = (w // 2, h // 2)
M = cv2.getRotationMatrix2D(center, angle, 1.0)
rotated = cv2.warpAffine(image, M, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)

cv2.imshow('rotated', rotated)
cv2.waitKey()

注意: 请参考 Python OpenCV 基于投影剖面法的倾斜校正,另一种用于纠正倾斜的方法。


2
使用QRCodeDetector::detectAndDecode检测代码,并从straight_qrcode值中重新绘制。QRCodeDetector可能无法解码您使用简单阈值和轮廓定位到的所有代码。特别是当它的部分缺失(包括空白区域)时,QR码探测器可能会遇到麻烦。
这将始终以规范方向显示代码,并将发现模式朝向NW,NE和SW方向。
简单的minAreaRect只能将代码的边缘与图像轴对齐,但它不能确定QR代码的“上”方向。
import cv2 as cv

im = cv.imread("OnDlO.png")

det = cv.QRCodeDetector()
(rv, points, straight_qrcode) = det.detectAndDecode(im)
# rv == 'testing123456'
# points:
# array([[[304.     ,  36.     ],
#         [415.     , 321.     ],
#         [141.55959, 428.3963 ],
#         [ 32.     , 151.     ]]], dtype=float32)

# some white padding
with_quiet_zone = cv.copyMakeBorder(straight_qrcode, 1, 1, 1, 1, borderType=cv.BORDER_CONSTANT, value=255)

# scale it up for display
larger = cv.resize(with_quiet_zone, dsize=None, fx=16, fy=16, interpolation=cv.INTER_NEAREST)

# and show it
cv.imshow("larger", larger)
cv.waitKey()

输入:

enter image description here

输出:

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接