23
23
iflogger = logging .getLogger ('interface' )
24
24
25
25
26
- class P2PDistanceInputSpec (BaseInterfaceInputSpec ):
26
+ class ComputeMeshWarpInputSpec (BaseInterfaceInputSpec ):
27
27
surface1 = File (exists = True , mandatory = True ,
28
- desc = (" Reference surface (vtk format) to which compute "
29
- " distance." ))
28
+ desc = (' Reference surface (vtk format) to which compute '
29
+ ' distance.' ))
30
30
surface2 = File (exists = True , mandatory = True ,
31
- desc = ("Test surface (vtk format) from which compute "
32
- "distance." ))
31
+ desc = ('Test surface (vtk format) from which compute '
32
+ 'distance.' ))
33
+ metric = traits .Enum ('euclidean' , 'sqeuclidean' , usedefault = True ,
34
+ desc = ('norm used to report distance' ))
33
35
weighting = traits .Enum (
34
- "none" , "area" , usedefault = True ,
35
- desc = ('"none": no weighting is performed, "area": vertex distances are'
36
- 'weighted by the total area of faces corresponding to the '
37
- 'vertex' ))
36
+ 'none' , 'area' , usedefault = True ,
37
+ desc = ('"none": no weighting is performed, surface": edge distance is '
38
+ 'weighted by the corresponding surface area' ))
39
+ out_warp = File ('surfwarp.vtk' , usedefault = True ,
40
+ desc = 'vtk file based on surface1 and warpings mapping it '
41
+ 'to surface2' )
38
42
out_file = File ('distance.npy' , usedefault = True ,
39
43
desc = 'numpy file keeping computed distances and weights' )
40
44
41
45
42
- class P2PDistanceOutputSpec (TraitedSpec ):
46
+ class ComputeMeshWarpOutputSpec (TraitedSpec ):
43
47
distance = traits .Float (desc = "computed distance" )
48
+ out_warp = File (exists = True , desc = ('vtk file with the vertex-wise '
49
+ 'mapping of surface1 to surface2' ))
44
50
out_file = File (exists = True ,
45
51
desc = 'numpy file keeping computed distances and weights' )
46
52
47
53
48
- class P2PDistance (BaseInterface ):
54
+ class ComputeMeshWarp (BaseInterface ):
49
55
50
- """Calculates a point-to-point (p2p) distance between two corresponding
51
- VTK-readable meshes or contours.
56
+ """
57
+ Calculates a the vertex-wise warping to get surface2 from surface1.
58
+ It also reports the average distance of vertices, using the norm specified
59
+ as input.
60
+
61
+ .. warning:
62
+
63
+ A point-to-point correspondence between surfaces is required
52
64
53
- A point-to-point correspondence between nodes is required
54
65
55
66
Example
56
67
-------
57
68
58
69
>>> import nipype.algorithms.mesh as mesh
59
- >>> dist = mesh.P2PDistance ()
70
+ >>> dist = mesh.ComputeMeshWarp ()
60
71
>>> dist.inputs.surface1 = 'surf1.vtk'
61
72
>>> dist.inputs.surface2 = 'surf2.vtk'
62
73
>>> res = dist.run() # doctest: +SKIP
74
+
63
75
"""
64
76
65
- input_spec = P2PDistanceInputSpec
66
- output_spec = P2PDistanceOutputSpec
77
+ input_spec = ComputeMeshWarpInputSpec
78
+ output_spec = ComputeMeshWarpOutputSpec
67
79
68
80
def _triangle_area (self , A , B , C ):
69
81
ABxAC = euclidean (A , B ) * euclidean (A , C )
@@ -73,10 +85,11 @@ def _triangle_area(self, A, B, C):
73
85
return area
74
86
75
87
def _run_interface (self , runtime ):
88
+ from numpy import linalg as nla
76
89
try :
77
- from tvtk .api import tvtk
90
+ from tvtk .api import tvtk , write_data
78
91
except ImportError :
79
- raise ImportError ('Interface P2PDistance requires tvtk' )
92
+ raise ImportError ('Interface ComputeMeshWarp requires tvtk' )
80
93
81
94
try :
82
95
from enthought .etsconfig .api import ETSConfig
@@ -99,9 +112,13 @@ def _run_interface(self, runtime):
99
112
points1 = np .array (vtk1 .points )
100
113
points2 = np .array (vtk2 .points )
101
114
102
- diff = np . linalg . norm ( points1 - points2 , axis = 1 )
115
+ diff = points2 - points1
103
116
weights = np .ones (len (diff ))
104
117
118
+ errvector = nla .norm (diff , axis = 1 )
119
+ if self .inputs .metric == 'sqeuclidean' :
120
+ errvector = errvector ** 2
121
+
105
122
if (self .inputs .weighting == 'area' ):
106
123
faces = vtk1 .polys .to_array ().reshape (- 1 , 4 ).astype (int )[:, 1 :]
107
124
@@ -117,14 +134,40 @@ def _run_interface(self, runtime):
117
134
w += self ._triangle_area (fp1 , fp2 , fp3 )
118
135
weights [i ] = w
119
136
120
- result = np .vstack ([diff , weights ])
137
+ result = np .vstack ([errvector , weights ])
121
138
np .save (op .abspath (self .inputs .out_file ), result .transpose ())
122
139
123
- self ._distance = np .average (diff , weights = weights )
140
+ out_mesh = tvtk .PolyData ()
141
+ out_mesh .points = vtk1 .points
142
+ out_mesh .polys = vtk1 .polys
143
+ out_mesh .point_data .warpings = [tuple (d ) for d in diff ]
144
+
145
+ write_data (out_mesh , op .abspath (self .inputs .out_warp ))
146
+
147
+ self ._distance = np .average (errvector , weights = weights )
124
148
return runtime
125
149
126
150
def _list_outputs (self ):
127
151
outputs = self ._outputs ().get ()
128
152
outputs ['out_file' ] = op .abspath (self .inputs .out_file )
129
153
outputs ['distance' ] = self ._distance
130
154
return outputs
155
+
156
+
157
+ class P2PDistance (ComputeMeshWarp ):
158
+
159
+ """
160
+ Calculates a point-to-point (p2p) distance between two corresponding
161
+ VTK-readable meshes or contours.
162
+
163
+ A point-to-point correspondence between nodes is required
164
+
165
+ .. deprecated:: 1.0-dev
166
+ Use :py:class:`ComputeMeshWarp` instead.
167
+ """
168
+
169
+ def __init__ (self , ** inputs ):
170
+ super (P2PDistance , self ).__init__ (** inputs )
171
+ warnings .warn (("This interface has been deprecated since 1.0,"
172
+ " please use nipype.algorithms.metrics.Distance" ),
173
+ DeprecationWarning )
0 commit comments