使用OpenCV对二维码/条形码进行矫正

使用OpenCV对二维码/条形码进行矫正

OpenCV提供了很多图像处理的API,我们可以利用这些API做一些矫正四边形物体比如二维码/条码的工作。

大概过程如下:

resize(图像尺寸缩小)->threshold(二值化)->erode(几次膨胀腐蚀)->HoughLines(寻找直线)->筛除出二维码/一维码的边线,计算出边线的倾斜角度->warpAffine(对原图像进行仿射变换)

下面贴具体的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
void correctImage(unsigned char *nv21, int width, int height, unsigned char *dest) {

int resizeWidth = width/2;
int resizeHeight = height/2;

//初始化需要使用的Mat
Mat imgMat(height * 3 / 2, width, CV_8UC1, nv21);
//灰度图Mat
Mat grayMat(height, width, CV_8UC1);
//最终结果的Mat
Mat resultMat(height, width, CV_8UC1,dest);
//过程Mat
Mat innerMat(resizeHeight, resizeWidth, CV_8UC1);
Mat binMat(resizeHeight, resizeWidth, CV_8UC1);

//将yuv420sp转为灰度图
cvtColor(imgMat, grayMat, CV_YUV420sp2GRAY);

//缩小图像尺寸以减少后面图像处理工作的耗时
resize(grayMat, innerMat, Size(resizeWidth, resizeHeight));

//自适应二值化参数
int blockSize = 3;
int constValue = 5;
const int maxVal = 255;

//自适应二值化
adaptiveThreshold(innerMat, binMat, maxVal,ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY,
blockSize, constValue);

int rectWidth = resizeWidth / 5;
int rectHeight = resizeHeight / 5;
int centerX = resizeWidth / 2, centerY = resizeHeight / 2;

Mat element = getStructuringElement(2, Size(7, 7));

//膨胀腐蚀
for (int i = 0; i < 2; i++) {
erode(innerMat, innerMat, element);
i++;
}

erode(innerMat, binMat, element);
binMat = innerMat - binMat;

//寻找直线
vector<Vec2f> lines;
HoughLines(binMat, lines, 1, CV_PI / 150, 90, 0, 0);
LOGV("OpenCV_CorrectImage寻找边线,边线数量:%d", lines.size());

//由于边线可能有很多,这里最多取8条边线来计算角度
int lineNum = lines.size() > 8 ? 8 : lines.size();
float sum = 0;

//num参数记录倾斜的线条的数量
int num = 0;
for (int i = 0; i < lineNum; i++) {

float theta = lines[i][1];
//各个角度对应的theta值,相当于:角度/180*PI
//90->1.5708
//100 -> 1.7453
//80 -> 1.3963
//95->1.6580
//85->1.4835
//0 ->0
//5->0.0872
//10 -> 0.1745
//12 ->0.209
//15 ->0.2618
//180-> 3.1415
//170 ->2.967

// 过滤掉角度正常的,0-15度,80-100 ,170-180
if ((theta >= 0 && theta <= 0.2618) || (theta >= 1.3963 && theta <= 1.7453) ||
(theta >= 2.967 && theta <= 3.1416)) {
} else {
if (theta >= 1.5708)
theta = theta - 1.5708;
LOGV("OpenCV_CorrectImage寻找边线,角度:%f", theta);
sum += theta;
num += 1;
}
}

//需要矫正
if (num > 0) {
float average = sum / num;
//转成角度
double angle = average / CV_PI * 180;
LOGV("OpenCV_CorrectImage寻找边线,角度:%f", angle);

//如果矫正角度大于5才矫正
if (angle > 5) {
Point2f center;
center.x = float(width / 2.0);
center.y = float(height / 2.0);
Mat M = getRotationMatrix2D(center, angle, 1);
//仿射变换,背景色填充为黑色
warpAffine(grayMat, resultMat, M, resultMat.size(), 1, 0, Scalar(255));
LOGV("OpenCV_CorrectImage角度变换完成");
}
}
}

OpenCV很多图像处理的API有各种各样的参数,不同的参数会适合不同的场景,所以以上代码也不可能适应所有场景下的二维码/条码图片。

#
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×