《数字图像处理-OpenCV/Python》第14章:边缘检测与图像轮廓

news2024/10/5 16:26:48

《数字图像处理-OpenCV/Python》第14章:边缘检测与图像轮廓


本书京东 优惠购书链接 https://item.jd.com/14098452.html
本书CSDN 独家连载专栏 https://blog.csdn.net/youcans/category_12418787.html

在这里插入图片描述


第 14 章 边缘检测与图像轮廓


边缘是图像的基本特征。边缘检测根据灰度的突变检测边缘,检测到的边缘通常是零散的片段,并不是连续的整体,要从图像中提取目标物体,就要将边缘像素连接构成连续闭合的轮廓。边缘主要作为图像的特征使用,而轮廓主要用来分析物体的形态。

本章内容概要

  • 理解边缘检测的原理,学习使用梯度算子进行边缘检测。
  • 学习使用LoG算子、DoG算子和Canny算子进行边缘检测。
  • 学习查找轮廓的方法,绘制轮廓图像。
  • 介绍轮廓的属性、基本参数和形状特征。

14.6 轮廓的查找与绘制

轮廓是一系列相连的像素点组成的曲线,代表物体的基本外形。轮廓常用于形状分析和物体的检测和识别。
边缘检测根据灰度的突变检测边缘,但检测到的边缘通常是零散的片段,并未构成整体。从背景中分离目标,要将边缘像素连接构成轮廓,也就是说,轮廓是连续的,边缘不一定是连续的。边缘主要作为图像的特征使用,而轮廓主要用来分析物体的形态。


OpenCV中的函数cv.findContours用于从黑色背景的二值图像中寻找轮廓。
OpenCV中的函数cv.drawContours用于在图像上绘制轮廓线或填充轮廓。绘制图像轮廓并不是显示图像,而是在原始图像上添加轮廓线。

函数原型

cv.findContours(image, mode, method[, contours, hierarchy, offset]) → contours, hierarchy
cv.drawContours(image, contours, contourIdx, color[, thickness, lineType, hierarchy, maxLevel, offset]) → image

参数说明

  • image:输入图像,是8位单通道二值图像。
  • mode:轮廓查找模式。
    • RETR_EXTERNAL:只查找最外层的轮廓。
    • RETR_LIST:查找所有轮廓,不建立层次关系。
    • RETR_CCOMP:查找所有轮廓,组织为两层,顶层是外部轮廓。
    • RETR_TREE:查找所有轮廓,并重建嵌套轮廓的完整层次结构。
  • method:轮廓的表示方法。
    • CHAIN_APPROX_NONE:输出轮廓所有的像素点(x,y)。
    • CHAIN_APPROX_SIMPLE:对于水平线/垂直线/对角线,只保留线段端点。
    • CHAIN_APPROX_TC89_L1:应用Teh-Chin链近似算法L1。
    • CHAIN_APPROX_TC89_KCOS:应用Teh-Chin 链近似算法KCOS。
  • contours:查找到的所有轮廓,是列表格式,每个轮廓以点的坐标向量表示。
  • hierarchy:轮廓的层次结构,是Numpy数组,形状为(1,L,4)。
  • offset:偏移量,可选项。

注意问题

(1) 查找轮廓是针对黑色背景中的白色目标而言的,以得到白色目标的轮廓。如果背景为亮色和浅色,如白纸黑字的印刷书籍,要在查找轮廓前进行反色处理。
(2) 函数将输入图像按二值图像处理,所有非0像素都会被视为1,因此必须先通过阈值分割或边缘检测获得二值图像。推荐在平滑滤波后使用边缘检测方法,可以减少白色噪点,提高轮廓检测的效率和质量。
(3) contours是一个列表(List),不是Numpy数组,而轮廓列表中的元素是Numpy数组,列表长度L是查找到的轮廓总数。
(4) contours列表中的第i个元素contours[i]是形为(k,1,2)的Numpy数组,表示第i个轮廓,k是第i个轮廓中的像素点数量。contours[i]的每一行contours[i][k,1,:]有两个元素,分别表示第i个轮廓的第k个像素点的坐标(x,y)。
注意轮廓处理函数中像素点的坐标为(x,y),与OpenCV中像素点的坐标(y,x)的次序相反。
(5) hierarchy是形为(1,L,4)的Numpy数组。第i个轮廓的层次结构为:hierarchy[0,i,:]=[Next, Previous, FirstChild, Parent]。这4个元素hierarchy[0,i,0]~hierarchy[0,i,3]分别表示轮廓i的同层下一个轮廓Next、同层前一个轮廓Previous、第一个子轮廓FirstChild和父轮廓Parent的编号,-1表示不存在。
(6) 从实际图像中查找的轮廓往往数量很多、拓扑结构复杂,可以基于轮廓的层次结构进行筛选和识别。例如,使用 h i e r a r c h y [ 0 , i , 3 ] = = − 1 hierarchy[0,i,3]==-1 hierarchy[0,i,3]==1可以筛选没有父轮廓的最外层轮廓,使用 h i e r a r c h y [ 0 , i , 2 ] = = − 1 hierarchy[0,i,2]==-1 hierarchy[0,i,2]==1可以筛选没有子轮廓的最内层轮廓。
(7) 轮廓是由很多像素点组成的。使用CHAIN_APPROX_NONE时,contours[i]能保存轮廓所有的像素点,可以计算轮廓长度;而使用CHAIN_APPROX_SIMPLE时,contours[i]对水平线/垂直线/对角线只保留轮廓的线段端点,可以简化轮廓描述。
(8) 在OpenCV的不同版本中,函数cv.findContours的返回值不同,使用返回值格式不当会导致程序报错。例如,在OpenCV3中函数的返回值为[image,contours,hierarchy],而在OpenCV2、OpenCV4、OpenCV5 中函数的返回值为[contours,hierarchy]。


【例程1406】查找和绘制图像轮廓

本例程用于查找和绘制图像轮廓,并基于层次结构对轮廓进行筛选。
注意:在不同OpenCV版本中,函数cv.findContours的用法不同,详见程序注释。


# 【1406】查找和绘制图像轮廓
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

if __name__ == '__main__':
    img = cv.imread("../images/Fig1402.png", flags=1)
    gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)  # 灰度图像
    _, binary = cv.threshold(gray, 127, 255, cv.THRESH_OTSU + cv.THRESH_BINARY_INV)

    # 寻找二值图中的轮廓
    # binary, contours, hierarchy = cv.findContours(binary, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)  # OpenCV3
    contours, hierarchy = cv.findContours(binary, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)  # OpenCV4~
    # print("len(contours): ", len(contours))  # contours 是列表,只有长度没有形状
    print("hierarchy.shape: ", hierarchy.shape)  # 层次结构

    # 绘制全部轮廓
    contourTree = img.copy()  # OpenCV 某些版本会修改原始图像
    contourTree = cv.drawContours(contourTree, contours, -1, (0, 0, 255), 2)  # OpenCV3

    #  绘制最外层轮廓和最内层轮廓
    imgContour = img.copy()
    for i in range(len(contours)):  # 绘制第 i 个轮廓
        x, y, w, h = cv.boundingRect(contours[i])  # 外接矩形
        text = "{}#({},{})".format(i, x, y)
        contourTree = cv.putText(contourTree, text, (x, y), cv.FONT_HERSHEY_DUPLEX, 0.8, (0,0,0))
        print("i={}\tcontours[{}]:{}\thierarchy[0,{}]={}"
              .format(i, i, contours[i].shape, i, hierarchy[0][i]))
        if hierarchy[0,i,2]==-1:  # 最内层轮廓
            imgContour = cv.drawContours(imgContour, contours, i, (0,0,255), thickness=-1)  # 内部填充
        if hierarchy[0,i,3]==-1:  # 最外层轮廓
            imgContour = cv.drawContours(imgContour, contours, i, (255,255,255), thickness=5)

    plt.figure(figsize=(9, 3.2))
    plt.subplot(131), plt.axis('off'), plt.title("1. Original")
    plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
    plt.subplot(132), plt.axis('off'), plt.title("2. Contours")
    plt.imshow(cv.cvtColor(contourTree, cv.COLOR_BGR2RGB))
    plt.subplot(133), plt.axis('off'), plt.title("3. Selected contour")
    plt.imshow(cv.cvtColor(imgContour, cv.COLOR_BGR2RGB))
    plt.tight_layout()
    plt.show()
    

运行结果:

len(contours):  6
hierarchy.shape:  (1, 6, 4)
i=0	contours[0]:(24, 1, 2)	hierarchy[0,0]=[ 1 -1 -1 -1]
i=1	contours[1]:(24, 1, 2)	hierarchy[0,1]=[ 2  0 -1 -1]
i=2	contours[2]:(4, 1, 2)	hierarchy[0,2]=[-1  1  3 -1]
i=3	contours[3]:(8, 1, 2)	hierarchy[0,3]=[-1 -1  4  2]
i=4	contours[4]:(11, 1, 2)	hierarchy[0,4]=[ 5 -1 -1  3]
i=5	contours[5]:(11, 1, 2)	hierarchy[0,5]=[-1  4 -1  3]

程序说明:

(1) 运行结果,图像轮廓如图14-6所示。图14-6(1)所示为浅色背景的原始图像,进行二值处理时反色为黑色背景和白色目标。
(2) 图14-6(2)所示为在原始图像上绘制查找到的全部轮廓,并标注轮廓编号。图14-6(3)所示为在原始图像上绘制指定的轮廓,外层轮廓以白色线条绘制,内层轮廓以红色填充。
(3) contours是所有轮廓的列表,长度为6,表示查找到6个轮廓。
(4) 查找轮廓时使用CHAIN_APPROX_SIMPLE选项,对水平线/垂直线/对角线只保留线段的端点。矩形轮廓最少可以用4个端点表示,如2#轮廓只有4个像素点,但看起来像矩形的轮廓也可能会有更多顶点,如3# 轮廓有8个像素点。
(5) hierarchy的形状为(1,6,4),每行表示一个轮廓的拓扑信息。结合运行结果逐行讨论如下。
hierarchy[0,0]=[1,-1,-1,-1],表示0#轮廓的同层下一个轮廓为1#,没有同层的前一个轮廓,没有子轮廓,没有父轮廓,因此是单层轮廓。
hierarchy[0,1]=[2,0,-1,-1],表示1#轮廓的同层下一个轮廓为2#,同层前一个轮廓为0#,没有子轮廓,没有父轮廓,因此是单层轮廓。
hierarchy[0,2]=[-1,1,3,-1],表示2# 轮廓没有同层下一个轮廓,同层前一个轮廓为1#,子轮廓为3#,没有父轮廓,因此是外层轮廓。
hierarchy[0,3] =[-1,-1,4,2],表示3#轮廓没有同层下一个轮廓,没有同层前一个轮廓,子轮廓为4#,父轮廓为2#。
hierarchy[0,4]=[5,-1,-1,3],表示4#轮廓的同层下一个轮廓为5#,没有同层前一个轮廓,没有子轮廓,父轮廓为3#,因此是内层轮廓。
hierarchy[0,5] =[-1,4,-1,3],表示5#轮廓没有同层下一个轮廓,同层前一个轮廓为4#,没有子轮廓,父轮廓为3#,因此是内层轮廓。


在这里插入图片描述

图14-6 图像轮廓


版权声明:
youcans@xupt 原创作品,转载必须标注原文链接:(https://blog.csdn.net/youcans/article/details/138395918)
Copyright 2024 youcans, XUPT
Crated:2024-05-01

《数字图像处理-OpenCV/Python》 独家连载专栏 : https://blog.csdn.net/youcans/category_12418787.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1638783.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue3中使用animate.css

在vue3中使用animate.css 20240428_093614 引入:npm install animate.css --save main.js注册:import ‘animate.css/animate.min.css’ 注意:import ‘animate.css’ 不适合在vue3项目 使用:class“animate__animated 动画名称”…

FreeRTOS-系统时钟节拍和时间管理

一、前言 任何操作系统都需要提供一个时钟节拍,以供系统处理诸如延时,超时等与时间相关的事件。时钟节拍是特定的周期性中断, 这个中断可以看做是系统心跳。 中断之间的时间间隔取决于不同的应用,一般是 1ms – 100ms。时钟的节拍…

Mac 安装John the Ripper 破解rar(zip)压缩文件

注:仅以此篇记录我满足好奇心所逝去的十几个小时。(自娱自乐) 1、首先利用 brewhome 包管理工具 安装john the ripper : brew install john-jumbo 如果没有安装brewhome 利用如下命令安装: /bin/zsh -c "$(c…

《与 Apollo 共创生态——Apollo7周年大会干货分享》

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” 文章目录 阿波罗X企业自动驾驶解决方案自动驾驶技术提升与挑战自动驾驶系统功能与性能的详细解析<td alig…

【网络基础】深入理解TCP协议:协议段、可靠性、各种机制

文章目录 1. TCP协议段格式1.1. 如何解包 / 向上交付1.1.1. 交付1.1.2. 解包 1.2. 如何理解可靠性1.2.1. 确认应答机制&#xff08;ACK&#xff09;1.2.2. 序号 与 确认序号 2. TCP做到全双工的原因2.1. 16位窗口大小2.2. 6个标记位 3. 如何理解连接3.1 连接管理机制3.1.1. 三次…

Angular基础-搭建Angular运行环境

这篇文章介绍了在Angular项目中进行开发环境搭建的关键步骤。包括node.js安装和配置、安装Angular CLI工具、安装angular-router、创建Angular项目等步骤。这篇文章为读者提供了清晰的指南&#xff0c;帮助他们快速搭建Angular开发环境&#xff0c;为后续的项目开发奠定基础。 …

【系统架构师】-选择题(九)

1、电子政务没有政府对客户(Government To Customer) 四种主要应用模式&#xff1a; G2B&#xff1a;政府对企业 Government to Business G2C&#xff1a;政府对公民 Government to Citizen G2E&#xff1a;政府对公务员 Government to Employee G2G&#xff1a;政府对政府 Go…

商务谈判模拟口才训练方案(3篇)

商务谈判模拟口才训练方案&#xff08;3篇&#xff09; 商务谈判模拟口才训练方案&#xff08;一&#xff09; 一、训练目标 本训练方案旨在提高参与者在商务谈判中的口才表达能力&#xff0c;包括清晰表达、有效倾听、应对挑战和构建信任等能力。 二、训练内容 基础口才训练…

YOLOv8主要命令讲解

YOLOv8主要有三个常用命令&#xff0c;分别是&#xff1a;train&#xff08;训练&#xff09;、predict&#xff08;预测&#xff09;、export&#xff08;转化模型格式&#xff09;&#xff0c;下面我将展开讲讲三个常用命令的常用参数与具体使用方法。 一、训练 通过自己标…

“Transformer挑战者”-Mamba之最全详解图解

-------------------------------------------------------------------------------------------------------------------- 1.AIGC未来发展前景 未完持续… 1.1 人工智能相关科研重要性 拥有一篇人工智能科研论文及专利软著竞赛是保研考研留学深造以及找工作的关键门票&a…

Pandas入门篇(二)-------Dataframe篇5(进阶)(Dataframe的时间序列Dataframe最终篇!!)(机器学习前置技术栈)

目录 概述一、pandas的日期类型&#xff08;一&#xff09;datetime64类型的特点&#xff08;二&#xff09; 时间序列的创建1.从字符串创建datetime64类型2. 整数&#xff08;Unix时间戳&#xff09;创建datetime64类型3.导入数据时直接转换 &#xff08;三&#xff09;dateti…

XY_RE复现(五)

一&#xff0c;给阿姨倒一杯卡布奇诺 是一道魔改TEA加密 给出了一些初始化&#xff0c;然后输入的flag拆分&#xff0c;两两一组&#xff0c;通过for循环放入encrypt加密函数 #include <stdio.h> #define uint32_t unsigned intvoid decrypt(uint32_t *v, uint32_t *ke…

笨蛋学C++之 C++连接数据库

笨蛋学C 之 VS2019使用C连接数据库 创建数据库SQL语句VS2019选择空项目&#xff0c;点击下一步创建输入项目名称&#xff0c;点击创建创建成功点击新建项创建源文件因为mysql是64位&#xff0c;此时的c项目是86位&#xff0c;所以这里需要将项目修改为x64位点击项目 -> 0501…

linux 单机安装consul

sudo yum install -y yum-utils && sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo && sudo yum -y install consul#添加consul配置文件 nano /etc/consul.d/server.json {"server": true,"boots…

Python异步Redis客户端与通用缓存装饰器

前言 这里我将通过 redis-py 简易封装一个异步的Redis客户端&#xff0c;然后主要讲解设计一个支持各种缓存代理&#xff08;本地内存、Redis等&#xff09;的缓存装饰器&#xff0c;用于在减少一些不必要的计算、存储层的查询、网络IO等。 具体代码都封装在 HuiDBK/py-tools: …

使用 uni-app 开发 iOS 应用的操作步骤

哈喽呀&#xff0c;大家好呀&#xff0c;淼淼又来和大家见面啦&#xff0c;上一期和大家一起探讨了使用uniapp开发iOS应用的优势及劣势之后有许多小伙伴想要尝试使用uniapp开发iOS应用&#xff0c;但是却不懂如何使用uniapp开发iOS应用&#xff0c;所以这一期淼淼就来给你们分享…

nginx--平滑升级

失败了&#xff0c;等我拍好错继续更新 命令 选项说明 帮助: -? -h 使用指定的配置文件: -c 指定配置指令:-g 指定运行目录:-p 测试配置文件是否有语法错误:-t -T 打印nginx的版本信息、编译信息等:-v -V 发送信号: -s 示例: nginx -s reload 信号说明 立刻停止服务:stop,相…

【C++】学习笔记——string_3

文章目录 六、string类5. string类的操作6. string类的转换7. string类的模拟实现 未完待续 搭配文档食用 六、string类 5. string类的操作 上面的函数中&#xff0c;有些是不常用的&#xff0c;咱们只挑几个重要的进行讲解。 c_str 就是将字符串转换成 C语言 字符串的格式。…

[Java EE] 多线程(六):线程池与定时器

1. 线程池 1.1 什么是线程池 我们前面提到,线程的创建要比进程开销小,但是如果线程的创建/销毁比较频繁,开销也会比较大.所以我们便引入了线程池,线程池的作用就是提前把线程都创建好,放到用户态代码中写的数据结构中,后面就可以随用随取. 线程池最大的好处就是减少每次启动,…

Python中动画显示与gif生成

1. 动画生成 主要使用的是 matplotlib.animation &#xff0c;具体示例如下&#xff1a; import matplotlib.pyplot as plt import matplotlib.animation as animation import numpy as np fig, ax plt.subplots() t np.linspace(0, 3, 40) g -9.81 v0 12 z g * t**2 / …