From b3d62afa28ac0b95fb19a5bbe95f20dd7a47b9b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Mon, 2 Dec 2013 11:50:33 +0100 Subject: [PATCH] Use public attribute for parameter values --- TODO.txt | 4 + doc/examples/applications/plot_geometric.py | 4 +- skimage/transform/_geometric.py | 101 ++++++++++++-------- skimage/transform/tests/test_geometric.py | 30 +++--- 4 files changed, 84 insertions(+), 55 deletions(-) diff --git a/TODO.txt b/TODO.txt index 16a3f85f..52699085 100644 --- a/TODO.txt +++ b/TODO.txt @@ -4,6 +4,10 @@ Version 0.11 * Change depecrated `enforce_connectivity=False`on skimage.segmentation.slic and set it to True as default * Remove deprecated `skimage.measure.fit.BaseModel._params` attribute +* Remove deprecated `skimage.measure.fit.BaseModel._params`, + `skimage.transform.ProjectiveTransform._matrx`, + `skimage.transform.PolynomialTransform._params`, + `skimage.transform.PiecewiseAffineTransform.affines_*` attributes Version 0.10 ------------ diff --git a/doc/examples/applications/plot_geometric.py b/doc/examples/applications/plot_geometric.py index 141ef51f..843faa1f 100644 --- a/doc/examples/applications/plot_geometric.py +++ b/doc/examples/applications/plot_geometric.py @@ -33,14 +33,14 @@ First we create a transformation using explicit parameters: tform = tf.SimilarityTransform(scale=1, rotation=math.pi / 2, translation=(0, 1)) -print(tform._matrix) +print(tform.matrix_) """ Alternatively you can define a transformation by the transformation matrix itself: """ -matrix = tform._matrix.copy() +matrix = tform.matrix_.copy() matrix[1, 2] = 2 tform2 = tf.SimilarityTransform(matrix) diff --git a/skimage/transform/_geometric.py b/skimage/transform/_geometric.py index a4587c10..611f9ab2 100644 --- a/skimage/transform/_geometric.py +++ b/skimage/transform/_geometric.py @@ -1,5 +1,6 @@ import six import math +import warnings import numpy as np from scipy import ndimage, spatial @@ -113,11 +114,17 @@ class ProjectiveTransform(GeometricTransform): matrix = np.eye(3) if matrix.shape != (3, 3): raise ValueError("invalid shape of transformation matrix") - self._matrix = matrix + self.matrix_ = matrix + + @property + def _matrix(self): + warnings.warn('`_matrix` attribute is deprecated, ' + 'use `matrix_` instead.') + return self.matrix_ @property def _inv_matrix(self): - return np.linalg.inv(self._matrix) + return np.linalg.inv(self.matrix_) def _apply_mat(self, coords, matrix): coords = np.array(coords, copy=False, ndmin=2) @@ -133,7 +140,7 @@ class ProjectiveTransform(GeometricTransform): return dst[:, :2] def __call__(self, coords): - return self._apply_mat(coords, self._matrix) + return self._apply_mat(coords, self.matrix_) def inverse(self, coords): """Apply inverse transformation. @@ -235,7 +242,7 @@ class ProjectiveTransform(GeometricTransform): H.flat[list(self._coeffs) + [8]] = - V[-1, :-1] / V[-1, -1] H[2, 2] = 1 - self._matrix = H + self.matrix_ = H def __add__(self, other): """Combine this transformation with another. @@ -248,7 +255,7 @@ class ProjectiveTransform(GeometricTransform): tform = self.__class__ else: tform = ProjectiveTransform - return tform(other._matrix.dot(self._matrix)) + return tform(other.matrix_.dot(self.matrix_)) else: raise TypeError("Cannot combine transformations of differing " "types.") @@ -299,7 +306,7 @@ class AffineTransform(ProjectiveTransform): elif matrix is not None: if matrix.shape != (3, 3): raise ValueError("Invalid shape of transformation matrix.") - self._matrix = matrix + self.matrix_ = matrix elif params: if scale is None: scale = (1, 1) @@ -311,34 +318,34 @@ class AffineTransform(ProjectiveTransform): translation = (0, 0) sx, sy = scale - self._matrix = np.array([ + self.matrix_ = np.array([ [sx * math.cos(rotation), -sy * math.sin(rotation + shear), 0], [sx * math.sin(rotation), sy * math.cos(rotation + shear), 0], [ 0, 0, 1] ]) - self._matrix[0:2, 2] = translation + self.matrix_[0:2, 2] = translation else: # default to an identity transform - self._matrix = np.eye(3) + self.matrix_ = np.eye(3) @property def scale(self): - sx = math.sqrt(self._matrix[0, 0] ** 2 + self._matrix[1, 0] ** 2) - sy = math.sqrt(self._matrix[0, 1] ** 2 + self._matrix[1, 1] ** 2) + sx = math.sqrt(self.matrix_[0, 0] ** 2 + self.matrix_[1, 0] ** 2) + sy = math.sqrt(self.matrix_[0, 1] ** 2 + self.matrix_[1, 1] ** 2) return sx, sy @property def rotation(self): - return math.atan2(self._matrix[1, 0], self._matrix[0, 0]) + return math.atan2(self.matrix_[1, 0], self.matrix_[0, 0]) @property def shear(self): - beta = math.atan2(- self._matrix[0, 1], self._matrix[1, 1]) + beta = math.atan2(- self.matrix_[0, 1], self.matrix_[1, 1]) return beta - self.rotation @property def translation(self): - return self._matrix[0:2, 2] + return self.matrix_[0:2, 2] class PiecewiseAffineTransform(GeometricTransform): @@ -354,8 +361,20 @@ class PiecewiseAffineTransform(GeometricTransform): def __init__(self): self._tesselation = None self._inverse_tesselation = None - self.affines = [] - self.inverse_affines = [] + self.affines_ = [] + self.inverse_affines_ = [] + + @property + def affines(self): + warnings.warn('`affines` attribute is deprecated, ' + 'use `affines_` instead.') + return self.affines_ + + @property + def inverse_affines(self): + warnings.warn('`inverse_affines` attribute is deprecated, ' + 'use `inverse_affines_` instead.') + return self.inverse_affines_ def estimate(self, src, dst): """Set the control points with which to perform the piecewise mapping. @@ -375,21 +394,21 @@ class PiecewiseAffineTransform(GeometricTransform): # triangulate input positions into mesh self._tesselation = spatial.Delaunay(src) # find affine mapping from source positions to destination - self.affines = [] + self.affines_ = [] for tri in self._tesselation.vertices: affine = AffineTransform() affine.estimate(src[tri, :], dst[tri, :]) - self.affines.append(affine) + self.affines_.append(affine) # inverse piecewise affine # triangulate input positions into mesh self._inverse_tesselation = spatial.Delaunay(dst) # find affine mapping from source positions to destination - self.inverse_affines = [] + self.inverse_affines_ = [] for tri in self._inverse_tesselation.vertices: affine = AffineTransform() affine.estimate(dst[tri, :], src[tri, :]) - self.inverse_affines.append(affine) + self.inverse_affines_.append(affine) def __call__(self, coords): """Apply forward transformation. @@ -418,7 +437,7 @@ class PiecewiseAffineTransform(GeometricTransform): for index in range(len(self._tesselation.vertices)): # affine transform for triangle - affine = self.affines[index] + affine = self.affines_[index] # all coordinates within triangle index_mask = simplex == index @@ -453,7 +472,7 @@ class PiecewiseAffineTransform(GeometricTransform): for index in range(len(self._inverse_tesselation.vertices)): # affine transform for triangle - affine = self.inverse_affines[index] + affine = self.inverse_affines_[index] # all coordinates within triangle index_mask = simplex == index @@ -501,7 +520,7 @@ class SimilarityTransform(ProjectiveTransform): elif matrix is not None: if matrix.shape != (3, 3): raise ValueError("Invalid shape of transformation matrix.") - self._matrix = matrix + self.matrix_ = matrix elif params: if scale is None: scale = 1 @@ -510,16 +529,16 @@ class SimilarityTransform(ProjectiveTransform): if translation is None: translation = (0, 0) - self._matrix = np.array([ + self.matrix_ = np.array([ [math.cos(rotation), - math.sin(rotation), 0], [math.sin(rotation), math.cos(rotation), 0], [ 0, 0, 1] ]) - self._matrix[0:2, 0:2] *= scale - self._matrix[0:2, 2] = translation + self.matrix_[0:2, 0:2] *= scale + self.matrix_[0:2, 2] = translation else: # default to an identity transform - self._matrix = np.eye(3) + self.matrix_ = np.eye(3) def estimate(self, src, dst): """Set the transformation matrix with the explicit parameters. @@ -585,7 +604,7 @@ class SimilarityTransform(ProjectiveTransform): # singular value a0, a1, b0, b1 = - V[-1, :-1] / V[-1, -1] - self._matrix = np.array([[a0, -b0, a1], + self.matrix_ = np.array([[a0, -b0, a1], [b0, a0, b1], [ 0, 0, 1]]) @@ -593,18 +612,18 @@ class SimilarityTransform(ProjectiveTransform): def scale(self): if math.cos(self.rotation) == 0: # sin(self.rotation) == 1 - scale = self._matrix[0, 1] + scale = self.matrix_[0, 1] else: - scale = self._matrix[0, 0] / math.cos(self.rotation) + scale = self.matrix_[0, 0] / math.cos(self.rotation) return scale @property def rotation(self): - return math.atan2(self._matrix[1, 0], self._matrix[1, 1]) + return math.atan2(self.matrix_[1, 0], self.matrix_[1, 1]) @property def translation(self): - return self._matrix[0:2, 2] + return self.matrix_[0:2, 2] class PolynomialTransform(GeometricTransform): @@ -627,7 +646,13 @@ class PolynomialTransform(GeometricTransform): params = np.array([[0, 1, 0], [0, 0, 1]]) if params.shape[0] != 2: raise ValueError("invalid shape of transformation parameters") - self._params = params + self.params_ = params + + @property + def _params(self): + warnings.warn('`_params` attribute is deprecated, ' + 'use `params_` instead.') + return self.params_ def estimate(self, src, dst, order=2): """Set the transformation matrix with the explicit transformation @@ -700,7 +725,7 @@ class PolynomialTransform(GeometricTransform): # singular value params = - V[-1, :-1] / V[-1, -1] - self._params = params.reshape((2, u / 2)) + self.params_ = params.reshape((2, u / 2)) def __call__(self, coords): """Apply forward transformation. @@ -718,7 +743,7 @@ class PolynomialTransform(GeometricTransform): """ x = coords[:, 0] y = coords[:, 1] - u = len(self._params.ravel()) + u = len(self.params_.ravel()) # number of coefficients -> u = (order + 1) * (order + 2) order = int((- 3 + math.sqrt(9 - 4 * (2 - u))) / 2) dst = np.zeros(coords.shape) @@ -726,8 +751,8 @@ class PolynomialTransform(GeometricTransform): pidx = 0 for j in range(order + 1): for i in range(j + 1): - dst[:, 0] += self._params[0, pidx] * x ** (j - i) * y ** i - dst[:, 1] += self._params[1, pidx] * x ** (j - i) * y ** i + dst[:, 0] += self.params_[0, pidx] * x ** (j - i) * y ** i + dst[:, 1] += self.params_[1, pidx] * x ** (j - i) * y ** i pidx += 1 return dst @@ -1046,7 +1071,7 @@ def warp(image, inverse_map=None, map_args={}, output_shape=None, order=1, # inverse_map is a homography elif isinstance(inverse_map, HOMOGRAPHY_TRANSFORMS): - matrix = inverse_map._matrix + matrix = inverse_map.matrix_ # inverse_map is the inverse of a homography elif (hasattr(inverse_map, '__name__') diff --git a/skimage/transform/tests/test_geometric.py b/skimage/transform/tests/test_geometric.py index 06c4f652..e6a2fcfc 100644 --- a/skimage/transform/tests/test_geometric.py +++ b/skimage/transform/tests/test_geometric.py @@ -56,19 +56,19 @@ def test_similarity_estimation(): # exact solution tform = estimate_transform('similarity', SRC[:2, :], DST[:2, :]) assert_array_almost_equal(tform(SRC[:2, :]), DST[:2, :]) - assert_equal(tform._matrix[0, 0], tform._matrix[1, 1]) - assert_equal(tform._matrix[0, 1], - tform._matrix[1, 0]) + assert_equal(tform.matrix_[0, 0], tform.matrix_[1, 1]) + assert_equal(tform.matrix_[0, 1], - tform.matrix_[1, 0]) # over-determined tform2 = estimate_transform('similarity', SRC, DST) assert_array_almost_equal(tform2.inverse(tform2(SRC)), SRC) - assert_equal(tform2._matrix[0, 0], tform2._matrix[1, 1]) - assert_equal(tform2._matrix[0, 1], - tform2._matrix[1, 0]) + assert_equal(tform2.matrix_[0, 0], tform2.matrix_[1, 1]) + assert_equal(tform2.matrix_[0, 1], - tform2.matrix_[1, 0]) # via estimate method tform3 = SimilarityTransform() tform3.estimate(SRC, DST) - assert_array_almost_equal(tform3._matrix, tform2._matrix) + assert_array_almost_equal(tform3.matrix_, tform2.matrix_) def test_similarity_init(): @@ -83,7 +83,7 @@ def test_similarity_init(): assert_array_almost_equal(tform.translation, translation) # init with transformation matrix - tform2 = SimilarityTransform(tform._matrix) + tform2 = SimilarityTransform(tform.matrix_) assert_array_almost_equal(tform2.scale, scale) assert_array_almost_equal(tform2.rotation, rotation) assert_array_almost_equal(tform2.translation, translation) @@ -111,7 +111,7 @@ def test_affine_estimation(): # via estimate method tform3 = AffineTransform() tform3.estimate(SRC, DST) - assert_array_almost_equal(tform3._matrix, tform2._matrix) + assert_array_almost_equal(tform3.matrix_, tform2.matrix_) def test_affine_init(): @@ -128,7 +128,7 @@ def test_affine_init(): assert_array_almost_equal(tform.translation, translation) # init with transformation matrix - tform2 = AffineTransform(tform._matrix) + tform2 = AffineTransform(tform.matrix_) assert_array_almost_equal(tform2.scale, scale) assert_array_almost_equal(tform2.rotation, rotation) assert_array_almost_equal(tform2.shear, shear) @@ -155,14 +155,14 @@ def test_projective_estimation(): # via estimate method tform3 = ProjectiveTransform() tform3.estimate(SRC, DST) - assert_array_almost_equal(tform3._matrix, tform2._matrix) + assert_array_almost_equal(tform3.matrix_, tform2.matrix_) def test_projective_init(): tform = estimate_transform('projective', SRC, DST) # init with transformation matrix - tform2 = ProjectiveTransform(tform._matrix) - assert_array_almost_equal(tform2._matrix, tform._matrix) + tform2 = ProjectiveTransform(tform.matrix_) + assert_array_almost_equal(tform2.matrix_, tform.matrix_) def test_polynomial_estimation(): @@ -173,20 +173,20 @@ def test_polynomial_estimation(): # via estimate method tform2 = PolynomialTransform() tform2.estimate(SRC, DST, order=10) - assert_array_almost_equal(tform2._params, tform._params) + assert_array_almost_equal(tform2.params_, tform.params_) def test_polynomial_init(): tform = estimate_transform('polynomial', SRC, DST, order=10) # init with transformation parameters - tform2 = PolynomialTransform(tform._params) - assert_array_almost_equal(tform2._params, tform._params) + tform2 = PolynomialTransform(tform.params_) + assert_array_almost_equal(tform2.params_, tform.params_) def test_polynomial_default_order(): tform = estimate_transform('polynomial', SRC, DST) tform2 = estimate_transform('polynomial', SRC, DST, order=2) - assert_array_almost_equal(tform2._params, tform._params) + assert_array_almost_equal(tform2.params_, tform.params_) def test_polynomial_inverse():