基于OPENCV 一维条码识别源码。

来源:互联网 发布:淘宝店怎么转让 编辑:程序博客网 时间:2024/04/29 18:08

上半年发布过一个opencv一维码识别的博客,好久没有关注,今天发现有网友询问源码,现将源码附上。

这个程序是学习OPENCV的一个例子,仅供参考。


#include "stdafx.h"
#include "opencv/cv.h"
#include "opencv/highgui.h"
#include "opencv/cxcore.h"
#include "TestBarCode.h"
#include <map>
#include "PointTrans.h"
#include <string>
#include <strstream>

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<string,int> ACode;
map<string,int> BCode;
map<string,int> 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<string,int> & tab)
{
char buffer[10];
sprintf(buffer,"%d%d%d",a,b,c);


map<string,int>::iterator it = tab.find(buffer);
if(it != tab.end())
{
return it->second;
}
return -1;
}
string Getcode(vector<int> &tgs)
{
char buffer[20];
memset(buffer,0,20);
strstream out(buffer,20);


vector<int>::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<<n;
}
else
{
int n = GetCode(a,b,c,BCode);
if(n > -1)out<<n;
}
}


//跳过中间分隔符
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<<n;

}


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<double> ds;
HistY(pImg,ds);


//map<double,int> mp1;
//HistConter(ds,mp1);
//DrawMap(mp1,"mp1");
double avgY = DataAvg(ds);

ds.clear();
HistX(pImg,ds);


//map<double,int> mp2;
//HistConter(ds,mp2);
//DrawMap(mp2,"mp2");
double avgX = DataAvg(ds);


if(avgX/avgY > 5)return true;


return false;
}


string DecodeImage(IplImage * pImg)
{
vector<int> ds;
double color = 0;
int h = pImg->height/2;
for(int i = 0; i<pImg->width; 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<int> wids;
double w = 0;
for(int i = 0; i<ds.size(); 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<int> 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;
}

0 0
原创粉丝点击