Skip to content
Advertisement

Quit Python QR Scanner when no code is detected but keep running while processing the code

I’m creating a python script that scans QR codes, and then processes the info in the code. The python-script will launch every few seconds via a timer in systemd on RBPI, but while scanning for a code – if no code has been detected in 5 seconds, the script should terminate. However, if a code is detected, the processing should keep running, and the script should only exit when the processing is done.

This is my code:

import cv2
import numpy as np
from pyzbar.pyzbar import decode
from multiprocessing import Process
import time

def decoder(image):
    gray_img = cv2.cvtColor(image,0)
    barcode = decode(gray_img)
    
    for obj in barcode:
        points = obj.polygon
        (x,y,w,h) = obj.rect
        pts = np.array(points, np.int32)
        pts = pts.reshape((-1, 1, 2))        
        barcodeData = obj.data.decode("utf-8")
        barcodeType = obj.type
        string = str(barcodeData)
        cv2.destroyAllWindows()
        # stop timeout on action_process and keep it running
        # processMyQRCode(barcodeData) Demo:
        i = 0
        while i < 10:
            print("processing code for " + str(i) + " seconds")
            i += 1
            time.sleep(1)
        
        print(string + " is processed")
        exit()

def open_scanner():
    #add cv2.CAP_DSHOW on windows while developing, remove on RBPI
    cap = cv2.VideoCapture(0 , cv2.CAP_DSHOW)
    while True:
        ret, frame = cap.read()
        decoder(frame)
        cv2.imshow('My Title', frame)
        code = cv2.waitKey(1)
        if code == ord('q'):
            exit()

if __name__ == '__main__':
    action_process = Process(target=open_scanner)
    action_process.start()
    action_process.join(timeout=5)
    action_process.terminate()

So when no code is detected, the timeout of 5 should be ok, but should be ignored while running the while-loop inside decoder(image)

Advertisement

Answer

After searching on this for the day, and with Yves’ comment on the question, I came to the conclusion that I was working the wrong way around. So now I added a global Timer, which get canceled if the processing of the QR code gets started.

Now my code looks like this, and it seems to work. Would love to hear it if there is a better way, or if this use of globals is bad practise.

import cv2
import numpy as np
from pyzbar.pyzbar import decode
import time
from threading import Timer
import os


def decoder(image):
    gray_img = cv2.cvtColor(image,0)
    barcode = decode(gray_img)
    for obj in barcode:           
        points = obj.polygon
        (x,y,w,h) = obj.rect
        pts = np.array(points, np.int32)
        pts = pts.reshape((-1, 1, 2))        
        barcodeData = obj.data.decode("utf-8")
        barcodeType = obj.type
        process_code(barcodeData)

def process_code(barcodeData):
    print("cancel timer")
    myTimer.cancel()
    i = 0
    while i < 10:
        print("processing code for " + str(i) + " seconds")
        i += 1
        time.sleep(1)
    print(str(barcodeData) + " is processed")
    os._exit(0)()

def time_out_exit() :
    print("No QR Code Found")
    os._exit(0)()

def open_scanner():
    myTimer.start()
    #add cv2.CAP_DSHOW on windows while developing, remove on RBPI
    cap = cv2.VideoCapture(0 , cv2.CAP_DSHOW)
    #cap = cv2.VideoCapture(0)
    while True:
        ret, frame = cap.read()
        decoder(frame)
        #cv2.imshow('My Title', frame)
        code = cv2.waitKey(1)
        if code == ord('q'):
            exit()

globals()['myTimer'] = Timer(10.0, time_out_exit)
if __name__ == '__main__':
    open_scanner()
User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement