高斯拉普拉斯算子是用于斑点检测还是用于边缘检测?

Is Laplacian of Gaussian for blob detection or for edge detection?

以下代码提供自(被要求删除link)。但我想知道它到底是如何工作的。如果这被认为是边缘检测或斑点检测,我感到困惑,因为 Wikipedia list the Laplacian of Gaussian (LoG) as blob detection

此外,有人可以解释并提供更深入的解释,说明为什么要计算绝对值以及 focus_stack() 函数中发生了什么吗?

#   Compute the gradient map of the image
def doLap(image):

    # YOU SHOULD TUNE THESE VALUES TO SUIT YOUR NEEDS
    kernel_size = 5         # Size of the laplacian window
    blur_size = 5           # How big of a kernal to use for the gaussian blur
                            # Generally, keeping these two values the same or very close works well
                            # Also, odd numbers, please...

    blurred = cv2.GaussianBlur(image, (blur_size,blur_size), 0)
    return cv2.Laplacian(blurred, cv2.CV_64F, ksize=kernel_size)

#
#   This routine finds the points of best focus in all images and produces a merged result...
#
def focus_stack(unimages):
    images = align_images(unimages)

    print "Computing the laplacian of the blurred images"
    laps = []
    for i in range(len(images)):
        print "Lap {}".format(i)
        laps.append(doLap(cv2.cvtColor(images[i],cv2.COLOR_BGR2GRAY)))

    laps = np.asarray(laps)
    print "Shape of array of laplacians = {}".format(laps.shape)

    output = np.zeros(shape=images[0].shape, dtype=images[0].dtype)

    abs_laps = np.absolute(laps)
    maxima = abs_laps.max(axis=0)
    bool_mask = abs_laps == maxima
    mask = bool_mask.astype(np.uint8)
    for i in range(0,len(images)):
        output = cv2.bitwise_not(images[i],output, mask=mask[i])

    return 255-output

编辑: 是正确的。忽略关于边缘检测器的部分。


高斯拉普拉斯算子 (LoG) 可用作 边缘检测器和 斑点检测器。我会跳过详细的数学和基本原理,我想你可以在书上或一些网站上阅读它们here, here and here

要了解为什么它可以同时用作两者,让我们看看它的情节和内核。

如果你有一个半径为 3 且值为 1 的斑点以内核为中心,而背景值为 0,你将有一个非常强烈的(否定的)响应。很明显,如果半径设置正确,为什么它可以进行斑点检测。

边缘检测怎么样?好吧,它不像 Sobel 算子那样为您提供梯度和对边缘的强烈响应。 Sobel 运算符不会为您提供准确的边缘,因为梯度通常会在几个像素上上升和下降。你的边缘将是几个像素宽。为了使其定位更准确,我们可以在本地找到具有最大(或最小)梯度的像素。这意味着它的二阶导数(拉普拉斯算子)应该等于零,或者在该点有一个零交叉点。

您可以看到处理后的图像同时具有亮带和暗带。过零是边缘。要使用内核查看这一点,请尝试在内核中手动滑动一个完美的步长边缘以查看响应如何变化。

对于你的第二个问题,我猜 absolute 正在尝试同时找到亮斑和暗斑(亮斑,深色背景;暗斑,浅背景),因为它们分别给出了强烈的负面和强烈的正面反应。然后它在每个像素位置找到所有图像的最大值。对于每个输出像素,它使用图像中具有最大响应的像素作为输出。我认为他的理由是具有强烈脉冲(小斑点)的像素在焦点上。

他正在使用 bitwise_not 作为复制机制。它将掩码指定的一些像素设置为源图像的按位非。最后,您将得到 output 由来自不同来源的像素组成,只是所有像素都经过了按位非运算。要恢复真实图像,只需再次 'NOT' 它们,如 NOT(NOT(x)) = x255-x does exactly that. I think a copyTo 也可以,不知道他为什么选择其他方式。

图片来自 http://fourier.eng.hmc.edu/e161/lectures/gradient/node8.html.

比较完整,但我不完全同意。也许我有点坚持正确的命名法。检测器是在被检测物体的位置产生强烈响应的东西。

高斯拉普拉斯算子 (LoG) 不是边缘检测器,因为它在(接近*)边缘有零交叉。但它可以用来构建边缘检测器。这样构造的边缘检测器就是Marr-Hildreth edge detector。因此,它经常被归类为边缘检测器。对我来说,它是一个线检测器

拉普拉斯是二阶导数之和(海森矩阵的迹)。用 LoG 卷积的图像与用高斯卷积的图像的 Laplacian 相同:

img * [ d^2/dx^2 G(x,y) + d^2/dy^2 G(x,y) ] = d^2/dx^2 [ img * G(x,y) ] + d^2/dy^2 [ img * G(x,y) ]

因此,LoG 在图像的极值处(二阶导数最大的地方)产生强烈的响应。这发生在 "blobs" 的山峰和沿线的脊线。

让我们使用这个简单的测试图像:

并对其应用 LoG:

这里,中灰是值为0的像素。可以看出,它沿着细线和小点有很强的(负)响应。它还在较宽物体的边缘周围有中等响应(边缘内为负,边缘外为正);零交叉点靠近边缘。

我们可以对这张图片设置阈值来检测细线和点:

(阈值幅度产生相同的结果)。我们可以降低阈值以查看中等响应发生在感兴趣的边缘周围:

获得边缘需要的不仅仅是一个简单的阈值。相比之下,可以对梯度大小(一阶导数在边缘位置很强)进行阈值处理以获得边缘:

梯度幅值对检测线没有用,因为它检测沿线的两个边缘,而不是线本身。上面的梯度幅度是使用高斯导数计算的(Sobel 是另一种选择,但不够精确)。

请注意,Canny edge detector是基于梯度大小,它添加了非最大抑制和滞后阈值,使检测变得薄而有意义。


* 二阶导数在拐点处有零交叉(可以作为边缘的真实位置)。然而,拉普拉斯算子是二阶导数的总和。如果您考虑梯度方向上的二阶导数,它的零交叉将被很好地定位。但是现在在垂直方向(沿着边缘)添加二阶导数。该二阶导数沿直线为零,沿凸曲线边缘(例如圆的边缘)为负,沿凹曲线边缘为正。因此,将这两个值相加将导致过零点在弯曲边缘上移动,曲率越大,过零点偏离其真实位置的程度就越大。