Как создать 4- или 8-связную матрицу смежности

Я искал реализацию Python, которая возвращает матрицу смежности с 4 или 8 связями, заданную массивом. Я нахожу удивительным, что cv2 или networkx не включают эту функцию. Я наткнулся на эту замечательную реализацию Matlab и решил сделать что-то подобное на Python.

Проблема: я ищу реализацию, которая улучшит связанное решение Matlab в среде выполнения / пространстве ИЛИ других интересных подходах.

Заявление об ограничении ответственности:

Я представляю здесь свою собственную реализацию, так как полагаю, что я не могу быть единственным человеком, которому когда-либо понадобится создать (4/8 связную) матрицу смежности для обработки изображений или других приложений. Я надеюсь, что будут предложены улучшения или лучшие реализации.


person Scott    schedule 12.05.2015    source источник


Ответы (1)


Используя диагональную структуру, как подробно описано в этом ответе относительно «Построить матрицу смежности в MATLAB», я создаю только верхние диагонали и добавьте их в соответствующие позиции в разреженную диагональную матрицу, используя scipy.sparse.diags. Эта разреженная матрица добавляется к транспонированной, чтобы получить матрицу смежности.

При работе с изображениями часто бывает желательно разбить изображение на неперекрывающиеся прямоугольные фрагменты изображения или участки. Параметр patch_size - это кортеж (rows, cols), который описывает прямоугольный патч размером «rows x cols».

import numpy as np
import scipy.sparse as s

def connected_adjacency(image, connect, patch_size=(1, 1)):
    """
    Creates an adjacency matrix from an image where nodes are considered adjacent 
    based on 4-connected or 8-connected pixel neighborhoods.

    :param image: 2 or 3 dim array
    :param connect: string, either '4' or '8'
    :param patch_size: tuple (n,m) used if the image will be decomposed into 
                   contiguous, non-overlapping patches of size n x m. The 
                   adjacency matrix will be formed from the smaller sized array
                   e.g. original image size = 256 x 256, patch_size=(8, 8), 
                   then the image under consideration is of size 32 x 32 and 
                   the adjacency matrix will be of size 
                   32**2 x 32**2 = 1024 x 1024
    :return: adjacency matrix as a sparse matrix (type=scipy.sparse.csr.csr_matrix)
    """

    r, c = image.shape[:2]

    r = r / patch_size[0]
    c = c / patch_size[1]

    if connect == '4':
        # constructed from 2 diagonals above the main diagonal
        d1 = np.tile(np.append(np.ones(c-1), [0]), r)[:-1]
        d2 = np.ones(c*(r-1))
        upper_diags = s.diags([d1, d2], [1, c])
        return upper_diags + upper_diags.T

    elif connect == '8':
        # constructed from 4 diagonals above the main diagonal
        d1 = np.tile(np.append(np.ones(c-1), [0]), r)[:-1]
        d2 = np.append([0], d1[:c*(r-1)])
        d3 = np.ones(c*(r-1))
        d4 = d2[1:-1]
        upper_diags = s.diags([d1, d2, d3, d4], [1, c-1, c, c+1])
        return upper_diags + upper_diags.T
    else:
        raise ValueError('Invalid parameter \'connect\'={connect}, must be "4" or "8".'
                     .format(connect=repr(connect)))

Простой пример:

a = np.arange(9).reshape((3, 3))
adj = connected_adjacency(a, '4').toarray()
print a

[[0 1 2]
 [3 4 5]
 [6 7 8]]

print adj

[[ 0.  1.  0.  1.  0.  0.  0.  0.  0.]
 [ 1.  0.  1.  0.  1.  0.  0.  0.  0.]
 [ 0.  1.  0.  0.  0.  1.  0.  0.  0.]
 [ 1.  0.  0.  0.  1.  0.  1.  0.  0.]
 [ 0.  1.  0.  1.  0.  1.  0.  1.  0.]
 [ 0.  0.  1.  0.  1.  0.  0.  0.  1.]
 [ 0.  0.  0.  1.  0.  0.  0.  1.  0.]
 [ 0.  0.  0.  0.  1.  0.  1.  0.  1.]
 [ 0.  0.  0.  0.  0.  1.  0.  1.  0.]]

Использование networkx + matplotlib для построения матрицы смежности в виде графика: введите здесь описание изображения

person Scott    schedule 12.05.2015
comment
Как насчет того, чтобы показать код, который создает этот график и эту конкретную схему маркировки? - person FaCoffee; 29.05.2017
comment
@FaCoffee Я полагаю, что использовал ответ в нижней части моего сообщения на stackoverflow.com/a/29574114/4663466. Он использует networkx networkx.github.io. - person Scott; 30.05.2017