Python - 从图像中检测二维码并使用 OpenCV 进行裁剪 [英] Python - Detect a QR code from an image and crop using OpenCV

查看:75
本文介绍了Python - 从图像中检测二维码并使用 OpenCV 进行裁剪的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 Python(3.7) 和 OpenCV 处理一个项目,其中我有一个文档的图像(使用相机捕获),上面放置了 QR 码.

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

  1. 二维码图片大小

  2. 顶部

  3. 对了

  4. 底部

  5. 单位

<小时>

最新更新:

<块引用>

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

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

我试过这个代码:

def decodeAndCrop(inputImage):打印(str(输入图像))图像 = cv2.imread(str(inputImage))qrCodeDetector = cv2.QRCodeDetector()解码文本,点,_ = qrCodeDetector.detectAndDecode(image)qr_data = decodedText.split(",")打印(来自功能的qr数据:{}".格式(qr_data))如果点不是无:pts = len(分)# 打印(分)对于我在范围内(pts):nextPointIndex = (i + 1) % pts如果 str(inputImage) == "scaled_img.jpg":cv2.line(图片,元组(点[i][0]),元组(点[nextPointIndex][0]),(255, 0, 0),5、)打印(点 [i][0])宽度 = 整数(数学.sqrt((点[0][0][0] - 点[1][0][0]) ** 2+ (点[0][0][1] - 点[1][0][1]) ** 2))高度 = 整数(数学.sqrt((点[1][0][0] - 点[2][0][0]) ** 2+ (点[1][0][1] - 点[2][0][1]) ** 2))print("缩放后的高度和宽度:{} {}".format(height, width))如果不是 str(inputImage) == "scaled_img.jpg":scaled_img = 无如果宽度 == qr_data[0] 和高度 == qr_data[0]:print("大小相等")# 将扩展值添加到点和裁剪y = int(points[0][0][1]) - int(qr_data[1])x = int(points[0][0][0]) - int(qr_data[4])投资回报率 = 图像[y : y + height + int(qr_data[3]), x : x + width + int(qr_data[2])]scaled_img = cv2.imwrite("scaled_img.jpg", roi)返回 scaled_img别的:打印(《宽度和高度》+ str(宽度)+ "x"+ str(高度)+ " 不等于 "+ str(qr_data[0])+ "x"+ str(qr_data[0]))如果高度 >int(qr_data[0]):scale_width = int(width) - int(qr_data[0])scale_height = int(height) - int(qr_data[0])打印(f缩放宽度:{scale_width} 缩放高度:{scale_height}")尺寸 = (scale_width, scale_height)scaled_img = cv2.resize(图像、维度、插值=cv2.INTER_AREA)打印(新的 img 变暗:{}".format(scaled_img.shape))cv2.imshow("缩放图像:", scaled_img)cv2.imwrite("scaled_img.jpg", scaled_img)elif 高度 

<小时><块引用>

上面的代码给出了一个错误: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: 错误: (-215:Assertion failed) !_img.empty() 在函数 'imwrite' 中

<小时>

最新更新结束:

<小时>

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

现在,我需要从这个文档图像中检测二维码,在第一步中,我需要将捕获的文档图像中二维码的大小与解码信息中提到的大小进行比较,例如,如果在捕获的图像 QR 图像的大小为 90X90 像素,解码信息的大小为 100X100 像素,我们需要进行比较.

然后,在第二步中,我必须使用顶部、右侧、底部和底部来裁剪完整的图像.相应地留下变量.根据上面的例子,我们需要将检测到的二维码位置的图像裁剪为顶部 20 像素、右侧 40 像素、底部 60 像素和右侧 20 像素.我在下面添加了一个示例图片.

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

<块引用>

这是我迄今为止尝试过的:

导入 cv2image = cv2.imread('/Users/abdul/PycharmProjects/QScanner/images/second.jpg')qrCodeDetector = cv2.QRCodeDetector()解码文本,点,_ = qrCodeDetector.detectAndDecode(image)qr_data = decodedText.split(',')qr_size = qr_data[0]顶部 = qr_data[1]右 = qr_data[2]底部 = qr_data[3]左 = qr_data[4]打印(f'大小:{qr_size}' + str(qr_data[5]))打印(f'顶部:{顶部}')打印(f'右:{右}')打印(f'底部:{底部}')打印(f'左:{左}')如果点不是无:pts = len(分)打印(分)对于我在范围内(pts):nextPointIndex = (i+1) % ptscv2.line(image, tuple(points[i][0]), tuple(points[nextPointIndex][0]), (255,0,0), 5)打印(点 [i][0])打印(解码文本)cv2.imshow("图像", 图像)cv2.waitKey(0)cv2.destroyAllWindows()别的:print("未检测到二维码")

<块引用>

这是一个示例图片:

<块引用>

这是输入图像的示例:

解决方案

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

  1. 获取二进制图像.

    提取的二维码

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

    代码

    导入 cv2将 numpy 导入为 np# 加载图片、灰度、高斯模糊、大津阈值图像 = cv2.imread('1.jpg')原始 = image.copy()灰色 = cv2.cvtColor(图像,cv2.COLOR_BGR2GRAY)模糊 = cv2.GaussianBlur(gray, (9,9), 0)thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]# 变形关闭内核 = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))关闭 = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, 内核, 迭代 = 2)# 寻找轮廓并过滤二维码cnts = cv2.findContours(关闭,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)cnts = cnts[0] 如果 len(cnts) == 2 else cnts[1]对于 cnts 中的 c:peri = cv2.arcLength(c, True)approx = cv2.approxPolyDP(c, 0.04 * peri, True)x,y,w,h = cv2.boundingRect(approx)面积 = cv2.contourArea(c)ar = w/float(h)如果 len(approx) == 4 and area >1000 和 (ar > .85 和 ar < 1.3):cv2.rectangle(图像, (x, y), (x + w, y + h), (36,255,12), 3)ROI = 原始[y:y+h, x:x+w]cv2.imwrite('ROI.png', ROI)cv2.imshow('thresh', thresh)cv2.imshow('关闭', 关闭)cv2.imshow('图像', 图像)cv2.imshow('ROI', ROI)cv2.waitKey()

    I'm working on a project using Python(3.7) and OpenCV in which I have an Image(captured using the camera) of a document with a QR code placed on it.

    This QR code has 6 variables respectively as:

    1. Size of QR code image

    2. Top

    3. Right

    4. Bottom

    5. Left

    6. Unit


    Latest Update:

    Here are the steps I need to perform in the same order:

    1. Detect the qr code & decode it to read size values
    2. So, if the size of QR-code(image) is not equal to the size which is mentioned inside it then scale the image to equal both size values.
    3. Then crop the image towards all sides from QR code image according to the values mentioned inside qr code.

    I have tried this code:

    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()
    


    The code above gives an error as: 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() in function 'imwrite'


    End of Latest Update:


    An example decoded information of a QR code is as: 100, 20, 40, 60, 20, px

    Now, I need to detect the QR code from this document image and in the first step I need to compare the size of QR code in captured image of document with the size which is mentioned in the decoded information for example if in the captured image the size of the QR image is 90X90px and the size from decoded info is 100X100px we need to compare that.

    Then, in the second step I have to crop the complete image by using the Top, Right, Bottom & Left variables accordingly. According to the above example we need to crop the image from the position of detected QR code to 20px Top, 40px Right, 60px Bottom and 20px Right. I have added an example Image below.

    I have done to decode the QR code information but how can I take the detected QR code area as a seprate image and compare it's size with the mentioned size and then crop the Image accordingly?

    Here's what I have tried so far:

    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")
    

    Here's an example Image:

    and here's a sample of input image:

    解决方案

    Here's a simple approach using thresholding, morphological operations, and contour filtering.

    1. Obtain binary image. Load image, grayscale, Gaussian blur, Otsu's threshold

    2. Connect individual QR contours. Create a rectangular structuring kernel with cv2.getStructuringElement() then perform morphological operations with cv2.MORPH_CLOSE.

    3. Filter for QR code. Find contours and filter using contour approximation, contour area, and aspect ratio.


    Detected QR code

    Extracted QR code

    From here you can compare the QR code with your reference information

    Code

    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()     
    

    这篇关于Python - 从图像中检测二维码并使用 OpenCV 进行裁剪的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆