From 1b5d7265b25d7d38af0a55c2c5cd57bb2cba35ae Mon Sep 17 00:00:00 2001 From: Jay Date: Fri, 5 Apr 2024 17:23:39 -0500 Subject: [PATCH] Adds create from state support --- CHANGELOG.md | 1 + knoten/csm.py | 61 +++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 48 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 51cb0da..82ebe84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ release. ## Unreleased ### Added +- `create_csm` now dispatches to `_from_isd` and `_from_state` to test whether the sensor model can be instantiated from either and ISD or a state file. - `generate_image_coordinate` to `csm.py`. This provides a similar interface to `generate_ground_coordinate` and abstracts away the `csmapi` from the user. - A surface class (moved from AutoCNet; credit @jessemapel) with support for Ellipsoid DEMs and basic support for raster DEMs readable by the plio.io.io_gdal.GeoDataset. Support is basic because it uses a single pixel intersection and not an interpolated elevation like ISIS does. - A check to `generate_ground_point` when a GeoDataset is used to raise a `ValueError` if the algorithm intersects a no data value in the passed DEM. This ensures that valid heights are used in the intersection computation. Fixes [#120](https://github.com/DOI-USGS/knoten/issues/120) diff --git a/knoten/csm.py b/knoten/csm.py index da04ae9..9912283 100644 --- a/knoten/csm.py +++ b/knoten/csm.py @@ -74,22 +74,26 @@ def create_camera(label, url='http://pfeffer.wr.usgs.gov/api/1.0/pds/'): model = plugin.constructModelFromISD(isd, model_name) return model -def create_csm(image, verbose=False): - """ - Given an image file, create a Community Sensor Model. +def _from_state(state, verbose): + with open(state, 'r') as stream: + model_name = stream.readline().rstrip() + state = json.load(stream) + state = json.dumps(state) - Parameters - ---------- - image : str - The image filename to create a CSM for - verbose : bool - Print information about which plugins and models were attempted + plugins = csmapi.Plugin.getList() + for plugin in plugins: + if verbose: + print(f'Trying plugin {plugin.getPluginName()}') + if plugin.canModelBeConstructedFromState(model_name, state): + camera_warnings = csmapi.WarningList() + camera = plugin.constructModelFromState(state, camera_warnings) + if verbose: + for warning in camera_warnings: + print(f'Warning in function {warning.getFunction()}: "{warning.getMessage()}"') + print('Success!') + return plugin.constructModelFromState(state) - Returns - ------- - model : object - A CSM sensor model (or None if no associated model is available.) - """ +def _from_isd(image, verbose): isd = csmapi.Isd(image) plugins = csmapi.Plugin.getList() for plugin in plugins: @@ -113,6 +117,34 @@ def create_csm(image, verbose=False): for warning in warnings: print(f'Warning in function {warning.getFunction()}: "{warning.getMessage()}"') print('Failed!') + raise TypeError('NoneType is not a sensor model.') + +def create_csm(image, verbose=False): + """ + Given an image file, create a Community Sensor Model. + + Parameters + ---------- + image : str + The image filename to create a CSM for + verbose : bool + Print information about which plugins and models were attempted + + Returns + ------- + model : object + A CSM sensor model (or None if no associated model is available.) + """ + try: + return _from_isd(image, verbose=verbose) + except: + if verbose: + print('Unable to instantiate CSM from ISD') + try: + return _from_state(image, verbose=verbose) + except: + if verbose: + print('Unable to instantiate CSM from state file.') @singledispatch def generate_ground_point(dem, image_pt, camera): @@ -551,3 +583,4 @@ def triangulate_ground_pt(cameras, image_pts): M[2] += look[2] * look - look_squared * unit_z b += np.dot(pos, look) * look - look_squared * pos return tuple(np.dot(np.linalg.inv(M), b)) +