Skip to content

Commit

Permalink
Merge pull request #146 from fcollman/scale_thinplate
Browse files Browse the repository at this point in the history
Scale thinplate
  • Loading branch information
RussTorres authored Jul 26, 2019
2 parents 0225da9 + 3961d07 commit a12126e
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 5 deletions.
85 changes: 81 additions & 4 deletions renderapi/transform/leaf/thin_plate_spline.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,10 +394,8 @@ def adaptive_mesh_estimate(

mn = self.srcPts.min(axis=1)
mx = self.srcPts.max(axis=1)
xt, yt = np.meshgrid(
np.linspace(mn[0], mx[0], starting_grid),
np.linspace(mn[1], mx[1], starting_grid))
new_src = np.vstack((xt.flatten(), yt.flatten())).transpose()
new_src = self.src_array(
mn[0], mn[1], mx[0], mx[1], starting_grid, starting_grid)
old_src = self.srcPts.transpose()
old_dst = self.tform(old_src)

Expand All @@ -411,3 +409,82 @@ def adaptive_mesh_estimate(
max_iter=max_iter,
nworst=nworst,
niter=0)

@staticmethod
def src_array(xmin, ymin, xmax, ymax, nx, ny):
"""create N x 2 array of regularly spaced points
Parameters
----------
xmin : float
minimum of x grid
ymin : float
minimum of y grid
xmax : float
maximum of x grid
ymax : float
maximum of y grid
nx : int
number of points in x axis
ny : int
number of points in y axis
Returns
-------
src : :class:`numpy.ndarray`
(nx * ny) x 2 array of coordinated.
"""
src = np.mgrid[xmin:xmax:nx*1j, ymin:ymax:ny*1j].reshape(2, -1).T
return src

def scale_coordinates(
self,
factor,
ngrid=20,
preserve_srcPts=False):
"""estimates a new ThinPlateSplineTransform from the current one
in a scaled transform space.
Parameters
----------
factor : float
the factor by which to scale the space
ngrid : int
number of points per axis for the estimation grid
preserve_srcPts : bool
one might want to keep the original scaled srcPts
for example, if pts were made specially for a mask
or a crack or fold
Returns
-------
new_tform : :class:`renderapi.transform.ThinPlateSplineTransform`
the new transform in the scaled space
"""

new_tform = ThinPlateSplineTransform()
computeAffine = True
if self.aMtx is None:
computeAffine = False

mn = self.srcPts.min(axis=1)
mx = self.srcPts.max(axis=1)
src = self.src_array(mn[0], mn[1], mx[0], mx[1], ngrid, ngrid)

if preserve_srcPts:
# do not repeat close points
dist = scipy.spatial.distance.cdist(
src,
self.srcPts.transpose(),
metric='euclidean')
ind = np.invert(np.any(dist < 1e-3, axis=0))
src = np.vstack((src, self.srcPts.transpose()[ind]))

new_tform.estimate(
src * factor,
self.tform(src) * factor,
computeAffine=computeAffine)

return new_tform
3 changes: 3 additions & 0 deletions test/rendersettings.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@
TEST_THINPLATESPLINE_FILE = os.path.join(
TEST_FILES_DIR,
'thin_plate_spline.json')
TEST_THINPLATEROUGH_FILE = os.path.join(
TEST_FILES_DIR,
'thin_plate_from_rough.json')
TEST_THINPLATESPLINEAFFINE_FILE = os.path.join(
TEST_FILES_DIR,
'thin_plate_spline_affine.json')
Expand Down
1 change: 1 addition & 0 deletions test/test_files/thin_plate_from_rough.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"type": "leaf", "className": "mpicbg.trakem2.transform.ThinPlateSplineTransform", "dataString": "ThinPlateSplineR2LogR 2 25 eJwBMADP/78yLRWQifN2vw/ErHm04Cs/IqdJx765j78ab8sN7GLJwCCjMIEXaI2/9qEQnRU3FUt4FyU= eJw9zFtMkmEYAOCJELrmIcvsoJ10Mipnx4VtfWLlRQ2PYFPCCNKVMv65iYeIiEw8QLFCy5b/nNp086KtRCNyvmOuzJjLuiBLRUGaW2ZYU1cbtnXzf9/lc/M4S2+NVnOM7c5LXS9/KrazhMYXIxPTn+aJHyuGOui6R8Tda+cXeywJxH2OV5z1qWVsJ/MJDe0Gu23Kij9i5iNmPmLmwyaf1UgnNy/tIx82/rDxh40/xuSjh2t+py0GyYeNP2z8YeOPMfmeavs8q6uL5MPGHzb+sPHHGPSsQ9JopwIKg2ZvIC8eien7u09ssgJ/JTaHX2RD1Mm43su5bqgKzeqXzFYAa+GLabRgL8oUNLDd3C0op9zMmz9gRjf+LU3T7gSQ58dy5+yfkVKUd+VJ2DdQJ3HLecUPkaQ47Nwc1YQaabbQwZVBibUSkk31KEMdDpPCCTBIHIG3+iY4Pfb6o89GobsCNeV5p4LrliMhH243QtWfo2lD72kweIOlG8pccCY1sXqN6kcmtsfrf84BnWU0qmOrCxrqJgfDHSEgVm3bGaX5jjSChYDaTqH03IEdIvlFkGplqjxxGdypOP5Vc+wUKvC0RW/Um5CupXe9qnkz4rsiWh1NflRb45CMZKSArLjNrA3UoqKrgsyDpgpU6ffFWFPjIXvlXpleIUf14z9ixuQdKH9Pl6dE3gri9F/jPfv/ogvPsqXU4UgoHBxWDuyKQEZWXOdyZAaSPOjU+brPQknDzMwELxRyNaGixBQdKG++uTablfQfS4+iWQ=="}
46 changes: 46 additions & 0 deletions test/test_transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import rendersettings
import importlib
import pytest
from scipy.spatial.distance import cdist


EPSILON = 0.0000000001
EPSILON2 = 0.000000001
Expand Down Expand Up @@ -1037,3 +1039,47 @@ def test_polynomial_shear():
assert atf.shear == ptf.shear
assert atf.rotation == ptf.rotation
assert atf.translation == ptf.translation


@pytest.mark.parametrize('ngrid', [5, 20])
@pytest.mark.parametrize('preserve_srcPts', [True, False])
@pytest.mark.parametrize('computeAffine', [True, False])
@pytest.mark.parametrize('factor', [1e-3, 1e3, 1e5])
def test_scale_thinplate(factor, computeAffine, preserve_srcPts, ngrid):
# use case is to scale a rough alignment thinplate spline
with open(rendersettings.TEST_THINPLATEROUGH_FILE, 'r') as f:
tform = renderapi.transform.load_transform_json(
json.load(f))

if not computeAffine:
tform.aMtx = None
tform.bVec = None

mn = tform.srcPts.min(axis=0)
mx = tform.srcPts.max(axis=0)

npts = 1000
src = np.random.rand(npts, 2)
src[:, 0] = src[:, 0] * (mx[0] - mn[0]) + mn[0]
src[:, 1] = src[:, 1] * (mx[1] - mn[1]) + mn[1]
dst = tform.tform(src)

scaled_tform = tform.scale_coordinates(
factor, ngrid=ngrid, preserve_srcPts=preserve_srcPts)
dst_scaled = scaled_tform.tform(src * factor)

delta = np.linalg.norm(dst_scaled - dst * factor, axis=1)
scale = dst_scaled.ptp(axis=0).mean()
tol = 1e-4
if ngrid == 5:
tol = 1e-3
assert (delta.max() / scale) < tol

if preserve_srcPts:
dist = cdist(
tform.srcPts.transpose() * factor,
scaled_tform.srcPts.transpose(),
metric='euclidean')
# check that the original srcPts have a close neighbor still
# in the scaled srcPts
assert np.all(np.any(dist < 1e-3, axis=1))
2 changes: 1 addition & 1 deletion test_requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
coverage>=4.1
mock>=2.0.0
pep8>=1.7.0
pytest>=3.0.5
pytest>4.6,<5.0
pytest-cov>=2.2.1
pytest-pep8>=1.0.6
pytest-xdist>=1.14
Expand Down

0 comments on commit a12126e

Please sign in to comment.