自适应Canny边缘检测算法
Adaptive Canny Edge Detection Algorithm
我正在尝试使用 python 从头开始实施 Canny 算法。
我正在按照步骤进行
双边过滤图像
在4个不同方向上使用高斯一阶导数计算梯度
def deroGauss(w=5,s=1,angle=0):
wlim = (w-1)/2
y,x = np.meshgrid(np.arange(-wlim,wlim+1),np.arange(-wlim,wlim+1))
G = np.exp(-np.sum((np.square(x),np.square(y)),axis=0)/(2*np.float64(s)**2))
G = G/np.sum(G)
dGdx = -np.multiply(x,G)/np.float64(s)**2
dGdy = -np.multiply(y,G)/np.float64(s)**2
angle = angle*math.pi/180 #converting to radians
dog = math.cos(angle)*dGdx + math.sin(angle)*dGdy
return dog
- 所有4个梯度图像都没有最大抑制
def nonmaxsup(I,gradang):
dim = I.shape
Inms = np.zeros(dim)
weak = np.zeros(dim)
strong = np.zeros(dim)
final = np.zeros(dim)
xshift = int(np.round(math.cos(gradang*np.pi/180)))
yshift = int(np.round(math.sin(gradang*np.pi/180)))
Ipad = np.pad(I,(1,),'constant',constant_values = (0,0))
for r in xrange(1,dim[0]+1):
for c in xrange(1,dim[1]+1):
maggrad = [Ipad[r-xshift,c-yshift],Ipad[r,c],Ipad[r+xshift,c+yshift]]
if Ipad[r,c] == np.max(maggrad):
Inms[r-1,c-1] = Ipad[r,c]
return Inms
- 双阈值和滞后:现在真正的问题来了。
我正在使用 Otsu 的方法来计算阈值。
我应该使用灰度图像还是渐变图像来计算阈值?
因为在梯度图像中,像素强度值在双边滤波后被降低到一个非常低的值,然后在与高斯导数卷积后进一步降低。例如 :: 28, 15
使用灰度计算的阈值远高于使用梯度图像计算的阈值。
此外,如果我使用灰度甚至梯度图像来计算阈值,则生成的图像不够好并且不包含所有边缘。
所以实际上,我已经没有什么可以应用滞后了。
我试过了
img_edge = img_edge*255/np.max(img_edge)
放大值,但结果保持不变
但如果我使用与 cv2.Canny
相同的阈值,结果会非常好。
究竟有什么问题?
从原始图像应用 Otsu 阈值没有意义,它与梯度强度完全无关。
梯度强度的 Otsu 并不完美,因为噪声和边缘的统计分布偏斜且重叠很多。
您可以尝试一些 Otsu 的小倍数或平均值的一些小倍数。但是在任何情况下,您都不会通过简单或滞后阈值来获得完美的结果。边缘检测是一个病态问题。
我正在尝试使用 python 从头开始实施 Canny 算法。
我正在按照步骤进行
双边过滤图像
在4个不同方向上使用高斯一阶导数计算梯度
def deroGauss(w=5,s=1,angle=0):
wlim = (w-1)/2
y,x = np.meshgrid(np.arange(-wlim,wlim+1),np.arange(-wlim,wlim+1))
G = np.exp(-np.sum((np.square(x),np.square(y)),axis=0)/(2*np.float64(s)**2))
G = G/np.sum(G)
dGdx = -np.multiply(x,G)/np.float64(s)**2
dGdy = -np.multiply(y,G)/np.float64(s)**2
angle = angle*math.pi/180 #converting to radians
dog = math.cos(angle)*dGdx + math.sin(angle)*dGdy
return dog
- 所有4个梯度图像都没有最大抑制
def nonmaxsup(I,gradang):
dim = I.shape
Inms = np.zeros(dim)
weak = np.zeros(dim)
strong = np.zeros(dim)
final = np.zeros(dim)
xshift = int(np.round(math.cos(gradang*np.pi/180)))
yshift = int(np.round(math.sin(gradang*np.pi/180)))
Ipad = np.pad(I,(1,),'constant',constant_values = (0,0))
for r in xrange(1,dim[0]+1):
for c in xrange(1,dim[1]+1):
maggrad = [Ipad[r-xshift,c-yshift],Ipad[r,c],Ipad[r+xshift,c+yshift]]
if Ipad[r,c] == np.max(maggrad):
Inms[r-1,c-1] = Ipad[r,c]
return Inms
- 双阈值和滞后:现在真正的问题来了。
我正在使用 Otsu 的方法来计算阈值。
我应该使用灰度图像还是渐变图像来计算阈值?
因为在梯度图像中,像素强度值在双边滤波后被降低到一个非常低的值,然后在与高斯导数卷积后进一步降低。例如 :: 28, 15
使用灰度计算的阈值远高于使用梯度图像计算的阈值。
此外,如果我使用灰度甚至梯度图像来计算阈值,则生成的图像不够好并且不包含所有边缘。
所以实际上,我已经没有什么可以应用滞后了。
我试过了
img_edge = img_edge*255/np.max(img_edge)
放大值,但结果保持不变
但如果我使用与 cv2.Canny
相同的阈值,结果会非常好。
究竟有什么问题?
从原始图像应用 Otsu 阈值没有意义,它与梯度强度完全无关。
梯度强度的 Otsu 并不完美,因为噪声和边缘的统计分布偏斜且重叠很多。
您可以尝试一些 Otsu 的小倍数或平均值的一些小倍数。但是在任何情况下,您都不会通过简单或滞后阈值来获得完美的结果。边缘检测是一个病态问题。