【无标题】

基于python的连通域算法实现

一、简介

由于课题需要在python上实现连通域算法的实现。根据网上的两步扫描法和种子法发现算法对非闭合曲线类型的图形分类效果有问题(比如说一个“U”形)。其原因主要是图像像素分布各向异性的问题,导致按从左到右,再按从上到下的扫描方式与从右到左,从下往上的扫描方式所获得的结果是完全不同的。当然我们可以增加扫描的次数,以将每个扫描窗的最小值赋给整个窗口,但是所需要的扫描次数是难以确定的,因此我认为每次以穷举法为原则,找出属于一个连通域所有像素,再去寻找下一个连通域的像素的方式是最为准确的。

二、代码

import numpy as np
import scipy.io as sio
import matplotlib.pyplot as plt
import datetime
start_time = datetime.datetime.now()
image = np.array([[0, 0, 1, 0, 0, 1],
                  [1, 0, 1, 0, 1, 0],
                  [1, 0, 1, 0, 1, 0],
                  [1, 0, 1, 0, 1, 0],
                  [1, 0, 1, 0, 1, 1],
                  [1, 1, 1, 0, 0, 1],])
# 图像
image_row = image.shape[0] + 2
image_col = image.shape[1] + 2
image_con = np.zeros([image_row, image_col], dtype=np.int16)
image_con[1:-1, 1:-1] = image
image_seed_value = np.reshape(image_con, [-1])
image_seed = np.argwhere(image_seed_value == 1).tolist()
cur_id = 2
total_area = []
def connect(window, center, image_col, mode):
	# 这个函数是根据原始二值图返回其邻域连通节点的坐标
    index_list = []
    if mode == '8':
        kernel = np.array([[1, 1, 1], [1, 0, 1], [1, 1, 1]])
        # 连通域卷积核,主要分为“8”连通和“4”连通
    elif mode == '4':
        kernel = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]])
    else:
        print('沙雕,填错了,重新来')
        return
    result = window * kernel
    connect_set = (np.argwhere(result == 1).astype(np.int32) + center + np.array([-1, -1], dtype=np.int32)).tolist()
    for index in connect_set:
        index_list.append(index[0] * image_col + index[1])
    return index_list

while len(image_seed) > 0:
    # 循环终止条件判断,既当所有的1都完全分类完成后,循环终止
    cur_seed = image_seed[0][0]
    cur_center = [cur_seed // image_col, cur_seed % image_col]
    image_seed.remove([cur_seed])
    cur_id_set = []
    cur_id_set.append(cur_seed)
    image_con[cur_center[0], cur_center[1]] = cur_id
    cur_window = image_con[cur_center[0] - 1:cur_center[0] + 2, cur_center[1] - 1:cur_center[1] + 2]
    cur_son = connect(cur_window, cur_center, image_col, mode)
    # 修正卷积后的坐标
    while len(cur_son) > 0:
        cur_seed = cur_son[0]
        if cur_seed in cur_id_set:
            cur_son.pop(0)
            continue
        cur_center = [cur_seed // image_col, cur_seed % image_col]
        # if [cur_seed] in image_seed:
        image_seed.remove([cur_seed])
        cur_id_set.append(cur_seed)
        cur_son.pop(0)
        image_con[cur_center[0], cur_center[1]] = cur_id
        cur_window = image_con[cur_center[0] - 1:cur_center[0] + 2, cur_center[1] - 1:cur_center[1] + 2]
        cur_son.extend(connect(cur_window, cur_center, image_col, mode))
    total_area.append(cur_id_set)
    cur_id += 1
image_lab = image_con[1:-1, 1:-1]
end_time0 = datetime.datetime.now()
time_use0 = 'label time use:%dms' % ((end_time0 - start_time).seconds * 1000 + (end_time0 - start_time).microseconds / 1000)
print(time_use0)

简单来说,就是先找出所有为1的元素总列表,然后根据连通特性将总列表的元素划分到不同的子列表中去。

三、结果

在这里插入图片描述效果如图所示,针对连通域特别多时,也能够适用,如下图所示
在这里插入图片描述
但是算法的总体速度不算特别快,大概是matlab中的bwlabeln函数的计算时间的8倍,而在我的电脑上,python计算循环的花的时间大概是matlab的4倍,其他时间上的花费我也不太清楚从什么方向上改进了,希望各位大佬帮我多多批评指正。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值