如何使用vtk选择线中的点?

问题描述 投票:1回答:1

在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_())

我的代码怎么了?任何建议表示赞赏!另外,如何在表面上选取点?

python pyqt vtk
1个回答
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中。

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.