机器视觉——OpenCV案例分析基础(七)(边缘检测和图像轮廓查找)

2023-10-30

一、理论分析

图像的边缘信息通俗来讲变化较大。基于此特征和数字图像的离散信号,我们可以计算图片的差分或梯度。
图像处理中有多种边缘检测的算电子,包括普通一阶差分,Sobel算子,Scharr算子等等,是基于寻找梯度强度。而普通二阶差分中,Laplacian算子其思想是基于过零点检测。

二、代码分析

2.1 边缘检测

2.1.1 Sobel算子

对每一个像素点px,用有右减左侧的特征值。因为对于边缘特征来说,px的值较大。那么值越大的说明其越有可能是边缘特征。
如下图所示,表示计算图像的水平特征。右侧减去左侧数值。
在这里插入图片描述
在这里插入图片描述

from cv2 import cv2 as cv
import numpy as np
img = cv.imread(r"./CV-Pictures/sobel.bmp",0)
cv.imshow("img",img)
sobel_x = cv.Sobel(img,-1,1,0) #-1处理结果代表与原图一致,1代表x,0代表y
cv.imshow("sobel_x",sobel_x)
cv.waitKey(0)
cv.destroyAllWindows()

结果如下,可以看到图像边缘x轴方向,采集只有右侧,因为sobel算法是,右侧减去左侧。那么左侧的点就被算为负值,直接被赋值为0,所以要对处理结果,取绝对值。让负值变为正值。
在这里插入图片描述
那么修改代码为:

from cv2 import cv2 as cv
import numpy as np
img = cv.imread(r"./CV-Pictures/sobel.bmp",0)
cv.imshow("img",img)
sobel_x = cv.Sobel(img,-1,1,0)
sobel_x = cv.convertScaleAbs(sobel_x)
cv.imshow("sobel_x",sobel_x)
cv.waitKey(0)
cv.destroyAllWindows()

代码运行结果如下:
可以看到还是如此,为什么呢?因为Sobel函数默认采用np.uint8数据类型,也就是说没有负值。都自动取0了。所以我们一般不用-1,而用cv.CV_64F
在这里插入图片描述

from cv2 import cv2 as cv
import numpy as np
img = cv.imread(r"./CV-Pictures/sobel.bmp",0)
cv.imshow("img",img)
sobel_x = cv.Sobel(img,cv.CV_64F,0,1)
sobel_x = cv.convertScaleAbs(sobel_x)
sobel_y = cv.Sobel(img,cv.CV_64F,1,0)
sobel_y = cv.convertScaleAbs(sobel_y)
sobel_add_xy = cv.addWeighted(sobel_x,0.5,sobel_y,0.5,0)

cv.imshow("sobel_xy",sobel_xy)
cv.waitKey(0)
cv.destroyAllWindows()

代码运行结果如下:
在这里插入图片描述

2.1.2 Scharr算子

Scharr算子和Sobel算子类似,不同的是,Scharr算子,同一列或同一行的数值差异更大。

from cv2 import cv2 as cv
import numpy as np
img = cv.imread(r"CV-Pictures/010.jpg",0)
cv.imshow("img",img)
Scharr_x = cv.Scharr(img,cv.CV_64F,0,1)
Scharr_x = cv.convertScaleAbs(Scharr_x)
Scharr_y = cv.Scharr(img,cv.CV_64F,1,0)
Scharr_y = cv.convertScaleAbs(Scharr_y)
Scharr_add_xy = cv.addWeighted(Scharr_x,0.5,Scharr_y,0.5,0)
cv.imshow("Scharr_x",Scharr_x)
cv.imshow("Scharr_y",Scharr_y)
cv.imshow("Scharr_xy",Scharr_add_xy)
cv.waitKey(0)
cv.destroyAllWindows()

在这里插入图片描述
可以对比一下Sobel检测,如下如所示
在这里插入图片描述

2.1.3 Laplacian算子

我们可以看到,简单的算子是要分别计算x方向和y方向,为了防止数值溢出,采用加权和。而拉普拉斯算子实现了同时计算两个方向的算子。
在这里插入图片描述

from cv2 import cv2 as cv
import numpy as np

img = cv.imread(r"CV-Pictures/015.jpg",0)
laplacian_img = cv.Laplacian(img,cv.CV_64F)
laplacian_img = cv.convertScaleAbs(laplacian_img)
cv.imshow("img",img)
cv.imshow("laplacian",laplacian_img)
cv.waitKey(0)
cv.destroyAllWindows()

运行结果如下
在这里插入图片描述

2.1.4 Canny算子

这个方法是传统的边缘检测方法中最为有效,效果最好的方法。其主要包括四个步骤,分别为:

  1. 去噪
  2. 梯度
  3. 非极大值抑制
  4. 滞后阈值
去噪

边缘检测已收到噪声的影响。因此,在进行边缘检测前,通常需要先进行去噪。去噪的方法一般是采用高斯滤波器去噪
且一个像素点的临近像素具有更高的重要度,对周围的像素计算加权平均值。其中的邻近的像素具有更大的权重

梯度

对平滑后的图像采用Sobal算子计算梯度和方向。
其中梯度的方向一般总是与边界垂直。梯度的方向分为四类,垂直、水平、两个对角线方向。

非极大值抑制

获得梯度的大小和方向后,逐个遍历像素点,判断当前像素点是否是周围像素点中具有相同梯度的最大值。
假设A,B,C三点具有相同的方向,梯度方向垂直于边缘。判断是否极大值,是的话保留,不是就抑制。

滞后阈值

我们提供一个最小阈值和最大阈值,也就是说所有检测出来的边缘值,都要存在于我的阈值之间,在阈值范围内舍弃,超出阈值的舍弃。只保留边界在阈值的边界之间的检测线。
在这里插入图片描述

from cv2 import cv2 as cv
import numpy as np

img = cv.imread(r"CV-Pictures/lena2.jpg")
cv.imshow("img",img)
dst1 = cv.Canny(img,100,200)
dst2 = cv.Canny(img,64,128)
cv.imshow("canny",dst1)
cv.imshow("canny1",dst2)
cv.waitKey(0)
cv.destroyAllWindows()

代码运行结果如下:
在这里插入图片描述

2.2 特征检测

特征检测检测出的主要是图像的轮廓。那么轮廓相比于不连续的边缘是一个整体。
图像的轮廓处理要注意以下问题:

  1. 对象是二值图像。
  2. 查找轮廓需要更改原始图像,所以要把原始图像拷贝一份。
  3. 在OpenCV中,是从黑色背景中找白色对象。因此,背景必须为黑,对象必须位白。

在OpenCV中,我们使用findContours()和drawContours()分别来查找图像的轮廓与绘制图像的轮廓。

  1. contours,hierarchy = cv2.findContours(image,mode,method)
    其中:
    (1)mode一般选择cv2.RETR_EXTERNEL 只检测外轮廓和cv2.RETR_TREE 建立一个等级树结构的轮廓。
    (2)method一般采用cv2.CHAIN_APPROX_SIMPLE。
    (3)返回值中contours代表图像的轮廓,hierarchy代表图像的拓扑信息(轮廓层次)
  2. r = cv2.drawContours(o,contours,contoursIdx,color[,thickness])
from cv2 import cv2 as cv
import numpy as np

img = cv.imread(r"./CV-Pictures/contours.bmp")
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
#img = cv.imread("2021-12-01--image/2021-12-01--image/contours.bmp",0) #直接获取灰度图像
ret,binary = cv.threshold(gray,127,255,cv.THRESH_BINARY) #获得二值图
counters,hierarchy = cv.findContours(binary,cv.RETR_TREE,cv.CHAIN_APPROX_SIMPLE) #参数分别为图像轮廓检测模式,图像的轮廓近似方法。
co = img.copy()
r = cv.drawContours(co,counters,3,(0,0,255),3) #counters 表示需要绘制的边缘数组,(-1代表全部,0开始依次从外到内,从右到左),颜色,线条宽度
print(img.shape)
cv.imshow("img",img)
cv.imshow("draw",r)
cv.waitKey(0)
cv.destroyAllWindows()

代码运行结果如下在这里插入图片描述

三、代码文件

小程序员将代码文件和相关素材整理到了百度网盘里,因为文件大小基本不大,大家也不用担心限速问题。后期小程序员有能力的话,将在gitee或者github上上传相关素材。
链接:https://pan.baidu.com/s/1Ce14ZQYEYWJxhpNEP1ERhg?pwd=7mvf
提取码:7mvf

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

机器视觉——OpenCV案例分析基础(七)(边缘检测和图像轮廓查找) 的相关文章

  • 在 Numpy 中切片后确定结果数组的形状

    我很难理解在 numpy 中切片后如何确定结果数组的形状 例如 我使用以下简单代码 import numpy as np array np arange 27 reshape 3 3 3 slice1 array 1 2 1 slice2
  • 如何确定非阻塞套接字是否真正连接?

    这个问题不仅限于Python 这是一个一般的套接字问题 我有一个非阻塞套接字 想要连接到一台可访问的机器 在另一端 该端口不存在 为什么 select 仍然成功 我预计会超时 sock send 因管道损坏而失败 select 之后如何确定
  • Tensorflow 可变图像输入大小(自动编码器、放大......)

    Edit WARNING不建议使用不同图像大小的图像 因为张量需要具有相同的大小才能实现并行化 我一直在寻找解决方案 了解如何使用不同大小的图像作为神经网络的输入 Numpy 第一个想法是使用numpy 然而 由于每个图像的大小不同 我无法
  • python - 是否可以扩展 xml-rpc 可以序列化的事物集?

    我看到几个问题询问如何发送numpy ndarray通过 xml rpc 调用 这不能开箱即用 因为正如 xml rpc 中所述docs https docs python org 2 library xmlrpclib html 有一组固
  • OpenCV InRange 参数

    我在 Android 上使用 OpenCV 来实时查找特定颜色的圆圈 我的第一步是仅保留与我正在寻找的定义颜色相对应的像素 在本例中为红色或绿色 示例图像 https i stack imgur com CIozU jpg 为此 我正在使用
  • 优化 Keras 以使用所有可用的 CPU 资源

    好吧 我真的不知道我在说什么 所以请耐心听我说 我正在使用 Theano 后端运行 Keras 以在 MNIST 图像上运行基本的神经网络 目前只是一个教程 过去 我一直使用我的旧 HP 笔记本电脑 因为我有 Windows 和 Ubunt
  • Paramiko - 使用私钥连接 - 不是有效的 OPENSSH 私钥/公钥文件

    我正在尝试找到解决方案 但无法理解我做错了什么 在我的 Linux 服务器上 我运行了以下命令 ssh keygen t rsa 这产生了一个id rsa and id rsa pub file 然后我将它们复制到本地并尝试运行以下代码 s
  • Pandas重置索引未生效[重复]

    这个问题在这里已经有答案了 我不确定我在哪里误入歧途 但我似乎无法重置数据帧上的索引 当我跑步时test head 我得到以下输出 正如您所看到的 数据帧是一个切片 因此索引超出范围 我想做的是重置该数据帧的索引 所以我跑test rese
  • sudo pip install python-Levenshtein 失败,错误代码 1

    我正在尝试在 Linux 上安装 python Levenshtein 库 但每当我尝试通过以下方式安装它时 sudo pip install python Levenshtein 我收到此错误 命令 usr bin python c 导入
  • matplotlib matshow 标签

    我一个月前开始使用 matplotlib 所以我仍在学习 我正在尝试用 matshow 制作热图 我的代码如下 data numpy array a reshape 4 4 cax ax matshow data interpolation
  • spacy 如何使用词嵌入进行命名实体识别 (NER)?

    我正在尝试使用以下方法训练 NER 模型spaCy识别位置 人 名和组织 我试图理解如何spaCy识别文本中的实体 但我无法找到答案 从这个问题 https github com explosion spaCy issues 491在 Gi
  • 具有多个元素的数组的真值是二义性错误吗? Python

    from numpy import from pylab import from math import def TentMap a x if x gt 0 and x lt 0 5 return 2 a x elif x gt 0 5 a
  • 获取列表中倒数第二个元素[重复]

    这个问题在这里已经有答案了 我可以通过以下方式获取列表的倒数第二个元素 gt gt gt lst a b c d e f gt gt gt print lst len lst 2 e 有没有比使用更好的方法print lst len lst
  • Python:计算数据帧列中所有行中特定字符的实例数

    我有一个包含列 toaddress ccaddress body 的数据框 df 我想迭代数据帧的索引 以获取 toaddress 和 ccaddress 字段中电子邮件地址的最小 最大和平均数量 这是通过计算这两列中每个字段中的 和 的实
  • 为什么我用 beautifulSoup 刮的时候有桌子,但没有 pandas

    尝试抓取条目页面转换为制表符分隔格式 主要拉出序列和 UniProt 登录号 当我跑步时 url www signalpeptide de index php sess m listspdb bacteria s details id 10
  • select() 可以在 Windows 下使用 Python 中的文件吗?

    我正在尝试在 Windows 下运行以下 python 服务器 An echo server that uses select to handle multiple clients at a time Entering any line o
  • 查找给定节点的最高权重边

    我在 NetworkX 中有一个有向图 边缘的权重从 0 到 1 表示它们发生的概率 网络连通性非常高 所以我想修剪每个节点的边缘 只保留最高概率的节点 我不确定如何迭代每个节点并仅保留最高权重in edges在图中 有没有一个networ
  • Python - 如何查询定义方法的类?

    我的问题有点类似于this one https stackoverflow com questions 5520580 how do you get all classes defined in a module but not impor
  • Python 3.2 中 **kwargs 和 dict 有什么区别?

    看起来Python的很多方面都只是功能的重复 除了我在 Python 中的 kwargs 和 dict 中看到的冗余之外 还有什么区别吗 参数解包存在差异 许多人使用kwargs 并通过dict作为论据之一 使用参数解包 Prepare f
  • 检查字符串是否只有字母和空格 - Python

    试图让 python 返回一个字符串仅包含字母和空格 string input Enter a string if all x isalpha and x isspace for x in string print Only alphabe

随机推荐