精华内容
下载资源
问答
  • opencv一维码识别

    2016-05-04 16:33:08
    opencv条码进行识别
  • 基于OPENCV 一维条码识别源码。

    千次阅读 2014-09-30 07:48:39
    #include "stdafx.h" ...#include "opencv/cv.h" #include "opencv/highgui.h" #include "opencv/cxcore.h" #include "TestBarCode.h" #include #include "PointTrans.h" #include #include us

    上半年发布过一个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;
    }

    展开全文
  • OpenCV一维码识别

    2019-04-30 15:48:18
    使用opencv3.41和zbar库,实现实时检测、识别一帧图像中多个条形码,数据库的动态链接库在ado目录下,数据库文件在db目录下,if1weima目录为检测的输出图像,is1weima目录下为识别出的一维码图像;zbar目录下为工程...
  • 基于opencv一维条码识别

    千次阅读 2014-03-20 14:52:42
    条码图像处理过程  图像的大致处理流程如下:  1. 将彩色图转变成灰度图  2. 对灰度图均衡化  3. 将灰度图转换成二值图 ...对每个轮廓包围的区域进行特征识别,判断是否是条码区域。  

    一. 条码图像处理过程

            图像的大致处理流程如下:

             1. 将彩色图转变成灰度图

             2. 对灰度图均衡化

             3. 将灰度图转换成二值图

             4. 对二值图进行腐蚀

             5. 识别边界检测轮廓

             6. 对每一个轮廓包围的区域进行特征识别,判断是否是条码区域。

             7. 对条码区域测量解码。

     

     

    二.代码解读

     

    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;

    }

     

    这段代码是处理的主代码,对图片载入并平滑处理。然后调用了Process函数做进一步处理。

     

    //型体分割,获取感兴趣的区域

    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) //当面积小于100时的忽略

                       {

                                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);

    }

     

    Process是核心处理代码,首先对图像进行了二值化,这样能去除更多的干扰。二值化是使用了CV_THRESH_BINARY_INV参数,对图像中黑白色反转。这样条码部分呈了白色。然后对其膨胀,膨胀的目的是将条码说在的整个区域编程白色,之后的轮廓识别能将其划分在一个轮廓里。

    cvFindContours查找了轮廓,将其保存在contour列表之中。之后就是遍历整个列表,遍历时,首先使用cvMinAreaRect2对每一个轮廓求取其最小外接矩形,他返回一个CvBox2D数据,其中包含有矩形的大小,中心点坐标,还有一个角度。利用这个角度可以可以知道条码型位信息,这个角度就是对裁剪后的感兴趣区域旋转的角度。

    CreateAndCopyBox2D对遍历的每个区域进行了裁剪和旋转。这样就得到了型位是正位的区域图片,之后要做的事情就是识别图片特征,判断是否是条码区域,若是就会对图片的解码。

     

    FutrueFind承担了图片特征识别的任务。

    //特征识别,找到条码区域

    bool FutrueFind(IplImage * pImg)

    {

             double max = 0;

             double min = 0;

     

             vector<double> ds;

             HistY(pImg,ds);

             double avgY = DataAvg(ds);

            

             ds.clear();

             HistX(pImg,ds);

             double avgX = DataAvg(ds);

     

             if(avgX/avgY > 5)return true;

     

             return false;

    }

     

    特征识别是一个图形处理系统的核心技术。这里使用了简单的特征识别,目前还不是很健壮。在一维条码的x,y方向上强度特征会有所不同,首先统计出X和Y方向的强度值,然后求取相邻强度值差值的绝对值,在对这些值求平均值。这样得到了avgY和avgX,经多个条码观察发现avgX都在avgY的5倍以上。

     

     

    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;

    }

     

    DecodeImage函数解码条码,他基于像素为单位对条码宽度测量,再找出最小宽度,之后再将其转换成条码识别的标注序列,和编码表比较获得条码值。

    展开全文
  • 个简单的实例,测试可用,opencv安装包比较大,需要的可以发邮件79947171@qq.com找我,测试图片,zbar安装以及相关文件已经打包在里面
  • Opencv+Zbar二维码识别(一维码校正)

    万次阅读 热门讨论 2016-08-13 11:39:05
    一维码由一组规则排列的黑色线条、白色线条以及对应的字符组成。对倾斜的(没有严重形变)一维码的角度校正,可以根据其黑白相间、排列规则的特点,计算傅里叶频谱,通过傅里叶频谱中直线的倾斜角度计算空间域图像...

    一维码由一组规则排列的黑色线条、白色线条以及对应的字符组成。对倾斜的(没有严重形变)一维码的角度校正,可以根据其黑白相间、排列规则的特点,计算傅里叶频谱,通过傅里叶频谱中直线的倾斜角度计算空间域图像一维码需校正的角度。


    先贴出来待校正的一维码和其傅里叶频谱图:

             

    傅里叶频谱中亮度值代表了频率变化的强弱,直线的方向代表了频率变化的方向。上图傅里叶频谱中最亮的那条线就是与一维码黑白相间条纹相垂直的方向,找到这条线的角度,就可以计算出一维码的校正角度。


    校正步骤:

    1. 计算图像X,Y方向上梯度图像,并求和,突出图像边缘信息

    2. 离散傅里叶变换,画出一维码的频谱图

    3. 霍夫变换定位到傅里叶频谱图中直线,获得直线角度

    4. 计算一维码需校正角度,通过仿射变换,校正图像


    X、Y方向梯度和:



    傅里叶频谱:



    阈值化,保留频率变化最明显的分量:



    Hough直线定位:



    一维码角度校正:



    Zbar识别:



    Code 实现:

    #include "core/core.hpp"    
    #include "highgui/highgui.hpp"    
    #include "imgproc/imgproc.hpp"    
    #include "iostream"  
    #include "zbar.h"
    
    using namespace std; 
    using namespace zbar;
    using namespace cv;    
    
    int main(int argc,char *argv[])    
    {    
    	Mat image,imageGray,imageGuussian;    
    	Mat imageSobelX,imageSobelY,imageSobelOut;    
    	imageGray=imread(argv[1],0);
    	imageGray.copyTo(image);
    	imshow("Source Image",image);
    	GaussianBlur(imageGray,imageGuussian,Size(3,3),0);   
    	//水平和垂直方向灰度图像的梯度和,使用Sobel算子    
    	Mat imageX16S,imageY16S;    
    	Sobel(imageGuussian,imageX16S,CV_16S,1,0,3,1,0,4);    
    	Sobel(imageGuussian,imageY16S,CV_16S,0,1,3,1,0,4);    
    	convertScaleAbs(imageX16S,imageSobelX,1,0);    
    	convertScaleAbs(imageY16S,imageSobelY,1,0);    
    	imageSobelOut=imageSobelX+imageSobelY;   
    	imshow("XY方向梯度和",imageSobelOut);       
    	Mat srcImg =imageSobelOut;  	    
    	//宽高扩充,非必须,特定的宽高可以提高傅里叶运算效率  
    	Mat padded;  
    	int opWidth = getOptimalDFTSize(srcImg.rows);  
    	int opHeight = getOptimalDFTSize(srcImg.cols);  
    	copyMakeBorder(srcImg, padded, 0, opWidth-srcImg.rows, 0, opHeight-srcImg.cols, BORDER_CONSTANT, Scalar::all(0));   
    	Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)};  
    	Mat comImg;  
    	//通道融合,融合成一个2通道的图像  
    	merge(planes,2,comImg);    
    	dft(comImg, comImg);       
    	split(comImg, planes);  
    	magnitude(planes[0], planes[1], planes[0]);       
    	Mat magMat = planes[0];  
    	magMat += Scalar::all(1);  
    	log(magMat, magMat);     //对数变换,方便显示 
    	magMat = magMat(Rect(0, 0, magMat.cols & -2, magMat.rows & -2));      
    	//以下把傅里叶频谱图的四个角落移动到图像中心
    	int cx = magMat.cols/2;  
    	int cy = magMat.rows/2;   
    	Mat q0(magMat, Rect(0, 0, cx, cy));  
    	Mat q1(magMat, Rect(0, cy, cx, cy));  
    	Mat q2(magMat, Rect(cx, cy, cx, cy));  
    	Mat q3(magMat, Rect(cx, 0, cx, cy));   
    	Mat tmp;  
    	q0.copyTo(tmp);  
    	q2.copyTo(q0);  
    	tmp.copyTo(q2);   
    	q1.copyTo(tmp);  
    	q3.copyTo(q1);  
    	tmp.copyTo(q3);  
    	normalize(magMat, magMat, 0, 1, CV_MINMAX);  
    	Mat magImg(magMat.size(), CV_8UC1);  
    	magMat.convertTo(magImg,CV_8UC1,255,0);  
    	imshow("傅里叶频谱", magImg); 
    	//HoughLines查找傅里叶频谱的直线,该直线跟原图的一维码方向相互垂直
    	threshold(magImg,magImg,180,255,CV_THRESH_BINARY);  
    	imshow("二值化", magImg);       
    	vector<Vec2f> lines;  
    	float pi180 = (float)CV_PI/180;  
    	Mat linImg(magImg.size(),CV_8UC3);  
    	HoughLines(magImg,lines,1,pi180,100,0,0);  
    	int numLines = lines.size();  
    	float theta;
    	for(int l=0; l<numLines; l++)  
    	{  
    		float rho = lines[l][0];
    		theta = lines[l][1];  
    		float aa=(theta/CV_PI)*180;
    		Point pt1, pt2;  
    		double a = cos(theta), b = sin(theta);  
    		double x0 = a*rho, y0 = b*rho;  
    		pt1.x = cvRound(x0 + 1000*(-b));  
    		pt1.y = cvRound(y0 + 1000*(a));  
    		pt2.x = cvRound(x0 - 1000*(-b));  
    		pt2.y = cvRound(y0 - 1000*(a));  
    		line(linImg,pt1,pt2,Scalar(255,0,0),3,8,0);		
    	}  
    	imshow("Hough直线",linImg);  
    	//校正角度计算
    	float angelD=180*theta/CV_PI-90;   
    	Point center(image.cols/2, image.rows/2);  
    	Mat rotMat = getRotationMatrix2D(center,angelD,1.0);  
    	Mat imageSource = Mat::ones(image.size(),CV_8UC3);  
    	warpAffine(image,imageSource,rotMat,image.size(),1,0,Scalar(255,255,255));//仿射变换校正图像  
    	imshow("角度校正",imageSource);     
    	//Zbar一维码识别
    	ImageScanner scanner;        
    	scanner.set_config(ZBAR_NONE, ZBAR_CFG_ENABLE, 1);   
    	int width1 = imageSource.cols;        
    	int height1 = imageSource.rows;        
    	uchar *raw = (uchar *)imageSource.data;           
    	Image imageZbar(width1, height1, "Y800", raw, width1 * height1);          
    	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<<endl;      
    		cout<<"条码:"<<endl<<symbol->get_data()<<endl<<endl;         
    	}        
    	namedWindow("Source Window",0);  
    	imshow("Source Window",imageSource);          
    	waitKey();      
    	imageZbar.set_data(NULL,0);    
    	return 0;    
    }  
    



    展开全文
  • 一维码识别 参考资料:(侵权删)...

    一维码识别

    参考资料:(侵权删)
    1、https://blog.csdn.net/qq_40908493/article/details/79829226?ops_request_misc=%25257B%252522request%25255Fid%252522%25253A%252522161188879716780274186320%252522%25252C%252522scm%252522%25253A%25252220140713.130102334.pc%25255Fall.%252522%25257D&request_id=161188879716780274186320&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_v2~rank_v29-1-79829226.pc_search_result_cache&utm_term=vs2013+opencv+2.4.9%25E5%25AE%2589%25E8%25A3%2585zbar
    2、https://blog.csdn.net/dcrmg/article/details/52194896?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522161190784316780255272641%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=161190784316780255272641&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_v2~rank_v29-2-52194896.pc_search_result_cache&utm_term=opencv%2Bzbar二维码识别(一维码校正)&spm=1018.2226.3001.4449

    zbar.h可以自动扫描识别一维码二维码,不需要校正也可识别。在参考资料的基础上修改了一些代码段及添加了注释,基本原理相同。

    1、安装zbar.h后简单测试(如何安装配置参考资料1)

    #include"opencv2/highgui/highgui.hpp"
    #include "zbar.h" 
    #include <iostream> 
    
    using namespace std;
    using namespace zbar; //添加zbar名称空间
    using namespace cv;
    
    double Point2PointDist(Point2f& a, Point2f& b);
    double Line_Angle(Point2f& a, Point2f& b);
    int main(int argc, char*argv[])
    {
    	ImageScanner scanner;	//构造扫描器ImageScanner对象,并使用set_config进行初始化
    	scanner.set_config(ZBAR_NONE, ZBAR_CFG_ENABLE, 1);
    
    	//加载灰度图并显示
    	Mat imageGray = imread("6.png",0);	//小于0或不写则加载原图,等于0则加载灰度图,大于0则加载RGB图像
    	if (!imageGray.data)
    	{
    		cout << "请确认图片是否存在" << endl;
    		system("pause");
    		return 0;
    	}
    	//imshow("原图", image);
    	//Mat imageGray;
    	//cvtColor(image, imageGray, CV_RGB2GRAY);	//转换为灰度图
    	imshow("灰度图", imageGray);
    
    	//扫描并显示信息
    	int width = imageGray.cols;
    	int height = imageGray.rows;
    	uchar *raw = (uchar *)imageGray.data;	
    	Image imageZbar(width, height, "Y800", raw, width * height);//y800实际为灰度图代号
    	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 << endl;
    		cout << "条码:" << endl << symbol->get_data() << endl << endl;
    	}
    	waitKey();
    	imageZbar.set_data(NULL, 0);
    	return 0;
    }
    

    结果图示:
    在这里插入图片描述
    在这里插入图片描述

    2、(实际上条码有一定角度也能扫描出来)将一维码校正后再次扫描显示信息

    #include "opencv2/core/core.hpp"
    #include"opencv2/highgui/highgui.hpp"
    #include "opencv2/imgproc/imgproc.hpp"
    #include "zbar.h" 
    #include <iostream> 
    
    using namespace std;
    using namespace zbar; //添加zbar名称空间
    using namespace cv;
    
    double Point2PointDist(Point2f& a, Point2f& b);	//用于计算频谱图直线距离
    double Line_Angle(Point2f& a, Point2f& b);//计算直线角度
    
    int main(int argc, char*argv[])
    {
    	ImageScanner scanner;	//构造扫描器ImageScanner对象,并使用set_config进行初始化
    	scanner.set_config(ZBAR_NONE, ZBAR_CFG_ENABLE, 1);
    
    	//1、加载灰度图并显示
    	Mat imageGray = imread("3.png", 0);	//小于0或不写则加载原图,等于0则加载灰度图,大于0则加载RGB图像
    	if (!imageGray.data)
    	{
    		cout << "请确认图片是否存在" << endl;
    		system("pause");
    		return 0;
    	}
    	imshow("【1】灰度图", imageGray);
    
    	//2、计算图像x、y方向的梯度,并求和,突出边缘信息
    	Mat grad_x, grad_y,dst;
    	Mat abs_grad_x, abs_grad_y;
    
    	Sobel(imageGray, grad_x, CV_16S, 1, 0, 3, 1);
    	convertScaleAbs(grad_x, abs_grad_x);
    	//imshow("【2】x方向Sobel", abs_grad_x);
    
    	Sobel(imageGray, grad_y, CV_16S, 0, 1, 3, 1);
    	convertScaleAbs(grad_y, abs_grad_y);
    	//imshow("【3】y方向Sobel", abs_grad_y);
    
    	addWeighted(abs_grad_x, 1, abs_grad_y, 1, 0, dst);
    	imshow("【4】合并Sobel梯度", dst);
    

    在这里插入图片描述
    在这里插入图片描述

    	//3、离散傅里叶变换,画出频谱信息
    	//扩充边界
    	int m = getOptimalDFTSize(dst.rows);
    	int n = getOptimalDFTSize(dst.cols);
    	Mat padded;							//填充边界,当图片尺寸为2,3,5的整数倍时,离散傅里叶变换速度最快
    	copyMakeBorder(dst, padded, 0,m - dst.rows, 0, n - dst.cols,BORDER_CONSTANT,Scalar::all(0));
    	//为傅里叶变化的结果(实部和虚部)分配存储空间
    	Mat planes[] = { Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F) };
    	Mat complexI;
    	merge(planes, 2, complexI);
    
    	dft(complexI,complexI);//进行就地离散傅里叶变换
    	
    	//将复数转换为幅值
    	split(complexI, planes);
    	magnitude(planes[0], planes[1], planes[0]);
    	Mat magnitudeImage = planes[0];
    	
    	//进行对数尺度缩放
    	magnitudeImage += Scalar::all(1);
    	log(magnitudeImage, magnitudeImage);
    
    	//剪切和重分布幅度图像限
    	int cx = magnitudeImage.cols / 2;
    	int cy = magnitudeImage.rows / 2;
    	Mat q0(magnitudeImage, Rect(0, 0, cx, cy));   // ROI区域的左上
    	Mat q1(magnitudeImage, Rect(cx, 0, cx, cy));  // ROI区域的右上
    	Mat q2(magnitudeImage, Rect(0, cy, cx, cy));  // ROI区域的左下
    	Mat q3(magnitudeImage, Rect(cx, cy, cx, cy)); // ROI区域的右下
    	//交换象限(左上与右下进行交换)
    	Mat tmp;
    	q0.copyTo(tmp);
    	q3.copyTo(q0);
    	tmp.copyTo(q3);
    	//交换象限(右上与左下进行交换)
    	q1.copyTo(tmp);
    	q2.copyTo(q1);
    	tmp.copyTo(q2);
    
    	normalize(magnitudeImage, magnitudeImage, 0, 1, CV_MINMAX);
    	imshow("【5】频谱幅值", magnitudeImage);
    
    	//4、二值化后找出频率变化最大的直线角度
    	//二值化并画出频谱图
    	Mat thresholdImg(magnitudeImage.size(), CV_8UC1);
    	magnitudeImage.convertTo(thresholdImg, CV_8UC1, 255, 0);//因归一化后数值均小于1,故应扩大回原有数值方便阈值化及后续操作
    	threshold(thresholdImg, thresholdImg,160,255,CV_THRESH_BINARY);
    	imshow("【6】频谱二值化图",thresholdImg);
    

    在这里插入图片描述
    在这里插入图片描述
    在此与参考资料2代码做了找出倾斜直线角度的修改,考虑到频谱二值化图中仍存在干扰,提高霍夫转换阈值可提取出最长线段,但阈值如果取得较低可能会出现多条线段,资料2中没有考虑到此种情况,将所有线段都画了出来(虽然只有一条),我则采用累计概率霍夫变换(好像更复杂了。。。)求出最长线段

    //找出最长直线及其角度
    	Mat angleImg(thresholdImg.size(),thresholdImg.type(),Scalar::all(0));
    	vector<Vec4i> lines;
    	HoughLinesP(thresholdImg, lines, 1, CV_PI / 180, 150, 0, 0);	
    	int maxNum = 0;
    	double len = 0;
    	for (int i = 0; i < lines.size(); i++)
    	{
    		Vec4f j = lines[i];
    		Point2f point1 = Point2f(j[0], j[1]);
    		Point2f point2 = Point2f(j[2], j[3]);
    		if (len <=(Point2PointDist(point1, point2)))
    		{
    			len = Point2PointDist(point1, point2);
    			maxNum = i;
    		}
    	}
    	Point2f a = Point(lines[maxNum][0], lines[maxNum][1]);
    	Point2f b = Point(lines[maxNum][2], lines[maxNum][3]);
    	line(angleImg, a,b, Scalar::all(255),1,CV_AA);
    	imshow("条码倾斜角度", angleImg);
    	double angle=Line_Angle(a, b);
    	Point center = Point(imageGray.cols/2,imageGray.rows/2);
    	Mat rotMat = getRotationMatrix2D(center,angle,1);
    	Mat rotImg(imageGray.size(), imageGray.type());
    	warpAffine(imageGray,rotImg,rotMat,rotImg.size());
    	imshow("校正图像", rotImg);
    
    	//扫描并显示信息
    	int width = rotImg.cols;
    	int height = rotImg.rows;
    	uchar *raw = (uchar *)rotImg.data;
    	Image imageZbar(width, height, "Y800", raw, width * height);//y800实际为灰度图代号
    	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 << endl;
    		cout << "条码:" << endl << symbol->get_data() << endl << endl;
    	}
    	
    	waitKey();
    	imageZbar.set_data(NULL, 0);
    	return 0;
    }
    
    //计算两点之间距离
    double Point2PointDist(Point2f& a,Point2f& b)
    {
    	double res = sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2));
    	return res;
    }
    
    //计算一条直线与水平线角度
    double Line_Angle(Point2f& a,Point2f& b)
    {
    	float k = 0;
    	k= (b.y -a.y) / (b.x-a.x);
    	double angle = atan(k) / CV_PI * 180;	//图片x轴在正上方
    	return angle;
    }
    

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • VS+OPENCV+ZBAR一维,二维码识别,对于中文乱码已经解码
  • **Zbar+Qt+opencv识别维条码** 这几天用qt+zbar在windows下识别条码可谓是入坑无数。首先是关于qt调用zbar一直没有成功。引用.a文件失败。直接引用又失败。找不到原因。重新使用MGW编译后无法使用,浪费了很多...
  • <p style="text-align:center"><img alt="" src="https://img-ask.csdnimg.cn/upload/1623641498442.jpg" /></p>  </p>
  • 主要介绍了在OpenCV里实现条码区域识别的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • github代码、Harris角点 cornerHarris() R = det(M) - k*(trace(M))^2 算法基本思想是使用个固定窗口在图像上进行任意方向上的滑动,  比较滑动前与滑动后两种情况,窗口中的像素灰度变化程度,  如果存在...
  • 一维码二维码识别.rar

    2021-03-07 10:46:06
    详细内容看我的博文一维码二维码识别(opencv c++)
  • 次提到了 三重建,许是三重建的应用面太广,从 PrimSense 到 Kinnect 再到RealSense,还有堆国内的山寨机不表。  从 Kinnect Fusion 到 Project Tango,伟大的项目 见证着个说法:世界总归是三的。 ...
  • 开发环境VS2015/C#,使用OpenCvSharp加ZXing实现条形的定位和识别。
  •  在一维信号中,图像也可以通过各种低通滤波器(LPF)、高通滤波器(HPF)等来过滤,LPF有助于消除噪声,模糊图像等。HPF过滤器有助于在图像中寻找边缘。  OpenCV提供了一个函数cv.filter2D()来将一个内核与一...
  • 工具版本:Android Studio版本3.4.2,OpenCV版本4.1.1 效果图: 下载和配置opencv 下载:https://opencv.org/releases/ 1.opencv-4.1.1-android-sdk.zip下载完成之后,解压。解压之后有文件夹simples,sdk等。...
  • OPENCV条形定位与识别

    热门讨论 2016-03-15 11:16:35
    opencv条形定位与识别,比较适合饮料瓶上的商标和二维码条形混在一起的情况,使用ZBAR完成识别过程
  • Opencv入门系列

    2021-01-30 22:09:14
    Opencv入门系列 、库 1.1 分类 1.1.1 Opencv库 ● Core:核心模块 ●Improc:图像转化模块 ●Highgui:图形交互模块 ●Video:视频模块 ●Calib3d:3d算法模块 ●Feature2d:2d算法模块 ●Ml:机器学习模块 ●...
  • 点击上方“小白学视觉”,选择加"星标"或“置顶” 重磅干货,第时间送达 推荐阅读 42个pycharm使用技巧,瞬间从黑铁变王者Google C++项目编程风格指南 ...
  • 注:本文主要针对Matlab和OpenCV跨平台进行相机标定、单相机三重建工作的实现,因为我发现网上竟然没有篇博客径直指出这两者在进行图像处理时的巨大差异(坐标系完全不同),不然我也不会走了很多弯路(呜呜呜欲...
  • 点击上方“小白学视觉”,选择加"星标"或“置顶”重磅干货,第时间送达本期,我们将一起学习如何从图像中提取出含有条形的区域。下面的代码,我们将在Anaconda中采用P...
  • 1、下载zbar库,zbar库下载地址如下: ...2、下载opencvopencv下载地址如下(需根据自己的VS版本下载对应的opencv版本,详见下面注意事项): https://opencv.org/releases/page/3/ 3、配置过程参考这篇文章: ...
  • 基于OpenCV的条形区域检测(完)

    千次阅读 2016-12-21 23:49:03
    基于OpenCV的条形区域检测(完) 工作较忙,该系列随笔就要草草收尾,这篇将贴出完整代码,经过大略整理并添加关键注释,希望能够帮助理解。 当时只是验证性质的实现,所以代码比较粗糙,请谅解!  若有疑问,...
  • 一维条形128嘛解码

    2011-05-13 20:00:13
    用于解码一维条形128嘛,基于OPENCV
  • VS2013平台利用opencv实现二维码和一维码的识别。需安装配置Z-bar库
  • opencv4 QR检测和识别源码解析

    千次阅读 2019-06-16 11:09:06
    opencv4新增功能之——QR检测和识别。下面简要介绍其算法步骤。 算法流程 缩放图片;opencv中设定待检测的图片最小维度为512,因此,如果图片的宽/高小于512话,将会保持长宽比缩放到512; 阈值化;采用...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,160
精华内容 2,064
关键字:

opencv一维码