## "Fossies" - the Fresh Open Source Software Archive

### Source code changes of the file "skimage/transform/_geometric.py" betweenscikit-image-0.19.1.tar.gz and scikit-image-0.19.2.tar.gz

About: scikit-image is a collection of algorithms for image processing in Python.

_geometric.py  (scikit-image-0.19.1):_geometric.py  (scikit-image-0.19.2)
skipping to change at line 698 skipping to change at line 698
success : bool success : bool
True, if model estimation succeeds. True, if model estimation succeeds.
""" """
n, d = src.shape n, d = src.shape
src_matrix, src = _center_and_normalize_points(src) src_matrix, src = _center_and_normalize_points(src)
dst_matrix, dst = _center_and_normalize_points(dst) dst_matrix, dst = _center_and_normalize_points(dst)
if not np.all(np.isfinite(src_matrix + dst_matrix)): if not np.all(np.isfinite(src_matrix + dst_matrix)):
self.params = np.full((d), np.nan) self.params = np.full((d + 1, d + 1), np.nan)
return False return False
# params: a0, a1, a2, b0, b1, b2, c0, c1 # params: a0, a1, a2, b0, b1, b2, c0, c1
A = np.zeros((n * d, (d+1) ** 2)) A = np.zeros((n * d, (d+1) ** 2))
# fill the A matrix with the appropriate block matrices; see docstring # fill the A matrix with the appropriate block matrices; see docstring
# for 2D example — this can be generalised to more blocks in the 3D and # for 2D example — this can be generalised to more blocks in the 3D and
# higher-dimensional cases. # higher-dimensional cases.
for ddim in range(d): for ddim in range(d):
A[ddim*n : (ddim+1)*n, ddim*(d+1) : ddim*(d+1) + d] = src A[ddim*n : (ddim+1)*n, ddim*(d+1) : ddim*(d+1) + d] = src
A[ddim*n : (ddim+1)*n, ddim*(d+1) + d] = 1 A[ddim*n : (ddim+1)*n, ddim*(d+1) + d] = 1
skipping to change at line 729 skipping to change at line 729
_, _, V = np.linalg.svd(A) _, _, V = np.linalg.svd(A)
else: else:
W = np.diag(np.tile(np.sqrt(weights / np.max(weights)), d)) W = np.diag(np.tile(np.sqrt(weights / np.max(weights)), d))
_, _, V = np.linalg.svd(W @ A) _, _, V = np.linalg.svd(W @ A)
# if the last element of the vector corresponding to the smallest # if the last element of the vector corresponding to the smallest
# singular value is close to zero, this implies a degenerate case # singular value is close to zero, this implies a degenerate case
# because it is a rank-defective transform, which would map points # because it is a rank-defective transform, which would map points
# to a line rather than a plane. # to a line rather than a plane.
if np.isclose(V[-1, -1], 0): if np.isclose(V[-1, -1], 0):
self.params = np.full((d + 1, d + 1), np.nan)
return False return False
H = np.zeros((d+1, d+1)) H = np.zeros((d+1, d+1))
# solution is right singular vector that corresponds to smallest # solution is right singular vector that corresponds to smallest
# singular value # singular value
H.flat[list(self._coeffs) + [-1]] = - V[-1, :-1] / V[-1, -1] H.flat[list(self._coeffs) + [-1]] = - V[-1, :-1] / V[-1, -1]
H[d, d] = 1 H[d, d] = 1
# De-center and de-normalize # De-center and de-normalize
H = np.linalg.inv(dst_matrix) @ H @ src_matrix H = np.linalg.inv(dst_matrix) @ H @ src_matrix
skipping to change at line 961 skipping to change at line 962
Parameters Parameters
---------- ----------
src : (N, D) array src : (N, D) array
Source coordinates. Source coordinates.
dst : (N, D) array dst : (N, D) array
Destination coordinates. Destination coordinates.
Returns Returns
------- -------
success : bool success : bool
True, if . True, if all pieces of the model are successfully estimated.
""" """
ndim = src.shape[1] ndim = src.shape[1]
# forward piecewise affine # forward piecewise affine
# triangulate input positions into mesh # triangulate input positions into mesh
self._tesselation = spatial.Delaunay(src) self._tesselation = spatial.Delaunay(src)
success = True
# find affine mapping from source positions to destination # find affine mapping from source positions to destination
self.affines = [] self.affines = []
for tri in self._tesselation.vertices: for tri in self._tesselation.vertices:
affine = AffineTransform(dimensionality=ndim) affine = AffineTransform(dimensionality=ndim)
affine.estimate(src[tri, :], dst[tri, :]) success &= affine.estimate(src[tri, :], dst[tri, :])
self.affines.append(affine) self.affines.append(affine)
# inverse piecewise affine # inverse piecewise affine
# triangulate input positions into mesh # triangulate input positions into mesh
self._inverse_tesselation = spatial.Delaunay(dst) self._inverse_tesselation = spatial.Delaunay(dst)
# find affine mapping from source positions to destination # find affine mapping from source positions to destination
self.inverse_affines = [] self.inverse_affines = []
for tri in self._inverse_tesselation.vertices: for tri in self._inverse_tesselation.vertices:
affine = AffineTransform(dimensionality=ndim) affine = AffineTransform(dimensionality=ndim)
affine.estimate(dst[tri, :], src[tri, :]) success &= affine.estimate(dst[tri, :], src[tri, :])
self.inverse_affines.append(affine) self.inverse_affines.append(affine)
return return success
def __call__(self, coords): def __call__(self, coords):
"""Apply forward transformation. """Apply forward transformation.
Coordinates outside of the mesh will be set to `- 1`. Coordinates outside of the mesh will be set to `- 1`.
Parameters Parameters
---------- ----------
coords : (N, D) array coords : (N, D) array
Source coordinates. Source coordinates.
skipping to change at line 1231 skipping to change at line 1235
Returns Returns
------- -------
success : bool success : bool
True, if model estimation succeeds. True, if model estimation succeeds.
""" """
self.params = _umeyama(src, dst, False) self.params = _umeyama(src, dst, False)
return # _umeyama will return nan if the problem is not well-conditioned.
return not np.any(np.isnan(self.params))
@property @property
def rotation(self): def rotation(self):
return math.atan2(self.params[1, 0], self.params[1, 1]) return math.atan2(self.params[1, 0], self.params[1, 1])
@property @property
def translation(self): def translation(self):
return self.params[0:2, 2] return self.params[0:2, 2]
class SimilarityTransform(EuclideanTransform): class SimilarityTransform(EuclideanTransform):
skipping to change at line 1346 skipping to change at line 1351
Returns Returns
------- -------
success : bool success : bool
True, if model estimation succeeds. True, if model estimation succeeds.
""" """
self.params = _umeyama(src, dst, estimate_scale=True) self.params = _umeyama(src, dst, estimate_scale=True)
return # _umeyama will return nan if the problem is not well-conditioned.
return not np.any(np.isnan(self.params))
@property @property
def scale(self): def scale(self):
# det = scale**(# of dimensions), therefore scale = det**(1/2) # det = scale**(# of dimensions), therefore scale = det**(1/2)
return np.sqrt(np.linalg.det(self.params)) return np.sqrt(np.linalg.det(self.params))
class PolynomialTransform(GeometricTransform): class PolynomialTransform(GeometricTransform):
"""2D polynomial transformation. """2D polynomial transformation.
Has the following form:: Has the following form::
End of changes. 9 change blocks.
7 lines changed or deleted 13 lines changed or added