VTK: не удается отобразить окно с помощью многопоточности

#vtk

Вопрос:

Мне нужно отрисовывать три окна vtk одновременно, и общее время составляет 0,11 с. Я хочу ускорить этот процесс.

Я хочу отобразить три окна с помощью многопоточности.

Мой код таков:

 
from PyQt5.QtWidgets import *
from vtk.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
import sys, vtk
from vtk.util.numpy_support import numpy_to_vtk
import numpy as np
import time
import _thread, threading
def numpyToVTK(data, multi_component=False, type='float'):
    '''
    multi_components: 比如rgb就是多component的,有3个通道,而gray图只有一个通道
    type:数据类型,比如mask转为vtkImageData的时候,就可以用char类型,默认是float
    '''
    if type == 'float':
        data_type = vtk.VTK_FLOAT
    elif type == 'char':
        data_type = vtk.VTK_UNSIGNED_CHAR
    else:
        raise RuntimeError('unknown type')
    if multi_component == False:
        if len(data.shape) == 2:
            data = data[:, :, np.newaxis]
        flat_data_array = data.transpose(2,1,0).flatten()
        vtk_data = numpy_to_vtk(num_array=flat_data_array, deep=True, array_type=data_type)
        shape = data.shape
    else:
        assert len(data.shape) == 3, 'only test for 2D RGB'
        flat_data_array = data.transpose(1, 0, 2)
        flat_data_array = np.reshape(flat_data_array, newshape=[-1, data.shape[2]])
        vtk_data = numpy_to_vtk(num_array=flat_data_array, deep=True, array_type=data_type)
        shape = [data.shape[0], data.shape[1], 1]
    img = vtk.vtkImageData()
    img.GetPointData().SetScalars(vtk_data)
    img.SetDimensions(shape[0], shape[1], shape[2])
    return img

class VTKWidget(QVTKRenderWindowInteractor):

    def __init__(self, setWindowLevel, render):
        super().__init__()
        self.lastPoint = None
        self.press = False
        self.setWindowLevel = setWindowLevel
        self.render = render
        img = np.zeros(shape=[256, 256])
        for i in range(256):
            for j in range(256):
                img[i, j] = i j
        imgActor = vtk.vtkImageSlice()
        imgMapper = vtk.vtkImageSliceMapper()
        self.windowLevel = vtk.vtkImageMapToWindowLevelColors()
        self.windowLevel.SetInputData(numpyToVTK(img))
        imgMapper.SetInputConnection(self.windowLevel.GetOutputPort())
        imgActor.SetMapper(imgMapper)
        render = vtk.vtkRenderer()
        render.AddActor(imgActor)
        self.GetRenderWindow().AddRenderer(render)
        interactor = self.GetRenderWindow().GetInteractor()
        interactor.RemoveAllObservers()
        self.GetRenderWindow().Render()

    def mouseMoveEvent(self, ev):
        super().mouseMoveEvent(ev)
        pos = [ev.pos().x(), ev.pos().y()]
        if self.press:
            if self.lastPoint is not None:
                dx = pos[0] - self.lastPoint[0]
                dy = pos[1] - self.lastPoint[1]
                window = self.windowLevel.GetWindow()
                level = self.windowLevel.GetLevel()
                self.setWindowLevel(window dx, level dy)
                self.render()
            self.lastPoint = pos

    def updateWindowLevel(self, window, level):
        self.windowLevel.SetLevel(level)
        self.windowLevel.SetWindow(window)

    def Render(self):
        self.GetRenderWindow().Render()

    def mousePressEvent(self, ev):
        super().mousePressEvent(ev)
        self.press = True

    def mouseReleaseEvent(self, ev):
        super().mouseReleaseEvent(ev)
        self.press = False
        self.lastPoint = None

    def closeEvent(self, evt):
        self.Finalize()
        super().closeEvent()

class RenderThread(threading.Thread):
    def __init__(self, func):
        super().__init__()
        self.func = func
    def run(self) -> None:
        self.func()

class Window(QFrame):

    def __init__(self):
        super().__init__()

        layout = QHBoxLayout()
        self.setLayout(layout)

        self.vtkWidget1 = VTKWidget(setWindowLevel=self.setWindowLevel, render=self.render)
        self.vtkWidget2 = VTKWidget(setWindowLevel=self.setWindowLevel, render=self.render)
        self.vtkWidget3 = VTKWidget(setWindowLevel=self.setWindowLevel, render=self.render)

        layout.addWidget(self.vtkWidget1)
        layout.addWidget(self.vtkWidget2)
        layout.addWidget(self.vtkWidget3)

    def setWindowLevel(self, window, level):
        self.vtkWidget1.updateWindowLevel(window=window, level=level)
        self.vtkWidget2.updateWindowLevel(window=window, level=level)
        self.vtkWidget3.updateWindowLevel(window=window, level=level)

    def render(self):
        start = time.time()
        # --------------------------------------------------------------------------------------
        # original data
        self.vtkWidget1.Render()
        self.vtkWidget2.Render()
        self.vtkWidget3.Render()
        # --------------------------------------------------------------------------------------
        ## thread method 1
        # _thread.start_new_thread(self.vtkWidget1.Render, ())
        # _thread.start_new_thread(self.vtkWidget2.Render, ())
        # _thread.start_new_thread(self.vtkWidget3.Render, ())
        # --------------------------------------------------------------------------------------
        ## thread method 2
        # thread1 = RenderThread(func=self.vtkWidget1.Render)
        # thread2 = RenderThread(func=self.vtkWidget2.Render)
        # thread3 = RenderThread(func=self.vtkWidget3.Render)
        #
        # thread1.start()
        # thread2.start()
        # thread3.start()
        # thread1.join()
        # thread2.join()
        # thread3.join()

        end = time.time()
        print('render time: ', end-start)

if __name__ == '__main__':

    app = QApplication(sys.argv)
    win = Window()
    win.show()
    app.exec_()
 

Среда моего компьютера-это:

 win 10
python 3.7
vtk 8.1.2
CPU: i7-9700K 3.60GHz
 

На моем компьютере отрисовка трех окон заняла около 0,12 секунды:

     self.vtkWidget1.Render()
    self.vtkWidget2.Render()
    self.vtkWidget3.Render()
 

Но, если я хочу использовать многопоточность:

     _thread.start_new_thread(self.vtkWidget1.Render, ())
    _thread.start_new_thread(self.vtkWidget2.Render, ())
    _thread.start_new_thread(self.vtkWidget3.Render, ())
 

Или:

     thread1 = RenderThread(func=self.vtkWidget1.Render)
    thread2 = RenderThread(func=self.vtkWidget2.Render)
    thread3 = RenderThread(func=self.vtkWidget3.Render)

    thread1.start()
    thread2.start()
    thread3.start()
    thread1.join()
    thread2.join()
    thread3.join()
 

Приложение работает неправильно.

Мне нужна помощь для:

  1. как использовать многопоточность для Render() .
  2. как ускорить Render()

Любое предложение приветствуется~~~