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
|
File without changes
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Function to normalize data.
|
|
3
|
+
"""
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def normalize(array: np.ndarray) -> tuple:
|
|
8
|
+
"""
|
|
9
|
+
Normalize array.
|
|
10
|
+
|
|
11
|
+
Args:
|
|
12
|
+
array (np.array): Array data to normalize.
|
|
13
|
+
|
|
14
|
+
Returns:
|
|
15
|
+
tuple: data normalize, offset of data and scale of data.
|
|
16
|
+
"""
|
|
17
|
+
offset = (np.min(array) + np.max(array))/2
|
|
18
|
+
scale = (np.max(array) - np.min(array))/2
|
|
19
|
+
array_norm = (array - offset) / scale
|
|
20
|
+
return array_norm, offset, scale
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def dist_2pts(pt1: np.ndarray, pt2: np.ndarray) -> float:
|
|
24
|
+
"""
|
|
25
|
+
Calculate the distance of two points.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
pt1 (np.array): Coordinates of the first point.
|
|
29
|
+
pt2 (np.array): Coordinates of the second point.
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
float: The distance.
|
|
33
|
+
"""
|
|
34
|
+
return np.linalg.norm(pt1 - pt2)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def min_max_pt(array: np.ndarray, type_m: str) -> tuple:
|
|
38
|
+
"""
|
|
39
|
+
Get min or max of coordinnate 2D in an array of dim (2,n).
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
array (np.array): Array data to get min or max.
|
|
43
|
+
type_m (str): Type min or max.
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
tuple: min or max Coordinate of one point and index in array.
|
|
47
|
+
"""
|
|
48
|
+
if type_m == "min":
|
|
49
|
+
func = np.argmin
|
|
50
|
+
else:
|
|
51
|
+
func = np.argmax
|
|
52
|
+
|
|
53
|
+
arg_col = func(array[0])
|
|
54
|
+
arg_lin = func(array[1])
|
|
55
|
+
pt_col = array[:, arg_col]
|
|
56
|
+
pt_lin = array[:, arg_lin]
|
|
57
|
+
|
|
58
|
+
if (pt_col == pt_lin).all():
|
|
59
|
+
return pt_col, arg_col
|
|
60
|
+
|
|
61
|
+
d1 = dist_2pts(np.array([0, 0]), pt_col)
|
|
62
|
+
d2 = dist_2pts(np.array([0, 0]), pt_lin)
|
|
63
|
+
if (d1 <= d2 and type_m == "min") or (d1 >= d2 and type_m == "max"):
|
|
64
|
+
return pt_col, arg_col
|
|
65
|
+
|
|
66
|
+
return pt_lin, arg_lin
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def angle_degree_2vect(u: np.ndarray, v: np.ndarray) -> float:
|
|
70
|
+
"""
|
|
71
|
+
Calculates degree angle between two vectors.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
u (np.array): Fisrt vector.
|
|
75
|
+
v (np.array): Second vector.
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
float: Degree angle between two vectors.
|
|
79
|
+
"""
|
|
80
|
+
nu = np.linalg.norm(u)
|
|
81
|
+
nv = np.linalg.norm(v)
|
|
82
|
+
costheta = (u @ v)/(nu * nv)
|
|
83
|
+
return np.arccos(costheta)*180/np.pi
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module math for bundle parameter.
|
|
3
|
+
"""
|
|
4
|
+
import numpy as np
|
|
5
|
+
from borea.datastruct.shot import Shot
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def set_param_bundle_diff(shot: Shot, coor_eucli: np.ndarray) -> tuple:
|
|
9
|
+
"""
|
|
10
|
+
Setting up the A vector, U vector and V matrix parameters for the differential function
|
|
11
|
+
of beam parameters, in the Euclidean reference frame.
|
|
12
|
+
A = M - S
|
|
13
|
+
U = R @ A
|
|
14
|
+
U = [u1, u2, u3]
|
|
15
|
+
V = [[u3, 0,-u1][ 0,u3,-u2]]
|
|
16
|
+
M euclidean point, S euclidean position shot, R rotation matrix euclidean to image.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
shot (Shot): The shot in which we work.
|
|
20
|
+
coor_eucli (np.array): Euclidean coordinates of the point.
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
tuple: vector A, vector U and matrix V.
|
|
24
|
+
"""
|
|
25
|
+
vect_a = np.vstack([coor_eucli[0] - shot.pos_shot_eucli[0],
|
|
26
|
+
coor_eucli[1] - shot.pos_shot_eucli[1],
|
|
27
|
+
coor_eucli[2] - shot.pos_shot_eucli[2]]) # vect_a = M-S
|
|
28
|
+
vect_u = shot.mat_rot_eucli @ vect_a # U = RA
|
|
29
|
+
|
|
30
|
+
mat_v = np.zeros((2 * len(vect_u[0]), 3))
|
|
31
|
+
mat_v[::2, 0] = vect_u[2]
|
|
32
|
+
mat_v[::2, 2] = -vect_u[0]
|
|
33
|
+
mat_v[1::2, 1] = vect_u[2]
|
|
34
|
+
mat_v[1::2, 2] = -vect_u[1]
|
|
35
|
+
|
|
36
|
+
return vect_a, vect_u, mat_v
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module math
|
|
3
|
+
"""
|
|
4
|
+
from scipy.sparse import coo_matrix
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def invert_diag_sparse_matrix_3_3(mat_inv: np.ndarray) -> np.ndarray:
|
|
9
|
+
"""
|
|
10
|
+
Block matrix inversion.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
mat (np.array): Matrix to flip.
|
|
14
|
+
|
|
15
|
+
Returns:
|
|
16
|
+
np.array: Flip matrix.
|
|
17
|
+
"""
|
|
18
|
+
mat = np.c_[np.pad(mat_inv.diagonal(-2), (2, 0)),
|
|
19
|
+
np.pad(mat_inv.diagonal(-1), (1, 0)),
|
|
20
|
+
mat_inv.diagonal(0),
|
|
21
|
+
np.pad(mat_inv.diagonal(1), (0, 1)),
|
|
22
|
+
np.pad(mat_inv.diagonal(2), (0, 2))]
|
|
23
|
+
|
|
24
|
+
mat[::3, :] = np.roll(mat[::3, :], -2)
|
|
25
|
+
mat[1::3, :] = np.roll(mat[1::3, :], -1)
|
|
26
|
+
|
|
27
|
+
data = np.linalg.inv(mat[:, :-2].reshape(1, -1, 3, 3)).flatten()
|
|
28
|
+
coord_i = np.repeat(np.arange(mat_inv.shape[0]), 3)
|
|
29
|
+
coord_j = np.tile(np.arange(mat_inv.shape[0]).reshape(-1, 3), 3).flatten()
|
|
30
|
+
|
|
31
|
+
return coo_matrix((data, (coord_i, coord_j)), shape=mat_inv.shape).tocsr()
|
|
File without changes
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module for class singleton
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Singleton(type):
|
|
7
|
+
"""
|
|
8
|
+
Class Singleton for Dtm and ProjEngine.
|
|
9
|
+
It's a design pattern, belonging to the category of creation patterns,
|
|
10
|
+
whose aim is to restrict the instantiation of a class to a single object.
|
|
11
|
+
"""
|
|
12
|
+
_instances = {}
|
|
13
|
+
|
|
14
|
+
def __call__(cls, *args, **kwargs):
|
|
15
|
+
if cls not in cls._instances:
|
|
16
|
+
cls._instances[cls] = super().__call__(*args, **kwargs)
|
|
17
|
+
return cls._instances[cls]
|
|
18
|
+
|
|
19
|
+
def clear(cls):
|
|
20
|
+
"""
|
|
21
|
+
Clear instances
|
|
22
|
+
"""
|
|
23
|
+
_ = cls._instances.pop(cls, None)
|
|
File without changes
|
borea/utils/xml/xml.py
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Function to implement xml.
|
|
3
|
+
"""
|
|
4
|
+
import xml.etree.ElementTree as ET
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def format_xml(elem: any, prec: str = ".5f") -> str:
|
|
9
|
+
"""
|
|
10
|
+
Write item in xml format.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
elem (any): The element to write in xml format.
|
|
14
|
+
prec (str): Precision of the element if is a number.
|
|
15
|
+
|
|
16
|
+
Returns:
|
|
17
|
+
str: elem in xml format.
|
|
18
|
+
"""
|
|
19
|
+
if isinstance(elem, float) and np.isnan(elem):
|
|
20
|
+
return "0.00000"
|
|
21
|
+
if isinstance(elem, (float, np.float32, np.float64)):
|
|
22
|
+
return f"{elem:{prec}}"
|
|
23
|
+
if elem is None:
|
|
24
|
+
return ""
|
|
25
|
+
|
|
26
|
+
return f"{elem}"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def indent(elem: ET, level: int = 0) -> None:
|
|
30
|
+
"""
|
|
31
|
+
Structure the xml file.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
elem (ET): The xml to write.
|
|
35
|
+
level (int): Level of structure.
|
|
36
|
+
"""
|
|
37
|
+
i = "\n" + level * " "
|
|
38
|
+
if len(elem):
|
|
39
|
+
if not elem.text or not elem.text.strip():
|
|
40
|
+
elem.text = i + " "
|
|
41
|
+
if not elem.tail or not elem.tail.strip():
|
|
42
|
+
elem.tail = i
|
|
43
|
+
for subelem in elem:
|
|
44
|
+
indent(subelem, level + 1)
|
|
45
|
+
if not elem.tail or not elem.tail.strip():
|
|
46
|
+
elem.tail = i
|
|
47
|
+
else:
|
|
48
|
+
if level and (not elem.tail or not elem.tail.strip()):
|
|
49
|
+
elem.tail = i
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def add_elem(xml: ET, balises: list, vals: list, prec: str = ".5f") -> None:
|
|
53
|
+
"""
|
|
54
|
+
Add a list of element to the ET.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
xml (ET): The xml to add elem.
|
|
58
|
+
balises (list): List of name of the balise.
|
|
59
|
+
vals (list): List of item to put on.
|
|
60
|
+
prec (str): Precision of the element if is a number.
|
|
61
|
+
"""
|
|
62
|
+
for balise, val in zip(balises, vals):
|
|
63
|
+
ET.SubElement(xml, balise).text = format_xml(val, prec)
|
|
File without changes
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Worksite data class module.
|
|
3
|
+
"""
|
|
4
|
+
import numpy as np
|
|
5
|
+
import pandas as pd
|
|
6
|
+
from borea.datastruct.dtm import Dtm
|
|
7
|
+
from borea.datastruct.workdata import Workdata
|
|
8
|
+
from borea.geodesy.proj_engine import ProjEngine
|
|
9
|
+
from borea.transform_world_image.transform_shot.image_world_shot import ImageWorldShot
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Worksite(Workdata):
|
|
13
|
+
"""
|
|
14
|
+
Worksite class, class main of the tools.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
name (str): Name of the worksite.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def get_point_image_dataframe(self, type_point: str, control_type: list = None) -> pd.DataFrame:
|
|
21
|
+
"""
|
|
22
|
+
Retrieves id_pt, id_img, column, line in a pandas of the requested point type.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
type_point (str): "co_points" or "gcp2d" depending on what you want to get.
|
|
26
|
+
control_type (list): Type controle for gcp.
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
pandas: Pandas table.
|
|
30
|
+
"""
|
|
31
|
+
if type_point not in ["co_points", "gcp2d", "gcp3d"]:
|
|
32
|
+
raise ValueError(f"type_point {type_point} is incorrect,['co_points','gcp2d','gcp3d']")
|
|
33
|
+
|
|
34
|
+
if type_point == "co_points" or not control_type:
|
|
35
|
+
control_type = []
|
|
36
|
+
|
|
37
|
+
type_iter = type_point if type_point != "gcp3d" else "gcp2d"
|
|
38
|
+
|
|
39
|
+
id_pt = []
|
|
40
|
+
id_img = []
|
|
41
|
+
coor = []
|
|
42
|
+
for name_pt, list_shot in getattr(self, type_iter).items():
|
|
43
|
+
if control_type and self.gcp3d[name_pt].code not in control_type:
|
|
44
|
+
continue
|
|
45
|
+
for name_shot in list_shot:
|
|
46
|
+
id_pt.append(name_pt)
|
|
47
|
+
id_img.append(name_shot)
|
|
48
|
+
coor.append(getattr(self.shots[name_shot], type_point)[name_pt])
|
|
49
|
+
|
|
50
|
+
coor = np.array(coor)
|
|
51
|
+
return pd.DataFrame({"id_pt": id_pt, "id_img": id_img,
|
|
52
|
+
"column": coor[:, 0], "line": coor[:, 1]})
|
|
53
|
+
|
|
54
|
+
def set_point_image_dataframe(self, pd_mes: pd.DataFrame, type_point: str) -> None:
|
|
55
|
+
"""
|
|
56
|
+
Set requested point type by pandas table id_pt, id_img, column, line.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
pd_mes (pd): Pandas table of data.
|
|
60
|
+
type_point (str): "co_points" or "gcp2d" depending on what you want to set.
|
|
61
|
+
"""
|
|
62
|
+
if type_point not in ["co_points", "gcp2d"]:
|
|
63
|
+
raise ValueError(f"type_point {type_point} is incorrect,['co_points','gcp2d']")
|
|
64
|
+
|
|
65
|
+
for _, row in pd_mes.iterrows():
|
|
66
|
+
try:
|
|
67
|
+
getattr(self.shots[row['id_img']],
|
|
68
|
+
type_point)[row['id_pt']] = np.array([row['column'], row['line']])
|
|
69
|
+
except KeyError:
|
|
70
|
+
continue
|
|
71
|
+
|
|
72
|
+
def get_point_world_dataframe(self, type_point: str, control_type: list) -> pd.DataFrame:
|
|
73
|
+
"""
|
|
74
|
+
Retrieves id_pt, x, y, z in a pandas of the requested point type.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
type_point (str): "co_points" or "gcp2d" depending on what you want to get.
|
|
78
|
+
control_type (list): Type controle for gcp.
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
pandas: Pandas table.
|
|
82
|
+
"""
|
|
83
|
+
if type_point not in ["co_points", "gcp2d"]:
|
|
84
|
+
raise ValueError(f"type_point {type_point} is incorrect,['co_points','gcp2d']")
|
|
85
|
+
|
|
86
|
+
out_pt, control_type = self.get_attr_transfo_pt(type_point, control_type)
|
|
87
|
+
|
|
88
|
+
id_pt = []
|
|
89
|
+
coor = []
|
|
90
|
+
for name_pt, coor_pt in getattr(self, out_pt).items():
|
|
91
|
+
if control_type and self.gcp3d[name_pt].code not in control_type:
|
|
92
|
+
continue
|
|
93
|
+
id_pt.append(name_pt)
|
|
94
|
+
coor.append(coor_pt)
|
|
95
|
+
|
|
96
|
+
coor = np.array(coor)
|
|
97
|
+
return pd.DataFrame({"id_pt": id_pt, "x": coor[:, 0], "y": coor[:, 1], "z": coor[:, 2]})
|
|
98
|
+
|
|
99
|
+
def set_point_world_dataframe(self, pd_mes: pd.DataFrame, type_point: str) -> None:
|
|
100
|
+
"""
|
|
101
|
+
Set requested point type by pandas table id_pt, x, y, z.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
pd_mes (pd): Pandas table of data.
|
|
105
|
+
type_point (str): "co_points" or "gcp2d" depending on what you want to set.
|
|
106
|
+
"""
|
|
107
|
+
if type_point not in ["co_points", "gcp2d"]:
|
|
108
|
+
raise ValueError(f"type_point {type_point} is incorrect,['co_points','gcp2d']")
|
|
109
|
+
|
|
110
|
+
out_pt, _ = self.get_attr_transfo_pt(type_point, None)
|
|
111
|
+
|
|
112
|
+
if "type" not in list(pd_mes.columns):
|
|
113
|
+
for _, row in pd_mes.iterrows():
|
|
114
|
+
getattr(self, out_pt)[row['id_pt']] = np.array([row['x'], row['y'], row['z']])
|
|
115
|
+
else:
|
|
116
|
+
for _, row in pd_mes.iterrows():
|
|
117
|
+
self.add_gcp3d(row['id_pt'], row['type'], np.array([row['x'], row['y'], row['z']]))
|
|
118
|
+
|
|
119
|
+
def get_coor_pt_img_and_world(self, name_shot: str, type_point: str) -> tuple:
|
|
120
|
+
"""
|
|
121
|
+
Recovers image and terrain data for all link points in the image.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
name_shot (str): Name of shot to take.
|
|
125
|
+
type_point (str): Type point to take "co_points" or "gcp2d".
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
tuple: np.array(obs_image), np.array(pt_world).
|
|
129
|
+
"""
|
|
130
|
+
if type_point not in ['co_points', 'gcp2d']:
|
|
131
|
+
raise ValueError(f"type point {type_point} is incorrect.['co_points','gcp2d']")
|
|
132
|
+
|
|
133
|
+
out_pt, _ = self.get_attr_transfo_pt(type_point, None)
|
|
134
|
+
|
|
135
|
+
if not getattr(self, out_pt):
|
|
136
|
+
raise ValueError(f"Attribut {out_pt} in worksite is empty.")
|
|
137
|
+
|
|
138
|
+
co_point = getattr(self.shots[name_shot], type_point)
|
|
139
|
+
world_pt = []
|
|
140
|
+
img_pt = []
|
|
141
|
+
for key_pt, img_coor in co_point.items():
|
|
142
|
+
try:
|
|
143
|
+
pt_world = getattr(self, out_pt)[key_pt]
|
|
144
|
+
world_pt.append(pt_world)
|
|
145
|
+
img_pt.append(img_coor)
|
|
146
|
+
except KeyError:
|
|
147
|
+
print(f"Point {key_pt}, doesn't have world coordinate, perhaps a single point.")
|
|
148
|
+
|
|
149
|
+
return np.stack(img_pt, axis=-1), np.stack(world_pt, axis=-1)
|
|
150
|
+
|
|
151
|
+
def set_param_shot(self, approx=False) -> None:
|
|
152
|
+
"""
|
|
153
|
+
Setting up different parameters in shot by data ressources.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
approx (bool): True if you want to use approx euclidean system.
|
|
157
|
+
"""
|
|
158
|
+
check_dtm = True
|
|
159
|
+
if not Dtm().path_dtm:
|
|
160
|
+
check_dtm = False
|
|
161
|
+
|
|
162
|
+
if not ProjEngine().geoid:
|
|
163
|
+
raise ValueError("you have not entered all the information required to set up"
|
|
164
|
+
" the projection system. Because type z shot != type z data.")
|
|
165
|
+
|
|
166
|
+
self.approxeucli = approx
|
|
167
|
+
for shot in self.shots.values():
|
|
168
|
+
shot.set_param_eucli_shot(approx)
|
|
169
|
+
if check_dtm:
|
|
170
|
+
cam = self.cameras[shot.name_cam]
|
|
171
|
+
z_nadir = ImageWorldShot(shot, cam).image_to_world(np.array([cam.ppax, cam.ppay]),
|
|
172
|
+
self.type_z_shot,
|
|
173
|
+
self.type_z_shot, False)[2]
|
|
174
|
+
shot.set_z_nadir(z_nadir)
|
|
175
|
+
|
|
176
|
+
def set_unit_shot(self, type_z: str = None, unit_angle: str = None,
|
|
177
|
+
linear_alteration: bool = None, order_axe: str = None) -> None:
|
|
178
|
+
"""
|
|
179
|
+
Allows you to change unit or parameter of shots.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
type_z (str): Unit of z shot you want.
|
|
183
|
+
unit_angle (str): Unit angle you want.
|
|
184
|
+
linear_alteration (bool): True if you want data corrected.
|
|
185
|
+
order_axe (str): Order of rotation matrice you want in your angle.
|
|
186
|
+
"""
|
|
187
|
+
if unit_angle not in ["degree", "radian", None]:
|
|
188
|
+
raise ValueError(f"unit_angle: {unit_angle} is not recognized,"
|
|
189
|
+
"recognized values are degree and radian.")
|
|
190
|
+
|
|
191
|
+
if type_z not in ["height", "altitude", None]:
|
|
192
|
+
raise ValueError(f"type_z: {type_z} is not recognized,"
|
|
193
|
+
"recognized values are altitude and height.")
|
|
194
|
+
|
|
195
|
+
if type_z == self.type_z_shot:
|
|
196
|
+
type_z = None
|
|
197
|
+
else:
|
|
198
|
+
self.type_z_shot = type_z
|
|
199
|
+
|
|
200
|
+
for shot in self.shots.values():
|
|
201
|
+
if unit_angle is not None:
|
|
202
|
+
shot.set_unit_angle(unit_angle)
|
|
203
|
+
if type_z is not None:
|
|
204
|
+
shot.set_type_z(type_z)
|
|
205
|
+
if linear_alteration is not None:
|
|
206
|
+
shot.set_linear_alteration(linear_alteration)
|
|
207
|
+
if order_axe is not None:
|
|
208
|
+
shot.set_order_axe(order_axe)
|
|
209
|
+
|
|
210
|
+
def calculate_barycentre(self) -> np.ndarray:
|
|
211
|
+
"""
|
|
212
|
+
Calculate barycentre of the worksite.
|
|
213
|
+
|
|
214
|
+
Returns:
|
|
215
|
+
np.array: The barycentre [X, Y, Z].
|
|
216
|
+
"""
|
|
217
|
+
size = len(self.shots)
|
|
218
|
+
pos = np.zeros((size, 3))
|
|
219
|
+
i = 0
|
|
220
|
+
for shot in self.shots.values():
|
|
221
|
+
pos[i, :] = shot.pos_shot
|
|
222
|
+
i += 1
|
|
223
|
+
return np.mean(pos, axis=0)
|
|
224
|
+
|
|
225
|
+
def get_attr_transfo_pt(self, type_point: str, control_type: list) -> tuple:
|
|
226
|
+
"""
|
|
227
|
+
Get string name of attribut where is save transformation image to world point.
|
|
228
|
+
|
|
229
|
+
Args:
|
|
230
|
+
type_point (str):"co_points" or "gcp2d"
|
|
231
|
+
depending on what you want.
|
|
232
|
+
control_type (list): Type controle for gcp.
|
|
233
|
+
"""
|
|
234
|
+
if type_point == 'co_points':
|
|
235
|
+
out_pt = "co_pts_world"
|
|
236
|
+
control_type = []
|
|
237
|
+
else:
|
|
238
|
+
out_pt = "gcp2d_in_world"
|
|
239
|
+
|
|
240
|
+
return out_pt, control_type
|
borea/writer/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Photogrammetry site file writer module.
|
|
3
|
+
"""
|
|
4
|
+
import importlib
|
|
5
|
+
from borea.worksite.worksite import Worksite
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def manager_writer(writer: str, name: str, pathreturn: str, args: dict, work: Worksite) -> None:
|
|
9
|
+
"""
|
|
10
|
+
Photogrammetric site file writing function.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
writer (str): Output file format.
|
|
14
|
+
name (str): Name of the file.
|
|
15
|
+
pathreturn (str): Path to save the project.
|
|
16
|
+
args (dict): Other information for writing the file.
|
|
17
|
+
work (Worksite): The site to be recorded.
|
|
18
|
+
"""
|
|
19
|
+
try:
|
|
20
|
+
my_module = importlib.import_module("borea.writer.writer_" + writer.lower())
|
|
21
|
+
work = my_module.write(name, pathreturn, args, work)
|
|
22
|
+
except ModuleNotFoundError as e:
|
|
23
|
+
raise ValueError(f"{writer} file is not taken into account !!!") from e
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Photogrammetry worksite to writing in rpc.
|
|
3
|
+
"""
|
|
4
|
+
import os
|
|
5
|
+
from pathlib import Path, PureWindowsPath
|
|
6
|
+
from borea.worksite.worksite import Worksite
|
|
7
|
+
from borea.geodesy.proj_engine import ProjEngine
|
|
8
|
+
from borea.format.conl import Conl
|
|
9
|
+
from borea.geodesy.projectionlist.search_proj import search_info
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def write(name: str, folder_con: str, param_con: dict, work: Worksite) -> None:
|
|
13
|
+
"""
|
|
14
|
+
Converte Worksite in Conical class and save it in CON.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
name (str): Name of file begin.
|
|
18
|
+
folder_con (str): Path of folder to registration file .CON.
|
|
19
|
+
param_con (dict): None.
|
|
20
|
+
work (Worksite): The site to be recorded.
|
|
21
|
+
"""
|
|
22
|
+
_, _ = name, param_con
|
|
23
|
+
geoview_proj = search_info("EPSG", str(ProjEngine().epsg), "GEOVIEW")
|
|
24
|
+
|
|
25
|
+
for name_shot, shot in work.shots.items():
|
|
26
|
+
cam = work.cameras[shot.name_cam]
|
|
27
|
+
path_conical = os.path.join(Path(PureWindowsPath(folder_con)), f"{name_shot}.CON")
|
|
28
|
+
|
|
29
|
+
Conl(shot, cam, geoview_proj).save_conl(path_conical)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Photogrammetry worksite to writing dataframe to txt.
|
|
3
|
+
"""
|
|
4
|
+
import os
|
|
5
|
+
from pathlib import Path, PureWindowsPath
|
|
6
|
+
import pandas as pd
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def write_df_to_txt(name: str, pathreturn: str, df: pd.DataFrame) -> None:
|
|
10
|
+
"""
|
|
11
|
+
Writing DataFrame to txt in column.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
name (str): Name of the file.
|
|
15
|
+
pathreturn (str): Path to save the file.
|
|
16
|
+
df (pd.DataFrame): DataFrame to save.
|
|
17
|
+
"""
|
|
18
|
+
path_txt = os.path.join(Path(PureWindowsPath(pathreturn)), f"{name}.txt")
|
|
19
|
+
|
|
20
|
+
name_column = list(df.columns)
|
|
21
|
+
|
|
22
|
+
with open(path_txt, "w", encoding="utf-8") as file:
|
|
23
|
+
for _, row in df.iterrows():
|
|
24
|
+
wline = ""
|
|
25
|
+
for id_col in name_column:
|
|
26
|
+
if not isinstance(row[id_col], float):
|
|
27
|
+
wline += f"{row[id_col]} "
|
|
28
|
+
else:
|
|
29
|
+
wline += f"{round(row[id_col], 3)} "
|
|
30
|
+
wline += "\n"
|
|
31
|
+
file.write(wline)
|
|
32
|
+
file.close()
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Photogrammetry worksite to writing in opk.
|
|
3
|
+
"""
|
|
4
|
+
import os
|
|
5
|
+
from pathlib import Path, PureWindowsPath
|
|
6
|
+
import numpy as np
|
|
7
|
+
from borea.worksite.worksite import Worksite
|
|
8
|
+
from borea.utils.check.check_args_opk import check_header_file
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def write(name_opk: str, path_opk: str, args: dict, work: Worksite) -> None:
|
|
12
|
+
"""
|
|
13
|
+
Write function, to save a photogrammetric site in .opk format.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
name_opk (str): Name of the file writing.
|
|
17
|
+
path_opk (str): Path of folder to registration file .opk.
|
|
18
|
+
args (dict): Information for writing an opk file.
|
|
19
|
+
keys:
|
|
20
|
+
"order_axe" (str): Order of rotation matrix axes,
|
|
21
|
+
"header" (list): List of column type file.
|
|
22
|
+
"unit_angle" (str): Unit of angle 'degree' or 'radian'.
|
|
23
|
+
"linear_alteration" (bool): True if data corrected by
|
|
24
|
+
linear alteration.
|
|
25
|
+
work (Worksite): The site to be recorded.
|
|
26
|
+
"""
|
|
27
|
+
path_opk = os.path.join(Path(PureWindowsPath(path_opk)), f"{name_opk}.opk")
|
|
28
|
+
|
|
29
|
+
if args["header"]:
|
|
30
|
+
header, type_z = check_header_file(args["header"])
|
|
31
|
+
else:
|
|
32
|
+
header = ['N', 'X', 'Y', 'Z', 'O', 'P', 'K', 'C']
|
|
33
|
+
type_z = work.type_z_shot
|
|
34
|
+
|
|
35
|
+
if "S" in header:
|
|
36
|
+
raise ValueError("Letter S doesn't existe in writing header opk.")
|
|
37
|
+
|
|
38
|
+
work.set_unit_shot(type_z, args["unit_angle"], args["linear_alteration"], args["order_axe"])
|
|
39
|
+
|
|
40
|
+
header_file = ""
|
|
41
|
+
for i in header:
|
|
42
|
+
header_file += i + " "
|
|
43
|
+
|
|
44
|
+
try:
|
|
45
|
+
with open(path_opk, "w", encoding="utf-8") as file:
|
|
46
|
+
file.write(header_file)
|
|
47
|
+
file.write("\n")
|
|
48
|
+
keys = np.sort(list(work.shots))
|
|
49
|
+
line_writing = ""
|
|
50
|
+
for k in keys:
|
|
51
|
+
shot = work.shots[k]
|
|
52
|
+
dict_letter = {"N": shot.name_shot,
|
|
53
|
+
"X": str(shot.pos_shot[0]),
|
|
54
|
+
"Y": str(shot.pos_shot[1]),
|
|
55
|
+
"Z": str(shot.pos_shot[2]),
|
|
56
|
+
"O": str(shot.ori_shot[0]),
|
|
57
|
+
"P": str(shot.ori_shot[1]),
|
|
58
|
+
"K": str(shot.ori_shot[2]),
|
|
59
|
+
"C": shot.name_cam}
|
|
60
|
+
for i in range(8):
|
|
61
|
+
line_writing += dict_letter[header[i]]
|
|
62
|
+
if i != 7:
|
|
63
|
+
line_writing += " "
|
|
64
|
+
else:
|
|
65
|
+
line_writing += "\n"
|
|
66
|
+
|
|
67
|
+
file.write(line_writing)
|
|
68
|
+
file.close()
|
|
69
|
+
except FileNotFoundError as e:
|
|
70
|
+
raise ValueError("The path doesn't exist !!!", e) from e
|