我试图通过分析它们的曲率值来定义嘈杂的轮廓。
以下是实现细节:
1. Threshold the gray scale image using fixed threshold value of 250 to retrieve the white edges
2.Extract the contours in the threshold image
3.Calculate the curvature values along each contour
4.From the curvature data we can observer that the noisy contour's curvature values has higher variance value, therefore we can classify such
noisy contours using certain threshold value.
以下是上述步骤的 Python 实现。
这里我使用定义为here的笛卡尔坐标系的曲率估计方程@
#function to calculate the curvature values along a given contour and classify noisy contour
def contourCurvature(contourspt):
#curvature value estimation using symmetric derivation
# at points (i-step), i, (i+step)
step = 5
s1 = 2*step
s2 = np.power(s1, 2)
if len(contourspt) < s1:
return False
kp = []
l = len(contourspt)
ct = 0
for i in range(l):
p = i - step
pp = i - s1
if p < 0:
p += l
pp += l
elif pp < 0:
pp += l
n = (i + step) % l
nn = (i + s1) % l
posPrev = contourspt[p][0]
posPrevP = contourspt[pp][0]
posCurr = contourspt[i][0]
posNext = contourspt[n][0]
posNextN = contourspt[nn][0]
#first order derivative at point i w.r.t. x and y
f1stderX = (posNext[0] - posPrev[0])/s1
f1stderY = (posNext[1] - posPrev[1])/s1
# second order derivative at point i w.r.t. x and y
f2ndderX = (posNextN[0] - 2*posCurr[0] + posPrevP[0])/s2
f2ndderY = (posNextN[1] - 2*posCurr[1] + posPrevP[1])/s2
if f1stderX != 0 or f1stderY != 0:
a = f2ndderX*f1stderY - f2ndderY*f1stderX
b = np.power(np.power(f1stderX,2) + np.power(f1stderY,2), 3/2)
curvature2D = float("{0:.5f}".format(a/b))
#Check if contour contains any regular section of more than
# 20 percent of the contour length
if np.abs(curvature2D) < 0.005:
ct += 1
if ct > l*0.2:
return True
else:
ct = 0
if np.abs(curvature2D) < 0.0001 or np.abs(curvature2D) > 5:
curvature2D = 0 #local noise suppression
#store the curvature values in a list
kp.append(np.abs(curvature2D))
# check the variance of curvatures values along the contour
var = np.var(kp, ddof=1)
if var < 0.01:
print('Variance: ',var)
return True
return False
def main():
gray = cv2.imread('D:/cnt.png', 0)
#threshold the image using 250 as threhold value
ret,th1 = cv2.threshold(gray,250,255,cv2.THRESH_BINARY)
img1,contours,hierarchy = cv2.findContours(th1, cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
img = cv2.cvtColor(gray, cv2.COLOR_GRAY2RGB)
#iterate through each contour
for cnt in contours:
if(len(cnt)>50): #neglect the small contours as noise
flag = contourCurvature(cnt)
if(flag):
cv2.drawContours(img,[cnt],0,(0,0,255),3)
cv2.imshow('Final image', img)
cv2.waitKey(0)
if __name__ == "__main__":
main()
这是仅显示非噪声(真实)轮廓的输出图像。
虽然最终输出的图像遗漏了一些真实的轮廓,但这里欢迎任何其他改进此算法的想法。