2012-03-01 4 views
2

Я пытаюсь создать список всех перекрывающихся подмассивов равного размера из большего 3D-массива (для сегментации на основе патчей), где каждый подмассив должен быть сплющен (как 1D-вектор), поэтому я могу использовать шаровую дерево в sklearn.neighbours.BallTree.Numpy - создание перекрывающихся 3D-подмассивов в качестве эффективных векторов

Так, например, при изображении 100x100x100, если бы я разбил это на 5x5x5 перекрывающихся патчей (subarrays), у меня было бы 96x96x96 = 884,736 из них.

Однако я не нашел никакого способа сделать это без numpy, выделяя больше памяти для каждого сплющенного/векторизованного подмассива. Кажется, это связано с тем, что каждый подмассив не является непрерывным в памяти.

например. Для изображения 100x100x100, если я хочу, чтобы каждый патч 5x5x5 был 1D-вектором (длиной 125), numpy решает выделить новый массив в памяти для всех 884 736 из них, который затем становится довольно большим, особенно если я хочу работать с более чем одно изображение 100x100x100!

Я бы приветствовал любые решения для преодоления этой проблемы памяти в python/numpy. Я рассматривал возможность создания подкласса объекта numpy.ndarray, который хранит указатель на расположение патча на большем изображении и возвращает данные в виде массива 1D numpy только при вызове (и после этого он снова удаляется, если не используется) но я не встречал достаточно подробностей о подклассе объектов ndarray для этого. Я буду очень разочарован, если единственным решением будет реализовать все на C/C++. Я ценю любую помощь, которая может быть предоставлена, спасибо!

+0

Наличие векторизованных данных изображений также необходимо для использования kdtree в scipy слишком – Zehan

ответ

1

Основываясь на вашем вопросе, вы, возможно, уже знаете обо всем этом. Тем не менее, я отправляю этот «ответ», как больше обсуждаю, что это за проблемы, потому что многие люди могут не знать о них ....

Если вы, однако, не можете сделать 96x96x96x5x5x5 массив из изображения 100x100x100, который действует как движущееся окно 5x5x5 без выделения дополнительной памяти.

Однако, поскольку вы можете иметь только один шаг на размер, нет возможности изменить его в массив 96x96x96x125, не делая копии.

Во всяком случае, вот пример (в основном взяты straight from one of my previous answers):

import numpy as np 

def rolling_window_lastaxis(a, window): 
    """Directly taken from Erik Rigtorp's post to numpy-discussion. 
    <http://www.mail-archive.com/[email protected]/msg29450.html>""" 
    if window < 1: 
     raise ValueError, "`window` must be at least 1." 
    if window > a.shape[-1]: 
     raise ValueError, "`window` is too long." 
    shape = a.shape[:-1] + (a.shape[-1] - window + 1, window) 
    strides = a.strides + (a.strides[-1],) 
    return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides) 

def rolling_window(a, window): 
    """Takes a numpy array *a* and a sequence of (or single) *window* lengths 
    and returns a view of *a* that represents a moving window.""" 
    if not hasattr(window, '__iter__'): 
     return rolling_window_lastaxis(a, window) 
    for i, win in enumerate(window): 
     if win > 1: 
      a = a.swapaxes(i, -1) 
      a = rolling_window_lastaxis(a, win) 
      a = a.swapaxes(-2, i) 
    return a 

x = np.zeros((100,100,100), dtype=np.uint8) 
y = rolling_window(x, (5,5,5)) 
print 'Now *y* will be a 96x96x96x5x5x5 array...' 
print y.shape 
print 'Representing a "rolling window" into *x*...' 
y[0,0,0,...] = 1 
y[1,1,0,...] = 2 
print x[:10,:10,0] # Note that *x* and *y* share the same memory! 

Это дает:

Now *y* will be a 96x96x96x5x5x5 array... 
(96, 96, 96, 5, 5, 5) 
Representing a "rolling window" into *x*... 
[[1 1 1 1 1 0 0 0 0 0] 
[1 2 2 2 2 2 0 0 0 0] 
[1 2 2 2 2 2 0 0 0 0] 
[1 2 2 2 2 2 0 0 0 0] 
[1 2 2 2 2 2 0 0 0 0] 
[0 2 2 2 2 2 0 0 0 0] 
[0 0 0 0 0 0 0 0 0 0] 
[0 0 0 0 0 0 0 0 0 0] 
[0 0 0 0 0 0 0 0 0 0] 
[0 0 0 0 0 0 0 0 0 0]] 

Однако, как вы уже отметили, что мы не можем изменить это 96x96x96x125 без создания копии. y.shape = (96,96,96,-1) поднимет ошибку, и z = y.reshape((96,96,96,-1)) будет работать, но вернет копию.

(Соответствующая документация находится в numpy.reshape, если это кажется запутанным. В основном reshape позволит избежать копирования, когда это возможно, и возвращает копию, если его нет, в то время как установка атрибута shape вызовет ошибку при копировании не представляется возможным.)

Однако, даже если вы построите более эффективный контейнер массива, sklearn.neighbors.BallTree почти наверняка сделает временные промежуточные копии.

Вы упомянули, что вы выполняете сегментацию изображения. Почему бы вам не искать более эффективный алгоритм, чем «грубая сила», которую вы пытаетесь? (Или, если это невозможно, дайте нам несколько подробностей о том, почему ... Может быть, у кого-то будет лучшая идея?)

+0

Этот подход для сегментации на основе патчей основан на методе, описанном здесь [http://www.sciencedirect.com/science/article/pii/S1053811910011997), который, как было показано, дает лучшие результаты, чем другие «более эффективные» алгоритмы сегментации. Однако я хочу поэкспериментировать с этой идеей в более широком масштабе, но при использовании python/numpy я запрещаю требования к памяти. Было бы хорошо, если бы вокруг этого не обойтись без необходимости повторного внедрения материала. – Zehan

Смежные вопросы