From cf11ad7832b31c4bf80ae29700c3854f4f7c14f6 Mon Sep 17 00:00:00 2001 From: Christine Kim <125395064+chkim-usgs@users.noreply.github.com> Date: Mon, 20 Nov 2023 10:23:45 -0700 Subject: [PATCH] Replace affine6p transformation with numpy solution (#579) * Replace affine6p transformation with numpy solution * Remove affine6p dependency * Update changelog and remove pip from conda-recipe --- CHANGELOG.md | 4 ++++ ale/drivers/lo_drivers.py | 19 +++++++++++++------ environment.yml | 3 --- recipe/meta.yaml | 1 - tests/pytests/test_lo_drivers.py | 19 +++++++++++++++++-- 5 files changed, 34 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31e559e04..75abfd90f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,10 @@ release. ### Fixed - Fixed LRO MiniRF drivers naif keywords focal to pixel and pixel to focal translations to be correct. [#569](https://github.com/DOI-USGS/ale/pull/569) +### Changed +- Removed the affine6p library and replaced affine6p's affine transformation with a numpy solution [#579](https://github.com/DOI-USGS/ale/pull/579) + + ## [0.9.1] - 2023-06-05 ### Changed diff --git a/ale/drivers/lo_drivers.py b/ale/drivers/lo_drivers.py index 42a7d2d97..7150982c6 100644 --- a/ale/drivers/lo_drivers.py +++ b/ale/drivers/lo_drivers.py @@ -1,6 +1,5 @@ import spiceypy as spice import numpy as np -import affine6p from ale.base.data_naif import NaifSpice from ale.base.label_isis import IsisLabel from ale.base.type_sensor import Framer @@ -156,17 +155,25 @@ def naif_keywords(self): p_fidYCoords = self.label['IsisCube']['Instrument']['FiducialYCoordinates'].value # Create Affine Transformation - p_src = [p_fidSamples, p_fidLines] p_dst = [p_fidXCoords, p_fidYCoords] - # format the fiducial coordinatens as [ [x, y], [x, y]...] + # Format the fiducial coordinates as [ [x, y], [x, y]...] p_src = np.rot90(np.array([p_fidSamples, p_fidLines])) p_dst = np.rot90(np.array([p_fidXCoords, p_fidYCoords])) - # find a best match for the transformation based on source and destination coordinates - tr_mat = affine6p.estimate(p_src, p_dst).get_matrix() + # Pad data with ones so that the transformation allows translations + pad = lambda x: np.hstack([x, np.ones((x.shape[0], 1))]) + X = pad(p_src) + Y = pad(p_dst) + # Solve the least squares problem X * A = Y to find our transformation matrix A + A, res, rank, s = np.linalg.lstsq(X, Y) + + # Transpose matrix and convert to list + tr_mat = np.transpose(A).tolist() + + # Compute inverse of transformation matrix tr_mat_inv = np.linalg.inv(tr_mat) # X and Y, Inverse S and L components of transformation @@ -175,7 +182,7 @@ def naif_keywords(self): itranss = tr_mat_inv[0] itransl = tr_mat_inv[1] - # move the last item to the front to get the ordering standard in ISIS + # Move the last item to the front to get the ordering standard in ISIS transx.insert(0, transx.pop()) transy.insert(0, transy.pop()) itranss = np.roll(itranss, 1).tolist() diff --git a/environment.yml b/environment.yml index b450dc601..062d3e934 100644 --- a/environment.yml +++ b/environment.yml @@ -22,6 +22,3 @@ dependencies: - pytest-cov - networkx - breathe - - pip - - pip: - - affine6p diff --git a/recipe/meta.yaml b/recipe/meta.yaml index 3ce001b06..80bc112dd 100644 --- a/recipe/meta.yaml +++ b/recipe/meta.yaml @@ -18,7 +18,6 @@ requirements: - cmake>=3.15 - eigen host: - - pip - python - nlohmann_json run: diff --git a/tests/pytests/test_lo_drivers.py b/tests/pytests/test_lo_drivers.py index f1c2befa2..50010ad76 100644 --- a/tests/pytests/test_lo_drivers.py +++ b/tests/pytests/test_lo_drivers.py @@ -98,7 +98,6 @@ def test_focal2pixel_lines(self): namfrm.assert_called_with("LO3_HIGH_RESOLUTION_CAMERA") def test_naif_keywords(self): - with patch('ale.drivers.lo_drivers.LoHighCameraIsisLabelNaifSpiceDriver.ikid', new_callable=PropertyMock) as ikid, \ patch('ale.base.data_naif.spice.bodvrd', return_value=[1737.4, 1737.4, 1737.4]) as bodvrd: @@ -114,6 +113,22 @@ def test_naif_keywords(self): "INS-533001_ITRANSL" : [4541.692430539061, -0.05845617762411283, 143.95514969883214] } - assert self.driver.naif_keywords == naif_keywords + assert self.driver.naif_keywords["BODY_CODE"] == naif_keywords["BODY_CODE"] + assert self.driver.naif_keywords["BODY301_RADII"] == naif_keywords["BODY301_RADII"] + assert self.driver.naif_keywords["BODY_FRAME_CODE"] == naif_keywords["BODY_FRAME_CODE"] + + np.testing.assert_almost_equal(np.asarray(self.driver.naif_keywords["INS-533001_TRANSX"]), + np.asarray(naif_keywords["INS-533001_TRANSX"]), + decimal=10) + np.testing.assert_almost_equal(np.asarray(self.driver.naif_keywords["INS-533001_TRANSY"]), + np.asarray(naif_keywords["INS-533001_TRANSY"]), + decimal=10) + np.testing.assert_almost_equal(np.asarray(self.driver.naif_keywords["INS-533001_ITRANSS"]), + np.asarray(naif_keywords["INS-533001_ITRANSS"]), + decimal=10) + np.testing.assert_almost_equal(np.asarray(self.driver.naif_keywords["INS-533001_ITRANSL"]), + np.asarray(naif_keywords["INS-533001_ITRANSL"]), + decimal=10) + bodvrd.assert_called_with('Moon', 'RADII', 3)