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

add enmap reader #21

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
59 changes: 59 additions & 0 deletions rpcm/rpc_file_readers.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ def read_rpc_xml(rpc_content):
# determine wether it's a pleiades, spot-6 or worldview image
a = tree.find('Metadata_Identification/METADATA_PROFILE') # PHR_SENSOR
b = tree.find('IMD/IMAGE/SATID') # WorldView
c = tree.find('specific/mission')
parsed_rpc = None
if a is not None:
if a.text in ['PHR_SENSOR', 'S6_SENSOR', 'S7_SENSOR']:
Expand All @@ -107,6 +108,9 @@ def read_rpc_xml(rpc_content):
elif b is not None:
if b.text == 'WV02' or b.text == 'WV01' or b.text == 'WV03':
parsed_rpc = read_rpc_xml_worldview(tree)
elif c is not None:
if c.text == 'EnMAP':
parsed_rpc = read_rpc_xml_enmap(tree)

if not parsed_rpc:
raise NotImplementedError()
Expand Down Expand Up @@ -253,6 +257,7 @@ def read_rpc_xml_worldview(tree):
dictionary read from the RPC file, or empty dict in case of failure

"""

m = {}

# inverse model (PROJECTION)
Expand Down Expand Up @@ -286,3 +291,57 @@ def read_rpc_xml_worldview(tree):
# m.lastCol = int(tree.find('IMD/NUMCOLUMNS').text)

return m


def read_rpc_xml_enmap(tree):
"""
Read RPC fields from a parsed XML tree assuming the EnMAP XML format.
This reader works for L1B, L1C and L2A products.

Args:
tree: parsed XML tree

Returns:
dictionary of models (dictionnaries) read from the RPC file, or empty dict in case of failure.
There is one model per band, the bands numbers correspond to dictionnary keys.

"""

def parse_coeff(element, prefix, indices):
""" helper function"""
return ' '.join([element.find(prefix+"_" + "{:02d}".format(x)).text for x in indices])

m = {}

# direct model (LOCALIZATION), there is 1 model per band
rpc_models = tree.find('product/navigation/RPC').findall("bandID")
n_bands = len(rpc_models)

for band_id in range(1, n_bands+1):
m[str(band_id)] = {}
model = {}
band = band_id - 1

model['LINE_OFF' ] = float(rpc_models[band].find('ROW_OFF').text)
model['SAMP_OFF' ] = float(rpc_models[band].find('COL_OFF').text)
model['LAT_OFF' ] = float(rpc_models[band].find('LAT_OFF').text)
model['LONG_OFF' ] = float(rpc_models[band].find('LONG_OFF').text)
model['HEIGHT_OFF' ] = float(rpc_models[band].find('HEIGHT_OFF').text)

model['LINE_SCALE' ] = float(rpc_models[band].find('ROW_SCALE').text)
model['SAMP_SCALE' ] = float(rpc_models[band].find('COL_SCALE').text)
model['LAT_SCALE' ] = float(rpc_models[band].find('LAT_SCALE').text)
model['LONG_SCALE' ] = float(rpc_models[band].find('LONG_SCALE').text)
model['HEIGHT_SCALE'] = float(rpc_models[band].find('HEIGHT_SCALE').text)

model['LINE_NUM_COEFF'] = parse_coeff(rpc_models[band], "ROW_NUM", range(1, 21))
model['LINE_DEN_COEFF'] = parse_coeff(rpc_models[band], "ROW_DEN", range(1, 21))
model['SAMP_NUM_COEFF'] = parse_coeff(rpc_models[band], "COL_NUM", range(1, 21))
model['SAMP_DEN_COEFF'] = parse_coeff(rpc_models[band], "COL_DEN", range(1, 21))

m[str(band_id)] = model

return m



23 changes: 22 additions & 1 deletion tests/test_rpc_file_parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

import pytest

from rpcm import rpc_from_rpc_file
from rpcm.rpc_model import rpc_from_rpc_file, RPCModel
from rpcm.rpc_file_readers import read_rpc_file

here = os.path.abspath(os.path.dirname(__file__))
files_dir = os.path.join(here, "test_rpc_files")
Expand All @@ -25,6 +26,16 @@ def supported_files():
return [os.path.join(files_dir, filename) for filename in filenames]


def supported_file_multi_model():
"""
Gives the list of files that should be correctly
parsed by `rpc_from_rpc_file` returning multiple RPC models
"""
filenames = ["ENMAP01-____L1B-DT0000001011_20220609T081225Z_001_V010111_20230119T143357Z-METADATA.XML"]

return [os.path.join(files_dir, filename) for filename in filenames]


def unsupported_files():
"""
Gives the list of files that `rpc_from_rpc_file` should not be
Expand All @@ -43,6 +54,16 @@ def test_successful_rpc_file_parsing(filepath):
rpc_from_rpc_file(filepath)


@pytest.mark.parametrize("filepath", supported_file_multi_model())
def test_successful_rpc_file_parsing_multi_model(filepath):
"""
Check that filepath can be parsed without errors being raised
"""
rpc = read_rpc_file(filepath)
assert len(rpc.keys()) > 1
model = RPCModel(rpc["1"])


@pytest.mark.parametrize("filepath", unsupported_files())
def test_failing_rpc_file_parsing(filepath):
"""
Expand Down
Loading