-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathQR_test_q.cpp
378 lines (321 loc) · 14.6 KB
/
QR_test_q.cpp
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
#include <iostream>
#include <opencv2/opencv.hpp>
#include <zbar.h>
using namespace std;
using namespace zbar; //添加zbar名称空间
using namespace cv;
Mat src;
Mat src_gray;
vector<double> qrcenter(2,0);
vector<int>img_size(2,0);
RNG rng(12345);
//Scalar colorful = CV_RGB(rng.uniform(0,255),rng.uniform(0,255),rng.uniform(0,255));
//获取轮廓的中心点
Point Center_cal(vector<vector<Point> > contours, int i) {
int centerx = 0, centery = 0, n = static_cast<int>(contours[i].size());
//在提取的小正方形的边界上每隔周长个像素提取一个点的坐标,
//求所提取四个点的平均坐标(即为小正方形的大致中心)
centerx = (contours[i][n / 4].x + contours[i][n * 2 / 4].x + contours[i][3 * n / 4].x + contours[i][n - 1].x) / 4;
centery = (contours[i][n / 4].y + contours[i][n * 2 / 4].y + contours[i][3 * n / 4].y + contours[i][n - 1].y) / 4;
Point point1 = Point(centerx, centery);
return point1;
}
Point decetecterweima(cv::Mat src);
void QRCode_Recognize(String s){
ImageScanner scanner;
scanner.set_config(ZBAR_NONE, ZBAR_CFG_ENABLE, 1);
Mat image = imread(s);
Mat imageGray;
cvtColor(image,imageGray,CV_RGB2GRAY);
int width = imageGray.cols;
int height = imageGray.rows;
auto *raw = imageGray.data;
Image imageZbar(static_cast<unsigned int>(width), static_cast<unsigned int>(height), "Y800", raw,
static_cast<unsigned long>(width * height));
scanner.scan(imageZbar); //扫描条码
Image::SymbolIterator symbol = imageZbar.symbol_begin();
if(imageZbar.symbol_begin()==imageZbar.symbol_end())
{
cout<<"查询条码失败,请检查图片!"<<endl;
}
for(;symbol != imageZbar.symbol_end();++symbol)
{
cout<<"类型:"<<endl<<symbol->get_type_name()<<endl<<endl;
cout<<"条码:"<<endl<<symbol->get_data()<<endl<<endl;
}
imshow("Source Image",image);
waitKey();
imageZbar.set_data(nullptr,0);
}
int main(int argc, char *argv[]) {
cout<<"test"<<endl;
src = imread("/media/q/neu/dataset/KITTI2/data_odometry_color/dataset/sequences/01/image_2/000000.png", 1);
// decetecterweima(src);
// return 0;
Mat src_all = src.clone();
cout<<"test"<<endl;
//彩色图转灰度图
cvtColor(src, src_gray, CV_BGR2GRAY);
//对图像进行平滑处理
blur(src_gray, src_gray, Size(3, 3));
//使灰度图象直方图均衡化
equalizeHist(src_gray, src_gray);
namedWindow("src_gray");
imshow("src_gray", src_gray);
Scalar color = Scalar(1, 1, 255);
Mat threshold_output;
vector<vector<Point> > contours, contours2;
vector<Vec4i> hierarchy;
Mat drawing = Mat::zeros(src.size(), CV_8UC3);
Mat drawing2 = Mat::zeros(src.size(), CV_8UC3);
Mat drawingAllContours = Mat::zeros(src.size(), CV_8UC3);
//指定112阀值进行二值化
threshold(src_gray, threshold_output, 112, 255, THRESH_BINARY);
namedWindow("Threshold_output");
imshow("Threshold_output", threshold_output);
/*查找轮廓
* 参数说明
输入图像image必须为一个2值单通道图像
contours参数为检测的轮廓数组,每一个轮廓用一个point类型的vector表示
hiararchy参数和轮廓个数相同,每个轮廓contours[ i ]对应4个hierarchy元素hierarchy[ i ][ 0 ] ~hierarchy[ i ][ 3 ],
分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有对应项,该值设置为负数。
mode表示轮廓的检索模式
CV_RETR_EXTERNAL 表示只检测外轮廓
CV_RETR_LIST 检测的轮廓不建立等级关系
CV_RETR_CCOMP 建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。
CV_RETR_TREE 建立一个等级树结构的轮廓。具体参考contours.c这个demo
method为轮廓的近似办法
CV_CHAIN_APPROX_NONE 存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
CV_CHAIN_APPROX_SIMPLE 压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS 使用teh-Chinl chain 近似算法
offset表示代表轮廓点的偏移量,可以设置为任意值。对ROI图像中找出的轮廓,并要在整个图像中进行分析时,这个参数还是很有用的。
*/
findContours(threshold_output, contours, hierarchy, CV_RETR_TREE, CHAIN_APPROX_NONE, Point(0, 0));
cout<<"contours.size()"<<contours.size()<<endl;
int c = 0, ic = 0, k = 0, area = 0;
//通过黑色定位角作为父轮廓,有两个子轮廓的特点,筛选出三个定位角
namedWindow("DrawingAllContours2");
int parentIdx = -1;
for (int i = 0; i < contours.size(); i++)//contours的数据结构为:大圈的下一个数据就是小圈
{
// cout<<"contours[i].size()"<<contours[i].size()<<endl;
//画出所以轮廓图
Mat drawingAllContours2 = Mat::zeros(src.size(), CV_8UC3);
drawContours(drawingAllContours2, contours, i, CV_RGB(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), 1, 8);
imshow("DrawingAllContours2", drawingAllContours2);
waitKey(0);
if (hierarchy[i][2] != -1 && ic == 0) {//i个轮廓的后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,无则为-1
parentIdx = i;
ic++;
if(contours[i][0].x==0 && contours[i][0].y==0)
ic=0;
cout<<"i="<<i<<" contours[i].size()"<<contours[i].size()<<endl;
} else if (hierarchy[i][2] != -1) {
ic++;
// parentIdx = i; //可以避掉最外面大框的影响
} else if (hierarchy[i][2] == -1) {
ic = 0;
parentIdx = -1;
}
//有两个子轮廓
if (ic >= 2) {
//保存找到的三个黑色定位角
contours2.push_back(contours[parentIdx]);
//画出三个黑色定位角的轮廓
drawContours(drawing, contours, parentIdx,
CV_RGB(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), 1, 8);
ic = 0;
parentIdx = -1;
}
}
//填充的方式画出三个黑色定位角的轮廓
for (int i = 0; i < contours2.size(); i++)
drawContours(drawing2, contours2, i,
CV_RGB(rng.uniform(100, 255), rng.uniform(100, 255), rng.uniform(100, 255)), -1, 4,
hierarchy[k][2], 0, Point());
//获取三个定位角的中心坐标
Point point[3];
for (int i = 0; i < contours2.size(); i++) {
point[i] = Center_cal(contours2, i);
circle(src_all,point[i] ,4,cv::Scalar(0,0,255),2);
}
//计算轮廓的面积,计算定位角的面积,从而计算出边长
area = static_cast<int>(contourArea(contours2[1]));
int area_side = cvRound(sqrt(double(area)));
for (int i = 0; i < contours2.size(); i++) {
//画出三个定位角的中心连线
line(drawing2, point[i % contours2.size()], point[(i + 1) % contours2.size()], color, area_side / 2, 8);
}
namedWindow("DrawingAllContours");
imshow("DrawingAllContours", drawingAllContours);
namedWindow("Drawing2");
imshow("Drawing2", drawing2);
namedWindow("Drawing");
imshow("Drawing", drawing);
//接下来要框出这整个二维码
Mat gray_all, threshold_output_all;
vector<vector<Point> > contours_all;
vector<Vec4i> hierarchy_all;
cvtColor(drawing2, gray_all, CV_BGR2GRAY);
threshold(gray_all, threshold_output_all, 45, 255, THRESH_BINARY);
findContours(threshold_output_all, contours_all, hierarchy_all, RETR_EXTERNAL, CHAIN_APPROX_NONE,
Point(0, 0));//RETR_EXTERNAL表示只寻找最外层轮廓
Point2f fourPoint2f[4];
//求最小包围矩形
RotatedRect rectPoint = minAreaRect(contours_all[0]);//返回包覆输入信息的最小斜矩形。如下图:
Rect myRect = boundingRect(contours_all[0]);//返回包覆输入信息的最小正矩形
//将rectPoint变量中存储的坐标值放到 fourPoint的数组中
rectPoint.points(fourPoint2f);
for (int i = 0; i < 4; i++) {
line(src_all, fourPoint2f[i % 4], fourPoint2f[(i + 1) % 4], Scalar(20, 21, 237), 1);
}
circle(src_all,rectPoint.center,4,cv::Scalar(0,0,255),2);
namedWindow("Src_all");
imshow("Src_all", src_all);
char resultFileNameSring[100];
sprintf(resultFileNameSring, "QRCode_Locate_result.png");
Mat resultImage = Mat(src_all, myRect);
imwrite(resultFileNameSring, resultImage);
//框出二维码后,就可以提取出二维码,然后使用解码库zxing,解出码的信息。
//或者研究二维码的排布规则,自己写解码部分
QRCode_Recognize(resultFileNameSring);
waitKey(0);
return (0);
}
Point decetecterweima(cv::Mat src) {
qrcenter[0]=0;//先初始化二维码中心为0
qrcenter[1]=0;
Mat src_gray;
RNG rng(12345);
Mat src_all = src.clone();
// Mat bigImage;
// resize(src, bigImage, Size(src.cols * 2, src.rows * 2));
// src=bigImage.clone();
//彩色图转灰度图
cvtColor(src, src_gray, CV_BGR2GRAY);
//对图像进行平滑处理
blur(src_gray, src_gray, Size(2, 2));
//使灰度图象直方图均衡化
equalizeHist(src_gray, src_gray);
// namedWindow("src_gray");
// imshow("src_gray", src_gray);
// waitKey(1);
Scalar color = Scalar(1, 1, 255);
Mat threshold_output;
vector<vector<Point> > contours, contours2;
vector<Vec4i> hierarchy;
Mat drawing = Mat::zeros(src.size(), CV_8UC3);
Mat drawing2 = Mat::zeros(src.size(), CV_8UC3);
Mat drawingAllContours = Mat::zeros(src.size(), CV_8UC3);
cv::Mat img_cut = src_gray(cv::Rect(0,int(src_gray.rows/4),src_gray.cols,int(src_gray.rows*2/4)));
src_gray=img_cut;
//指定112阀值进行二值化
threshold(src_gray, threshold_output, 35, 255, THRESH_BINARY);
// adaptiveThreshold(src_gray,threshold_output,255,ADAPTIVE_THRESH_MEAN_C,THRESH_BINARY,5,10);// adaptiveThreshold(src_gray, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 11, 2)
namedWindow("Threshold_output");
imshow("Threshold_output", threshold_output);
waitKey(1);
cv::Mat img_cut2 = src_all(cv::Rect(0,int(src_all.rows/4),src_all.cols,int(src_all.rows*2/4)));
src_all=img_cut2;
findContours(threshold_output, contours, hierarchy, CV_RETR_TREE, CHAIN_APPROX_NONE, Point(0, 0));
cout<<"contours.size()"<<contours.size()<<endl;
int c = 0, ic = 0, k = 0, area = 0;
int parentIdx = -1;
for (int i = 1; i < contours.size(); i++)
{
//drawContours(drawingAllContours, contours, parentIdx, CV_RGB(255, 255, 255), 1, 8);
if (hierarchy[i][2] != -1 && ic == 0) {
parentIdx = i;
ic++;
} else if (hierarchy[i][2] != -1) {
ic++;
} else if (hierarchy[i][2] == -1) {
ic = 0;
parentIdx = -1;
}
//有两个子轮廓
if (ic >= 2) {
//保存找到的三个黑色定位角
contours2.push_back(contours[parentIdx]);
//画出三个黑色定位角的轮廓
drawContours(drawing, contours, parentIdx,
CV_RGB(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), 1, 8);
ic = 0;
parentIdx = -1;
}
}
//填充的方式画出三个黑色定位角的轮廓
for (int i = 0; i < contours2.size(); i++)
drawContours(drawing2, contours2, i,
CV_RGB(rng.uniform(100, 255), rng.uniform(100, 255), rng.uniform(100, 255)), -1, 4,
hierarchy[k][2], 0, Point());
//获取三个定位角的中心坐标
Point point[3];
// ROS_INFO("1.0");
// Point centerpoint;
for (int i = 0; i < contours2.size(); i++) {
point[i] = Center_cal(contours2, i);
// centerpoint.x+=point[i].x;
// centerpoint.y+=point[i].y;
circle(src_all,point[i] ,4,cv::Scalar(0,0,255),2);
}
if (contours2.size()==0||contours2.size()!=3) {
point[0].x=0;
point[0].y=0;
return point[0];
}
// centerpoint.x=centerpoint.x/contours2.size();
// centerpoint.x=centerpoint.y/contours2.size();
// circle(src_all,centerpoint ,4,cv::Scalar(0,0,255),2);
if (contours2.size()==1){
namedWindow("Src_all");
imshow("Src_all", src_all);
return point[0];
}
// cout<<contours2.size()<<endl;
//计算轮廓的面积,计算定位角的面积,从而计算出边长
// cout<<1<<endl;
area = static_cast<int>(contourArea(contours2[1]));
// cout<<1.111<<endl;
int area_side = cvRound(sqrt(double(area)));
// cout<<3.11<<endl;
for (int i = 0; i < contours2.size(); i++) {
//画出三个定位角的中心连线
line(drawing2, point[i % contours2.size()], point[(i + 1) % contours2.size()], color, area_side / 2, 8);
}
namedWindow("DrawingAllContours");
imshow("DrawingAllContours", drawingAllContours);
//
// namedWindow("Drawing2");
// imshow("Drawing2", drawing2);
//
// namedWindow("Drawing");
// imshow("Drawing", drawing);
//接下来要框出这整个二维码
Mat gray_all, threshold_output_all;
vector<vector<Point> > contours_all;
vector<Vec4i> hierarchy_all;
cvtColor(drawing2, gray_all, CV_BGR2GRAY);
threshold(gray_all, threshold_output_all, 45, 255, THRESH_BINARY);
findContours(threshold_output_all, contours_all, hierarchy_all, RETR_EXTERNAL, CHAIN_APPROX_NONE,
Point(0, 0));//RETR_EXTERNAL表示只寻找最外层轮廓
// cout<<5<<endl;
Point2f fourPoint2f[4];
// cout<<"hhhhh"<<endl;
//求最小包围矩形
RotatedRect rectPoint = minAreaRect(contours_all[0]);
circle(src_all,rectPoint.center,4,cv::Scalar(0,0,255),2);//画出矩形中心
qrcenter[0]=rectPoint.center.x;
qrcenter[1]=rectPoint.center.y;
Rect myRect = boundingRect(contours_all[0]);
//将rectPoint变量中存储的坐标值放到 fourPoint的数组中
rectPoint.points(fourPoint2f);
// Scalar用于设置图像框的颜色
for (int i = 0; i < 4; i++) {
line(src_all, fourPoint2f[i % 4], fourPoint2f[(i + 1) % 4], Scalar(20, 21, 237), 1);
}
// namedWindow("Src_all");
imshow("Src_all", src_all);
waitKey(0);
return point[0];
}