问题描述
我试图在python中实现sobel过滤器,但输出效果不佳且充满噪音。 我得到的输出图像是:
我给的输入是(模糊之后):
sobel过滤器的代码如下:
def sobel_filters(img):
Kx = np.array([[-1,1],[-2,2],[-1,1]])
Ky = np.array([[1,2,[0,0],-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内置的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,ksize=3)
sobely = cv2.Sobel(blur,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,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,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,1.3)
# define Sobel X and Y (correlation) kernels
Kx = np.array([[-1,1],[-2,2],[-1,1]])
Ky = np.array([[-1,-2,-1],[ 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,Ky)
# optionally normalize to range 0 to 255 for proper display and saving as 8-bit data.
sobelx_norm= exposure.rescale_intensity(sobelx,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,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)
cv2.waitKey(0)
cv2.destroyAllWindows()
Sobel X(规范化):
Sobel Y(标准化):
苏贝尔幅值: