Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added projection code #524

Merged
merged 8 commits into from
Apr 3, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions ale/base/base.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import pvl
import json

import tempfile
import os

class Driver():
"""
Base class for all Drivers.
Expand Down Expand Up @@ -323,3 +326,60 @@ def center_ephemeris_time(self):
@property
def short_mission_name(self):
return self.__module__.split('.')[-1].split('_')[0]

@property
def projection(self):
if not hasattr(self, "_projection"):
try:
from osgeo import gdal
except:
self._projection = None
return self._projection
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Localized the import to keep the optional gdal stuff in one location without complicating things by adding some gdal module or something.


if isinstance(self._file, pvl.PVLModule):
# save it to a temp folder
with tempfile.NamedTemporaryFile() as tmp:
tmp.write(pvl.dumps(self._file))

geodata = gdal.Open(tempfile.name)
self._projection = geodata.GetSpatialRef()
else:
# should be a path
if not os.path.exists(self._file):
self._projection = None
else:
geodata = gdal.Open(self._file)
self._projection = geodata.GetSpatialRef()

# is None if not projected
if self._projection:
self._projection = self._projection.ExportToProj4()

return self._projection


@property
def geotransform(self):
if not hasattr(self, "_geotransform"):
try:
from osgeo import gdal
except:
self._geotransform = (0.0, 1.0, 0.0, 0.0, 0.0, 1.0)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Im preeeetty sure this is the identity, probably good as a default.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that should identity for GDAL. https://github.com/OSGeo/gdal/blob/c642af0722d43bb337aaf86293129dbed576e534/alg/gdaltransformer.cpp#L1847

But just a warning, this is not same order for all packages.

return self._geotransform

if isinstance(self._file, pvl.PVLModule):
# save it to a temp folder
with tempfile.NamedTemporaryFile() as tmp:
tmp.write(pvl.dumps(self._file))

geodata = gdal.Open(tempfile.name)
self._geotransform = geodata.GetGeoTransform()
else:
# should be a path
if not os.path.exists(self._file):
self._geotransform = (0.0, 1.0, 0.0, 0.0, 0.0, 1.0)
else:
geodata = gdal.Open(self._file)
self._geotransform = geodata.GetGeoTransform()

return self._geotransform
3 changes: 3 additions & 0 deletions ale/formatters/usgscsm_formatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ def to_usgscsm(driver):
'unit' : 'm'
}

isd_data["projection"] = driver.projection
isd_data["geotransform"] = driver.geotransform
acpaquette marked this conversation as resolved.
Show resolved Hide resolved

acpaquette marked this conversation as resolved.
Show resolved Hide resolved
# shared isd keywords for Framer and Linescanner
if isinstance(driver, LineScanner) or isinstance(driver, Framer):
# exterior orientation for just Framer and LineScanner
Expand Down
1 change: 1 addition & 0 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ dependencies:
- cmake>=3.15
- pytest
- eigen
- gdal
- jupyter
- nlohmann_json
- numpy
Expand Down
4 changes: 3 additions & 1 deletion recipe/meta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ requirements:
- scipy >=1.4.0
- spiceypy >=4.0.1
- pyyaml

run_contrained:
- gdal
Comment on lines +34 to +35
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will only install if it can do so without conflicts. important to co-install with ISIS.


test:
imports:
- ale
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,25 @@ Object = IsisCube
Source = isis
End_Group

Group = Mapping
ProjectionName = Sinusoidal
CenterLongitude = 148.36859083039
TargetName = MARS
Comment on lines +72 to +75
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just kinda shoved a projection into an MRO image for testing, I imagine the same to what a real image is like.

EquatorialRadius = 3396190.0 <meters>
PolarRadius = 3376200.0 <meters>
LatitudeType = Planetocentric
LongitudeDirection = PositiveEast
LongitudeDomain = 360
MinimumLatitude = 63.636322793577
MaximumLatitude = 87.296295823424
MinimumLongitude = 139.6658284858
MaximumLongitude = 157.07135317498
UpperLeftCornerX = -219771.1526456 <meters>
UpperLeftCornerY = 5175537.8728989 <meters>
PixelResolution = 1455.4380969907 <meters/pixel>
Scale = 40.726361118253 <pixels/degree>
End_Group

Group = AlphaCube
AlphaSamples = 5000
AlphaLines = 24576
Expand Down
2 changes: 0 additions & 2 deletions tests/pytests/test_load.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,10 @@ def test_load_mes_from_metakernels(tmpdir, monkeypatch, mess_kernels):
mk_file.write(mk_str)

usgscsm_isd_obj = ale.load(label_file, verbose=True)

assert usgscsm_isd_obj['name_platform'] == 'MESSENGER'
assert usgscsm_isd_obj['name_sensor'] == 'MERCURY DUAL IMAGING SYSTEM NARROW ANGLE CAMERA'
assert usgscsm_isd_obj['name_model'] == 'USGS_ASTRO_FRAME_SENSOR_MODEL'


def test_load_mes_with_no_metakernels(tmpdir, monkeypatch, mess_kernels):
monkeypatch.setenv('ALESPICEROOT', str(tmpdir))

Expand Down
4 changes: 3 additions & 1 deletion tests/pytests/test_mex_drivers.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,9 @@ def usgscsm_compare_dict():
"t0_ephemeris": -101.83713859319687,
"dt_ephemeris": 40.734855437278746,
"t0_quaternion": -101.83713859319687,
"dt_quaternion": 40.734855437278746
"dt_quaternion": 40.734855437278746,
"projection" : None,
"geotransform" : (0.0, 1.0, 0.0, 0.0, 0.0, 1.0)
},

"isis" :
Expand Down
19 changes: 19 additions & 0 deletions tests/pytests/test_usgscsm_formatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
from ale.base.data_naif import NaifSpice
from ale.rotation import ConstantRotation, TimeDependentRotation

from conftest import get_image_label

class TestDriver(Driver, NaifSpice):
"""
Test Driver implementation with dummy values
Expand Down Expand Up @@ -342,3 +344,20 @@ def test_line_scan_sun_position(test_line_scan_driver):
assert sun_position_obj['positions'] == [[0, 1, 2], [3, 4, 5]]
assert sun_position_obj['velocities'] == [[0, -1, -2], [-3, -4, -5]]
assert sun_position_obj['unit'] == 'm'

def test_no_projection(test_frame_driver):
isd = usgscsm_formatter.to_usgscsm(test_frame_driver)
# isn't using real projection so it should be None
assert isd['projection'] == None

def test_isis_projection():
isd = usgscsm_formatter.to_usgscsm(TestLineScanner(get_image_label('B10_013341_1010_XN_79S172W', "isis3")))
assert isd["projection"] == "+proj=sinu +lon_0=148.36859083039 +x_0=0 +y_0=0 +R=3396190 +units=m +no_defs"


def test_isis_geotransform():
isd = usgscsm_formatter.to_usgscsm(TestLineScanner(get_image_label('B10_013341_1010_XN_79S172W', "isis3")))
expected = (-219771.1526456, 1455.4380969907, 0.0, 5175537.8728989, 0.0, -1455.4380969907)
for value, truth in zip(isd["geotransform"], expected):
pytest.approx(value, truth)