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

边缘检测和图像轮廓查找

  • 一、理论分析
  • 二、代码分析
    • 2.1 边缘检测
      • 2.1.1 Sobel算子
      • 2.1.2 Scharr算子
      • 2.1.3 Laplacian算子
      • 2.1.4 Canny算子
        • 去噪
        • 梯度
        • 非极大值抑制
        • 滞后阈值
    • 2.2 特征检测
  • 三、代码文件

一、理论分析

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

二、代码分析

2.1 边缘检测

2.1.1 Sobel算子

对每一个像素点px,用有右减左侧的特征值。因为对于边缘特征来说,px的值较大。那么值越大的说明其越有可能是边缘特征。
如下图所示,表示计算图像的水平特征。右侧减去左侧数值。
机器视觉——OpenCV案例分析基础(七)(边缘检测和图像轮廓查找)_第1张图片
机器视觉——OpenCV案例分析基础(七)(边缘检测和图像轮廓查找)_第2张图片

from cv2 import cv2 as cv
import numpy as np
img = cv.imread("2021-12-01--image/2021-12-01--image/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,所以要对处理结果,取绝对值。让负值变为正值。
机器视觉——OpenCV案例分析基础(七)(边缘检测和图像轮廓查找)_第3张图片
那么修改代码为:

from cv2 import cv2 as cv
import numpy as np
img = cv.imread("2021-12-01--image/2021-12-01--image/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
机器视觉——OpenCV案例分析基础(七)(边缘检测和图像轮廓查找)_第4张图片

from cv2 import cv2 as cv
import numpy as np
img = cv.imread("2021-12-01--image/2021-12-01--image/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()

代码运行结果如下:
机器视觉——OpenCV案例分析基础(七)(边缘检测和图像轮廓查找)_第5张图片

2.1.2 Scharr算子

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

from cv2 import cv2 as cv
import numpy as np
img = cv.imread("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方向,为了防止数值溢出,采用加权和。而拉普拉斯算子实现了同时计算两个方向的算子。
机器视觉——OpenCV案例分析基础(七)(边缘检测和图像轮廓查找)_第6张图片

from cv2 import cv2 as cv
import numpy as np

img = cv.imread("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()

运行结果如下
机器视觉——OpenCV案例分析基础(七)(边缘检测和图像轮廓查找)_第7张图片

2.1.4 Canny算子

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

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

去噪

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

梯度

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

非极大值抑制

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

滞后阈值

我们提供一个最小阈值和最大阈值,也就是说所有检测出来的边缘值,都要存在于我的阈值之间,在阈值范围内舍弃,超出阈值的舍弃。只保留边界在阈值的边界之间的检测线。
机器视觉——OpenCV案例分析基础(七)(边缘检测和图像轮廓查找)_第8张图片

from cv2 import cv2 as cv
import numpy as np

img = cv.imread("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("2021-12-01--image/2021-12-01--image/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()

代码运行结果如下机器视觉——OpenCV案例分析基础(七)(边缘检测和图像轮廓查找)_第9张图片

三、代码文件

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

你可能感兴趣的:(人工智能,机器视觉,OpenCV,python,人工智能,1024程序员节)