Moving Heavy Computation from Raspberry Pi to Windows PC
If you want to use Raspberry Pi as an economical way of detecting barcodes, you can take account for Dynamsoft Barcode Reader SDK. As a business software, Dynamsoft Barcode Reader SDK is designed for overcoming a variety of complicated scenarios with sophisticated algorithms and heavy computations. Although the SDK is flexible for customizing algorithm parameters, subject to the low-frequency CPU of Raspberry Pi, the tradeoff between recognition accuracy and detection speed is still a big challenge. In this article, I will use Socket client-server model as a substitute solution. Thanks to Sabjorn’s NumpySocket module.
System Requirements
- Python 2.7
- Dynamsoft Barcode Reader
Python Barcode Reader Module
Install Dynamsoft Barcode Reader and follow the GitHub repository to build and install the Python barcode module.
Why do We Need the Socket Client-Server Model for Raspberry Pi
I am using the Raspberry Pi 3 Model B+:
- Broadcom BCM2837B0, Cortex-A53 (ARMv8) 64-bit SoC @ 1.4GHz
- 1GB LPDDR2 SDRAM
Here is the time cost of calling the barcode decoding method on Raspberry Pi. Let’s see the resolution of 640×480 first.
The average elapsed time is more than 400ms. What about the resolution of 320×240?
It seems a little bit better but not stable. The CPU utilization may reach 100% which will freeze the process. That is why we need the Socket client-server model by which we can continuously send video frames from Raspberry Pi to a remote server and execute barcode detection tasks on the server.
How to Implement the C/S Model for Barcode Detection
Install OpenCV, scipy, and pillow on Raspberry Pi:
$ sudo apt-get install libopencv-dev python-opencv python-scipy
$ python -m pip install pillow
Download NumpySocket. The Python module has already implemented the function of transferring the NumPy array. I only added two methods for sending and receiving barcode results in JSON formats:
import json
def sendJSON(self, data):
out = json.dumps(data)
try:
self.connection.sendall(out)
except Exception:
exit()
def receiveJSON(self):
try:
chunk = self.socket.recv(1024)
except Exception:
exit()
return json.loads(chunk)
Create a pc.py file:
from numpysocket import NumpySocket
import cv2
import time
import json
import dbr
# Get the license of Dynamsoft Barcode Reader from https://www.dynamsoft.com/CustomerPortal/Portal/Triallicense.aspx
dbr.initLicense('LICENSE KEY')
npSocket = NumpySocket()
npSocket.startServer(9999)
# Receive frames for barcode detection
while(True):
try:
frame = npSocket.recieveNumpy()
# cv2.imshow('PC Reader', frame)
results = dbr.decodeBuffer(frame, 0x3FF | 0x2000000 | 0x4000000 | 0x8000000 | 0x10000000)
out = {}
out['results'] = results
# Send barcode results to Raspberry Pi
npSocket.sendJSON({'results': results})
except:
break
# Press ESC to exit
key = cv2.waitKey(20)
if key == 27 or key == ord('q'):
break
npSocket.endServer()
print('Closed')
In the infinite loop, receive the video frames from Raspberry Pi and then call barcode decoding function to get the results.
Create a rpi.py file. In this file, create a queue for storing and sharing video frames between threads:
def read_barcode():
vc = cv2.VideoCapture(0)
vc.set(3, 640) #set width
vc.set(4, 480) #set height
if not vc.isOpened():
print('Camera is not ready.')
return
host_ip = '192.168.8.84'
npSocket = NumpySocket()
npSocket.startClient(host_ip, 9999)
socket_thread = SocketThread('SocketThread', npSocket)
socket_thread.start()
while vc.isOpened():
ret, f = vc.read()
cv2.imshow("RPi Reader", f)
frame = imresize(f, .5)
key = cv2.waitKey(20)
if key == 27 or key == ord('q'):
socket_thread.isRunning = False
socket_thread.join()
break
if not socket_thread.is_alive():
break
try:
frame_queue.put_nowait(frame)
except:
# Clear unused frames
try:
while True:
frame_queue.get_nowait()
except:
pass
frame_queue.close()
frame_queue.join_thread()
vc.release()
Create a worker thread for Socket connection:
class SocketThread (threading.Thread):
def __init__(self, name, npSocket):
threading.Thread.__init__(self)
self.name = name
self.npSocket = npSocket
self.isRunning = True
def run(self):
while self.isRunning:
frame = frame_queue.get(timeout=100)
try:
start_time = time.time()
self.npSocket.sendNumpy(frame)
obj = self.npSocket.receiveJSON()
print("--- %.2f ms seconds ---" % ((time.time() - start_time) * 1000))
data = obj['results']
if (len(data) > 0):
for result in data:
print("Type: " + result[0])
print("Value: " + result[1] + "\n")
else:
print('No barcode detected.')
except:
break
self.npSocket.endClient()
Run pc.py in Windows and run rpi.py on Raspberry Pi. I used the resolution of 640×480 for preview and resized the frame size for TCP/IP transfer.
The barcode detection works stalely, and the average elapsed time is less than 150ms.