From 4e9aadfaec3f41e1caa8e93c89b53fad3d421c76 Mon Sep 17 00:00:00 2001 From: David de Meij Date: Thu, 7 Jul 2022 08:57:59 +0200 Subject: [PATCH 1/3] Bump version to v1.4.8 --- rpcm/__about__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpcm/__about__.py b/rpcm/__about__.py index 6a80bee..5a3a800 100644 --- a/rpcm/__about__.py +++ b/rpcm/__about__.py @@ -1,6 +1,6 @@ __title__ = "rpcm" __description__ = "Rational Polynomial Camera Model for optical satellite images." __url__ = 'https://github.com/centreborelli/rpcm' -__version__ = "1.4.7" +__version__ = "1.4.8" __author__ = "Carlo de Franchis" __author_email__ = 'carlo.de-franchis@ens-paris-saclay.fr' From b80c78d272eea2fe639acf3c01ced76d21d6c42d Mon Sep 17 00:00:00 2001 From: Tim <35193581+tonzowonzo@users.noreply.github.com> Date: Tue, 28 Mar 2023 16:50:08 +0200 Subject: [PATCH 2/3] Adding neo/pleiades image bounds reading to rpcs (#2) * Adding neo/pleiades image bounds reading to rpcs --------- Co-authored-by: David de Meij --- rpcm/rpc_file_readers.py | 282 +++++++++++++++++---------------------- 1 file changed, 123 insertions(+), 159 deletions(-) diff --git a/rpcm/rpc_file_readers.py b/rpcm/rpc_file_readers.py index 5aa975a..bd983c7 100644 --- a/rpcm/rpc_file_readers.py +++ b/rpcm/rpc_file_readers.py @@ -1,8 +1,6 @@ # Copyright (C) 2015-19, Carlo de Franchis # Copyright (C) 2015-19, Gabriele Facciolo # Copyright (C) 2015-19, Enric Meinhardt - - from xml.etree import ElementTree @@ -11,99 +9,77 @@ def read_rpc_file(rpc_file): Read RPC from a file deciding the format from the extension of the filename. xml : spot6, pleiades, worldview txt (others) : ikonos - Args: rpc_file: RPC sidecar file path - Returns: dictionary read from the RPC file, or an empty dict if fail - """ - with open(rpc_file) as f: rpc_content = f.read() - - if rpc_file.lower().endswith('xml'): + if rpc_file.lower().endswith("xml"): try: rpc = read_rpc_xml(rpc_content) except NotImplementedError: - raise NotImplementedError('XML file {} not supported'.format(rpc_file)) + raise NotImplementedError("XML file {} not supported".format(rpc_file)) else: # we assume that non xml rpc files follow the ikonos convention rpc = read_rpc_ikonos(rpc_content) - return rpc def read_rpc_ikonos(rpc_content): """ Read RPC file assuming the ikonos format - Args: rpc_content: content of RPC sidecar file path read as a string - Returns: dictionary read from the RPC file - """ import re - - lines = rpc_content.split('\n') - + lines = rpc_content.split("\n") d = {} for l in lines: ll = l.split() if len(ll) > 1: k = re.sub(r"[^a-zA-Z0-9_]","",ll[0]) d[k] = ll[1] - def parse_coeff(dic, prefix, indices): """ helper function""" - return ' '.join([dic["%s_%s" % (prefix, str(x))] for x in indices]) - - d['SAMP_NUM_COEFF'] = parse_coeff(d, "SAMP_NUM_COEFF", range(1, 21)) - d['SAMP_DEN_COEFF'] = parse_coeff(d, "SAMP_DEN_COEFF", range(1, 21)) - d['LINE_NUM_COEFF'] = parse_coeff(d, "LINE_NUM_COEFF", range(1, 21)) - d['LINE_DEN_COEFF'] = parse_coeff(d, "LINE_DEN_COEFF", range(1, 21)) + return " ".join([dic["%s_%s" % (prefix, str(x))] for x in indices]) + d["SAMP_NUM_COEFF"] = parse_coeff(d, "SAMP_NUM_COEFF", range(1, 21)) + d["SAMP_DEN_COEFF"] = parse_coeff(d, "SAMP_DEN_COEFF", range(1, 21)) + d["LINE_NUM_COEFF"] = parse_coeff(d, "LINE_NUM_COEFF", range(1, 21)) + d["LINE_DEN_COEFF"] = parse_coeff(d, "LINE_DEN_COEFF", range(1, 21)) return d - def read_rpc_xml(rpc_content): """ - Read RPC file assuming the XML format and determine whether it's a pleiades, spot-6 or worldview image - + Read RPC file assuming the XML format and determine whether it’s a pleiades, spot-6 or worldview image Args: rpc_content: content of RPC sidecar file path read as a string (XML format) - Returns: dictionary read from the RPC file - Raises: NotImplementedError: if the file format is not handled (the expected keys are not found) - """ - # parse the xml file content tree = ElementTree.fromstring(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 + # 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 parsed_rpc = None if a is not None: - if a.text in ['PHR_SENSOR', 'S6_SENSOR', 'S7_SENSOR']: + if a.text in ["PHR_SENSOR", "S6_SENSOR", "S7_SENSOR"]: parsed_rpc = read_rpc_xml_pleiades(tree) - elif a.text in ['PNEO_SENSOR']: + elif a.text in ["PNEO_SENSOR"]: parsed_rpc = read_rpc_xml_pleiades_neo(tree) elif b is not None: - if b.text == 'WV02' or b.text == 'WV01' or b.text == 'WV03': + if b.text == "WV02" or b.text == "WV01" or b.text == "WV03": parsed_rpc = read_rpc_xml_worldview(tree) - if not parsed_rpc: raise NotImplementedError() - return parsed_rpc @@ -111,66 +87,64 @@ def read_rpc_xml_pleiades(tree): """ Read RPC fields from a parsed XML tree assuming the pleiades, spot-6 XML format Also reads the inverse model parameters - Args: tree: parsed XML tree - Returns: dictionary read from the RPC file, or empty dict in case of failure - """ m = {} - + def parse_coeff(element, prefix, indices): - """ helper function""" - return ' '.join([element.find("%s_%s" % (prefix, str(x))).text for x in indices]) - + """ + helper function + """ + return " ".join([element.find("%s_%s" % (prefix, str(x))).text for x in indices]) + # direct model (LOCALIZATION) - d = tree.find('Rational_Function_Model/Global_RFM/Direct_Model') - m['LON_NUM_COEFF'] = parse_coeff(d, "SAMP_NUM_COEFF", range(1, 21)) - m['LON_DEN_COEFF'] = parse_coeff(d, "SAMP_DEN_COEFF", range(1, 21)) - m['LAT_NUM_COEFF'] = parse_coeff(d, "LINE_NUM_COEFF", range(1, 21)) - m['LAT_DEN_COEFF'] = parse_coeff(d, "LINE_DEN_COEFF", range(1, 21)) - #m['ERR_BIAS'] = parse_coeff(d, "ERR_BIAS", ['X', 'Y']) - - + d = tree.find("Rational_Function_Model/Global_RFM/Direct_Model") + m["LON_NUM_COEFF"] = parse_coeff(d, "SAMP_NUM_COEFF", range(1, 21)) + m["LON_DEN_COEFF"] = parse_coeff(d, "SAMP_DEN_COEFF", range(1, 21)) + m["LAT_NUM_COEFF"] = parse_coeff(d, "LINE_NUM_COEFF", range(1, 21)) + m["LAT_DEN_COEFF"] = parse_coeff(d, "LINE_DEN_COEFF", range(1, 21)) + #m["ERR_BIAS"] = parse_coeff(d, "ERR_BIAS", ["X", "Y"]) ## inverse model (PROJECTION) - i = tree.find('Rational_Function_Model/Global_RFM/Inverse_Model') - m['SAMP_NUM_COEFF'] = parse_coeff(i, "SAMP_NUM_COEFF", range(1, 21)) - m['SAMP_DEN_COEFF'] = parse_coeff(i, "SAMP_DEN_COEFF", range(1, 21)) - m['LINE_NUM_COEFF'] = parse_coeff(i, "LINE_NUM_COEFF", range(1, 21)) - m['LINE_DEN_COEFF'] = parse_coeff(i, "LINE_DEN_COEFF", range(1, 21)) - m['ERR_BIAS'] = parse_coeff(i, "ERR_BIAS", ['ROW', 'COL']) - + i = tree.find("Rational_Function_Model/Global_RFM/Inverse_Model") + m["SAMP_NUM_COEFF"] = parse_coeff(i, "SAMP_NUM_COEFF", range(1, 21)) + m["SAMP_DEN_COEFF"] = parse_coeff(i, "SAMP_DEN_COEFF", range(1, 21)) + m["LINE_NUM_COEFF"] = parse_coeff(i, "LINE_NUM_COEFF", range(1, 21)) + m["LINE_DEN_COEFF"] = parse_coeff(i, "LINE_DEN_COEFF", range(1, 21)) + m["ERR_BIAS"] = parse_coeff(i, "ERR_BIAS", ["ROW", "COL"]) # validity domains - v = tree.find('Rational_Function_Model/Global_RFM/RFM_Validity') - #vd = v.find('Direct_Model_Validity_Domain') - #m.firstRow = float(vd.find('FIRST_ROW').text) - #m.firstCol = float(vd.find('FIRST_COL').text) - #m.lastRow = float(vd.find('LAST_ROW').text) - #m.lastCol = float(vd.find('LAST_COL').text) - - #vi = v.find('Inverse_Model_Validity_Domain') - #m.firstLon = float(vi.find('FIRST_LON').text) - #m.firstLat = float(vi.find('FIRST_LAT').text) - #m.lastLon = float(vi.find('LAST_LON').text) - #m.lastLat = float(vi.find('LAST_LAT').text) - + v = tree.find("Rational_Function_Model/Global_RFM/RFM_Validity") + i = tree.find("Rational_Function_Model/Global_RFM/RFM_Validity/Inverse_Model_Validity_Domain") + #vd = v.find("Direct_Model_Validity_Domain") + #m.firstRow = float(vd.find("FIRST_ROW").text) + #m.firstCol = float(vd.find("FIRST_COL").text) + #m.lastRow = float(vd.find("LAST_ROW").text) + #m.lastCol = float(vd.find("LAST_COL").text) + #vi = v.find("Inverse_Model_Validity_Domain") + #m.firstLon = float(vi.find("FIRST_LON").text) + #m.firstLat = float(vi.find("FIRST_LAT").text) + #m.lastLon = float(vi.find("LAST_LON").text) + #m.lastLat = float(vi.find("LAST_LAT").text) # scale and offset # the -1 in line and column offsets is due to Pleiades RPC convention # that states that the top-left pixel of an image has coordinates # (1, 1) - m['LINE_OFF' ] = float(v.find('LINE_OFF').text) - 1 - m['SAMP_OFF' ] = float(v.find('SAMP_OFF').text) - 1 - m['LAT_OFF' ] = float(v.find('LAT_OFF').text) - m['LONG_OFF' ] = float(v.find('LONG_OFF').text) - m['HEIGHT_OFF' ] = float(v.find('HEIGHT_OFF').text) - m['LINE_SCALE' ] = float(v.find('LINE_SCALE').text) - m['SAMP_SCALE' ] = float(v.find('SAMP_SCALE').text) - m['LAT_SCALE' ] = float(v.find('LAT_SCALE').text) - m['LONG_SCALE' ] = float(v.find('LONG_SCALE').text) - m['HEIGHT_SCALE'] = float(v.find('HEIGHT_SCALE').text) - + m["LINE_OFF" ] = float(v.find("LINE_OFF").text) - 1 + m["SAMP_OFF" ] = float(v.find("SAMP_OFF").text) - 1 + m["LAT_OFF" ] = float(v.find("LAT_OFF").text) + m["LONG_OFF" ] = float(v.find("LONG_OFF").text) + m["HEIGHT_OFF" ] = float(v.find("HEIGHT_OFF").text) + m["LINE_SCALE" ] = float(v.find("LINE_SCALE").text) + m["SAMP_SCALE" ] = float(v.find("SAMP_SCALE").text) + m["LAT_SCALE" ] = float(v.find("LAT_SCALE").text) + m["LONG_SCALE" ] = float(v.find("LONG_SCALE").text) + m["HEIGHT_SCALE"] = float(v.find("HEIGHT_SCALE").text) + m["FIRST_LON"] = float(i.find("FIRST_LON").text) + m["FIRST_LAT"] = float(i.find("FIRST_LAT").text) + m["LAST_LON"] = float(i.find("LAST_LON").text) + m["LAST_LAT"] = float(i.find("LAST_LAT").text) return m @@ -184,101 +158,91 @@ def read_rpc_xml_pleiades_neo(tree): dictionary read from the RPC file, or empty dict in case of failure """ m = {} - + def parse_coeff(element, prefix, indices): - """ helper function""" - return ' '.join([element.find("%s_%s" % (prefix, str(x))).text for x in indices]) + """ + helper function + """ + return " ".join([element.find("%s_%s" % (prefix, str(x))).text for x in indices]) + # direct model (LOCALIZATION) - d = tree.find('Rational_Function_Model/Global_RFM/ImagetoGround_Values') - m['LON_NUM_COEFF'] = parse_coeff(d, "LON_NUM_COEFF", range(1, 21)) - m['LON_DEN_COEFF'] = parse_coeff(d, "LON_DEN_COEFF", range(1, 21)) - m['LAT_NUM_COEFF'] = parse_coeff(d, "LAT_NUM_COEFF", range(1, 21)) - m['LAT_DEN_COEFF'] = parse_coeff(d, "LAT_DEN_COEFF", range(1, 21)) - #m['ERR_BIAS'] = parse_coeff(d, "ERR_BIAS", ['X', 'Y']) - - + d = tree.find("Rational_Function_Model/Global_RFM/ImagetoGround_Values") + m["LON_NUM_COEFF"] = parse_coeff(d, "LON_NUM_COEFF", range(1, 21)) + m["LON_DEN_COEFF"] = parse_coeff(d, "LON_DEN_COEFF", range(1, 21)) + m["LAT_NUM_COEFF"] = parse_coeff(d, "LAT_NUM_COEFF", range(1, 21)) + m["LAT_DEN_COEFF"] = parse_coeff(d, "LAT_DEN_COEFF", range(1, 21)) + #m["ERR_BIAS"] = parse_coeff(d, "ERR_BIAS", ["X", "Y"]) ## inverse model (PROJECTION) - i = tree.find('Rational_Function_Model/Global_RFM/GroundtoImage_Values') - m['SAMP_NUM_COEFF'] = parse_coeff(i, "SAMP_NUM_COEFF", range(1, 21)) - m['SAMP_DEN_COEFF'] = parse_coeff(i, "SAMP_DEN_COEFF", range(1, 21)) - m['LINE_NUM_COEFF'] = parse_coeff(i, "LINE_NUM_COEFF", range(1, 21)) - m['LINE_DEN_COEFF'] = parse_coeff(i, "LINE_DEN_COEFF", range(1, 21)) - m['ERR_BIAS'] = parse_coeff(i, "ERR_BIAS", ['ROW', 'COL']) - + i = tree.find("Rational_Function_Model/Global_RFM/GroundtoImage_Values") + m["SAMP_NUM_COEFF"] = parse_coeff(i, "SAMP_NUM_COEFF", range(1, 21)) + m["SAMP_DEN_COEFF"] = parse_coeff(i, "SAMP_DEN_COEFF", range(1, 21)) + m["LINE_NUM_COEFF"] = parse_coeff(i, "LINE_NUM_COEFF", range(1, 21)) + m["LINE_DEN_COEFF"] = parse_coeff(i, "LINE_DEN_COEFF", range(1, 21)) + m["ERR_BIAS"] = parse_coeff(i, "ERR_BIAS", ["ROW", "COL"]) # validity domains - v = tree.find('Rational_Function_Model/Global_RFM/RFM_Validity') - #vd = v.find('Direct_Model_Validity_Domain') - #m.firstRow = float(vd.find('FIRST_ROW').text) - #m.firstCol = float(vd.find('FIRST_COL').text) - #m.lastRow = float(vd.find('LAST_ROW').text) - #m.lastCol = float(vd.find('LAST_COL').text) - - #vi = v.find('Inverse_Model_Validity_Domain') - #m.firstLon = float(vi.find('FIRST_LON').text) - #m.firstLat = float(vi.find('FIRST_LAT').text) - #m.lastLon = float(vi.find('LAST_LON').text) - #m.lastLat = float(vi.find('LAST_LAT').text) - + v = tree.find("Rational_Function_Model/Global_RFM/RFM_Validity") + g = tree.find("Rational_Function_Model/Global_RFM/RFM_Validity/GroundtoImage_Validity_Domain") + #vd = v.find("Direct_Model_Validity_Domain") + #m.firstRow = float(vd.find("FIRST_ROW").text) + #m.firstCol = float(vd.find("FIRST_COL").text) + #m.lastRow = float(vd.find("LAST_ROW").text) + #m.lastCol = float(vd.find("LAST_COL").text) + #vi = v.find("Inverse_Model_Validity_Domain") + #m.firstLon = float(vi.find("FIRST_LON").text) + #m.firstLat = float(vi.find("FIRST_LAT").text) + #m.lastLon = float(vi.find("LAST_LON").text) + #m.lastLat = float(vi.find("LAST_LAT").text) # scale and offset # the -1 in line and column offsets is due to Pleiades RPC convention # that states that the top-left pixel of an image has coordinates # (1, 1) - m['LINE_OFF' ] = float(v.find('LINE_OFF').text) - 1 - m['SAMP_OFF' ] = float(v.find('SAMP_OFF').text) - 1 - m['LAT_OFF' ] = float(v.find('LAT_OFF').text) - m['LONG_OFF' ] = float(v.find('LONG_OFF').text) - m['HEIGHT_OFF' ] = float(v.find('HEIGHT_OFF').text) - m['LINE_SCALE' ] = float(v.find('LINE_SCALE').text) - m['SAMP_SCALE' ] = float(v.find('SAMP_SCALE').text) - m['LAT_SCALE' ] = float(v.find('LAT_SCALE').text) - m['LONG_SCALE' ] = float(v.find('LONG_SCALE').text) - m['HEIGHT_SCALE'] = float(v.find('HEIGHT_SCALE').text) - + m["LINE_OFF" ] = float(v.find("LINE_OFF").text) - 1 + m["SAMP_OFF" ] = float(v.find("SAMP_OFF").text) - 1 + m["LAT_OFF" ] = float(v.find("LAT_OFF").text) + m["LONG_OFF" ] = float(v.find("LONG_OFF").text) + m["HEIGHT_OFF" ] = float(v.find("HEIGHT_OFF").text) + m["LINE_SCALE" ] = float(v.find("LINE_SCALE").text) + m["SAMP_SCALE" ] = float(v.find("SAMP_SCALE").text) + m["LAT_SCALE" ] = float(v.find("LAT_SCALE").text) + m["LONG_SCALE" ] = float(v.find("LONG_SCALE").text) + m["HEIGHT_SCALE"] = float(v.find("HEIGHT_SCALE").text) + m["FIRST_LON"] = float(g.find("FIRST_LON").text) + m["FIRST_LAT"] = float(g.find("FIRST_LAT").text) + m["LAST_LON"] = float(g.find("LAST_LON").text) + m["LAST_LAT"] = float(g.find("LAST_LAT").text) return m def read_rpc_xml_worldview(tree): """ Read RPC fields from a parsed XML tree assuming the worldview XML format - Args: tree: parsed XML tree - Returns: dictionary read from the RPC file, or empty dict in case of failure - """ m = {} - # inverse model (PROJECTION) - im = tree.find('RPB/IMAGE') - l = im.find('LINENUMCOEFList/LINENUMCOEF') - m['LINE_NUM_COEFF'] = l.text - l = im.find('LINEDENCOEFList/LINEDENCOEF') - m['LINE_DEN_COEFF'] = l.text - l = im.find('SAMPNUMCOEFList/SAMPNUMCOEF') - m['SAMP_NUM_COEFF'] = l.text - l = im.find('SAMPDENCOEFList/SAMPDENCOEF') - m['SAMP_DEN_COEFF'] = l.text - m['ERR_BIAS'] = float(im.find('ERRBIAS').text) - + im = tree.find("RPB/IMAGE") + l = im.find("LINENUMCOEFList/LINENUMCOEF") + m["LINE_NUM_COEFF"] = l.text + l = im.find("LINEDENCOEFList/LINEDENCOEF") + m["LINE_DEN_COEFF"] = l.text + l = im.find("SAMPNUMCOEFList/SAMPNUMCOEF") + m["SAMP_NUM_COEFF"] = l.text + l = im.find("SAMPDENCOEFList/SAMPDENCOEF") + m["SAMP_DEN_COEFF"] = l.text + m["ERR_BIAS"] = float(im.find("ERRBIAS").text) # scale and offset - m['LINE_OFF' ] = float(im.find('LINEOFFSET').text) - m['SAMP_OFF' ] = float(im.find('SAMPOFFSET').text) - m['LAT_OFF' ] = float(im.find('LATOFFSET').text) - m['LONG_OFF' ] = float(im.find('LONGOFFSET').text) - m['HEIGHT_OFF' ] = float(im.find('HEIGHTOFFSET').text) - - m['LINE_SCALE' ] = float(im.find('LINESCALE').text) - m['SAMP_SCALE' ] = float(im.find('SAMPSCALE').text) - m['LAT_SCALE' ] = float(im.find('LATSCALE').text) - m['LONG_SCALE' ] = float(im.find('LONGSCALE').text) - m['HEIGHT_SCALE'] = float(im.find('HEIGHTSCALE').text) - - -# # image dimensions -# m.lastRow = int(tree.find('IMD/NUMROWS').text) -# m.lastCol = int(tree.find('IMD/NUMCOLUMNS').text) - + m["LINE_OFF" ] = float(im.find("LINEOFFSET").text) + m["SAMP_OFF" ] = float(im.find("SAMPOFFSET").text) + m["LAT_OFF" ] = float(im.find("LATOFFSET").text) + m["LONG_OFF" ] = float(im.find("LONGOFFSET").text) + m["HEIGHT_OFF" ] = float(im.find("HEIGHTOFFSET").text) + m["LINE_SCALE" ] = float(im.find("LINESCALE").text) + m["SAMP_SCALE" ] = float(im.find("SAMPSCALE").text) + m["LAT_SCALE" ] = float(im.find("LATSCALE").text) + m["LONG_SCALE" ] = float(im.find("LONGSCALE").text) + m["HEIGHT_SCALE"] = float(im.find("HEIGHTSCALE").text) return m From 6deb8e4ba7ffb8cced4733c7908db1e1227ab9a3 Mon Sep 17 00:00:00 2001 From: David de Meij Date: Mon, 7 Aug 2023 09:48:04 +0000 Subject: [PATCH 3/3] Implement cam2rpc RPC file reading and add test --- rpcm/rpc_file_readers.py | 37 +++++++++++++- tests/test_rpc_file_parsing.py | 1 + tests/test_rpc_files/rpc_cam2rpc.xml | 76 ++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 tests/test_rpc_files/rpc_cam2rpc.xml diff --git a/rpcm/rpc_file_readers.py b/rpcm/rpc_file_readers.py index bd983c7..8c1d415 100644 --- a/rpcm/rpc_file_readers.py +++ b/rpcm/rpc_file_readers.py @@ -76,7 +76,9 @@ def read_rpc_xml(rpc_content): elif a.text in ["PNEO_SENSOR"]: parsed_rpc = read_rpc_xml_pleiades_neo(tree) elif b is not None: - if b.text == "WV02" or b.text == "WV01" or b.text == "WV03": + if b.text == "cam2rpc": + parsed_rpc = read_rpc_xml_cam2rpc(tree) + elif b.text == "WV02" or b.text == "WV01" or b.text == "WV03": parsed_rpc = read_rpc_xml_worldview(tree) if not parsed_rpc: raise NotImplementedError() @@ -246,3 +248,36 @@ def read_rpc_xml_worldview(tree): m["LONG_SCALE" ] = float(im.find("LONGSCALE").text) m["HEIGHT_SCALE"] = float(im.find("HEIGHTSCALE").text) return m + +def read_rpc_xml_cam2rpc(tree): + m = {} + d = tree.find("RPB/IMAGE") + + m["LON_NUM_COEFF"] = d.find("SAMPNUMCOEFList/SAMPNUMCOEF").text + m["LON_DEN_COEFF"] = d.find("SAMPDENCOEFList/SAMPDENCOEF").text + m["LAT_NUM_COEFF"] = d.find("LINENUMCOEFList/LINENUMCOEF").text + m["LAT_DEN_COEFF"] = d.find("LINEDENCOEFList/LINEDENCOEF").text + m["SAMP_NUM_COEFF"] = d.find("SAMPNUMCOEFList/SAMPNUMCOEF").text + m["SAMP_DEN_COEFF"] = d.find("SAMPDENCOEFList/SAMPDENCOEF").text + m["LINE_NUM_COEFF"] = d.find("LINENUMCOEFList/LINENUMCOEF").text + m["LINE_DEN_COEFF"] = d.find("LINEDENCOEFList/LINEDENCOEF").text + m["ERR_BIAS"] = d.find("ERRBIAS").text + + m["LINE_OFF" ] = float(d.find("LINEOFFSET").text) - 1 + m["SAMP_OFF" ] = float(d.find("SAMPOFFSET").text) - 1 + m["LAT_OFF" ] = float(d.find("LATOFFSET").text) + m["LONG_OFF" ] = float(d.find("LONGOFFSET").text) + m["HEIGHT_OFF" ] = float(d.find("HEIGHTOFFSET").text) + + m["LINE_SCALE" ] = float(d.find("LINESCALE").text) + m["SAMP_SCALE" ] = float(d.find("SAMPSCALE").text) + m["LAT_SCALE" ] = float(d.find("LATSCALE").text) + m["LONG_SCALE" ] = float(d.find("LONGSCALE").text) + m["HEIGHT_SCALE"] = float(d.find("HEIGHTSCALE").text) + + b = tree.find("IMD/BAND_P") + m["FIRST_LON"] = float(b.find("ULLON").text) + m["FIRST_LAT"] = float(b.find("ULLAT").text) + m["LAST_LON"] = float(b.find("LRLON").text) + m["LAST_LAT"] = float(b.find("LRLAT").text) + return m diff --git a/tests/test_rpc_file_parsing.py b/tests/test_rpc_file_parsing.py index 97f2c04..352c809 100644 --- a/tests/test_rpc_file_parsing.py +++ b/tests/test_rpc_file_parsing.py @@ -20,6 +20,7 @@ def supported_files(): "rpc_WV1.xml", "rpc_WV2.xml", "rpc_WV3.xml", + "rpc_cam2rpc.xml", ] return [os.path.join(files_dir, filename) for filename in filenames] diff --git a/tests/test_rpc_files/rpc_cam2rpc.xml b/tests/test_rpc_files/rpc_cam2rpc.xml new file mode 100644 index 0000000..9bb4793 --- /dev/null +++ b/tests/test_rpc_files/rpc_cam2rpc.xml @@ -0,0 +1,76 @@ + + + + 17005 + 19237 + + -116.089975173619564 + 44.606620122993057 + 1448.36804199200105 + -116.01327197768606 + 44.606620122993057 + 1711.53320312471942 + -116.01327197768606 + 44.555510605898391 + 1448.36804199200105 + -116.089975173619564 + 44.555510605898391 + 1711.53320312471942 + + + cam2rpc + FullSwath + Forward + 0 + 2010-06-21T21:32:55.534775Z + 2 + + 0.0 0.000000000000000e+00 + 27572.0 1.378600000000000e+00 + + 2010-06-21T21:32:55.534775Z + 20000.0 + 0.0016 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + + + + cam2rpc + P + RPC00B + + 1.006000000000000e+01 + 1.100000000000000e-01 + GEOGCS["Geographic Coordinate System",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563002]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AXIS["Latitude",NORTH],AXIS["Longitude",EAST]] + 8502 + 9618.5 + 44.58106536444572 + -116.0516235756528 + 1579.95062255836 + 8502 + 9618.5 + 0.02555475854733302 + 0.03835159796675214 + 131.5825805663592 + + -0.019285377041998255 -0.049142287879579055 -1.038724645632561 -0.012691983271680292 6.7853527912497577e-06 -2.0774770004314933e-05 1.0219325753680678e-06 -0.00013808564155389649 -3.3523052126610758e-07 -4.5266566394734187e-06 -2.5264360363096692e-06 1.3696462742894201e-06 5.491732456388042e-07 6.7443447639832831e-06 -9.0963571631624812e-07 -1.1476652103733783e-06 4.6555368986707965e-07 2.7465203061880996e-05 -2.9352539670415658e-07 2.3136137971812508e-06 + + + 1 -0.00055663472702691477 0.00033097998046295753 -1.9046678176016687e-05 2.087723112866626e-06 -5.1637807941184432e-06 -1.6792240670843906e-06 -4.7952970604020387e-06 -4.686380957136418e-06 3.2756097978494011e-06 -2.1367589044860398e-06 -2.1903102436646541e-06 5.4656524660158696e-07 1.2557908923560919e-06 -7.6514049073589322e-06 5.5599469521790227e-07 -8.0240048678094791e-08 -1.133561362286693e-06 1.0577591103623469e-06 -1.0708168266274069e-06 + + + -0.0059811411504001443 1.0015238040102472 -0.00047439021780777501 -0.006934615473209095 -1.8919539958205122e-07 -4.5289327720355641e-08 -2.3958772937047222e-05 2.6783222176420235e-09 -4.0979664456208515e-05 -3.9488306612374517e-06 -2.7940527263938541e-06 -1.3346876822442813e-09 -9.798182910142582e-07 -1.3559179810397192e-06 1.0616919433576885e-06 -8.7632725092060532e-07 3.3131523468379558e-06 -7.9884967081318925e-08 6.0610989735158641e-06 -3.6800855581351667e-07 + + + 1 -0.00081154177529528006 0.00086267805867892389 -0.00020395022695666353 -4.3484409908354773e-06 2.6893660170376e-07 1.1155244246325799e-05 6.1700262390157579e-09 3.8579604136081591e-06 5.4093455639760719e-06 2.2933959332084551e-06 -8.420994678862199e-07 3.4912485210514804e-06 8.5741622982219513e-07 -1.467135383538925e-06 -3.6173240686882021e-07 -1.3108099008403949e-06 -2.6680954257603801e-07 9.2501418115104453e-07 -7.1035576384365164e-07 + + + +