Объедините сегменты изображения в зависимости от длины водораздела между ними, используя Python, Numpy и Scikit-Image / OpenCV - PullRequest
1 голос
/ 14 июля 2020

Я работаю над алгоритмом сегментации на основе водораздела, чтобы сегментировать флуоресцентные изображения, такие как это:

enter image description here

As result I obtain a Numpy array with labels for each segment. These are separated by a watershed lines, if the corresponding regions in the fluorescence image have a sufficiently large intensity-drop-off between them. For very large intensity-drop-offs they are completely separated through simple thresholding. The result for the image above is this:

enter image description here

My algorithm performs well for the vast majority of cases. However, it sometimes it has a slight tendency to oversegment. Such as in this case from the image above:

введите описание изображения здесь

Поскольку эти случаи будет трудно улучшить, продолжая работать над самой сегментацией на основе интенсивности (и я рискую нарушить другие вещи), я хочу вместо этого выборочно объединить соседние сегменты на основе длина водораздела между ними и усредненная максимальная ширина двух сегментов вверху и внизу. Я знаю, что мне нужно делать для каждого пикселя:

  1. Найти пиксели, которые имеют два разных значений метки в непосредственной близости. Сохраните эти пиксели отдельно для каждой пары сегментов (с соответствующими метками сегментов).
  2. Вычислите количество этих пикселей для каждой пары смежных сегментов, чтобы получить длину водораздела.
  3. Рассчитайте максимальную ширину (для простоты по горизонтали) соседних сегментов.
  4. Объедините смежные сегменты, если линия водораздела длиннее заданной пороговой доли (определяемой пользователем) усредненной ширины два сегмента. Я мог бы сделать это, преобразовав метки в двоичную маску, заполнив линию водораздела с использованием сохраненных пикселей, где это применимо, и перемаркировав двоичную маску. медленно, я не уверен, как написать для этого эффективный код. Поэтому я ищу предложения о том, как реализовать это с помощью Numpy и Skimage (OpenCV также является вариантом).

1 Ответ

0 голосов
/ 14 июля 2020

Вы не указали, как вы получили свои начальные сегменты. Несмотря на это, я думаю, что улучшение линий водоразделов может решить вашу проблему, и это можно сделать в структуре иерархии водоразделов с помощью пакета 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()

Вот результат.

Результат

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...