Python+OpenCV實(shí)現(xiàn)定位二維碼
相較于BarCode,QRCode有明顯的特征區(qū)域,也就是左上角、右上角、左下角三個(gè)”回“字區(qū)域,得益于hierarchy中,父子關(guān)系的輪廓是連續(xù)的(下標(biāo)),所以這個(gè)時(shí)候我們就可以通過(guò)cv2.findContours()返回的hierarchy來(lái)進(jìn)行定位。
我們直接上代碼
import cv2
import numpy
def qrcode(image):
# 有些二維碼和邊緣緊貼,無(wú)法識(shí)別出整個(gè)矩形,所以我們先對(duì)圖片大小進(jìn)行擴(kuò)展
expand_length = 10
edge = expand_length // 2
h, w = image.shape[:2]
image_extend = numpy.zeros((image.shape[0] + expand_length, image.shape[1] + expand_length, 3), numpy.uint8)
image_extend[:] = 255
image_extend[edge:edge + h, edge:edge + w] = image
# 轉(zhuǎn)灰度、二值化、找輪廓
gray = cv2.cvtColor(image_extend, cv2.COLOR_BGR2GRAY)
# blur = cv2.GaussianBlur(gray, (5, 5), 0)
_, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
contours, hir = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
'''
2.4282182798755647
2.3203121154092337
2.3487607213520345
2.318010267306266
'''
# 三個(gè)“回”字特征輪廓存儲(chǔ)
parent_hierarchy_list = []
parent_contours_list = []
# 通過(guò)層級(jí)信息去查找三個(gè)“回”字特征區(qū)域
for index, item in enumerate(hir[0][:-2]): # 查找最外層(A)輪廓
if item[2] != -1:
parent_index = item[2] - 1
if hir[0][index+1][3] == parent_index: # 查找次一層(B)輪廓
child_first = hir[0][index+1][2] - 1
if hir[0][index+2][3] == child_first: # 查找最里層(C)輪廓
# 計(jì)算A輪廓的周長(zhǎng)和C輪廓周長(zhǎng)的比值
error = cv2.arcLength(contours[parent_index], True) / cv2.arcLength(contours[parent_index + 2], True)
if 2 < error < 3:
parent_hierarchy_list.append(item)
parent_contours_list.append(contours[index])
# 繪制出三個(gè)“回”字特征區(qū)域的最外層輪廓
cv2.drawContours(image_extend, contours, index, (0, 255, 0), 3)
# 將整個(gè)二維碼區(qū)域繪制出來(lái)
points_list = []
for index, box in enumerate(parent_contours_list):
x, y, w, h = cv2.boundingRect(box)
if index == 0:
points_list.append((x, y+h))
if index == 1:
points_list.append((x+w, y))
if index == 2:
points_list.append((x, y))
points_list = numpy.array(points_list)
rect = cv2.minAreaRect(points_list)
box = cv2.boxPoints(rect)
box = numpy.int0(box)
cv2.drawContours(image_extend, [box], 0, (255, 0, 0), 2)
cv2.imshow('', image_extend)
if __name__ == '__main__':
img = cv2.imread('../images/QRCode_3.png')
qrcode(img)
cv2.waitKey()
cv2.destroyAllWindows()通常我們所見(jiàn)的二維碼都是有留白邊緣區(qū)域的,但是在隨便找一些二維碼圖的過(guò)程中,有一些是沒(méi)有留白邊緣區(qū)域的:

上圖是在IDE中打開(kāi)的,原圖是沒(méi)有灰色邊緣的,這個(gè)時(shí)候我們?nèi)绻苯幼x取這張圖片,得到的輪廓信息并不是我們期待的三個(gè)連續(xù)的父子關(guān)系的hierarchy,為了避免這種情況,這里就手動(dòng)向外擴(kuò)展十個(gè)像素,人為制造一個(gè)間隔。
通常來(lái)說(shuō),我們通過(guò)三層for循環(huán)來(lái)定位特征區(qū)域已經(jīng)是足夠的,但是如果二維碼的其他區(qū)域也出現(xiàn)了三層輪廓,那么我們就需要進(jìn)行篩選,所以代碼通過(guò)計(jì)算最外層輪廓的長(zhǎng)度和最內(nèi)存輪廓長(zhǎng)度的比值來(lái)進(jìn)行篩選,每一個(gè)“回”的黑白框框的比例大概為1:1:3:1:1,也就是說(shuō)他們的邊長(zhǎng)比為7:3,而這個(gè)比值在標(biāo)準(zhǔn)二維碼中,只有三個(gè)特征區(qū)域才符合。
代碼的21到24行中的數(shù)值,便是嘗試過(guò)了四個(gè)不同的二維碼得出的比值,都接近7:3。

最后我們繪制出四個(gè)邊框,完成二維碼的定位:

到此這篇關(guān)于Python+OpenCV實(shí)現(xiàn)定位二維碼的文章就介紹到這了,更多相關(guān)Python OpenCV定位二維碼內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python實(shí)現(xiàn)樹(shù)莓派WiFi斷線自動(dòng)重連的實(shí)例代碼
實(shí)現(xiàn) WiFi 斷線自動(dòng)重連,原理是用 Python 監(jiān)測(cè)網(wǎng)絡(luò)是否斷線,如果斷線則重啟網(wǎng)絡(luò)服務(wù)。接下來(lái)給大家分享實(shí)現(xiàn)代碼,需要的朋友參考下2017-03-03
Streamlit+Echarts實(shí)現(xiàn)繪制精美圖表
在數(shù)據(jù)分析和可視化的領(lǐng)域,選擇合適的工具可以讓我們事半功倍,本文主要為大家介紹兩個(gè)工具,Streamlit和ECharts,感興趣的小伙伴可以跟隨小編一起了解下2023-09-09
Python numpy 數(shù)組的向量化運(yùn)算操作方法
這篇文章主要介紹了Python numpy數(shù)組的向量化運(yùn)算操作方法,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-06-06
解決Tkinter中button按鈕未按卻主動(dòng)執(zhí)行command函數(shù)的問(wèn)題
這篇文章主要介紹了解決Tkinter中button按鈕未按卻主動(dòng)執(zhí)行command函數(shù)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-05-05
怎么處理Python分割字符串時(shí)有多個(gè)分隔符
在使用Python處理字符串的時(shí)候,有時(shí)候會(huì)需要分割字符。本文就介紹了Python分割字符串時(shí)有多個(gè)分隔符,感興趣的可以了解一下2021-07-07
Python collections.deque雙邊隊(duì)列原理詳解
這篇文章主要介紹了Python collections.deque雙邊隊(duì)列原理詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10

