Python 通过zbar和Raspicam模块扫描二维码

Python 通过zbar和Raspicam模块扫描二维码,python,raspberry-pi,qr-code,zbar,Python,Raspberry Pi,Qr Code,Zbar,我想用我的raspi cam模块扫描二维码。 对于检测和解码二维码,我想使用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.sta

我想用我的raspi cam模块扫描二维码。 对于检测和解码二维码,我想使用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
导入io
导入时间
进口皮卡梅拉
进口zbar
导入图像
如果len(argv)<2:退出(1)
#创建内存中的流
my_stream=io.BytesIO()
使用picamera.picamera()作为摄影机:
camera.start_预览()
#摄像机预热时间
时间。睡眠(2)
camera.capture(我的视频流,'jpeg')
scanner=zbar.ImageScanner()
scanner.parse_config('enable'))
pil=Image.open(argv[1]).convert('L')
宽度、高度=桩号
raw=pil.tostring()
my_stream=zbar.Image(宽度、高度,'Y800',原始)
扫描器.扫描(图像)
对于图像中的符号:
打印'decoded',symbol.type','symbol','%s''%symbol.data
正如您可能看到的,我想创建一个图片流,将此流发送到zbar以检查图片中是否包含二维码。 我无法运行此代码,导致此错误:

分段故障

------------------(程序退出,代码:139)按return继续

我找不到任何解决方案如何修复这个bug,有什么想法吗


亲切问候

我在我的项目中使用了raspberry上的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"

如果需要不同大小的图像进行解码。

行中

扫描器.扫描(图像)

您使用的变量以前没有出现在代码中。因为zbar是用C编写的,所以它不会发现变量是未定义的,库会尝试读取垃圾数据,就像它是一个图像一样。因此,segfault。我猜你指的是我的流而不是图像。

阅读之后,我想出了一个涉及OpenCV的pythonic解决方案

首先,通过以下方法在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
键时才会停止。。。 这段代码很难看,但是它在普通网络摄像头上工作得很好,还没有试过Pi摄像头。我是Python2和pytho3的新手,所以这是我能想到的最好的方法

制作一个名为kill.sh的bash脚本并使其可执行。。。(chmod-x)

然后从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()

希望这能帮助将来有同样问题的人

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

更重要的是,sourceforge的zbar不适合我,但github的zbar适合我,它有一个Python包装器


我在《如果有帮助》一步一步地记录了我的答案。所有其他答案的不足之处在于它们有很大的延迟-例如,它们扫描并显示到屏幕上的实际上是几秒钟前拍摄的一帧,等等

这是由于Raspberry Pi的CPU速度较慢所致。因此,
帧速率
远大于我们的软件可以读取和扫描的速率

经过大量的努力,我终于完成了这段代码,它几乎没有延迟。所以,当你给它一个QRCode/条形码时,它会在不到一秒钟内给你一个结果

代码中解释了我使用的技巧

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

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