1. 程式人生 > >用python寫的opencv實時監測和解析二維碼和條形碼最牛教程

用python寫的opencv實時監測和解析二維碼和條形碼最牛教程

今天,我實現了一個很有趣的demo,它可以在視訊裡找到並解析二維碼,然後把解析的內容實時在螢幕上顯示出來。

然後我們直入主題,首先你得確保你裝了opencv,python,zbar等環境。然後這個教程對於學過opencv的人可能更好理解,但是沒學過也無妨,到時候也可以直接用。

比如我的電腦上的環境是opencv2.4.x,python2.7,和最新的zbar,在Ubuntu 12.12的系統下執行的

假設你的opencv已經安裝好了,那麼我們就可以安裝zbar

你可以先更新一下

sudo apt-get update

然後在輸入

sudo apt-get install python-zbar

如果環境裝好了,我們就可以接著下一步操作了。

首先讓我們來實現找到在圖片裡面找到二維碼的功能

先新建一個python檔案叫做;simple_barcode_detection.py

程式碼如下,這定義了一個函式,實現從一副圖片裡面找出二維碼的位置

我們要檢測的二維碼的圖片


import numpy as np
import cv2


def detect(image):
# 把影象從RGB裝換成灰度圖
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)


# 使用Scharr操作(指定使用ksize = -1)構造灰度圖在水平和豎直方向上的梯度幅值表示。
gradX = cv2.Sobel(gray, ddepth = cv2.cv.CV_32F, dx = 1, dy = 0, ksize = -1)
gradY = cv2.Sobel(gray, ddepth = cv2.cv.CV_32F, dx = 0, dy = 1, ksize = -1)


#Scharr操作後,從x的梯度減去y的梯度
gradient = cv2.subtract(gradX, gradY)
gradient = cv2.convertScaleAbs(gradient)

#經過上面的操作後看起來是這樣


# 對上述的梯度圖採用用9x9的核進行平均模糊,這是有利於降噪的

#然後進行二值化處理,要麼是255(白)要麼是0(黑)

blurred = cv2.blur(gradient, (9, 9))
(_, thresh) = cv2.threshold(blurred, 225, 255, cv2.THRESH_BINARY)

#模糊與二值化處理後,看起來是這個樣子,

#上面的操作後發現有一些條形碼的豎槓之間存在一些縫隙,並使我們的演算法能檢測到斑點區域,我們進行一些基本的形態學操作
#我們首先使用cv2.getStructuringElement構造一個長方形核心。這個核心的寬度大於長度,因此我們可以消除條形碼中垂直條之間的縫隙。


這裡進行形態學操作,將上一步得到的核心應用到我們的二值圖中,以此來消除豎槓間的縫隙。
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (21, 7))
closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)

#上述操作後看起來是這個樣子


#我們發現還是存在一些小斑點,這時我們可以使用opencv裡面的腐蝕和膨脹來處理他們,來去除白色的斑點

closed = cv2.erode(closed, None, iterations = 4)
closed = cv2.dilate(closed, None, iterations = 4)

#這時候的效果看起來是這樣的


# 接下來我們來找輪廓
(cnts, _) = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)


#如果沒找到則返回為空
if len(cnts) == 0:
return None


#找到了就通過面積來排序,並計算旋轉角
# 給最大的輪廓找到邊框
c = sorted(cnts, key = cv2.contourArea, reverse = True)[0]
rect = cv2.minAreaRect(c)

#box(裡面是ndarry陣列,包含了4個頂點的位置)
box = np.int0(cv2.cv.BoxPoints(rect))


# 返回box
return box

最終結果


 好了,上面的解釋裡面有中文,可能python解釋的時候會通不過,我下面直接給出程式碼

import numpy as np
import cv2

def detect(image):
	# convert the image to grayscale
	gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

	# compute the Scharr gradient magnitude representation of the images
	# in both the x and y direction
	gradX = cv2.Sobel(gray, ddepth = cv2.cv.CV_32F, dx = 1, dy = 0, ksize = -1)
	gradY = cv2.Sobel(gray, ddepth = cv2.cv.CV_32F, dx = 0, dy = 1, ksize = -1)

	# subtract the y-gradient from the x-gradient
	gradient = cv2.subtract(gradX, gradY)
	gradient = cv2.convertScaleAbs(gradient)

	# blur and threshold the image
	blurred = cv2.blur(gradient, (9, 9))
	(_, thresh) = cv2.threshold(blurred, 225, 255, cv2.THRESH_BINARY)

	# construct a closing kernel and apply it to the thresholded image
	kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (21, 7))
	closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)

	# perform a series of erosions and dilations
	closed = cv2.erode(closed, None, iterations = 4)
	closed = cv2.dilate(closed, None, iterations = 4)

	# find the contours in the thresholded image
	(cnts, _) = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL,
		cv2.CHAIN_APPROX_SIMPLE)

	# if no contours were found, return None
	if len(cnts) == 0:
		return None

	# otherwise, sort the contours by area and compute the rotated
	# bounding box of the largest contour
	c = sorted(cnts, key = cv2.contourArea, reverse = True)[0]
	rect = cv2.minAreaRect(c)
	box = np.int0(cv2.cv.BoxPoints(rect))

	# return the bounding box of the barcode
	return box


完成了上述的工作,我們就完成了二維碼和條形碼的定位,接下去實現視訊裡面二維碼的解析

你可以新建一個python檔案,barcode_vid.py

解析二維碼我們需要用zbar這個模組和PIL,PIL在python裡面裝好了

我們先匯入模組

# import the necessary packages
import simple_barcode_detection
import cv2
import numpy as np
import zbar
from PIL import Image

#接下去是建立一個掃描器,他可以解析二維碼的內容

# create a reader
scanner = zbar.ImageScanner()
# configure the reader
scanner.parse_config('enable')

#設定螢幕顯示字型

font=cv2.FONT_HERSHEY_SIMPLEX

#啟用攝像頭

camera=cv2.VideoCapture(0)

#接下去是一個大的while迴圈

while True:

#得到當前的幀
# grab the current frame
(grabbed, frame) = camera.read()

#檢測視訊是否到底了,如果檢測視訊檔案裡面的二維碼或條形碼用這個,如果開啟攝像頭就無所謂了
# check to see if we have reached the end of the
# video
if not grabbed:
break

呼叫剛才我們建的那個函式來查詢二維碼返回二維碼的位置
# detect the barcode in the image
box = simple_barcode_detection.detect(frame)
if box != None:

#這下面的3步得到掃描區域,掃描區域要比檢測出來的位置要大
min=np.min(box,axis=0)
max=np.max(box,axis=0)

roi=frame[min[1]-10:max[1]+10,min[0]-10:max[0]+10]

#把區域裡的二維碼傳換成RGB,並把它轉換成pil裡面的影象,因為zbar得呼叫pil裡面的影象,而不能用opencv的影象
roi=cv2.cvtColor(roi,cv2.COLOR_BGR2RGB)
pil= Image.fromarray(frame).convert('L')
width, height = pil.size
raw = pil.tostring()


#把影象裝換成資料
zarimage = zbar.Image(width, height, 'Y800', raw)

#掃描器進行掃描
scanner.scan(zarimage)


#得到結果
for symbol in zarimage:
   # 對結果進行一些有用的處理
print 'decoded', symbol.type, 'symbol', '"%s"' %symbol.data
cv2.drawContours(frame, [box], -1, (0, 255, 0), 2)

#把解析的內容放到視訊上
cv2.putText(frame,symbol.data,(20,100),font,1,(0,255,0),4)




# show the frame and record if the user presses a key
cv2.imshow("Frame", frame)
key = cv2.waitKey(1) & 0xFF


# if the 'q' key is pressed, stop the loop
if key == ord("q"):
break

# cleanup the camera and close any open windows
camera.release()
cv2.destroyAllWindows()

CSDN不能上傳視訊,我下面傳一下圖片


下面還是上原始碼

# import the necessary packages
import simple_barcode_detection
import cv2
import numpy as np
import zbar
from PIL import Image


# create a reader
scanner = zbar.ImageScanner()
# configure the reader
scanner.parse_config('enable')
font=cv2.FONT_HERSHEY_SIMPLEX
camera=cv2.VideoCapture(0)
while True:
# grab the current frame
(grabbed, frame) = camera.read()


# check to see if we have reached the end of the
# video
if not grabbed:
break


# detect the barcode in the image
box = simple_barcode_detection.detect(frame)
if box != None:
min=np.min(box,axis=0)
max=np.max(box,axis=0)
roi=frame[min[1]-10:max[1]+10,min[0]-10:max[0]+10]
print roi.shape
roi=cv2.cvtColor(roi,cv2.COLOR_BGR2RGB)
pil= Image.fromarray(frame).convert('L')
width, height = pil.size
raw = pil.tostring()
# wrap image data
zarimage = zbar.Image(width, height, 'Y800', raw)
# scan the image for barcodes
scanner.scan(zarimage)
# extract results
for symbol in zarimage:
   # do something useful with results
print 'decoded', symbol.type, 'symbol', '"%s"' %symbol.data
cv2.drawContours(frame, [box], -1, (0, 255, 0), 2)
cv2.putText(frame,symbol.data,(20,100),font,1,(0,255,0),4)
# if a barcode was found, draw a bounding box on the frame



# show the frame and record if the user presses a key
cv2.imshow("Frame", frame)
key = cv2.waitKey(1) & 0xFF


# if the 'q' key is pressed, stop the loop
if key == ord("q"):
break


# cleanup the camera and close any open windows
camera.release()
cv2.destroyAllWindows()

我明明可以靠臉吃飯,偏偏要靠才華!
求點贊!