opencv 十四 二维码的粗定位提取

这篇具有很好参考价值的文章主要介绍了opencv 十四 二维码的粗定位提取。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、算法需求

对原始图像进行优化,提取其中的二维码区域,以便于后续算法(如zbar库)进行识别。具体图片如下所示。
补充说明:在进行二维码识别时,二维码成像区域太小,很容易导致识别失败。手机软件(如微信或支付宝)在识别二维码时,发现二维码较小,会自动缩放摄像头。
dm二维码roi提取,opencv实战,opencv,人工智能,计算机视觉

二、问题分析

对上图进行分析发现,图像中的二维码有以下特点:
1、二维码成像区域较小,在全图中占比不大===》二维码提取难度大
2、图像光照环境较为复杂,有亮部、暗部、阴影、黑色物体===》较难进行合理的二值化
3、背景比较复杂,存在灰色和白色的斑点,而二维码是白色和黑色的斑点===》二维码的局部图形与背景图形高度类似

三、核心思路

1、读取图片为灰度图,并优化图像质量(使用滤波尽可能减少图像背景的复杂度)
2、对图像进行自适应二值化(其可以根据图像局部空间,计算每一个区域的二值化阈值)
3、图形显著化,使用大kernel进行均值滤波,使二维码图形在原二值化中变得十分显著【该操作可以提升二维码区域的显著度,弱化背景】
4、显著区域提取,根据均值滤波结果进行二值化,并找出最大面积连通域,然后得出其位置

四、具体实现

4.1 读取并优化图像

使用GaussianBlur可以降低图像中的噪声

	std::string path = "D:\\实战项目\\二维码识别\\img2.jpg";
	Mat imageSource = imread(path, 0);
	Mat img_blur, img_bin, img_boxfilter, img_boxfilter_bin, img_boxfilter_bin_erode;
	    imageSource.copyTo(img_blur);
    GaussianBlur(img_blur, img_blur, Size(3, 3), 0);  //滤波  

dm二维码roi提取,opencv实战,opencv,人工智能,计算机视觉

4.2 自适应二值化

自适应二值化是一种图像处理技术,它可以根据图像的局部特征自适应地设定阈值,做出二值化处理。这种技术有多种实现方式,其中一种是自适应阈值二值化。自适应阈值二值化是一种局部的方法,使用一个滑动窗口在图片上滑动,使用窗口内的值来计算阈值。
在使用过程中,针对不同尺度的目标需要调整blockSize的值,本文中值为7.

//自适应二值化
    cv::adaptiveThreshold(img_blur, img_bin, 255, cv::THRESH_BINARY_INV, cv::ADAPTIVE_THRESH_GAUSSIAN_C, 7, 8);

自适应二值化的参数列表及其含义如下:
void adaptiveThreshold(InputArray src, OutputArray dst, double maxValue, int adaptiveMethod, int thresholdType, int blockSize, double C)

src参数 表示输入图像(8位单通道图像);
maxValue参数 表示使用 THRESH_BINARY 和 THRESH_BINARY_INV 的最大值;
adaptiveMethod参数 表示自适应阈值算法,平均 (ADAPTIVE_THRESH_MEAN_C)或高斯(ADAPTIVE_THRESH_GAUSSIAN_C);
thresholdType参数表示阈值类型,必须为THRESH_BINARY或THRESH_BINARY_INV的阈值类型;
blockSize参数 表示块大小(奇数且大于1,比如3,5,7........ );
C参数是常数,表示从平均值或加权平均值中减去的数。通常情况下,这是正值,但也可能为零或负值。

在进行自适应二值化后,可以发现二维码区域已经比较显著,但是无法将其与背景噪音移除开。(曾尝试过低通滤波【无法完全消除噪点】、选最大面积连通域【图形中的白线或数字才是最大面积连通域】、选topk连通域【k值不确定,不同的图片需要修改k值才能确保二维码被保留】)
dm二维码roi提取,opencv实战,opencv,人工智能,计算机视觉

4.3 图形显著化

大kernel均值滤波是一种图像平滑处理方法,它可以通过对图像进行卷积操作,将每个像素的值替换为其周围像素的平均值。这种方法的优点是简单易懂,计算速度快,而且可以有效地去除噪声。然而,大kernel均值滤波也有一些缺点,例如它可能会导致图像模糊,而且在处理边缘时可能会产生不良效果。但是,在很多背景噪声较多的图片中,大kernel均值滤波,使噪声变得更加平滑,同时使目标图像变得显著的亮、或者显著性的暗。

boxFilter(img_bin, img_boxfilter, -1, Size(50, 50), Point(-1, -1), true);
cv::threshold(img_boxfilter, img_boxfilter_bin, 60, 255, cv::THRESH_BINARY);

通过大kernel均值均值滤波后,只有二维码区域和数字区域比较显著。
dm二维码roi提取,opencv实战,opencv,人工智能,计算机视觉
在进行二值化后,就只有二维码区域和数字区域了
dm二维码roi提取,opencv实战,opencv,人工智能,计算机视觉

4.4 显著区域提取

先对二值图进行进行腐蚀,使一些错误的显著区域(数字区域)与目标显著区域断开连接,然后找到最大面积连通域,再对其进行膨胀,使其能完整的覆盖原图二维码区域。最后,获取图形的外接矩形,并基于此将其从原图中截取出来。

以下代码中的findTopKArea函数源自https://hpg123.blog.csdn.net/article/details/126864086


	morphologyEx(img_boxfilter_bin, img_boxfilter_bin_erode, MORPH_ERODE,
        getStructuringElement(MORPH_RECT, Size(7, 7)));
 Mat img_max_area, img_area_dilate, img_qr_area;
    // 找到最大面积连通域(二维码区域)
    img_max_area = findTopKArea(img_boxfilter_bin_erode, 1);

    //使二维码的连通域能覆盖原图区域
    morphologyEx(img_max_area, img_area_dilate, MORPH_DILATE,
        getStructuringElement(MORPH_RECT, Size(31, 31)));
    bitwise_and(img_area_dilate, imageSource, img_qr_area);

    //获取轮廓的外接矩形,并裁剪出来
    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    findContours(img_area_dilate, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));
    vector<Rect> boundRect(contours.size());
    for (int i = 0; i < contours.size(); i++)
    {
        boundRect[i] = boundingRect(Mat(contours[i]));
        rectangle(imageSource, boundRect[i].tl(), boundRect[i].br(), (0, 0, 255), 2, 8, 0);
    }
    Mat ROI = imageSource(boundRect[0]);

对图形进行腐蚀,使二维码区域与数字区域断开
dm二维码roi提取,opencv实战,opencv,人工智能,计算机视觉
选择最大面积连通域,保留二维码区域
dm二维码roi提取,opencv实战,opencv,人工智能,计算机视觉
对二维码区域进行膨胀后,获取其连通域位置并绘制在原图上。
dm二维码roi提取,opencv实战,opencv,人工智能,计算机视觉

五、完整代码

以下代码中,opencv的配置请参考https://blog.csdn.net/m0_74259636/article/details/128525031文章来源地址https://www.toymoban.com/news/detail-834699.html

#include <iostream>
#include "string.h"
#include <opencv2/opencv.hpp>
using namespace std;  
using namespace cv;

//https://hpg123.blog.csdn.net/article/details/126864086
bool mypairsort(pair<int, int> i, pair<int, int> j) { return (i.second > j.second); }
//找图中topk个连通域
Mat findTopKArea(Mat srcImage, int topk)
{
    Mat temp;
    Mat labels;
    srcImage.copyTo(temp);

    //1. 标记连通域
    int n_comps = connectedComponents(temp, labels, 4, CV_16U);
    vector<pair<int, int>> histogram_of_labels;
    for (int i = 0; i < n_comps; i++)//初始化labels的个数为0
    {
        histogram_of_labels.push_back({ i,0 });
    }

    int rows = labels.rows;
    int cols = labels.cols;
    for (int row = 0; row < rows; row++) //计算每个labels的个数--即连通域的面积
    {
        for (int col = 0; col < cols; col++)
        {
            histogram_of_labels.at(labels.at<unsigned short>(row, col)).second += 1;
        }
    }
    //histogram_of_labels.at(0).second = 0; //将背景的labels个数设置为0

    //2.对连通域进行排序
    std::sort(histogram_of_labels.begin(), histogram_of_labels.end(), mypairsort);
    //3. 取前k个连通域的labels id
    vector<int> select_labels;
    for (int i = 0; i < topk; i++)
    {
        if (histogram_of_labels[i].first == 0) {
            topk += 1;
            //如果碰到背景,则跳过,且topk+1
        }
        else {
            select_labels.push_back(histogram_of_labels[i].first);
        }
    }

    //3. 将label id在select_labels的连通域标记为255,并将其他连通域置0
    for (int row = 0; row < rows; row++)
    {
        for (int col = 0; col < cols; col++)
        {
            int now_label_id = labels.at<unsigned short>(row, col);
            if (std::count(select_labels.begin(), select_labels.end(), now_label_id)) {
                labels.at<unsigned short>(row, col) = 255;
            }
            else {
                labels.at<unsigned short>(row, col) = 0;
            }
        }
    }

    //4. 将图像更改为CV_8U格式
    labels.convertTo(labels, CV_8U);
    return labels;
}

//截取出图像中的二维码
Mat get_qr_code(Mat imageSource) {
    Mat img_blur, img_bin, img_boxfilter, img_boxfilter_bin, img_boxfilter_bin_erode;
    imageSource.copyTo(img_blur);
    GaussianBlur(img_blur, img_blur, Size(3, 3), 0);  //滤波  
    //自适应二值化
    cv::adaptiveThreshold(img_blur, img_bin, 255, cv::THRESH_BINARY_INV, cv::ADAPTIVE_THRESH_GAUSSIAN_C, 7, 8);

    // true表示为 均值滤波
    boxFilter(img_bin, img_boxfilter, -1, Size(50, 50), Point(-1, -1), true);

    cv::threshold(img_boxfilter, img_boxfilter_bin, 60, 255, cv::THRESH_BINARY);

    //imshow("img_bin", img_bin);
    //imshow("img_boxfilter", img_boxfilter);

    //-------------进行形态学操作,提取二维码区域切片--------
    // 使连通域断开,将二维码主体与数字进行分离
    morphologyEx(img_boxfilter_bin, img_boxfilter_bin_erode, MORPH_ERODE,
        getStructuringElement(MORPH_RECT, Size(7, 7)));

    Mat img_max_area, img_area_dilate, img_qr_area;
    // 找到最大面积连通域(二维码区域)
    img_max_area = findTopKArea(img_boxfilter_bin_erode, 1);

    //使二维码的连通域能覆盖原图区域
    morphologyEx(img_max_area, img_area_dilate, MORPH_DILATE,
        getStructuringElement(MORPH_RECT, Size(31, 31)));
    bitwise_and(img_area_dilate, imageSource, img_qr_area);

    //获取轮廓的外接矩形,并裁剪出来
    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    findContours(img_area_dilate, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));
    vector<Rect> boundRect(contours.size());
    for (int i = 0; i < contours.size(); i++)
    {
        boundRect[i] = boundingRect(Mat(contours[i]));
        rectangle(imageSource, boundRect[i].tl(), boundRect[i].br(), (0, 0, 255), 2, 8, 0);
    }
    Mat ROI = imageSource(boundRect[0]);

    //
    imshow("imageSource", imageSource);
    imshow("img_blur", img_blur);
    imshow("img_bin", img_bin);
    imshow("img_boxfilter", img_boxfilter);
    imshow("img_boxfilter_bin", img_boxfilter_bin);
    imshow("img_boxfilter_bin_erode", img_boxfilter_bin_erode);
    imshow("img_max_area", img_max_area);;
    imshow("ROI", ROI);
    return ROI;
}
int main(int argc, char* argv[]) {
    std::string path = "img2.jpg";
    Mat imageSource = imread(path, 0);
    Mat qrcode = get_qr_code(imageSource);
}

到了这里,关于opencv 十四 二维码的粗定位提取的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • OpenCV(三十八):二维码检测

    1.二维码识别原理 功能图形: 位置探测图形:通常,二维码中有三个位置探测图形,呈现L型或大角度十字架形状,分布在二维码的三个角上,用于帮助扫描设备定位二维码的位置和方向。 位置探测图形分隔符:帮助扫描设备区分位置探测图形和二维码的数据区域。 计算模式

    2024年02月07日
    浏览(39)
  • 计算机竞赛 基于机器视觉的二维码识别检测 - opencv 二维码 识别检测 机器视觉

    🔥 优质竞赛项目系列,今天要分享的是 基于机器学习的二维码识别检测 - opencv 二维码 识别检测 机器视觉 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐! 🧿 更多资料, 项目分享: https://gitee.com/dancheng-senior/postgraduate 物体检测就是对数字图像中一类特定的物体的

    2024年02月11日
    浏览(58)
  • 互联网加竞赛 基于机器视觉的二维码识别检测 - opencv 二维码 识别检测 机器视觉

    🔥 优质竞赛项目系列,今天要分享的是 基于机器学习的二维码识别检测 - opencv 二维码 识别检测 机器视觉 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐! 🧿 更多资料, 项目分享: https://gitee.com/dancheng-senior/postgraduate 物体检测就是对数字图像中一类特定的物体的

    2024年01月18日
    浏览(64)
  • 计算机毕设 基于机器视觉的二维码识别检测 - opencv 二维码 识别检测 机器视觉

    今天学长向大家介绍一个机器视觉的毕设项目,二维码 / 条形码检测与识别 基于机器学习的二维码识别检测 - opencv 二维码 识别检测 机器视觉 物体检测就是对数字图像中一类特定的物体的位置进行自动检测。基本的检测框架有两种: 一种是以滑动窗口为单位对图像进行扫描

    2024年02月10日
    浏览(46)
  • 10. Opencv检测并截取图中二维码

    1. 说明 在二维码扫描功能开发中,使用相机扫描图片时,往往图片中的信息比较多样,可能会造成二维码检测失败的问题。一种提高检测精度的方式就是把二维码在图片中单独抠出来,去除其它冗余信息,然后再去识别这张提取出来的二维码。本篇博客记录采用的一种实现二

    2024年02月03日
    浏览(30)
  • opencv快速实现任意角度二维码矫正

    那天听到领导他们在讨论,说要将图片进行个矫正处理,还叫来了算法部的大佬来讨论将要如何处理这个,讨论场面很是激烈 不得不说好奇心是个很神奇的东西,就把我给吸引过去了 我定眼一看,感觉作为JAVA开发的我自己也能进行处理 因为看到了图片后,发现了图片中一个

    2024年02月05日
    浏览(58)
  • opencv检测二维码和条形码

    使用excel可以实现制作二维码,但只能实现做英文和数字类型的,步骤如下: 在任意单元格输入内容 选项卡里找到开发工具—插入—点击ActiveX控件的最右下角。 弹出的窗口内,往下滑动选择Microsoft BarCode Control 16.0后,点击确定。 在任意区域,摁住鼠标左键不放,拖动鼠标,

    2024年02月10日
    浏览(45)
  • 利用opencv实现二维码检测(简单易上手)

    二维码检测是一个简单易上手的小项目,掌握opencv基础的语句就可以实现。解析二维码的过程有专门的库来实现,所以只需调相应的库就好了。在实现这个代码前,先要配置opencv环境。 Python与Opencv配置安装_哔哩哔哩_bilibili 这里用anaconda配置很方便 摄像头帧画面的提取:调用

    2024年02月04日
    浏览(38)
  • OpenCv案例(十): 基于OpenCvSharp识别二维码

    1:二维码在工业和工作生活中应用广泛,下面基于OpenCvSharp识别图像中二维码; 2:函数:OpenCvSharp中, QRCodeDetector  有两个相关API分别实现二维码检测与二维码解析。           public string DetectAndDecode(InputArray img, out Point2f[] points, OutputArray straightQrcode = null); 其中:      

    2024年02月11日
    浏览(33)
  • Python Opencv实践 - 二维码和条形码识别

            使用pyzbar模块来识别二维码和条形码。ZBar是一个开源软件,用来从图像中读取条形码,支持多种编码,比如EAN-13/UPC-A、UPC-E、EAN-8、代码128、代码39、交错2/5以及二维码。         pyzbar是python封装ZBar的模块,我们用它来做条形码和二维码的识别。         安装方法:

    2024年02月04日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包