opencv3+Zbar识别二维码--水平垂直交叉定位
成像比较清晰,二维码占据整个图像的比例达到4成以上的标准二维码,用opencv和zbar识别还是很容易的,而且zbar的鲁棒性很好。
- // Zbar_code.cpp : 定义控制台应用程序的入口点。
- //
- #include "stdafx.h"
- #include<iostream>
- #include<zbar.h>
- #include<opencv2\highgui\highgui.hpp>
- #include<opencv2\opencv.hpp>
- using namespace std;
- using namespace cv;
- using namespace zbar;
- Rect DrawXY(const Mat image, Mat &imageOut, const int threshodValue, const int binaryzationValue);
- int main()
- {
- // 定义Zbar扫描的类
- ImageScanner scanner;
- // 初始化
- scanner.set_config(ZBAR_NONE, ZBAR_CFG_ENABLE, 1);
- // 加载二维码图像数据
- Mat srcImage = imread("baidu.jpg");
- if (!srcImage.data) {
- cout << "Input image error!" << endl;
- system("pause");
- return 0;
- }
- Mat src_copy = srcImage.clone();
- Mat src_gray, dstImage;
- cvtColor(srcImage, src_gray, CV_BGR2GRAY);
- int width = src_gray.cols;
- int height = src_gray.rows;
- // wrap the image
- uchar*raw = (uchar*)src_gray.data;
- Image imageZbar(width, height, "Y800", raw, 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;
- cout << "条码:" << endl << symbol->get_data() << endl;
- }
- imshow("原始二维码图片", srcImage);
- Rect rect(0, 0, 0, 0);
- // 调用函数将二维码区域截取
- rect = DrawXY(srcImage, dstImage, srcImage.rows / 10, 150);
- Mat roi = srcImage(rect);
- // 根据获取的二维码矩形区域四个角点坐标在原图像上画出二维码
- rectangle(src_copy, Point(rect.x, rect.y), Point(rect.x + rect.width, rect.y + rect.height), Scalar(0, 0, 255), 4);
- imshow("水平垂直投影", dstImage);
- imshow("截取的二维码区域", roi);
- imshow("圈画原始图像二维码区域", src_copy);
- waitKey(0);
- imageZbar.set_data(NULL, 0);
- return 0;
- }
- //***********************************************
- // 函数通过水平和垂直方向投影,找到两个方向上投影的交叉矩形,定位到条形码/二维码
- // int threshodValue 投影的最少像素单位
- // int binaryzationValue 原图像阈值分割值
- //***********************************************
- Rect DrawXY(const Mat image, Mat &imageOut, const int threshodValue, const int binaryzationValue)
- {
- // 将原始图像备份
- Mat img = image.clone();
- // 非单通道图像先预处理--灰度化
- if (img.channels()>1)
- {
- cvtColor(img, img, CV_RGB2GRAY);
- }
- // 根据原始图像的尺寸构建新的图像用于接收投影信息
- Mat out(img.size(), img.type(), Scalar(255));
- imageOut = out;
- // 对每一个传入的图片做灰度归一化,以便使用同一套阈值参数
- normalize(img, img, 0, 255, NORM_MINMAX);
- // 垂直方向投影,构建数组向量,包含img.cols维度
- vector<int> vectorVertical(img.cols, 0);
- // 根据像素坐标所在像素值大小与阈值比较,若有黑店覆盖则计数+1
- for (int i = 0; i<img.cols; i++)
- {
- for (int j = 0; j<img.rows; j++)
- {
- if (img.at<uchar>(j, i)<binaryzationValue)
- {
- vectorVertical[i]++;
- }
- }
- }
- // 列值归一化
- int high = img.rows / 6;
- normalize(vectorVertical, vectorVertical, 0, high, NORM_MINMAX);
- for (int i = 0; i<img.cols; i++)
- {
- for (int j = 0; j<img.rows; j++)
- {
- // 少于设置的像素统计值则不显示柱状图,这里srcImage.rows / 10根据二维码的定位区域得到
- // 还需要研究,后期会更新这参数计算原理
- if (vectorVertical[i]>threshodValue)
- {
- line(imageOut, Point(i, img.rows), Point(i, img.rows - vectorVertical[i]), Scalar(0, 0, 0));
- }
- }
- }
- //水平投影
- vector<int> vectorHorizontal(img.rows, 0);
- for (int i = 0; i<img.rows; i++)
- {
- for (int j = 0; j<img.cols; j++)
- {
- if (img.at<uchar>(i, j)<binaryzationValue)
- {
- vectorHorizontal[i]++;
- }
- }
- }
- normalize(vectorHorizontal, vectorHorizontal, 0, high, NORM_MINMAX);
- for (int i = 0; i<img.rows; i++)
- {
- for (int j = 0; j<img.cols; j++)
- {
- if (vectorHorizontal[i]>threshodValue)
- {
- line(imageOut, Point(img.cols - vectorHorizontal[i], i), Point(img.cols, i), Scalar(0));
- }
- }
- }
- //找到投影四个角点坐标
- vector<int>::iterator beginV = vectorVertical.begin();
- vector<int>::iterator beginH = vectorHorizontal.begin();
- vector<int>::iterator endV = vectorVertical.end() - 1;
- vector<int>::iterator endH = vectorHorizontal.end() - 1;
- int widthV = 0;
- int widthH = 0;
- int highV = 0;
- int highH = 0;
- while (*beginV<threshodValue)
- {
- beginV++;
- widthV++;
- }
- while (*endV<threshodValue)
- {
- endV--;
- widthH++;
- }
- while (*beginH<threshodValue)
- {
- beginH++;
- highV++;
- }
- while (*endH<threshodValue)
- {
- endH--;
- highH++;
- }
- //投影矩形
- Rect rect(widthV, highV, img.cols - widthH - widthV, img.rows - highH - highV);
- return rect;
- }
二维码:
条形码:
原文:http://blog.csdn.net/OliverkingLi/article/details/78091942