Previously, I wrote an article Raspberry Pi Barcode Scanner with Webcam and Python illustrating how to build a simple barcode scanner using Dynamsoft Barcode Reader SDK and OpenCV from scratch. The method decodeFile() was used for detecting barcodes from an image file. To use the API, you have to write image buffer that obtained by OpenCV API to a file beforehand. Because the I/O operation takes too much time, this API is not suitable for real-time barcode detection from webcam video stream. Considering this scenario, I have added a new Python API decodeBuffer(). In this article, I will illustrate how to create and use the new API.

Testing Environment

Device: Raspberry Pi 3

Operating System: RASPBIAN JESSIE WITH PIXEL

Prerequisites

Dynamsoft Barcode Reader for Raspberry Pi

Python 2.7.0

OpenCV 3.0.0

Raspberry Pi 2 or 3

USB webcam

Building and Installation

How to Build OpenCV on Raspberry Pi

Download and extract the source code. Install dependencies: sudo apt-get install cmake sudo apt-get install libjpeg-dev libtiff5-dev libjasper-dev libpng12-dev sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev sudo apt-get install libxvidcore-dev libx264-dev sudo apt-get install python-dev Setting up the build: cd ~/opencv-3.0.0/ mkdir build cd build cmake -D CMAKE_BUILD_TYPE=RELEASE \ -D CMAKE_INSTALL_PREFIX=/usr/local \ -D INSTALL_C_EXAMPLES=ON \ -D INSTALL_PYTHON_EXAMPLES=ON \ -D OPENCV_EXTRA_MODULES_PATH=~/opencv_contrib-3.0.0/modules \ -D BUILD_EXAMPLES=ON .. Compile and install OpenCV: make -j4 sudo make install

The shared library will be located at /usr/local/lib/python2.7/dist-packages/cv2.so.

How to build the Python extension with Dynamsoft Barcode Reader SDK

Download and extract the SDK package. Create a symbolic link for libDynamsoftBarcodeReader.so: sudo ln –s <Your dbr path>/lib/libDynamsoftBarcodeReader.so /usr/lib/libDynamsoftBarcodeReader.so Open setup.py and modify the paths of include and lib files: include_dirs=["/usr/lib/python2.7/dist-packages/numpy/core/include/numpy", "<Your dbr path>/include"], library_dirs=['<Your dbr path>/lib'], Build the extension: sudo python setup.py build install

How to implement the decodeBuffer method?

Because the source code is transplanted from Windows edition, we have to define following types and structure:

typedef unsigned long DWORD; typedef long LONG; typedef unsigned short WORD; typedef struct tagBITMAPINFOHEADER { DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; } BITMAPINFOHEADER;

Convert the numpy data from Python to C in decodeBuffer(). Besides that, we have to construct a buffer for barcode reading:

#include <ndarraytypes.h> static PyObject * decodeBuffer(PyObject *self, PyObject *args) { PyObject *o; if (!PyArg_ParseTuple(args, "O", &o)) return NULL; PyObject *ao = PyObject_GetAttrString(o, "__array_struct__"); PyObject *retval; if ((ao == NULL) || !PyCObject_Check(ao)) { PyErr_SetString(PyExc_TypeError, "object does not have array interface"); return NULL; } PyArrayInterface *pai = (PyArrayInterface*)PyCObject_AsVoidPtr(ao); if (pai->two != 2) { PyErr_SetString(PyExc_TypeError, "object does not have array interface"); Py_DECREF(ao); return NULL; } // Construct data with header info and image data char *buffer = (char*)pai->data; // The address of image data int width = pai->shape[1]; // image width int height = pai->shape[0]; // image height int size = pai->strides[0] * pai->shape[0]; // image size = stride * height char *total = (char *)malloc(size + 40); // buffer size = image size + header size memset(total, 0, size + 40); BITMAPINFOHEADER bitmap_info = {40, width, height, 0, 24, 0, size, 0, 0, 0, 0}; memcpy(total, &bitmap_info, 40); // Copy image data to buffer from bottom to top char *data = total + 40; int stride = pai->strides[0]; int i = 1; for (; i <= height; i++) { memcpy(data, buffer + stride * (height - i), stride); data += stride; } // Dynamsoft Barcode Reader initialization __int64 llFormat = (OneD | QR_CODE | PDF417 | DATAMATRIX); int iMaxCount = 0x7FFFFFFF; ReaderOptions ro = {0}; pBarcodeResultArray pResults = NULL; ro.llBarcodeFormat = llFormat; ro.iMaxBarcodesNumPerPage = iMaxCount; printf("width: %d, height: %d, size:%d

", width, height, size); int iRet = DBR_DecodeBuffer((unsigned char *)total, size + 40, &ro, &pResults); printf("DBR_DecodeBuffer ret: %d

", iRet); free(total); // Do not forget to release the constructed buffer // Get results int count = pResults->iBarcodeCount; pBarcodeResult* ppBarcodes = pResults->ppBarcodes; pBarcodeResult tmp = NULL; retval = PyList_New(count); // The returned Python object PyObject* result = NULL; i = 0; for (; i < count; i++) { tmp = ppBarcodes[i]; result = PyString_FromString(tmp->pBarcodeData); printf("result: %s

", tmp->pBarcodeData); PyList_SetItem(retval, i, Py_BuildValue("iN", (int)tmp->llFormat, result)); // Add results to list } // release memory DBR_FreeBarcodeResults(&pResults); Py_DECREF(ao); return retval; }

Raspberry Pi Barcode Scanner

How to set video frame rate, frame width, and frame height?

You can refer to the Property identifier:

CV_CAP_PROP_FRAME_WIDTH : Width of the frames in the video stream.

: Width of the frames in the video stream. CV_CAP_PROP_FRAME_HEIGHT : Height of the frames in the video stream.

: Height of the frames in the video stream. CV_CAP_PROP_FPS: Frame rate.

If failed to use the property identifier, set the value directly as follows:

vc = cv2.VideoCapture(0) vc.set(5, 30) #set FPS vc.set(3, 320) #set width vc.set(4, 240) #set height

How to use the API decodeBuffer()?

while True: cv2.imshow(windowName, frame) rval, frame = vc.read(); results = decodeBuffer(frame) if (len(results) > 0): print "Total count: " + str(len(results)) for result in results: print "Type: " + types[result[0]] print "Value: " + result[1] + "

" # 'ESC' for quit key = cv2.waitKey(20) if key == 27: break

How to run the Raspberry Pi Barcode Scanner?

Connect a USB webcam to Raspberry Pi 2 or 3. Run app.py: python app.py

Raspberry Pi Camera (Not USB Camera)

If you are using a Pi camera, please follow the tutorial – Accessing the Raspberry Pi Camera with OpenCV and Python – to convert the image data before using barcode detection API.

Install picamera:

pip install "picamera[array]"

Try following code:

from picamera.array import PiRGBArray from picamera import PiCamera import time import cv2 # initialize the camera and grab a reference to the raw camera capture camera = PiCamera() rawCapture = PiRGBArray(camera) # allow the camera to warmup time.sleep(0.1) # grab an image from the camera camera.capture(rawCapture, format="bgr") image = rawCapture.array # Barcode detection results = decodeBuffer(image)

Source Code

https://github.com/dynamsoftlabs/raspberrypi-python-barcode