通过zbar和Raspicam模块扫描QR码

时间:2014-05-08 09:59:32

标签: python raspberry-pi qr-code zbar

我想使用我的raspi cam模块来扫描QR码。 为了检测和解码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以检查图片中是否包含qr代码。 我无法运行此代码,结果是错误:

  

分段错误

     

------------------(程序退出代码:139)按返回继续

我找不到任何解决方法如何修复这个错误,任何想法?

亲切的问候;

7 个答案:

答案 0 :(得分:4)

所有其他答案的不足之处在于它们有大量的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()

答案 1 :(得分:1)

在第

scanner.scan(图像)

您正在使用之前未出现在代码中的变量。因为zbar是用C语言编写的,所以它不会捕获变量是未定义的,并且库会尝试读取垃圾数据,就像它是图像一样。因此,段错误。我猜你的意思是my_stream而不是图像。

答案 2 :(得分:0)

我在我的项目中使用覆盆子上的QR解码。我用它来解决它 子程序模块。 这是我的QR解码功能:

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"

"raspistill -n -t 1 -w %d -h %d -o cam.png" % (img_width, img_height)

如果你想要不同尺寸的图像进行解码。

答案 3 :(得分:0)

阅读this后,我能够提出一个涉及OpenCV的pythonic解决方案。

首先,按照these instructions在Pi上构建OpenCV。这可能需要几个小时才能完成。

现在重启Pi并使用以下脚本(假设你安装了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键时停止

答案 4 :(得分:0)

对于仍在寻找解决方案的人来说...... 这段代码很难看,但它很适合普通网络摄像头,还没有试过Pi相机。我是python的新手,所以这是我能想出的最好的Python2和3。

创建一个名为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()

希望这有助于人们在将来遇到同样的问题!

答案 5 :(得分:0)

相当迟到的回应,但在尝试让Zbar工作时遇到了一些问题。虽然我使用的是USB网络摄像头,但在安装zbar之前我必须安装多个库。我安装了fswebcam,python-zbar,libzbar-dev,最后运行了setup.py。

更重要的是,来自sourceforge的zbar对我来说不起作用,但是来自github的那个,它有一个Python包装器为我工作。

如果可能有帮助,我会在http://techblog.saurabhkumar.com/2015/09/scanning-barcodes-using-raspberry-pi.html按步骤记录我的步骤

答案 6 :(得分:0)

只是从Dan2theR修改了一小部分,因为我不想创建另一个shell文件。

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()