opencv3+Zbar识别二维码--水平垂直交叉定位

来源:互联网 发布:支付宝怎么绑定淘宝 编辑:程序博客网 时间:2024/06/03 18:17

成像比较清晰,二维码占据整个图像的比例达到4成以上的标准二维码,用opencv和zbar识别还是很容易的,而且zbar的鲁棒性很好。

[cpp] view plain copy
  1. // Zbar_code.cpp : 定义控制台应用程序的入口点。  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5. #include<iostream>  
  6. #include<zbar.h>  
  7. #include<opencv2\highgui\highgui.hpp>  
  8. #include<opencv2\opencv.hpp>  
  9.   
  10. using namespace std;  
  11. using namespace cv;  
  12. using namespace zbar;  
  13.   
  14. Rect DrawXY(const Mat image, Mat &imageOut, const int threshodValue, const int binaryzationValue);  
  15.   
  16. int main()  
  17. {  
  18.     // 定义Zbar扫描的类  
  19.     ImageScanner scanner;  
  20.     // 初始化  
  21.     scanner.set_config(ZBAR_NONE, ZBAR_CFG_ENABLE, 1);  
  22.     // 加载二维码图像数据  
  23.     Mat srcImage = imread("baidu.jpg");  
  24.     if (!srcImage.data) {  
  25.         cout << "Input image error!" << endl;  
  26.         system("pause");  
  27.         return 0;  
  28.     }  
  29.     Mat src_copy = srcImage.clone();  
  30.     Mat src_gray, dstImage;  
  31.     cvtColor(srcImage, src_gray, CV_BGR2GRAY);  
  32.   
  33.     int width = src_gray.cols;  
  34.     int height = src_gray.rows;  
  35.     // wrap the image  
  36.     uchar*raw = (uchar*)src_gray.data;  
  37.     Image imageZbar(width, height, "Y800", raw, width*height);  
  38.     // 开始扫描  
  39.     scanner.scan(imageZbar);  
  40.     // 扩展结果  
  41.     Image::SymbolIterator symbol = imageZbar.symbol_begin();  
  42.     if (imageZbar.symbol_begin() == imageZbar.symbol_end()) {  
  43.         cout << "扫描失败,检查图片数据!" << endl;  
  44.     }  
  45.     for (; symbol != imageZbar.symbol_end(); ++symbol) {  
  46.         cout << "类型:" << endl << symbol->get_type_name() << endl;  
  47.         cout << "条码:" << endl << symbol->get_data() << endl;  
  48.     }  
  49.   
  50.     imshow("原始二维码图片", srcImage);  
  51.   
  52.     Rect rect(0, 0, 0, 0);  
  53.     // 调用函数将二维码区域截取  
  54.     rect = DrawXY(srcImage, dstImage, srcImage.rows / 10, 150);  
  55.     Mat roi = srcImage(rect);  
  56.     // 根据获取的二维码矩形区域四个角点坐标在原图像上画出二维码  
  57.     rectangle(src_copy, Point(rect.x, rect.y), Point(rect.x + rect.width, rect.y + rect.height), Scalar(0, 0, 255), 4);  
  58.     imshow("水平垂直投影", dstImage);  
  59.     imshow("截取的二维码区域", roi);  
  60.     imshow("圈画原始图像二维码区域", src_copy);  
  61.   
  62.     waitKey(0);  
  63.     imageZbar.set_data(NULL, 0);  
  64.   
  65.     return 0;  
  66. }  
  67.   
  68. //***********************************************    
  69. // 函数通过水平和垂直方向投影,找到两个方向上投影的交叉矩形,定位到条形码/二维码    
  70. // int threshodValue 投影的最少像素单位    
  71. // int binaryzationValue  原图像阈值分割值    
  72. //***********************************************  
  73.   
  74. Rect DrawXY(const Mat image, Mat &imageOut, const int threshodValue, const int binaryzationValue)  
  75. {  
  76.     // 将原始图像备份  
  77.     Mat img = image.clone();  
  78.     // 非单通道图像先预处理--灰度化  
  79.     if (img.channels()>1)  
  80.     {  
  81.         cvtColor(img, img, CV_RGB2GRAY);  
  82.     }  
  83.     // 根据原始图像的尺寸构建新的图像用于接收投影信息  
  84.     Mat out(img.size(), img.type(), Scalar(255));  
  85.     imageOut = out;  
  86.     // 对每一个传入的图片做灰度归一化,以便使用同一套阈值参数  
  87.     normalize(img, img, 0, 255, NORM_MINMAX);  
  88.     // 垂直方向投影,构建数组向量,包含img.cols维度  
  89.     vector<int> vectorVertical(img.cols, 0);  
  90.     // 根据像素坐标所在像素值大小与阈值比较,若有黑店覆盖则计数+1  
  91.     for (int i = 0; i<img.cols; i++)  
  92.     {  
  93.         for (int j = 0; j<img.rows; j++)  
  94.         {  
  95.             if (img.at<uchar>(j, i)<binaryzationValue)  
  96.             {  
  97.                 vectorVertical[i]++;  
  98.             }  
  99.         }  
  100.     }  
  101.     // 列值归一化    
  102.     int high = img.rows / 6;  
  103.     normalize(vectorVertical, vectorVertical, 0, high, NORM_MINMAX);  
  104.     for (int i = 0; i<img.cols; i++)  
  105.     {  
  106.         for (int j = 0; j<img.rows; j++)  
  107.         {  
  108.             // 少于设置的像素统计值则不显示柱状图,这里srcImage.rows / 10根据二维码的定位区域得到  
  109.             // 还需要研究,后期会更新这参数计算原理  
  110.             if (vectorVertical[i]>threshodValue)  
  111.             {  
  112.                 line(imageOut, Point(i, img.rows), Point(i, img.rows - vectorVertical[i]), Scalar(0, 0, 0));  
  113.             }  
  114.         }  
  115.     }  
  116.     //水平投影    
  117.     vector<int> vectorHorizontal(img.rows, 0);  
  118.     for (int i = 0; i<img.rows; i++)  
  119.     {  
  120.         for (int j = 0; j<img.cols; j++)  
  121.         {  
  122.             if (img.at<uchar>(i, j)<binaryzationValue)  
  123.             {  
  124.                 vectorHorizontal[i]++;  
  125.             }  
  126.         }  
  127.     }  
  128.     normalize(vectorHorizontal, vectorHorizontal, 0, high, NORM_MINMAX);  
  129.     for (int i = 0; i<img.rows; i++)  
  130.     {  
  131.         for (int j = 0; j<img.cols; j++)  
  132.         {  
  133.             if (vectorHorizontal[i]>threshodValue)  
  134.             {  
  135.                 line(imageOut, Point(img.cols - vectorHorizontal[i], i), Point(img.cols, i), Scalar(0));  
  136.             }  
  137.         }  
  138.     }  
  139.     //找到投影四个角点坐标    
  140.     vector<int>::iterator beginV = vectorVertical.begin();  
  141.     vector<int>::iterator beginH = vectorHorizontal.begin();  
  142.     vector<int>::iterator endV = vectorVertical.end() - 1;  
  143.     vector<int>::iterator endH = vectorHorizontal.end() - 1;  
  144.     int widthV = 0;  
  145.     int widthH = 0;  
  146.     int highV = 0;  
  147.     int highH = 0;  
  148.     while (*beginV<threshodValue)  
  149.     {  
  150.         beginV++;  
  151.         widthV++;  
  152.     }  
  153.     while (*endV<threshodValue)  
  154.     {  
  155.         endV--;  
  156.         widthH++;  
  157.     }  
  158.     while (*beginH<threshodValue)  
  159.     {  
  160.         beginH++;  
  161.         highV++;  
  162.     }  
  163.     while (*endH<threshodValue)  
  164.     {  
  165.         endH--;  
  166.         highH++;  
  167.     }  
  168.     //投影矩形    
  169.     Rect rect(widthV, highV, img.cols - widthH - widthV, img.rows - highH - highV);  
  170.     return rect;  
  171. }  

二维码:







条形码:



原文:http://blog.csdn.net/OliverkingLi/article/details/78091942

原创粉丝点击