使用Python、Numpy和ScikitImage/OpenCV根据流域线的长度合并图像段

2024-06-17 10:32:23 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在研究一种基于分水岭的分割算法来分割荧光图像,例如:

enter image description here

因此,我获得了一个Numpy数组,每个片段都有标签。如果荧光图像中的相应区域之间有足够大的强度衰减,则这些区域由分水岭线分隔。对于非常大的强度衰减,它们通过简单的阈值完全分离。上图的结果如下:

enter image description here

我的算法在绝大多数情况下都表现良好。然而,它有时有一个轻微的倾向,以超期。如上图所示:

enter image description here

由于这些情况很难通过进一步研究基于强度的分割本身来改善(我冒着破坏其他东西的风险),因此我希望根据它们之间的分水岭线的长度以及上面和下面两个分段的平均最大宽度,有选择地合并相邻分段。 我知道在逐像素的基础上我必须做什么:

  1. 查找在其直接邻域中具有两个不同标签值的像素。为每个段对分别存储这些像素(带有相应的段标签)
  2. 计算每对相邻线段的像素数,以获得分水岭线的长度
  3. 计算相邻管段的最大宽度(水平方向为简单起见)
  4. 如果分水岭线长于两段平均宽度的给定阈值分数(用户定义),则合并相邻段。我可以通过将标签转换为二进制掩码,在适用的情况下使用存储的像素填充分水岭线,并重新标记二进制掩码来实现这一点

因为在Python中,在单个像素上迭代通常很慢,所以我不确定如何为此编写性能代码。因此,我正在寻找关于如何使用Numpy和Skimage实现这一点的建议(OpenCV也是一个选项)


Tags: 图像numpy算法区域宽度二进制情况阈值
1条回答
网友
1楼 · 发布于 2024-06-17 10:32:23

你没有提供你是如何得到你最初的部分。尽管如此,我认为改进流域线可以解决您的问题,这可以在流域层次结构框架中通过Higra包实现

我通过图像补码指定分水岭的初始顺序,并使用另一个属性(体积)重新计算其分水岭线

您描述的强度下降和面积是体积属性,您可以通过层次中的阈值来控制分割

这是一个工作示例:

import cv2
import numpy as np
import higra as hg
from skimage.morphology import remove_small_objects, label
import matplotlib.pyplot as plt

def main():
    img_path = "fig.png"
    img = cv2.imread(img_path)
    img = img[:,:,0].copy()
    img = img.max() - img

    size = img.shape[:2]
    graph = hg.get_4_adjacency_graph(size)
    
    edge_weights = hg.weight_graph(graph, img, hg.WeightFunction.mean)
    tree, altitudes = hg.quasi_flat_zone_hierarchy(graph, edge_weights)

    attr = hg.attribute_volume(tree, altitudes)

    saliency = hg.saliency(tree, attr) 
    # Take a look at this :)
    # grid = hg.graph_4_adjacency_2_khalimsky(graph, saliency)
    # plt.imshow(grid)
    # plt.show()
    
    attr_thold = np.mean(saliency) / 4  # arbitrary
    area_thold = 500  # arbitrary 

    segments = hg.labelisation_horizontal_cut_from_threshold(tree, attr, attr_thold)
    segments = label(remove_small_objects(segments, area_thold))

    plt.imshow(segments)
    plt.show()

if __name__ == "__main__":
    main()

这就是结果

Result

相关问题 更多 >