上半年发布过一个opencv一维码识别的博客,好久没有关注,今天发现有网友询问源码,现将源码附上。
这个程序是学习OPENCV的一个例子,仅供参考。
#include "stdafx.h" #include "opencv/cv.h" #include "opencv/highgui.h" #include "opencv/cxcore.h" #include "TestBarCode.h" #include #include "PointTrans.h" #include #include using std::map; using std::string; using std::strstream; #define RAD_ANGEL(n) (180*n/CV_PI) #define ANGEL_RAD(n) (n*CV_PI/180) const char strPictureName[] = "E:\\works\\10.bmp"; map ACode; map BCode; map CCode; void InitCodeMap() {ACode["211"] = 0;ACode["221"] = 1;ACode["122"] = 2;ACode["411"] = 3;ACode["131"] = 4;ACode["231"] = 5;ACode["114"] = 6;ACode["312"] = 7;ACode["213"] = 8;ACode["112"] = 9;BCode["123"] = 0;BCode["222"] = 1;BCode["212"] = 2;BCode["141"] = 3;BCode["311"] = 4;BCode["321"] = 5;BCode["111"] = 6;BCode["131"] = 7;BCode["121"] = 8;BCode["113"] = 9;CCode["321"] = 0;CCode["222"] = 1;CCode["212"] = 2;CCode["141"] = 3;CCode["113"] = 4;CCode["123"] = 5;CCode["111"] = 6;CCode["131"] = 7;CCode["121"] = 8;CCode["311"] = 9; } int GetCode(int a,int b,int c,map & tab) {char buffer[10];sprintf(buffer,"%d%d%d",a,b,c);map::iterator it = tab.find(buffer);if(it != tab.end()){return it->second;}return -1; } string Getcode(vector &tgs) {char buffer[20];memset(buffer,0,20);strstream out(buffer,20);vector::iterator it = tgs.begin();it += 4;//跳过起始位//获取左侧6个数字for(int i = 0 ; i< 6; i++){int a = *it++;int b = *it++;int c = *it++;it++;if(0 == i || 4==i || 5 == i){int n = GetCode(a,b,c,ACode);if(n > -1)out<}else{int n = GetCode(a,b,c,BCode);if(n > -1)out<}}//跳过中间分隔符it += 4;//获取右侧6个数字for(int i = 0 ; i< 6; i++){int a = *it++;int b = *it++;int c = *it++;it++;int n = GetCode(a,b,c,CCode);if(n > -1)out<}return buffer; } //-------------------------------------------------------------------------------------- //从二值图中抓取box包含的图片,并调整图片的角度。 IplImage * CreateAndCopyBox2D(IplImage * pImg,CvBox2D &box) {CvSize dst_size; dst_size.width = cvRound(box.size.width); dst_size.height = cvRound(box.size.height);IplImage * dst = cvCreateImage( dst_size, 8, 1 ); double angle = box.angle;double a = cos(ANGEL_RAD(angle));double b = sin(ANGEL_RAD(angle));int dw = dst_size.width /2;int dh = dst_size.height /2;printf("The angle : %f,%f,%f\n",angle,a,b);for(int i = 0; i< dst_size.width-1; i++){for(int j = 0; j < dst_size.height-1; j++){//平移到矩形中心int x = i - dw;int y = j - dh;//旋转double px = x * a - y * b;double py = y * a + x * b;//平移到目标中心px += (box.center.x);py += (box.center.y);x = cvRound(px);y = cvRound(py);if(PtInRect(cvSize(pImg->width,pImg->height),x,y)){CvScalar val = cvGet2D(pImg,y,x);cvSet2D(dst,j,i,val);}}}return dst; } //特征识别,找到条码区域 bool FutrueFind(IplImage * pImg) {double max = 0;double min = 0;vector ds;HistY(pImg,ds);//map mp1;//HistConter(ds,mp1);//DrawMap(mp1,"mp1");double avgY = DataAvg(ds);ds.clear();HistX(pImg,ds);//map mp2;//HistConter(ds,mp2);//DrawMap(mp2,"mp2");double avgX = DataAvg(ds);if(avgX/avgY > 5)return true;return false; } string DecodeImage(IplImage * pImg) {vector ds;double color = 0;int h = pImg->height/2;for(int i = 0; iwidth; i++){double d = cvGet2D(pImg,h,i).val[0];if(0 == i)color = d;else{if(abs(color -d) > 100){ds.push_back(i);}color = d;}}printf("decode size :%d\n",ds.size());//计算宽度系列vector wids;double w = 0;for(int i = 0; i{double d = ds[i];if(0== i)w = d;else {wids.push_back(d - w);w = d;}}wids.pop_back();printf("width size :%d\n",wids.size());int min = FindMin(wids);vector tgs;DevTh(wids,tgs,min);string code = Getcode(tgs);printf("code :%s\n",code.c_str());return code; } //型体分割,获取感兴趣的区域 void Process(IplImage * pImg) {//转换成二值图IplImage * dst = cvCreateImage( cvGetSize(pImg), 8, 1 );cvThreshold(pImg,dst,100,200,CV_THRESH_BINARY_INV);//将灰度图转成二值图cvNamedWindow("ThImage",1);cvShowImage("ThImage",dst);//膨胀IplImage * dst2 = cvCreateImage( cvGetSize(pImg), 8, 1 );IplConvKernel * element = cvCreateStructuringElementEx( 5, 5, 1, 1, CV_SHAPE_ELLIPSE, 0);cvDilate(dst,dst2,element,3);//图像膨胀cvNamedWindow("DilateImage",1);cvShowImage("DilateImage",dst2);//检测轮廓CvMemStorage * storage = cvCreateMemStorage(0); CvSeq * contour = 0; int n = cvFindContours( dst2, storage, &contour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);//用白色填充面积最大的轮廓 double maxArea = 20; IplImage* pContourImg = cvCreateImage(cvGetSize(dst2), IPL_DEPTH_8U, 3); //初始化为黑色cvZero(pContourImg); int k = 0;while(contour) { double area=fabs(cvContourArea(contour, CV_WHOLE_SEQ)); //求轮廓包含的面积 if(area > 100) //当面积小于50时的忽略{if(k++ < 8){ cvDrawContours(pContourImg,contour,cvScalarAll(255),cvScalarAll(0),0,CV_FILLED); CvRect rect = cvBoundingRect(contour,1); //获取外接矩形cvRectangleR(pContourImg,rect,CV_RGB(0,255,0)); //绘制外接矩形CvBox2D box = cvMinAreaRect2(contour,NULL); //求取轮廓最小的外接矩形IplImage * cpImg = CreateAndCopyBox2D(dst,box);if(cpImg){if(FutrueFind(cpImg)){string str = DecodeImage(cpImg);cvNamedWindow("cpImg",1);cvShowImage("cpImg",cpImg);}else cvReleaseImage(&cpImg);}} }contour=contour->h_next; } cvReleaseMemStorage(&storage); } bool TestBarCode() {InitCodeMap(); IplImage* src = cvLoadImage(strPictureName,0); //装载图像 if( !src ){printf("打开文件失败,请重新打开"); //读取失败返回return false;}cvNamedWindow("src",1);cvShowImage("src",src); IplImage * dst = cvCreateImage( cvGetSize(src), 8, 1 ); //创建图像 IplImage * dst1 = cvCreateImage( cvGetSize(src), 8, 1 );//创建图像//进行图像平滑,并转成灰度图像cvSmooth(src,dst1,CV_BLUR,3, 3); Process(dst1); cvWaitKey(0); //等待按键//释放图像分配的内存cvReleaseImage(&src); cvReleaseImage(&dst); cvReleaseImage(&dst1);cvDestroyWindow("src");cvDestroyWindow("dest");cvDestroyWindow("cpImg");return true; }