用OpenCV读取条码图像,并利用EAN-13码的编码方式解码。
通过读入一张条码图像,识别对应的条码。
参考自 http://felix.abecassis.me/2011/10/opencv-barcode-reader-part-1/
/*version 0.01:
* 只是把upc的识别换成了ean的识别
* 第一个数字只能识别6或者9
* 图像要求为只包含条码
* 清晰度要求太高,500w手机拍照的照片不能完全识别
*----
* ChriZZ 2013.5.5
*/
1 #include
2 #include
通过改进测量方法,用数学的手段减小了误差,提高了识别率,代码如下
/*version 0.02
*提高了识别精度
*第一位字符通过左侧6个数据反推得到,不仅仅限定于6和9
*------
* ChrisZZ 2012.5.5
*/
1 #include
2 #include
目前把摄像头调用和条码图片检测联系在一起,发现有问题,矩形区域的确认还没做好。。使用了多边形。
1 #include
2 #include
今天打开Qt发现Qt抽了。。程序一直报错。把复杂的程序都注释了只剩下读入和显示一张图片的代码结果仍然报错。我确实有清理过项目和重新构建项目。诶,蛋疼。重新建立一个工程写吧。。
代码:读入图片,检测、圈出并截图显示 :宽度在50-280之间的矩形框
1 #include "opencv2/core/core.hpp"
2 #include "opencv2/imgproc/imgproc.hpp"
3 #include "opencv2/highgui/highgui.hpp"
4
5 #include
6 #include
7 #include <string.h>
8
9 using namespace cv;
10 using namespace std;
11
12
13 #define SPACE 0
14 #define BAR 255
15
16 typedef Mat_ MatU;
17 map<string, int> table[3];
18 enum position{LEFT,RIGHT};
19 int front; //Æðʼ±àºÅ
20 int mode[6]; //²»Í¬µÄÆðʼ±àºÅ¶ÔÓ¦×Ų»Í¬µÄ×ó²à±àÂëģʽ£¬±ÈÈçÆðʼ±àºÅΪ6¶ÔÓ¦¡°ÆæżżżÆæÆ桱£¬9¶ÔÓ¦¡°ÆæżżÆæżÆ桱¡£ÓÃ1±íʾÆæÊý£¬0±íʾżÊý
21 const double eps=1e-5;
22 int z;
23
24 int get_front(){
25 string tmp="";
26 int i;
27 for(i=0; i<6; i++){
28 if(mode[i]==0) tmp=tmp+"0";
29 else tmp=tmp+"1";
30 }
31 if(tmp=="000000") return 0;
32 else if(tmp=="001011") return 1;
33 else if(tmp=="001101") return 2;
34 else if(tmp=="001110") return 3;
35 else if(tmp=="010011") return 4;
36 else if(tmp=="011001") return 5;
37 else if(tmp=="011100") return 6;
38 else if(tmp=="010101") return 7;
39 else if(tmp=="010110") return 8;
40 else if(tmp=="011010") return 9;
41 else return -1;
42 }
43
44 void align_boundary(const MatU& img, Point& cur, int begin, int end){
45 if (img(cur) == end){
46 while (img(cur)==end)
47 ++cur.x;
48 }else{
49 while (img(cur.y, cur.x-1)==begin)
50 --cur.x;
51 }
52 }
53
54 /*int read_digit(...)
55 *·µ»Ø½âÎöºóµÃµ½µÄÊý×Ö*/
56 int read_digit(const MatU& img, Point& cur, int position){
57 // Read the 7 consecutive bits.
58 int pattern[4] = {0,0,0,0};
59 int i;
60 for (i=0; i<4; i++){
61 int cur_val=img(cur);
62 while(img(cur)==cur_val){
63 ++pattern[i];
64 ++cur.x;
65 }
66 cout << endl;
67 cout << "pattern[" << i << "]=" << pattern[i] << endl;
68 // See below for explanation.
69 /* if ((pattern[i] == 1 && img(cur) == BAR) || (pattern[i] == unit_width - 1 && img(cur) == SPACE))
70 --cur.x;*/
71 }
72
73
74
75 // Convert to binary, consider that a bit is set if the number of
76 // bars encountered is greater than a threshold.
77 double sum=pattern[0]+pattern[1]+pattern[2]+pattern[3];
78 double tmp1=(pattern[0]+pattern[1])*1.0;
79 double tmp2=(pattern[1]+pattern[2])*1.0;
80 int at1, at2;
81 if(tmp1/sum < 2.5/7) at1=2;
82 else if(tmp1/sum < 3.5/7) at1=3;
83 else if(tmp1/sum < 4.5/7) at1=4;
84 else at1=5;
85
86 if(tmp2/sum < 2.5/7) at2=2;
87 else if(tmp2/sum < 3.5/7) at2=3;
88 else if(tmp2/sum < 4.5/7) at2=4;
89 else at2=5;
90
91 int digit=-1;
92
93 if(position==LEFT){
94 if(at1==2){
95 if(at2==2) {
96 mode[z++]=0;
97 digit = 6;
98 }
99 else if(at2==3) {
100 mode[z++]=1;
101 digit = 0;
102 }
103 else if(at2==4) {
104 mode[z++]=0;
105 digit = 4;
106 }
107 else if(at2==5) {
108 mode[z++]=1;
109 digit = 3;
110 }
111 }
112 else if(at1==3){
113 if(at2==2) {
114 mode[z++]=1;
115 digit = 9;
116 }
117 else if(at2==3) {
118 mode[z++]=0;
119 if(pattern[2]+13]) digit = 8;
120 else digit = 2;
121 }
122 else if(at2==4) {
123 mode[z++]=1;
124 if(pattern[1]+12]) digit = 7;
125 else digit = 1;
126 }
127 else if(at2==5) {
128 mode[z++]=0;
129 digit = 5;
130 }
131 }
132 else if(at1==4){
133 if(at2==2) {
134 mode[z++]=0;
135 digit = 9;
136 }
137 else if(at2==3) {
138 mode[z++]=1;
139 if(pattern[1]+10]) digit = 8;
140 else digit = 2;
141 }
142 else if(at2==4) {
143 mode[z++]=0;
144 if(pattern[0]+11]) digit = 7;
145 else digit = 1;
146 }
147 else if(at2==5) {
148 mode[z++]=1;
149 digit = 5;
150 }
151 }
152 else if(at1==5){
153 if(at2==2) {
154 mode[z++]=1;
155 digit = 6;
156 }
157 else if(at2==3) {
158 mode[z++]=0;
159 digit = 0;
160 }
161 else if(at2==4) {
162 mode[z++]=1;
163 digit = 4;
164 }
165 else if(at2==5) {
166 mode[z++]=0;
167 digit=3;
168 }
169 }
170 // align_boundary(img, cur, SPACE, BAR);
171 }else{
172 if(at1==2){
173 if(at2==2) digit = 6;
174 else if(at2==4) digit = 4;
175 }
176 else if(at1==3){
177 if(at2==3) {
178 if(pattern[2]+13]) digit = 8;
179 else digit = 2;
180 }
181 else if(at2==5) digit = 5;
182 }
183 else if(at1==4){
184 if(at2==2) digit = 9;
185 else if(at2==4) {
186 if(pattern[0]+11]) digit = 7;
187 else digit = 1;
188 }
189 }
190 else if(at1==5){
191 if(at2==3) digit = 0;
192 else if(at2==5) digit=3;
193 }
194 // align_boundary(img, cur, SPACE, BAR);
195 }
196 cout << "digit=" << digit << endl;
197 return digit;
198 }
199
200 void skip_quiet_zone(const MatU& img, Point& cur){//ÂÔ¹ý¿Õ°×ÇøÓò
201 while (img(cur) == SPACE)
202 ++cur.x;
203 }
204
205 void read_lguard(const MatU& img, Point& cur){//ͨ¹ý¶ÁÈ¡×ó²à¹Ì¶¨µÄ¡°Ìõ¿ÕÌõ¡±£¬»ñÈ¡µ¥Î»³¤¶È¡£
206 int pattern[3] = { BAR, SPACE, BAR };
207 for (int i=0; i<3; i++)
208 while (img(cur)==pattern[i])
209 ++cur.x;
210 }
211
212 void skip_mguard(const MatU& img, Point& cur){ //ÂÔ¹ý×ó²àÊý¾ÝºÍÓÒ²àÊý¾ÝÖ®¼äµÄ·Ö½ç
213 int pattern[5] = { SPACE, BAR, SPACE, BAR, SPACE };
214 for (int i=0; i<5; i++)
215 while (img(cur)==pattern[i])
216 ++cur.x;
217 }
218
219 bool isBar(MatU& img){
220 Size size = img.size();
221 Point cur(0, size.height / 2);
222 int cnt=0;//count the number of BAR-and-SPACE regions
223 if(img(cur)!=SPACE){
224 cnt=0;
225 return false;
226 }else{
227 while(img(cur)==SPACE)
228 cur.x++;
229 int statue=SPACE;
230 while(cur.x<img.cols){
231 if(img(cur)!=statue)
232 cnt++;
233 if(cnt>20) return true;
234 }
235 return false;
236 }
237 }
238
239 void read_barcode(MatU& img/*const string& filename*/){ //¶ÁÈ¡ÌõÂëÖ÷³ÌÐò
240
241 // if(isBar(img)) //isBar():judge weather img is a barcode region or not
242 // return;
243
244 z=0;
245 // MatU img = imread(filename, 0); //ÔØÈëͼÏñ
246 Size size = img.size();
247 Point cur(0, size.height / 2); //cur±íʾµ±Ç°Î»ÖÃ
248
249 bitwise_not(img, img);
250 threshold(img, img, 128, 255, THRESH_BINARY);
251
252 if (img(cur) != SPACE) return;
253
254 skip_quiet_zone(img, cur);
255
256 read_lguard(img, cur);
257
258 vector<int> digits;
259 for (int i=0; i<6; i++){ //×ó²àÊý¾Ý½âÂë
260 int d = read_digit(img, cur, LEFT);
261 digits.push_back(d);
262 }
263
264 skip_mguard(img, cur);
265
266 for (int i = 0; i < 6; i++){ //ÓÒ²àÊý¾Ý½âÂë
267 int d = read_digit(img, cur, RIGHT);
268 digits.push_back(d);
269 }
270 // cout << front; //Êä³ö½âÂë½á¹û
271 int front=get_front();
272 cout << front << " ";
273 for (int i = 0; i < 12; i++)
274 cout << digits[i] << " ";
275 cout << endl;
276 //waitKey();
277 }
278
279 static void help()
280 {
281 cout <<
282 "\nA program using pyramid scaling, Canny, contours, contour simpification and\n"
283 "memory storage (it's got it all folks) to find\n"
284 "squares in a list of images pic1-6.png\n"
285 "Returns sequence of squares detected on the image.\n"
286 "the sequence is stored in the specified memory storage\n"
287 "Call:\n"
288 "./squares\n"
289 "Using OpenCV version %s\n" << CV_VERSION << "\n" << endl;
290 }
291
292
293 int thresh = 50, N = 11;
294 const char* wndname = "Square Detection Demo";
295
296 // helper function:
297 // finds a cosine of angle between vectors
298 // from pt0->pt1 and from pt0->pt2
299 static double angle( Point pt1, Point pt2, Point pt0 )
300 {
301 double dx1 = pt1.x - pt0.x;
302 double dy1 = pt1.y - pt0.y;
303 double dx2 = pt2.x - pt0.x;
304 double dy2 = pt2.y - pt0.y;
305 return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
306 }
307
308 // returns sequence of squares detected on the image.
309 // the sequence is stored in the specified memory storage
310 static void findSquares( const Mat& image, vector >& squares )
311 {
312 squares.clear();
313
314 Mat pyr, timg, gray0(image.size(), CV_8U), gray;
315
316 // down-scale and upscale the image to filter out the noise
317 pyrDown(image, pyr, Size(image.cols/2, image.rows/2));
318 pyrUp(pyr, timg, image.size());
319 vector > contours;
320
321 // find squares in every color plane of the image
322 for( int c = 0; c < 3; c++ )
323 {
324 int ch[] = {c, 0};
325 mixChannels(&timg, 1, &gray0, 1, ch, 1);
326
327 // try several threshold levels
328 for( int l = 0; l < N; l++ )
329 {
330 // hack: use Canny instead of zero threshold level.
331 // Canny helps to catch squares with gradient shading
332 if( l == 0 )
333 {
334 // apply Canny. Take the upper threshold from slider
335 // and set the lower to 0 (which forces edges merging)
336 Canny(gray0, gray, 0, thresh, 5);
337 // dilate canny output to remove potential
338 // holes between edge segments
339 dilate(gray, gray, Mat(), Point(-1,-1));
340 }
341 else
342 {
343 // apply threshold if l!=0:
344 // tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0
345 gray = gray0 >= (l+1)*255/N;
346 }
347
348 // find contours and store them all as a list
349 findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
350
351 vector approx;
352
353 // test each contour
354 for( size_t i = 0; i < contours.size(); i++ )
355 {
356 // approximate contour with accuracy proportional
357 // to the contour perimeter
358 approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02, true);
359
360 // square contours should have 4 vertices after approximation
361 // relatively large area (to filter out noisy contours)
362 // and be convex.
363 // Note: absolute value of an area is used because
364 // area may be positive or negative - in accordance with the
365 // contour orientation
366 if( approx.size() == 4 &&
367 fabs(contourArea(Mat(approx))) > 1000 &&
368 isContourConvex(Mat(approx)) )
369 {
370 double maxCosine = 0;
371
372 for( int j = 2; j < 5; j++ )
373 {
374 // find the maximum cosine of the angle between joint edges
375 double cosine = fabs(angle(approx[j%4], approx[j-2], approx[j-1]));
376 maxCosine = MAX(maxCosine, cosine);
377 }
378
379 // if cosines of all angles are small
380 // (all angles are ~90 degree) then write quandrange
381 // vertices to resultant sequence
382 if( maxCosine < 0.3 )
383 squares.push_back(approx);
384 }
385 }
386 }
387 }
388 }
389
390 double dist(Point p1, const Point p2){
391 return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
392 }
393
394 // the function draws all the squares in the image
395 static void drawSquares( Mat& image, const vector >& squares )
396 {
397 for( size_t i = 0; i < squares.size(); i++ )
398 {
399 const Point* p = &squares[i][0];
400 double d1=dist(p[0], p[1]);
401 double d2=dist(p[1], p[2]);
402 if(d1<50 || d2<50 || d1>280 || d2>280) continue;//把宽度小于50和大于350的矩形过滤
403 cout << dist(p[0], p[1]) << endl;
404 cout << dist(p[1], p[2]) << endl;
405 for(int j=0; j<4; j++){//使用line()函数替代polyline()函数画四边形
406 line(image, p[j], p[(j+1)%4], Scalar( 255 ), 3, 8);
407 }
408
409 MatU imageROI=image(Rect(Point(p[1].x,p[1].y), Point(p[3].x, p[3].y)));
410 MatU zcopy=Mat(imageROI);
411 imshow("sdfds", zcopy);
412
413
414 if(isBar(imageROI)){
415 cout << "yes" << endl;
416 read_barcode(imageROI);
417 addWeighted(imageROI,1.0,zcopy,0.3,0.,image);
418 }
419
420 }
421
422 imshow(wndname, image);
423 }
424
425 int main(int /*argc*/, char** /*argv*/)
426 {
427 help();
428 namedWindow( wndname, 1 );
429 vector > squares;
430
431
432 string imgname="C:/testdir/barcode1.jpg";
433 Mat image = imread(imgname, 1);
434 if( image.empty() ) return -1;
435
436 findSquares(image, squares);
437 drawSquares(image, squares);
438
439 waitKey(0);
440 }