Real-time Webcam Barcode Detection with OpenCV and C++

Dynamsoft Barcode Reader C++ SDK is available for Windows, Linux, and Mac (iOS and Android editions are coming soon). I have shared an article that illustrates how to build webcam barcode reader in Python. In this tutorial, I’ll use a different C++ API to implement barcode scanner applications for Windows and Raspberry Pi with a webcam.

What You Should Know

Getting Started with Webcam Barcode Reader

How to capture frame from webcam using OpenCV

       VideoCapture cap(0);
       if (!cap.isOpened())
              return -1;
       Mat frame;
       for (;;)
       {
              cap >> frame; // Get a new frame from camera
              imshow(windowName, frame); // Display the new frame
              if (waitKey(30) >= 0)
                     break;
       }

How to initialize Dynamsoft Barcode Reader

       CBarcodeReader reader;
       reader.InitLicense("LICENSE_KEY");
       __int64 llFormat = (OneD | QR_CODE | PDF417 | DATAMATRIX);
       int iMaxCount = 0x7FFFFFFF;
       ReaderOptions ro = { 0 };
       ro.llBarcodeFormat = llFormat;
       ro.iMaxBarcodesNumPerPage = iMaxCount;
       reader.SetReaderOptions(ro);

How to pre-process camera frame buffer

The barcode API only takes DIB (device-independent bitmap) structure as the input data, and thus, you have to re-construct the buffer wrapped in Mat:

       int elemSize = image.elemSize();
       int size = image.total() * elemSize;
       // Get image data
       char *imageData = (char *)image.data;

       // Combine header info and image data
       int width = image.cols, height = image.rows;
       char *total = (char *)malloc(size + 40);

       if (!total)
       {
              printf("Failed to allocate memory");
              return;
       }

       memset(total, 0, size + 40);
       BITMAPINFOHEADER bitmap_info = { 40, width, height, 0, 24, 0, size, 0, 0, 0, 0 };
       memcpy(total, &bitmap_info, 40);

       char *data = total + 40;
       // Reverse the image buffer from bottom to top
       width *= 3;

       for (int i = 1; i <= height; i++)
       {
              memcpy(data, imageData + width * (height - i), width);
              data += width;
       }

Reading barcode image buffer on Windows

       int iRet = reader.DecodeBuffer((unsigned char*)total, size + 40);

       char * pszTemp = (char*)malloc(4096);
       if (iRet != DBR_OK && iRet != DBRERR_LICENSE_EXPIRED && iRet != DBRERR_QR_LICENSE_INVALID &&
              iRet != DBRERR_1D_LICENSE_INVALID && iRet != DBRERR_PDF417_LICENSE_INVALID && iRet != DBRERR_DATAMATRIX_LICENSE_INVALID)
       {
              sprintf(pszTemp, "Failed to read barcode: %s\r\n", DBR_GetErrorString(iRet));
              printf(pszTemp);
              free(pszTemp);
              free(total);
              return;
       }

       pBarcodeResultArray paryResult = NULL;
       reader.GetBarcodes(&paryResult);

       if (paryResult->iBarcodeCount > 0)
       {
              for (int iIndex = 0; iIndex < paryResult->iBarcodeCount; iIndex++)
              {
                     sprintf(pszTemp, "Barcode %d:\r\n", iIndex + 1);
                     printf(pszTemp);
                     sprintf(pszTemp, "    Page: %d\r\n", paryResult->ppBarcodes[iIndex]->iPageNum);
                     printf(pszTemp);
                     sprintf(pszTemp, "    Type: %s\r\n", GetFormatStr(paryResult->ppBarcodes[iIndex]->llFormat));
                     printf(pszTemp);
                     char *pszTemp1 = (char*)malloc(paryResult->ppBarcodes[iIndex]->iBarcodeDataLength + 1);
                     memset(pszTemp1, 0, paryResult->ppBarcodes[iIndex]->iBarcodeDataLength + 1);
                     memcpy(pszTemp1, paryResult->ppBarcodes[iIndex]->pBarcodeData, paryResult->ppBarcodes[iIndex]->iBarcodeDataLength);
                     sprintf(pszTemp, "    Value: %s\r\n", pszTemp1);
                     printf(pszTemp);
                     free(pszTemp1);
                     sprintf(pszTemp, "    Region: {Left: %d, Top: %d, Width: %d, Height: %d}\r\n\r\n",
                           paryResult->ppBarcodes[iIndex]->iLeft, paryResult->ppBarcodes[iIndex]->iTop,
                           paryResult->ppBarcodes[iIndex]->iWidth, paryResult->ppBarcodes[iIndex]->iHeight);
                     printf(pszTemp);
              }
       }

       free(pszTemp);
       reader.FreeBarcodeResults(&paryResult);
       free(total);

webcam barcode scanner in C/C++

Reading barcode image buffer on Linux

Porting the source code from Windows to Linux is a little bit tricky because DIB structure is not defined on Linux platform. We can define it ourselves:

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;

Build the source code:

g++ -ggdb -I$(DynamsoftBarcodeReader)/include -o barcodereader barcodereader.cpp -lDynamsoftBarcodeReader `pkg-config --libs opencv`

Source Code

https://github.com/dynamsoftlabs/cplusplus-webcam-barcode-reader