商品條形碼是二維碼嗎?
實際上條形碼包括【一維條形碼】和【二維條形碼】。
我們常說的條形碼就是【一維條形碼】,而我們說的二維碼則是【二維條形碼】。我們最常見的二維碼是QR Code,全稱是 Quick Response
我們仔細觀察下面的二維碼可以發現,二維碼實際上是由一系列黑白(或彩色的)方塊表示,就像計算機只認識“0”和“1”一樣。也正是這些方塊的不同組合,表示了各種含義的數據信息
對比來講【二維碼】相比傳統的【一維碼】存儲數據的效率更高,糾錯能力也更強,所以目前二維碼的應用也更加廣泛。
現在你是不是對二維碼多了一些了解?那接下來,我們來快速生成一個二維碼吧!
二維碼的生成
在Python中生成一個二維碼非常簡單,我們只需要安裝幾個模塊,就可以用幾行代碼生成一個二維碼。
首先,我們需要安裝qrcode模塊,用pip安裝的語句如下:
pip install qrcode
緊接着,因為qrcode模塊本身使用到了PIL模塊,所以我們還需要安裝PIL模塊。
在Python3中的安裝語句如下:
pip install pillow
安裝完成后,我們就可以開始寫代碼了。想要生成二維碼,我們只需要幾句代碼:
# 導入模塊 import qrcode # 填入數據,並創建二維碼圖片 qr_im = qrcode.make(data='你好啊') # 顯示二維碼圖片 qr_im.show()
上面代碼關鍵的操作是--make函數的使用。最簡單的使用就是傳入一個data參數,也就是二維碼中包含的數據信息。make函數會返回一個圖片對象,有了這個圖片,我們就可以調用show方法顯示它了。
除了顯示,我們還可以調用save方法將圖片保存到本地,代碼如下:
qr_im.save('qrcode.png')
調用save方法后,我們就可以在當前目錄找到qrcode.png圖片了。
我們發現外面的白色邊框比較粗,而且每個小正方形也比較大。
那有什么方法自己設置嗎?哈哈,想知道的話就繼續往下學習吧!
make函數解析
在上一關我們學習了調用make函數需要傳入一個data參數,而且make函數會返回一個圖片對象,那你有想過make函數里面做了些什么操作嗎?
我們先來看看make函數里面的代碼:
def make(data=None, **kwargs): qr = QRCode(**kwargs) qr.add_data(data) return qr.make_image()
為了方便看,我把代碼改成下面幾句
# 創建二維碼對象 qr = QRCode() # 在二維碼中添加數據 qr.add_data(data) # 創建二維碼圖片 qr_im = qr.make_image()
由此可以看出,make函數做了三件事:
-
創建二維碼對象;
-
在二維碼中添加數據;
-
創建二維碼圖片,並返回。
因此,我們還可以通過創建QRCode對象的方式來創建二維碼。
我們只需要實現上面三個操作即可,具體代碼如下:
from qrcode import QRCode # 創建QRCode對象 qr = QRCode() # 在二維碼中添加數據 qr.add_data('https://www.baidu.com/') # 創建二維碼圖片 qr_im = qr.make_image() # 保存二維碼圖片 qr_im.save('qrcode.png')
上面代碼都非常好理解。在添加數據時,調用了add_data方法,這次傳入的是一個網址。
之前我們掃碼會以【文本】的方式顯示添加的數據,這次直接進入了百度的網站。
因此我們可以知道,當我們添加的數據是一個網址時,掃碼會直接進入網站。
精確生成一個二維碼
了解了make函數具體做的事情后,我們就可以來看看怎樣精確地生成一個二維碼了。
在創建QRCode對象時,我們可以傳入幾個參數:
import qrcode qr = qrcode.QRCode( version=1, box_size=5, error_correction=qrcode.ERROR_CORRECT_H, border=1 )
我們來看看這四個參數的含義:
前面兩個參數都非常好理解,我們具體看看后兩個參數。
首先,你可能就會問,糾錯能力是什么?
請思考:在你掃碼時,是不是有些損壞了的二維碼有時候也能掃出內容?但是,有些二維碼破損了一點,就掃不出內容,而有的二維碼破損了很多都還能掃出內容。
這種差異就是【糾錯能力】不同而導致的。所以,【糾錯能力】其實就是容許二維碼損壞(錯誤)的百分比。
在qrcode中定義了四個常量,分別如下:
-
ERROR_CORRECT_L:糾正不超過7%的錯誤
-
ERROR_CORRECT_M(默認):糾正不超過15%的錯誤
-
ERROR_CORRECT_Q:糾正不超過25%的錯誤
-
ERROR_CORRECT_H:就在不超過30%的錯誤
說了這么多,現在應該知道【糾錯能力】是什么了吧!
接下來,我們來看看border參數,也就是白色邊框的大小。
在前面我們設置了一個box_size參數,表示最小正方形的邊長,而border表示的是有幾個白色小正方形。所以實際白色邊框的寬度是border*box_size個像素。
知道這些后,下面這段代碼你理解起來應該沒有問題吧:
import qrcode qr = qrcode.QRCode( version=1, box_size=5, error_correction=qrcode.ERROR_CORRECT_H, border=1 ) qr.add_data('https://www.boxuegu.com/') qr_im = qr.make_image() qr_im.save('qrcode.png')
有時候,我們還可以不設置version參數,這個時候可以調用一個make方法,讓它自動設置大小:
import qrcode qr = qrcode.QRCode( box_size=5, error_correction=qrcode.ERROR_CORRECT_H, border=1 ) # 設置為自動設置大小 qr.make(fit=True) qr.add_data('https://www.boxuegu.com/') qr_im = qr.make_image() qr_im.save('im.png')
去掉version參數后,我們調用了make方法,並把fit參數設置為True,這樣程序會自動給我們設置合適的大小,完工~
生成二維碼的操作我們就學習到這里,接下來,我們再來看看要怎么解析二維碼!
二維碼的解析
讀取圖片
要解析二維碼我們還需要用到另外兩個模塊,它們分別是opencv和pyzbar模塊。
opencv模塊是用來讀取圖片的,而pyzbar則是解析二維碼的關鍵,安裝opencv的語句如下:
pip install opencv-python
安裝pyzbar的語句如下:
pip install pyzbar
在解析二維碼之前,我們先看看讀取圖片操作。
在安裝好opencv模塊后,我們就可以開始讀取圖片了,代碼如下:
# 導入模塊 import cv2 # 讀取二維碼圖片 qrcode = cv2.imread('qrcode.png')
雖然模塊叫opencv,但是導入的時候我們是導入cv2。
在導入模塊后,我們就可以調用cv2模塊的imread函數讀取圖片,執行后會返回一個特殊的圖片對象,我們把這個對象交給pyzbar模塊處理就能拿到二維碼的數據了。
解析二維碼的操作也非常簡單,具體代碼如下:
import cv2 from pyzbar import pyzbar # 讀取二維碼圖片 qrcode = cv2.imread('qrcode.png') # 解析二維碼中的數據 data = pyzbar.decode(qrcode) # 解析二維碼中的主要數據 text = data[0].data.decode('utf-8') # 輸出內容 print(text)
前面讀取圖片的操作我們已經講過,那我們來看看解析二維碼的操作。
在解析二維碼時,我們解析了兩次,第一次調用pyzbar.decode函數,傳入我們的二維碼圖片。
這時候解析的結果是一個列表,我們瞄一眼它長什么樣子:
[Decoded(data=b'https://www.boxuegu.com/', type='QRCODE', rect=Rect(left=51, top=51, width=368, height=368), polygon=[Point(x=51, y=51), Point(x=51, y=418), Point(x=419, y=419), Point(x=418, y=51)])]
雖然不知道是些什么東西,但可以看出來有很多。
但仔細一看,列表第一個數據不就是二維碼的數據嗎?哈哈,機靈的你看出了端倪。這也就是我們要進行第二次解析的原因。
最后輸出結果如下:
https://www.boxuegu.com/
即我們在創建二維碼時,通過add_data方法添加的數據。
現在解析二維碼你也學會了,是不是能寫個掃碼小工具了啊?
先別急,我們還不知道怎么調用攝像頭呢!所以我們再來學習一下怎么調用攝像頭吧!
調用攝像頭
前面我們用到的opencv模塊,不僅可以讀取圖片,還可以調用攝像頭,所以,我們不需要再額外安裝模塊了。
調用攝像頭的代碼如下:
import cv2 # 調用攝像頭 cap = cv2.VideoCapture(0) # 釋放攝像頭 cap.release()
代碼中我們調用了cv2.VideoCapture函數,這個函數是用來讀取視頻的。不過當我們傳入0時,它會直接調用我們的攝像頭。在使用完攝像頭后,我們調用release方法釋放攝像頭。
不過上面的代碼我們什么都沒做,只是調用攝像頭后立馬釋放了。
那要怎么才能【一直調用】攝像頭呢?咱繼續往下學習~
逐幀讀取畫面
在上面獲取的cap對象中,有一個read方法可以讀取到攝像頭拍攝到的內容。
代碼如下:
import cv2 cap = cv2.VideoCapture(0) # 讀取一幀畫面 ret, frame = cap.read() cap.release()
read方法會返回兩個參數,第一個表示是否有下一幀,第二個則是當前幀的圖片對象。
如果想要一直讀取攝像頭拍攝的圖像,我們就需要循環讀取,直到read方法返回的ret參數為False,完成上述操作的代碼如下:
import cv2 cap = cv2.VideoCapture(0) ret, frame = cap.read() # 循環讀取攝像頭內容,直到沒有下一幀 while ret: # 顯示當前幀的圖像 cv2.imshow('frame', frame) # 等待10毫秒 cv2.waitKey(10) # 繼續讀取下一幀圖像 ret, frame = cap.read() # 銷毀窗口 cv2.destroyAllWindows() cap.release()
循環讀取攝像頭內容:這里用ret作為循環條件,表示沒有下一幀時結束。但是因為攝像頭是一直在拍攝畫面,所以這里不會結束。
顯示當前幀的圖像:我們可以調用cv2.imshow函數顯示圖像,該函數接收兩個參數,分別是窗口名稱和畫面。但是這個函數只會顯示一瞬間畫面,因此我們還要結合cv2.waitKey函數,等待10毫秒。
繼續讀取下一幀圖像:read方法每次只會讀取一幀畫面,所以我們需要在循環中一直調用read方法。
銷毀窗口:在opencv中我們只要調用了cv2.imshow函數,就需要在最后調用cv2.destroyAllWindows函數,保證窗口真正銷毀。
掃碼工具的實現
掃碼工具的實現非常簡單,要想實現掃碼功能我們需要有解析二維碼的能力,以及調用攝像頭的能力。
而這兩種操作我們在前幾關我們都講解過了~
那具體流程又是怎樣的呢?請看:
第一步,我們要把解析二維碼的功能封裝成一個函數,方便后面使用。
第二步,我們需要逐幀讀取攝像頭的畫面,對每一幀畫面進行解析。
第三步,我們要判斷是否解析到了內容。如果解析到了,就停止循環,如果沒解析到就繼續循環。
好,理解了上面的流程,我們就可以開始寫代碼了。
首先,我們把解析二維碼的操作編寫成一個函數,代碼如下
def decode_qr(im): data = pyzbar.decode(im) # 解析的結果默認為None text = None # 如果檢測到二維碼再解析主要數據 if data: text = data[0].data.decode('utf-8') return text
上面的代碼相對於第三關中的代碼做了一些修改,你有注意到么?
首先,把text設置為None,表示主要數據默認為None。
然后對第一次的解析結果data做判斷,如果有數據才解析主要數據。
這樣上面函數的功能就成了:傳入圖片,如果有二維碼返回二維碼的數據,如果沒有返回None。
然后就是逐幀讀取畫面了:
def scanner(): cap = cv2.VideoCapture(0) ret, frame = cap.read() while ret: # 對當前幀畫面進行解析 result = decode_qr(frame) # 如果解析到了結果就輸出,沒解析到就繼續 if result: print(result) break cv2.imshow('decode qrcode', frame) cv2.waitKey(10) ret, frame = cap.read() cap.release() cv2.destroyAllWindows()
上面的代碼也在第四關代碼基礎上進行了一些小的修改,我們來看一下。
在進入循環后,我們對當前讀取到的畫面進行解析。
如果解析到了內容,程序就會輸出結果,然后跳出循環,這樣就完成了我們的掃碼工作。
掃碼工具完整的代碼如下:
import cv2 from pyzbar import pyzbar def decode_qr(im): data = pyzbar.decode(im) text = None if data: text = data[0].data.decode('utf-8') return text def scanner(): cap = cv2.VideoCapture(0) ret, frame = cap.read() while ret: result = decode_qr(frame) if result: print(result) break cv2.imshow('decode qrcode', frame) cv2.waitKey(10) ret, frame = cap.read() cap.release() cv2.destroyAllWindows() scanner()
因為第二步的操作也編寫成了函數,所以需要在下面調用才會執行。怎么樣,是不是挺簡單的?你也趕快動手實踐
一下吧~
因此你只需要記住那幾個函數即可。為了方便你記憶,老師給你整理了下面這張圖,請收好: