Python 中的非最大值抑制给出了不好的结果:出了啥问题?
Posted
技术标签:
【中文标题】Python 中的非最大值抑制给出了不好的结果:出了啥问题?【英文标题】:Non maxima suppression in Python gives bad result: what is wrong?Python 中的非最大值抑制给出了不好的结果:出了什么问题? 【发布时间】:2020-05-12 10:13:40 【问题描述】:我自己在 Python 中实现 Canny 边缘检测,我被困在非最大值抑制部分。我以为我的代码是正确的,但是我得到了一个非常糟糕的结果,根本没有漂亮的线条。我使用 Skimage 的 Canny 边缘检测进行比较,下面是结果(左:Sobel 滤波器的梯度幅度,中:非极大值抑制后,右:skimage Canny 的结果(我知道这是在阈值和滞后之后,但我希望非极大值抑制后的结果应该与 skimage Canny 结果相当))。
这是我用于非最大值抑制的代码:
def non_max_sup8(magn,direct):
size=magn.shape
out=np.zeros_like(magn)
direct=np.rad2deg(direct)+180 # direction is now between 0 and 360
for i in range(1,size[0]-1):
for j in range(1,size[1]-1):
if 0<=direct[i,j]<22.5 or 337.5<=direct[i,j]<=360 or 157.5<=direct[i,j]<202.5:
before=magn[i,j-1] # compare to left and right
after=magn[i,j+1]
elif 22.5<=direct[i,j]<67.5 or 202.5<=direct[i,j]<247.5:
before=magn[i+1,j-1] # compare diagonally
after=magn[i-1,j+1]
elif 67.5<=direct[i,j]<112.5 or 247.5<=direct[i,j]<292.5:
before=magn[i+1,j] # compare above and under
after=magn[i-1,j]
else:
before=magn[i-1,j-1] # compare diagonally
after=magn[i+1,j+1]
if magn[i,j]>=before and magn[i,j]>=after:
out[i,j]=magn[i,j]
return out
梯度计算如下,应该是正确的。 (方向在 -pi 和 pi 之间的弧度,在上面的代码中转换为 0 到 360 度)
def edges(img,filterv=vSobel,filterh=hSobel):
height,width = img.shape
magn=np.zeros_like(img)
direc=np.zeros_like(img)
X=np.zeros_like(img)
Y=np.zeros_like(img)
for y in range(3,height-2):
for x in range(3,width-2):
box = img[x-1:x+2,y-1:y+2]
transformv = filterv * box
Gy = transformv.sum()/4
transformh = filterh * box
Gx = transformh.sum()/4
X[x,y] = Gx
Y[x,y] = Gy
magn[x,y]=np.sqrt(Gx**2+Gy**2)
direc[x,y]=np.arctan2(Gy,Gx)
return X,Y,magn,direc
所以,我的问题是:我做错了什么?我正在考虑以下内容,但我想听听您的想法: 假设方向是 90 度(所以向上),那么我认为您实际上想要比较像素左右而不是上下(就像我到目前为止所做的那样),从那时起您会得到一个像素边缘。然而,我的代码基于我在互联网上找到的东西,它们似乎都做了类似上面的事情:与梯度方向上的像素而不是法线方向上的像素进行比较。你怎么看待这件事?是我误解了什么,还是我的想法还不错?
编辑:尝试上述方法(将像素与法线方向上的两个像素进行比较,而不是像素的方向)给出的结果类似于 skimage 的 canny 边缘检测。
问候。
【问题讨论】:
Gx = transformv
看起来不对。 “v”代表垂直,不是吗? “x”是水平的,不是吗?您的结果与方向旋转 90 度一致。我建议您绘制并检查方向图像,并根据图像中的边缘将其与您的预期进行比较。
感谢您指出这一点!我什至没有注意到。不过奇怪的是我也换了Sobel过滤器,所以filterv
实际上是用来计算Gx的过滤器,所以它消除了错误哈哈!我会在我的问题中改变它:)
不过,请查看direct
的值,以确保它们符合您的期望。您可能必须使用-direct
或direct+90
或90-direct
或一些这样的转换来使角度与跨边缘的方向匹配。
【参考方案1】:
45 和 135 的顺序是错误的(已更改),因为当您应该使用 yx 坐标系时考虑 xy 坐标系(45 yx 中的度数相当于 xy 平面中的 315 度)。根据我的实现,应该是:
#for 45
elif 22.5<=direct[i,j]<67.5 or 202.5<=direct[i,j]<247.5:
before=magn[i-1,j-1]
after=magn[i+1,j+1]
#for 135
else:
before=magn[i+1,j-1]
after=magn[i-1,j+1]
【讨论】:
以上是关于Python 中的非最大值抑制给出了不好的结果:出了啥问题?的主要内容,如果未能解决你的问题,请参考以下文章
[目标检测][python][cpp]非极大值抑制(NMS)算法原理以及CPP实现