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 firstly write image buffer that obtained by OpenCV API to a file. Because the I/O operation takes too much time, this API is not good 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 installed 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 native 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\n", width, height, size); int iRet = DBR_DecodeBuffer((unsigned char *)total, size + 40, &ro, &pResults); printf("DBR_DecodeBuffer ret: %d\n", 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\n", 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.
- CV_CAP_PROP_FRAME_HEIGHT: 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] + "\n" # '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
Source Code
https://github.com/yushulx/opencv-python-webcam-barcode-reader/tree/master/raspberrypi
The post Raspberry Pi Barcode Scanner in Python appeared first on Code Pool.