Python-эквивалент функции label2idx MATLAB - PullRequest
2 голосов
/ 25 июня 2019

Есть ли какая-либо реализация библиотеки для функции label2idx() в python?

Я хочу извлечь суперпиксели из представления метки в формат, точно возвращаемый функцией label2idx().

Функция label2idx: https://in.mathworks.com/help/images/ref/label2idx.html

Ответы [ 2 ]

3 голосов
/ 25 июня 2019

Учитывая массив меток label_arr, содержащий все метки от 1 до max(label_arr), вы можете сделать:

def label2idx(label_arr):
    return [
        np.where(label_arr.ravel() == i)[0]
        for i in range(1, np.max(label_arr) + 1)]

Если вы хотите ослабить требования ко всем содержащимся ярлыкам, вы можете добавить простой if, т.е.:

def label2idx(label_arr):
    return [
        np.where(label_arr.ravel() == i)[0]
            if i in label_arr else np.array([], dtype=int)
        for i in range(1, np.max(label_arr) + 1)]

Просто повторить пример в документации MATLAB:

import numpy as np
import scipy as sp
import scipy.ndimage

struct_arr = np.array(
    [[1, 1, 1, 0, 0, 0, 0, 0],
     [1, 1, 1, 0, 1, 1, 0, 0],
     [1, 1, 1, 0, 1, 1, 0, 0],
     [1, 1, 1, 0, 0, 0, 0, 0],
     [1, 1, 1, 0, 0, 0, 1, 0],
     [1, 1, 1, 0, 0, 0, 1, 0],
     [1, 1, 1, 0, 0, 1, 1, 0],
     [1, 1, 1, 0, 0, 0, 0, 0]])

label_arr, num_labels = sp.ndimage.label(struct_arr)
# label_arr:
# [[1 1 1 0 0 0 0 0]
#  [1 1 1 0 2 2 0 0]
#  [1 1 1 0 2 2 0 0]
#  [1 1 1 0 0 0 0 0]
#  [1 1 1 0 0 0 3 0]
#  [1 1 1 0 0 0 3 0]
#  [1 1 1 0 0 3 3 0]
#  [1 1 1 0 0 0 0 0]]

def label2idx(label_arr):
    return [
        np.where(label_arr.ravel() == i)[0]
        for i in range(1, np.max(label_arr) + 1)]

pixel_idxs = label2idx(label_arr)

for pixel_idx in pixel_idxs:
    print(pixel_idx)

# [ 0  1  2  8  9 10 16 17 18 24 25 26 32 33 34 40 41 42 48 49 50 56 57 58]
# [12 13 20 21]
# [38 46 53 54]

Обратите внимание, что вы не получите те же результаты из-за различий между MATLAB и NumPy, а именно:

  • MATLAB: матричная индексация в стиле FORTRAN и индексация на основе 1
  • Python + NumPy: индексирование матрицы в стиле C и индексирование на основе 0

и если вы хотите получить те же самые числа, которые вы получаете в MATLAB, вы можете использовать это вместо этого (обратите внимание на дополнительные .T и + 1):

def label2idx_MATLAB(label_arr):
    return [
        np.where(label_arr.T.ravel() == i)[0] + 1
        for i in range(1, np.max(label_arr) + 1)]
2 голосов
/ 25 июня 2019

MATLAB's label2idx выводит уплощенные индексы (упорядоченные по главному столбцу) с учетом помеченного изображения.

Мы можем использовать scikit-image's встроенный regionprops, чтобы получить эти индексы из помеченного изображения. Scikit-image также предоставляет нам встроенный модуль для получения помеченного изображения, так что все работает с тем же пакетом. Реализация будет выглядеть примерно так -

from skimage.measure import label,regionprops

def label2idx(L):
    # Get region-properties for all labels
    props = regionprops(L)

    # Get XY coordinates/indices for each label
    indices = [p.coords for p in props]

    # Get flattened-indices for each label, similar to MATLAB version
    # Note that this is row-major ordered.
    flattened_indices = [np.ravel_multi_index(idx.T,L.shape) for idx in indices]
    return indices, flattened_indices

Пробный прогон -

# Input array
In [62]: a
Out[62]: 
array([[1, 1, 1, 0, 0, 0, 0, 0],
       [1, 1, 1, 0, 1, 1, 0, 0],
       [1, 1, 1, 0, 1, 1, 0, 0],
       [1, 1, 1, 0, 0, 0, 0, 0],
       [1, 1, 1, 0, 0, 0, 1, 0],
       [1, 1, 1, 0, 0, 0, 1, 0],
       [1, 1, 1, 0, 0, 1, 1, 0],
       [1, 1, 1, 0, 0, 0, 0, 0]])

# Get labeled image
In [63]: L = label(a)

In [64]: idx,flat_idx = label2idx(L)

In [65]: flat_idx
Out[65]: 
[array([ 0,  1,  2,  8,  9, 10, 16, 17, 18, 24, 25, 26, 32, 33, 34, 40, 41,
        42, 48, 49, 50, 56, 57, 58]),
 array([12, 13, 20, 21]),
 array([38, 46, 53, 54])]

Если вам нужны индексы в главном порядке столбцов, как в MATLAB, просто транспонируйте изображение, а затем введите -

In [5]: idx,flat_idx = label2idx(L.T)

In [6]: flat_idx
Out[6]: 
[array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
        17, 18, 19, 20, 21, 22, 23]),
 array([33, 34, 41, 42]),
 array([46, 52, 53, 54])]

Обратите внимание, что индексирование по-прежнему начинается с 0, в отличие от MATLAB, где оно 1.

Альтернатива получению помеченного изображения с помощью SciPy

В SciPy также есть встроенное изображение для маркировки: scipy.ndimage.label -

from scipy.ndimage import label

L = label(a)[0]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...