Python?OpenCV實(shí)現(xiàn)任意角度二維碼矯正
前言
那天聽(tīng)到領(lǐng)導(dǎo)他們?cè)谟懻?,說(shuō)要將圖片進(jìn)行個(gè)矯正處理,還叫來(lái)了算法部的大佬來(lái)討論將要如何處理這個(gè),討論場(chǎng)面很是激烈
不得不說(shuō)好奇心是個(gè)很神奇的東西,就把我給吸引過(guò)去了
我定眼一看,感覺(jué)作為JAVA開(kāi)發(fā)的我自己也能進(jìn)行處理
因?yàn)榭吹搅藞D片后,發(fā)現(xiàn)了圖片中一個(gè)很重要的特征點(diǎn):
要進(jìn)行矯正的圖片中都會(huì)有一個(gè)二維碼圖案,想要矯正的文字和二維碼圖案是處于同一水平線(xiàn)的。
如下面這個(gè)

要把圖片中的“水中加點(diǎn)糖”四個(gè)字矯正,只需要把二維碼矯正就可以了。
具體想法就是,求得二維碼矯正的角度a,對(duì)原圖整體按照角度a進(jìn)行旋轉(zhuǎn)就可以了。
有了想法后,就趁熱打鐵,正好周末了在家試試。
一般圖片矯正方式
對(duì)于一般的圖片矯正,最常見(jiàn)的做法有這么兩種:
對(duì)圖片進(jìn)行預(yù)處理獲取出輪廓,并求得輪廓的近似矩形,通過(guò)矩形的定位點(diǎn)來(lái)進(jìn)行透視變換
對(duì)圖片進(jìn)行預(yù)處理后,進(jìn)行霍夫變換進(jìn)行直線(xiàn)檢測(cè),再根據(jù)直線(xiàn)的傾斜角進(jìn)行旋轉(zhuǎn)
但是對(duì)于圖片中有二維碼的圖片進(jìn)行矯正就可以更加簡(jiǎn)單了,因?yàn)槎S碼中有定位點(diǎn)并且成熟框架很多,實(shí)現(xiàn)起來(lái)也更加方便且識(shí)別率非常高。
二維碼圖片矯正
思路
識(shí)別出二維碼的角點(diǎn),通過(guò)相鄰兩個(gè)角點(diǎn)的坐標(biāo)計(jì)算出夾角度數(shù),再次用此度數(shù)對(duì)圖片進(jìn)行旋轉(zhuǎn)。
以下面圖為例:

先獲取出二維碼正方向時(shí)底部的兩點(diǎn)坐標(biāo),并求得兩點(diǎn)的傾斜角。
斜率計(jì)算用初中數(shù)學(xué)中求兩點(diǎn)坐標(biāo)斜率的公式算一下即可,忘了就搜搜回憶一下:
兩點(diǎn)的斜率公式:k=(y1-y2)/(x1-x2),x1≠x2。其中(x1,y1),(x2,y2)是已知兩點(diǎn)的坐標(biāo),x1≠x2。
斜率是表示一條直線(xiàn)(或曲線(xiàn)的切線(xiàn))關(guān)于(橫)坐標(biāo)軸傾斜程度的量。它通常用直線(xiàn)(或曲線(xiàn)的切線(xiàn))與(橫)坐標(biāo)軸夾角的正切,或兩點(diǎn)的縱坐標(biāo)之差與橫坐標(biāo)之差的比來(lái)表示。記作k,k=tgα。
一條直線(xiàn)與某平面直角坐標(biāo)系橫坐標(biāo)軸正半軸方向所成的角的正切值即該直線(xiàn)相對(duì)于該坐標(biāo)系的斜率。如果直線(xiàn)與x軸互相垂直,直角的正切值為tan90°,故此直線(xiàn)不存在斜率(也可以說(shuō)直線(xiàn)的斜率為無(wú)窮大)。當(dāng)直線(xiàn)L的斜率存在時(shí),對(duì)于一次函數(shù)y=kx+b(斜截式),k即該函數(shù)圖像的斜率。
編碼實(shí)現(xiàn)
實(shí)現(xiàn)時(shí)對(duì)于二維碼的識(shí)別用到了pyzbar庫(kù),對(duì)圖片處理用的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):
""" 已知兩點(diǎn)坐標(biāo)計(jì)算角度 -
:param x1: 原點(diǎn)橫坐標(biāo)值
:param y1: 原點(diǎn)縱坐標(biāo)值
:param x2: 目標(biāo)點(diǎn)橫坐標(biāo)值
:param y2: 目標(biāo)縱坐標(biāo)值
"""
dx = x2 - x1
dy = y2 - y1
# 求斜率
k = dy / dx
# 結(jié)果是弧度值
angle = math.atan(k)
# 弧度值轉(zhuǎn)為角度
return angle * 180 / math.pi
def get_angle(qr_item):
"""
獲取出進(jìn)行矯正所需要的角度
"""
# 將坐標(biāo)從下到上,從左到右進(jìn)行排序
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]
# 執(zhí)行壓縮,按照500的寬度為標(biāo)準(zhǔn)
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
# 對(duì)圖片進(jìn)行壓縮
img = resize_img(img)
# symbol為64代表二維碼
qr_result = pyzbar.decode(img, symbols=[64])
if len(qr_result) == 1:
# 識(shí)別到了一個(gè)二維碼,將二維碼朝上旋轉(zhuǎn)
first_adjust_angle = to_up_angle(qr_result[0])
# 進(jìn)行旋轉(zhuǎn)
img_rotae_to_up = imutils.rotate_bound(img, first_adjust_angle)
# 再次識(shí)別
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 未識(shí)別到二維碼')
else:
print('first 未識(shí)別到二維碼')
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)
最終輸出的圖片結(jié)果:

矯正成功!
需要說(shuō)明的是,上面之所以要進(jìn)行對(duì)圖片的resize,是因?yàn)閳D片太大的話(huà)pyzbar可能會(huì)識(shí)別不出來(lái)二維碼
到此這篇關(guān)于Python OpenCV實(shí)現(xiàn)任意角度二維碼矯正的文章就介紹到這了,更多相關(guān)Python OpenCV二維碼矯正內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python 中pandas索引切片讀取數(shù)據(jù)缺失數(shù)據(jù)處理問(wèn)題
pandas是一個(gè)Python軟件包,提供快速,靈活和富于表現(xiàn)力的數(shù)據(jù)結(jié)構(gòu),旨在使使用“關(guān)系”或“標(biāo)記”數(shù)據(jù)既簡(jiǎn)單又直觀。這篇文章主要介紹了pandas索引切片讀取數(shù)據(jù)缺失數(shù)據(jù)處理,需要的朋友可以參考下2019-10-10
python圖片指定區(qū)域替換img.paste函數(shù)的使用
這篇文章主要介紹了python圖片指定區(qū)域替換img.paste函數(shù)的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04
Python編程functools模塊創(chuàng)建修改的高階函數(shù)解析
本篇文章主要為大家介紹functools模塊中用于創(chuàng)建、修改函數(shù)的高階函數(shù),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2021-09-09
python rolling regression. 使用 Python 實(shí)現(xiàn)滾動(dòng)回歸操作
這篇文章主要介紹了python rolling regression. 使用 Python 實(shí)現(xiàn)滾動(dòng)回歸操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-06-06
Python趣味挑戰(zhàn)之給幼兒園弟弟生成1000道算術(shù)題
為了讓弟弟以后好好學(xué)習(xí),我特地用Python給他生成了1000道算術(shù)題讓他做,他以后一定會(huì)感謝我的!文中有非常詳細(xì)的代碼示例,需要的朋友可以參考下2021-05-05
淺談python裝飾器探究與參數(shù)的領(lǐng)取
下面小編就為大家分享一篇淺談python裝飾器探究與參數(shù)的領(lǐng)取,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2017-12-12
Pytorch 實(shí)現(xiàn)凍結(jié)指定卷積層的參數(shù)
今天小編就為大家分享一篇Pytorch 實(shí)現(xiàn)凍結(jié)指定卷積層的參數(shù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-01-01
Python生成任意范圍任意精度的隨機(jī)數(shù)方法
下面小編就為大家分享一篇Python生成任意范圍任意精度的隨機(jī)數(shù)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-04-04

