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(归一化):
索贝尔星等:
我试图在 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(归一化):
索贝尔星等: