ign-borea 0.1.5__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.
- borea/__init__.py +0 -0
- borea/datastruct/__init__.py +0 -0
- borea/datastruct/camera.py +25 -0
- borea/datastruct/dtm.py +119 -0
- borea/datastruct/gcp.py +22 -0
- borea/datastruct/shot.py +222 -0
- borea/datastruct/workdata.py +220 -0
- borea/format/__init__.py +0 -0
- borea/format/conl.py +143 -0
- borea/format/rpc.py +244 -0
- borea/geodesy/__init__.py +0 -0
- borea/geodesy/approx_euclidean_proj.py +91 -0
- borea/geodesy/euclidean_proj.py +25 -0
- borea/geodesy/local_euclidean_proj.py +127 -0
- borea/geodesy/proj_engine.py +70 -0
- borea/geodesy/projectionlist/__init__.py +0 -0
- borea/geodesy/projectionlist/search_proj.py +60 -0
- borea/geodesy/transform_geodesy.py +114 -0
- borea/process/__init__.py +0 -0
- borea/process/p_add_data/__init__.py +0 -0
- borea/process/p_add_data/p_add_shot.py +63 -0
- borea/process/p_add_data/p_file_gcp2d.py +55 -0
- borea/process/p_add_data/p_file_gcp3d.py +53 -0
- borea/process/p_add_data/p_gen_param.py +76 -0
- borea/process/p_add_data/p_pt2d.py +48 -0
- borea/process/p_add_data/p_pt3d.py +48 -0
- borea/process/p_add_data/p_unit_shot.py +48 -0
- borea/process/p_add_data/p_write.py +23 -0
- borea/process/p_format/__init__.py +0 -0
- borea/process/p_format/p_read_opk.py +78 -0
- borea/process/p_format/p_write_con.py +36 -0
- borea/process/p_format/p_write_opk.py +64 -0
- borea/process/p_format/p_write_rpc.py +48 -0
- borea/process/p_func/__init__.py +0 -0
- borea/process/p_func/p_control.py +67 -0
- borea/process/p_func/p_image_world.py +48 -0
- borea/process/p_func/p_spaceresection.py +51 -0
- borea/process/p_func/p_world_image.py +49 -0
- borea/reader/__init__.py +0 -0
- borea/reader/orientation/__init__.py +0 -0
- borea/reader/orientation/manage_reader.py +33 -0
- borea/reader/orientation/reader_opk.py +58 -0
- borea/reader/reader_camera.py +52 -0
- borea/reader/reader_point.py +113 -0
- borea/stat/__init__.py +0 -0
- borea/stat/statistics.py +215 -0
- borea/transform_world_image/__init__.py +0 -0
- borea/transform_world_image/transform_dtm/__init__.py +0 -0
- borea/transform_world_image/transform_dtm/world_image_dtm.py +47 -0
- borea/transform_world_image/transform_shot/__init__.py +0 -0
- borea/transform_world_image/transform_shot/conversion_coor_shot.py +58 -0
- borea/transform_world_image/transform_shot/image_world_shot.py +153 -0
- borea/transform_world_image/transform_shot/world_image_shot.py +117 -0
- borea/transform_world_image/transform_worksite/__init__.py +0 -0
- borea/transform_world_image/transform_worksite/image_world_intersection.py +154 -0
- borea/transform_world_image/transform_worksite/image_world_least_square.py +184 -0
- borea/transform_world_image/transform_worksite/image_world_work.py +49 -0
- borea/transform_world_image/transform_worksite/space_resection.py +343 -0
- borea/transform_world_image/transform_worksite/world_image_work.py +43 -0
- borea/utils/__init__.py +0 -0
- borea/utils/check/__init__.py +0 -0
- borea/utils/check/check_args_opk.py +59 -0
- borea/utils/check/check_args_reader_pt.py +44 -0
- borea/utils/check/check_array.py +56 -0
- borea/utils/check/check_header.py +90 -0
- borea/utils/check/check_order_axe.py +50 -0
- borea/utils/miscellaneous/__init__.py +0 -0
- borea/utils/miscellaneous/miscellaneous.py +83 -0
- borea/utils/miscellaneous/param_bundle.py +36 -0
- borea/utils/miscellaneous/sparse.py +31 -0
- borea/utils/singleton/__init__.py +0 -0
- borea/utils/singleton/singleton.py +23 -0
- borea/utils/xml/__init__.py +0 -0
- borea/utils/xml/xml.py +63 -0
- borea/worksite/__init__.py +0 -0
- borea/worksite/worksite.py +240 -0
- borea/writer/__init__.py +0 -0
- borea/writer/manage_writer.py +23 -0
- borea/writer/writer_con.py +29 -0
- borea/writer/writer_df_to_txt.py +32 -0
- borea/writer/writer_opk.py +70 -0
- borea/writer/writer_rpc.py +55 -0
- borea_tools/__init__.py +0 -0
- borea_tools/opk_control.py +33 -0
- borea_tools/opk_to_conl.py +33 -0
- borea_tools/opk_to_opk.py +33 -0
- borea_tools/opk_to_rpc.py +33 -0
- borea_tools/pt_image_to_world.py +32 -0
- borea_tools/pt_world_to_image.py +32 -0
- borea_tools/ptfile_image_to_world.py +32 -0
- borea_tools/ptfile_world_to_image.py +32 -0
- borea_tools/spaceresection_opk.py +34 -0
- ign_borea-0.1.5.dist-info/LICENSE +21 -0
- ign_borea-0.1.5.dist-info/METADATA +274 -0
- ign_borea-0.1.5.dist-info/RECORD +98 -0
- ign_borea-0.1.5.dist-info/WHEEL +5 -0
- ign_borea-0.1.5.dist-info/entry_points.txt +10 -0
- ign_borea-0.1.5.dist-info/top_level.txt +2 -0
borea/__init__.py
ADDED
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Camera data class module.
|
|
3
|
+
"""
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class Camera:
|
|
9
|
+
"""
|
|
10
|
+
Camera class definition.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
name_camera (str): Name of the camera.
|
|
14
|
+
ppax (float): Center of distortion in x.
|
|
15
|
+
ppay (float): Center of distortion in y.
|
|
16
|
+
focal (float): Focal of the camera.
|
|
17
|
+
width (int): Width of the image in pixel.
|
|
18
|
+
height (int): Height of the image in pixel.
|
|
19
|
+
"""
|
|
20
|
+
name_camera: str
|
|
21
|
+
ppax: float = field(default=None)
|
|
22
|
+
ppay: float = field(default=None)
|
|
23
|
+
focal: float = field(default=None)
|
|
24
|
+
width: int = field(default=None)
|
|
25
|
+
height: int = field(default=None)
|
borea/datastruct/dtm.py
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"""
|
|
2
|
+
A module for manipulating a digital elevation model.
|
|
3
|
+
"""
|
|
4
|
+
from pathlib import Path, PureWindowsPath
|
|
5
|
+
import numpy as np
|
|
6
|
+
from osgeo import gdal
|
|
7
|
+
from scipy import ndimage
|
|
8
|
+
from borea.transform_world_image.transform_dtm.world_image_dtm import WorldImageDtm
|
|
9
|
+
from borea.utils.singleton.singleton import Singleton
|
|
10
|
+
gdal.UseExceptions()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# pylint: disable-next=too-many-instance-attributes
|
|
14
|
+
class Dtm(WorldImageDtm, metaclass=Singleton):
|
|
15
|
+
"""
|
|
16
|
+
Represents a digital elevation model.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
path_dtm (str): Path to the dtm file. If None Dtm.get() always returns 0.
|
|
20
|
+
order (int): The method of interpolation to perform.
|
|
21
|
+
0 : nearest, 1 : slinear, 3 : cubic, 5 : quintic.
|
|
22
|
+
cval (int): Value to fill past edges of dtm.
|
|
23
|
+
If None raise an error for any point outside the dtm.
|
|
24
|
+
keep_in_memory (bool): Store all data in memory.
|
|
25
|
+
|
|
26
|
+
.. note::
|
|
27
|
+
All gdal formats are supported. The file must contain georeferencing information.
|
|
28
|
+
"""
|
|
29
|
+
def __init__(self):
|
|
30
|
+
self.path_dtm = None
|
|
31
|
+
self.type_dtm = None
|
|
32
|
+
self.order = 1
|
|
33
|
+
self.keep_in_memory = False
|
|
34
|
+
self.cval = np.nan
|
|
35
|
+
self.img = None
|
|
36
|
+
self.rb = None
|
|
37
|
+
self.nodata = None
|
|
38
|
+
self.dtm_array = None
|
|
39
|
+
WorldImageDtm.__init__(self, None)
|
|
40
|
+
|
|
41
|
+
def set_dtm(self, path_dtm: str, type_dtm: str) -> None:
|
|
42
|
+
"""
|
|
43
|
+
Set the dtm path for reading dtm.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
path_dtm (str): Path to the dtm file.
|
|
47
|
+
type (str): Type of dtm "a" altitude, "h" height.
|
|
48
|
+
"""
|
|
49
|
+
if path_dtm:
|
|
50
|
+
gdal.AllRegister()
|
|
51
|
+
self.type_dtm = type_dtm
|
|
52
|
+
self.path_dtm = Path(PureWindowsPath(path_dtm))
|
|
53
|
+
self.img = gdal.Open(self.path_dtm.as_posix())
|
|
54
|
+
self.rb = self.img.GetRasterBand(1)
|
|
55
|
+
self.nodata = self.rb.GetNoDataValue()
|
|
56
|
+
if self.keep_in_memory:
|
|
57
|
+
self.dtm_array = self.rb.ReadAsArray()
|
|
58
|
+
WorldImageDtm.__init__(self, self.img.GetGeoTransform())
|
|
59
|
+
else:
|
|
60
|
+
self.path_dtm = path_dtm
|
|
61
|
+
|
|
62
|
+
def set_order(self, order: int) -> None:
|
|
63
|
+
"""
|
|
64
|
+
The method of interpolation to perform.
|
|
65
|
+
0:nearest 1:bilinear 3:cubic 5:quintic.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
order (int): The method of interpolation to perform.
|
|
69
|
+
"""
|
|
70
|
+
self.order = order
|
|
71
|
+
|
|
72
|
+
def set_cval(self, cval: int) -> None:
|
|
73
|
+
"""
|
|
74
|
+
Value to fill past edges of dtm or nodata.
|
|
75
|
+
If None raise an error for any point outside the dtm or Nodata.
|
|
76
|
+
|
|
77
|
+
Args
|
|
78
|
+
cval (int): Value to fill past edges of dtm or nodata.
|
|
79
|
+
"""
|
|
80
|
+
self.cval = cval if cval else np.nan
|
|
81
|
+
|
|
82
|
+
def set_keep_memory(self, keep_memory: bool) -> None:
|
|
83
|
+
"""
|
|
84
|
+
Store all image in memory.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
keep_in_memory (bool): Store all image in memory.
|
|
88
|
+
"""
|
|
89
|
+
self.keep_in_memory = keep_memory
|
|
90
|
+
|
|
91
|
+
def get_z_world(self, coor_2d: np.ndarray) -> np.ndarray:
|
|
92
|
+
"""
|
|
93
|
+
Extract value in the Dtm.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
coor_2d (np.array): World coordinate 2D [X, Y].
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
np.array: z value.
|
|
100
|
+
"""
|
|
101
|
+
if self.path_dtm is None:
|
|
102
|
+
return np.zeros_like(coor_2d[0])
|
|
103
|
+
col, line = self.world_to_image(coor_2d)
|
|
104
|
+
if not self.keep_in_memory:
|
|
105
|
+
z = []
|
|
106
|
+
if isinstance(col, float):
|
|
107
|
+
col, line = [col], [line]
|
|
108
|
+
for colt, linet in zip(col, line):
|
|
109
|
+
try:
|
|
110
|
+
z += [self.rb.ReadAsArray(colt, linet, 1, 1, resample_alg=self.order)]
|
|
111
|
+
except RuntimeError:
|
|
112
|
+
z += [self.cval]
|
|
113
|
+
else:
|
|
114
|
+
z = ndimage.map_coordinates(self.dtm_array, np.vstack([line, col]),
|
|
115
|
+
order=self.order, mode="constant", cval=self.cval)
|
|
116
|
+
if np.any(np.isnan(z)):
|
|
117
|
+
raise IndexError(f"Out dtm {coor_2d[0]} {coor_2d[1]}")
|
|
118
|
+
|
|
119
|
+
return np.round(np.array(z, dtype=float), 3)
|
borea/datastruct/gcp.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Ground Control Point (GCP) class.
|
|
3
|
+
"""
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class GCP:
|
|
10
|
+
"""
|
|
11
|
+
Ground Control Point class.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
name_gcp (str): Name of the gcp.
|
|
15
|
+
code (str): IGN code to differentiate between support points (1, 2, 3)
|
|
16
|
+
and control points (11, 12, 13)
|
|
17
|
+
1 means precision in Z, 2 in X and Y and 3 in X, Y, Z.
|
|
18
|
+
coor (numpy.array): Array of ground coordinate [X, Y, Z].
|
|
19
|
+
"""
|
|
20
|
+
name_gcp: str
|
|
21
|
+
code: str
|
|
22
|
+
coor: np.ndarray
|
borea/datastruct/shot.py
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Acquisition data class module.
|
|
3
|
+
"""
|
|
4
|
+
import numpy as np
|
|
5
|
+
from scipy.spatial.transform import Rotation as R
|
|
6
|
+
from borea.geodesy.proj_engine import ProjEngine
|
|
7
|
+
from borea.geodesy.approx_euclidean_proj import ApproxEuclideanProj
|
|
8
|
+
from borea.geodesy.local_euclidean_proj import LocalEuclideanProj
|
|
9
|
+
from borea.utils.check.check_order_axe import check_order_axe
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# pylint: disable=too-many-instance-attributes too-many-arguments
|
|
13
|
+
class Shot:
|
|
14
|
+
"""
|
|
15
|
+
Shot class definition.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
name_shot (str): Name of the shot.
|
|
19
|
+
pos_shot (numpy.array): Array of coordinate position [X, Y, Z].
|
|
20
|
+
ori_shot (numpy.array): Array of orientation of the shot [Omega, Phi, Kappa] in degree.
|
|
21
|
+
name_cam (str): Name of the camera.
|
|
22
|
+
unit_angle (str): Unit of angle 'degrees', 'radian'.
|
|
23
|
+
linear_alteration (bool): True if z shot is correct of linear alteration.
|
|
24
|
+
order_axe (str): Order of rotation matrix axes.
|
|
25
|
+
"""
|
|
26
|
+
def __init__(self, name_shot: str, pos_shot: np.ndarray,
|
|
27
|
+
ori_shot: np.ndarray, name_cam: str,
|
|
28
|
+
unit_angle: str, linear_alteration: bool,
|
|
29
|
+
order_axe: str) -> None:
|
|
30
|
+
self.name_shot = name_shot
|
|
31
|
+
self.pos_shot = pos_shot
|
|
32
|
+
self.pos_shot_eucli = None
|
|
33
|
+
self.linear_alteration = linear_alteration
|
|
34
|
+
self.ori_shot = ori_shot
|
|
35
|
+
self.unit_angle = unit_angle
|
|
36
|
+
self.name_cam = name_cam
|
|
37
|
+
self.order_axe = order_axe
|
|
38
|
+
self.z_nadir = None
|
|
39
|
+
self.co_points = {}
|
|
40
|
+
self.gcp2d = {}
|
|
41
|
+
self.gcp3d = {}
|
|
42
|
+
self.mat_rot = self.set_rot_shot()
|
|
43
|
+
self.mat_rot_eucli = None
|
|
44
|
+
self.projeucli = None
|
|
45
|
+
self.approxeucli = False
|
|
46
|
+
self.f_sys = lambda x_shot, y_shot, z_shot: (x_shot, y_shot, z_shot)
|
|
47
|
+
self.f_sys_inv = lambda x_shot, y_shot, z_shot: (x_shot, y_shot, z_shot)
|
|
48
|
+
|
|
49
|
+
@classmethod
|
|
50
|
+
def from_param_euclidean(cls, name_shot: str, pos_eucli: np.ndarray,
|
|
51
|
+
mat_ori_eucli: np.ndarray, name_cam: str,
|
|
52
|
+
unit_angle: str, linear_alteration: bool,
|
|
53
|
+
order_axe: str, approx: bool) -> None:
|
|
54
|
+
"""
|
|
55
|
+
Construction of a shot object using the Euclidean position.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
name_shot (str): Name of the shot.
|
|
59
|
+
pos_eucli (np.array): Euclidean position of the shot.
|
|
60
|
+
mat_ori_eucli (np.array): Euclidean rotation matrix of the shot.
|
|
61
|
+
name_cam (str): Name of the camera.
|
|
62
|
+
unit_angle (str): Unit of angle 'degrees', 'radian'.
|
|
63
|
+
linear_alteration (bool): True if z shot is correct of linear alteration.
|
|
64
|
+
order_axe (str): Order of rotation matrix axes.
|
|
65
|
+
approx (bool): True if you want to use approx euclidean system.
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
Shot: The shot.
|
|
69
|
+
"""
|
|
70
|
+
shot = cls(name_shot, np.array([0, 0, 0]), np.array([0, 0, 0]),
|
|
71
|
+
name_cam, unit_angle, linear_alteration, order_axe)
|
|
72
|
+
shot.pos_shot_eucli = pos_eucli
|
|
73
|
+
shot.approxeucli = approx
|
|
74
|
+
if approx:
|
|
75
|
+
shot.projeucli = ApproxEuclideanProj(pos_eucli[0], pos_eucli[1])
|
|
76
|
+
else:
|
|
77
|
+
shot.projeucli = LocalEuclideanProj(pos_eucli[0], pos_eucli[1])
|
|
78
|
+
unitori = shot.unit_angle == "degree"
|
|
79
|
+
shot.pos_shot = shot.projeucli.eucli_to_world(pos_eucli)
|
|
80
|
+
shot.co_points = {}
|
|
81
|
+
shot.gcp3d = {}
|
|
82
|
+
shot.gcp2d = {}
|
|
83
|
+
shot.mat_rot = shot.projeucli.mat_eucli_to_mat(shot.pos_shot[0], shot.pos_shot[1],
|
|
84
|
+
mat_ori_eucli)
|
|
85
|
+
shot.mat_rot_eucli = mat_ori_eucli
|
|
86
|
+
order_xyz = check_order_axe(order_axe)
|
|
87
|
+
shot.ori_shot = -(R.from_euler("x", np.pi) *
|
|
88
|
+
R.from_matrix(shot.mat_rot)).as_euler(order_xyz, degrees=unitori)
|
|
89
|
+
|
|
90
|
+
shot.f_sys = lambda x_shot, y_shot, z_shot: (x_shot, y_shot, z_shot)
|
|
91
|
+
shot.f_sys_inv = lambda x_shot, y_shot, z_shot: (x_shot, y_shot, z_shot)
|
|
92
|
+
|
|
93
|
+
return shot
|
|
94
|
+
|
|
95
|
+
def set_rot_shot(self) -> np.ndarray:
|
|
96
|
+
"""
|
|
97
|
+
Build the rotation matrix with omega phi kappa.
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
np.array: The rotation matrix.
|
|
101
|
+
"""
|
|
102
|
+
order_xyz = check_order_axe(self.order_axe)
|
|
103
|
+
rot = R.from_euler(order_xyz, -np.array(self.ori_shot), degrees=self.unit_angle == "degree")
|
|
104
|
+
rot = R.from_euler("x", np.pi) * rot
|
|
105
|
+
return rot.as_matrix()
|
|
106
|
+
|
|
107
|
+
def set_param_eucli_shot(self, approx: bool) -> None:
|
|
108
|
+
"""
|
|
109
|
+
Setting up Euclidean parameters projeucli, pos_shot_eucli, mat_rot_eucli.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
approx (bool): True if you want to use approx euclidean system.
|
|
113
|
+
"""
|
|
114
|
+
if approx:
|
|
115
|
+
self.projeucli = ApproxEuclideanProj(self.pos_shot[0], self.pos_shot[1])
|
|
116
|
+
else:
|
|
117
|
+
self.projeucli = LocalEuclideanProj(self.pos_shot[0], self.pos_shot[1])
|
|
118
|
+
|
|
119
|
+
self.mat_rot_eucli = self.projeucli.mat_to_mat_eucli(self.pos_shot[0],
|
|
120
|
+
self.pos_shot[1],
|
|
121
|
+
self.mat_rot)
|
|
122
|
+
self.approxeucli = approx
|
|
123
|
+
self.pos_shot_eucli = self.projeucli.world_to_eucli(self.pos_shot)
|
|
124
|
+
|
|
125
|
+
def set_z_nadir(self, z_nadir: float) -> None:
|
|
126
|
+
"""
|
|
127
|
+
Give z nadir to the shot.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
z_nadir (flaot): z_nadir of the shot.
|
|
131
|
+
"""
|
|
132
|
+
self.z_nadir = z_nadir
|
|
133
|
+
|
|
134
|
+
def set_unit_angle(self, unit_angle: str) -> None:
|
|
135
|
+
"""
|
|
136
|
+
Allows you to change the orientation angle unit.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
unit_angle (str): Unit angle.
|
|
140
|
+
"""
|
|
141
|
+
if unit_angle != self.unit_angle:
|
|
142
|
+
self.unit_angle = unit_angle
|
|
143
|
+
if unit_angle == "radian":
|
|
144
|
+
self.ori_shot = self.ori_shot*np.pi/180
|
|
145
|
+
else:
|
|
146
|
+
self.ori_shot = self.ori_shot*180/np.pi
|
|
147
|
+
|
|
148
|
+
def set_type_z(self, type_z: str) -> None:
|
|
149
|
+
"""
|
|
150
|
+
Allows you to change the type of z.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
type_z (str): z type height or altitude.
|
|
154
|
+
"""
|
|
155
|
+
if type_z == "height":
|
|
156
|
+
self.pos_shot[2] = ProjEngine().tranform_height(self.pos_shot)
|
|
157
|
+
else:
|
|
158
|
+
self.pos_shot[2] = ProjEngine().tranform_altitude(self.pos_shot)
|
|
159
|
+
|
|
160
|
+
def set_linear_alteration(self, linear_alteration: bool) -> None:
|
|
161
|
+
"""
|
|
162
|
+
Allows you to correct or de-correct the linear alteration.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
linear_alteration (bool): Linear alteration boolean.
|
|
166
|
+
"""
|
|
167
|
+
if linear_alteration != self.linear_alteration:
|
|
168
|
+
self.linear_alteration = linear_alteration
|
|
169
|
+
if linear_alteration:
|
|
170
|
+
self.pos_shot[2] = self.get_z_add_scale_factor()
|
|
171
|
+
else:
|
|
172
|
+
self.pos_shot[2] = self.get_z_remove_scale_factor()
|
|
173
|
+
|
|
174
|
+
def set_order_axe(self, order_axe: str) -> None:
|
|
175
|
+
"""
|
|
176
|
+
Allows to change order of axe for the matrice and angle.
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
order_axe (str): New order axe.
|
|
180
|
+
"""
|
|
181
|
+
if order_axe != self.order_axe:
|
|
182
|
+
self.order_axe = order_axe
|
|
183
|
+
order_xyz = check_order_axe(self.order_axe)
|
|
184
|
+
unitori = self.unit_angle == "degree"
|
|
185
|
+
self.ori_shot = -(R.from_euler("x", np.pi) *
|
|
186
|
+
R.from_matrix(self.mat_rot)).as_euler(order_xyz, degrees=unitori)
|
|
187
|
+
|
|
188
|
+
def get_z_remove_scale_factor(self) -> float:
|
|
189
|
+
"""
|
|
190
|
+
Return Z after removing the scale factor. The Z of the object is NOT modified.
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
float: z without linear alteration.
|
|
194
|
+
"""
|
|
195
|
+
if self.z_nadir:
|
|
196
|
+
scale_factor = ProjEngine().get_scale_factor(self.pos_shot[0],
|
|
197
|
+
self.pos_shot[1])
|
|
198
|
+
new_z = (self.pos_shot[2] + scale_factor * self.z_nadir) / (1 + scale_factor)
|
|
199
|
+
else:
|
|
200
|
+
raise ValueError(f"No removing linear alteration of the z shot {self.name_shot}, "
|
|
201
|
+
"because no dtm or no set z_nadir of shot. For setting z_nadir "
|
|
202
|
+
"of shots make dtm or add work.set_z_nadir_shot()")
|
|
203
|
+
|
|
204
|
+
return new_z
|
|
205
|
+
|
|
206
|
+
def get_z_add_scale_factor(self) -> float:
|
|
207
|
+
"""
|
|
208
|
+
Return Z after adding the scale factor. The Z of the object is NOT modified.
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
float: z with linear alteration.
|
|
212
|
+
"""
|
|
213
|
+
if self.z_nadir:
|
|
214
|
+
scale_factor = ProjEngine().get_scale_factor(self.pos_shot[0],
|
|
215
|
+
self.pos_shot[1])
|
|
216
|
+
new_z = self.pos_shot[2] + scale_factor * (self.pos_shot[2] - self.z_nadir)
|
|
217
|
+
else:
|
|
218
|
+
raise ValueError(f"No adding linear alteration of the z shot {self.name_shot}, "
|
|
219
|
+
"because no dtm or no set z_nadir of shot. For setting z_nadir "
|
|
220
|
+
"of shots make dtm or add work.set_z_nadir_shot()")
|
|
221
|
+
|
|
222
|
+
return new_z
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Workdata data class module.
|
|
3
|
+
"""
|
|
4
|
+
import numpy as np
|
|
5
|
+
from pyproj import CRS, exceptions
|
|
6
|
+
from borea.datastruct.shot import Shot
|
|
7
|
+
from borea.datastruct.camera import Camera
|
|
8
|
+
from borea.datastruct.gcp import GCP
|
|
9
|
+
from borea.geodesy.proj_engine import ProjEngine
|
|
10
|
+
from borea.datastruct.dtm import Dtm
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# pylint: disable-next=too-many-instance-attributes
|
|
14
|
+
class Workdata:
|
|
15
|
+
"""
|
|
16
|
+
Workdata class.
|
|
17
|
+
"""
|
|
18
|
+
def __init__(self, name: str) -> None:
|
|
19
|
+
"""
|
|
20
|
+
Class definition of Workdata.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
name (str): Name of the worksite.
|
|
24
|
+
"""
|
|
25
|
+
self.name = name
|
|
26
|
+
self.shots = {}
|
|
27
|
+
self.cameras = {}
|
|
28
|
+
self.co_points = {}
|
|
29
|
+
self.gcp2d = {}
|
|
30
|
+
self.gcp3d = {}
|
|
31
|
+
self.co_pts_world = {}
|
|
32
|
+
self.gcp2d_in_world = {}
|
|
33
|
+
self.type_z_data = None
|
|
34
|
+
self.type_z_shot = None
|
|
35
|
+
self.approxeucli = False
|
|
36
|
+
|
|
37
|
+
# pylint: disable-next=too-many-arguments
|
|
38
|
+
def add_shot(self, name_shot: str, pos_shot: np.ndarray,
|
|
39
|
+
ori_shot: np.ndarray, name_cam: str,
|
|
40
|
+
unit_angle: str, linear_alteration: bool,
|
|
41
|
+
order_axe: str) -> None:
|
|
42
|
+
"""
|
|
43
|
+
Add Shot to the attribut Shots.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
name_shot (str): Name of the shot.
|
|
47
|
+
pos_shot (np.array): Array of coordinate position [X, Y, Z].
|
|
48
|
+
ori_shot (np.array): Array of orientation of the shot [Omega, Phi, Kappa].
|
|
49
|
+
name_cam (str): Name of the camera.
|
|
50
|
+
unit_angle (str): Unit of angle 'degrees', 'radian'.
|
|
51
|
+
linear_alteration (bool): True if z shot is correct of linear alteration.
|
|
52
|
+
order_axe (str): Order of rotation matrix axes,
|
|
53
|
+
"""
|
|
54
|
+
self.shots[name_shot] = Shot(name_shot=name_shot,
|
|
55
|
+
pos_shot=pos_shot,
|
|
56
|
+
ori_shot=ori_shot,
|
|
57
|
+
name_cam=name_cam,
|
|
58
|
+
unit_angle=unit_angle,
|
|
59
|
+
linear_alteration=linear_alteration,
|
|
60
|
+
order_axe=order_axe)
|
|
61
|
+
|
|
62
|
+
def set_proj(self, epsg: int, path_geoid: list = None) -> None:
|
|
63
|
+
"""
|
|
64
|
+
Setup a projection system to the worksite.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
epsg (int): Code epsg of the porjection ex: 2154.
|
|
68
|
+
path_geoid (str): List of GeoTIFF which represents the geoid in grid form.
|
|
69
|
+
"""
|
|
70
|
+
ProjEngine.clear()
|
|
71
|
+
try: # Check if the epsg exist
|
|
72
|
+
crs = CRS.from_epsg(epsg)
|
|
73
|
+
del crs
|
|
74
|
+
except exceptions.CRSError as e_info:
|
|
75
|
+
raise exceptions.CRSError(f"Your EPSG:{epsg} doesn't exist") from e_info
|
|
76
|
+
|
|
77
|
+
ProjEngine().set_epsg(epsg, path_geoid)
|
|
78
|
+
|
|
79
|
+
# pylint: disable-next=too-many-arguments
|
|
80
|
+
def add_camera(self, name_camera: str, ppax: float, ppay: float,
|
|
81
|
+
focal: float, width: int, height: int) -> None:
|
|
82
|
+
"""
|
|
83
|
+
Add data camera in the Worksite.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
name_camera (str): Name of the camera.
|
|
87
|
+
ppax (float): Center of distortion in x.
|
|
88
|
+
ppay (float): Center of distortion in y.
|
|
89
|
+
focal (float): Focal of the camera.
|
|
90
|
+
width (int): Width of the image camera.
|
|
91
|
+
height (int): Height of the image camera.
|
|
92
|
+
"""
|
|
93
|
+
self.cameras[name_camera] = Camera(name_camera=name_camera,
|
|
94
|
+
ppax=ppax,
|
|
95
|
+
ppay=ppay,
|
|
96
|
+
focal=focal,
|
|
97
|
+
width=width,
|
|
98
|
+
height=height)
|
|
99
|
+
|
|
100
|
+
def add_co_point(self, name_point: str, name_shot: str, coor2d: np.ndarray) -> None:
|
|
101
|
+
"""
|
|
102
|
+
Add linking point between acquisition in two part.
|
|
103
|
+
One in self.co_points a dict with name_point the key and list of acquisition the result.
|
|
104
|
+
And One in self.shot[name_shot].co_points a dict whit
|
|
105
|
+
name_point the key and list of coordinate x (column) y (line) the result in list.
|
|
106
|
+
|
|
107
|
+
Agrs:
|
|
108
|
+
name_point (str): Name of the connecting point.
|
|
109
|
+
name_shot (str): Name of the acquisition.
|
|
110
|
+
coor2d (array): Pixel position in the shot [x, y] = [column, line]
|
|
111
|
+
"""
|
|
112
|
+
if name_shot not in self.shots:
|
|
113
|
+
raise ValueError(f"The shot {name_shot} doesn't exist in list of shots.")
|
|
114
|
+
|
|
115
|
+
if name_point not in self.co_points:
|
|
116
|
+
self.co_points[name_point] = []
|
|
117
|
+
|
|
118
|
+
if name_point not in self.shots[name_shot].co_points:
|
|
119
|
+
self.shots[name_shot].co_points[name_point] = coor2d
|
|
120
|
+
else:
|
|
121
|
+
print("\n :--------------------------:")
|
|
122
|
+
print("Warning : connecting point duplicate.")
|
|
123
|
+
print(f"The point {name_point} already exists in the shot {name_shot}.")
|
|
124
|
+
print("Keep first point with coordinates " +
|
|
125
|
+
f"{self.shots[name_shot].co_points[name_point]}.")
|
|
126
|
+
print(":--------------------------:")
|
|
127
|
+
|
|
128
|
+
self.co_points[name_point].append(name_shot)
|
|
129
|
+
|
|
130
|
+
def add_gcp2d(self, name_point: str, name_shot: str, coor2d: np.ndarray) -> None:
|
|
131
|
+
"""
|
|
132
|
+
Add linking point between acquisition in two part.
|
|
133
|
+
One in self.gcp2d a dict with name_point the key
|
|
134
|
+
and list of acquisition the result.
|
|
135
|
+
And One in self.shot[name_shot].gcp2d a dict whit
|
|
136
|
+
name_point the key and list of coordinate x (column) y (line) the result in list.
|
|
137
|
+
|
|
138
|
+
Agrs:
|
|
139
|
+
name_point (str): Name of the connecting point.
|
|
140
|
+
name_shot (str): Name of the acquisition.
|
|
141
|
+
coor2d (array): Pixel position in the shot [x, y] = [column, line]
|
|
142
|
+
"""
|
|
143
|
+
try:
|
|
144
|
+
self.shots[name_shot]
|
|
145
|
+
except KeyError as e_info:
|
|
146
|
+
raise ValueError(f"The shot {name_shot} doesn't exist in list of shots.") from e_info
|
|
147
|
+
|
|
148
|
+
if name_point not in self.gcp2d:
|
|
149
|
+
self.gcp2d[name_point] = []
|
|
150
|
+
|
|
151
|
+
if name_point not in self.shots[name_shot].gcp2d:
|
|
152
|
+
self.shots[name_shot].gcp2d[name_point] = coor2d
|
|
153
|
+
else:
|
|
154
|
+
print("\n :--------------------------:")
|
|
155
|
+
print("Warning : connecting point duplicate.")
|
|
156
|
+
print(f"The point {name_point} already exists in the shot {name_shot}.")
|
|
157
|
+
print("Keep first point with coordinates " +
|
|
158
|
+
f"{self.shots[name_shot].gcp2d[name_point]}.")
|
|
159
|
+
print(":--------------------------:")
|
|
160
|
+
|
|
161
|
+
self.gcp2d[name_point].append(name_shot)
|
|
162
|
+
|
|
163
|
+
def add_gcp3d(self, name_gcp: str, code_gcp: str, coor_gcp: np.ndarray) -> None:
|
|
164
|
+
"""
|
|
165
|
+
Add GCP in the Worksite.
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
name_gcp (str): Name of the gcp.
|
|
169
|
+
code_gcp (str): IGN code to differentiate between support points (1, 2, 3)
|
|
170
|
+
and control points (11, 12, 13).
|
|
171
|
+
1 means precision in Z, 2 in X and Y and 3 in X, Y, Z.
|
|
172
|
+
coor_gcp (numpy.array): Array of ground coordinate [X, Y, Z].
|
|
173
|
+
"""
|
|
174
|
+
self.gcp3d[name_gcp] = GCP(name_gcp, code_gcp, coor_gcp)
|
|
175
|
+
|
|
176
|
+
def set_dtm(self, path_dtm: str, type_dtm: str) -> None:
|
|
177
|
+
"""
|
|
178
|
+
Set class DtM to the worksite.
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
path_dtm (str): Path to the dtm.
|
|
182
|
+
type (str): Type of the dtm "altitude" or "height".
|
|
183
|
+
"""
|
|
184
|
+
if path_dtm:
|
|
185
|
+
if type_dtm not in ["altitude", "height"]:
|
|
186
|
+
raise ValueError(f"The dtm's type {type_dtm} isn't correct"
|
|
187
|
+
" ('altitude' or 'height')")
|
|
188
|
+
|
|
189
|
+
Dtm.clear()
|
|
190
|
+
Dtm().set_dtm(path_dtm, type_dtm)
|
|
191
|
+
|
|
192
|
+
def set_approx_eucli_proj(self, approx: bool) -> None:
|
|
193
|
+
"""
|
|
194
|
+
Setup approxeucli in worksite.
|
|
195
|
+
|
|
196
|
+
Args:
|
|
197
|
+
apprx (bool): True if there are not projengine.
|
|
198
|
+
"""
|
|
199
|
+
self.approxeucli = approx
|
|
200
|
+
|
|
201
|
+
def set_type_z_shot(self, type_z_shot: str) -> None:
|
|
202
|
+
"""
|
|
203
|
+
Setup type_z_shot in worksite.
|
|
204
|
+
|
|
205
|
+
Args:
|
|
206
|
+
type_z_shot (str): altitude or height.
|
|
207
|
+
"""
|
|
208
|
+
self.type_z_shot = type_z_shot
|
|
209
|
+
|
|
210
|
+
def set_type_z_data(self, type_z_data: str) -> None:
|
|
211
|
+
"""
|
|
212
|
+
Setup type_z_data with one condition if is None.
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
type_z_data (str): altitude or height.
|
|
216
|
+
"""
|
|
217
|
+
if type_z_data:
|
|
218
|
+
self.type_z_data = type_z_data
|
|
219
|
+
else:
|
|
220
|
+
self.type_z_data = self.type_z_shot
|
borea/format/__init__.py
ADDED
|
File without changes
|