在VTK中,我有一个曲面和一条线,并且该线包含在该曲面中。然后,我需要在直线上选择一个点。我实现了自己的交互器,并通过右键单击获得世界坐标。我希望选择点可以位于直线上。释放右键时,我在渲染器中显示选定的行。但是,我发现无法在直线上选择一个点。我的代码是:
import vtk, os, sys
import numpy as np
from PyQt5.QtWidgets import *
from vtk.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
from vtk.util.numpy_support import vtk_to_numpy, numpy_to_vtk
def numpyToVtk(data, type=vtk.VTK_FLOAT):
flat_data_array = data.transpose(2,1,0).flatten()
vtk_data_array = numpy_to_vtk(flat_data_array)
vtk_data = numpy_to_vtk(num_array=vtk_data_array, deep=True, array_type=type)
img = vtk.vtkImageData()
img.GetPointData().SetScalars(vtk_data)
img.SetDimensions(data.shape)
img.SetOrigin(0, 0, 0)
img.SetSpacing(1, 1, 1)
return img
class ourInteractor(vtk.vtkInteractorStyleTrackballCamera):
def __init__(self, renderer=None, renWindow=None):
super(ourInteractor, self).__init__()
self.AddObserver("RightButtonReleaseEvent", self.OnRightButtonUp)
self.ren = renderer
self.renWin = renWindow
def OnRightButtonUp(self, obj, event):
super(ourInteractor, self).OnRightButtonUp()
pos = self.GetInteractor().GetEventPosition()
coordinate = vtk.vtkCoordinate()
coordinate.SetCoordinateSystemToDisplay()
coordinate.SetValue(pos[0], pos[1], 0)
worldCoor = coordinate.GetComputedWorldValue(
self.GetInteractor().GetRenderWindow().GetRenderers().GetFirstRenderer())
print('screen coor: ', pos, 'world coor: ', worldCoor)
points = vtk.vtkPoints()
vertices = vtk.vtkCellArray()
id = points.InsertNextPoint(worldCoor[0], worldCoor[1], worldCoor[2])
vertices.InsertNextCell(1)
vertices.InsertCellPoint(id)
point = vtk.vtkPolyData()
point.SetPoints(points)
point.SetVerts(vertices)
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputData(point)
actor = vtk.vtkActor()
actor.SetMapper(mapper)
actor.GetProperty().SetPointSize(10)
actor.GetProperty().SetColor(0, 1, 0)
self.ren.AddActor(actor)
self.renWin.Render()
class AirwaySkeleton(QMainWindow):
def __init__(self, parent=None):
super(AirwaySkeleton, self).__init__(parent=parent)
self.setWindowTitle("Airway Skeleton")
widget = QWidget()
self.setCentralWidget(widget)
layout = QHBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
widget.setLayout(layout)
self.mainLayout = layout
frame = QFrame()
vtkWidget = QVTKRenderWindowInteractor(frame)
self.mainLayout.addWidget(vtkWidget)
ren = vtk.vtkRenderer()
vtkWidget.GetRenderWindow().AddRenderer(ren)
iren = vtkWidget.GetRenderWindow().GetInteractor()
style = ourInteractor(renderer=ren, renWindow=vtkWidget.GetRenderWindow())
iren.SetInteractorStyle(style)
ren.SetBackground(0, 0, 0)
self.ren = ren
mask = np.zeros(shape=[200, 200, 200], dtype=np.uint8)
mask[20:80, 50:150, 50:150] = 1
mask[80:150, 80:120, 80:120] = 1
mask[150:170, 50:150, 50:150] = 1
xs = np.arange(20, 170, 0.1)
line = []
for x in xs:
line.append([x, 100, 100])
actors = self.createActorsForLines([np.array(line)])
vtkMask = numpyToVtk(data=mask, type=vtk.VTK_CHAR)
mesh = self.maskToMesh(vtkMask)
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(mesh.GetOutputPort())
mapper.ScalarVisibilityOff()
actor = vtk.vtkLODActor()
actor.SetMapper(mapper)
actor.GetProperty().SetColor(1, 1, 1)
actor.GetProperty().SetOpacity(0.4)
self.ren.AddActor(actor)
for lineActor in actors:
self.ren.AddActor(lineActor)
self.renWin = vtkWidget.GetRenderWindow()
iren.Initialize()
self.iren = iren
def maskToMesh(self, mask):
contour = vtk.vtkDiscreteMarchingCubes()
contour.SetInputData(mask)
contour.SetValue(0, 1)
contour.Update()
smoother = vtk.vtkWindowedSincPolyDataFilter()
smoother.SetInputConnection(contour.GetOutputPort())
smoother.SetNumberOfIterations(30)
smoother.BoundarySmoothingOff()
smoother.NonManifoldSmoothingOn()
smoother.NormalizeCoordinatesOn()
smoother.Update()
triangleCellNormals = vtk.vtkPolyDataNormals()
triangleCellNormals.SetInputConnection(smoother.GetOutputPort())
triangleCellNormals.ComputeCellNormalsOn()
triangleCellNormals.ComputePointNormalsOff()
triangleCellNormals.ConsistencyOn()
triangleCellNormals.AutoOrientNormalsOn()
triangleCellNormals.Update()
return triangleCellNormals
def createActorsForLines(self, lines):
actors = []
endPoints = vtk.vtkPoints()
for line in lines:
n = line.shape[0]
endPoints.InsertNextPoint(line[0, 0], line[0, 1], line[0, 2])
endPoints.InsertNextPoint(line[-1, 0], line[-1, 1], line[-1, 2])
points = vtk.vtkPoints()
vtkLines = vtk.vtkCellArray()
vtkLines.InsertNextCell(n)
for i in range(n):
points.InsertNextPoint(line[i, 0], line[i, 1], line[i, 2])
vtkLines.InsertCellPoint(i)
polygonPolyData = vtk.vtkPolyData()
polygonPolyData.SetPoints(points)
polygonPolyData.SetLines(vtkLines)
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputData(polygonPolyData)
actor = vtk.vtkActor()
actor.SetMapper(mapper)
actor.GetProperty().SetColor(1, 0, 0)
actors.append(actor)
polyData = vtk.vtkPolyData()
polyData.SetPoints(endPoints)
sphereSource = vtk.vtkSphereSource()
sphereSource.SetRadius(1)
glyph3D = vtk.vtkGlyph3D()
glyph3D.SetSourceConnection(sphereSource.GetOutputPort())
glyph3D.SetInputData(polyData)
glyph3D.Update()
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(glyph3D.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
actor.GetProperty().SetColor(0, 0, 1)
actors.append(actor)
return actors
if __name__ == '__main__':
app = QApplication(sys.argv)
window = AirwaySkeleton()
window.show()
sys.exit(app.exec_())
我的代码有什么问题?任何建议表示赞赏! 另外,我该如何在曲面上拾取点?
答案 0 :(得分:0)
使用vtkplotter的解决方案很简单:
from vtkplotter import *
import numpy as np
mask = np.zeros(shape=[200,200,200], dtype=np.uint8)
mask[ 20:80, 50:150, 50:150] = 1
mask[ 80:150, 80:120, 80:120] = 1
mask[150:170, 50:150, 50:150] = 1
vol = Volume(mask) # returns vtkVolume
iso = vol.isosurface(threshold=1).c('grey').alpha(0.3).pickable(0)
smoothed_iso = iso.smoothLaplacian(niter=30)
aline = Line((20,100,100), (170,100,100), lw=10) # vtkActor
def onLeftClick(mesh):
printc("clicked 3D point:", mesh.picked3d, c='red')
vp.add(Sphere(pos=mesh.picked3d, r=2, c="green"))
vp = Plotter(verbose=0, axes=8, bg='black')
vp.mouseLeftClickFunction = onLeftClick
vp.show(smoothed_iso, aline)
可以在示例here下使用嵌入到Qt中。