我正在研究一种基于分水岭的分割算法来分割荧光图像,例如:
结果,我获得了一个带有每个段标签的 Numpy 数组。如果荧光图像中的相应区域在它们之间具有足够大的强度下降,则它们由分水岭线分隔。对于非常大的强度下降,它们通过简单的阈值完全分离。上图的结果是这样的:
我的算法在绝大多数情况下都表现良好。但是,有时它有轻微的过度分割趋势。例如上图中的这种情况:
由于这些情况很难通过进一步处理基于强度的分割本身来改进(并且我冒着破坏其他东西的风险),我想根据它们之间的分水线的长度有选择地合并相邻的片段和上下两段的平均最大宽度。
我知道我必须逐个像素地做些什么:
由于在 Python 中迭代单个像素通常很慢,我不确定如何为此编写高性能代码。因此,我正在寻找有关如何使用 Numpy 和 Skimage 实现此功能的建议(OpenCV 也是一种选择)。
最佳答案
您没有提供如何获得初始分割。尽管如此,我认为改进分水岭线可以解决您的问题,这可以在分水岭层次结构框架中完成,使用 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()
这是结果。关于python - 使用 Python、Numpy 和 Scikit-Image/OpenCV 根据中间分水线的长度合并图像段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62896061/