Quantcast
Channel: OpenCV – Code Pool
Viewing all 26 articles
Browse latest View live

Building OpenCV with CMake on Windows

$
0
0

OpenCV (Open Source Computer Vision Library) is a powerful open source library of computer vision algorithms. It is widely used by many technologies, such as image acquiring (e.g. Webcam capture), image processing (e.g. noise reduction), image detection (e.g. face detection), image recognition (e.g. OCR), and so on. Since all OpenCV source code is on GitHub, let’s get the copy and build the source code ourselves for fun.

Prerequisites for Building OpenCV on Windows

CMake-GUI Configuration

To facilitate the building work, we just need to launch CMake-GUI. Specify the source code path and the target build directory.

cmake_gui

Click Configure, and specify the generator for building. I’m using Visual Studio 2013.

cmake_generator

After that, you will see a bunch of checked options.

cmake_configure

You are free to select any build modules you like, and then press Generate to generate build files.

Building OpenCV Source Code with Visual Studio

Open OpenCV.sln with Visual Studio.

opencv_build

Now you just need to click Build Solution. Wait for a while, and then you will see the final results:

opencv_final

How to Build OpenCV with Command Line Tool

If you prefer building source code with a command line tool, you can learn how to write scripts from opencv\platforms\scripts. Here is the script for building OpenCV source code with default configurations:

set PATH=%PATH%;F:\CMake\bin\

mkdir OpenCVBuild

cd OpenCVBuild

cmake F:\git\opencv\opencv

cmake --build .

opencv_command_line

How to Build OpenCV for Android

OpenCV contains toolchains for diverse platforms.

opencv_platform

Let’s take Android for example. To build OpenCV for Android on Windows, we need to download ninja. And then we can use following Windows batch scripts:

set PATH=%PATH%;F:\CMake\bin\;F:\zip\ninja-win\

mkdir OpenCV4AndroidBuild

cd OpenCV4AndroidBuild

cmake -GNinja -DCMAKE_TOOLCHAIN_FILE=F:\git\opencv\opencv\platforms\android\android.toolchain.cmake -DANDROID_NDK=F:\android-ndk-r10 -DCMAKE_BUILD_TYPE=Release F:\git\opencv\opencv

cmake --build .

opencv_android

If you are interested in OpenCV, try to build the source code yourself.


OpenCV Edge Detection

$
0
0

Changes or discontinuities of amplitude attribute, such as luminance value, are fundamentally important primitive characteristics of an image. They often provide an indication of the physical extent of objects. Local Discontinuities of image luminance that from one level to another are called luminance edges. In this post, I’ll share how to make image edge detection with OpenCV.

Overview of Edge Detection

Edge detection is a very common task during image processing. OpenCV provides three most popular edge detection methods: Sobel, Canny, and Laplacian.

The Sobel function prototype is as follows:

CV_EXPORTS_W void Sobel( InputArray src, OutputArray dst, int ddepth,
                         int dx, int dy, int ksize = 3,
                         double scale = 1, double delta = 0,
                         int borderType = BORDER_DEFAULT );

Canny is another famous edge detection algorithm. The function prototype is as follows:

CV_EXPORTS_W void Canny( InputArray image, OutputArray edges,
                         double threshold1, double threshold2,
                         int apertureSize = 3, bool L2gradient = false );

Laplacian is a second-order derivative edge detection technique. The function prototype is as follows:

CV_EXPORTS_W void Laplacian( InputArray src, OutputArray dst, int ddepth,
                             int ksize = 1, double scale = 1, double delta = 0,
                             int borderType = BORDER_DEFAULT );

Building Image Edge Detection Application with Visual Studio 2013

  1. Make sure to prepare your OpenCV environment successfully. If you want to build OpenCV lib by yourself, please refer to blog Building OpenCV with CMake on Windows.
  2. Create a Win32 console project “EdgeDetectionDemo”.
  3. Add Include directories of OpenCV:
    F:\opencv\build\include
    F:\opencv\build\include\opencv2
  4. Add Library directories of OpenCV:
    F:\opencv\build\x86\vc12\lib
  5. Find Post-Build Event and add the following commands to copy relevant OpenCV DLLs:
    copy "F:\opencv\build\x86\vc12\bin\opencv_core2410.dll" $(OutDir)
    copy "F:\opencv\build\x86\vc12\bin\opencv_imgproc2410.dll" $(OutDir)
    copy "F:\opencv\build\x86\vc12\bin\opencv_highgui2410.dll" $(OutDir)
  6. Use following code snippets:
    #include "imgproc/imgproc.hpp"
    #include "highgui/highgui.hpp"
    
    #ifdef _DEBUG // Change lib version: opencv_core{version}.lib
    #pragma comment(lib, "opencv_core2410d.lib") 
    #pragma comment(lib, "opencv_imgproc2410d.lib")
    #pragma comment(lib, "opencv_highgui2410d.lib")
    #else
    #pragma comment(lib, "opencv_core2410.lib") 
    #pragma comment(lib, "opencv_imgproc2410.lib")
    #pragma comment(lib, "opencv_highgui2410.lib")
    #endif
    
    using namespace cv;
    
    int main( int, char** argv )
    {
    	const char * file_name = "f:\\test.jpg";
    
    	Mat src, src_gray;
    	int kernel_size = 3;
    	int scale = 1;
    	int delta = 0;
    	int ddepth = CV_16S;
    
    	const char* src_name = "Source";
    	const char* sobel_name = "Sobel";
    	const char* canny_name = "Canny";
    	const char* laplace_name = "Laplace";
    
    	src = imread( file_name );
    
    	cvtColor( src, src_gray, COLOR_RGB2GRAY );
    	GaussianBlur( src_gray, src_gray, Size(3,3), 0, 0, BORDER_DEFAULT );
    
    	namedWindow( src_name, WINDOW_AUTOSIZE );
    	namedWindow( sobel_name, WINDOW_AUTOSIZE );
    	namedWindow( canny_name, WINDOW_AUTOSIZE );
    	namedWindow( laplace_name, WINDOW_AUTOSIZE );
    
    	//This is for source image.
    	imshow(src_name, src);
    
    	//This is for sobel edge detection.
    	Mat sobel_dst;
    	Mat sobel_abs_dst;
    	Sobel(src_gray, sobel_dst, ddepth, 1, 1, kernel_size);
    	convertScaleAbs(sobel_dst, sobel_abs_dst);
    	imshow( sobel_name, sobel_abs_dst );
    
    	//This is for canny edge detection.
    	Mat canny_dst;
    	Canny(src_gray, canny_dst, 50, 200, 3, false);
    	imshow(canny_name, canny_dst);
    
    	//This is for laplace edge detection.
    	Mat laplace_dst;
    	Mat laplace_abs_dst;
    	Laplacian( src_gray, laplace_dst, ddepth, kernel_size, scale, delta, BORDER_DEFAULT );
    	convertScaleAbs( laplace_dst, laplace_abs_dst );
    	imshow( laplace_name, laplace_abs_dst);
    
    	waitKey(0);
    
    	return 0;
    }

Edge Detection Showcase

a)  The source image.source image

b) The edge image produced by sobel.

sobel

c) The edge image produced by canny.canny

d) The edge image produced by laplace.laplace

Source Code

https://github.com/DynamsoftRD/opencv-programming/tree/master/edge-detecion

OpenCV Line Detection

$
0
0

In this tutorial, let’s learn how to use Hough line transformation with OpenCV to make line detection in an Image.

Hough Line Transform

The Hough Line Transform is a transform used to detect straight lines. OpenCV implements three kinds of Hough Line Transforms:(Standard Hough Transform, SHT),(Multi-Scale Hough Transform, MSHT)and (Progressive Probabilistic Hough Transform, PPHT).

Theory

In the Cartesian coordinate system, the line can be expressed as y = mx+b. In general, the straight line can be represented as a point (b, m) in the parameter space.

cartesian coordinatepolar system

We can express lines in the Polar system. Hence, a line equation can be written as: line equation where r is the length of a normal from the origin to this line and theta is the orientation of r with respect to the X-axis. For each pointpoint, we can find a series of lines that goes through that point which means that each pairpair represents each line that passes bypoint. And for each pointpoint, it can be represented as a sinusoid.

X-Y coordinate systemr-theta coordinate system

It means for each point in X-Y coordinate system can be represented as a sinusoid in the r-theta coordinate system. So all the points can be described as a series of sinusoids. If the curves of two different points intersect in the plane θ - r, that means that both points belong to a same line.

curvesintersection

So we can detect a line by finding the number of intersections between curves. In general, we can define a threshold of the minimum number of intersections needed to identify a line. For more information, please refer to http://docs.opencv.org/doc/tutorials/imgproc/imgtrans/hough_lines/hough_lines.html.

Using Hough Line Transformation with OpenCV

Functions for HoughLine Transform

void HoughLines( InputArray image, OutputArray lines,

                     double rho, double theta, int threshold,

                     double srn, double stn )
  • image: Output of the edge detector. It should be a grayscale image.
  • lines: A vector that will store the parameters  of the detected lines
  • rho: The resolution of the parameter in pixels. We use 1 pixel.
  • theta: The resolution of the parameter in radians. We use 1 degree (CV_PI/180)
  • threshold: The minimum number of intersections to “detect” a line
  • srn and stn: Default parameters to zero.
void HoughLinesP( InputArray image, OutputArray lines,

                double rho, double theta, int threshold,

                double minLineLength=0, double maxLineGap=0 );
  • img: Output of the edge detector. It should be a grayscale image.
  • lines: A vector that will store the parameters  of the detected lines
  • rho: The resolution of the parameter in pixels. We use 1 pixel.
  • theta: The resolution of the parameter in radians. We use 1 degree (CV_PI/180)
  • threshold: The minimum number of intersections to “detect” a line
  • minLinLength: The minimum number of points that can form a line. Lines with less than this number of points are disregarded.
  • maxLineGap: The maximum gap between two points to be considered in the same line.

The sample code

#include "highgui/highgui.hpp"
#include "imgproc/imgproc.hpp"

#include <iostream>

using namespace cv;
using namespace std;

int DetectLines(const char* filename, const char* sourceName, const char* destName)
{
	Mat src = imread(filename, 0);
	if (src.empty())
	{
		cout << "can not open " << filename << endl;
		return -1;
	}

	Mat dst, cdst;
	Canny(src, dst, 50, 200, 3);
	cvtColor(dst, cdst, COLOR_GRAY2BGR);

	vector<Vec4i> lines;
	HoughLinesP(dst, lines, 1, CV_PI / 180, 50, 50, 10);
	for (size_t i = 0; i < lines.size(); i++)
	{
		Vec4i l = lines[i];
		line(cdst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255), 3, 2);
	}

	imshow(sourceName, src);
	imshow(destName, cdst);

	return 0;
}

int main(int argc, char** argv)
{
	DetectLines("..\\1.bmp", "line src", "line dest");
	DetectLines("..\\2.jpg", "door src", "door dest");
	waitKey();

	return 0;
}

Line Detection Results

door testline test

Source Code

 https://github.com/DynamsoftRD/opencv-programming/tree/master/line-detection

Reading Barcode with Webcam in OpenCV and Python

$
0
0

Barcode is an efficient way to make information readable for machines. There are many scenarios of using Barcode reader software. For example, companies use Barcode encoding and decoding software to manage various documents that captured by office scanners. Airport security uses handheld scanners to check the boarding pass and record personal information to the database. Students use the built-in camera of the smartphone to check attendance via Barcode reader software. Since I have a Webcam connected to my desktop PC, I want to empower it to work as a Barcode reader. To implement the solution, I decide to choose OpenCV and Dynamsoft Barcode Reader SDK.


Python Webcam Barcode Reader

Installation

How to Recognize Barcode via Webcam in Python

Here are the steps:

  1. Copy <opencv_installation_dir>\build\python\2.7\x86\cv2.pyd
    to <Python27>\Lib\site-packages\cv2.pyd
  2. Create a project folder.
  3. Build Python Barcode library with Dynamsoft Barcode Reader SDK.
  4. Copy Barcode library and all dependencies to the project folder.
  5. Connect a Webcam to your PC. Make sure you have installed the Webcam driver.
  6. Create a Python script to control Webcam, capture images from Webcam and decode images with Python Barcode library.

Creating Python Barcode Library with Dynamsoft Barcode SDK

The first step is to build the Python Barcode library yourself.

#include "Python.h"

#include "If_DBR.h"
#include "BarcodeFormat.h"
#include "BarcodeStructs.h"
#include "ErrorCode.h"

#ifdef _WIN64
#pragma comment(lib, "DBRx64.lib")
#else
#pragma comment(lib, "DBRx86.lib")
#endif

void SetOptions(pReaderOptions pOption, int option_iMaxBarcodesNumPerPage, int option_llBarcodeFormat){

	if (option_llBarcodeFormat > 0)
		pOption->llBarcodeFormat = option_llBarcodeFormat;
	else
		pOption->llBarcodeFormat = OneD;

	if (option_iMaxBarcodesNumPerPage > 0)
		pOption->iMaxBarcodesNumPerPage = option_iMaxBarcodesNumPerPage;
	else
		pOption->iMaxBarcodesNumPerPage = INT_MAX;

}

static PyObject *
initLicense(PyObject *self, PyObject *args)
{
	char *license;

	if (!PyArg_ParseTuple(args, "s", &license)) {
		return NULL;
	}

	printf("information: %s\n", license);

	int ret = DBR_InitLicense(license);

	printf("return value = %d", ret);

	return Py_None;
}

static PyObject *
decodeFile(PyObject *self, PyObject *args)
{
	char *pFileName;
	int option_iMaxBarcodesNumPerPage = -1;
	int option_llBarcodeFormat = -1;

	if (!PyArg_ParseTuple(args, "s", &pFileName)) {
		return NULL;
	}

	pBarcodeResultArray pResults = NULL;
	ReaderOptions option;
	SetOptions(&option, option_iMaxBarcodesNumPerPage, option_llBarcodeFormat);

	int ret = DBR_DecodeFile(
		pFileName,
		&option,
		&pResults
		);

	if (ret == DBR_OK){
		int count = pResults->iBarcodeCount;
		pBarcodeResult* ppBarcodes = pResults->ppBarcodes;
		pBarcodeResult tmp = NULL;

		PyObject* list = PyList_New(count);
		PyObject* result = NULL;

		for (int i = 0; i < count; i++)
		{
			tmp = ppBarcodes[i];
			result = PyString_FromString(tmp->pBarcodeData);

			PyList_SetItem(list, i, Py_BuildValue("iN", (int)tmp->llFormat, result));
		}

		// release memory
		DBR_FreeBarcodeResults(&pResults);

		return list;
	}

	return Py_None;
}

static PyMethodDef methods[] = {
	{ "initLicense", initLicense, METH_VARARGS, NULL },
	{ "decodeFile", decodeFile, METH_VARARGS, NULL },
	{ NULL, NULL }
};

PyMODINIT_FUNC
initDynamsoftBarcodeReader(void)
{
	Py_InitModule("DynamsoftBarcodeReader", methods);
}

For detailed information, please refer to the source code on GitHub. Once the library built successfully, copy DynamsoftBarcodeReader.pyd and DynamsoftBarcodeReaderx64.dll /DynamsoftBarcodeReaderx86.dll to the project folder.

Opening Webcam with OpenCV

Using OpenCV, we can show Webcam preview and capture images with a few lines of Python code.

import cv2.cv as cv

title = "Dynamsoft Barcode Reader"
cv.NamedWindow(title, 1)
capture = cv.CaptureFromCAM(0)

while True:
    img = cv.QueryFrame(capture)
    cv.ShowImage(title, img)

Reading Barcode and Drawing Results over Image

line_type = cv.CV_AA
font = cv.InitFont(cv.CV_FONT_HERSHEY_COMPLEX,
                          0.1, 1, 1, 1, line_type)
fileName = 'test.jpg'
img = cv.QueryFrame(capture)
cv.SaveImage(fileName, img)

results = DynamsoftBarcodeReader.decodeFile(fileName)
top = 30
increase = 20
if results:
    for result in results:
        barcode_format = "Format: " + formats[result[0]]
        barcode_value = "Value: " + result[1]
        cv.PutText(img, barcode_format, (10, top), font, (254, 142, 20))
        top += increase
        cv.PutText(img, barcode_value, (10, top), font, (254, 142, 20))
        top += increase
        cv.PutText(img, "************************", (10, top), font, (254, 142, 20))
        top += increase

cv.ShowImage(title, img)

Source Code

https://github.com/yushulx/webcam-barcode-reader

 

Finding Contours in Images with OpenCV

$
0
0

In this tutorial, let’s see how easy to find all contours in an image with OpenCV APIs.

Overview

Finding contours is a useful task during image processing. The relevant OpenCV functions are as follows:

  • Find contours in a binary image.
    void findContours(InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset=Point())
  • Draw contour outlines or fill contours.
    void drawContours(InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar& color, int thickness=1, int lineType=8, InputArray hierarchy=noArray(), int maxLevel=INT_MAX, Point offset=Point() )
  • Calculates a contour perimeter or a curve length.
    double arcLength(InputArray curve, bool closed)
  • Calculates a contour area.
    double contourArea(InputArray contour, bool oriented=false )
  • Calculates the upright bounding rectangle of a point set.
    Rect boundingRect(InputArray points)
  • Find a rotated rectangle of the minimum area enclosing the input 2D point set.
    RotatedRect minAreaRect(InputArray points)
  • Find a circle of the minimum area enclosing a 2D point set.
    void minEnclosingCircle(InputArray points, Point2f& center, float& radius)

Building Contour Demo with Visual Studio 2013

  1.  Make sure to prepare your OpenCV environment successfully. If you want to make OpenCV library by yourself, please refer to blog Building OpenCV with CMake on Windows.
  2. Create a win32 console project “FindContourDemo”.
  3. Add include directories of OpenCV for project:
    F:\opencv\build\include
    F:\opencv\build\include\opencv2
  4. Add library directories of OpenCV for project:
    F:\opencv\build\x86\vc12\lib
  5. Find Post-Build Event and add the following commands to copy relevant OpenCV DLLs:
    copy "F:\opencv\build\x86\vc12\bin\opencv_core2410.dll" $(OutDir)
    copy "F:\opencv\build\x86\vc12\bin\opencv_imgproc2410.dll" $(OutDir)
    copy "F:\opencv\build\x86\vc12\bin\opencv_highgui2410.dll" $(OutDir)
  6. Edit the main function like this:
    #include "opencv2/imgproc/imgproc.hpp"
    #include "opencv2/highgui/highgui.hpp"
    
    #ifdef _DEBUG
    #pragma comment(lib, "opencv_core2410d.lib")
    #pragma comment(lib, "opencv_imgproc2410d.lib")
    #pragma comment(lib, "opencv_highgui2410d.lib")
    #else
    #pragma comment(lib, "opencv_core249.lib")
    #pragma comment(lib, "opencv_imgproc249.lib")
    #pragma comment(lib, "opencv_highgui249.lib")
    #endif
    
    using namespace cv;
    using namespace std;
    
    int main( int, char** argv )
    {
    	const char * file_name = "shape.png";
    
    	Mat src_mat, gray_mat, canny_mat;
    	Mat contour_mat;
    	Mat bounding_mat;
    
    	const char* src_name = "Source";
    	const char* contours_name = "Contours";
    	const char* bounding_name = "Bounding";
    
    	//1.Read image file & clone.
    	src_mat = imread( file_name );
    	contour_mat = src_mat.clone();
    	bounding_mat = src_mat.clone();
    
    	//2. Convert to gray image and apply canny edge detection
    	cvtColor( src_mat, gray_mat, COLOR_RGB2GRAY );
    	Canny(gray_mat, canny_mat, 30, 128, 3, false);
    
    	//3. Find & process the contours
    	//3.1 find contours on the edge image.
    	vector< vector< cv::Point> > contours;
    	findContours(canny_mat, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
    
    	//3.2 draw contours & property value on the source image.
    	double area, length;
    	drawContours(contour_mat, contours, -1, cv::Scalar(0), 2);	//draw contours on the image
    	for(int i = 0; i < contours.size(); ++i)
    	{
    		Point2f center;
    		float radius;
    
    		area = contourArea(contours[i]);
    		length = arcLength(contours[i], true);
    		minEnclosingCircle(contours[i], center, radius);
    
    		//draw contour property value at the contour center.
    		char buffer[64] = {0};		
    		sprintf(buffer, "Area: %.2lf", area);
    		putText(contour_mat, buffer, center, FONT_HERSHEY_SIMPLEX, .6, Scalar(0), 1);
    
    		sprintf(buffer, "Length: %.2lf", length);
    		putText(contour_mat, buffer, Point(center.x,center.y+20), FONT_HERSHEY_SIMPLEX, .6, Scalar(0), 1);
    
    	}
    
    	//3.3 find bounding of each contour, and draw it on the source image.
    	for(int i = 0; i < contours.size(); ++i)
    	{
    		Point2f points[4];
    		Point2f center;
    		float radius;
    		Rect rect;
    		RotatedRect rotate_rect;
    
    		//compute the bounding rect, rotated bounding rect, minum enclosing circle.
    		rect = boundingRect(contours[i]);
    		rotate_rect = minAreaRect(contours[i]);
    		minEnclosingCircle(contours[i], center, radius);
    
    		rotate_rect.points(points);
    
    		vector< vector< Point> > polylines;
    		polylines.resize(1);
    		for(int j = 0; j < 4; ++j)
    			polylines[0].push_back(points[j]);
    
    		//draw them on the bounding image.
    		cv::rectangle(bounding_mat, rect, Scalar(0,0,255), 2);
    		cv::polylines(bounding_mat, polylines, true, Scalar(0, 255, 0), 2);
    		cv::circle(bounding_mat, center, radius, Scalar(255, 0, 0), 2);
    
    	}
    
    	//4. show window
    	namedWindow( src_name, WINDOW_AUTOSIZE );
    	namedWindow( contours_name, WINDOW_AUTOSIZE );
    	namedWindow( bounding_name, WINDOW_AUTOSIZE );
    
    	imshow(src_name, src_mat);
    	imshow(contours_name, contour_mat);
    	imshow(bounding_name, bounding_mat);
    
    	waitKey(0);
    
    	return 0;
    }
  7. Build and run.
    • Here is the source image.
      contour source
    • The found contour property values are displayed as follows.
      contour property
    • This image shows the results of the bounding rectangle, rotated bounding rectangle and minimum enclosing circles.
      (Red: bounding rectangle; Green: rotated bounding rectangle; Blue: minimum enclosing circle)
      contour results

Source Code

https://github.com/DynamsoftRD/opencv-programming/tree/master/finding-contours

 

How to Use Gamma Correction for Image Processing with Opencv

$
0
0

In reality, we can always see some photos that have low brightnesses and low contrast. To make objects recognizable in pictures,  we need to process the photo with Illumination Compensation. There are many algorithms used for Illumination Compensation such as Histogram equalization, Color similarity measure, Gamma Correction and so on. In this tutorial, I will introduce Gamma Correction and show you how to use it with OpenCV.

What is Gamma Correction

Gamma correction was originally designed to compensate for CRT monitors’ non-linear response to the input signal. CRTs were not able to amplify the input signal themselves and thus the output signal from the PC needed to be adjusted, giving rise to (as of today) standard gamma 2.2 correction and sRGB color space. Gamma Correction is the name of a nonlinear operation used to code and decode luminance or tristimulus values in video or still image systems. Here is the definition of Gamma Correction in Wikipedia:

“Gamma correction is, in the simplest cases, defined by the following power-law expression:

gamma law expression

where A is a constant and the input and output values are non-negative real values; in the common case of A = 1, inputs and outputs are typically in the range 0–1. A gamma value γ < 1 is sometimes called an encoding gamma, and the process of encoding with this compressive power-law nonlinearity is called gamma compression; conversely a gamma value γ > 1 is called a decoding gamma and the application of the expansive power-law nonlinearity is called gamma expansion.”gamma correction definition

Gamma encoded images store tones more efficiently. Since gamma encoding redistributes tonal levels closer to how our eyes perceive them, fewer bits are needed to describe a given tonal range. Otherwise, an excess of bits would be devoted to describing the brighter tones (where the camera is relatively more sensitive), and a shortage of bits would be left to describe the darker tones (where the camera is relatively less sensitive):

gamma encoded image

If an image is under or over gamma corrected, this also affects the color balance. Over correction (in addition to making mid-tones too light) shifts colors towards neutral grey, while under correction (in addition to making mid-tones too dark) shifts colors towards the display primaries.

mapping function for gamma correction
We can see when the image has low brightnesses and low contrast, we can process it by Gamma Correction, and the value of gamma should be less than 1.Because the algorithm can expand low gray steps and compress the high gray steps when γ < 1.

How to Use Gamma Correction with OpenCV

Gamma correction controls the overall brightness of an image. Images that are not corrected can look either bleached out or too dark. We can use this case:

R = pow(R, 1/Gamma)

G = pow(G, 1/Gamma)

B = pow(B, 1/Gamma)

The algorithm can be implemented with the following code, which can process images that have one or three channels.

void GammaCorrection(Mat& src, Mat& dst, float fGamma)

{

unsigned char lut[256];

for (int i = 0; i < 256; i++)

{

lut[i] = saturate_cast<uchar>(pow((float)(i / 255.0), fGamma) * 255.0f);

}

dst = src.clone();

const int channels = dst.channels();

switch (channels)

{

case 1:

{

MatIterator_<uchar> it, end;

for (it = dst.begin<uchar>(), end = dst.end<uchar>(); it != end; it++)

*it = lut[(*it)];

break;

}

case 3:

{

MatIterator_<Vec3b> it, end;

for (it = dst.begin<Vec3b>(), end = dst.end<Vec3b>(); it != end; it++)

{

(*it)[0] = lut[((*it)[0])];

(*it)[1] = lut[((*it)[1])];

(*it)[2] = lut[((*it)[2])];

}

break;

}

}

}

How to Build and Run OpenCV Program on Ubuntu

Follow the official tutorial to install OpenCV 3.0.

#!/bin/bashd
#https://help.ubuntu.com/community/OpenCV
version="$(wget -q -O - http://sourceforge.net/projects/opencvlibrary/files/opencv-unix | egrep -m1 -o '\"[0-9](\.[0-9]+)+' | cut -c2-)"
echo "Installing OpenCV" $version
mkdir OpenCV
cd OpenCV
echo "Removing any pre-installed ffmpeg and x264"
sudo apt-get -qq remove ffmpeg x264 libx264-dev
echo "Installing Dependenices"
sudo apt-get -qq install libopencv-dev build-essential checkinstall cmake pkg-config yasm libjpeg-dev libjasper-dev libavcodec-dev libavformat-dev libswscale-dev libdc1394-22-dev libxine2-dev libgstreamer0.10-dev libgstreamer-plugins-base0.10-dev libv4l-dev python-dev python-numpy libtbb-dev libqt4-dev libgtk2.0-dev libfaac-dev libmp3lame-dev libopencore-amrnb-dev libopencore-amrwb-dev libtheora-dev libvorbis-dev libxvidcore-dev x264 v4l-utils ffmpeg cmake qt5-default checkinstall
echo "Downloading OpenCV" $version
wget -O OpenCV-$version.zip http://sourceforge.net/projects/opencvlibrary/files/opencv-unix/$version/opencv-"$version".zip/download
echo "Installing OpenCV" $version
unzip OpenCV-$version.zip
cd opencv-$version
mkdir build
cd build
cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D WITH_TBB=ON -D BUILD_NEW_PYTHON_SUPPORT=ON -D WITH_V4L=ON -D INSTALL_C_EXAMPLES=ON -D INSTALL_PYTHON_EXAMPLES=ON -D BUILD_EXAMPLES=ON -D WITH_QT=ON -D WITH_OPENGL=ON ..
make -j2
sudo checkinstall
sudo sh -c 'echo "/usr/local/lib" > /etc/ld.so.conf.d/opencv.conf'
sudo ldconfig
echo "OpenCV" $version "ready to be used"

Build the C++ program with g++:

g++ -ggdb `pkg-config --cflags opencv` -o `basename gamma.cpp .cpp` gamma.cpp `pkg-config --libs opencv`

Results:
Gamma = 1
gamma1
Gamma = 0.5
gamma0.5
Gamma = 2
gamma2

Source Code

https://github.com/DynamsoftRD/opencv-programming/tree/master/gamma-correction

 

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

$
0
0

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.

Prerequisites

Windows

Raspberry Pi

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("38B9B94D8B0E2B41660D13B593BE6EF9");
       __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

The post Real-time Webcam Barcode Detection with OpenCV and C++ appeared first on Code Pool.

How to Convert OpenCV Image Data from Python to C

$
0
0

OpenCV officially provides both C++ and Python APIs for developers. Most of the time, developers just need to use one kind of programming languages to read, write and process images with hundreds of computer vision algorithms. However, if you want to use OpenCV Python APIs with an extended C/C++ library, it will be tricky to pass the data. In this article, I will share how to read camera stream with OpenCV-Python and detect barcode with Dynamsoft C/C++ Barcode SDK.

webcam barcode reader with OpenCV Python

Development Environment

Python Extension for Reading Barcode from OpenCV Image Data

Installation

Copy DynamsoftBarcodeReaderx86.dll and cv2.pyd to Python27\Lib\site-packages.

What is the type of the frame data that output by OpenCV?

To convert the image data, we have to know what type it is. The type is numpy.ndarray:

> rval, frame = vc.read();
> print type(frame)
> <type 'numpy.ndarray'>

How to get the C/C++ pointer that pointing to numpy.ndarray?

According to the OpenCV source file opencv\modules\python\src2\cv2.cv.hpp, we can use the following code to get the memory address of the data in C:

    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

How to use the barcode detection API?

You can’t just pass the data pointer directly to DBR_DecodeBuffer(). The data needs to be reconstructed with some extra information:

    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];
    for (int i = 1; i <= height; i++) {
        memcpy(data, buffer + stride * (height - i), stride);
        data += stride;
    }

Read barcode from images and return results:

// 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;
    for (int i = 0; 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);

What if you see the error ‘Unable to find vcvarsall.bat’ when building Python extension on Windows?

According to the answer from StackOverflow, execute the following command based on the version of Visual Studio installed:

  • Visual Studio 2010 (VS10): SET VS90COMNTOOLS=%VS100COMNTOOLS%
  • Visual Studio 2012 (VS11): SET VS90COMNTOOLS=%VS110COMNTOOLS%
  • Visual Studio 2013 (VS12): SET VS90COMNTOOLS=%VS120COMNTOOLS%
  • Visual Studio 2015 (VS14): SET VS90COMNTOOLS=%VS140COMNTOOLS%

I’m using Visual Studio 2015, and thus I can build Python extension as follows:

SET VS90COMNTOOLS=%VS140COMNTOOLS%
python setup.py build install

Python Script for Testing

Open camera:

import cv2
from dbr import *
import time

vc = cv2.VideoCapture(0)

Read and render camera video stream:

cv2.imshow(windowName, frame)
rval, frame = vc.read();

Detect barcode from frame and show results in console:

initLicense("<license>") # Invalid license is fine.
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"

Source Code

https://github.com/yushulx/opencv-python-webcam-barcode-reader

 

The post How to Convert OpenCV Image Data from Python to C appeared first on Code Pool.


Raspberry Pi Barcode Scanner in Python

$
0
0

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.

Raspberry Pi Barcode Scanner in Python

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

  1. Download and extract the source code.
  2. 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
  3. 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 ..
  4. 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

  1. Download and extract the SDK package.
  2. Create a symbolic link for libDynamsoftBarcodeReader.so:
    sudo ln –s <Your dbr path>/lib/libDynamsoftBarcodeReader.so /usr/lib/libDynamsoftBarcodeReader.so
  3. 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'],
  4. 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?

  1. Connect a USB webcam to Raspberry Pi 2 or 3.
  2. 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.

Using OpenCV to Build Python Barcode Reader for macOS

$
0
0

This article is about how to use OpenCV and Dynamsoft Barcode Reader SDK to create a Python barcode reader on macOS.

How to Install OpenCV on macOS

Use ‘sw_vers’ to check macOS system version information:

check mac version

Install Homebrew.

If you have already installed Homebrew, just update it. When running ‘brew update’, you may see following errors.

Error: /usr/local/Library/brew.sh: line 32: /usr/local/Library/ENV/scm/git: No such file or directory.

To fix the error, run:

cd "$(brew --repository)" && git fetch && git reset --hard origin/master

Error: Fetching /usr/local/Library/Taps/flutter/homebrew-flutter failed!

To repair the error, run:

brew untap flutter/flutter

The next step is to install Python and NumPy. Python is pre-installed on macOS. The default version is not compatible with the latest OpenCV. Therefore, you need to install the latest Python using Homebrew.

brew install python python3 numpy
echo 'import site; site.addsitedir("/usr/local/lib/python2.7/site-packages")' >> /Users/xiao/Library/Python/2.7/lib/python/site-packages/homebrew.pth

Use command ‘python –version’ to check the current version. If it is not the latest version, you can edit .bash_profile and export the path:

vim ~/.bash_profile
export PATH=/usr/local/Cellar/python/2.7.13/bin:$PATH
source ~/.bash_profile

Install OpenCV:

brew tap homebrew/science
brew install opencv3

Python Barcode Reader for macOS

Get libDynamsoftBarcodeReader.dylib and relevant header files from DBR-Libs.zip.

To link the dynamic library and use barcode reading APIs, we need to write code in C/C++. Include the header files:

#include <Python.h>
#include "If_DBR.h"
#include "BarcodeFormat.h"
#include "BarcodeStructs.h"
#include "ErrorCode.h"
#include <ndarraytypes.h>

Where is ndarraytypes.h?
Use command ‘find / -name ndarraytypes.h’ to find it:

/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/numpy/core/include/numpy/ndarraytypes.h
/usr/local/Cellar/numpy/1.13.0/lib/python2.7/site-packages/numpy/core/include/numpy/ ndarraytypes.h
/usr/local/lib/python2.7/site-packages/numpy/core/include/numpy/ndarraytypes.h

Get native image data that decoded by OpenCV Python API:

    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;
    }

    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

Define BITMAPINFOHEADER structure. The DWORD defined by Microsoft is unsigned long, but here it is unsigned int. The size of the type should be 4 bytes.

typedef unsigned int DWORD;
typedef int LONG;
typedef unsigned short WORD;

#pragma pack(push)
#pragma pack(1)

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;

#pragma pack(pop)

Construct a buffer with bitmap header info for barcode detection.

int dib_header_size = sizeof(BITMAPINFOHEADER);

char *total = (char *)malloc(size + dib_header_size); // buffer size = image size + header size
memset(total, 0, size + dib_header_size);
BITMAPINFOHEADER bitmap_info = {dib_header_size, width, height, 0, 24, 0, size, 0, 0, 0, 0};
memcpy(total, &bitmap_info, dib_header_size);

// Copy image data to buffer from bottom to top
char *data = total + dib_header_size;
int stride = pai->strides[0];
int i = 1;
for (; i <= height; i++) {
    memcpy(data, buffer + stride * (height - i), stride);
    data += stride;
}
int iRet = DBR_DecodeBuffer((unsigned char *)total, size + dib_header_size, &ro, &pResults);

Get and return barcode 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);

Configure setup.py for building Python extension:

from distutils.core import setup, Extension
 
module_dbr = Extension('dbr', 
                        sources = ['dbr.c'], 
                        include_dirs=['/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/numpy/core/include/numpy', './include'],
                        library_dirs=['./lib'],
                        libraries=['DynamsoftBarcodeReader'])
 
setup (name = 'DynamsoftBarcodeReader',
        version = '1.0',
        description = 'Python barcode extension',
        ext_modules = [module_dbr])

Build and install dbr.so:

python setup.py build install

Write a simple Python barcode detection app:

import cv2
from dbr import *
import sys
import os.path

initLicense("D426ABF246933C82A16D537FC46C064F")
frame = cv2.imread(fileName, cv2.CV_LOAD_IMAGE_COLOR)
results = decodeBuffer(frame)

Note: when using imread, you have to set second parameter CV_LOAD_IMAGE_COLOR. The native API only works for a color image.

OpenCV Python barcode reader for macOS

Source Code

https://github.com/dynamsoft-dbr/mac-opencv

The post Using OpenCV to Build Python Barcode Reader for macOS appeared first on Code Pool.

Listing Multiple Cameras for OpenCV-Python on Windows

$
0
0

Using OpenCV APIs to capture video from a camera is convenient. However, OpenCV does not provide an API for listing all available devices. If you have multiple cameras connected to your PC, you have no idea how to choose the right one. To get device information on Windows, you need to invoke DirectShow APIs. In this post, I will share how to create a Python extension that lists camera devices for OpenCV-Python on Windows.

Bridging DirectShow APIs to OpenCV-Python

How to run DirectShow sample

To use DirectShow APIs, read the Microsoft’s tutorial – Selecting a Capture Device, which shares how to list video and audio devices in C++.

To run the sample, create an empty Win32 Console Application in Visual Studio: File > New > Project > Templates > Visual C++ > Win32.

Create main.cpp, and copy all codes snippets from the tutorial page to the C++ file.

Build and run the project.

How to wrap up DirectShow C++ code

Define Python module and change main() function to a Python method:

static PyObject *
getDeviceList(PyObject *self, PyObject *args)
{
	PyObject* pyList = NULL; 
	
	HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
	if (SUCCEEDED(hr))
	{
		IEnumMoniker *pEnum;

		hr = EnumerateDevices(CLSID_VideoInputDeviceCategory, &pEnum);
		if (SUCCEEDED(hr))
		{
			pyList = DisplayDeviceInformation(pEnum);
			pEnum->Release();
		}
		CoUninitialize();
	}

    return pyList;
}

static PyMethodDef Methods[] =
{
    {"getDeviceList", getDeviceList, METH_VARARGS, NULL},
    {NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC
initdevice(void)
{
     (void) Py_InitModule("device", Methods);
}

Create Python list to save device information:

PyObject* pyList = PyList_New(0);
Char *pValue = _com_util::ConvertBSTRToString(var.bstrVal);
HRESULT hr = PyList_Append(pyList, Py_BuildValue("s", pValue));

Note: you have to convert BSTR to string. To use ConvertBSTRToString, we need a header file #include <comutil.h>, and the corresponding library #pragma comment(lib, “comsuppw.lib”).

How to build and use Python extension

Create setup.py:

from distutils.core import setup, Extension

module_device = Extension('device',
                        sources = ['device.cpp'], 
                        library_dirs=['G:\Program Files\Microsoft SDKs\Windows\v6.1\Lib']
                      )

setup (name = 'WindowsDevices',
        version = '1.0',
        description = 'Get device list with DirectShow',
        ext_modules = [module_device])

Build and install the extension:

python setup.py build install

If you see the error ‘Unable to find vcvarsall.bat’, set Visual Studio environment:

  • Visual Studio 2010 (VS10): SET VS90COMNTOOLS=%VS100COMNTOOLS%
  • Visual Studio 2012 (VS11): SET VS90COMNTOOLS=%VS110COMNTOOLS%
  • Visual Studio 2013 (VS12): SET VS90COMNTOOLS=%VS120COMNTOOLS%
  • Visual Studio 2015 (VS14): SET VS90COMNTOOLS=%VS140COMNTOOLS%

Create test.py to use the extension for OpenCV-Python:

import device
import cv2

def select_camera(last_index):
    number = 0
    hint = "Select a camera (0 to " + str(last_index) + "): "
    try:
        number = int(input(hint))
        # select = int(select)
    except Exception ,e:
        print("It's not a number!")
        return select_camera(last_index)

    if number > last_index:
        print("Invalid number! Retry!")
        return select_camera(last_index)

    return number


def open_camera(index):
    cap = cv2.VideoCapture(index)
    return cap

def main():
    # print OpenCV version
    print("OpenCV version: " + cv2.__version__)

    # Get camera list
    device_list = device.getDeviceList()
    index = 0

    for name in device_list:
        print(str(index) + ': ' + name)
        index += 1

    last_index = index - 1

    if last_index < 0:
        print("No device is connected")
        return

    # Select a camera
    camera_number = select_camera(last_index)
    
    # Open camera
    cap = open_camera(camera_number)

    if cap.isOpened():
        width = cap.get(3) # Frame Width
        height = cap.get(4) # Frame Height
        print('Default width: ' + str(width) + ', height: ' + str(height))

        while True:
            
            ret, frame = cap.read();
            cv2.imshow("frame", frame)

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

        cap.release() 
        cv2.destroyAllWindows() 

if __name__ == "__main__":
    main()

list capture device for OpenCV-Python

Source Code

https://github.com/yushulx/python-capture-device-list

The post Listing Multiple Cameras for OpenCV-Python on Windows appeared first on Code Pool.

How to Build Web Camera Recorder Using OpenCV and Flask

$
0
0

Recently, I was inspired by a blog post “Python Live Video Streaming Example” and thinking whether it is possible to save the camera streaming to a video file. Based on the example code, I managed to figure out a solution. In this post, I want to share the process of building the web camera recorder using OpenCV and Flask.

web camera recorder

How to Use OpenCV to Record a Video

Let’s start with the code snippet posted on OpenCV website:

import numpy as np
import cv2

cap = cv2.VideoCapture(0)

# Define the codec and create VideoWriter object
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi',fourcc, 20.0, (640,480))

while(cap.isOpened()):

    ret, frame = cap.read()
    if ret==True:
        frame = cv2.flip(frame,0)
        # write the flipped frame
        out.write(frame)
        cv2.imshow('frame',frame)

        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    else:
        break

# Release everything if job is finished
cap.release()
out.release()
cv2.destroyAllWindows()

After running the code on Windows, I got a 0KB file. The reason is the codec does not exist in my Windows 10. Replace fourcc with -1 to check the available codec list:

out = cv2.VideoWriter('output.avi', -1, 20.0, (640,480))

windows video codec

Instead of XVID, using MJPG will work.

fourcc = cv2.VideoWriter_fourcc(*'MJPG')

MJPG codec results in high size video. To get a smaller size, we need to install X264, which is not in the codec list by default.

Change codec to X264:

fourcc = cv2.VideoWriter_fourcc(*'X264')

Once you run the app, an annoying log window will pop up:

x264 log window

I have found the solution here. Open Windows registry and set log_level value 0.

close x264 log window

How to Build Camera Recorder in Web Browser

The source code of video_streaming_with_flask_example is good but limited. It keeps sending responses that contain image data and never ends.

def get_frame(self):
        success, image = self.video.read()
        # We are using Motion JPEG, but OpenCV defaults to capture raw images,
        # so we must encode it into JPEG in order to correctly display the
        # video stream.
        ret, jpeg = cv2.imencode('.jpg', image)
        return jpeg.tobytes()

In this case, the web browser cannot load other resources and execute JavaScript code. To avoid this situation, I removed the loop: an image request only receives one frame.

def video_stream():
    global video_camera 
    global global_frame

    if video_camera == None:
        video_camera = VideoCamera()
        
    frame = video_camera.get_frame()

    if frame != None:
        global_frame = frame
        yield (b'--frame\r\n'
                b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')
    else:
        yield (b'--frame\r\n'
                        b'Content-Type: image/jpeg\r\n\r\n' + global_frame + b'\r\n\r\n')

To make the static image looks like a video, use setInterval() to grab images from server continuously:

function playVideo() {
    var video = document.getElementById("video");
    video.src = "/video_viewer?" + new Date().getTime();
}

setInterval(playVideo, 30);

Use XMLHttpRequest to start and stop video recording event.

Client:

    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4 && xhr.status == 200) {
            // alert(xhr.responseText);
        }
    }
    xhr.open("POST", "/record_status");
    xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
    xhr.send(JSON.stringify({ status: "true" }));

Server:

@app.route('/record_status', methods=['POST'])
def record_status():
    global video_camera 
    if video_camera == None:
        video_camera = VideoCamera()

    json = request.get_json()

    status = json['status']

    if status == "true":
        video_camera.start_record()
        return jsonify(result="started")
    else:
        video_camera.stop_record()
        return jsonify(result="stopped")

Every time the event is triggered, create a new thread to save camera stream to a video file.

class RecordingThread (threading.Thread):
    def __init__(self, name, camera):
        threading.Thread.__init__(self)
        self.name = name
        self.isRunning = True

        self.cap = camera
        fourcc = cv2.VideoWriter_fourcc(*'MJPG')
        self.out = cv2.VideoWriter('./static/video.avi',fourcc, 20.0, (640,480))

    def run(self):
        while self.isRunning:
            ret, frame = self.cap.read()
            if ret:
                self.out.write(frame)

        self.out.release()

    def stop(self):
        self.isRunning = False

    def __del__(self):
        self.out.release()

Run the app:

python server.py

Note: if you are using Python 2, you will see the socket connection issue:

python server error

To get rid of the exception, enable threaded mode:

if __name__ == '__main__':
    app.run(host='0.0.0.0', threaded=True)

Or use Python 3 to run the app.

streaming video recorder

Source Code

https://github.com/yushulx/web-camera-recorder

The post How to Build Web Camera Recorder Using OpenCV and Flask appeared first on Code Pool.

How to Build Web Document Scanner Using OpenCV-Python

$
0
0

Many excellent document mobile apps support not only image capture, but also edge detection and perspective transformation. If you are interested in these computer vision technologies, you can use OpenCV to create a free document scanner app yourself. In this post, I want to share how to use OpenCV-Python to create a web document scanner step by step.

Setting Up Environment

Download Python 3.5.

Install Flask:

pip3 install flask

Install OpenCV 3.3.0 for Python:

pip3 install opencv-python

Download the latest NumPy 1.11.2. Unzip the package and build it:

python3 setup.py build install

To compile NumPy source code on Windows 10, install Microsoft Visual C++ Compiler for Python 2.7.

Web Document Scanner

Article and Code References

Steps of Building the App

Create document.py to do edge detection and perspective transformation:

import cv2
import rect
import numpy as np

class Scanner(object):
    # http://www.pyimagesearch.com/2014/08/25/4-point-opencv-getperspective-transform-example/
    def four_point_transform(self, image, rect):
    	# obtain a consistent order of the points and unpack them
        # individually
        (tl, tr, br, bl) = rect
    
        # compute the width of the new image, which will be the
        # maximum distance between bottom-right and bottom-left
        # x-coordiates or the top-right and top-left x-coordinates
        widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
        widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
        maxWidth = max(int(widthA), int(widthB))
    
        # compute the height of the new image, which will be the
        # maximum distance between the top-right and bottom-right
        # y-coordinates or the top-left and bottom-left y-coordinates
        heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
        heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
        maxHeight = max(int(heightA), int(heightB))
    
        # now that we have the dimensions of the new image, construct
        # the set of destination points to obtain a "birds eye view",
        # (i.e. top-down view) of the image, again specifying points
        # in the top-left, top-right, bottom-right, and bottom-left
        # order
        dst = np.array([
            [0, 0],
            [maxWidth - 1, 0],
            [maxWidth - 1, maxHeight - 1],
            [0, maxHeight - 1]], dtype = "float32")
    
        # compute the perspective transform matrix and then apply it
        M = cv2.getPerspectiveTransform(rect, dst)
        warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))
    
        # return the warped image
        return warped

    # https://github.com/vipul-sharma20/document-scanner
    def detect_edge(self, image, enabled_transform = False):
        dst = None
        orig = image.copy()

        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        blurred = cv2.GaussianBlur(gray, (5, 5), 0)
        edged = cv2.Canny(blurred, 0, 20)
        _, contours, _ = cv2.findContours(edged, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)

        contours = sorted(contours, key=cv2.contourArea, reverse=True)

        for cnt in contours:
            epsilon = 0.051 * cv2.arcLength(cnt, True)
            approx = cv2.approxPolyDP(cnt, epsilon, True)

            if len(approx) == 4:
                target = approx
                cv2.drawContours(image, [target], -1, (0, 255, 0), 2)

                if enabled_transform:
                    approx = rect.rectify(target)
                    # pts2 = np.float32([[0,0],[800,0],[800,800],[0,800]])
                    # M = cv2.getPerspectiveTransform(approx,pts2)
                    # dst = cv2.warpPerspective(orig,M,(800,800))
                    dst = self.four_point_transform(orig, approx)
                break

        return image, dst

Create camera.py to capture frames from a camera:

import cv2
from document import Scanner

class VideoCamera(object):
    def __init__(self):
        # Open a camera
        self.cap = cv2.VideoCapture(2)
      
        # Initialize video recording environment
        self.is_record = False
        self.out = None
        self.transformed_frame = None

        self.scanner = Scanner()
        self.cached_frame = None
    
    def __del__(self):
        self.cap.release()

    def get_video_frame(self):
        ret, frame = self.cap.read()
        if ret:
            frame, _ = self.scanner.detect_edge(frame)
            self.cached_frame = frame
            ret, jpeg = cv2.imencode('.jpg', frame)
            return jpeg.tobytes()
        else:
            return None

    def capture_frame(self):
        ret, frame = self.cap.read()
        if ret:
            _, frame = self.scanner.detect_edge(frame, True)
            ret, jpeg = cv2.imencode('.jpg', frame)
            self.transformed_frame = jpeg.tobytes()
        else:
            return None

    def get_cached_frame(self):
        return self.cached_frame

    def get_image_frame(self):
        return self.transformed_frame

Note: if you have only one device connected, the parameter in cv2.VideoCapture() should be 0.

Create server.py to stream camera frames to your web client:

from flask import Flask, render_template, Response, jsonify, request
from camera import VideoCamera

app = Flask(__name__)

video_camera = None

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/capture_status', methods=['POST'])
def capture_status():
    global video_camera 

    if video_camera == None:
        video_camera = VideoCamera()

    json = request.get_json()

    status = json['status']

    if status == "true":
        video_camera.capture_frame()
        return jsonify(result="done")

def video_frame():
    global video_camera 

    if video_camera == None:
        video_camera = VideoCamera()
        
    while True:
        frame = video_camera.get_video_frame()

        if frame is not None:
            yield (b'--frame\r\n'
                    b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')
        else:
            yield (b'--frame\r\n'
                    b'Content-Type: image/jpeg\r\n\r\n' + video_camera.get_cached_frame() + b'\r\n\r\n')

def image_frame():
    global video_camera 

    if video_camera == None:
        video_camera = VideoCamera()
        
    frame = video_camera.get_image_frame()

    if frame is not None:
        yield (b'--frame\r\n'
                b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')

@app.route('/video_viewer')
def video_viewer():
    return Response(video_frame(),
                    mimetype='multipart/x-mixed-replace; boundary=frame')

@app.route('/image_viewer')
def image_viewer():
    return Response(image_frame(),
                        mimetype='multipart/x-mixed-replace; boundary=frame')

if __name__ == '__main__':
    app.run(host='0.0.0.0', threaded=True)

Run the app:

python server.py

web document scanner

Source Code

https://github.com/yushulx/web-document-scanner

The post How to Build Web Document Scanner Using OpenCV-Python appeared first on Code Pool.

A Simple Web Document Management App with OpenCV.js

$
0
0

Document Scanning is nothing new for mobile apps. I remember the first time that I installed a document scanning app was in 2010. However, Apple, Microsoft, and Google the giant tech companies got started to recognize the importance of document scanning technology recently. It is good to see the function appears in iOS Notes, Office Lens and Google Drive. Why is the document scanning being hot now? I think the reason is the quality of images captured by mobile cameras is getting better and better. More and more users tend to scan documents with cameras instead of traditional scanners. If you are not familiar with Android and iOS development, you can use HTML5. In this post, I will share how to create a simple web document management app using OpenCV.js.

How to Use FileSystem APIs to Write, Read and Remove Images

While creating a web client-side document management app, if you keep all image data in memory, you will see the “out of memory” warning soon. To avoid the issue, we can write memory data to cache. There are several storage options available in HTML5, such as Local Storage, Session Storage, IndexedDB, Web SQL, and Cookies. Due to the size limitation, they are not suitable for my scenario. My use case is to load and edit images that are large binary blobs in the web browser. It is why I need to use FileSystem APIs which aims to deal with data outside of the context of the browser.

Load an image to memory

Create an input element and set “file” as the type. The following code can change the button text:

<input type="button" id="load" value="Load image" onclick="document.getElementById('upload').click();" />
<input type="file" id="upload" onchange="loadImage();" style="display:none;" />

Comparing to desktop platforms, the “file” type running on mobile platforms trigger not only a file selection window but also the default camera app.

Use FileReader to load an image into an array buffer and wrap it as a blob.

fileReader.onload = function (event) {
    if (!cacheManager.hasStorage(event.target.result.byteLength)) {
      alert('Image storage is full. Please clear some images to get storage quota.');
      return;
    }
    let size = event.target.result.byteLength / 1024;
    log('size = ' + size + 'K');

    var arrayBufferView = new Uint8Array(this.result);
    var blob = new Blob([arrayBufferView], {
      type: "image/png"
    });

    renderBlobImage(blob, 'canvas');

  };
  fileReader.readAsArrayBuffer(file);

Draw the image on a canvas:

function renderBlobImage(blob, canvasID) {
  var urlCreator = window.URL || window.webkitURL;

  let canvas = document.getElementById(canvasID);
  let ctx = canvas.getContext('2d');
  var image = new Image();
  image.onload = function () {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    var canvasWidth = 600;
    var canvasHeight = 400;

    var scaleFactor = Math.min((canvasWidth / image.width), (canvasHeight / image.height));
    canvas.width = image.width * scaleFactor;
    canvas.height = image.height * scaleFactor;
    ctx.drawImage(image, 0, 0, image.width * scaleFactor, image.height * scaleFactor);
  }
  image.src = urlCreator.createObjectURL(blob);
}

Write a file

Here is the code for writing a file:

CacheManager.prototype.writeFile = function (
    fileName, blob, successCallback, errorCallback) {

    function onInitFs(fs) {
      fs.root.getFile(fileName, {
        create: true
      }, function (fileEntry) {
        fileEntry.createWriter(function (fileWriter) {

          fileWriter.truncate(0);

        }, errorHandler);

        fileEntry.createWriter(function (fileWriter) {

          fileWriter.onwriteend = function (e) {
          
            console.log('Write completed.');
            successCallback();
          };

          fileWriter.onerror = function (e) {
            console.log('Write failed: ' + e.toString());
            errorCallback();
          };

          fileWriter.write(blob);

        }, errorHandler);

      }, errorHandler);
    }

    window.requestFileSystem(
      window.TEMPORARY, this.storageSize, onInitFs, errorHandler);
  };

Why do we need to use createWriter() twice? The first createWriter() is used to clear the existing data.

We can compare the storage usage before and after:

Before

FileSystem before

After

FileSystem after

Read a file

CacheManager.prototype.readFile = function (fileName, callback) {
    function onInitFs(fs) {
      fs.root.getFile(
        fileName, {},
        function (fileEntry) {

          // Get a File object representing the file,
          // then use FileReader to read its contents.
          fileEntry.file(callback, errorHandler);

        },
        errorHandler);
    }

    window.requestFileSystem(
      window.TEMPORARY, this.storageSize, onInitFs, errorHandler);
  };

Remove a file

CacheManager.prototype.removeFile = function (fileName) {
    function onInitFs(fs) {
        fs.root.getFile(fileName, {
          create: false
        }, function (fileEntry) {

          fileEntry.remove(function () {
            console.log('File removed.');
          }, errorHandler);

        }, errorHandler);
      }

      window.requestFileSystem(
        window.TEMPORARY, this.storageSize, onInitFs, errorHandler);

    
  };

How to Use OpenCV.js

OpenCV.js is a JavaScript binding that exposes OpenCV library to the web.

To use OpenCV.js, you just need to include cv.js:

<script async src="cv.js"></script>

When opening your web page, OpenCV.js will load the cv.data file via XMLHttpRequest. Here is the code snippet that I extracted from the complex sample code for monitoring the download status:

var Module = {
  setStatus: function (text) {
    if (!Module.setStatus.last) Module.setStatus.last = {
      time: Date.now(),
      text: ''
    };
    if (text === Module.setStatus.text) return;
    var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
    var now = Date.now();
    if (m && now - Date.now() < 30) return; // if this is a progress update, skip it if too soon
    if (m) {
      text = m[1];

    }
    if (text === '') {
      isOpenCVReady = true;
      console.log('OpenCV is ready');
      // onPreprocess();
    }

  },
  totalDependencies: 0,
  monitorRunDependencies: function (left) {
    this.totalDependencies = Math.max(this.totalDependencies, left);
    Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies - left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
  }
};
Module.setStatus('Downloading...');

Once OpenCV context is ready, we can call any OpenCV methods in JavaScript. However, there seems to be a bug:

OpenCV.js bug

I debugged line by line and finally focused on the following code:

cv.convexHull(contours.get(0), item, false, true);

As long as I run the snippet before calling other APIs, I can get the expected result.

OpenCV.js: edge detection

The full code for skipping the bug:

function onPreprocess() {

  var canvas = document.createElement('canvas');
  var ctx = canvas.getContext('2d');
  var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
  var src = cv.matFromArray(imgData, cv.CV_8UC4);
  var canny_output = new cv.Mat();
  var blurred = new cv.Mat();
  var cthresh = 75;
  cv.blur(src, blurred, [5, 5], [-1, -1], cv.BORDER_DEFAULT);
  cv.Canny(blurred, canny_output, cthresh, cthresh * 2, 3, 0);

  var contours = new cv.MatVector();
  var hierarchy = new cv.Mat();
  cv.findContours(canny_output, contours, hierarchy, 3, 2, [0, 0]);

  var item = new cv.Mat();
  // For preprocessing. Bug?
  cv.convexHull(contours.get(0), item, false, true);
  item.delete();

  src.delete();
  blurred.delete();
  contours.delete();
  hierarchy.delete();
  canny_output.delete();

}

Now, let’s play the web document management app:

web document management

Source Code

https://github.com/yushulx/javascript-image-storage

The post A Simple Web Document Management App with OpenCV.js appeared first on Code Pool.

Building .NET Barcode Reader with OpenCV and DBR 5.2

$
0
0

OpenCV is written in C++.  If you install OpenCV library on Windows, you will see OpenCV officially provides wrappers for Python and Java but not for C#. Fortunately, there are many .NET open source projects for wrapping OpenCV C++ APIs, and thus we don’t need to write a wrapper from scratch. In this post, I will share how to use OpenCV library and Dynamsoft Barcode Reader SDK to create a .NET barcode reader app on Windows.

Prerequisites

.NET Barcode Reader with OpenCV

I tried difference open source projects and finally decided to use OpenCvSharp which is continuously maintained by open source community.

Install OpenCvSharp and Dynamsoft Barcode Reader via Package Manager in Visual Studio. Tools >  NuGet Package Manager > Package Manager Console:

PM > Install-Package OpenCvSharp3-AnyCPU
PM> Install-Package Dynamsoft.DotNet.Barcode

Create a video capture object:

VideoCapture capture = new VideoCapture(0);

Get a video frame:

Mat image = capture.RetrieveMat();

Render the frame in a Window:

Cv2.ImShow("video", image);

Break the infinite loop when pressing ‘ESC’ key:

int key = Cv2.WaitKey(20);
// 'ESC'
if (key == 27)
{
    break;
}

Create a barcode reader object:

BarcodeReader reader = new BarcodeReader("t0068MgAAALLyUZ5pborJ8XVc3efbf4XdSvDAVUonA4Z3/FiYqz1MOHaUJD3d/uBmEtXVCn9fw9WIlNw6sRT/DepkdvVW4fs=");

To recognize barcodes, you can use DecodeBuffer() function. However, the type of the first parameter is byte[]. Now the biggest problem is how we can make the function work with Mat type.

Get the data pointer, width, height and element size as follows:

IntPtr data = image.Data;
int width = image.Width;
int height = image.Height;
int elemSize = image.ElemSize();
int buffer_size = width * height * elemSize;

Copy the data to a byte array:

using System.Runtime.InteropServices;
byte[] buffer = new byte[buffer_size];
Marshal.Copy(data, buffer, 0, buffer_size);

Decode the buffer and return barcode results:

BarcodeResult[] results = reader.DecodeBuffer(buffer, width, height, width * elemSize, ImagePixelFormat.IPF_RGB_888);
if (results != null)
{
    Console.WriteLine("Total result count: " + results.Length);
    foreach (BarcodeResult result in results)
    {
        Console.WriteLine(result.BarcodeText);
    }
}

Build and run the program:

.NET barcode reader with OpenCV

API References

Source Code

https://github.com/dynamsoft-dbr/opencv-dotnet

The post Building .NET Barcode Reader with OpenCV and DBR 5.2 appeared first on Code Pool.


How to Build DotCode Reader in Java on Windows 10

$
0
0

A dot code is a 2D barcode symbology composed of disconnected dots. It is widely used in the tobacco industry. Recently, Dynamsoft rolled out barcode reader SDK v7.4, which added DotCode support. In this post, I will share a command-line app and a GUI app, demonstrating how to build Java DotCode reader on Windows 10.

Decoding DotCode in Java Command-Line App

The command-line app is simple. What I am going to do is to invoke an API to decode DotCode from an image file.

Configure Dynamsoft Barcode Reader in pom.xml:

  <repositories>
    <repository>
      <id>dbr</id>
      <url>https://download2.dynamsoft.com/maven/dbr/jar</url>
    </repository>
  </repositories>
  <dependencies>
    <dependency>
      <groupId>com.dynamsoft</groupId>
      <artifactId>dbr</artifactId>
      <version>7.4.0</version>
    </dependency>
  </dependencies>

To simply the running command, we can add a plugin to assemble all dependencies into one jar file:

  <build>
    <plugins>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
      </plugin>
    </plugins>
  </build>

Instantiate Dynamsoft Barcode Reader and set DotCode as the target barcode:

        BarcodeReader br = null;
        try {
            br = new BarcodeReader("LICENSE-KEY");
            br.initRuntimeSettingsWithString("{\"ImageParameter\":{\"Name\":\"BestCoverage\",\"DeblurLevel\":9,\"ExpectedBarcodesCount\":512,\"ScaleDownThreshold\":100000,\"LocalizationModes\":[{\"Mode\":\"LM_CONNECTED_BLOCKS\"},{\"Mode\":\"LM_SCAN_DIRECTLY\"},{\"Mode\":\"LM_STATISTICS\"},{\"Mode\":\"LM_LINES\"},{\"Mode\":\"LM_STATISTICS_MARKS\"}],\"GrayscaleTransformationModes\":[{\"Mode\":\"GTM_ORIGINAL\"},{\"Mode\":\"GTM_INVERTED\"}]}}", EnumConflictMode.CM_OVERWRITE);
            PublicRuntimeSettings runtimeSettings = br.getRuntimeSettings();
            runtimeSettings.barcodeFormatIds_2 = EnumBarcodeFormat_2.BF2_DOTCODE;
            br.updateRuntimeSettings(runtimeSettings);
        } catch (Exception e) {
            System.out.println(e);
            return;
        }

By default, the SDK will decode all supported barcode formats. If you want to focus on DotCode and speed up the decoding process, disable other 1D and 2D barcode formats:

runtimeSettings.barcodeFormatIds = EnumBarcodeFormat.BF_NULL;

Pass the file path to the decodeFile() function which will soon return the barcode results:

        TextResult[] results = null;
        try {
            results = br.decodeFile(filename, "");
        } catch (Exception e) {
            System.out.println("decode buffered image: " + e);
        }

Build and run the project:

mvn clean install assembly:assembly -Dmaven.test.skip=true

java -cp target/command-line-dotcode-1.0-SNAPSHOT-jar-with-dependencies.jar com.java.barcode.App test.png

A Webcam DotCode Reader Built with OpenCV Java and Java Swing

A GUI app needs more effort.

How to install OpenCV Java?

The OpenCV Java SDK contains a jar package and a shared library. For Windows users, you just need to install the pre-built package and find the OpenCV Java SDK at opencv-4.3\opencv\build\java. Since I’m using a Maven project, I have to install the jar file to the Maven local repository beforehand:

mvn install:install-file -Dfile=opencv-430.jar -DgroupId=org -DartifactId=opencv -Dversion=4.3.0 -Dpackaging=jar

Thereafter, add the configuration to pom.xml:

    <dependency>
      <groupId>org</groupId>
      <artifactId>opencv</artifactId>
      <version>4.3.0</version>
    </dependency>

What about the dll file? If you don’t put the dll in the right place, you will get the error log as loading the library:

Exception in thread "main" java.lang.UnsatisfiedLinkError: no opencv_java430 in java.library.path
        at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867)
        at java.lang.Runtime.loadLibrary0(Runtime.java:870)
        at java.lang.System.loadLibrary(System.java:1122)
        at com.java.barcode.App.main(App.java:65)

Here are workarounds for the issue.

Check the available java library path. Copy the dll file to current working directory or add the dll path to system environment PATH:

System.out.println(System.getProperty("java.library.path"));

Use the full path to load the library:

System.load("D:/opencv-4.3/opencv/build/java/x64/opencv_java430.dll");

Define the Java library path when running your Java app:

java -Djava.library.path=<dll path> -cp target/opencv-dotcode-1.0-SNAPSHOT-jar-with-dependencies.jar com.java.barcode.App

A “hello world” program using OpenCV Java

Once OpenCV is ready, you can test the library as follows:

System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Mat mat = Mat.eye(3, 3, CvType.CV_8UC1);
System.out.println("mat = " + mat.dump());

Display Webcam video stream in Java Swing component

Inspired by the OpenCV Java docs that guide JavaFX programming, I studied the OpenCV capture logic and rendered the video frames in a JLable:

public void updateViewer(final BufferedImage image) {
        if (!SwingUtilities.isEventDispatchThread()) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    mImage.setIcon(new ImageIcon(image));
                }
            });
            return;
        }
    }

Runnable frameGrabber = new Runnable() {

                    @Override
                    public void run() {
                        Mat frame = grabFrame();
                        byte[] data = Utils.matToByteArray(frame);

                        if (!status.get()) {
                            status.set(true);
                            barcodeTimer.schedule(new BarcodeRunnable(frame, mBarcodeReader, callback, status), 0, TimeUnit.MILLISECONDS);
                        }
                    
                        BufferedImage bufferedImage = Utils.byteToBufferedImage(data, frame.width(), frame.height(), frame.channels());
                        if (isRunning) updateViewer(bufferedImage);
                    }
                };
this.timer = Executors.newSingleThreadScheduledExecutor();
this.timer.scheduleAtFixedRate(frameGrabber, 0, 33, TimeUnit.MILLISECONDS);

Read DotCode and show results

In the code above, you can see I created a barcode timer instance for reading DotCode:

barcodeTimer = Executors.newSingleThreadScheduledExecutor();

We have to run the barcode decoding API in a worker thread in order to avoid decreasing the frame rate.

To draw the DotCode position, create a class CustomJLable that extends JLable:

    private ArrayList<Point[]> data = new ArrayList<>();

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g.create();
        if (data.size() > 0) {
            g2d.setColor(Color.RED);
            for (Point[] points : data) {
                for (int i = 0; i < points.length; ++i) {
                    if (i == 3) {
                        g2d.drawLine(points[i].x, points[i].y, points[0].x, points[0].y);
                    } else {
                        g2d.drawLine(points[i].x, points[i].y, points[i + 1].x, points[i + 1].y);
                    }
                }
            }

        }
        g2d.dispose();
    }

    public void appendPoints(Point[] points) {
        data.add(points);
    }

    public void clearPoints() {
        data.clear();
    }

Build and run the GUI DotCode reader:

mvn clean install assembly:assembly -Dmaven.test.skip=true
java -cp target/opencv-dotcode-1.0-SNAPSHOT-jar-with-dependencies.jar com.java.barcode.App
Java DotCode reader

Q&A

How to convert OpenCV Mat to Java byte array?

    public static byte[] matToByteArray(Mat original)
    {
        int width = original.width(), height = original.height(), channels = original.channels();
        byte[] sourcePixels = new byte[width * height * channels];
        original.get(0, 0, sourcePixels);
        return sourcePixels;
    }

How to convert Java byte array to Java BufferedImage?

    public static BufferedImage byteToBufferedImage(byte[] sourcePixels, int width, int height, int channels)
    {
        BufferedImage image = null;
        
        if (channels > 1)
        {
            image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
        }
        else
        {
            image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
        }
        final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
        System.arraycopy(sourcePixels, 0, targetPixels, 0, sourcePixels.length);
        
        return image;
    }

Source Code

https://github.com/yushulx/java-dotcode-reader

The post How to Build DotCode Reader in Java on Windows 10 appeared first on Code Pool.

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

$
0
0

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.

Prerequisites

Windows

Raspberry Pi

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("38B9B94D8B0E2B41660D13B593BE6EF9");
       __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

The post Real-time Webcam Barcode Detection with OpenCV and C++ appeared first on Code Pool.

How to Convert OpenCV Image Data from Python to C

$
0
0

OpenCV officially provides both C++ and Python APIs for developers. Most of the time, developers just need to use one kind of programming languages to read, write and process images with hundreds of computer vision algorithms. However, if you want to use OpenCV Python APIs with an extended C/C++ library, it will be tricky to pass the data. In this article, I will share how to read camera stream with OpenCV-Python and detect barcode with Dynamsoft C/C++ Barcode SDK.

webcam barcode reader with OpenCV Python

Development Environment

Python Extension for Reading Barcode from OpenCV Image Data

Installation

Copy DynamsoftBarcodeReaderx86.dll and cv2.pyd to Python27\Lib\site-packages.

What is the type of the frame data that output by OpenCV?

To convert the image data, we have to know what type it is. The type is numpy.ndarray:

> rval, frame = vc.read();
> print type(frame)
> <type 'numpy.ndarray'>

How to get the C/C++ pointer that pointing to numpy.ndarray?

According to the OpenCV source file opencv\modules\python\src2\cv2.cv.hpp, we can use the following code to get the memory address of the data in C:

    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

How to use the barcode detection API?

You can’t just pass the data pointer directly to DBR_DecodeBuffer(). The data needs to be reconstructed with some extra information:

    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];
    for (int i = 1; i <= height; i++) {
        memcpy(data, buffer + stride * (height - i), stride);
        data += stride;
    }

Read barcode from images and return results:

// 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;
    for (int i = 0; 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);

What if you see the error ‘Unable to find vcvarsall.bat’ when building Python extension on Windows?

According to the answer from StackOverflow, execute the following command based on the version of Visual Studio installed:

  • Visual Studio 2010 (VS10): SET VS90COMNTOOLS=%VS100COMNTOOLS%
  • Visual Studio 2012 (VS11): SET VS90COMNTOOLS=%VS110COMNTOOLS%
  • Visual Studio 2013 (VS12): SET VS90COMNTOOLS=%VS120COMNTOOLS%
  • Visual Studio 2015 (VS14): SET VS90COMNTOOLS=%VS140COMNTOOLS%

I’m using Visual Studio 2015, and thus I can build Python extension as follows:

SET VS90COMNTOOLS=%VS140COMNTOOLS%
python setup.py build install

Python Script for Testing

Open camera:

import cv2
from dbr import *
import time

vc = cv2.VideoCapture(0)

Read and render camera video stream:

cv2.imshow(windowName, frame)
rval, frame = vc.read();

Detect barcode from frame and show results in console:

initLicense("<license>") # Invalid license is fine.
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"

Source Code

https://github.com/yushulx/opencv-python-webcam-barcode-reader

 

The post How to Convert OpenCV Image Data from Python to C appeared first on Code Pool.

Raspberry Pi Barcode Scanner in Python

$
0
0

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.

Raspberry Pi Barcode Scanner in Python

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

  1. Download and extract the source code.
  2. 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
  3. 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 ..
  4. 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

  1. Download and extract the SDK package.
  2. Create a symbolic link for libDynamsoftBarcodeReader.so:
    sudo ln –s <Your dbr path>/lib/libDynamsoftBarcodeReader.so /usr/lib/libDynamsoftBarcodeReader.so
  3. 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'],
  4. 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\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?

  1. Connect a USB webcam to Raspberry Pi 2 or 3.
  2. 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

 

The post Raspberry Pi Barcode Scanner in Python appeared first on Code Pool.

Using OpenCV to Build Python Barcode Reader for macOS

$
0
0

This article is about how to use OpenCV and Dynamsoft Barcode Reader SDK to create a Python barcode reader on macOS.

How to Install OpenCV on macOS

Use ‘sw_vers’ to check macOS system version information:

check mac version

Install Homebrew.

If you have already installed Homebrew, just update it. When running ‘brew update’, you may see following errors.

Error: /usr/local/Library/brew.sh: line 32: /usr/local/Library/ENV/scm/git: No such file or directory.

To fix the error, run:

cd "$(brew --repository)" && git fetch && git reset --hard origin/master

Error: Fetching /usr/local/Library/Taps/flutter/homebrew-flutter failed!

To repair the error, run:

brew untap flutter/flutter

The next step is to install Python and NumPy. Python is pre-installed on macOS. The default version is not compatible with the latest OpenCV. Therefore, you need to install the latest Python using Homebrew.

brew install python python3 numpy
echo 'import site; site.addsitedir("/usr/local/lib/python2.7/site-packages")' >> /Users/xiao/Library/Python/2.7/lib/python/site-packages/homebrew.pth

Use command ‘python –version’ to check the current version. If it is not the latest version, you can edit .bash_profile and export the path:

vim ~/.bash_profile
export PATH=/usr/local/Cellar/python/2.7.13/bin:$PATH
source ~/.bash_profile

Install OpenCV:

brew tap homebrew/science
brew install opencv3

Python Barcode Reader for macOS

Get libDynamsoftBarcodeReader.dylib and relevant header files from DBR-Libs.zip.

To link the dynamic library and use barcode reading APIs, we need to write code in C/C++. Include the header files:

#include <Python.h>
#include "If_DBR.h"
#include "BarcodeFormat.h"
#include "BarcodeStructs.h"
#include "ErrorCode.h"
#include <ndarraytypes.h>

Where is ndarraytypes.h?
Use command ‘find / -name ndarraytypes.h’ to find it:

/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/numpy/core/include/numpy/ndarraytypes.h
/usr/local/Cellar/numpy/1.13.0/lib/python2.7/site-packages/numpy/core/include/numpy/ ndarraytypes.h
/usr/local/lib/python2.7/site-packages/numpy/core/include/numpy/ndarraytypes.h

Get native image data that decoded by OpenCV Python API:

    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;
    }

    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

Define BITMAPINFOHEADER structure. The DWORD defined by Microsoft is unsigned long, but here it is unsigned int. The size of the type should be 4 bytes.

typedef unsigned int DWORD;
typedef int LONG;
typedef unsigned short WORD;

#pragma pack(push)
#pragma pack(1)

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;

#pragma pack(pop)

Construct a buffer with bitmap header info for barcode detection.

int dib_header_size = sizeof(BITMAPINFOHEADER);

char *total = (char *)malloc(size + dib_header_size); // buffer size = image size + header size
memset(total, 0, size + dib_header_size);
BITMAPINFOHEADER bitmap_info = {dib_header_size, width, height, 0, 24, 0, size, 0, 0, 0, 0};
memcpy(total, &bitmap_info, dib_header_size);

// Copy image data to buffer from bottom to top
char *data = total + dib_header_size;
int stride = pai->strides[0];
int i = 1;
for (; i <= height; i++) {
    memcpy(data, buffer + stride * (height - i), stride);
    data += stride;
}
int iRet = DBR_DecodeBuffer((unsigned char *)total, size + dib_header_size, &ro, &pResults);

Get and return barcode 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);

Configure setup.py for building Python extension:

from distutils.core import setup, Extension
 
module_dbr = Extension('dbr', 
                        sources = ['dbr.c'], 
                        include_dirs=['/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/numpy/core/include/numpy', './include'],
                        library_dirs=['./lib'],
                        libraries=['DynamsoftBarcodeReader'])
 
setup (name = 'DynamsoftBarcodeReader',
        version = '1.0',
        description = 'Python barcode extension',
        ext_modules = [module_dbr])

Build and install dbr.so:

python setup.py build install

Write a simple Python barcode detection app:

import cv2
from dbr import *
import sys
import os.path

initLicense("D426ABF246933C82A16D537FC46C064F")
frame = cv2.imread(fileName, cv2.CV_LOAD_IMAGE_COLOR)
results = decodeBuffer(frame)

Note: when using imread, you have to set second parameter CV_LOAD_IMAGE_COLOR. The native API only works for a color image.

OpenCV Python barcode reader for macOS

Source Code

https://github.com/dynamsoft-dbr/mac-opencv

The post Using OpenCV to Build Python Barcode Reader for macOS appeared first on Code Pool.

Viewing all 26 articles
Browse latest View live