Commit ce45b5b7 authored by Matt Clarkson's avatar Matt Clarkson

Merge branch '14-fiducial-registration-error-computation' into 'master'

Resolve "Move Fiducial Registration Error computation"

Closes #14

See merge request WEISS/SoftwareRepositories/SNAPPY/scikit-surgerycore!12
parents efe762bb 98b6ac4e
# -*- coding: utf-8 -*-
"""Functions for point based registration using Orthogonal Procrustes."""
import numpy as np
def validate_procrustes_inputs(fixed, moving):
"""
Validates the fixed and moving set of points
1. fixed and moving must be numpy array
2. fixed and moving should have 3 columns
3. fixed and moving should have at least 3 rows
4. fixed and moving should have the same number of rows
:param fixed: point set, N x 3 ndarray
:param moving: point set, N x 3 ndarray of corresponding points
:returns: nothing
:raises: TypeError, ValueError
"""
if not isinstance(fixed, np.ndarray):
raise TypeError("fixed is not a numpy array'")
if not isinstance(moving, np.ndarray):
raise TypeError("moving is not a numpy array")
if not fixed.shape[1] == 3: # pylint: disable=literal-comparison
raise ValueError("fixed should have 3 columns")
if not moving.shape[1] == 3: # pylint: disable=literal-comparison
raise ValueError("moving should have 3 columns")
if fixed.shape[0] < 3:
raise ValueError("fixed should have at least 3 points (rows)")
if moving.shape[0] < 3:
raise ValueError("moving should have at least 3 points (rows)")
if not fixed.shape[0] == moving.shape[0]:
raise ValueError("fixed and moving should have "
+ "the same number of points (rows)")
def compute_fre(fixed, moving, rotation, translation):
"""
Computes the Fiducial Registration Error, equal
to the root mean squared error between corresponding fiducials.
:param fixed: point set, N x 3 ndarray
:param moving: point set, N x 3 ndarray of corresponding points
:param rotation: 3 x 3 ndarray
:param translation: 3 x 1 ndarray
:returns: Fiducial Registration Error (FRE)
"""
# pylint: disable=assignment-from-no-return
validate_procrustes_inputs(fixed, moving)
transformed_moving = np.matmul(rotation, moving.transpose()) + translation
squared_error_elementwise = np.square(fixed
- transformed_moving.transpose())
square_distance_error = np.sum(squared_error_elementwise, 1)
sum_squared_error = np.sum(square_distance_error, 0)
mean_squared_error = sum_squared_error / fixed.shape[0]
fre = np.sqrt(mean_squared_error)
return fre
......@@ -3,70 +3,13 @@
"""Functions for point based registration using Orthogonal Procrustes."""
import numpy as np
from sksurgerycore.algorithms.errors \
import validate_procrustes_inputs, compute_fre
def validate_procrustes_inputs(fixed, moving):
"""
Validates the fixed and moving set of points
1. fixed and moving must be numpy array
2. fixed and moving should have 3 columns
3. fixed and moving should have at least 3 rows
4. fixed and moving should have the same number of rows
:param fixed: point set, N x 3 ndarray
:param moving: point set, N x 3 ndarray of corresponding points
:returns: nothing
:raises: TypeError, ValueError
"""
if not isinstance(fixed, np.ndarray):
raise TypeError("fixed is not a numpy array'")
if not isinstance(moving, np.ndarray):
raise TypeError("moving is not a numpy array")
if not fixed.shape[1] == 3: # pylint: disable=literal-comparison
raise ValueError("fixed should have 3 columns")
if not moving.shape[1] == 3: # pylint: disable=literal-comparison
raise ValueError("moving should have 3 columns")
if fixed.shape[0] < 3:
raise ValueError("fixed should have at least 3 points (rows)")
if moving.shape[0] < 3:
raise ValueError("moving should have at least 3 points (rows)")
if not fixed.shape[0] == moving.shape[0]:
raise ValueError("fixed and moving should have "
+ "the same number of points (rows)")
def compute_fre(fixed, moving, rotation, translation):
"""
Computes the Fiducial Registration Error, equal
to the root mean squared error between corresponding fiducials.
:param fixed: point set, N x 3 ndarray
:param moving: point set, N x 3 ndarray of corresponding points
:param rotation: 3 x 3 ndarray
:param translation: 3 x 1 ndarray
:returns: Fiducial Registration Error (FRE)
"""
# pylint: disable=assignment-from-no-return
validate_procrustes_inputs(fixed, moving)
transformed_moving = np.matmul(rotation, moving.transpose()) + translation
squared_error_elementwise = np.square(fixed
- transformed_moving.transpose())
square_distance_error = np.sum(squared_error_elementwise, 1)
sum_squared_error = np.sum(square_distance_error, 0)
mean_squared_error = sum_squared_error / fixed.shape[0]
fre = np.sqrt(mean_squared_error)
return fre
# pylint: disable=invalid-name, line-too-long
# pylint: disable=invalid-name, line-too-long
def orthogonal_procrustes(fixed, moving):
"""
Implements point based registration via the Orthogonal Procrustes method.
......@@ -123,7 +66,7 @@ def orthogonal_procrustes(fixed, moving):
raise ValueError("Registration fails as determinant < 0"
" and no singular values are close enough to zero")
if det_X < 0 and (np.any(np.isclose(svd[1], np.zeros((3, 1))))):
if det_X < 0 and np.any(np.isclose(svd[1], np.zeros((3, 1)))):
# Implement 2a in section VI in Arun paper.
v_prime = svd[2].transpose()
......
# -*- coding: utf-8 -*-
import six
import numpy as np
import pytest
import sksurgerycore.algorithms.errors as e
def test_empty_fixed():
with pytest.raises(TypeError):
e.compute_fre(None, None, np.ones(1, 3), np.ones(3, 3))
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment