scipy 和 numpy sobel 梯度计算的区别 [英] Difference between scipy and numpy sobel gradient calculation

查看:76
本文介绍了scipy 和 numpy sobel 梯度计算的区别的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

设置

我目前正在尝试使用 sobel 过滤器计算图像梯度.起初我使用 scipy.ndimage.sobel 函数通过

sx = ndimage.sobel(im,axis=0,mode="constant")sy = ndimage.sobel(im,axis=1,mode="constant")sobel = np.hypot(sx,sy)索贝尔 *= 255/np.max(索贝尔)

然而,这仅适用于 (3x3) sobel 过滤器到我的图像,但我想尝试更大的过滤器.因此,我尝试使用 numpyscipy.signal 计算图像梯度.首先,我再次尝试了 (3x3) 过滤器.

filter_x = np.array([[-1,0,1],[-2,0,2],[-1,0,1]], dtype=np.float)filter_y = np.array([[1,2,1], [0,0,0], [-1,-2,-1]], dtype = np.float)sx = signal.convolve2d(im,filter_x,mode="same",boundary="symm", fillvalue=0)sy = signal.convolve2d(im,filter_y,mode="same",boundary="symm",fillvalue=0)sobel = np.hypot(sx,sy)索贝尔 *= 255/np.max(索贝尔)

首先,让我们定义一个 sobel 边缘检测内核:

g = np.asarray([[-1, 0, 1],[-2, 0, 2],[-1, 0, 1]])

现在让我们首先使用 sicpy 的 signal.convolve2d

将图像与我们的内核进行卷积

img_convolved = signal.convolve2d(img, g)plt.imshow(img_convolved, cmap='gray')

...并放大边缘:

plt.imshow(img_convolved[100:150,100:150], cmap='gray')

现在,让我们使用 sicpy 的 signal.correlate2d

将图像与我们的内核相关联

img_correlated = signal.correlate2d(img, g)plt.imshow(img_correlated, cmap='gray')

...并放大边缘:

plt.imshow(img_correlated[100:150,100:150], cmap='gray')

最后,让我们将相关结果与使用翻转内核进行卷积时的结果进行比较:

img_convolved_flipped = signal.convolve2d(img, np.fliplr(g))plt.imshow(img_convolved, cmap='gray')

...并放大边缘:

plt.imshow(img_convolved_flipped[100:150,100:150], cmap='gray')

所以,scipy的signal.correlate2d(img, g)等价于signal.convolve2d(img, np.fliplr(g))

编辑(2D 代码示例的说明):

请注意,在 2D 情况下,信号 f 与内核 g 的卷积涉及围绕两个基轴翻转内核:f*g(-t,-u).

因此,在我的代码中,我实际上应该将过滤器翻转两次:np.flipud(np.fliplr(g)).我省略了这一点,因为这对于垂直对称的 sobel 滤波器不是必需的,但请记住,这是一个特例.

Setting

I am currently trying to calcualte the image gradients with sobel filters. At first I used scipy.ndimage.sobelfunction via

sx = ndimage.sobel(im, axis=0,mode="constant")
sy = ndimage.sobel(im, axis=1,mode="constant")
sobel = np.hypot(sx,sy)
sobel *= 255 / np.max(sobel)

However this only applies (3x3) sobel filter to my image, but I want to try bigger filter. Therefore I tried to calculated the image gradient with numpy and scipy.signal. First of all I tried (3x3) filter again.

filter_x = np.array([[-1,0,1],[-2,0,2],[-1,0,1]], dtype=np.float)
filter_y = np.array([[1,2,1], [0,0,0], [-1,-2,-1]], dtype = np.float)
sx = signal.convolve2d(im,filter_x,mode="same",boundary="symm", fillvalue=0)
sy = signal.convolve2d(im,filter_y,mode="same",boundary="symm", fillvalue=0)
sobel = np.hypot(sx,sy)
sobel *= 255 / np.max(sobel)

as suggestet in this post.

Problem

Unfortunately these two approaches are leading to completely different results, which was already mentioned in this question. So I digged a little bit deeper and found that scipy.ndimage.sobel uses the correlate1d function instead of convolve2d or anything similar (source code). Unfortunately it is not possible to look inside the souce code for the correlate1d function since its functionallty is hidden inside the already compiled _nd_image.pyd file in the site-packages folder of my conda enviroment. So here comes my question:

Question

Does anyone explicitely know, what exactly is being calculated by correlate1d and in what way it is comparable to convolve2d?

Edit

As already mentioned in the answer of Florian Drawitsch one should be able to replace convolution by correlation. But then again, how do these different results appear?!

解决方案

Judging by the method names correlate1d and convolve2d I would strongly suspect that the former computes a correlation, whereas the latter computes a convolution. What's the difference?

Generally speaking, a convolution of a signal f with a kernel g involves flipping the kernel before the operation: f*g(-t)

In contrast, a correlation of a signal f with a kernel g is carried out without flipping the kernel: f*g(t)

Applying a directional edge detection kernel (like a sobel kernel) using convolution should therefore result in inverted edges compared to the result using correlation. Let's test this in code:

import numpy as np
from scipy import signal
from PIL import Image
from matplotlib import pyplot as plt

img = Image.open('lena.png')
plt.imshow(img)

First, let's define a sobel edge detection kernel:

g = np.asarray([[-1, 0, 1],
                [-2, 0, 2],
                [-1, 0, 1]])

Now let's first convolve the image with our kernel using sicpy's signal.convolve2d

img_convolved = signal.convolve2d(img, g)
plt.imshow(img_convolved, cmap='gray')

... and zoom in on a edge:

plt.imshow(img_convolved[100:150,100:150], cmap='gray')

Now, let's correlate the image with our kernel using sicpy's signal.correlate2d

img_correlated = signal.correlate2d(img, g)
plt.imshow(img_correlated, cmap='gray')

... and zoom in on a edge:

plt.imshow(img_correlated[100:150,100:150], cmap='gray')

Finally, let's compare the correlation result with what happens if we do a convolution with a flipped kernel:

img_convolved_flipped = signal.convolve2d(img, np.fliplr(g))
plt.imshow(img_convolved, cmap='gray')

... and zoom in on a edge:

plt.imshow(img_convolved_flipped[100:150,100:150], cmap='gray')

So, scipy's signal.correlate2d(img, g) is equivalent to signal.convolve2d(img, np.fliplr(g))

EDIT (Clarification for the 2D code example):

Please note that in the 2D case a convolution of a signal f with a kernel g involves flipping the kernel around both cardinal axes: f*g(-t,-u).

Therefore, in my code I should have actually flipped the filter twice: np.flipud(np.fliplr(g)). I have omitted this since is not necessary for the vertically symmetric sobel filter but keep in mind that this was a special case.

这篇关于scipy 和 numpy sobel 梯度计算的区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆