Scanning QR Code via zbar and Raspicam module

26,590

Solution 1

The shortage of all the other answers is that they have a large amount of DELAY - for example, what they are scanning and displaying to the screen was actually a frame taken several seconds ago and so on.

This is due to the slow CPU of Raspberry Pi. So the frame-rate is much bigger than the rate our software can read and scan.

With lots of effort, I finally made this code, which have LITTLE DELAY. So when you give it a QRCode/BarCode, it will give you a result in less than a second.

The trick I use is explained in the code.

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

Solution 2

In the line

scanner.scan(image)

you're using a variable that hasn't appeared in the code before. Because zbar is written in C, it doesn't catch that the variable is undefined, and the library tries to read garbage data as if it were an image. Hence, the segfault. I'm guessing you meant my_stream instead of image.

Share:
26,590
user3551782
Author by

user3551782

Updated on November 10, 2020

Comments

  • user3551782
    user3551782 over 3 years

    I want to use my raspi cam modul to scan QR codes. For detecting and decoding qr codes I want to use zbar. My current code:

    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
    

    As you may see, I want to create a picture stream, send this stream to zbar to check if a qr code is contained in the picture. I am not able to run this code, this error is the result:

    Segmentation fault

    ------------------ (program exited with code: 139) Press return to continue

    I don't find any solution how to fixx this bug, any idea?

    Kind regards;