This post was first published on my personal blog. For more Python and Django development tutorials, visit the Dreamers blog.

Alipay or wechat pay export collection two-dimensional code, in addition to the two-dimensional code part, there is a large piece of background pattern, for example, the following is wechat pay collection two-dimensional code:

Sometimes we just want the square QR code part in the middle of the image. To extract the middle part, we can use image processing software, but image processing software is not good for batch processing, and learning costs. This article will teach you how to easily batch extract the square QR code portion in the middle of your images using Python’s image-processing library, Pillow.

Extract the train of thought

Take the wechat payment receipt code picture as an example:

Analyzing the image, we can see that the QR code is on a white background, and the white background is on a green background. We take the upper left corner of the picture as the origin of coordinates, with the X-axis in the horizontal direction (positive direction to the right) and the Y-axis in the vertical direction (positive direction to the downward direction). Our goal is to determine the coordinates of the four corners of the white background.

When the background color changes from green to white, the abscissa of the position of the point is the abscissa of the upper left corner and lower left corner, denoting x_left.

Similarly, it passes horizontally to the left from the right center of the picture. When the background color changes from green to white, the abscissa of the position of the point is the abscissa of the upper right corner and lower right corner, denoting x_right.

The width and height of the white background are h = x_right-x_left.

Start from the point where the green background changes to white background and move up (or down, for example). When the background color changes from white to green, the ordinate of the position of the point is the ordinate of the upper left and upper right corner, denoted as y_top.

The y-coordinates of the lower left and right corners can be calculated as y_top + h.

Thus, the coordinates of the four corners of the white background are determined as (clockwise from the upper left corner) :(x_left, y_top), (x_right, y_top), (x_right, y_top+h), (x_left, y_top+h).

Code implementation

With this in mind, we can easily write Python scripts. The basic idea is to import the picture, turn it into a two-dimensional matrix, the element of the matrix is the RGBA value of the corresponding pixel of the picture, and then determine the boundary to be clipped according to the change of the RGBA value (that is, the change of the color).

import glob
from PIL import Image

if __name__ == '__main__':
    filenames = glob.glob('*.png')  # wechat payment receipt code exported to PNG format
    filenames.extend(glob.glob('*.jpg'))  # Alipay payment code export to JPG format

    for filename in filenames:
        with Image.open(filename) as img:
            img.convert('RGBA')
            pix_data = img.load()

            # The upper left corner of the picture is the origin, the horizontal direction is x axis (positive direction is to the right), and the vertical direction is y axis (positive direction is to the downward direction).
            width, height = img.size  # Picture width and height
            mid_height = height // 2  # Image center ordinate

            # determine the left abscissa:
            x_left = 0
            for x in range(width):
                rgba = pix_data[x, mid_height]
                if rgba[:3] = = (255.255.255):
                    x_left = x
                    break

            # determine the abscissa of the right boundary:
            x_right = width - 1  # right boundary
            for x in range(width - 1.0.- 1):
                rgba = pix_data[x, mid_height]
                if rgba[:3] = = (255.255.255):
                    x_right = x
                    break

            h = x_right - x_left  # White background height (square)
            mid_height_rgba = pix_data[x_left, mid_height]
            if filename.endswith('png') :# wechat Pay determines the ordinate of the lower boundary down, because when the amount received is set, the amount is displayed above
                y_bottom = mid_height
                for y in range(mid_height, height):
                    rgba = pix_data[x_left, y]
                    ifrgba ! = mid_height_rgba: y_bottom = ybreak
                box = (x_left, y_bottom - h, x_right, y_bottom)
            else:
                # Alipay determines the ordinate of the upper boundary, because when the amount is set, the amount is displayed below
                y_top = mid_height
                for y in range(mid_height, 0.- 1):
                    rgba = pix_data[x_left, y]
                    ifrgba ! = mid_height_rgba: y_top = ybreak
                box = (x_left, y_top, x_right, y_top + h)
            crop = img.crop(box) The # box argument is a quad, representing the top left corner and bottom right corner
            crop.save('./result/{}'.format(filename))
Copy the code

The script code is uploaded to GitHub at the same time. Please refer to the README document for instructions. Script source repository: clip-pay-pic

I share programming sentiment and learning materials of the public account, please pay attention to: programmer doughnuts