首頁 > 軟體

Python OpenCV實現任意角度二維條碼矯正

2022-05-31 18:00:29

前言

那天聽到領導他們在討論,說要將圖片進行個矯正處理,還叫來了演演算法部的大佬來討論將要如何處理這個,討論場面很是激烈

不得不說好奇心是個很神奇的東西,就把我給吸引過去了

我定眼一看,感覺作為JAVA開發的我自己也能進行處理

因為看到了圖片後,發現了圖片中一個很重要的特徵點:

要進行矯正的圖片中都會有一個二維條碼圖案,想要矯正的文字和二維條碼圖案是處於同一水平線的。

如下面這個

要把圖片中的“水中加點糖”四個字矯正,只需要把二維條碼矯正就可以了。

具體想法就是,求得二維條碼矯正的角度a,對原圖整體按照角度a進行旋轉就可以了。

有了想法後,就趁熱打鐵,正好週末了在家試試。

一般圖片矯正方式

對於一般的圖片矯正,最常見的做法有這麼兩種:

對圖片進行預處理獲取出輪廓,並求得輪廓的近似矩形,通過矩形的定位點來進行透視變換

對圖片進行預處理後,進行霍夫變換進行直線檢測,再根據直線的傾斜角進行旋轉

但是對於圖片中有二維條碼的圖片進行矯正就可以更加簡單了,因為二維條碼中有定位點並且成熟框架很多,實現起來也更加方便且識別率非常高。

二維條碼圖片矯正

思路

識別出二維條碼的角點,通過相鄰兩個角點的座標計算出夾角度數,再次用此度數對圖片進行旋轉。

以下面圖為例:

先獲取出二維條碼正方向時底部的兩點座標,並求得兩點的傾斜角。

斜率計算用初中數學中求兩點座標斜率的公式算一下即可,忘了就搜搜回憶一下:

兩點的斜率公式:k=(y1-y2)/(x1-x2),x1≠x2。其中(x1,y1),(x2,y2)是已知兩點的座標,x1≠x2。

斜率是表示一條直線(或曲線的切線)關於(橫)座標軸傾斜程度的量。它通常用直線(或曲線的切線)與(橫)座標軸夾角的正切,或兩點的縱座標之差與橫座標之差的比來表示。記作k,k=tgα。

一條直線與某平面直角座標系橫座標軸正半軸方向所成的角的正切值即該直線相對於該座標系的斜率。如果直線與x軸互相垂直,直角的正切值為tan90°,故此直線不存在斜率(也可以說直線的斜率為無窮大)。當直線L的斜率存在時,對於一次函數y=kx+b(斜截式),k即該函數影象的斜率。

編碼實現

實現時對於二維條碼的識別用到了pyzbar庫,對圖片處理用的opencv包

"""
author: puhaiyang
blog: https://blog.csdn.net/puhaiyang
github: https://github.com/puhaiyang
"""
import math
import cv2
from pyzbar import pyzbar
import imutils


def azimuthangle(x1, y1, x2, y2):
    """ 已知兩點座標計算角度 -
    :param x1: 原點橫座標值
    :param y1: 原點縱座標值
    :param x2: 目標點橫座標值
    :param y2: 目標縱座標值
    """
    dx = x2 - x1
    dy = y2 - y1
    # 求斜率
    k = dy / dx
    # 結果是弧度值
    angle = math.atan(k)
    # 弧度值轉為角度
    return angle * 180 / math.pi


def get_angle(qr_item):
    """
    獲取出進行矯正所需要的角度
    """
    # 將座標從下到上,從左到右進行排序
    locs = {qr_item.polygon[0], qr_item.polygon[1], qr_item.polygon[2], qr_item.polygon[3]}
    locs = sorted(locs, key=lambda x: x.y * 100000 + x.x * 1000)
    return azimuthangle(locs[2].x, locs[2].y, locs[3].x, locs[3].y)


def to_up_angle(qr_item):
    """
    獲取出使二維條碼朝上的角度
    """
    if qr_item.orientation == 'UP':
        angle_ext = 0
    elif qr_item.orientation == 'RIGHT':
        angle_ext = 270
    elif qr_item.orientation == 'DOWN':
        angle_ext = 180
    else:
        angle_ext = 90
    return angle_ext


def resize_img(ori_img):
    """
    圖片壓縮
    """
    height = ori_img.shape[0]
    width = ori_img.shape[1]
    # 執行壓縮,按照500的寬度為標準
    if width > 500:
        scale_percent = int(500 / width * 100)
        s_width = int(width * scale_percent / 100)
        s_height = int(height * scale_percent / 100)
        # 新的寬度和高度
        dim = (s_width, s_height)
        return cv2.resize(ori_img, dim, interpolation=cv2.INTER_AREA)
    else:
        return ori_img


def adjust_rotae_angle(img):
    angle = 0
    # 對圖片進行壓縮
    img = resize_img(img)
    # symbol為64代表二維條碼
    qr_result = pyzbar.decode(img, symbols=[64])
    if len(qr_result) == 1:
        # 識別到了一個二維條碼,將二維條碼朝上旋轉
        first_adjust_angle = to_up_angle(qr_result[0])
        # 進行旋轉
        img_rotae_to_up = imutils.rotate_bound(img, first_adjust_angle)
        # 再次識別
        qr_result2 = pyzbar.decode(img_rotae_to_up, symbols=[64])
        if len(qr_result2) == 1:
            last_adjust_angle = -get_angle(qr_result2[0])
            angle = first_adjust_angle + last_adjust_angle
            print("first angle:%d last angle:%d angle:%d" % (first_adjust_angle, last_adjust_angle, angle))
        else:
            print('last 未識別到二維條碼')
    else:
        print('first 未識別到二維條碼')
    return angle


if __name__ == '__main__':
    # 載入圖片
    img = cv2.imread('123.jpg')
    adjust_angle = adjust_rotae_angle(img.copy())
    if adjust_angle != 0:
        img_rotae = imutils.rotate_bound(img, adjust_angle)
        cv2.imwrite('img_rotae.jpg', img_rotae)

最終輸出的圖片結果:

矯正成功!

需要說明的是,上面之所以要進行對圖片的resize,是因為圖片太大的話pyzbar可能會識別不出來二維條碼

到此這篇關於Python OpenCV實現任意角度二維條碼矯正的文章就介紹到這了,更多相關Python OpenCV二維條碼矯正內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com