標準二維碼的識別
libdmtx 配置
Libdmtx 是一個專門用於識別 datamatrix 二維碼的庫。搭配Opencv 可以較爲準確識別工業二維碼 ECC200(關於二維碼的編碼種類以及 ECC200,自行 google/百度)。接下來是 libdmtx 在VS2013 中的配置,以及簡單的測試用例。
1. 下載libdmtx
進入網站https://sourceforge.net/p/libdmtx/libdmtx/ci/master/tree/ 在左側標 籤區域選擇版本,下載最新版v0.7.4。
2. 編譯代碼生成 libdmtx.lib 和libdmtx.dll 文件
在編譯時發現v0.7.4版本缺少工程目錄。解決辦法:下載v0.7.2版本解壓,將project和wrapper文件夾拷到0.7.4的源碼包裏。用VS2013打開project工程目錄下的libdmtx.sln。將工程libdmtx設置爲當前啓動項,編譯,在Debug目錄下生成libmtx.lib和libmtx.dll文件。
3. Libdmtx+Opencv測試
VS下新建空項目工程libdmtxTest。將生成的libmtx.lib libmtx.dll文件以及dmtx.h文件拷貝到工程目錄下,將dmtx.h添加添加至頭文件。在工程屬性頁->鏈接器->輸入->附加依賴中加入libdmtx.lib
然後添加libdmtxTest.cpp文件,輸入以下代碼:
#include <iostream>
#include "dmtx.h"
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
using namespace std;
using namespace cv;
int main()
{
DmtxMessage *msg;
DmtxRegion *reg;
Mat src = imread("data_matrix_encode.jpg");
if (!src.data){
cout << "Load image failed!" << endl;
return 0;
}
DmtxImage *img;
img = dmtxImageCreate(src.data, src.cols, src.rows, DmtxPack24bppRGB);
DmtxDecode *dec = dmtxDecodeCreate(img, 1);
reg = dmtxRegionFindNext(dec, NULL);
if (reg != NULL) {
msg = dmtxDecodeMatrixRegion(dec, reg, DmtxUndefined);
if (msg != NULL) {
cout << msg->output << endl;
dmtxMessageDestroy(&msg);
}
dmtxRegionDestroy(®);
}
dmtxDecodeDestroy(&dec);
dmtxImageDestroy(&img);
return 0;
}
運行結果如下:
注意:data_matrix_encode.jpg是位於工程目錄下的ECC200二維碼圖片。
非標準二維碼識別
以上二維碼的識別要求二維碼圖像清晰且角度標準,若圖像發生一定角度的旋轉該如何識別?
基本思路:
-將圖像二值化
-對圖像進行膨脹操作
-尋找二維碼四條邊界輪廓線
-利用角點檢測算法得出四條直線相交的四個點的座標
-利用得到的四個點座標將圖像進行仿射變換得到校正的二維碼圖片
-對校正後的圖片進行識別
爲節約篇幅,只貼出校正函數代碼:
void ImgCorrection(Mat imageSource)
{
Mat image;
imageSource.copyTo(image);
GaussianBlur(image, image, Size(3, 3), 0); //濾波
threshold(image, image, 100, 255, CV_THRESH_BINARY); //二值化
imshow("二值化", image);
Mat element = getStructuringElement(2, Size(7, 7)); //膨脹腐蝕核
dilate(image, image, element);
imshow("膨脹", image);
Mat image1;
Laplacian(image, image1, image.depth(), 1);//拉普拉斯變換尋找邊界
imshow("邊界", image1);
//尋找直線
vector<Vec2f>lines;
HoughLines(image1, lines, 1, CV_PI / 150, 60, 0, 0);
Mat DrawLine = Mat::zeros(image1.size(), CV_8UC1);
for (int i = 0; i<lines.size(); i++)
{
float rho = lines[i][0];
float theta = lines[i][1];
Point pt1, pt2;
double a = cos(theta), b = sin(theta);
double x0 = a*rho, y0 = b*rho;
pt1.x = cvRound(x0 + 1000 * (-b));
pt1.y = cvRound(y0 + 1000 * a);
pt2.x = cvRound(x0 - 1000 * (-b));
pt2.y = cvRound(y0 - 1000 * a);
line(DrawLine, pt1, pt2, Scalar(255), 1, CV_AA);
}
imshow("直線", DrawLine);
Point2f P1[4];
Point2f P2[4];
vector<Point2f>corners;
goodFeaturesToTrack(DrawLine, corners, 4, 0.1, 10, Mat()); //角點檢測
cout << "角點座標:" << endl;
for (int i = 0; i<corners.size(); i++)//四個角點的座標
{
circle(DrawLine, corners[i], 3, Scalar(255), 3);
P1[i] = corners[i];
cout << corners[i].x << " " << corners[i].y << endl;
}
imshow("交點", DrawLine);
P2[0] = Point2f(0, 0);
P2[1] = Point2f(0, imageSource.rows);
P2[2] = Point2f(imageSource.cols, imageSource.rows);
P2[3] = Point2f(imageSource.cols, 0);
Mat elementTransf;
elementTransf = getAffineTransform(P1, P2);
warpAffine(imageSource, imageSource, elementTransf, imageSource.size(), 1, 0, Scalar(255));
imwrite("corrImge.jpg", imageSource);//校正後的圖片保存
}
運行結果如下:
校正後的圖:
識別結果: