Удалить кадр изображения из 3D-массива

Я новый пользователь Python и хотел бы выполнить простую обработку изображений. По сути, у меня будет динамическое медицинское изображение — серия 2D-изображений в разные моменты времени, которые я хотел бы сохранить в виде 3D-массива. Из-за характера метода сканирования во время определенных кадров изображения пациент может время от времени двигаться, что делает данные непригодными для использования. Я хотел бы удалить такие кадры и переделать массив - новые размеры (n-1, 256, 256). После удаления кадра я хотел бы обновить отображение изображения. Как лучше всего достичь этой цели? Вот код скелета, который у меня есть до сих пор:

import dicom
import numpy as np
import pylab 
from matplotlib.widgets import Slider, Button

ds = dicom.read_file("/home/moadeep/Dropbox/FS1.dcm")
#data = ds.pixel_array
data = np.random.rand(16,256,256)
nframes = data.shape[0]

ax = pylab.subplot(111)
pylab.subplots_adjust(left=0.25, bottom=0.25)

frame = 0
l = pylab.imshow(data[frame,:,:]) #shows 1024x256 imagge, i.e. 0th frame*

axcolor = 'lightgoldenrodyellow'
axframe = pylab.axes([0.35, 0.1, 0.5, 0.03], axisbg=axcolor)

#add slider to scroll image frames
sframe = Slider(axframe, 'Frame', 0, nframes, valinit=0,valfmt='%1d'+'/'+str(nframes))

ax_delete = pylab.axes([0.8,0.025,0.1,0.04], axisbg=axcolor)

#add slider to scroll image frames

#Delete button to delete frame from data set
bDelete = Button(ax_delete, 'Delete')

def update(val):
    frame = np.around(sframe.val)
    pylab.subplot(111)
    pylab.subplots_adjust(left=0.25, bottom=0.25)
    pylab.imshow(data[frame,:,:])

sframe.on_changed(update)

pylab.gray()
pylab.show()

person moadeep    schedule 18.11.2012    source источник


Ответы (1)


Короткий ответ на ваш вопрос: используйте numpy.delete. Например.

import numpy as np
data = np.arange(1000).reshape((10,10,10))

# Delete the third slice along the first axis 
# (note that you can delete multiple slices at once)
data = np.delete(data, [2], axis=0)

print data.shape

Однако это плохой подход, если вы собираетесь многократно удалять отдельные фрагменты.

Более длинный ответ заключается в том, чтобы не делать этого каждый раз, когда вы хотите удалить фрагмент.

Массивы Numpy должны быть непрерывными в памяти. Таким образом, каждый раз будет создаваться новая копия (и удаляться старая). Это будет относительно медленно и потребует, чтобы у вас было вдвое больше свободного места в памяти, необходимого для хранения массива.

В вашем случае, почему бы не сохранить список 2D-массивов Python? Таким образом, вы можете без проблем вытолкнуть ненужные фрагменты. Если впоследствии вам понадобится 3D-массив, просто используйте numpy.dstack для его создания.

Конечно, если вам нужно выполнить 3D-обработку, вам понадобится 3D-массив. Следовательно, другим подходом было бы сохранение списка "плохих" индикаторов и удаление их в конце с помощью numpy.delete (обратите внимание, что удаляемые элементы представляют собой список, поэтому вы можете просто передать свой список "плохих" индикаторов).


Кстати, способ обновления изображения будет очень медленным.

Вы создаете много изображений, поэтому каждое из них будет перерисовываться каждый раз, и обновление будет очень медленным по мере продвижения.

Вам лучше установить данные изображения (im.set_data(next_slice)), а не создавать каждый раз новое изображение.

Еще лучше использовать блиттинг, но с данными изображения в matplotlib это не так выгодно, как для других типов графиков, из-за медленного масштабирования изображений в matplotlib.

В качестве быстрого примера:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider

def main():
    # Set up 3D coordinates from -10 to 10 over a 200x100x100 "open" grid
    x, y, z = np.ogrid[-10:10:200j, -10:10:100j, -10:10:100j]

    # Generate a cube of interesting data
    data= np.sin(x*y*z) / (x*y*z)

    # Visualize it
    viewer = VolumeViewer(data)
    viewer.show()

class VolumeViewer(object):
    def __init__(self, data):
        self.data = data
        self.nframes = self.data.shape[0]

        # Setup the axes.
        self.fig, self.ax = plt.subplots()
        self.slider_ax = self.fig.add_axes([0.2, 0.03, 0.65, 0.03])

        # Make the slider
        self.slider = Slider(self.slider_ax, 'Frame', 1, self.nframes, 
                            valinit=1, valfmt='%1d/{}'.format(self.nframes))
        self.slider.on_changed(self.update)

        # Plot the first slice of the image
        self.im = self.ax.imshow(data[0,:,:])

    def update(self, value):
        frame = int(np.round(value - 1))

        # Update the image data
        dat = self.data[frame,:,:]
        self.im.set_data(dat)

        # Reset the image scaling bounds (this may not be necessary for you)
        self.im.set_clim([dat.min(), dat.max()])

        # Redraw the plot
        self.fig.canvas.draw()

    def show(self):
        plt.show()

if __name__ == '__main__':
    main()
person Joe Kington    schedule 18.11.2012
comment
Спасибо за вашу помощь. Список 2D-массивов звучит как разумное решение. - person moadeep; 18.11.2012