我一直在使用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
答案 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
这样您就可以从自定义类中的任何位置访问它!非常基本,但它飞过了我。