• Numpy实现分水岭分割算法【未完结】


    from queue import PriorityQueue
    import numpy as np
    
    
    class Pixel(object):
        """
        像素信息,包含像素的坐标和梯度
        """
    
        def __init__(self, gradient, location):
            self.gradient = gradient
            self.location = location
    
        def __lt__(self, other):
            return self.gradient < other.gradient
    
        def __str__(self):
            return f'{self.gradient}:{self.location}'
    
    
    class Watershed:
        grad: np.ndarray
        markers: np.ndarray
    
        def __init__(self, grad, markers=None):
            """
            分水岭分割算法:\n
            (1)基于标记控制的分水岭算法:原始梯度图 + 标记矩阵\n
            (2)基于标记控制和强制最小技术的分水岭算法:强制最小后的梯度图
    
            :param grad:    输入的梯度图像(用于优先级排序:梯度小的优先级大)
            :param markers: 输入的标记矩阵(用于区分汇水区:汇水区分界处为分水岭)
            """
            # 进入队列的标记
            self.VISITED = -2
            # 分水岭的标记
            self.W_SHED = -1
            # 未知点的标记
            self.UNKNOWN = 0
            # 像素队列(优先级为梯度值,梯度小的优先级高:类似于汇水区汇水,由低至高涨水)
            self.queue = PriorityQueue()
            # 输入梯度图像的拷贝
            self.grad = grad.copy()
            # 输入标记矩阵
            if markers is None:
                self.markers = np.zeros_like(grad)
            else:
                self.markers = markers.copy()
            # opencv的视觉边缘设置为分水岭(东南西北)
            self.markers[:, self.markers.shape[1] - 1] = self.W_SHED
            self.markers[0, :] = self.W_SHED
            self.markers[:, 0] = self.W_SHED
            self.markers[self.markers.shape[0] - 1, :] = self.W_SHED
            # 定义4邻域规则,邻域内有无已知前景区域或者背景区域
            self.neighbourhood4 = lambda x, y: {(x - 1, y): self.markers[x - 1, y],
                                                (x + 1, y): self.markers[x + 1, y],
                                                (x, y - 1): self.markers[x, y - 1],
                                                (x, y + 1): self.markers[x, y + 1]}
            self.nbh4_any_known = lambda x, y: np.any(np.array([val for loc, val in self.neighbourhood4(x, y).items()]) > 0)
    
        def ws_push(self, location: tuple) -> None:
            """
            将传入的像素点的位置信息入队,并在markers上做标记
    
            :param location:    输入的像素点位置信息(x, y)
            :return:            None
            """
            gradient: int = self.grad[location[0], location[1]]
            pixel = Pixel(gradient, location)
            self.queue.put(pixel)
            self.markers[location[0], location[1]] = self.VISITED
    
        def ws_pop(self) -> tuple:
            """
            将队首像素点信息出队
    
            :return:    队首像素点信息(若队为空则返回[-1,-1])
            """
            return self.queue.get().location if self.queue.qsize() > 0 else (-1, -1)
    
        def label_nbh4_pixels(self, location: tuple) -> None:
            """
            在markers中,为每一个像素点对应的位置处设置label
    
            :param location:    输入的像素点位置
            :return:            None
            """
            (x, y), label = location, self.UNKNOWN
            for nbh4_loc, nbh4_val in self.neighbourhood4(x, y).items():
                # 当邻域内像素是前景区域或者背景区域时
                if nbh4_val > 0:
                    # 如果是第一个邻域点,则让label赋值为该邻域点的值
                    if label == self.UNKNOWN:
                        label = nbh4_val
                    # 如果该邻域点的值不等于之前领域点的值,则说明pixel是分水岭(前景和背景的交界处,也就是边缘处)
                    elif label != nbh4_val:
                        label = self.W_SHED
                    # 如果该邻域点的值与之前邻域点的值是相等的,则保持不变
                    else:
                        pass
            # 将该点在markers中标记为label
            self.markers[x, y] = label
    
        def push_nbh4_pixels(self, location: tuple) -> None:
            """
            对各个像素点进行四领域分析:\n
                如果满足以下条件则入队:\n
                (1)pixel既不是分水岭,也没有入队(没有归属于积水池);\n
                (2)邻域点既不是前景区域,也不是背景区域,也就是说它属于unknown区域;
    
            :param location:    输入的像素坐标
            :return:            None
            """
            (x, y) = location
            # 首先得确保该像素点不是分水岭,如果是分水岭就没必要再入队寻找了(因为已经找到了)
            if self.markers[x, y] != self.W_SHED:
                for nbh4_loc, nbh4_val in self.neighbourhood4(x, y).items():
                    # 只对未知区域进行扩散(已知区域已经确定了,就没必要扩散了)
                    if nbh4_val == self.UNKNOWN:
                        self.ws_push(nbh4_loc)
    
        def watershed(self) -> np.ndarray:
            """
            执行基于标记的分水岭分割算法
    
            :return:    处理后的标记矩阵
            """
            # 将markers的初始点(属于unknown区域且4邻域内存在已知区域)放入优先队列
            for row in range(1, self.markers.shape[0] - 1):
                for col in range(1, self.markers.shape[1] - 1):
                    # 保证先从unknown区域的边缘处开始寻找分水岭
                    if self.markers[row, col] == self.UNKNOWN and self.nbh4_any_known(row, col):
                        self.ws_push((row, col))
            # 将优先队列中的像素点位置信息“先出队后入队”,并保证每个像素点有且仅有一次处理机会
            counter, max_its = 0, self.markers.shape[0] * self.markers.shape[1]
            while self.queue.qsize() > 0 and counter < max_its:
                # 将梯度最高的像素点出队(梯度越高的点也可能是分水岭)
                location = self.ws_pop()
                # 判断该像素点是否为分水岭(依据为4邻域内是否同时存在不同类型的已知区域)
                self.label_nbh4_pixels(location)
                # 如果该点不是分水岭,则将其4邻域内unknown区域的像素点入队
                self.push_nbh4_pixels(location)
                counter += 1
            # 返回处理后的标记矩阵
            return self.markers
    
  • 相关阅读:
    webkit 技术内幕 笔记 二
    webkit 技术内幕 笔记 一
    javascript 权威指南1
    正则
    react-virtualized
    移动端字体
    vue 学习3
    vue 学习2
    vue 学习1
    移动端display:flex
  • 原文地址:https://www.cnblogs.com/SimbaWang/p/16388005.html
Copyright © 2020-2023  润新知