从3d数组中删除图像帧

时间:2012-11-18 13:36:48

标签: python image numpy matplotlib dicom

我是一名新的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()

1 个答案:

答案 0 :(得分:3)

对您的问题的简短回答是使用numpy.delete。 E.g。

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)),而不是每次都创建新图像。

更好的是,使用blitting,但是使用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()