专栏名称: 新机器视觉
最前沿的机器视觉与计算机视觉技术
目录
相关文章推荐
河南日报  ·  来河南,总有_________! ·  22 小时前  
河南新闻广播  ·  别跑空!今晚,河南多个景区取消烟花秀 ·  昨天  
河南新闻广播  ·  李国勇被开除党籍 ·  昨天  
河南新闻广播  ·  一看一个Amazing!神仙级大展我先冲为敬 ·  3 天前  
河南新闻广播  ·  濮阳地震?!官方回应来了 ·  3 天前  
51好读  ›  专栏  ›  新机器视觉

在OpenCV中基于深度学习的边缘检测

新机器视觉  · 公众号  ·  · 2024-09-09 07:50

正文


本文转自:AI算法与图像处理

导读

分析了Canny的优劣,并给出了OpenCV使用深度学习做边缘检测的流程,文末有代码链接。

在这篇文章中,我们将学习如何在OpenCV中使用基于深度学习的边缘检测,它比目前流行的canny边缘检测器更精确。 边缘检测在许多用例中是有用的,如视觉显著性检测,目标检测,跟踪和运动分析,结构从运动,3D重建,自动驾驶,图像到文本分析等等。

什么是边缘检测?


边缘检测是计算机视觉中一个非常古老的问题,它涉及到检测图像中的边缘来确定目标的边界,从而分离感兴趣的目标。最流行的边缘检测技术之一是Canny边缘检测,它已经成为大多数计算机视觉研究人员和实践者的首选方法。让我们快速看一下Canny边缘检测。


Canny边缘检测算法


1983年,John Canny在麻省理工学院发明了Canny边缘检测。它将边缘检测视为一个信号处理问题。其核心思想是,如果你观察图像中每个像素的强度变化,它在边缘的时候非常高。

在下面这张简单的图片中,强度变化只发生在边界上。所以,你可以很容易地通过观察像素强度的变化来识别边缘。

现在,看下这张图片。强度不是恒定的,但强度的变化率在边缘处最高。(微积分复习:变化率可以用一阶导数(梯度)来计算。)

Canny边缘检测器通过4步来识别边缘:

  1. 去噪 :因为这种方法依赖于强度的突然变化,如果图像有很多随机噪声,那么会将噪声作为边缘。所以,使用5×5的高斯滤波器平滑你的图像是一个非常好的主意。
  2. 梯度计算 :下一步,我们计算图像中每个像素的强度的梯度(强度变化率)。我们也计算梯度的方向。

梯度方向垂直于边缘,它被映射到四个方向中的一个(水平、垂直和两个对角线方向)。
  1. 非极大值抑制 :现在,我们想删除不是边缘的像素(设置它们的值为0)。你可能会说,我们可以简单地选取梯度值最高的像素,这些就是我们的边。然而,在真实的图像中,梯度不是简单地在只一个像素处达到峰值,而是在临近边缘的像素处都非常高。因此我们在梯度方向上取3×3附近的局部最大值。

  1. 迟滞阈值化 :在下一步中,我们需要决定一个梯度的阈值,低于这个阈值所有的像素都将被抑制(设置为0)。而Canny边缘检测器则采用迟滞阈值法。迟滞阈值法是一种非常简单而有效的方法。我们使用两个阈值来代替只用一个阈值:

    高阈值 = 选择一个非常高的值,这样任何梯度值高于这个值的像素都肯定是一个边缘。

    低阈值 = 选择一个非常低的值,任何梯度值低于该值的像素绝对不是边缘。

    在这两个阈值之间有梯度的像素会被检查,如果它们和边缘相连,就会留下,否则就会去掉。

迟滞阈值化


Canny 边缘检测的问题:


由于Canny边缘检测器只关注局部变化,没有语义(理解图像的内容)理解,精度有限(很多时候是这样)。

Canny边缘检测器在这种情况下会失败,因为没有理解图像的上下文

语义理解对于边缘检测是至关重要的,这就是为什么使用机器学习或深度学习的基于学习的检测器比canny边缘检测器产生更好的结果。


OpenCV中基于深度学习的边缘检测


OpenCV在其全新的DNN模块中集成了基于深度学习的边缘检测技术。你需要OpenCV 3.4.3或更高版本。这种技术被称为整体嵌套边缘检测或HED,是一种基于学习的端到端边缘检测系统,使用修剪过的类似vgg的卷积神经网络进行图像到图像的预测任务。

HED利用了中间层的输出。之前的层的输出称为side output,将所有5个卷积层的输出进行融合,生成最终的预测。由于在每一层生成的特征图大小不同,它可以有效地以不同的尺度查看图像。

网络结构:整体嵌套边缘检测

HED方法不仅比其他基于深度学习的方法更准确,而且速度也比其他方法快得多。这就是为什么OpenCV决定将其集成到新的DNN模块中。以下是这篇论文的结果:

在OpenCV中训练深度学习边缘检测的代码


OpenCV使用的预训练模型已经在Caffe框架中训练过了,可以这样加载:

sh download_pretrained.sh

网络中有一个crop层,默认是没有实现的,所以我们需要自己实现一下。

class CropLayer(object):
    def __init__(self, params, blobs):
        self.xstart = 0
        self.xend = 0
        self.ystart = 0
        self.yend = 0

    # Our layer receives two inputs. We need to crop the first input blob
    # to match a shape of the second one (keeping batch size and number of channels)
    def getMemoryShapes(self, inputs):
        inputShape, targetShape = inputs[0], inputs[1]
        batchSize, numChannels = inputShape[0], inputShape[1]
        height, width = targetShape[2], targetShape[3]

        self.ystart = (inputShape[2] - targetShape[2]) // 2
        self.xstart = (inputShape[3] - targetShape[3]) // 2
        self.yend = self.ystart + height
        self.xend = self.xstart + width

        return [[batchSize, numChannels, height, width]]

    def forward(self, inputs):
        return [inputs[0][:,:,self.ystart:self.yend,self.xstart:self.xend]]

现在,我们可以重载这个类,只需用一行代码注册该层。

cv.dnn_registerLayer('Crop', CropLayer)

现在,我们准备构建网络图并加载权重,这可以通过OpenCV的 dnn.readNe 函数。

net = cv.dnn.readNet(args.prototxt, args.caffemodel)

现在,下一步是批量加载图像,并通过网络运行它们。为此,我们使用 cv2.dnn.blobFromImage 方法。该方法从输入图像中创建四维blob。

blob = cv.dnn.blobFromImage(image, scalefactor, size, mean, swapRB, crop)

其中:







请到「今天看啥」查看全文


推荐文章
河南日报  ·  来河南,总有_________!
22 小时前
河南新闻广播  ·  李国勇被开除党籍
昨天
河南新闻广播  ·  一看一个Amazing!神仙级大展我先冲为敬
3 天前
河南新闻广播  ·  濮阳地震?!官方回应来了
3 天前