OpenCV 检测二维码并定位

注意:该程序功能是检测二维码,不是识别,只是在图中定出二维码的位置即可

原图是这样:如果出现这张图片时,程序需要找到二维码

这里写图片描述

其余图片是这样:

这里写图片描述

程序步骤: 
1.图片缩小 
2.灰度化,直方图均衡化,对比度增强,滤波 
3.otsu阈值分割 
4.五次膨胀 
5.轮廓查找,如果轮廓满足一下条件,认为可能为二维码区域,像素面积大于60,长短轴之比小于1.3 
6.对疑似区域做判断,因为本实验二维码贴在大概中心位置,找到疑似轮廓的质心,判断质心是不是在图片长宽的三分之一到三分之二之间,如果是认为是二维码区域 
7.对二维码区域画成蓝色

#include <stdio.h>  
#include <opencv/highgui.h>  
#include <time.h>  
#include <opencv2/opencv.hpp>  
#include <opencv/cv.h>  
#include <iostream> 

using namespace std;  
using namespace cv; 

int main(int argc,char *argv[])  
{

    Mat srcImage;
    Mat resizeImage;
    Mat grayImage;
    Mat equalizeHistImage;
    Mat contrastandbrightImage;
    Mat sobelImage;
    Mat thresholdImage;
    Mat dilateImage;
    Mat areaImage;
    Mat ellipseImage;
    srcImage = imread("3.jpg");
    Size dsize = Size(srcImage.cols*0.3,srcImage.rows*0.3);
    resize(srcImage, resizeImage,dsize);
    cvtColor(resizeImage,grayImage,CV_BGR2GRAY);
    equalizeHist(grayImage,equalizeHistImage);
    亮度、对比度增强
    contrastandbrightImage= Mat::zeros( equalizeHistImage.size(), equalizeHistImage.type() ); 
    for(int y = 0; y < equalizeHistImage.rows; y++ )  
    {  
        for(int x = 0; x <equalizeHistImage.cols; x++ )  
        {  
            contrastandbrightImage.at<uchar>(y,x)= saturate_cast<uchar>(6*(equalizeHistImage.at<uchar>(y,x) ));     
        } 
    } 
    blur(contrastandbrightImage,contrastandbrightImage,Size(3,3));  
    //Sobel(contrastandbrightImage, sobelImage, CV_8U, 0,1 ,1, 1, 0, BORDER_DEFAULT);
    threshold(contrastandbrightImage,thresholdImage, 0, 255, CV_THRESH_OTSU+CV_THRESH_BINARY_INV);  
    Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));  
    //进行膨胀操作  
    dilate(thresholdImage, dilateImage, element);  
    dilate(dilateImage, dilateImage, element);
    dilate(dilateImage, dilateImage, element);  
    dilate(dilateImage, dilateImage, element);  
    dilate(dilateImage, dilateImage, element);  

    //dilateImage.copyTo(areaImage);
    //vector< vector< Point> > contours;  
    //findContours(areaImage,contours,CV_RETR_TREE,  CV_CHAIN_APPROX_NONE); 
    //vector<vector<Point> >::iterator itc= contours.begin();  
    //while (itc!=contours.end()) 
    //{  
    //  if( itc->size()<100)
    //  {  
    //      itc= contours.erase(itc);  
    //  }
    //   else
    //   {
    //     ++itc;  
    //  }
    //}  
    //drawContours(areaImage, contours, -1, Scalar(255), CV_FILLED);

    //找轮廓 两步判断  一个是大小  一个是长短轴比比  认为面积比60大,长短轴比比1.3小的区域是二维码区域  再做下一步判断
    dilateImage.copyTo(ellipseImage);
    vector<vector<Point> > twocontours;
    vector<Vec4i>twohierarchy;
    findContours(ellipseImage,twocontours,twohierarchy,CV_RETR_TREE,CV_CHAIN_APPROX_SIMPLE);  
    vector<Moments> mu(twocontours.size() );      
    vector<Point2f> mc( twocontours.size() );
    for(int k = 0; k < (int)twocontours.size(); k++)    //查找轮廓
    {
        if (int(twocontours.at(k).size()) <=60)//轮廓面积小于60的不处理
        {
            drawContours(ellipseImage, twocontours, k, Scalar(0), CV_FILLED);
        }
        else
        {
            RotatedRect rRect = fitEllipse(twocontours.at(k)); 
            double majorAxis = rRect.size.height > rRect.size.width ? rRect.size.height : rRect.size.width;
            double minorAxis = rRect.size.height > rRect.size.width ? rRect.size.width : rRect.size.height;
            float rate = majorAxis/minorAxis;
            if (rate<1.3)   //长短轴之比小于1.4的轮廓
            {
                //可能为二维码的区域,判断是否为二维码区域
                printf("%f\n",rate);
                //求区域的质心
                mu[k] = moments( twocontours[k], false );   
                mc[k] = Point2d( mu[k].m10/mu[k].m00 , mu[k].m01/mu[k].m00 ); 
                //打印质心
                printf("x=%f,y=%f\n",mc[k].x,mc[k].y);
                //打印图像的长宽
                printf("图像的长%d,图像的宽%d\n",resizeImage.cols,resizeImage.rows);
                //画出质心
                Point center = Point(mc[k].x,mc[k].y);  
                int r = 10;    
                circle(resizeImage,center,r,Scalar(255,0,0));  
                //判断质心是不是在图像中间   三分之一 < 质心 < 三分之二
                if ((int)mc[k].x<(int)2*(resizeImage.cols/3)&&(int)mc[k].x>(int)(resizeImage.cols/3))
                {
                    if ((int)mc[k].y<(int)2*(resizeImage.rows/3)&&(int)mc[k].y>(int)(resizeImage.rows/3))
                    {
                            drawContours(resizeImage, twocontours, k, Scalar(255,0,0), CV_FILLED);//把轮廓涂成蓝色
                            printf("蓝色是二维码区域\n");
                    }
                }
            }
            else  //长短轴之比大于1.4的轮廓  不是二维码区域
            {
                drawContours(resizeImage, twocontours, k, Scalar(0,0,255), CV_FILLED);//把轮廓涂成红色
            }
        }
    }       
    imshow("缩小图",resizeImage);
    imshow("灰度图",grayImage);
    imshow("对比度和亮度增强",contrastandbrightImage);
    //imshow("soble检测",sobelImage);
    imshow("二值化结果",thresholdImage);
    imshow("膨胀",dilateImage);
    //imshow("删除小面积",areaImage);
    imshow("长短轴",ellipseImage);
    waitKey(0);
}


 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127

部分结果图:

这里写图片描述

这里写图片描述

无二维码图片的结果图:

这里写图片描述

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值