python - 使用 Python、Numpy 和 Scikit-Image/OpenCV 根据中间分水线的长度合并图像段
问题描述
我正在研究一种基于分水岭的分割算法来分割荧光图像,例如:
结果,我获得了一个带有每个段标签的 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()
这是结果。
推荐阅读
- sql - 将事实表连接到维度并为每个连接创建新行
- python - QWizard 取消注册已注册的字段
- angular - 平移管道在角度材料对话框中不起作用
- python - 我正在编写我的第一个 Gui 游戏并且遇到了一些小部件问题
- node.js - 部署后从简单的 Node.js Express 应用程序中获取
- json - 如何在 Hashicorp Nomad 中连接前端应用程序和数据库应用程序?
- c# - 在 C# 中获取当月第一周的日期列表
- sonarqube - 是否有 PMD/Checkstyle/Findbugs 到 Sonar 规则映射?
- java - 是否可以在 jre 5 环境中运行的容器实例中部署 jdk 6(或 7)war?
- ruby-on-rails - 使用 Carrierwave 上传图像时不会将字符串隐式转换为哈希