Python - 从图像中检测二维码并使用 OpenCV 进行裁剪

新手上路,请多包涵

我正在使用 Python(3.7) 和 OpenCV 开发一个项目,其中我有一个文档的图像(使用相机捕获),上面放置了二维码。

这个二维码有6个变量,分别为:

  1. 二维码图片大小

  2. 最佳

  3. 正确的

  4. 底部

  5. 剩下

  6. 单元


最新更新:

以下是我需要按相同顺序执行的步骤:

  1. 检测二维码并将其解码以读取尺寸值
  2. 因此,如果 QR 码(图像)的大小不等于其中提到的大小,则将图像缩放为等于两个大小值。
  3. 然后根据二维码中提到的值从二维码图像向四面八方裁剪图像。

我试过这段代码:

 def decodeAndCrop(inputImage):
    print(str(inputImage))
    image = cv2.imread(str(inputImage))
    qrCodeDetector = cv2.QRCodeDetector()
    decodedText, points, _ = qrCodeDetector.detectAndDecode(image)
    qr_data = decodedText.split(",")
    print("qr data from fucntion: {}".format(qr_data))
    if points is not None:
        pts = len(points)
    # print(pts)
    for i in range(pts):
        nextPointIndex = (i + 1) % pts
        if str(inputImage) == "scaled_img.jpg":
            cv2.line(
                image,
                tuple(points[i][0]),
                tuple(points[nextPointIndex][0]),
                (255, 0, 0),
                5,
            )
        print(points[i][0])
        width = int(
            math.sqrt(
                (points[0][0][0] - points[1][0][0]) ** 2
                + (points[0][0][1] - points[1][0][1]) ** 2
            )
        )
        height = int(
            math.sqrt(
                (points[1][0][0] - points[2][0][0]) ** 2
                + (points[1][0][1] - points[2][0][1]) ** 2
            )
        )
        print("height and width after scaling: {} {}".format(height, width))
        if not str(inputImage) == "scaled_img.jpg":
            scaled_img = None
            if width == qr_data[0] and height == qr_data[0]:
                print("Sizes are equal")
                # Add the extension values to points and crop
                y = int(points[0][0][1]) - int(qr_data[1])
                x = int(points[0][0][0]) - int(qr_data[4])
                roi = image[
                    y : y + height + int(qr_data[3]), x : x + width + int(qr_data[2])
                ]
                scaled_img = cv2.imwrite("scaled_img.jpg", roi)
                return scaled_img
            else:
                print(
                    "Width and height  "
                    + str(width)
                    + "x"
                    + str(height)
                    + "  not equal to "
                    + str(qr_data[0])
                    + "x"
                    + str(qr_data[0])
                )
                if height > int(qr_data[0]):
                    scale_width = int(width) - int(qr_data[0])
                    scale_height = int(height) - int(qr_data[0])
                    print(f"scaled width: {scale_width} scaled height: {scale_height}")
                    dimension = (scale_width, scale_height)
                    scaled_img = cv2.resize(
                        image, dimension, interpolation=cv2.INTER_AREA
                    )
                    print("new img dims: {}".format(scaled_img.shape))
                    cv2.imshow("scaled image:", scaled_img)
                    cv2.imwrite("scaled_img.jpg", scaled_img)
                elif height < int(qr_data[0]):
                    scale_width = int(qr_data[0]) - width
                    scale_height = int(qr_data[0] - height)
                    print(f"scaled width: {scale_width} scaled height: {scale_height}")
                    dimension = (scale_width, scale_height)
                    scaled_img = cv2.resize(
                        image, dimension, interpolation=cv2.INTER_AREA
                    )
                    print("new img dims: {}".format(scaled_img.shape))
                    cv2.imshow("scaled image:", scaled_img)
                    cv2.imwrite("scaled_img.jpg", scaled_img)
                    cv2.imshow("final output:", roi)
                return scaled_img

        else:
            y = int(points[0][0][1]) - int(qr_data[1])
            x = int(points[0][0][0]) - int(qr_data[4])
            print(" x and y")
            print(x)
            print(y)
            roi = image[
                y : y + height + int(qr_data[3]), x : x + width + int(qr_data[2])
            ]
            final_img = cv2.imwrite("finalized_image.jpg", roi)
            cv2.imshow("finalized image:", final_img)
            return final_img

if __name__ == "__main__":
    image_to_crop = decodeAndCrop("example_input_1.jpg")
    final_image = decodeAndCrop("scaled_img.jpg")
    cv2.imshow("Cropped:", image_to_crop)
    # cv2.imshow("Final: ", final_image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

上面的代码给出了一个错误:final_img = cv2.imwrite(“finalized_image.jpg”, roi) cv2.error: OpenCV(4.2.0) /Users/travis/build/skvark/opencv-python/opencv/modules/imgcodecs /src/loadsave.cpp:715: error: (-215:Assertion failed) !_img.empty() 在函数 ‘imwrite’ 中


最新更新结束:


一个二维码的解码信息示例为:100, 20, 40, 60, 20, px

现在,我需要从该文档图像中检测 QR 码,在第一步中,我需要将捕获的文档图像中的 QR 码大小与解码信息中提到的大小进行比较,例如,如果在捕获的图像中QR 图像的大小是 90X90px,解码信息的大小是 100X100px,我们需要比较它们。

然后,在第二步中,我必须相应地使用 Top、Right、Bottom 和 Left 变量来裁剪完整的图像。根据上面的示例,我们需要将图像从检测到的二维码位置裁剪为 20px Top、40px Right、60px Bottom 和 20px Right。我在下面添加了一个示例图像。

我已经解码了 QR 码信息,但如何将检测到的 QR 码区域作为单独的图像并将其大小与提到的大小进行比较,然后相应地裁剪图像?

到目前为止,这是我尝试过的:

 import cv2

image = cv2.imread('/Users/abdul/PycharmProjects/QScanner/images/second.jpg')

qrCodeDetector = cv2.QRCodeDetector()
decodedText, points, _ = qrCodeDetector.detectAndDecode(image)
qr_data = decodedText.split(',')
qr_size = qr_data[0]
top = qr_data[1]
right = qr_data[2]
bottom = qr_data[3]
left = qr_data[4]

print(f'Size: {qr_size}' + str(qr_data[5]))
print(f'Top: {top}')
print(f'Right: {right}')
print(f'Bottom: {bottom}')
print(f'Left: {left}')
if points is not None:
    pts = len(points)
    print(pts)
    for i in range(pts):
        nextPointIndex = (i+1) % pts
        cv2.line(image, tuple(points[i][0]), tuple(points[nextPointIndex][0]), (255,0,0), 5)
        print(points[i][0])
    print(decodedText)
    cv2.imshow("Image", image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
else:
    print("QR code not detected")

这是一个示例图片:

在此处输入图像描述

这是输入图像的示例:

在此处输入图像描述

原文由 Abdul Rehman 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.2k
1 个回答

这是使用阈值、形态学操作和轮廓过滤的简单方法。

  1. 获取二值图像。 加载图像, 灰度, 高斯模糊, Otsu 的阈值

  2. 连接各个 QR 轮廓。 使用 --- 创建矩形结构内核,然后使用 cv2.MORPH_CLOSE cv2.getStructuringElement() 执行 形态学操作

  3. 筛选二维码。 查找轮廓 并使用 轮廓近似轮廓面积纵横比 进行过滤。


检测到二维码

在此处输入图像描述

提取的二维码

在此处输入图像描述

在这里您可以将二维码与您的参考信息进行比较

代码

import cv2
import numpy as np

# Load imgae, grayscale, Gaussian blur, Otsu's threshold
image = cv2.imread('1.jpg')
original = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (9,9), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# Morph close
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
close = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=2)

# Find contours and filter for QR code
cnts = cv2.findContours(close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.04 * peri, True)
    x,y,w,h = cv2.boundingRect(approx)
    area = cv2.contourArea(c)
    ar = w / float(h)
    if len(approx) == 4 and area > 1000 and (ar > .85 and ar < 1.3):
        cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 3)
        ROI = original[y:y+h, x:x+w]
        cv2.imwrite('ROI.png', ROI)

cv2.imshow('thresh', thresh)
cv2.imshow('close', close)
cv2.imshow('image', image)
cv2.imshow('ROI', ROI)
cv2.waitKey()

原文由 nathancy 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题