极市导读
作者介绍了 Canny 边缘检测器的所有概念,并使用 OpenCV 对其进行了编码。以及详细讨论了 Canny 边缘检测涉及的 5 个步骤。 >>加入极市CV技术交流群,走在计算机视觉的最前沿
介绍
图像处理是一个广泛使用的概念,用于利用图像中的信息。图像处理算法需要很长时间来处理数据,因为图像很大,并且其中可用的信息量很大。因此,在这些前沿技术中,有必要减少算法所关注的信息量。有时这只能通过传递图像的边缘来完成。
所以在这篇博客中,让我们了解 Canny 边缘检测器和整体嵌套边缘检测器。
什么是边缘检测?
图像中的边缘是图像强度的显着局部变化。顾名思义,边缘检测是检测图像边缘的过程。下面的示例描述了海星图像的边缘检测。
为什么我们需要边缘检测?
深度、表面方向、场景照明变化和材料属性变化的不连续性会导致图像亮度的不连续性。我们得到表示对象边界和表面标记的曲线集,以及对应于表面方向不连续性的曲线。
因此,将边缘检测算法应用于图像可以显着减少要处理的数据量,因此可以过滤掉可能被认为不太相关的信息,同时保留图像的重要结构属性。
如图 1.1 所示,图像的结构属性是通过边缘检测捕获的。
了解流行的边缘检测算法
在讨论了边缘检测算法的重要性之后,本节将重点了解一些流行且广泛使用的边缘检测算法。
边缘检测有多种方法。让我们将这些方法大致分为:
传统方法 基于深度学习的方法
现在,让我们讨论最流行的边缘检测算法之一——canny 边缘检测器,并将其与 Sobel 和 Prewitt 进行比较。
Canny 边缘检测器
Canny 边缘检测算法是当今图像处理应用中广泛使用的边缘检测算法。它在多个阶段工作,如图 1.2 所示。Canny 边缘检测算法产生比 Sobel 和 Prewitt 过滤器更平滑、更薄、更清晰的图像。
这里是canny边缘检测算法的总结:
对输入图像进行平滑处理,应用 Sobel 滤波器检测图像的边缘。然后我们应用非最大抑制,保留梯度方向上的局部最大像素,其余的被抑制。我们应用阈值处理来去除低于某个阈值的像素,并保留高于某个阈值的像素以去除可能由于噪声而形成的边缘。
稍后,如果 8 个相邻像素中的任何一个像素很强,我们就会应用滞后跟踪来使像素变强。
现在,我们将详细讨论每个步骤。
Canny边缘检测涉及5个步骤,如上图1.2所示。我们将使用下图进行说明。
图像平滑
在这一步中,我们将图像转换为灰度,因为边缘检测不依赖于颜色。然后我们用高斯滤波器去除图像中的噪声,因为边缘检测容易产生噪声。
寻找图像的强度梯度
然后,我们在水平和垂直方向上应用 Sobel 核,以获得平滑图像上水平方向 (G x ) 和垂直方向 (G y ) 的一阶导数。然后我们计算边缘梯度(G)和角度(θ),如下所示,
我们知道梯度方向垂直于边缘。我们将角度四舍五入到代表垂直、水平和两个对角线方向的四个角度之一。
非最大值抑制
现在我们删除所有可能不构成边缘的像素。为此,如果每个像素在其邻域中是局部最大值,则在梯度方向上进行检查。如果是局部最大值,则考虑用于下一阶段,否则,将其变暗,设置为 0。这将在输出图像中给出一条细线。
双阈值
由于噪声和颜色变化导致的像素会在图像中持续存在。因此,为了消除这一点,我们从用户那里获得了两个阈值,lowerVal 和 upperVal。
我们过滤掉具有弱梯度(lowerVal)值的边缘像素,并保留具有高梯度值(upperVal)的边缘像素。强度梯度大于upperVal的边缘肯定是边缘,低于lowerVal的肯定是非边缘,所以丢弃。像素值小于 upperVal 且大于 lowerVal 的像素如果连接到“确定边缘(sure-edge)”,则被视为边缘的一部分。否则,它们也会被丢弃。
滞后边缘跟踪
如果一个像素周围的 8 个像素中有一个是强像素(像素值 = 255),则将其设为强像素,否则将其设为 0。
这几乎是关于 Canny 边缘检测的。如图,边缘是从图像中检测到的。
现在,我们将探索基于深度学习的边缘检测方法。但是为什么我们首先需要使用基于深度学习的边缘检测算法呢?Canny边缘检测只关注局部变化,不理解图像的语义,即图像内容。因此,提出了基于深度学习的算法来解决这些问题。我们现在将详细讨论它。
但在我们深入研究深度学习的数学之前,让我们首先尝试在 OpenCV 中实现 Canny 边缘检测器和基于深度学习的模型(HED)。
实现 - Canny 边缘检测器
让我们导入必要的模块
import cv2 from skimage.metrics import mean_squared_error,peak_signal_noise_ratio,structural_similarity
import matplotlib.pyplot as plt
以下代码在海星图像上应用 Canny 边缘检测器
img_path = 'starfish.png'
#Reading the image
image = cv2.imread(img_path)
(H, W) = image.shape[:2]
# convert the image to grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# blur the image
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
# Perform the canny operator
canny = cv2.Canny(blurred, 30, 150)
让我们看看 Canny 边缘检测器的输出
fig,ax = plt.subplots(1,2,figsize=(18, 18))
ax[0].imshow(gray,cmap='gray')
ax[1].imshow(canny,cmap='gray')
ax[0].axis('off')
ax[1].axis('off')
接下来,让我们在进行数学运算之前看看 HED 的代码。
实现 - HED
#This class helps in cropping the specified coordinated in the function
class CropLayer(object):
def __init__(self, params, blobs):
# initialize our starting and ending (x, y)-coordinates of
self.startX = 0
self.startY = 0
self.endX = 0
self.endY = 0
def getMemoryShapes(self, inputs):
(inputShape, targetShape) = (inputs[0], inputs[1])
(batchSize, numChannels) = (inputShape[0], inputShape[1])
(H, W) = (targetShape[2], targetShape[3])
# compute the starting and ending crop coordinates
self.startX = int((inputShape[3] - targetShape[3]) / 2)
self.startY = int((inputShape[2] - targetShape[2]) / 2)
self.endX = self.startX + W
self.endY = self.startY + H
# return the shape of the volume (we'll perform the actual
# crop during the forward pass
return [[batchSize, numChannels, H, W]]
def forward(self, inputs):
return [inputs[0][:, :, self.startY:self.endY,self.startX:self.endX]]
你可以从此 repo 下载 deploy.prototxt 和 caffemodel:https://github.com/ashukid/hed-edge-detector
#The caffemodel contains the model of the architecture and the deploy.prototxt contains the weights
protoPath = 'deploy.prototxt.txt'
modelPath = 'hed_pretrained_bsds.caffemodel'
net = cv2.dnn.readNetFromCaffe(protoPath, modelPath)
# register our new layer with the model
cv2.dnn_registerLayer("Crop", CropLayer)
现在我们读取我们的图像并将其传递给算法。
#Input image is converted to a blog
blob = cv2.dnn.blobFromImage(image, scalefactor=1.0, size=(W, H),mean=(104.00698793, 116.66876762, 122.67891434),swapRB=False, crop=False)
#We pass the blob into the network and make a forward pass
net.setInput(blob)
hed = net.forward()
hed = cv2.resize(hed[0, 0], (W, H))
hed = (255 * hed).astype("uint8")
我们读取由边缘组成的实际图像
test_y_path = 'edge.png'
test_y = cv2.imread(test_y_path)
#The test image has its third dimesion as 3
#So we are extractin only one dimension
test_y = test_y[:,:,0]
我们对图像进行标准化,以使 MSE 值不会上升
#Normalising all the images
test_y = test_y/255
hed = hed/255
canny = canny/255
gray = gray/255
我们现在可视化我们的结果
fig,ax = plt.subplots(1,2,figsize=(18, 18))
ax[0].imshow(gray,cmap='gray')
ax[1].imshow(hed,cmap='gray')
ax[0].axis('off')
ax[1].axis('off')
最后,我们计算指标并比较我们的结果
#Calculating metrics between actual test image and the output we got through Canny edge detection
print(mean_squared_error(test_y,canny),peak_signal_noise_ratio(test_y,canny),structural_similarity(test_y,canny))
#Calculating metrics between actual test image and the output we got through HED
print(mean_squared_error(test_y,hed),peak_signal_noise_ratio(test_y,hed),structural_similarity(test_y,hed))
为什么要使用深度学习进行边缘检测?
在阅读 HED 之前,可能会出现一个问题,为什么我们需要深度学习算法来完成如此简单的边缘检测任务?
答案是 Canny 边缘检测主要关注局部变化而不是图像的语义,即它较少关注图像的内容。因此,我们得到不太准确的边缘。
边缘检测的深度学习方法
整体嵌套边缘检测( HED)技术是一种基于学习的端到端边缘检测系统,它使用修剪后的 VGG 类卷积神经网络来执行图像到图像的预测任务。HED 在神经网络中生成边输出。所有侧面输出都融合在一起以形成最终输出。让我们更详细地了解该算法。
算法概述
我们采用 VGGNet 架构,但做了以下修改:
(a) 我们将侧输出层连接到每个阶段的最后一个卷积层,分别为 conv1 2、conv2 2、conv3 3、conv4 3、conv5 3。
(b) 我们去掉了 VGGNet 的最后阶段,包括第 5 个池化层和所有全连接层。此外,网络内反卷积层结合了双线性插值的输出。
HED 的训练和测试阶段将在本文的最后一节中介绍。我建议你浏览一下,以便更好地理解模型体系结构。
HED:训练和测试阶段
现在,让我们谈谈 HED 的训练和测试阶段。正如我在文章开头提到的,这是一个涉及很多数学知识的部分,所以这一部分的阅读是可选的。我强烈建议你阅读这一部分以真正掌握 HED 的内部运作原理。
训练阶段
让我们将所有标准网络层参数的集合表示为 W,该网络有 M 个侧输出层。每个侧输出层还与一个分类器相关联,其中相应的权重表示为 w = (w (1) , . . . , w (m) ))
其中 表示侧面输出的图像级损失函数。对于典型的自然图像,边缘/非边缘像素分布存在严重偏差:90% 是非边缘的。成本敏感的损失函数是为有偏采样引入了额外的权衡参数。
具体来说,我们定义了上述等式中使用的以下类平衡交叉熵损失函数
其中:
为了直接利用侧输出预测,我们在网络中添加了一个“加权融合”层,并(同时)在训练期间学习融合权重。我们在融合层 的损失函数变为
其中 Dist 是交叉熵损失。我们给出整个目标函数为,
测试阶段
在测试期间,给定图像 X,我们从侧面输出层和加权融合层获得边缘图预测。通过聚合这些生成的边缘图可以得到最终的统一输出。
评估指标
现在,我们已经了解了不同的边缘检测算法——传统和深度学习方法。但是我们如何评估边缘检测算法的性能或比较不同的边缘检测算法呢?
这给我们带来了边缘检测中另一个有趣的话题——评估指标。我们现在将讨论边缘检测的不同评估指标。
均方误差
MSE 表示影响表示质量的失真噪声的能力。
公式:
峰值信噪比方程
峰值信噪比 (PSNR) 表示信号的最大可能值(功率)与影响其表示质量的失真噪声的功率之间的比率。它是由
结构相似性指数指标
结构相似性指数指标从图像的亮度、对比度和结构中提取 3 个关键特征。公式:
其中:
μx 是图像 X 的平均值
μy 是图像 Y 的平均值
是 X 的方差
是 Y 的方差
是 X 和 Y 的协方差
和)k1 = 0.01 和 k2 = 0.03
结论
我们已经涵盖了 Canny 边缘检测器的所有概念,然后使用 OpenCV 对其进行了编码。我们讨论了 Canny 边缘检测涉及的 5 个步骤,为什么 Canny 边缘检测器比以前的方法更好。还介绍了HED 方法所涉及的数学。我们还讨论了一些评估指标来评估算法对图像的执行情况。
本文的主要内容是:
Canny 边缘检测器提供比 Sobel 和 Prewitt 滤波器更平滑和更精细的边缘 一种关注图像的内容的深度学习方法
公众号后台回复“数据集”获取100+深度学习各方向资源整理
极市干货
点击阅读原文进入CV社区
收获更多技术干货