目标轮廓提取之边界跟踪法

1 引言

上一篇我们介绍了目标轮廓提取法来提取目标轮廓,这一章节我们来介绍边界跟踪法。边界跟踪的定义为从图像中的一个边界点出发,然后根据某种判别准则搜索出下一个边界点,以此跟踪出目标边界。
目标轮廓提取之边界跟踪法_第1张图片
边界跟踪的一般步骤如下:
1)确定边界的起始搜索点,起始点的选择很关键,对于某些图像,选择不同的起始点会导致不同的结果
2)确定合适边界判别准则搜索准则,判别准则主要用于判断一个点是不是边界点,搜索准则则知道如何搜索下一个边缘点。
3)确定搜索的终止条件

2 算法原理

边界跟踪算法原理:
1)从左下角开始逐点扫描,当遇到边缘点时,则跟踪,直至跟后续点回到起始点(对于闭合线),或其后续点在没有新的后续点(对于非闭合线)为止。
2)如果为非闭合线,则跟踪一侧后,需从起始点开始朝相反方向跟踪到另一尾点。
3)如果不止一个后续点,则按上述连接准则选择距离最近的点为后续点,另一次近的后续点作为新的边缘跟踪起点另行跟踪。
4)一条线跟踪完后,接着扫描到下一个未跟踪点,直到所有边缘都跟踪完毕。
我们来举个栗子吧:
目标轮廓提取之边界跟踪法_第2张图片
上图为边界跟踪示意图,图中黑点表示边界点,白点为图像的内部点。

  • 跟踪的初始点是最左下方的黑点(即最后一行的最左黑点),跟踪的初始方向设定为左上角45度。
  • 跟踪开始后,初始点沿初始跟踪方向检测该方向是否有黑点(检测距离为一个像素点),如果是,则保存初始点,将检测到的点作为新的初始点,同时在原来检测的基础上,逆时针旋转90度作为新的跟踪方向。如果不是目标点,则沿顺时针旋转45度,沿新跟踪方向继续检测,直到找到黑色像素,然后将跟踪方向逆时针旋转90作为新的跟踪方向。
  • 重复上面不断改变跟踪方向,直到找到新的边界点。找到新的边界点后,将旧的边界点保存,将新检测到的点作为新的初始点。
  • 这样不断重复上述过程,直到检测点回到最开始的检测点为止。

注意:中心像素可以跟踪的方向有8个,对每个方向制定了方向编号以及偏移量,如下图所示。一般来说,通常选取图像的最左下角的像素点作为起点。
目标轮廓提取之边界跟踪法_第3张图片

3 Python实现

  1. 读入彩色图像
img_name = "./20210812/sample3.png"
img = cv2.imread(img_name)

结果如下:
目标轮廓提取之边界跟踪法_第4张图片
2) 彩色图像灰度化

 gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

结果如下:
目标轮廓提取之边界跟踪法_第5张图片
3) 图像二值化

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) 

结果如下:
目标轮廓提取之边界跟踪法_第6张图片

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)

结果如下:
目标轮廓提取之边界跟踪法_第7张图片

4 总结

通过上述简单步骤,我们实现了物体边界跟踪,相应的处理效果如下:
目标轮廓提取之边界跟踪法_第8张图片

上图中 左侧为原图,右侧为我们提取的物体边界跟踪效果图。


关注公众号《AI算法之道》,获取更多AI算法资讯。

在这里插入图片描述

你可能感兴趣的:(图像处理,计算机视觉,python,opencv)