sarkit-convert 0.1.0__py3-none-any.whl → 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sarkit_convert/_utils.py +47 -18
- sarkit_convert/_version.py +1 -1
- sarkit_convert/{csk.py → cosmo.py} +369 -218
- sarkit_convert/create_arp_poly.py +166 -0
- sarkit_convert/iceye.py +217 -301
- sarkit_convert/sentinel.py +457 -453
- sarkit_convert/sidd_metadata.py +201 -0
- sarkit_convert/{tsx.py → terrasar.py} +318 -215
- {sarkit_convert-0.1.0.dist-info → sarkit_convert-0.3.0.dist-info}/METADATA +26 -26
- sarkit_convert-0.3.0.dist-info/RECORD +14 -0
- {sarkit_convert-0.1.0.dist-info → sarkit_convert-0.3.0.dist-info}/WHEEL +1 -1
- sarkit_convert-0.1.0.dist-info/RECORD +0 -12
- {sarkit_convert-0.1.0.dist-info → sarkit_convert-0.3.0.dist-info}/entry_points.txt +0 -0
- {sarkit_convert-0.1.0.dist-info → sarkit_convert-0.3.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import enum
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
import numpy.typing as npt
|
|
6
|
+
import pyproj
|
|
7
|
+
|
|
8
|
+
import sarkit_convert._utils
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class _ModelTypeCodes(enum.IntEnum):
|
|
14
|
+
"""GeoTIFF GTModelTypeGeoKey values"""
|
|
15
|
+
|
|
16
|
+
ModelTypeProjected = 1
|
|
17
|
+
ModelTypeGeographic = 2
|
|
18
|
+
ModelTypeGeocentric = 3
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _get_transformation_matrix(
|
|
22
|
+
model_transformation_tag: npt.ArrayLike | None,
|
|
23
|
+
model_tiepoint_tag: npt.ArrayLike | None,
|
|
24
|
+
model_pixel_scale_tag: npt.ArrayLike | None,
|
|
25
|
+
):
|
|
26
|
+
"""Matrix to convert from image coordinates to model coordinates
|
|
27
|
+
|
|
28
|
+
See: http://geotiff.maptools.org/spec/geotiff2.6.html
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
if model_transformation_tag is not None:
|
|
32
|
+
matrix = np.asarray(model_transformation_tag).reshape(4, 4)
|
|
33
|
+
if np.any(matrix[-1] != (0.0, 0.0, 0.0, 1.0)):
|
|
34
|
+
logger.warning(
|
|
35
|
+
"Last row of ModelTransformation matrix must be (0, 0, 0, 1)"
|
|
36
|
+
)
|
|
37
|
+
return matrix
|
|
38
|
+
|
|
39
|
+
if model_pixel_scale_tag is not None and model_tiepoint_tag is not None:
|
|
40
|
+
sx, sy, sz = np.asarray(model_pixel_scale_tag)
|
|
41
|
+
mtp = np.atleast_2d(model_tiepoint_tag)
|
|
42
|
+
|
|
43
|
+
if mtp.shape[0] != 1:
|
|
44
|
+
# Probably want to interpolate tiepoints if there is more than one
|
|
45
|
+
# Should only be one tiepoint when ModelPixelScale is present
|
|
46
|
+
return None
|
|
47
|
+
|
|
48
|
+
i, j, k, x, y, z = mtp[0]
|
|
49
|
+
tx = x - i * sx
|
|
50
|
+
ty = y + j * sy
|
|
51
|
+
tz = z - k * sz
|
|
52
|
+
matrix = np.asarray(
|
|
53
|
+
[
|
|
54
|
+
[sx, 0.0, 0.0, tx],
|
|
55
|
+
[0.0, -sy, 0.0, ty],
|
|
56
|
+
[0.0, 0.0, sz, tz],
|
|
57
|
+
[0.0, 0.0, 0.0, 1.0],
|
|
58
|
+
]
|
|
59
|
+
)
|
|
60
|
+
return matrix
|
|
61
|
+
|
|
62
|
+
return None
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def sidd_projection_from_geotiff(
|
|
66
|
+
shape: tuple[int, int],
|
|
67
|
+
gt_model_type_geo_key: int,
|
|
68
|
+
projected_cs_type_geo_key: int | None,
|
|
69
|
+
geographic_type_geo_key: int | None,
|
|
70
|
+
model_transformation_tag: npt.ArrayLike | None,
|
|
71
|
+
model_tiepoint_tag: npt.ArrayLike | None,
|
|
72
|
+
model_pixel_scale_tag: npt.ArrayLike | None,
|
|
73
|
+
grid_size: int = 11,
|
|
74
|
+
max_order: int = 5,
|
|
75
|
+
) -> tuple[npt.NDArray, npt.NDArray, npt.NDArray, npt.NDArray]:
|
|
76
|
+
"""
|
|
77
|
+
Generate SIDD PolynomialProjection polynomials for a GeoTIFF
|
|
78
|
+
|
|
79
|
+
Parameters
|
|
80
|
+
----------
|
|
81
|
+
shape : tuple of int
|
|
82
|
+
Shape of the image
|
|
83
|
+
gt_model_type_geo_key : int
|
|
84
|
+
Value of the GTModelTypeGeoKey
|
|
85
|
+
projected_cs_type_geo_key : int, optional
|
|
86
|
+
Value of the ProjectedCSTypeGeoKey. Required if gt_model_type_geo_key == 1
|
|
87
|
+
geographic_type_geo_key : int, optional
|
|
88
|
+
Value of the GeographicTypeGeoKey. Required if gt_model_type_geo_key == 2
|
|
89
|
+
model_transformation_tag : array-like, optional
|
|
90
|
+
Value of the ModelTransformationTag
|
|
91
|
+
model_tiepoint_tag : array-like, optional
|
|
92
|
+
Value of the ModelTiepointTag
|
|
93
|
+
model_pixel_scale_tag : array-like, optional
|
|
94
|
+
Value of the ModelPixelScaleTag
|
|
95
|
+
grid_size : int, optional
|
|
96
|
+
Number of fit points in each dimension
|
|
97
|
+
max_order : int, optional
|
|
98
|
+
Maximum order of generated polynomials
|
|
99
|
+
|
|
100
|
+
Returns
|
|
101
|
+
-------
|
|
102
|
+
rowcol_to_lat : ndarray
|
|
103
|
+
2D polynomial coefficients. (row, col) -> latitude degrees
|
|
104
|
+
rowcol_to_lon : ndarray
|
|
105
|
+
2D polynomial coefficients. (row, col) -> longitude degrees
|
|
106
|
+
latlon_to_row : ndarray
|
|
107
|
+
2D polynomial coefficients. (latitude degrees, longitude degrees) -> row
|
|
108
|
+
latlon_to_col : ndarray
|
|
109
|
+
2D polynomial coefficients. (latitude degrees, longitude degrees) -> col
|
|
110
|
+
|
|
111
|
+
Notes
|
|
112
|
+
-----
|
|
113
|
+
See:
|
|
114
|
+
* http://geotiff.maptools.org/spec/geotiff2.5.html
|
|
115
|
+
* http://geotiff.maptools.org/spec/geotiff2.6.html
|
|
116
|
+
|
|
117
|
+
"""
|
|
118
|
+
# Image Coordinates are [I J K 1] -> (column, row, vertical, 1)
|
|
119
|
+
image_coords = np.stack(
|
|
120
|
+
[
|
|
121
|
+
*np.meshgrid(
|
|
122
|
+
np.linspace(0, shape[1], grid_size),
|
|
123
|
+
np.linspace(0, shape[0], grid_size),
|
|
124
|
+
),
|
|
125
|
+
np.zeros((grid_size, grid_size)), # no vertical component
|
|
126
|
+
np.ones((grid_size, grid_size)),
|
|
127
|
+
],
|
|
128
|
+
axis=-1,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
matrix = _get_transformation_matrix(
|
|
132
|
+
model_transformation_tag, model_tiepoint_tag, model_pixel_scale_tag
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
if matrix is None:
|
|
136
|
+
raise RuntimeError("Failed to get transformation matrix")
|
|
137
|
+
|
|
138
|
+
swap_axis = False
|
|
139
|
+
if gt_model_type_geo_key == _ModelTypeCodes.ModelTypeProjected:
|
|
140
|
+
if projected_cs_type_geo_key is None:
|
|
141
|
+
raise ValueError(
|
|
142
|
+
"projected_cs_type_geo_key must be provided for Projected model type"
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
crs = pyproj.CRS.from_epsg(int(projected_cs_type_geo_key))
|
|
146
|
+
elif gt_model_type_geo_key == _ModelTypeCodes.ModelTypeGeographic:
|
|
147
|
+
if geographic_type_geo_key is None:
|
|
148
|
+
raise ValueError(
|
|
149
|
+
"geographic_type_geo_key must be provided for Geographic model type"
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
crs = pyproj.CRS.from_epsg(int(geographic_type_geo_key))
|
|
153
|
+
# GeoTIFF axis order convention is reversed from CRS for Geographic coordinate systems
|
|
154
|
+
swap_axis = True
|
|
155
|
+
else:
|
|
156
|
+
raise RuntimeError(
|
|
157
|
+
f"GTModelTypeGeoKey == {gt_model_type_geo_key} not supported"
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
# model image
|
|
161
|
+
# coords = matrix * coords
|
|
162
|
+
# |- -| |- -| |- -|
|
|
163
|
+
# | X | | a b c d | | I |
|
|
164
|
+
# | | | | | |
|
|
165
|
+
# | Y | | e f g h | | J |
|
|
166
|
+
# | | = | | | |
|
|
167
|
+
# | Z | | i j k l | | K |
|
|
168
|
+
# | | | | | |
|
|
169
|
+
# | 1 | | m n o p | | 1 |
|
|
170
|
+
# |- -| |- -| |- -|
|
|
171
|
+
model_coords = np.inner(matrix, image_coords)
|
|
172
|
+
if swap_axis:
|
|
173
|
+
model_x = model_coords[1]
|
|
174
|
+
model_y = model_coords[0]
|
|
175
|
+
else:
|
|
176
|
+
model_x = model_coords[0]
|
|
177
|
+
model_y = model_coords[1]
|
|
178
|
+
|
|
179
|
+
transformer = pyproj.Transformer.from_crs(crs, 4326) # 4326 = WGS84 Lat/Lon
|
|
180
|
+
lats, lons = transformer.transform(model_x, model_y)
|
|
181
|
+
rows = image_coords[..., 1]
|
|
182
|
+
cols = image_coords[..., 0]
|
|
183
|
+
|
|
184
|
+
rc_span = max(np.ptp(rows), np.ptp(cols))
|
|
185
|
+
tol_px = 0.1
|
|
186
|
+
tol_lat = np.ptp(lats) / rc_span * tol_px
|
|
187
|
+
tol_lon = np.ptp(lons) / rc_span * tol_px
|
|
188
|
+
|
|
189
|
+
rowcol_to_lat = sarkit_convert._utils.polyfit2d_tol(
|
|
190
|
+
rows.flatten(), cols.flatten(), lats.flatten(), max_order, max_order, tol_lat
|
|
191
|
+
)
|
|
192
|
+
rowcol_to_lon = sarkit_convert._utils.polyfit2d_tol(
|
|
193
|
+
rows.flatten(), cols.flatten(), lons.flatten(), max_order, max_order, tol_lon
|
|
194
|
+
)
|
|
195
|
+
latlon_to_row = sarkit_convert._utils.polyfit2d_tol(
|
|
196
|
+
lats.flatten(), lons.flatten(), rows.flatten(), max_order, max_order, tol=tol_px
|
|
197
|
+
)
|
|
198
|
+
latlon_to_col = sarkit_convert._utils.polyfit2d_tol(
|
|
199
|
+
lats.flatten(), lons.flatten(), cols.flatten(), max_order, max_order, tol=tol_px
|
|
200
|
+
)
|
|
201
|
+
return rowcol_to_lat, rowcol_to_lon, latlon_to_row, latlon_to_col
|