vtkRenderWindowInteractor拖延程序

时间:2014-06-27 16:09:22

标签: python multithreading listener render vtk

我一直在使用Python开发一个原型应用程序,用于使用VTK对3D模型进行立体成像,但是我在接口端遇到了一些问题。目前,下面的代码的目标是在按下middlemouse时放大两个renderWindows。但是,在调用vtkRenderWindowInteractor.Start()函数时,我的vtkRenderWindowInteractor有效地拖延了整个程序,就像它们在同一个线程中运行一样。更奇怪的是,当我使用CTRL-C(我在UNIX shell中工作)时,不会抛出键盘中断,直到我使用' x'手动关闭渲染窗口。按钮。如果我只是手动关闭窗口而不按CTRL-C,程序会在Start()调用后直接选中(例如在下面的代码中,无限循环)。我在这篇文章的最后提供了一系列的屏幕截图,以便在我的解释令人困惑的情况下准确地看到发生了什么。

我已经尝试了多种解决方法来解决这个问题但到目前为止还没有成功。将渲染线程渲染到隔离线程中即使我尝试使用ncurses进行输入也没有任何区别,同时将它们分配给新进程会导致一些我不愿意处理的操作系统问题。我刚才使用内置VTK监听器的最新交互器样式方法(如下所示)在某种程度上工作,允许我在窗口处于焦点并且交互器处于活动状态时检测输入,但由于缺少关联相机和MyInteractorStyle课程,Start()通话后,我无法在没有包含循环的情况下访问摄像机,这会让我回到我开始的地方。

有什么想法?我只是误解了VTK的渲染工具应该如何使用?

from vtk import*
import os.path
#import thread
#import time
#import threading 
#import curses

class MyInteractorStyle(vtk.vtkInteractorStyleTrackballCamera):

        pos1 = [0, 0, 200]
        foc1 = [0, 0, 0]
        pos2 = [40, 0, 200]
        foc2 = [0, 0, 0]

        def __init__(self,parent=None):
                self.AddObserver("MiddleButtonPressEvent", self.middleButtonPressEvent)
                self.AddObserver("MiddleButtonReleaseEvent", self.middleButtonReleaseEvent)
        def middleButtonPressEvent(self,obj,event):
                print "Middle button pressed"
                self.pos1[2] += 10
                self.pos2[2] += 30
                self.OnMiddleButtonDown()
                return
        def middleButtonReleaseEvent(self,obj,event):
                print "Middle button released"
                self.OnMiddleButtonUp()
                return
def main():


        # create two cameras
        camera1 = vtkCamera()
        camera1.SetPosition(0,0,200)
        camera1.SetFocalPoint(0,0,0)

        camera2 = vtkCamera()
        camera2.SetPosition(40,0,200)
        camera2.SetFocalPoint(0,0,0)


        # create a rendering window and renderer
        ren1 = vtkRenderer()
        ren1.SetActiveCamera(camera1)

        ren2 = vtkRenderer()
        ren2.SetActiveCamera(camera2)

        # create source
        reader = vtkPolyDataReader()
        path = "/home/compilezone/Documents/3DSlicer/SlicerScenes/LegoModel-6_25/Model_5_blood.vtk"
        reader.SetFileName(path)
        print(path)
        reader.Update()

        # create render window

        renWin1 = vtkRenderWindow()
        renWin1.AddRenderer(ren1)

        renWin2 = vtkRenderWindow()
        renWin2.AddRenderer(ren2)

        # create a render window interactor

        inputHandler = MyInteractorStyle()

        iren1 = vtkRenderWindowInteractor()
        iren1.SetRenderWindow(renWin1)
        iren1.SetInteractorStyle(inputHandler)

        iren2 = vtkRenderWindowInteractor()
        iren2.SetRenderWindow(renWin2)
        iren2.SetInteractorStyle(inputHandler)

        # mapper
        mapper = vtkPolyDataMapper()
        mapper.SetInput(reader.GetOutput())

        # actor
        actor = vtkActor()
        actor.SetMapper(mapper)

        # assign actor to the renderer
        ren1.AddActor(actor)
        ren2.AddActor(actor)

        # enable user interface interactor
        iren1.Initialize()
        iren2.Initialize()
        renWin1.Render()
        renWin2.Render()
        iren1.Start()
        iren2.Start()
        print "Test"
        while 1:
                pos1 = iren1.GetInteractorStyle().pos1
                foc1 = iren1.GetInteractorStyle().foc1
                pos2 = iren2.GetInteractorStyle().pos2
                foc2 = iren2.GetInteractorStyle().foc2
                print     

if __name__ == '__main__':
        main()  

程序正在运行 KeyboardInterrupt(CTRL-C命中并在终端中回显但没有任何反应) 手动关闭渲染窗口,抛出KeyboardInterrupt

2 个答案:

答案 0 :(得分:2)

在RenderWindowInteractor上调用Start()启动执行渲染事件所必需的事件循环,就像GUI中的事件循环一样。所以你要做的事情,开始两个事件循环,并没有多大意义。

概念性解决方法是不在RenderWindowInteractors上调用Start,而是编写一个包含多个特定于工具包的RenderWindowInteractors的小GUI,并使用该GUI的事件循环。

作为示例,这里是如何使用tvtk的wxVtkRenderWindowInteractor类中的GUI工具包特定代码完成的,该类不在RenderWindowInteractor上调用start,而是使用GUI的事件循环来管理事件:

def wxVTKRenderWindowInteractorConeExample():
 """Like it says, just a simple example
 """
 # every wx app needs an app
 app = wx.PySimpleApp()

 # create the top-level frame, sizer and wxVTKRWI
 frame = wx.Frame(None, -1, "wxVTKRenderWindowInteractor", size=(400,400))
 widget = wxVTKRenderWindowInteractor(frame, -1)
 sizer = wx.BoxSizer(wx.VERTICAL)
 sizer.Add(widget, 1, wx.EXPAND)
 frame.SetSizer(sizer)
 frame.Layout()

 # It would be more correct (API-wise) to call widget.Initialize() and
 # widget.Start() here, but Initialize() calls RenderWindow.Render().
 # That Render() call will get through before we can setup the
 # RenderWindow() to render via the wxWidgets-created context; this
 # causes flashing on some platforms and downright breaks things on
 # other platforms.  Instead, we call widget.Enable().  This means
 # that the RWI::Initialized ivar is not set, but in THIS SPECIFIC CASE,
 # that doesn't matter.
 widget.Enable(1)

 widget.AddObserver("ExitEvent", lambda o,e,f=frame: f.Close())

 ren = vtk.vtkRenderer()
 widget.GetRenderWindow().AddRenderer(ren)

 cone = vtk.vtkConeSource()
 cone.SetResolution(8)

 coneMapper = vtk.vtkPolyDataMapper()
 coneMapper.SetInput(cone.GetOutput())

 coneActor = vtk.vtkActor()
 coneActor.SetMapper(coneMapper)

 ren.AddActor(coneActor)

 # show the window
 frame.Show()

 app.MainLoop()

(请注意,此代码不会改变,并且与您尝试执行的操作有明显区别。)

此外,ctrl + C不起作用的原因是因为VTK事件循环对此事件没有任何作用。一些GUI确实尊重这个事件,包括wxpython。但是如果您没有使用尊重此事件的GUI(例如,Qt),您可以手动告诉python解释器拦截此事件并崩溃,而不是将事件转发到GUI事件循环:

import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)

答案 1 :(得分:1)

对于碰巧遇到这种问题的人,同样的问题是无法操纵vtkInteractorStyle课程中的相机,请查看Dolly()Pan(),{{1} },Spin()Rotate()Zoom()。所有这些都可以让您从您使用的UniformScale()子类中访问相机。祝你好运!

编辑:更好的是,只需将相机连接到继承自vtkInteractorStyle作为属性的类,例如:

vtkInteractorStyle

这样您就可以从自定义类中的任何位置访问它!非常基本,但它飞过了我。