数字图像处理【11】OpenCV-Canny边缘提取到FindContours轮廓发现

这篇具有很好参考价值的文章主要介绍了数字图像处理【11】OpenCV-Canny边缘提取到FindContours轮廓发现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本章主要介绍图像处理中一个比较基础的操作:Canny边缘发现、轮廓发现 和 绘制轮廓。概念不难,主要是结合OpenCV 4.5+的API相关操作,为往下 "基于距离变换的分水岭图像分割" 做知识储备。

Canny边缘检测

在讲述轮廓之前,要花点时间学学边缘检测提取的一个著名算法——Canny边缘提取算法。该算法检测出边相对于其他边缘检测算法的效果显著不同就是,Canny 检测出的边是比较细且清晰。该算法相比之前学习的Sobel和Laplace而言,它是一个应用方法,是真正的做到“提取”边缘这个操作;而Sobel和Laplace只是提留在图像像素的集合中。

Canny 算法的边缘检测到提取,主要有如下几个步骤:

1、灰度化cvColor与高斯滤波GaussianBlur

将图像变为灰度图像,减少通道,高斯滤波的作用是平滑图像,减少噪声,不让Canny算法检测时,误认为是边缘,所以在一开始就使用这个高斯滤波来减少比较突出的地方,简单的来说就是过滤掉图像上不合适的地方。

2、计算图像的梯度和梯度方向Sobel/Scharr

图像的边缘是灰度值急剧变化的位置。比如在灰度图像中它只有明暗的变化,当某个地方的强度变化比较的剧烈,那么它就会形成一个边缘。明暗变化较大的地方,梯度变化也会很大。

3、非极大值抑制

这一步是要做什么的呢?经过上面的操作,我们只是对图像进行了一个增强,而并不是找到真正的边缘。而且经过1-2步骤发现的边缘是一个范围信号,但是边缘只能是一条或者一簇,所以我需要对非边缘的个体进行压制除掉?怎么做呢,就是在边缘的梯度方向上,不是给定的最大值的话,那就去掉不要。(如下图,左边是Sobel求梯度方向,右边是常用的抑制范围选取)

数字图像处理【11】OpenCV-Canny边缘提取到FindContours轮廓发现,# 数字图像处理,OpenCV 4.5,轮廓发现与绘制,Canny边缘提取

但是这个最大的阈值该如何设置?过高将许多原本是线的位置未设置,过低就会细碎边,我们希望效果是找到清晰、连续的边缘线。

4、双阈值筛选边缘连接

经过非极大值抑制后图像检测出边还是有许多灰色而且不算清晰。所以接下来设置双阈值,规定上下阈值,所谓双阈值就是有两个阈值分别是低阈值和高阈值。如果像素点灰度值是大于最大阈值就直接将其更新为 255 。如果像素点的灰度值小于最小阈值就将其灰度值更新为 0。如果像素点灰度值是处于最大阈值到最小阈值之间,就看其 8 邻域中是否有大于最大阈值的值,如果有也就将其归为 255,也可以取 8 领域的平均值。

Canny边缘检测算法基本上就是经过以上的步骤。OpenCV有对应优化的Canny方法,一起看看如何使用,往下在学发现轮廓的时候就要用到。

CV_EXPORTS_W void Canny(
    InputArray image,  // 8-bit输入图像
    OutputArray edges, // 输出的边缘图像,一般都是二值图像,背景是黑色
    double threshold1, // 低阈值,常取高阈值的1/2或者1/3 
    double threshold2, // 高阈值
    int apertureSize = 3,   // Sobel算子的size,取值3代表是3x3
    bool L2gradient = false // 选择true用L2=sqrt{(dI/dx)^2 + (dI/dy)^2}求梯度方向,
                            // 默认false用L1=|dI/dx|+|dI/dy|计算
);

轮廓(contour)

  • 轮廓发现是基于图像边缘提取的基础上,寻找对象轮廓的方法。所以边缘提取的阈值选定会影响最终轮廓发现的结果
  • API介绍:findContours发现轮廓 / drawContours绘制轮廓

数字图像处理【11】OpenCV-Canny边缘提取到FindContours轮廓发现,# 数字图像处理,OpenCV 4.5,轮廓发现与绘制,Canny边缘提取

有时候,轮廓和边缘的概念是非常相似的,在单一物体对象上表面的轮廓就相当于其边缘特征。但是多个物体对象叠加之后,轮廓和边缘就不再能这样相提并论了。(如上图示)

轮廓是在边缘的基础上,构成一张轮廓的拓扑图,然后利用不同的拓扑算法去寻找和构建轮廓。所以边缘提取的阈值选定会影响最终轮廓发现的结果。

说完边缘与轮廓的关系与区别之后。那么在OpenCV中,轮廓的发现绘制与绘制要如何实现呢?

  1. 输入图像转为灰度图像cvtColor
  2. 使用Canny进行边缘提取,转化二值图像
  3. 使用findContours发现轮廓
  4. 使用drawContours绘制轮廓

这里先介绍cv::findCountours 和 cv::drawContours这两个api

CV_EXPORTS_W void findContours(
    InputArray image,             // 输入图像,二值图,一般就是Canny的输出,8-bit
    OutputArrayOfArrays contours, // 全部发现的轮廓对象,就是一个二维数组,图结构,往下细说
    OutputArray hierarchy, // 轮廓图的拓扑结构,可选输出,最终的轮廓发现就是基于这个拓扑结构实现
    int mode,              // 寻找轮廓的模式,一般返回RETR_TREE树模式
    int method,            // 轮廓发现的方法,一般使用CHAIN_APPROX_SIMPLE简单方式
    Point offset = Point() // 轮廓像素偏移,默认(0,0)没偏移
);

CV_EXPORTS_W void drawContours( 
    InputOutputArray image, // 绘制的目标图像
    InputArrayOfArrays contours, // 全部轮廓对象,就是findContours的第二个输出参数
    int contourIdx,              // 轮廓索引号,contours的第一维索引
    const Scalar& color,         // 绘制颜色
    int thickness = 1,           // 绘制线宽
    int lineType = LINE_8,       // 绘制线类型
    InputArray hierarchy = noArray(), // 拓扑结构图,findContours的第三个可选输出参数
    int maxLevel = INT_MAX, // 最大层数,0只绘制当前的,1包含内部轮廓,2所有轮廓
    Point offset = Point()  // 轮廓偏移
);

接着来一段案例代码,讲讲findContours的第二、第三参数如何理解。

int main()
{
    //读取测试图片
    src = imread("F:\\other\\learncv\\bottle.png");
    namedWindow(titleStr + "src", WINDOW_AUTOSIZE);
    imshow(titleStr + "src", src);
    //rgb转gray
    cvtColor(src, gray, COLOR_BGR2GRAY);
    namedWindow(titleStr + "circles", WINDOW_AUTOSIZE);
    namedWindow(titleStr + "contours", WINDOW_AUTOSIZE);
    createTrackbar("边缘检测阈值", titleStr + "src", &threshold_value, threshold_max, Callback_Contours);

    waitKey(0);
    return 0;
}

void Callback_Contours(int pos, void* userdata) {
    Mat canny_img;
    Canny(gray, canny_img, threshold_value, threshold_value * 2.0, 3, false);

    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    findContours(canny_img, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));

    Mat dst1 = Mat::zeros(gray.size(), CV_8UC3);
    Mat dst2 = Mat::zeros(gray.size(), CV_8UC3);

    for (size_t i = 0; i < contours.size(); i++) {
        drawContours(dst1, contours, i, colorWhite, 1, LINE_8, hierarchy, 0, Point(0, 0));

        vector<Point> contourPoints = contours[i];
        for (size_t j = 0; j < contourPoints.size(); j++) {
            circle(dst2, contourPoints[j], 1, colorWhite);
        }
    }
    imshow(titleStr + "contours", dst1);
    imshow(titleStr + "circles", dst2);
}

数字图像处理【11】OpenCV-Canny边缘提取到FindContours轮廓发现,# 数字图像处理,OpenCV 4.5,轮廓发现与绘制,Canny边缘提取

以上代码运行的效果,Canny边缘阈值在100~200之间。 其中我把Canny的第二个输出参数contours也以点的方式绘制出来,对应的是图最左边,中间部分是drawContours绘制的轮廓,右边是原图。放大可以清楚观察到 “荷花” 二字上方,荷花瓣的位置,明显看出点的方式是断断续续的中间留有很大一部分的空白,而绘制轮廓后是能把它们连接成一条线。这是因为drawContours会根据contours二维数据的第一维去判断这些是不是属于同一线段。Debug调试就可以知道contours[i]的每一层长度都是不一样的。

至于第三个参数 hierarchy 轮廓拓扑关系,此参数输出的内容 与 第四个参数 mode 寻找轮廓的模式,有莫大的关系,详细看看查阅以下这个同学的详细分析。

(十二) findContours函数的hierarchy详解_findcontours hierarchy_恒友成的博客-CSDN博客获取对象的轮廓,一般最好先对图像进行灰度化再进行阈值处理,然后用来检测轮廓。_findcontours hierarchyhttps://blog.csdn.net/lx_ros/article/details/126258801

Ok,That’s All.文章来源地址https://www.toymoban.com/news/detail-563473.html

到了这里,关于数字图像处理【11】OpenCV-Canny边缘提取到FindContours轮廓发现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 《数字图像处理-OpenCV/Python》连载:形态学图像处理

    本书京东 优惠购书链接 https://item.jd.com/14098452.html 本书CSDN 独家连载专栏 https://blog.csdn.net/youcans/category_12418787.html 形态学图像处理是基于形状的图像处理,基本思想是利用各种形状的结构元进行形态学运算,从图像中提取表达和描绘区域形状的结构信息。形态学运算的数学原

    2024年02月19日
    浏览(80)
  • OpenCV数字图像处理基于C++:图像分割

    图像阈值化分割是一种常用的、传统的图像分割技术,因其 实现简单、计算量小、性能比较稳定 而成为图像分割中基本和应用广泛的分割技术。特别 适合于目标和背景占据不同灰度级范围的图像 。不仅 可以极大地压缩数据量 ,而且大大 简化了分析和处理的步骤 ,是进行

    2024年02月11日
    浏览(69)
  • OpenCV数字图像处理详细教程

    1.编写程序,将自选图像(如图 1)和 OpenCV 的 Logo 图像叠加现实,其中 Logo 图像做背景透明处理。(提示:OpenCV 的 Logo 图像背景是白色的)   实现代码及注释讲解 结果展示   编写程序,使用 cv2.warpAffine()函数使一幅图像放大为原来的二倍后,以图像中 心为原点,顺时针旋

    2024年04月17日
    浏览(46)
  • 《数字图像处理-OpenCV/Python》连载(41)图像的旋转

    本书京东优惠购书链接:https://item.jd.com/14098452.html 本书CSDN独家连载专栏:https://blog.csdn.net/youcans/category_12418787.html 几何变换分为等距变换、相似变换、仿射变换和投影变换,是指对图像的位置、大小、形状和投影进行变换,将图像从原始平面投影到新的视平面。OpenCV图像的几

    2024年02月05日
    浏览(60)
  • 《数字图像处理-OpenCV/Python》连载(44)图像的投影变换

    本书京东优惠购书链接:https://item.jd.com/14098452.html 本书CSDN独家连载专栏:https://blog.csdn.net/youcans/category_12418787.html 几何变换分为等距变换、相似变换、仿射变换和投影变换,是指对图像的位置、大小、形状和投影进行变换,将图像从原始平面投影到新的视平面。OpenCV图像的几

    2024年02月04日
    浏览(75)
  • 轻松入门数字图像处理,搞定OpenCV编程!

    在刚开始学习数字图像处理时,你是否也有这样的困扰: 教材的开篇介绍绪论和数学工具,看得似懂非懂,似乎还不涉及编程…… 接下来学习灰度变换、空间滤波和频域滤波,涉及内容丰富、方法繁多,试着编了几个程序就编不下去了…… 开始学习OpenCV,找了几本参考书,

    2024年02月09日
    浏览(51)
  • 《数字图像处理-OpenCV/Python》连载(10)图像属性与数据类型

    本书京东优惠购书链接:https://item.jd.com/14098452.html 本书CSDN独家连载专栏:https://blog.csdn.net/youcans/category_12418787.html 在Python语言中,OpenCV以Numpy数组存储图像,对图像的访问和处理都是通过Numpy数组的操作来实现的。 本章内容概要 介绍Python语言中OpenCV的数据结构,学习获取图像

    2024年02月07日
    浏览(88)
  • 《数字图像处理-OpenCV/Python》连载(4)图像的读取与保存

    本书京东优惠购书链接:https://item.jd.com/14098452.html 本书CSDN独家连载专栏:https://blog.csdn.net/youcans/category_12418787.html 为了方便初学者从零开始学习OpenCV-Python,本书从图像的读取、保存和显示等基本操作开始介绍,使读者可以循序渐进地使用和理解本书的每一个例程。 本章内容

    2024年02月09日
    浏览(64)
  • OpenCV数字图像处理基于C++:边缘检测

    边缘检测是图像处理和计算机视觉中的基本问题,边缘检测的目的是标识数字图像中亮度变化明显的点。图像属性中的显著变化通常反映了属性的重要事件和变化。 图像边缘检测大幅度地减少了数据量,并且剔除了可以认为不相关的信息,保留了图像重要的结构属性。有许多

    2024年02月05日
    浏览(59)
  • 数字图像处理 基于OpenCV的景深融合算法

            景深 合成是对显微镜头连续变焦时采集的非平面物体的图像序列进行分析,提取序列里每一帧图像中聚焦相对清晰的区域,然后对这些区域按其位置进行聚焦清晰度竞争、图像 融合 ,形成一幅新的各区域都清晰的全 景深 的图像。         这里算法的前提是图像

    2024年02月14日
    浏览(47)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包