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

《数字图像处理-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的用法不同,详见程序注释。

python 复制代码
# 【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()
    

运行结果:

python 复制代码
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

相关推荐
拥抱AGI9 分钟前
我说大模型微调没啥技术含量,谁赞成谁反对?
人工智能·学习·语言模型·大模型学习·大模型入门·大模型教程
aqymnkstkw10 分钟前
2024年【电气试验】考试题库及电气试验模拟试题
大数据·c语言·人工智能·嵌入式硬件·安全
小鹿( ﹡ˆoˆ﹡ )12 分钟前
Python中的树与图:构建复杂数据结构的艺术
开发语言·python
阡之尘埃17 分钟前
Python数据分析案例59——基于图神经网络的反欺诈交易检测(GCN,GAT,GIN)
python·神经网络·数据挖掘·数据分析·图神经网络·反欺诈·风控大数据
xiaojiesec22 分钟前
第157天: 安全开发-Python 自动化挖掘项目&SRC 目标&FOFA 资产&Web 爬虫解析库
python·安全
27划流星雨_26 分钟前
from tqdm.auto import tqdm用法详细介绍
python
2401_85044049729 分钟前
激发AI创造力:掌握Prompt提示词的高效提问方法
人工智能·prompt
爱里承欢。31 分钟前
【Python语言初识(二)】
python
hzw051037 分钟前
Jupyter的使用
ide·python·jupyter
Terry Cao 漕河泾1 小时前
SRT3D: A Sparse Region-Based 3D Object Tracking Approach for the Real World
人工智能·计算机视觉·3d·目标跟踪