我想使用我的raspi cam模块来扫描QR码。为了检测和解码二维码,我想使用zbar。我当前的代码:
import io
import time
import picamera
import zbar
import Image
if len(argv) < 2: exit(1)
# Create an in-memory stream
my_stream = io.BytesIO()
with picamera.PiCamera() as camera:
camera.start_preview()
# Camera warm-up time
time.sleep(2)
camera.capture(my_stream, 'jpeg')
scanner = zbar.ImageScanner()
scanner.parse_config('enable')
pil = Image.open(argv[1]).convert('L')
width, height = pil.size
raw = pil.tostring()
my_stream = zbar.Image(width, height, 'Y800', raw)
scanner.scan(image)
for symbol in image:
print 'decoded', symbol.type, 'symbol', '"%s"' % symbol.data
您可能会看到,我想创建一个图片流,将该流发送到zbar,以检查图片中是否包含二维码。我无法运行此代码,导致此错误:
分段错误
----(程序退出,代码:139)按回车键继续
我没有找到解决此错误的解决方案,有什么主意吗?
亲切的问候;
所有其他答案的不足之处在于它们有大量的DELAY-例如,它们正在扫描并显示到屏幕上的实际上是几秒钟前拍摄的一帧,依此类推。
这是由于Raspberry Pi的CPU速度慢。因此,frame-rate
比我们的软件可以读取和扫描的速率大得多。
[尽力而为,我终于完成了这段代码,其中<< LITTLE DELAY。因此,当您给它一个QRCode / BarCode时,它将在不到一秒钟的时间内为您提供结果。
代码中说明了我使用的技巧。import cv2
import cv2.cv as cv
import numpy
import zbar
import time
import threading
'''
LITTLE-DELAY BarCodeScanner
Author: Chen Jingyi (From FZYZ Junior High School, China)
PS. If your pi's V4L is not available, the cv-Window may have some error sometimes, but other parts of this code works fine.
'''
class BarCodeScanner(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.WINDOW_NAME = 'Camera'
self.CV_SYSTEM_CACHE_CNT = 5 # Cv has 5-frame cache
self.LOOP_INTERVAL_TIME = 0.2
cv.NamedWindow(self.WINDOW_NAME, cv.CV_WINDOW_NORMAL)
self.cam = cv2.VideoCapture(-1)
def scan(self, aframe):
imgray = cv2.cvtColor(aframe, cv2.COLOR_BGR2GRAY)
raw = str(imgray.data)
scanner = zbar.ImageScanner()
scanner.parse_config('enable')
#print 'ScanZbar', time.time()
width = int(self.cam.get(cv.CV_CAP_PROP_FRAME_WIDTH))
height = int(self.cam.get(cv.CV_CAP_PROP_FRAME_HEIGHT))
imageZbar = zbar.Image(width, height,'Y800', raw)
scanner.scan(imageZbar)
#print 'ScanEnd', time.time()
for symbol in imageZbar:
print 'decoded', symbol.type, 'symbol', '"%s"' % symbol.data
def run(self):
#print 'BarCodeScanner run', time.time()
while True:
#print time.time()
''' Why reading several times and throw the data away: I guess OpenCV has a `cache-queue` whose length is 5.
`read()` will *dequeue* a frame from it if it is not null, otherwise wait until have one.
When the camera has a new frame, if the queue is not full, the frame will be *enqueue*, otherwise be thrown away.
So in this case, the frame rate is far bigger than the times the while loop is executed. So when the code comes to here, the queue is full.
Therefore, if we want the newest frame, we need to dequeue the 5 frames in the queue, which is useless because it is old. That's why.
'''
for i in range(0,self.CV_SYSTEM_CACHE_CNT):
#print 'Read2Throw', time.time()
self.cam.read()
#print 'Read2Use', time.time()
img = self.cam.read()
self.scan(img[1])
cv2.imshow(self.WINDOW_NAME, img[1])
cv.WaitKey(1)
#print 'Sleep', time.time()
time.sleep(self.LOOP_INTERVAL_TIME)
cam.release()
scanner = BarCodeScanner()
scanner.start()
scanner.scan(图像)
您使用的变量以前没有出现在代码中。因为zbar是用C编写的,所以它无法捕获未定义的变量,并且库试图像读取图像一样读取垃圾数据。因此,段错误。我猜你是说my_stream而不是图像。
import subprocess
def detect():
"""Detects qr code from camera and returns string that represents that code.
return -- qr code from image as string
"""
subprocess.call(["raspistill -n -t 1 -w 120 -h 120 -o cam.png"],shell=True)
process = subprocess.Popen(["zbarimg -D cam.png"], stdout=subprocess.PIPE, shell=True)
(out, err) = process.communicate()
qr_code = None
# out looks like "QR-code: Xuz213asdY" so you need
# to remove first 8 characters plus whitespaces
if len(out) > 8:
qr_code = out[8:].strip()
return qr_code
您可以轻松地向img_widt和img_height之类的函数添加参数并更改这部分代码
"raspistill -n -t 1 -w 120 -h 120 -o cam.png"
to
"raspistill -n -t 1 -w %d -h %d -o cam.png" % (img_width, img_height)
如果您想要不同尺寸的图像进行解码。
首先,按照these instructions在Pi上构建OpenCV。这可能需要几个小时才能完成。
现在重启树莓派并使用以下脚本(假设您已安装python-zbar)来获取QR /条形码数据:
import cv2
import cv2.cv as cv
import numpy
import zbar
class test():
def __init__(self):
cv.NamedWindow("w1", cv.CV_WINDOW_NORMAL)
# self.capture = cv.CaptureFromCAM(camera_index) #for some reason, this doesn't work
self.capture = cv.CreateCameraCapture(-1)
self.vid_contour_selection()
def vid_contour_selection(self):
while True:
self.frame = cv.QueryFrame(self.capture)
aframe = numpy.asarray(self.frame[:,:])
g = cv.fromarray(aframe)
g = numpy.asarray(g)
imgray = cv2.cvtColor(g,cv2.COLOR_BGR2GRAY)
raw = str(imgray.data)
scanner = zbar.ImageScanner()
scanner.parse_config('enable')
imageZbar = zbar.Image( self.frame.width, self.frame.height,'Y800', raw)
scanner.scan(imageZbar)
for symbol in imageZbar:
print 'decoded', symbol.type, 'symbol', '"%s"' % symbol.data
cv2.imshow("w1", aframe)
c = cv.WaitKey(5)
if c == 110: #pressing the 'n' key will cause the program to exit
exit()
#
p = test()
注意:在zbar能够检测到QR /条形码之前,我必须逆时针旋转Raspi相机的镜头大约1/4-1/3。使用以上代码,每当zbar检测到QR /条形码时,解码的数据都会打印在控制台中。它连续运行,仅在按下
n
键时停止运行
制作一个名为kill.sh的bash脚本,使其可执行...(chmod -x)
#kill all running zbar tasks ... call from python
ps -face | grep zbar | awk '{print $2}' | xargs kill -s KILL
然后像这样从python进行系统调用...
import sys import os def start_cam(): while True: #Initializes an instance of Zbar to the commandline to detect barcode data-strings. p=os.popen('/usr/bin/zbarcam --prescale=300x200','r') #Barcode variable read by Python from the commandline. print("Please Scan a QRcode to begin...") barcode = p.readline() barcodedata = str(barcode)[8:] if barcodedata: print("{0}".format(barcodedata)) #Kills the webcam window by executing the bash file os.system("/home/pi/Desktop/kill.sh") start_cam()
希望这对以后有相同问题的人有所帮助!
更重要的是,sourceforge的zbar不适用于我,但是github的zbar具有Python包装器。
如果有帮助,我在http://techblog.saurabhkumar.com/2015/09/scanning-barcodes-using-raspberry-pi.html处逐步记录了我的步骤
import sys
import os
p = os.popen('/usr/bin/zbarcam --prescale=300x300 --Sdisable -Sqrcode.enable', 'r')
def start_scan():
global p
while True:
print('Scanning')
data = p.readline()
qrcode = str(data)[8:]
if(qrcode):
print(qrcode)
try:
start_scan()
except KeyboardInterrupt:
print('Stop scanning')
finally:
p.close()