. 本次小玩意主要是运用opencv的图像识别技术,同时又用到了zbar。opencv相信大家应该比较熟悉了,我就不废话了
我就给大家简单介绍一下zbar吧。
ZBar 是款桌面电脑用条形码/二维码扫描工具,支持摄像头及图片扫描,支持多平台包括 iPhone 手机。同时 ZBar 提供了二维码扫描的 API 开发包。
ZBar 目前支持扫描,除了 Windows 平台外,还支持 Linux 及 iPhone 平台。可扫描以下类型,常见的都有。
EAN-13/UPC-A, UPC-E, EAN-8, Code 128, Code 39, Interleaved 2 of 5 and QR Code.。
2. 那如何使用zbar来识别二维码呢? 首先我们需要下载zbar的源码,源码下载地址在http://download.csdn.net/detail/cjj1130320082/9586128
3. 在虚拟机ubuntu12.04安装zbar
3.1 解压 tar -zxvf zbar-0.10-tar.gz
3.2 cd zbar-0.10
3.3 配置 执行 ./configure
3.4 编译与安装 make && make install
经过上面几个简单的步骤之后,zbar就安装好了
下面就具体的看代码吧
/*
程序功能 -- 二维码图片检测和解码
用的是opencv1版本的函数用到了 1 边缘检测Sobel
2 二值化threshold
3 形态学操作膨胀腐蚀 erode dilate
4 轮廓寻找findContours
5 二维码解码
参考资料:http://blog.jobbole.com/80448/
*/
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace cv;
using namespace zbar;
#define FLOAT 10
#define PICTURE "13.bmp"
int main(int argc,char *argv[])
{
//加载原图
IplImage *srcImage = cvLoadImage(PICTURE,1);
//cvNamedWindow("1.原图",0);
//cvShowImage("1.原图",image);
//测时
clock_t start, finish;
double duration;
start = clock();
//转变为灰度图
IplImage *Grayimage = cvCreateImage(cvGetSize(srcImage),IPL_DEPTH_8U, 1);
cvCvtColor(srcImage,Grayimage,CV_BGR2GRAY);
//cvNamedWindow("Grayimage",0);
// cvShowImage("Grayimage",Grayimage);
//通过sobel来对图片进行竖向边缘检测,输入图像是8位时,输出必须是16位,然后再将图像转变成8位深
IplImage *sobel = cvCreateImage(cvGetSize(Grayimage),IPL_DEPTH_16S,1);
cvSobel(Grayimage,sobel,2,0,7);
IplImage *temp = cvCreateImage(cvGetSize(sobel),IPL_DEPTH_8U,1);
cvConvertScale(sobel,temp,0.002,0);
//cvNamedWindow("temp",0);
//cvShowImage("temp",temp);
//对图像进行二值化处理
IplImage *threshold = cvCreateImage(cvGetSize(temp),IPL_DEPTH_8U,1);
cvThreshold(temp,threshold,13,100,CV_THRESH_BINARY/*| CV_THRESH_OTSU*/);
//cvThreshold(temp, threshold, 0, 255, CV_THRESH_OTSU+CV_THRESH_BINARY);
//cvNamedWindow("threshold",0);
//cvShowImage("threshold",threshold);
//自定义1*3的核进行X方向的膨胀腐蚀
IplImage *erode_dilate=cvCreateImage(cvGetSize(threshold),IPL_DEPTH_8U,1);
IplConvKernel* kernal = cvCreateStructuringElementEx(3,1, 1, 0, CV_SHAPE_RECT);
cvDilate(threshold, erode_dilate, kernal, 15);//X方向膨胀连通数字
cvErode(erode_dilate, erode_dilate, kernal, 6);//X方向腐蚀去除碎片
cvDilate(erode_dilate, erode_dilate, kernal, 1);//X方向膨胀回复形态
//自定义3*1的核进行Y方向的膨胀腐蚀
kernal = cvCreateStructuringElementEx(1,3, 0, 1, CV_SHAPE_RECT);
//cvDilate(erode_dilate, erode_dilate, kernal, 5);
cvErode(erode_dilate, erode_dilate, kernal, 2);// Y方向腐蚀去除碎片
cvDilate(erode_dilate, erode_dilate, kernal, 6);//回复形态
//cvNamedWindow("erode_dilate",0);
//cvShowImage("erode_dilate",erode_dilate);
//图形检测
IplImage* copy = cvCloneImage(erode_dilate);//直接把erode_dilate的数据复制给copy
IplImage* copy1 = cvCloneImage(srcImage);//直接把image的数据复制给copy1
CvMemStorage* storage = cvCreateMemStorage();
CvSeq* contours;
cvFindContours(copy, storage, &contours);
int i=0,k=0,j=0;
CvRect RECT[100];
CvRect Rect[100];
while(contours != NULL)
{
//绘制轮廓的最小外接矩形,如果满足条件,将该矩形绘制在显示图片dst
/*
矩形要求:
1.宽度与高度的比值在(2,5)之间
2.面积大于图像的 1/20000
3.y轴的位置在图像高度减去50以下
*/
CvRect rect=cvBoundingRect( contours, 1 ); //cvBoundingRect计算点集的最外面(up-right)矩形边界。
if(rect.width/rect.height>0.8
&&rect.width/rect.height<1.2
&&rect.height*rect.height*FLOAT>copy1->height*copy1->width
&&rect.yheight-50
)
{
printf("rect.x = %d rect.y = %d rect.width = %d rect.height = %d\n",rect.x,rect.y,rect.width,rect.height);
//rect.x-=10;
// rect.y-=10;
// rect.width+=20;
// rect.height+=20;
RECT[i]=rect; //将图片中符合的矩形区域存到RECT
i++;
}
contours= contours->h_next;
}
printf("Find the rect %d!\n",i);
for(j=0;j100
||(RECT[j-1].x-RECT[j].x>200
||RECT[j].x-RECT[j-1].x>200))
{
cvRectangleR(copy1,RECT[j],CV_RGB(255,0,0),3);
Rect[k]=RECT[j];
k++;
//printf("The jj is the %d!\n",j);
}
}
cvNamedWindow("copy1",0);
cvShowImage("copy1",copy1);
//cvWaitKey(0);
//cvReleaseImage(&Grayimage);
cvReleaseImage(&temp);
cvReleaseImage(&threshold);
cvReleaseImage(&erode_dilate);
cvReleaseImage(&srcImage);
cvReleaseImage(©);
cvReleaseImage(©1);
// create a reader
//srcImage = cvLoadImage(PICTURE,1);
srcImage = Grayimage;//解码图片必需位灰度图
ImageScanner scanner;
// configure the reader
scanner.set_config(ZBAR_NONE, ZBAR_CFG_ENABLE, 1);
// obtain image data
const void *raw = NULL;
//int width=srcImage->width;
//int height=srcImage->height;
//raw = srcImage->imageDataOrigin;
//cvMat(int rows, int cols, int type, void * data CV_DEFAULT(NULL))
//cout<<"The number is the one!"<get_type_name()<get_data()+";";
cout << "decoded " << symbol->get_type_name()<< " symbol \"" << symbol->get_data() << '"' << endl;
}
// clean up
image.set_data(NULL, 0);
cvWaitKey(0);
cvReleaseImage(&Grayimage);
return(0);
}
看一下代码执行的效果:
rect.x = 1 rect.y = 1 rect.width = 298 rect.height = 298
Find the rect 1!
decoded QR-Code
decoded QR-Code symbol "http://www.baidu.com1sfsdfsdf212334344343334334" //解码后的结果