2

Im stuck with implementing a Qr-Code Scanner I found here:

https://stackoverflow.com/questions/23538522/scanning-qr-code-via-zbar-and-raspicam-modul

I already managed to set up the Raspberry Pi camera in the Browser, like it was explained at this tutorial: https://blog.miguelgrinberg.com/post/video-streaming-with-flask

I'd like to read the Qr Code from the camera which is displayed in the Browser window, but unfortunately the Camera Window from the Qr-Code scanner script always pops up when I enter the route where the camera is supposed to appear. I haven't got much experience with threading and OpenCv etc. and tried various combinations with the camera.py script and scanner.py script. At this point I'm only importing scanner.py, which obviously can't work.

Does somebody know how to implement the scanner into the camera in my program? And what is the element from which to read / scan the Qr Code in the camera.py script?

routes.py:

from flask import Flask
from flask import render_template, Response
from camera import Camera


app = Flask(__name__)


@app.route("/scanner/")
def scanner():
    return render_template("scanner.html")

def gen(camera):
    """Video streaming generator function."""
    while True:
        frame = camera.get_frame()
        yield (b'--frame\r\n'
               b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')

@app.route('/video_feed')
def video_feed():
    """Video streaming route. Put this in the src attribute of an img tag."""
    return Response(gen(Camera()),
                    mimetype='multipart/x-mixed-replace; boundary=frame')

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", threaded=True)

camera.py:

import time
import io
import threading
import picamera
import cv2
import cv2.cv as cv
import numpy
import zbar
#import stackscanner



class Camera(object):
    thread = None  # background thread that reads frames from camera
    frame = None  # current frame is stored here by background thread
    last_access = 0  # time of last client access to the camera


    def initialize(self):

        if Camera.thread is None:
            # start background frame thread
            Camera.thread = threading.Thread(target=self._thread)
            Camera.thread.start()
        import stackscanner     
        # wait until frames start to be available
        while self.frame is None:
            time.sleep(0)

    def get_frame(self):
        Camera.last_access = time.time()
        self.initialize()
        return self.frame


    @classmethod
    def _thread(cls):
        with picamera.PiCamera() as camera:
            # camera setup
            camera.resolution = (320, 320)
            camera.hflip = True
            camera.vflip = False

            # let camera warm up
            #~ camera.start_preview()
            #~ time.sleep(2)

            stream = io.BytesIO()
            for foo in camera.capture_continuous(stream, 'jpeg',
                                                 use_video_port=True):
                # store frame
                stream.seek(0)
                cls.frame = stream.read()

                # reset stream for next frame
                stream.seek(0)
                stream.truncate()



                # if there hasn't been any clients asking for frames in
                # the last 10 seconds stop the thread
        #camera.close()
                if time.time() - cls.last_access > 10:
                    break

        cls.thread = None

scanner.py:

import cv2
import cv2.cv as cv
import numpy
import zbar
import time
import threading


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

I appreciate any help from you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.