pyvale 2025.5.3__cp311-cp311-macosx_14_0_arm64.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.

Potentially problematic release.


This version of pyvale might be problematic. Click here for more details.

Files changed (175) hide show
  1. pyvale/.dylibs/libomp.dylib +0 -0
  2. pyvale/__init__.py +89 -0
  3. pyvale/analyticmeshgen.py +102 -0
  4. pyvale/analyticsimdatafactory.py +91 -0
  5. pyvale/analyticsimdatagenerator.py +323 -0
  6. pyvale/blendercalibrationdata.py +15 -0
  7. pyvale/blenderlightdata.py +26 -0
  8. pyvale/blendermaterialdata.py +15 -0
  9. pyvale/blenderrenderdata.py +30 -0
  10. pyvale/blenderscene.py +488 -0
  11. pyvale/blendertools.py +420 -0
  12. pyvale/camera.py +146 -0
  13. pyvale/cameradata.py +69 -0
  14. pyvale/cameradata2d.py +84 -0
  15. pyvale/camerastereo.py +217 -0
  16. pyvale/cameratools.py +522 -0
  17. pyvale/cython/rastercyth.c +32211 -0
  18. pyvale/cython/rastercyth.cpython-311-darwin.so +0 -0
  19. pyvale/cython/rastercyth.py +640 -0
  20. pyvale/data/__init__.py +5 -0
  21. pyvale/data/cal_target.tiff +0 -0
  22. pyvale/data/case00_HEX20_out.e +0 -0
  23. pyvale/data/case00_HEX27_out.e +0 -0
  24. pyvale/data/case00_HEX8_out.e +0 -0
  25. pyvale/data/case00_TET10_out.e +0 -0
  26. pyvale/data/case00_TET14_out.e +0 -0
  27. pyvale/data/case00_TET4_out.e +0 -0
  28. pyvale/data/case13_out.e +0 -0
  29. pyvale/data/case16_out.e +0 -0
  30. pyvale/data/case17_out.e +0 -0
  31. pyvale/data/case18_1_out.e +0 -0
  32. pyvale/data/case18_2_out.e +0 -0
  33. pyvale/data/case18_3_out.e +0 -0
  34. pyvale/data/case25_out.e +0 -0
  35. pyvale/data/case26_out.e +0 -0
  36. pyvale/data/optspeckle_2464x2056px_spec5px_8bit_gblur1px.tiff +0 -0
  37. pyvale/dataset.py +325 -0
  38. pyvale/errorcalculator.py +109 -0
  39. pyvale/errordriftcalc.py +146 -0
  40. pyvale/errorintegrator.py +336 -0
  41. pyvale/errorrand.py +607 -0
  42. pyvale/errorsyscalib.py +134 -0
  43. pyvale/errorsysdep.py +327 -0
  44. pyvale/errorsysfield.py +414 -0
  45. pyvale/errorsysindep.py +808 -0
  46. pyvale/examples/__init__.py +5 -0
  47. pyvale/examples/basics/ex1_1_basicscalars_therm2d.py +131 -0
  48. pyvale/examples/basics/ex1_2_sensormodel_therm2d.py +158 -0
  49. pyvale/examples/basics/ex1_3_customsens_therm3d.py +216 -0
  50. pyvale/examples/basics/ex1_4_basicerrors_therm3d.py +153 -0
  51. pyvale/examples/basics/ex1_5_fielderrs_therm3d.py +168 -0
  52. pyvale/examples/basics/ex1_6_caliberrs_therm2d.py +133 -0
  53. pyvale/examples/basics/ex1_7_spatavg_therm2d.py +123 -0
  54. pyvale/examples/basics/ex2_1_basicvectors_disp2d.py +112 -0
  55. pyvale/examples/basics/ex2_2_vectorsens_disp2d.py +111 -0
  56. pyvale/examples/basics/ex2_3_sensangle_disp2d.py +139 -0
  57. pyvale/examples/basics/ex2_4_chainfielderrs_disp2d.py +196 -0
  58. pyvale/examples/basics/ex2_5_vectorfields3d_disp3d.py +109 -0
  59. pyvale/examples/basics/ex3_1_basictensors_strain2d.py +114 -0
  60. pyvale/examples/basics/ex3_2_tensorsens2d_strain2d.py +111 -0
  61. pyvale/examples/basics/ex3_3_tensorsens3d_strain3d.py +182 -0
  62. pyvale/examples/basics/ex4_1_expsim2d_thermmech2d.py +171 -0
  63. pyvale/examples/basics/ex4_2_expsim3d_thermmech3d.py +252 -0
  64. pyvale/examples/genanalyticdata/ex1_1_scalarvisualisation.py +35 -0
  65. pyvale/examples/genanalyticdata/ex1_2_scalarcasebuild.py +43 -0
  66. pyvale/examples/genanalyticdata/ex2_1_analyticsensors.py +80 -0
  67. pyvale/examples/imagedef2d/ex_imagedef2d_todisk.py +79 -0
  68. pyvale/examples/renderblender/ex1_1_blenderscene.py +121 -0
  69. pyvale/examples/renderblender/ex1_2_blenderdeformed.py +119 -0
  70. pyvale/examples/renderblender/ex2_1_stereoscene.py +128 -0
  71. pyvale/examples/renderblender/ex2_2_stereodeformed.py +131 -0
  72. pyvale/examples/renderblender/ex3_1_blendercalibration.py +120 -0
  73. pyvale/examples/renderrasterisation/ex_rastenp.py +153 -0
  74. pyvale/examples/renderrasterisation/ex_rastercyth_oneframe.py +218 -0
  75. pyvale/examples/renderrasterisation/ex_rastercyth_static_cypara.py +187 -0
  76. pyvale/examples/renderrasterisation/ex_rastercyth_static_pypara.py +190 -0
  77. pyvale/examples/visualisation/ex1_1_plot_traces.py +102 -0
  78. pyvale/examples/visualisation/ex2_1_animate_sim.py +89 -0
  79. pyvale/experimentsimulator.py +175 -0
  80. pyvale/field.py +128 -0
  81. pyvale/fieldconverter.py +351 -0
  82. pyvale/fieldsampler.py +111 -0
  83. pyvale/fieldscalar.py +166 -0
  84. pyvale/fieldtensor.py +218 -0
  85. pyvale/fieldtransform.py +388 -0
  86. pyvale/fieldvector.py +213 -0
  87. pyvale/generatorsrandom.py +505 -0
  88. pyvale/imagedef2d.py +569 -0
  89. pyvale/integratorfactory.py +240 -0
  90. pyvale/integratorquadrature.py +217 -0
  91. pyvale/integratorrectangle.py +165 -0
  92. pyvale/integratorspatial.py +89 -0
  93. pyvale/integratortype.py +43 -0
  94. pyvale/output.py +17 -0
  95. pyvale/pyvaleexceptions.py +11 -0
  96. pyvale/raster.py +31 -0
  97. pyvale/rastercy.py +77 -0
  98. pyvale/rasternp.py +603 -0
  99. pyvale/rendermesh.py +147 -0
  100. pyvale/sensorarray.py +178 -0
  101. pyvale/sensorarrayfactory.py +196 -0
  102. pyvale/sensorarraypoint.py +278 -0
  103. pyvale/sensordata.py +71 -0
  104. pyvale/sensordescriptor.py +213 -0
  105. pyvale/sensortools.py +142 -0
  106. pyvale/simcases/case00_HEX20.i +242 -0
  107. pyvale/simcases/case00_HEX27.i +242 -0
  108. pyvale/simcases/case00_HEX8.i +242 -0
  109. pyvale/simcases/case00_TET10.i +242 -0
  110. pyvale/simcases/case00_TET14.i +242 -0
  111. pyvale/simcases/case00_TET4.i +242 -0
  112. pyvale/simcases/case01.i +101 -0
  113. pyvale/simcases/case02.i +156 -0
  114. pyvale/simcases/case03.i +136 -0
  115. pyvale/simcases/case04.i +181 -0
  116. pyvale/simcases/case05.i +234 -0
  117. pyvale/simcases/case06.i +305 -0
  118. pyvale/simcases/case07.geo +135 -0
  119. pyvale/simcases/case07.i +87 -0
  120. pyvale/simcases/case08.geo +144 -0
  121. pyvale/simcases/case08.i +153 -0
  122. pyvale/simcases/case09.geo +204 -0
  123. pyvale/simcases/case09.i +87 -0
  124. pyvale/simcases/case10.geo +204 -0
  125. pyvale/simcases/case10.i +257 -0
  126. pyvale/simcases/case11.geo +337 -0
  127. pyvale/simcases/case11.i +147 -0
  128. pyvale/simcases/case12.geo +388 -0
  129. pyvale/simcases/case12.i +329 -0
  130. pyvale/simcases/case13.i +140 -0
  131. pyvale/simcases/case14.i +159 -0
  132. pyvale/simcases/case15.geo +337 -0
  133. pyvale/simcases/case15.i +150 -0
  134. pyvale/simcases/case16.geo +391 -0
  135. pyvale/simcases/case16.i +357 -0
  136. pyvale/simcases/case17.geo +135 -0
  137. pyvale/simcases/case17.i +144 -0
  138. pyvale/simcases/case18.i +254 -0
  139. pyvale/simcases/case18_1.i +254 -0
  140. pyvale/simcases/case18_2.i +254 -0
  141. pyvale/simcases/case18_3.i +254 -0
  142. pyvale/simcases/case19.geo +252 -0
  143. pyvale/simcases/case19.i +99 -0
  144. pyvale/simcases/case20.geo +252 -0
  145. pyvale/simcases/case20.i +250 -0
  146. pyvale/simcases/case21.geo +74 -0
  147. pyvale/simcases/case21.i +155 -0
  148. pyvale/simcases/case22.geo +82 -0
  149. pyvale/simcases/case22.i +140 -0
  150. pyvale/simcases/case23.geo +164 -0
  151. pyvale/simcases/case23.i +140 -0
  152. pyvale/simcases/case24.geo +79 -0
  153. pyvale/simcases/case24.i +123 -0
  154. pyvale/simcases/case25.geo +82 -0
  155. pyvale/simcases/case25.i +140 -0
  156. pyvale/simcases/case26.geo +166 -0
  157. pyvale/simcases/case26.i +140 -0
  158. pyvale/simcases/run_1case.py +61 -0
  159. pyvale/simcases/run_all_cases.py +69 -0
  160. pyvale/simcases/run_build_case.py +64 -0
  161. pyvale/simcases/run_example_cases.py +69 -0
  162. pyvale/simtools.py +67 -0
  163. pyvale/visualexpplotter.py +191 -0
  164. pyvale/visualimagedef.py +74 -0
  165. pyvale/visualimages.py +76 -0
  166. pyvale/visualopts.py +493 -0
  167. pyvale/visualsimanimator.py +111 -0
  168. pyvale/visualsimsensors.py +318 -0
  169. pyvale/visualtools.py +136 -0
  170. pyvale/visualtraceplotter.py +142 -0
  171. pyvale-2025.5.3.dist-info/METADATA +144 -0
  172. pyvale-2025.5.3.dist-info/RECORD +175 -0
  173. pyvale-2025.5.3.dist-info/WHEEL +6 -0
  174. pyvale-2025.5.3.dist-info/licenses/LICENSE +21 -0
  175. pyvale-2025.5.3.dist-info/top_level.txt +1 -0
pyvale/cameradata2d.py ADDED
@@ -0,0 +1,84 @@
1
+ # ==============================================================================
2
+ # pyvale: the python validation engine
3
+ # License: MIT
4
+ # Copyright (C) 2025 The Computer Aided Validation Team
5
+ # ==============================================================================
6
+
7
+ """
8
+ NOTE: This module is a feature under developement.
9
+ """
10
+
11
+ from dataclasses import dataclass, field
12
+ import numpy as np
13
+ from scipy.spatial.transform import Rotation
14
+
15
+ @dataclass(slots=True)
16
+ class CameraData2D:
17
+ pixels_count: np.ndarray | None = None
18
+ leng_per_px: float = 1.0e-3
19
+ bits: int = 8
20
+ roi_cent_world: np.ndarray | None = None
21
+
22
+ background: float = 0.5
23
+ sample_times: np.ndarray | None = None
24
+ angle: Rotation | None = None
25
+
26
+ subsample: int = 2
27
+
28
+ field_of_view: np.ndarray = field(init=False)
29
+ dynamic_range: int = field(init=False)
30
+
31
+ world_to_cam: np.ndarray = field(init=False)
32
+ cam_to_world: np.ndarray = field(init=False)
33
+
34
+ def __post_init__(self) -> None:
35
+
36
+ if self.pixels_count is None:
37
+ self.pixels_count = np.array((1000,1000),dtype=np.int32)
38
+
39
+ if self.roi_cent_world is None:
40
+ self.roi_cent_world = np.array((0.0,0.0,0.0),dtype=np.float64)
41
+
42
+ self.field_of_view = self.leng_per_px*(self.pixels_count.astype(np.float64))
43
+ self.dynamic_range = 2**self.bits
44
+ self.background = self.background*float(self.dynamic_range)
45
+
46
+ self.world_to_cam = self.field_of_view/2 - self.roi_cent_world[:-1]
47
+ self.cam_to_world = -self.world_to_cam
48
+
49
+
50
+ #@dataclass(slots=True)
51
+ #class CameraData2D:
52
+ # #shape=(n_px_X,n_px_Y)
53
+ # num_pixels: np.ndarray
54
+
55
+ # # Center location of the region of interest in world coords
56
+ # #shape=(3,) as (x,y,z)
57
+ # roi_center_world: np.ndarray
58
+
59
+ # # Converts pixels to length units to align with global coords
60
+ # leng_per_px: float
61
+
62
+ # #shape=(n_time_steps,)
63
+ # sample_times: np.ndarray | None = None
64
+
65
+ # #TODO: this only works for flat surfaces aligned with the axis
66
+ # view_axes: tuple[int,int] = (0,1)
67
+
68
+ # bits_sensor: int = 16
69
+ # bits_file: int = 16
70
+
71
+ # angle: Rotation | None = None
72
+
73
+ # field_of_view_center_local: np.ndarray = field(init=False)
74
+ # field_of_view_local: np.ndarray = field(init=False)
75
+ # roi_shift_world: np.ndarray = field(init=False)
76
+
77
+ # def __post_init__(self) -> None:
78
+ # self.field_of_view_local = self.num_pixels*self.leng_per_px
79
+ # self.field_of_view_center_local = self.field_of_view_local/2
80
+
81
+ # self.roi_shift_world = np.zeros_like(self.roi_center_world)
82
+ # for ii,vv in enumerate(self.view_axes):
83
+ # self.roi_shift_world[vv] = self.roi_center_world[vv] - \
84
+ # self.field_of_view_center_local[ii]
pyvale/camerastereo.py ADDED
@@ -0,0 +1,217 @@
1
+ # ==============================================================================
2
+ # pyvale: the python validation engine
3
+ # License: MIT
4
+ # Copyright (C) 2025 The Computer Aided Validation Team
5
+ # ==============================================================================
6
+
7
+ """
8
+ NOTE: This module is a feature under developement.
9
+ """
10
+
11
+ from typing import Self
12
+ from pathlib import Path
13
+ import numpy as np
14
+ import yaml
15
+ from scipy.spatial.transform import Rotation
16
+ from pyvale.cameradata import CameraData
17
+ from pyvale.pyvaleexceptions import BlenderError
18
+
19
+
20
+ class CameraStereo:
21
+ __slots__ = ("cam_data_0","cam_data_1","stereo_dist","stereo_rotation")
22
+
23
+ def __init__(self, cam_data_0: CameraData, cam_data_1: CameraData) -> None:
24
+ self.cam_data_0 = cam_data_0
25
+ self.cam_data_1 = cam_data_1
26
+
27
+ cam0_rot_matrix = Rotation.as_matrix(self.cam_data_0.rot_world)
28
+ cam1_rot_matrix = Rotation.as_matrix(self.cam_data_1.rot_world)
29
+ (self.stereo_rotation, _) = Rotation.align_vectors(cam0_rot_matrix,
30
+ cam1_rot_matrix)
31
+ dist = self.cam_data_0.pos_world - self.cam_data_1.pos_world
32
+ dist_rot = self.cam_data_0.rot_world.apply(dist)
33
+ inverse = self.stereo_rotation.inv().as_quat()
34
+ inverse[3] *= -1
35
+ inverse = Rotation.from_quat(inverse)
36
+ self.stereo_dist = inverse.apply(dist_rot)
37
+
38
+ @classmethod
39
+ def from_calibration(cls,
40
+ calib_path: Path,
41
+ pos_world_0: np.ndarray,
42
+ rot_world_0: Rotation,
43
+ focal_length: float) -> Self:
44
+ """A method to initialise the CameraStereo using a calibration file and
45
+ some additional parameters. This creates an instance of the CameraStereo
46
+ class from the calibration parameters.
47
+
48
+ Parameters
49
+ ----------
50
+ calib_path : Path
51
+ The path to the calibration file (in yaml format).
52
+ pos_world_0 : np.ndarray
53
+ The position of camera 0 in world coordinates.
54
+ rot_world_0 : Rotation
55
+ The rotation of camera 0 in world coordinates.
56
+ focal_length : float
57
+ The focal length of camera 0.
58
+
59
+ Returns
60
+ -------
61
+ Self
62
+ An instance of the CameraStereo class, given the specified parameters.
63
+ """
64
+ calib_params = yaml.safe_load(calib_path.read_text())
65
+ pixels_num_cam0 = np.array([calib_params['Cam0_Cx [pixels]']*2,
66
+ calib_params['Cam0_Cy [pixels]']*2])
67
+ pixels_num_cam1 = np.array([calib_params['Cam1_Cx [pixels]']*2,
68
+ calib_params['Cam1_Cy [pixels]']*2])
69
+ pixels_size = focal_length / calib_params["Cam0_Fx [pixels]"]
70
+ stereo_rotation = Rotation.from_euler("xyz", ([calib_params['Theta [deg]'],
71
+ calib_params['Phi [deg]'],
72
+ calib_params['Psi [deg]']]), degrees=True)
73
+ stereo_dist = np.array([calib_params["Tx [mm]"],
74
+ calib_params["Ty [mm]"],
75
+ calib_params["Tz [mm]"]])
76
+
77
+ rot_world_1 = stereo_rotation * rot_world_0
78
+
79
+ inverse = stereo_rotation.inv().as_quat()
80
+ inverse[3] *= -1
81
+ inverse = Rotation.from_quat(inverse)
82
+
83
+ dist_rot = inverse.inv().apply(stereo_dist)
84
+ dist = rot_world_0.inv().apply(dist_rot)
85
+ pos_world_1 = pos_world_0 - dist
86
+
87
+ cam_data_0 = CameraData(pixels_num=pixels_num_cam0,
88
+ pixels_size=np.array([pixels_size, pixels_size]),
89
+ pos_world=pos_world_0,
90
+ rot_world=rot_world_0,
91
+ roi_cent_world=np.array([0, 0, 0]),
92
+ focal_length=focal_length)
93
+ cam_data_1 = CameraData(pixels_num=pixels_num_cam1,
94
+ pixels_size=np.array([pixels_size, pixels_size]),
95
+ pos_world=pos_world_1,
96
+ rot_world=rot_world_1,
97
+ roi_cent_world=np.array([0, 0, 0]),
98
+ focal_length=focal_length)
99
+ camera_stereo = cls(cam_data_0, cam_data_1)
100
+
101
+ return camera_stereo
102
+
103
+ def save_calibration(self, base_dir: Path) -> None:
104
+ """A method to save a calibration file of the stereo system as a yaml.
105
+ This is so that the file can easily be read into python, but is also
106
+ user-readable.
107
+
108
+ Parameters
109
+ ----------
110
+ base_dir : Path
111
+ The base directory to which all files should be saved. The
112
+ calibration file will be saved in a sub-directory named "calibration"
113
+ within this directory.
114
+
115
+ Raises
116
+ ------
117
+ BlenderError
118
+ "The specified save directory does not exist"
119
+ """
120
+ stereo_rotation = self.stereo_rotation.as_euler("xyz", degrees=True)
121
+ calib_params = {
122
+ "Cam0_Fx [pixels]": float(self.cam_data_0.focal_length /
123
+ self.cam_data_0.pixels_size[0]),
124
+ "Cam0_Fy [pixels]": float(self.cam_data_0.focal_length /
125
+ self.cam_data_0.pixels_size[1]),
126
+ "Cam0_Fs [pixels]": 0,
127
+ "Cam0_Kappa 1": self.cam_data_0.k1,
128
+ "Cam0_Kappa 2": self.cam_data_0.k2,
129
+ "Cam0_Kappa 3": self.cam_data_0.k3,
130
+ "Cam0_P1": self.cam_data_0.p1,
131
+ "Cam0_P2": self.cam_data_0.p2,
132
+ "Cam0_Cx [pixels]": float(self.cam_data_0.c0),
133
+ "Cam0_Cy [pixels]": float(self.cam_data_0.c1),
134
+ "Cam1_Fx [pixels]": float(self.cam_data_1.focal_length /
135
+ self.cam_data_1.pixels_size[0]),
136
+ "Cam1_Fy [pixels]": float(self.cam_data_1.focal_length /
137
+ self.cam_data_1.pixels_size[1]),
138
+ "Cam1_Fs [pixels]": 0,
139
+ "Cam1_Kappa 1": self.cam_data_1.k1,
140
+ "Cam1_Kappa 2": self.cam_data_1.k2,
141
+ "Cam1_Kappa 3": self.cam_data_1.k3,
142
+ "Cam1_P1": self.cam_data_1.p1,
143
+ "Cam1_P2": self.cam_data_1.p2,
144
+ "Cam1_Cx [pixels]": float(self.cam_data_1.c0),
145
+ "Cam1_Cy [pixels]": float(self.cam_data_1.c1),
146
+ "Tx [mm]": float(self.stereo_dist[0]),
147
+ "Ty [mm]": float(self.stereo_dist[1]),
148
+ "Tz [mm]": float(self.stereo_dist[2]),
149
+ "Theta [deg]": float(stereo_rotation[0]),
150
+ "Phi [deg]": float(stereo_rotation[1]),
151
+ "Psi [deg]": float(stereo_rotation[2])
152
+ }
153
+ if not base_dir.is_dir():
154
+ raise BlenderError("The specified save directory does not exist")
155
+
156
+ save_dir = base_dir / "calibration"
157
+ if not save_dir.is_dir():
158
+ save_dir.mkdir(parents=True, exist_ok=True)
159
+
160
+ filepath = str(save_dir / "calibration.yaml")
161
+ calib_file = open(filepath, "w")
162
+ yaml.safe_dump(calib_params, calib_file)
163
+ calib_file.close()
164
+ print("Calibration file saved to:", (save_dir / "calibration.yaml"))
165
+
166
+ def save_calibration_mid(self, base_dir: Path) -> None:
167
+ """A method to save a calibration file of the stereo system in a MatchID
168
+ accepted format.
169
+
170
+ Parameters
171
+ ----------
172
+ base_dir : Path
173
+ The base directory to which all files should be saved. The
174
+ calibration file will be saved in a sub-directory named "calibration"
175
+ within this directory.
176
+
177
+ Raises
178
+ ------
179
+ BlenderError
180
+ "The specified save directory does not exist"
181
+ """
182
+ if not base_dir.is_dir():
183
+ raise BlenderError("The specified save directory does not exist")
184
+
185
+ save_dir = base_dir / "calibration"
186
+ if not save_dir.is_dir():
187
+ save_dir.mkdir(parents=True, exist_ok=True)
188
+
189
+ filepath = str(save_dir / "calibration.caldat")
190
+ with open(filepath, "w") as file:
191
+ file.write(f'Cam0_Fx [pixels]; {self.cam_data_0.focal_length/ self.cam_data_0.pixels_size[0]}\n')
192
+ file.write(f'Cam0_Fy [pixels]; {self.cam_data_0.focal_length/ self.cam_data_0.pixels_size[1]}\n')
193
+ file.write("Cam0_Fs [pixels];0\n")
194
+ file.write(f'Cam0_Kappa 1;{self.cam_data_0.k1}\n')
195
+ file.write(f'Cam0_Kappa 2;{self.cam_data_0.k2}\n')
196
+ file.write(f'Cam0_Kappa 3;{self.cam_data_0.k3}\n')
197
+ file.write(f'Cam0_P1;{self.cam_data_0.p1}\n')
198
+ file.write(f'Cam0_P2;{self.cam_data_0.p2}\n')
199
+ file.write(f'Cam0_Cx [pixels];{self.cam_data_0.c0}\n')
200
+ file.write(f'Cam0_Cy [pixels];{self.cam_data_0.c1}\n')
201
+ file.write(f'Cam1_Fx [pixels]; {self.cam_data_1.focal_length/ self.cam_data_1.pixels_size[0]}\n')
202
+ file.write(f'Cam1_Fy [pixels]; {self.cam_data_1.focal_length/ self.cam_data_1.pixels_size[1]}\n')
203
+ file.write("Cam1_Fs [pixels];0\n")
204
+ file.write(f'Cam1_Kappa 1;{self.cam_data_1.k1}\n')
205
+ file.write(f'Cam1_Kappa 2;{self.cam_data_1.k2}\n')
206
+ file.write(f'Cam1_Kappa 3;{self.cam_data_1.k3}\n')
207
+ file.write(f'Cam1_P1;{self.cam_data_1.p1}\n')
208
+ file.write(f'Cam1_P2;{self.cam_data_1.p2}\n')
209
+ file.write(f'Cam1_Cx [pixels];{self.cam_data_1.c0}\n')
210
+ file.write(f'Cam1_Cy [pixels];{self.cam_data_1.c1}\n')
211
+ file.write(f"Tx [mm];{self.stereo_dist[0]}\n")
212
+ file.write(f"Ty [mm];{self.stereo_dist[1]}\n")
213
+ file.write(f"Tz [mm];{self.stereo_dist[2]}\n")
214
+ stereo_rotation = self.stereo_rotation.as_euler("xyz", degrees=True)
215
+ file.write(f"Theta [deg];{stereo_rotation[0]}\n")
216
+ file.write(f"Phi [deg];{stereo_rotation[1]}\n")
217
+ file.write(f"Psi [deg];{stereo_rotation[2]}")