-
Notifications
You must be signed in to change notification settings - Fork 1
/
DeviationFrechet.py
73 lines (56 loc) · 2.71 KB
/
DeviationFrechet.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import math
import vtk
from PythonMetricsCalculator import PerkEvaluatorMetric
class DeviationFrechet( PerkEvaluatorMetric ):
# This metric computes the Frechet distance from the analyzed trajectory to a reference trajectory
# Use dynamic programming to get this to work in "real-time"
# AddTimestamp works in O( n ) time, where n is the number of points in the reference trajectory (which is fixed)
# Based on: Eiter, Thomas; Mannila, Heikki (1994), Computing discrete Fréchet distance (PDF), Tech. Report CD-TR 94/64, Christian Doppler Laboratory for Expert Systems, TU Vienna, Austria.
# Static methods
@staticmethod
def GetMetricName():
return "Deviation from Trajectory - Frechet"
@staticmethod
def GetMetricUnit():
return "mm"
@staticmethod
def GetAnatomyRoles():
return { "Trajectory": "vtkMRMLSequenceNode" }
# Instance methods
def __init__( self ):
PerkEvaluatorMetric.__init__( self )
self.distanceMatrix = []
self.frechetDistance = 0
self.trajectory = None
def SetAnatomy( self, role, node ):
if ( role == "Trajectory" ):
self.trajectory = node
return True
return False
def AddTimestamp( self, time, matrix, point, role ):
if ( self.trajectory is None ):
return
# Build up the matrix
newRow = [ 0 ] * self.trajectory.GetNumberOfDataNodes()
self.distanceMatrix.append( newRow )
i = len( self.distanceMatrix ) - 1
# Use dynamic programming to compute the next row
for j in range( self.trajectory.GetNumberOfDataNodes() ):
currTrajectoryNode = self.trajectory.GetNthDataNode( j )
currTrajectoryMatrix = vtk.vtkMatrix4x4()
currTrajectoryNode.GetMatrixTransformToWorld( currTrajectoryMatrix )
currTrajectoryPoint = [ currTrajectoryMatrix.GetElement( 0, 3 ), currTrajectoryMatrix.GetElement( 1, 3 ), currTrajectoryMatrix.GetElement( 2, 3 ) ]
currDistance = vtk.vtkMath.Distance2BetweenPoints( point[ 0:3 ], currTrajectoryPoint )
if ( i == 0 ):
if ( j == 0 ):
self.distanceMatrix[ i ][ j ] = currDistance
else:
self.distanceMatrix[ i ][ j ] = max( self.distanceMatrix[ i ][ j - 1 ], currDistance )
else:
if ( j == 0 ):
self.distanceMatrix[ i ][ j ] = max( self.distanceMatrix[ i - 1 ][ j ], currDistance )
else:
self.distanceMatrix[ i ][ j ] = max( min( self.distanceMatrix[ i ][ j - 1 ], self.distanceMatrix[ i - 1 ][ j ], self.distanceMatrix[ i - 1 ][ j - 1 ] ), currDistance )
self.frechetDistance = math.sqrt( self.distanceMatrix[ i ][ self.trajectory.GetNumberOfDataNodes() - 1 ] )
def GetMetric( self ):
return self.frechetDistance