简体   繁体   English

使用 matplotlib 滚动重叠 3D 图像的 2D 切片

[英]Using matplotlib to scroll through 2D slices of overlapping 3D images

I have this piece of code which works perfectly fine for scrolling through 2D slices of a 3D numpy array.我有这段代码,它非常适合滚动 3D numpy 数组的 2D 切片。

import matplotlib.pyplot as plt
import numpy as np


class IndexTracker(object):
    def __init__(self, ax, X):
        self.ax = ax
        ax.set_title('use scroll wheel to navigate images')

        self.X = X
        rows, cols, self.slices = X.shape
        self.ind = self.slices // 2

        self.im = ax.imshow(self.X[:, :, self.ind], cmap="gray")
        self.update()

    def onscroll(self, event):
        print("%s %s" % (event.button, event.step))
        if event.button == 'up':
            self.ind = (self.ind + 1) % self.slices
        else:
            self.ind = (self.ind - 1) % self.slices
        self.update()

    def update(self):
        self.im.set_data(self.X[:, :, self.ind])
        self.ax.set_ylabel('slice %s' % self.ind)
        self.im.axes.figure.canvas.draw()


def plot3d(image):
    fig, ax = plt.subplots(1, 1)
    tracker = IndexTracker(ax, image)
    fig.canvas.mpl_connect('scroll_event', tracker.onscroll)
    plt.show()


if __name__ == "__main__":
    img = np.array([[[0, 0, 0], [0, 1, 0], [0, 0, 0]],
                     [[0, 0, 0], [1, 1, 1], [0, 0, 0]],
                     [[0, 0, 0], [0, 1, 0], [0, 0, 0]]])

    plot3d(img)

I would like to have the same functionality but for scrolling through two, equally sized, 3D numpy arrays at the same.我想拥有相同的功能,但要同时滚动两个大小相同的 3D numpy 数组。 One of the arrays shall be displayed with a certain level of opacity and a different color scheme, so both arrays can be inspected at the same time.其中一个阵列应以一定程度的不透明度和不同的配色方案显示,以便可以同时检查两个阵列。 Without scrolling, for a 2D slice, this can be achieved easily:无需滚动,对于 2D 切片,这可以轻松实现:

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

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

plt.imshow(img1[:, :, 1], cmap="gray")
plt.imshow(img2[:, :, 1], cmap="jet", alpha=0.25)
plt.show()

I tried to extend the IndexTracker class to accept a second 3D array and display one slice of each volume (with the same index) using imshow().我尝试扩展 IndexTracker 类以接受第二个 3D 数组并使用 imshow() 显示每个卷的一个切片(具有相同的索引)。 Also, it was intended to update the displayed images on each scroll event using set_data().此外,它旨在使用 set_data() 更新每个滚动事件上显示的图像。 However, this did not succeed.然而,这并没有成功。

import numpy as np
import matplotlib.pyplot as plt


class IndexTracker(object):
    def __init__(self, ax, X, Y):
        self.ax = ax
        self.X = X
        self.Y = Y
        _, _, self.slices = X.shape
        self.ind = self.slices // 2

        self.im = ax.imshow(self.X[:, :, self.ind], cmap="gray")
        self.im = ax.imshow(self.Y[:, :, self.ind], cmap="jet", alpha=0.25)

        self.update()

    def onscroll(self, event):
        print("%s %s" % (event.button, event.step))
        if event.button == 'up':
            self.ind = (self.ind + 1) % self.slices
        else:
            self.ind = (self.ind - 1) % self.slices
        self.update()

    def update(self):
        self.im.set_data(self.X[:, :, self.ind])
        self.im.set_data(self.Y[:, :, self.ind])

        self.ax.set_ylabel('slice %s' % self.ind)
        self.im.axes.figure.canvas.draw()


def plot3d(image1, image2):
    image1 = np.rot90(image1, k=-1)
    image2 = np.rot90(image2, k=-1)
    fig, ax = plt.subplots(1, 1)
    tracker = IndexTracker(ax, image1, image2)
    fig.canvas.mpl_connect('scroll_event', tracker.onscroll)
    plt.show()


if __name__ == "__main__":
    img1 = np.array([[[0, 0, 0], [0, 1, 0], [0, 0, 0]],
                     [[0, 0, 0], [1, 1, 1], [0, 0, 0]],
                     [[0, 0, 0], [0, 1, 0], [0, 0, 0]]])
    img2 = np.array([[[0, 0, 0], [0, 1, 0], [0, 0, 0]],
                     [[0, 1, 0], [0, 1, 0], [0, 1, 0]],
                     [[0, 0, 0], [0, 1, 0], [0, 0, 0]]])

    plot3d(img1, img2)

Do you have any idea on how to solve the given problem using matplotlib?您对如何使用 matplotlib 解决给定问题有任何想法吗? Ideally by extending the first code snippet containing the IndexTracker class.理想情况下,通过扩展包含 IndexTracker 类的第一个代码片段。

Edit: Added second image as parameter to plot3d() call编辑:将第二张图像作为参数添加到 plot3d() 调用

Happily enough if you keep track of the two Axes.imshow objects (returned by plt.imshow ) separately, then matplotlib will deal with the layering of the images for you.令人高兴的是,如果您分别跟踪两个Axes.imshow对象(由plt.imshow返回),那么 matplotlib 将为您处理图像的分层。 Then you can use set_data on each of these individually.然后,您可以单独对这些中的每一个使用 set_data。 When doing so you need to keep the same colormap and alpha values for each of the images, you can accomplish this using a combination of im.to_rgba and im.get_alpha .这样做时,您需要为每个图像保留相同的颜色图和 alpha 值,您可以使用im.to_rgbaim.get_alpha的组合来完成此操作。 Here are the modifications you need to make to your class for this too work:以下是您需要对您的班级进行的修改,以实现此功能:

class IndexTracker(object):
    def __init__(self, ax, X, Y):
        ...

        self.im1 = ax.imshow(self.X[:, :, self.ind], cmap="gray")
        self.im2 = ax.imshow(self.Y[:, :, self.ind], cmap="jet", alpha=.25)


        ...


    def update(self):
        im1_data = self.im1.to_rgba(self.X[:, :, self.ind], alpha=self.im1.get_alpha())
        im2_data = self.im2.to_rgba(self.Y[:, :, self.ind], alpha=self.im2.get_alpha())

        self.im1.set_data(im1_data)
        self.im2.set_data(im2_data)

        ...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM