上一篇我们介绍了目标轮廓提取法来提取目标轮廓,这一章节我们来介绍边界跟踪法。边界跟踪的定义为从图像中的一个边界点出发,然后根据某种判别准则搜索出下一个边界点,以此跟踪出目标边界。
边界跟踪的一般步骤如下:
1)确定边界的起始搜索点,起始点的选择很关键,对于某些图像,选择不同的起始点会导致不同的结果
2)确定合适边界判别准则和搜索准则,判别准则主要用于判断一个点是不是边界点,搜索准则则知道如何搜索下一个边缘点。
3)确定搜索的终止条件。
边界跟踪算法原理:
1)从左下角开始逐点扫描,当遇到边缘点时,则跟踪,直至跟后续点回到起始点(对于闭合线),或其后续点在没有新的后续点(对于非闭合线)为止。
2)如果为非闭合线,则跟踪一侧后,需从起始点开始朝相反方向跟踪到另一尾点。
3)如果不止一个后续点,则按上述连接准则选择距离最近的点为后续点,另一次近的后续点作为新的边缘跟踪起点另行跟踪。
4)一条线跟踪完后,接着扫描到下一个未跟踪点,直到所有边缘都跟踪完毕。
我们来举个栗子吧:
上图为边界跟踪示意图,图中黑点表示边界点,白点为图像的内部点。
注意:中心像素可以跟踪的方向有8个,对每个方向制定了方向编号以及偏移量,如下图所示。一般来说,通常选取图像的最左下角的像素点作为起点。
img_name = "./20210812/sample3.png"
img = cv2.imread(img_name)
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
def get_binary_img(img):
# gray img to bin image
bin_img = np.zeros(shape=(img.shape), dtype=np.uint8)
h = img.shape[0]
w = img.shape[1]
for i in range(h):
for j in range(w):
bin_img[i][j] = 255 if img[i][j] > 200 else 0
return bin_img
# 调用
bin_img = get_binary_img(gray_img)
4)边界跟踪
参考上述原理,进行实现,代码如下:
# 从左上角查找开始
def get_left_up_start_pt(bin_img):
h = bin_img.shape[0]
w = bin_img.shape[1]
find = 0
start_i = 0
start_j = 0
for i in range(h):
for j in range(w):
if bin_img[i][j] == 0:
find = 1
start_i = i
start_j = j
break
return find,start_i,start_j
def trace_contour(bin_img,find,start_i,start_j):
contour_img = np.zeros(shape=(bin_img.shape), dtype=np.uint8)
contour_img += 255
if find:
contour_img[start_i][start_j] = 0
Direct = [(-1,1),(0,1),(1,1),(1,0),(1,-1),(0,-1),(-1,-1),(-1,0)]
BeginDirect = 0
findstart = 0
cur_i = start_i
cur_j = start_j
while findstart==0 :
findpoint = 0
while findpoint==0:
i = cur_i + Direct[BeginDirect][1]
j = cur_j + Direct[BeginDirect][0]
pixel = bin_img[i][j]
if pixel==0:
findpoint = 1
cur_i = i
cur_j = j
if cur_i ==start_i and cur_j == start_j:
findstart = 1
contour_img[cur_i][cur_j] = 0
BeginDirect-=1
if BeginDirect == -1:
BeginDirect = 7
BeginDirect-=1
if BeginDirect == -1:
BeginDirect = 7
else:
BeginDirect += 1
if BeginDirect == 8:
BeginDirect = 0
return contour_img
# 调用
find, start_i, start_j = get_left_up_start_pt(bin_img)
contour_img = trace_contour(bin_img,find,start_i,start_j)
通过上述简单步骤,我们实现了物体边界跟踪,相应的处理效果如下:
上图中 左侧为原图,右侧为我们提取的物体边界跟踪效果图。