Script repository 译:脚本存储库
Note 译:注意
Usage: Copy-paste the code lines displayed below or the linked .py
file contents into Python console in Slicer. Or save them to a .py
file and run them using execfile
. 译:**用法::将下面显示的代码行或链接的.py
文件内容复制粘贴到Slicer中的Python控制台中。或者将它们保存到.py
文件中,然后使用execfile
运行它们。
译者的几点说明:
- 今天开始学习这一章,包括每段代码的结果,我是用JupyterLab操作的,相应的
.ipynb
我会放到下载区 - 主要感兴趣的内容,重点分析
- 最近在做一个有关医学影像3d重建经皮定位的项目,希望有大神合作.
Markups 译: 标记
Load markups fiducial list from file 译:从文件加载标记Fiducial列表
Markups fiducials can be loaded from file: 译:标记Fiducial可以从文件中加载:
slicer.util.loadMarkupsFiducialList("data/F.fcsv")
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
In [3]:
Line 1:
File /Applications/Slicer.app/Contents/bin/Python/slicer/util.py, in loadMarkupsFiducialList:
Line 746: node = loadMarkups(filename)
File /Applications/Slicer.app/Contents/bin/Python/slicer/util.py, in loadMarkups:
Line 771: return loadNodeFromFile(filename, 'MarkupsFile')
File /Applications/Slicer.app/Contents/bin/Python/slicer/util.py, in loadNodeFromFile:
Line 650: raise RuntimeError(errorMessage)
RuntimeError: Failed to load node from file: data/F.fcsv
---------------------------------------------------------------------------
- ✎✎✎ :
新版的文件为下面这个格式mrk.json
,用fcsv
出错
slicer.util.loadMarkupsFiducialList("data/F.mrk.json")
[True, (vtkSlicerMarkupsModuleMRMLPython.vtkMRMLMarkupsFiducialNode)0x16f2ecd68]
Adding Fiducials Programatically 译: 以编程方式添加Fiducial
Markups fiducials can be added to the currently active list from the python console by using the following module logic command: 译:使用以下模块逻辑命令,可以从python控制台将标记Fiducial点添加到当前活动列表中:
slicer.modules.markups.logic().AddFiducial() # 默认原点加到F
The command with no arguments will place a new fiducial at the origin. You can also pass it an initial location: 译:不带参数的命令将在原点放置一个新Fiducial。您还可以将其传递给初始位置:
slicer.modules.markups.logic().AddFiducial(1.0, -2.0, 3.3)
0
- ✎✎✎ :
如何加到指定的列表中
我们将上面那个点加到F-1列表中
加到F里了可是标签却:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Qg4zHqMa-1620137485954)(attachment:4e9a83d1-f414-463a-8fcc-bc4aa9aa05a9.png)]
知道为啥吗?
# 译者代码
fixedLRS = slicer.util.getNode('F')
fixedLRS.AddFiducial(-100.0, 0.0, 0.0)
fixedLRS.SetNthFiducialLabel(0, 'FixedL')
How to draw a curve using control points stored in a numpy array 译: 如何使用存储在numpy数组中的控制点绘制曲线
# Create random numpy array to use as input 译:创建随机的numpy数组以用作输入
import numpy as np
pointPositions = np.random.uniform(-50,50,size=[15,3])
# Create curve from numpy array 译:从numpy数组创建曲线
curveNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLMarkupsCurveNode")
slicer.util.updateMarkupsControlPointsFromArray(curveNode, pointPositions)
- ✎✎✎ :
Add a button to module GUI to activate fiducial placement 译:向模块GUI添加按钮以激活Fiducial放置
This code snippet creates a toggle button, which activates fiducial placement when pressed (and deactivates when released). 译:此代码段创建一个切换按钮,按下该按钮可激活Fiducial位置(释放时将其禁用)。
The qSlicerMarkupsPlaceWidget widget can automatically activate placement of multiple points and can show buttons for deleting points, changing colors, lock, and hide points. 译:[qSlicerMarkupsPlaceWidget小部件](http://apidocs.slicer.org/master/classqSlicerMarkupsPlaceWidget.html)可以自动激活多个点的放置,并可以显示用于删除点,更改颜色,锁定和隐藏点的按钮。
w=slicer.qSlicerMarkupsPlaceWidget()
w.setMRMLScene(slicer.mrmlScene)
markupsNodeID = slicer.modules.markups.logic().AddNewFiducialNode()
w.setCurrentNode(slicer.mrmlScene.GetNodeByID(markupsNodeID))
# Hide all buttons and only show place button 译:隐藏所有按钮,仅显示位置按钮
w.buttonsVisible=False
w.placeButton().show()
w.show()
- ✎✎✎ :
如图
Adding Fiducials via mouse clicks 译: 通过鼠标单击添加Fiducial
You can also set the mouse mode into Markups fiducial placement by calling: 译:您还可以通过调用以下命令将鼠标模式设置为标记Fiducial位置:
placeModePersistence = 1
slicer.modules.markups.logic().StartPlaceMode(placeModePersistence)
A lower level way to do this is via the selection and interaction nodes: 译:一种较低级别的方法是通过选择和交互节点:
selectionNode = slicer.mrmlScene.GetNodeByID("vtkMRMLSelectionNodeSingleton")
selectionNode.SetReferenceActivePlaceNodeClassName("vtkMRMLMarkupsFiducialNode")
interactionNode = slicer.mrmlScene.GetNodeByID("vtkMRMLInteractionNodeSingleton")
placeModePersistence = 1
interactionNode.SetPlaceModePersistence(placeModePersistence)
# mode 1 is Place, can also be accessed via slicer.vtkMRMLInteractionNode().Place 译:模式1为Place,也可以通过slicer.vtkMRMLInteractionNode()访问。
interactionNode.SetCurrentInteractionMode(1)
To switch back to view transform once you’re done placing fiducials: 译:完成Fiducial放置后,要切换回视图转换:
interactionNode = slicer.mrmlScene.GetNodeByID("vtkMRMLInteractionNodeSingleton")
interactionNode.SwitchToViewTransformMode()
# also turn off place mode persistence if required 译:如果需要,还可以关闭场所模式持久性
interactionNode.SetPlaceModePersistence(0)
Access to Fiducial Properties 译:访问Fiducial属性
Each vtkMRMLMarkupsFiducialNode has a vector of points in it which can be accessed from python: 译:每个vtkMRMLMarkupsFiducialNode中都有一个点矢量,可以从python访问这些点:
fidNode = getNode("vtkMRMLMarkupsFiducialNode1")
n = fidNode.AddFiducial(4.0, 5.5, -6.0)
fidNode.SetNthFiducialLabel(n, "new label")
# each markup is given a unique id which can be accessed from the superclass level 译:每个标记都有一个唯一的ID,可以从超类级别访问
id1 = fidNode.GetNthMarkupID(n)
# manually set the position 译:手动设置位置
fidNode.SetNthFiducialPosition(n, 6.0, 7.0, 8.0)
# set the label 译:设置标签
fidNode.SetNthFiducialLabel(n, "New label")
# set the selected flag, only selected = 1 fiducials will be passed to CLIs 译:设置选定的标志,只有选定的= 1个Fiducial将被传递到CLI
fidNode.SetNthFiducialSelected(n, 1)
# set the visibility flag 译:设置可见性标志
fidNode.SetNthFiducialVisibility(n, 0)
- ✎✎✎ :
这组代码比我前面的👍太多…
You can loop over the fiducials in a list and get the coordinates: 译:您可以遍历列表中的Fiducial并获取坐标:
fidList = slicer.util.getNode("F")
numFids = fidList.GetNumberOfFiducials()
for i in range(numFids):
ras = [0,0,0]
fidList.GetNthFiducialPosition(i,ras)
# the world position is the RAS position with any transform matrices applied
world = [0,0,0,0]
fidList.GetNthFiducialWorldCoordinates(0,world)
print(i,": RAS =",ras,", world =",world)
0 : RAS = [-75.94607190857545, -37.56009742901087, -2.1938657726656743] , world = [-75.94607190857545, -37.56009742901087, -2.1938657726656743, 0.0]
1 : RAS = [14.155074704408154, -75.46471772966771, -2.194670949981628] , world = [-75.94607190857545, -37.56009742901087, -2.1938657726656743, 0.0]
2 : RAS = [-95.76510768417384, 85.85852034072332, -2.19344815423176] , world = [-75.94607190857545, -37.56009742901087, -2.1938657726656743, 0.0]
3 : RAS = [-81.11312212763353, -96.62529981603525, -2.1939475814752427] , world = [-75.94607190857545, -37.56009742901087, -2.1938657726656743, 0.0]
4 : RAS = [124.01467571038447, 129.81447702084876, -2.195127093658982] , world = [-75.94607190857545, -37.56009742901087, -2.1938657726656743, 0.0]
- ✎✎✎ :
0 : RAS = [-75.94607190857545, -37.56009742901087, -2.1938657726656743] , world = [-75.94607190857545, -37.56009742901087, -2.1938657726656743, 0.0]
1 : RAS = [14.155074704408154, -75.46471772966771, -2.194670949981628] , world = [-75.94607190857545, -37.56009742901087, -2.1938657726656743, 0.0]
2 : RAS = [-95.76510768417384, 85.85852034072332, -2.19344815423176] , world = [-75.94607190857545, -37.56009742901087, -2.1938657726656743, 0.0]
3 : RAS = [-81.11312212763353, -96.62529981603525, -2.1939475814752427] , world = [-75.94607190857545, -37.56009742901087, -2.1938657726656743, 0.0]
4 : RAS = [124.01467571038447, 129.81447702084876, -2.195127093658982] , world = [-75.94607190857545, -37.56009742901087, -2.1938657726656743, 0.0]
比较一下坐标系的差别…
You can also look at the sample code in the Endoscopy module to see how python is used to access fiducials from a scripted module. 译:您还可以查看[内窥镜模块]中的示例代码(https://github.com/Slicer/Slicer/blob/master/Modules/Scripted/Endoscopy/Endoscopy.pyL287)以查看python的运行方式用于从脚本模块访问Fiducial。
Define/edit a circular region of interest in a slice viewer 译:在Slicer查看器中定义/编辑感兴趣的圆形区域
Drop two markup points on a slice view and copy-paste the code below into the Python console. After this, as you move the markups you’ll see a circle following the markups. 译:在Slicer视图上放置两个标记点,然后将以下代码复制粘贴到Python控制台中。此后,当您移动标记时,标记后面会出现一个圆圈。
# Update the sphere from the fiducial points 译:从Fiducial点更新球体
def UpdateSphere(param1, param2):
"""Update the sphere from the fiducial points
"""
import math
centerPointCoord = [0.0, 0.0, 0.0]
markups.GetNthFiducialPosition(0,centerPointCoord)
circumferencePointCoord = [0.0, 0.0, 0.0]
markups.GetNthFiducialPosition(1,circumferencePointCoord)
sphere.SetCenter(centerPointCoord)
radius=math.sqrt((centerPointCoord[0]-circumferencePointCoord[0])**2+(centerPointCoord[1]-circumferencePointCoord[1])**2+(centerPointCoord[2]-circumferencePointCoord[2])**2)
sphere.SetRadius(radius)
sphere.SetPhiResolution(30)
sphere.SetThetaResolution(30)
sphere.Update()
# Get markup node from scene 译:从场景中获取标记节点
markups=slicer.util.getNode("F")
sphere = vtk.vtkSphereSource()
UpdateSphere(0,0)
# Create model node and add to scene 译:创建模型节点并添加到场景
modelsLogic = slicer.modules.models.logic()
model = modelsLogic.AddModel(sphere.GetOutput())
model.GetDisplayNode().SetSliceIntersectionVisibility(True)
model.GetDisplayNode().SetSliceIntersectionThickness(3)
model.GetDisplayNode().SetColor(1,1,0)
# Call UpdateSphere whenever the fiducials are changed 译:每当Fiducial点更改时调用UpdateSphere
markups.AddObserver(slicer.vtkMRMLMarkupsNode.PointModifiedEvent, UpdateSphere, 2)
178
- ✎✎✎ :
Specify a sphere by multiple of markups points 译:通过多个标记点指定一个球体
Drop multiple markup points at the boundary of the spherical object and and copy-paste the code below into the Python console to get best-fit sphere. Minimum 4 points are required, it is recommended to place the points far from each other for most accurate fit. 译:在球形对象的边界处放置多个标记点,然后将以下代码复制粘贴到Python控制台中,以获得最合适的球形。至少需要4个点,建议将这些点彼此分开以实现最精确的拟合。
# Get markup node from scene 译:从场景中获取标记节点
markups = slicer.util.getNode("F")
from scipy.optimize import least_squares
import numpy
def fit_sphere_least_squares(x_values, y_values, z_values, initial_parameters, bounds=((-numpy.inf, -numpy.inf, -numpy.inf, -numpy.inf),(numpy.inf, numpy.inf, numpy.inf, numpy.inf))):
"""
Source: https://github.com/thompson318/scikit-surgery-sphere-fitting/blob/master/sksurgeryspherefitting/algorithms/sphere_fitting.py
Uses scipy's least squares optimisor to fit a sphere to a set
of 3D Points
:return: x: an array containing the four fitted parameters
:return: ier: int An integer flag. If it is equal to 1, 2, 3 or 4, the
solution was found.
:param: (x,y,z) three arrays of equal length containing the x, y, and z
coordinates.
:param: an array containing four initial values (centre, and radius)
"""
return least_squares(_calculate_residual_sphere, initial_parameters, bounds=bounds, method="trf", jac="3-point", args=(x_values, y_values, z_values))
def _calculate_residual_sphere(parameters, x_values, y_values, z_values):
"""
Source: https://github.com/thompson318/scikit-surgery-sphere-fitting/blob/master/sksurgeryspherefitting/algorithms/sphere_fitting.py
Calculates the residual error for an x,y,z coordinates, fitted
to a sphere with centre and radius defined by the parameters tuple
:return: The residual error
:param: A tuple of the parameters to be optimised, should contain [x_centre, y_centre, z_centre, radius]
:param: arrays containing the x,y, and z coordinates.
"""
#extract the parameters
x_centre, y_centre, z_centre, radius = parameters
#use numpy's sqrt function here, which works by element on arrays
distance_from_centre = numpy.sqrt((x_values - x_centre)**2 + (y_values - y_centre)**2 + (z_values - z_centre)**2)
return distance_from_centre - radius
# Fit a sphere to the markups fidicual points 译:使球形适应标记的折点
markupsPositions = slicer.util.arrayFromMarkupsControlPoints(markups)
import numpy as np
# initial guess 译:初步猜测
center0 = np.mean(markupsPositions, 0)
radius0 = np.linalg.norm(np.amin(markupsPositions,0)-np.amax(markupsPositions,0))/2.0
fittingResult = fit_sphere_least_squares(markupsPositions[:,0], markupsPositions[:,1], markupsPositions[:,2], [center0[0], center0[1], center0[2], radius0])
[centerX, centerY, centerZ, radius] = fittingResult["x"]
# Create a sphere using the fitted parameters 译:使用拟合的参数创建一个球体
sphere = vtk.vtkSphereSource()
sphere.SetPhiResolution(30)
sphere.SetThetaResolution(30)
sphere.SetCenter(centerX, centerY, centerZ)
sphere.SetRadius(radius)
sphere.Update()
# Add the sphere to the scene 译:将球体添加到场景
modelsLogic = slicer.modules.models.logic()
model = modelsLogic.AddModel(sphere.GetOutput())
model.GetDisplayNode().SetSliceIntersectionVisibility(True)
model.GetDisplayNode().SetSliceIntersectionThickness(3)
model.GetDisplayNode().SetColor(1,1,0)
- ✎✎✎ :
参阅: 翻译:Slicer脚本存储库
<未完待续>