Sobel 滤波器结果不佳

Sobel Filter giving poor results

我试图在 python 中实现 sobel 滤波器,但输出很差且充满噪音。 我得到的输出图像是:

我给出的输入是(模糊后):

索贝尔滤波器代码如下:

def sobel_filters(img):
  Kx = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
  Ky = np.array([[1, 2, 1], [0, 0, 0], [-1, -2, -1]])

  Ix = ndimage.filters.convolve(img, Kx)
  Iy = ndimage.filters.convolve(img, Ky)

  G = np.sqrt(np.square(Ix) + np.square(Iy))
  G *= 255.0 / G.max()
  

  return G

我使用 sigma=1.3 模糊了结果。输入图像大小为 512 x 512。 我希望输出类似于此处显示的内容:https://www.adeveloperdiary.com/data-science/computer-vision/how-to-implement-sobel-edge-detection-using-python-from-scratch/

这是 Python/OpenCV 中的一种方法。您的问题是您的导数没有正确规范化,应该作为浮点数处理。您的规范化也没有考虑负值。在这个答案中,我使用了 OpenCV built-in Sobel 和其他方法。所以就不用介绍了scipy.ndimage

输入:

import cv2
import numpy as np
import skimage.exposure as exposure

# read the image
img = cv2.imread('gray_lena.png')

# convert to gray
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

# blur
blur = cv2.GaussianBlur(gray, (0,0), 1.3, 1.3)

# apply sobel derivatives
sobelx = cv2.Sobel(blur,cv2.CV_64F,1,0,ksize=3)
sobely = cv2.Sobel(blur,cv2.CV_64F,0,1,ksize=3)

# optionally normalize to range 0 to 255 for proper display
sobelx_norm= exposure.rescale_intensity(sobelx, in_range='image', out_range=(0,255)).clip(0,255).astype(np.uint8)
sobely_norm= exposure.rescale_intensity(sobelx, in_range='image', out_range=(0,255)).clip(0,255).astype(np.uint8)

# square 
sobelx2 = cv2.multiply(sobelx,sobelx)
sobely2 = cv2.multiply(sobely,sobely)

# add together and take square root
sobel_magnitude = cv2.sqrt(sobelx2 + sobely2)

# normalize to range 0 to 255 and clip negatives
sobel_magnitude = exposure.rescale_intensity(sobel_magnitude, in_range='image', out_range=(0,255)).clip(0,255).astype(np.uint8)

# save results
cv2.imwrite('gray_lena_sobelx_norm.jpg', sobelx_norm)
cv2.imwrite('gray_lena_sobely_norm.jpg', sobely_norm)
cv2.imwrite('gray_lena_sobel_magnitude.jpg', sobel_magnitude)

# show results
cv2.imshow('sobelx_norm', sobelx_norm)  
cv2.imshow('sobely_norm', sobely_norm)  
cv2.imshow('sobel_magnitude', sobel_magnitude)  
cv2.waitKey(0)
cv2.destroyAllWindows()

Sobel X(归一化):

Sobel Y(归一化):

索贝尔星等:

这是您在 Python/OpenCV 中使用浮动图像和适当标准化的方法。如果没有浮点数据,您只会得到单边导数(而不是正负结果)。

正如 Cris Luengo 所指出的,您答案中的导数相对于 OpenCV 中的标准导数是错误的。参考中的导数用于适当的卷积。但是Scipy既有卷积又有相关性。大多数“卷积”实际上是相关性。 (OpenCV cv2.filter2D 就是这样。该函数实际上计算相关性,而不是卷积)。所以我已经纠正了内核的相关性,使其与 OpenCV Sobel 中的或 cv2.filter2D() 使用的一致。卷积和相关性通过转置关联。参见 https://medium.com/@aybukeyalcinerr/correlation-vs-convolution-filtering-2711d8bb3666

输入:

import cv2
import numpy as np
import scipy.ndimage as ndimage
import skimage.exposure as exposure

# read the image and convert to float
img = cv2.imread('gray_lena.png').astype(np.float32)

# convert to gray
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

# blur
blur = cv2.GaussianBlur(gray, (0,0), 1.3, 1.3)

# define Sobel X and Y (correlation) kernels
Kx = np.array([[-1, 0, 1], 
               [-2, 0, 2], 
               [-1, 0, 1]])

Ky = np.array([[-1, -2, -1], 
               [ 0,  0,  0], 
               [ 1,  2,  1]])

# apply correlations and normalize by sum of absolute values of elements
sobelx = ndimage.filters.correlate(blur, Kx)
sobely = ndimage.filters.correlate(blur, Ky)

#OpenCV alternate:
#sobelx = cv2.filter2D(blur, cv2.CV_32F, Kx)
#sobely = cv2.filter2D(blur, cv2.CV_32F, Ky)

# optionally normalize to range 0 to 255 for proper display and saving as 8-bit data.
sobelx_norm= exposure.rescale_intensity(sobelx, in_range='image', out_range=(0,255)).clip(0,255).astype(np.uint8)
sobely_norm= exposure.rescale_intensity(sobelx, in_range='image', out_range=(0,255)).clip(0,255).astype(np.uint8)

# add and take square root
sobel_magnitude = np.sqrt(np.square(sobelx) + np.square(sobely))

# normalize to range 0 to 255 and clip negatives
sobel_magnitude = exposure.rescale_intensity(sobel_magnitude, in_range='image', out_range=(0,255)).clip(0,255).astype(np.uint8)

# save results
cv2.imwrite('gray_lena_sobelx_norm2.jpg', sobelx_norm)
cv2.imwrite('gray_lena_sobely_norm2.jpg', sobely_norm)
cv2.imwrite('gray_lena_sobel_magnitude2.jpg', sobel_magnitude)

# show results
cv2.imshow('sobelx_norm', sobelx_norm)  
cv2.imshow('sobely_norm', sobely_norm)  
cv2.imshow('sobel_magnitude', sobel_magnitude)  
cv2.waitKey(0)
cv2.destroyAllWindows()

Sobel X(归一化):

Sobel Y(归一化):

索贝尔星等: