Python提取支付寶和微信支付二維碼

追夢人物發表於2019-02-14

本文首發於我的個人部落格,更多 Python 和 django 開發教程,請訪問 追夢人物的部落格

支付寶或者微信支付匯出的收款二維碼,除了二維碼部分,還有很大一塊背景圖案,例如下面就是微信支付的收款二維碼:

Python提取支付寶和微信支付二維碼

有時候我們僅僅只想要圖片中間的方形二維碼部分,為了提取出中間部分,我們可以使用圖片處理軟體,但圖片處理軟體不利於批處理,且學習也需要一定成本。本文將教你使用 Python 的影象處理庫 pillow,輕鬆批量提取圖片中間的方形二維碼部分。

提取思路

以微信支付收款碼圖片為例:

分析圖片我們可以看到,二維碼位於白色背景中,而白色背景又位於綠色背景上。我們以圖片左上角為座標原點,橫向為 x 軸(向右為正方向),縱向為 y 軸(向下為正方向)。我們的目標是需要確定白色背景部分 4 個角的座標。

從圖片左邊正中向右橫向穿過,當背景色從綠色變為白色時,該點所在位置的橫座標即為左上角和左下角的橫座標,記為 x_left。

同理從圖片右邊正中向左橫向穿過,當背景色從綠色變為白色時,該點所在位置的橫座標即為右上角和右下角的橫座標,記為 x_right。

則白色背景寬度和高度為 h = x_right - x_left。

再從綠色背景轉為白色背景時的點向上(或者向下,此處以向上為例)出發,當背景色從白色又變為綠色時,該點所在位置的縱座標即為左上角和右上角的縱座標,記為 y_top。

則可以計算出左下角和右下角的縱座標為 (y_top + h)。

由此,白色背景部分 4 個角的座標均確定,分別為(從左上角開始順時針):(x_left, y_top)、(x_right, y_top)、(x_right, y_top+h)、(x_left, y_top+h)。

程式碼實現

有了上述思路,我們就可以輕鬆寫出 Python 指令碼了。程式碼中給出了詳細註釋,其基本思路就是匯入圖片,將其轉為一個二維矩陣,矩陣的元素為圖片對應畫素點的 RGBA 值,然後根據 RGBA 值的變化(即顏色的變化)確定待裁剪邊界即可。

import glob
from PIL import Image

if __name__ == '__main__':
    filenames = glob.glob('*.png')  # 微信支付收款碼匯出為 png 格式
    filenames.extend(glob.glob('*.jpg'))  # 支付寶收款碼匯出為 jpg 格式

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

            # 圖片左上角為原點,橫向為 x 軸(向右為正方向),縱向為 y 軸(向下為正方向)
            width, height = img.size  # 圖片寬和高
            mid_height = height // 2  # 圖片正中縱座標

            # 確定左邊界橫座標:
            x_left = 0
            for x in range(width):
                rgba = pix_data[x, mid_height]
                if rgba[:3] == (255, 255, 255):
                    x_left = x
                    break

            # 確定右邊界橫座標:
            x_right = width - 1  # 右邊界
            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  # 白色背景高度(正方形)
            mid_height_rgba = pix_data[x_left, mid_height]
            if filename.endswith('png'):
                # 微信支付往下確定下邊界縱座標,因為當設定了收款金額時,金額顯示在上方
                y_bottom = mid_height
                for y in range(mid_height, height):
                    rgba = pix_data[x_left, y]
                    if rgba != mid_height_rgba:
                        y_bottom = y
                        break
                box = (x_left, y_bottom - h, x_right, y_bottom)
            else:
                # 支付寶往上確定上邊界縱座標,因為當設定了收款金額時,金額顯示在下方
                y_top = mid_height
                for y in range(mid_height, 0, -1):
                    rgba = pix_data[x_left, y]
                    if rgba != mid_height_rgba:
                        y_top = y
                        break
                box = (x_left, y_top, x_right, y_top + h)
            crop = img.crop(box) # box 引數為四元組,分別為左上角和右下角的橫縱座標
            crop.save('./result/{}'.format(filename))
複製程式碼

指令碼程式碼同時上傳在 GitHub,使用方法請看 README 文件即可。指令碼原始碼倉庫:clip-pay-pic

我分享程式設計感悟與學習資料的公眾號,敬請關注:程式設計師甜甜圈

相關文章