Commit 3e9f9cb0 by Stephen Thompson

### Issue #1 implemted unit test and fixed style errors

parent 97393a03
Pipeline #2165 passed with stages
in 20 minutes and 8 seconds
 ... ... @@ -3,3 +3,4 @@ # confused with the software requirements, which are listed in # doc/requirements.rst numpy scipy
 # coding=utf-8 """ Module for fitting a sphere to a list of 3D points """ #let's use scipy's least squares optimisor #scipy has a nice least squares optimisor from scipy.optimize import leastsq from math import sqrt import numpy def CalculateResidual(parameters, x, y , z): """ Calculates the residual error for an x,y,z coordinates :return The residual error :param A tuple of the parameters to be optimised, should contain [x_centre, y_centre, z_centre, radius] :the x,y, and z coordinates. """ #extract the parameters x_centre, y_centre, z_centre, radius = parameters print (x_centre, y_centre, z_centre, radius) #distance_from_centre = sqrt( (x-x_centre)**2 + (y-y_centre)**2 + (z-z_centre)**2 ) distance_from_centre = numpy.sqrt((x-x_centre)**2 + (y-y_centre)**2 + (z-z_centre)**2) error = distance_from_centre - radius return error def FitSphere_LeastSquares(x, y, z): def fit_sphere_least_squares(x_values, y_values, z_values, initial_parameters): """ Uses scipy's least squares optimisor to fit a sphere to a set Uses scipy's least squares optimisor to fit a sphere to a set of 3D Points :return The fitted sphere parameters, x, y, z, and radius and the residual error :param three lists of equal length containing the x, y, and z coordinates. """ #initialise the parameters parameters=[0.0, 0.0, 0.0, 0.0] result = leastsq (CalculateResidual, parameters, args=(x,y,z)) return result from random import uniform if __name__ == "__main__": x_centre = 1.0 y_centre = 167.0 z_centre = 200.0 radius = 7.5 xs=numpy.ndarray(shape=(1000,),dtype=float ) ys=numpy.ndarray(shape=(1000,),dtype=float ) zs=numpy.ndarray(shape=(1000,),dtype=float ) #xs=numpy.zeros((1,10)) #ys=numpy.zeros((1,10)) #zs=numpy.zeros((1,10)) for i in range(1000): #make a random vector x=uniform(-1.0, 1.0) y=uniform(-1.0, 1.0) z=uniform(-1.0, 1.0) #scale it to length radius length=sqrt( (x)**2 + (y)**2 + (z)**2 ) factor = radius / length xs[i] = x*factor + x_centre ys[i] = y*factor + y_centre zs[i] = z*factor + z_centre :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 leastsq(_calculate_residual_sphere, initial_parameters, args=(x_values, y_values, z_values)) result = FitSphere_LeastSquares(xs,ys,zs) print (result) def _calculate_residual_sphere(parameters, x_values, y_values, z_values): """ 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
 ... ... @@ -9,7 +9,7 @@ # Add files or directories to the blacklist. They should be base names, not # paths. ignore=CVS ignore=CVS, ui # Add files or directories matching the regex patterns to the blacklist. The # regex matches against base names, not paths. ... ...
 ... ... @@ -2,26 +2,57 @@ """scikit-surgery-sphere-fitting tests""" from sksurgeryspherefitting.ui.sksurgeryspherefitting_demo import run_demo from sksurgeryspherefitting.algorithms import addition, multiplication import numpy #from sksurgeryspherefitting.ui.sksurgeryspherefitting_demo import run_demo from sksurgeryspherefitting.algorithms import sphere_fitting import six # Pytest style def test_using_pytest_sksurgeryspherefitting(): x = 1 y = 2 verbose = False multiply = False expected_answer = 3 assert run_demo(x, y, multiply, verbose) == expected_answer def test_addition(): assert addition.add_two_numbers(1, 2) == 3 def test_multiplication(): assert multiplication.multiply_two_numbers(2, 2) == 4 #def test_using_pytest_sksurgeryspherefitting(): # x = 1 # y = 2 # verbose = False # multiply = False # expected_answer = 3 # assert run_demo(x, y, multiply, verbose) == expected_answer def test_fit_sphere_least_squares(): x_centre = 1.0 y_centre = 167.0 z_centre = 200.0 radius = 7.5 #some arrays to fit data to xs=numpy.ndarray(shape=(1000,),dtype=float ) ys=numpy.ndarray(shape=(1000,),dtype=float ) zs=numpy.ndarray(shape=(1000,),dtype=float ) #fill the arrays with points uniformly spread on #a sphere centred at x,y,z with radius radius #first seed the random generator so we get consistent test behaviour numpy.random.seed(seed=0) for i in range(1000): #make a random vector x=numpy.random.uniform(-1.0, 1.0) y=numpy.random.uniform(-1.0, 1.0) z=numpy.random.uniform(-1.0, 1.0) #scale it to length radius length=numpy.sqrt( (x)**2 + (y)**2 + (z)**2 ) factor = radius / length xs[i] = x*factor + x_centre ys[i] = y*factor + y_centre zs[i] = z*factor + z_centre parameters = [0.0, 0.0, 0.0, 0.0] result = sphere_fitting.fit_sphere_least_squares (xs, ys, zs, parameters) numpy.testing.assert_approx_equal (result[0][0], x_centre, significant = 10) numpy.testing.assert_approx_equal (result[0][1], y_centre, significant = 10) numpy.testing.assert_approx_equal (result[0][2], z_centre, significant = 10) numpy.testing.assert_approx_equal (result[0][3], radius, significant = 10)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!