8方向连通域统计——two-pass算法(用于图像斑块数统计)

8方向连通域统计——two-pass算法(用于图像斑块数统计)

问题描述

现有一幅单通道灰度图像,图中像素共有0,1两种取值(取值代表类别代号,与算法无关)。现欲统计:每种取值的像素在图中构成的“斑块”的数目。斑块类似连通域的概念,这里我们定义像素数大于4的连通域才被算作一个斑块。

这个问题可以借助连通域标记算法解决。

连通域标记问题

连通域标记(Connected Component Labelling)问题, 主要有Two-Pass和Seed-Filling两种算法。本文介绍Two-Pass算法。

逐像素遍历图像,根据周围邻居像素的标签来给当前像素打标签。然后进行二次遍历,将同在一个斑块内的几种标签标记为一样(一个斑块内的几种标签,即等效标签,存储在并查集中)。

Two-Pass算法

只需要遍历两遍就可以完成标记。

First Pass

遍历每一个像素,如果像素p的值不为0,则考察它左上方的4个邻居的值。

  • 如果邻居的值均为0,则给他打上标签(自增的,label_counter)。
  • 如果邻居中存在不为0的值,取其中的最小值赋给p。随后利用并查集,把邻居的各种取值都建立联系(认定为同一个连通域)。

比如在下图中,像素p(红色块)的值不为0,考察其邻居的值,把2赋给p,同时把2和3标记为等价(在Union-Find set中,2和3有公共的根节点)。
红色是当前像素,蓝色是8连通中的4个邻居。

Second Pass

遍历每一个非0的像素,利用建好的并查集的find方法,把每一个像素的取值设为对应根节点的值。

Python实现

import numpy as np


class UnionFind:
    def __init__(self, n):
        """长度为n的并查集"""
        self.uf = [-1] * (n + 1)  # 列表0位置空出
        self.sets_count = n  # 判断并查集里共有几个集合, 初始化默认互相独立

    def find(self, p):
        """查找p的根结点(祖先)"""
        r = p  # 初始p
        while self.uf[p] > 0:
            p = self.uf[p]
        while r != p:  # 路径压缩, 把搜索下来的结点祖先全指向根结点
            self.uf[r], r = p, self.uf[r]
        return p

    def union(self, p, q):
        """连通p,q 让q指向p"""
        proot = self.find(p)
        qroot = self.find(q)
        if proot == qroot:
            return
        elif self.uf[proot] > self.uf[qroot]:  # 负数比较, 左边规模更小
            self.uf[qroot] += self.uf[proot]
            self.uf[proot] = qroot
        else:
            self.uf[proot] += self.uf[qroot]
            self.uf[qroot] = proot
        self.sets_count -= 1                   # 连通后集合总数减一

    def is_connected(self, p, q):
        """判断pq是否已经连通"""
        return self.find(p) == self.find(q)  # 即判断两个结点是否是属于同一个祖先


def im_binary(data: np.ndarray, target_value: int):
    return np.where(data == target_value, 1, 0)


def im_padding(data: np.ndarray):
    return np.pad(data, ((1, 1), (1, 1)), 'constant')


def first_pass(data, uf_set):
    offsets = [[-1, -1], [0, -1], [-1, 1], [-1,  0]]
    label_counter = 2
    for y in range(1, data.shape[0]-1):
        for x in range(1, data.shape[1]-1):
            if data[y, x] == 0:
                continue
            neighbor = []
            for offset in offsets:
                if data[y + offset[0], x + offset[1]] != 0:
                    neighbor.append(data[y + offset[0], x + offset[1]])
            neighbor = np.unique(neighbor)
            if len(neighbor) == 0:
                data[y, x] = label_counter
                label_counter += 1
            elif len(neighbor) == 1:
                data[y, x] = neighbor[0]
            else:
                # 邻居内有多重label, 这种情况要把最小值赋给data[y, x], 同时建立值之间的联系.
                data[y, x] = neighbor[0]
                for n in neighbor:
                    uf_set.union(int(neighbor[0]), int(n))


def second_pass(data, uf_set):
    for y in range(data.shape[0]):
        for x in range(data.shape[1]):
            if data[y, x] != 0:
                data[y, x] = uf_set.find(int(data[y, x]))
  • im_binary() 方法把一个图像中等于target_value的值置为1,其余的置为0,实现二值化。
  • im_padding() 把图片周围补一圈0,这样才能用下面的算法。

例子

输入是一个植被指数(NDVI)单通道图像。希望把NDVI值大于0.1的部分设为1,小于的部分设为0,再计算1构成的连通域(图斑)的数量,并实现可视化。

def count_patch(data, get_img=False):
    # 统计某一种类别的图斑数. 返回各个图斑的像素数,和结果图.
    ufSet = UnionFind(1000000)
    first_pass(data, ufSet)
    second_pass(data, ufSet)

    count_dic = {}
    for y in range(1, data.shape[0] - 1):
        for x in range(1, data.shape[1] - 1):
            if data[y, x] in count_dic:
                count_dic[data[y, x]] += 1
            else:
                count_dic[data[y, x]] = 1

    count_dic.pop(0)

    if get_img:
        return list(count_dic.values()), data
    else:
        return list(count_dic.values())

结果图如下(同一连通域被标记成一种颜色):
同一连通域被标记成一种颜色

  • 6
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
Two-Pass算法是计算连通域的一种基本方法之一\[1\]。它是一种用于图像处理算法,可以用于标记和计算图像中的连通域。在FPGA(现场可编程门阵列)中实现Two-Pass算法可以提高图像处理的效率和速度。 FPGA是一种可编程的硬件设备,可以根据需要重新配置其内部电路,以实现特定的功能。在FPGA中实现Two-Pass算法,可以通过并行处理的方式同时处理多个像素,从而加快图像处理的速度。通过将Two-Pass算法的各个步骤分配到FPGA的不同部分,可以实现高效的图像连通域计算。 具体实现Two-Pass算法的FPGA设计需要根据具体的硬件平台和需求进行设计和优化。可以使用硬件描述语言(如VHDL或Verilog)来描述算法的逻辑和功能,并使用FPGA开发工具进行编译和综合。通过合理的设计和优化,可以实现高性能和低功耗的图像处理系统。 总之,通过在FPGA中实现Two-Pass算法,可以提高图像处理的效率和速度,适用于需要高性能图像处理的应用场景。 #### 引用[.reference_title] - *1* *3* [Two-Pass算法——图像连通域分析](https://blog.csdn.net/liujiabin076/article/details/80788459)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [图像算法--基于fpga的双边滤波算法](https://blog.csdn.net/qq_40057229/article/details/127517641)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

毕尔街日报

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值