Skip to content

Commit

Permalink
Merge branch '221-ajout-structure-de-classe-geomodel-aggregeant-grid-…
Browse files Browse the repository at this point in the history
…et-rpc' into 'master'

Resolve "Ajout Structure de Classe GeoModel aggrégeant Grid et RPC"

Closes #221

See merge request 3d/shareloc!126
  • Loading branch information
duboise-cnes committed Dec 1, 2023
2 parents a359048 + bf9df23 commit 528aa38
Show file tree
Hide file tree
Showing 21 changed files with 839 additions and 588 deletions.
2 changes: 1 addition & 1 deletion .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ ignore-on-opaque-inference=yes
# List of class names for which member attributes should not be checked (useful
# for classes with dynamically set attributes). This supports the use of
# qualified names.
ignored-classes=optparse.Values,thread._local,_thread._local
ignored-classes=optparse.Values,thread._local,_thread._local, GeoModel

# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
Expand Down
4 changes: 2 additions & 2 deletions docs/source/getting_started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ Quick Start
$ python3
>>> # Import shareloc modules rpc and localization
>>> from shareloc.geomodels.rpc import RPC
>>> from shareloc.geomodels import GeoModel
>>> from shareloc.geofunctions.localization import Localization
>>> # Create RPC object from downloaded geometry file
>>> rpc_geom_file = "left_image.geom"
>>> rpc = RPC.from_any(rpc_geom_file)
>>> rpc = GeoModel(rpc_geom_file, "rpc") # "rpc" is the geomodel type in ("rpc", "grid") with default value "rpc"
>>> # Create Localization object from created RPC
>>> loc = Localization(rpc)
Expand Down
6 changes: 0 additions & 6 deletions docs/source/user_manual_conventions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,6 @@ Geometric model convention for coordinates is, by default, [0.5,0.5] at the cent

pixel convention

When dealing with shareloc RPC (``shareloc.geomodels.rpc.RPC``), the center at [0,0] can be changed by setting the ``topleftconvention`` option to ``False``.

.. code-block:: bash
@classmethod
def from_any(cls, primary_file, secondary_file=None, topleftconvention=True):

Image convention
================
Expand Down
14 changes: 7 additions & 7 deletions docs/source/user_manual_functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ It is possible to use geometric model directly using ``shareloc.grid.Grid`` and
"""
constructor
:param model : geometric model
:type model : shareloc.grid or shareloc.rpc
:type model : GeoModelTemplate
:param elevation : dtm or default elevation over ellipsoid if None elevation is set to 0
:type elevation : shareloc.dtm or float or np.ndarray
:param image : image class to handle geotransform
Expand Down Expand Up @@ -108,9 +108,9 @@ colocalization returns image positions (row2,col2) in image 2 from (row1,col1) p
Colocalization : direct localization with model1, then inverse localization with model2
:param model1: geometric model 1
:type model1: shareloc.grid or shareloc.rpc
:type model1: GeomodelTemplate
:param model2: geometric model 2
:type model2: shareloc.grid or shareloc.rpc
:type model2: GeomodelTemplate
:param row: sensor row
:type row: int or 1D numpy array
:param col: sensor col
Expand Down Expand Up @@ -163,9 +163,9 @@ where :math:`v_i` is the orientation of the :term:`LOS` i and :math:`s_i` the ha
:param matches : matches in sensor coordinates Nx[row (left), col (left), row (right), col (right)]
:type matches : np.array
:param geometrical_model_left : left image geometrical model
:type geometrical_model_left : shareloc.grid or shareloc.rpc
:type geometrical_model_left : GeomodelTemplate
:param geometrical_model_right : right image geometrical model
:type geometrical_model_right : shareloc.grid or shareloc.rpc
:type geometrical_model_right : GeomodelTemplate
:param left_min_max : left min/max for los creation, if None model min/max will be used
:type left_min_max : list
:param right_min_max : right min/max for los creation, if None model min/max will be used
Expand Down Expand Up @@ -207,11 +207,11 @@ Algorithm details can be found in reference below.
:param left_im: left image
:type left_im: shareloc.image object
:param geom_model_left: geometric model of the left image
:type geom_model_left: shareloc.grid or shareloc.rpc
:type geom_model_left: GeomodelTemplate
:param right_im: right image
:type right_im: shareloc.image object
:param geom_model_right: geometric model of the right image
:type geom_model_right: shareloc.grid or shareloc.rpc
:type geom_model_right: GeomodelTemplate
:param elevation: elevation
:type elevation: shareloc.dtm or float
:param epi_step: epipolar step
Expand Down
8 changes: 4 additions & 4 deletions docs/source/user_manual_geometric_models.rst
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ RPC class API Example
$ wget https://raw.githubusercontent.com/CNES/shareloc/tests/data/rpc/RPC_PHR1B_P_201709281038393_SEN_PRG_FC_178609-001.XML
$ python3
>>> from shareloc.geomodels.rpc import RPC
>>> from shareloc.geomodels import GeoModel
>>> file_dimap = "RPC_PHR1B_P_201709281038393_SEN_PRG_FC_178609-001.XML")
>>> rpc_dimap = RPC.from_any(file_dimap)
>>> rpc_dimap = GeoModel(file_dimap, "rpc")
Direct location grids
Expand Down Expand Up @@ -140,9 +140,9 @@ Grid API Example
$ wget https://raw.githubusercontent.com/CNES/shareloc/tests/data/ellipsoide/loc_direct_grid_PHR_2013072139303958CP.tif
$ python3
>>> from shareloc.geomodels.grid import Grid
>>> from shareloc.geomodels import GeoModel
>>> geotiff_grid_path = "loc_direct_grid_PHR_2013072139303958CP.tif"
>>> geotiff_grid = Grid(geotiff_grid_path)
>>> geotiff_grid = GeoModel(geotiff_grid_path, "grid")
References
__________
Expand Down
14 changes: 8 additions & 6 deletions shareloc/geofunctions/localization.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@ def __init__(self, model, elevation=None, image=None, epsg=None):
Localization constructor
:param model: geometric model
:type model: shareloc.grid or shareloc.rpc
:type model: GeomodelTemplate
:param elevation: dtm or default elevation over ellipsoid if None elevation is set to 0
:type elevation: shareloc.dtm or float or np.ndarray
:param image: image class to handle geotransform
:type image: shareloc.image.Image
:param epsg: coordinate system of world points, if None model coordiante system will be used
:type epsg: int
"""
self.use_rpc = model.type == "rpc"
self.use_rpc = model.type == "RPC"
self.model = model
self.default_elevation = 0.0
self.dtm = None
Expand Down Expand Up @@ -136,8 +136,10 @@ def inverse(self, lon, lat, h=None, using_geotransform=False):
:rtype: Tuple(1D np.ndarray row position, 1D np.ndarray col position, 1D np.ndarray alt)
"""

if not self.use_rpc and not hasattr(self.model, "pred_ofset_scale_lon"):
self.model.estimate_inverse_loc_predictor()
if not self.use_rpc:
# for grids only
if self.model.pred_ofset_scale_lon is None:
self.model.estimate_inverse_loc_predictor()
if h is None:
h = self.default_elevation

Expand Down Expand Up @@ -166,9 +168,9 @@ def coloc(model1, model2, row, col, elevation=None, image1=None, image2=None, us
Colocalization : direct localization with model1, then inverse localization with model2
:param model1: geometric model 1
:type model1: shareloc.grid or shareloc.rpc
:type model1: GeomodelTemplate
:param model2: geometric model 2
:type model2: shareloc.grid or shareloc.rpc
:type model2: GeomodelTemplate
:param row: sensor row
:type row: int or 1D numpy array
:param col: sensor col
Expand Down
20 changes: 10 additions & 10 deletions shareloc/geofunctions/rectification.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,9 @@ def compute_local_epipolar_line(geom_model_left, geom_model_right, left_point, e
Estimate the beginning and the ending of local epipolar line in left image
:param geom_model_left: geometric model of the left image
:type geom_model_left: shareloc.grid or shareloc.rpc
:type geom_model_left: GeomodelTemplate
:param geom_model_right: geometric model of the right image
:type geom_model_right: shareloc.grid or shareloc.rpc
:type geom_model_right: GeomodelTemplate
:param left_point: georeferenced coordinates in the left image
:type left_point: 1D numpy array : [row coord, col coord, altitude]
or 2D numpy array : (number of points, [row coord, col coord, altitude])
Expand Down Expand Up @@ -159,9 +159,9 @@ def prepare_rectification(left_im, geom_model_left, geom_model_right, elevation,
:param left_im: left image
:type left_im: shareloc.image object
:param geom_model_left: geometric model of the left image
:type geom_model_left: shareloc.grid or shareloc.rpc
:type geom_model_left: GeomodelTemplate
:param geom_model_right: geometric model of the right image
:type geom_model_right: shareloc.grid or shareloc.rpc
:type geom_model_right: GeomodelTemplate
:param elevation: elevation
:type elevation: shareloc.dtm or float
:param epi_step: epipolar step
Expand Down Expand Up @@ -269,9 +269,9 @@ def get_epipolar_extent(
:param left_im: left image
:type left_im: shareloc.image object
:param geom_model_left: geometric model of the left image
:type geom_model_left: shareloc.grid or shareloc.rpc
:type geom_model_left: GeomodelTemplate
:param geom_model_right: geometric model of the right image
:type geom_model_right: shareloc.grid or shareloc.rpc
:type geom_model_right: GeomodelTemplate
:param elevation: elevation
:type elevation: shareloc.dtm or float
:param epi_step: epipolar step
Expand Down Expand Up @@ -333,9 +333,9 @@ def moving_along_axis(
Moving to the next line in epipolar geometry
:param geom_model_left: geometric model of the left image
:type geom_model_left: shareloc.grid or shareloc.rpc
:type geom_model_left: GeomodelTemplate
:param geom_model_right: geometric model of the right image
:type geom_model_right: shareloc.grid or shareloc.rpc
:type geom_model_right: GeoModelTemplate
:param current_coords: current line in the left epipolar geometry
or current georeferenced coordinates in left epipolar line
:type current_coords: 1D np.array [row, col, altitude]
Expand Down Expand Up @@ -389,11 +389,11 @@ def compute_stereorectification_epipolar_grids(
:param left_im: left image
:type left_im: shareloc.image object
:param geom_model_left: geometric model of the left image
:type geom_model_left: shareloc.grid or shareloc.rpc
:type geom_model_left: GeomodelTemplate
:param right_im: right image
:type right_im: shareloc.image object
:param geom_model_right: geometric model of the right image
:type geom_model_right: shareloc.grid or shareloc.rpc
:type geom_model_right: GeomodelTemplate
:param elevation: elevation
:type elevation: shareloc.dtm or float
:param epi_step: epipolar step
Expand Down
2 changes: 1 addition & 1 deletion shareloc/geofunctions/rectification_grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def __init__(self, grid_filename):
:param grid_filename: grid filename
:type filename: string
"""
self.filename = grid_filename
self.grid_filename = grid_filename

dataset = rio.open(grid_filename)

Expand Down
8 changes: 4 additions & 4 deletions shareloc/geofunctions/triangulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ def sensor_triangulation(
:param matches: matches in sensor coordinates Nx[row (left), col (left), row (right), col (right)]
:type matches: np.array
:param geometrical_model_left: left image geometrical model
:type geometrical_model_left: shareloc.grid or shareloc.rpc
:type geometrical_model_left: GeomodelTemplate
:param geometrical_model_right: right image geometrical model
:type geometrical_model_right: shareloc.grid or shareloc.rpc
:type geometrical_model_right: GeomodelTemplate
:param left_min_max: left min/max for los creation, if None model min/max will be used
:type left_min_max: list
:param right_min_max: right min/max for los creation, if None model min/max will be used
Expand Down Expand Up @@ -190,9 +190,9 @@ def epipolar_triangulation(
:param matches_type: 'disp' or 'sift'
:type matches_type: str
:param geometrical_model_left: left image geometrical model
:type geometrical_model_left: shareloc.grid or shareloc.rpc
:type geometrical_model_left: GeomodelTemplate
:param geometrical_model_right: right image geometrical model
:type geometrical_model_right: shareloc.grid or shareloc.rpc
:type geometrical_model_right: GeomodelTemplate
:param grid_left: left rectification grid filename
:type grid_left: str
:param grid_right: right rectification grid filename
Expand Down
8 changes: 7 additions & 1 deletion shareloc/geomodels/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env python
# coding: utf8
#
# Copyright (c) 2022 Centre National d'Etudes Spatiales (CNES).
# Copyright (c) 2023 Centre National d'Etudes Spatiales (CNES).
#
# This file is part of Shareloc
# (see https://github.com/CNES/shareloc).
Expand All @@ -20,4 +20,10 @@
#
"""
Shareloc geomodels module
Imports are used to simplify calls to module API Coregistration.
"""
# Demcompare imports
from . import grid, rpc
from .geomodel import GeoModel

__all__ = ["rpc", "grid", "GeoModel"] # To avoid flake8 F401
116 changes: 116 additions & 0 deletions shareloc/geomodels/geomodel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#!/usr/bin/env python
# coding: utf8
#
# Copyright (c) 2023 Centre National d'Etudes Spatiales (CNES).
#
# This file is part of shareloc
# (see https://github.com/CNES/shareloc).
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""
This module contains the GeoModel class factory.
This main API GeoModel class generates an object linked
with geomodel configuration "geomodel_name"
(from registered GeoModelTemplate class)
** Experimental and not used as API for now**
** Will be used with an automatic switcher between Grid file format and
RPC file format obj = GeoModel("file_geom") only without geomodel_type
"""

# Standard imports
import logging
from typing import Any, Dict


class GeoModel:
"""
GeoModel factory:
A class designed for registered all available geomodels
and instantiate them when needed.
"""

# Dict (geomodel_name: str, class: object) containing registered geomodels
available_geomodels: Dict[str, Any] = {}

def __new__(cls, geomodel_path: str, geomodel_type: str = "RPC"):
"""
Return a GeoModelTemplate child instance
associated with the "geomodel_name" given in the configuration
through create_geomodel local method for clarity.
TODO: optional geomodel_type would profit to have an automatic switcher between geomodels (RPC, grids, ...)
:param geomodel_path: Path of geomodel file
:type geomodel_path: string
:param geomodel_type: Type of the geomodel, default "rpc", used as key for specific geomodel subclass instance
:type geomodel_type: string
"""
return cls.create_geomodel(geomodel_path, geomodel_type)

@classmethod
def create_geomodel(cls, geomodel_path: str, geomodel_type: str = "RPC"):
"""
Factory command to create the geomodel from geomodel_type
Return a GeoModelTemplate child instance
associated with the "geomodel_type"
:param geomodel_path: Path of geomodel file
:type geomodel_path: string
:param geomodel_type: Type of the geomodel, default "rpc", used as key for specific geomodel subclass instance
:type geomodel_type: string
"""

# If no type is given, the default is "RPC"

# Create geomodel object with geomodel_path parameter from geomodel_type if exists
try:
geomodel_class = cls.available_geomodels[geomodel_type]
geomodel = geomodel_class.load(geomodel_path)
logging.debug("GeoModel type name: %s", geomodel_type)
except KeyError:
logging.error("Geomodel type named %s is not supported", geomodel_type)
raise

return geomodel

@classmethod
def print_avalaible_geomodels(cls):
"""
Print all registered applications
"""
for geomodel_type in cls.available_geomodels:
print(geomodel_type)

@classmethod
def register(cls, geomodel_type: str):
"""
Allows to register the GeoModelTemplate subclass in the factory
with its geomodel geomodel_type through decorator
:param geomodel_type: the subclass name to be registered
:type geomodel_type: string
"""

def decorator(geomodel_subclass):
"""
Register the geomodel subclass in the available methods
:param geomodel_subclass: the subclass to be registered
:type geomodel_subclass: object
"""
cls.available_geomodels[geomodel_type] = geomodel_subclass
return geomodel_subclass

return decorator
Loading

0 comments on commit 528aa38

Please sign in to comment.