pyvale 2025.5.3__cp311-cp311-win_amd64.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.
- pyvale/__init__.py +89 -0
- pyvale/analyticmeshgen.py +102 -0
- pyvale/analyticsimdatafactory.py +91 -0
- pyvale/analyticsimdatagenerator.py +323 -0
- pyvale/blendercalibrationdata.py +15 -0
- pyvale/blenderlightdata.py +26 -0
- pyvale/blendermaterialdata.py +15 -0
- pyvale/blenderrenderdata.py +30 -0
- pyvale/blenderscene.py +488 -0
- pyvale/blendertools.py +420 -0
- pyvale/camera.py +146 -0
- pyvale/cameradata.py +69 -0
- pyvale/cameradata2d.py +84 -0
- pyvale/camerastereo.py +217 -0
- pyvale/cameratools.py +522 -0
- pyvale/cython/rastercyth.c +32211 -0
- pyvale/cython/rastercyth.cp311-win_amd64.pyd +0 -0
- pyvale/cython/rastercyth.py +640 -0
- pyvale/data/__init__.py +5 -0
- pyvale/data/cal_target.tiff +0 -0
- pyvale/data/case00_HEX20_out.e +0 -0
- pyvale/data/case00_HEX27_out.e +0 -0
- pyvale/data/case00_HEX8_out.e +0 -0
- pyvale/data/case00_TET10_out.e +0 -0
- pyvale/data/case00_TET14_out.e +0 -0
- pyvale/data/case00_TET4_out.e +0 -0
- pyvale/data/case13_out.e +0 -0
- pyvale/data/case16_out.e +0 -0
- pyvale/data/case17_out.e +0 -0
- pyvale/data/case18_1_out.e +0 -0
- pyvale/data/case18_2_out.e +0 -0
- pyvale/data/case18_3_out.e +0 -0
- pyvale/data/case25_out.e +0 -0
- pyvale/data/case26_out.e +0 -0
- pyvale/data/optspeckle_2464x2056px_spec5px_8bit_gblur1px.tiff +0 -0
- pyvale/dataset.py +325 -0
- pyvale/errorcalculator.py +109 -0
- pyvale/errordriftcalc.py +146 -0
- pyvale/errorintegrator.py +336 -0
- pyvale/errorrand.py +607 -0
- pyvale/errorsyscalib.py +134 -0
- pyvale/errorsysdep.py +327 -0
- pyvale/errorsysfield.py +414 -0
- pyvale/errorsysindep.py +808 -0
- pyvale/examples/__init__.py +5 -0
- pyvale/examples/basics/ex1_1_basicscalars_therm2d.py +131 -0
- pyvale/examples/basics/ex1_2_sensormodel_therm2d.py +158 -0
- pyvale/examples/basics/ex1_3_customsens_therm3d.py +216 -0
- pyvale/examples/basics/ex1_4_basicerrors_therm3d.py +153 -0
- pyvale/examples/basics/ex1_5_fielderrs_therm3d.py +168 -0
- pyvale/examples/basics/ex1_6_caliberrs_therm2d.py +133 -0
- pyvale/examples/basics/ex1_7_spatavg_therm2d.py +123 -0
- pyvale/examples/basics/ex2_1_basicvectors_disp2d.py +112 -0
- pyvale/examples/basics/ex2_2_vectorsens_disp2d.py +111 -0
- pyvale/examples/basics/ex2_3_sensangle_disp2d.py +139 -0
- pyvale/examples/basics/ex2_4_chainfielderrs_disp2d.py +196 -0
- pyvale/examples/basics/ex2_5_vectorfields3d_disp3d.py +109 -0
- pyvale/examples/basics/ex3_1_basictensors_strain2d.py +114 -0
- pyvale/examples/basics/ex3_2_tensorsens2d_strain2d.py +111 -0
- pyvale/examples/basics/ex3_3_tensorsens3d_strain3d.py +182 -0
- pyvale/examples/basics/ex4_1_expsim2d_thermmech2d.py +171 -0
- pyvale/examples/basics/ex4_2_expsim3d_thermmech3d.py +252 -0
- pyvale/examples/genanalyticdata/ex1_1_scalarvisualisation.py +35 -0
- pyvale/examples/genanalyticdata/ex1_2_scalarcasebuild.py +43 -0
- pyvale/examples/genanalyticdata/ex2_1_analyticsensors.py +80 -0
- pyvale/examples/imagedef2d/ex_imagedef2d_todisk.py +79 -0
- pyvale/examples/renderblender/ex1_1_blenderscene.py +121 -0
- pyvale/examples/renderblender/ex1_2_blenderdeformed.py +119 -0
- pyvale/examples/renderblender/ex2_1_stereoscene.py +128 -0
- pyvale/examples/renderblender/ex2_2_stereodeformed.py +131 -0
- pyvale/examples/renderblender/ex3_1_blendercalibration.py +120 -0
- pyvale/examples/renderrasterisation/ex_rastenp.py +153 -0
- pyvale/examples/renderrasterisation/ex_rastercyth_oneframe.py +218 -0
- pyvale/examples/renderrasterisation/ex_rastercyth_static_cypara.py +187 -0
- pyvale/examples/renderrasterisation/ex_rastercyth_static_pypara.py +190 -0
- pyvale/examples/visualisation/ex1_1_plot_traces.py +102 -0
- pyvale/examples/visualisation/ex2_1_animate_sim.py +89 -0
- pyvale/experimentsimulator.py +175 -0
- pyvale/field.py +128 -0
- pyvale/fieldconverter.py +351 -0
- pyvale/fieldsampler.py +111 -0
- pyvale/fieldscalar.py +166 -0
- pyvale/fieldtensor.py +218 -0
- pyvale/fieldtransform.py +388 -0
- pyvale/fieldvector.py +213 -0
- pyvale/generatorsrandom.py +505 -0
- pyvale/imagedef2d.py +569 -0
- pyvale/integratorfactory.py +240 -0
- pyvale/integratorquadrature.py +217 -0
- pyvale/integratorrectangle.py +165 -0
- pyvale/integratorspatial.py +89 -0
- pyvale/integratortype.py +43 -0
- pyvale/output.py +17 -0
- pyvale/pyvaleexceptions.py +11 -0
- pyvale/raster.py +31 -0
- pyvale/rastercy.py +77 -0
- pyvale/rasternp.py +603 -0
- pyvale/rendermesh.py +147 -0
- pyvale/sensorarray.py +178 -0
- pyvale/sensorarrayfactory.py +196 -0
- pyvale/sensorarraypoint.py +278 -0
- pyvale/sensordata.py +71 -0
- pyvale/sensordescriptor.py +213 -0
- pyvale/sensortools.py +142 -0
- pyvale/simcases/case00_HEX20.i +242 -0
- pyvale/simcases/case00_HEX27.i +242 -0
- pyvale/simcases/case00_HEX8.i +242 -0
- pyvale/simcases/case00_TET10.i +242 -0
- pyvale/simcases/case00_TET14.i +242 -0
- pyvale/simcases/case00_TET4.i +242 -0
- pyvale/simcases/case01.i +101 -0
- pyvale/simcases/case02.i +156 -0
- pyvale/simcases/case03.i +136 -0
- pyvale/simcases/case04.i +181 -0
- pyvale/simcases/case05.i +234 -0
- pyvale/simcases/case06.i +305 -0
- pyvale/simcases/case07.geo +135 -0
- pyvale/simcases/case07.i +87 -0
- pyvale/simcases/case08.geo +144 -0
- pyvale/simcases/case08.i +153 -0
- pyvale/simcases/case09.geo +204 -0
- pyvale/simcases/case09.i +87 -0
- pyvale/simcases/case10.geo +204 -0
- pyvale/simcases/case10.i +257 -0
- pyvale/simcases/case11.geo +337 -0
- pyvale/simcases/case11.i +147 -0
- pyvale/simcases/case12.geo +388 -0
- pyvale/simcases/case12.i +329 -0
- pyvale/simcases/case13.i +140 -0
- pyvale/simcases/case14.i +159 -0
- pyvale/simcases/case15.geo +337 -0
- pyvale/simcases/case15.i +150 -0
- pyvale/simcases/case16.geo +391 -0
- pyvale/simcases/case16.i +357 -0
- pyvale/simcases/case17.geo +135 -0
- pyvale/simcases/case17.i +144 -0
- pyvale/simcases/case18.i +254 -0
- pyvale/simcases/case18_1.i +254 -0
- pyvale/simcases/case18_2.i +254 -0
- pyvale/simcases/case18_3.i +254 -0
- pyvale/simcases/case19.geo +252 -0
- pyvale/simcases/case19.i +99 -0
- pyvale/simcases/case20.geo +252 -0
- pyvale/simcases/case20.i +250 -0
- pyvale/simcases/case21.geo +74 -0
- pyvale/simcases/case21.i +155 -0
- pyvale/simcases/case22.geo +82 -0
- pyvale/simcases/case22.i +140 -0
- pyvale/simcases/case23.geo +164 -0
- pyvale/simcases/case23.i +140 -0
- pyvale/simcases/case24.geo +79 -0
- pyvale/simcases/case24.i +123 -0
- pyvale/simcases/case25.geo +82 -0
- pyvale/simcases/case25.i +140 -0
- pyvale/simcases/case26.geo +166 -0
- pyvale/simcases/case26.i +140 -0
- pyvale/simcases/run_1case.py +61 -0
- pyvale/simcases/run_all_cases.py +69 -0
- pyvale/simcases/run_build_case.py +64 -0
- pyvale/simcases/run_example_cases.py +69 -0
- pyvale/simtools.py +67 -0
- pyvale/visualexpplotter.py +191 -0
- pyvale/visualimagedef.py +74 -0
- pyvale/visualimages.py +76 -0
- pyvale/visualopts.py +493 -0
- pyvale/visualsimanimator.py +111 -0
- pyvale/visualsimsensors.py +318 -0
- pyvale/visualtools.py +136 -0
- pyvale/visualtraceplotter.py +142 -0
- pyvale-2025.5.3.dist-info/METADATA +144 -0
- pyvale-2025.5.3.dist-info/RECORD +174 -0
- pyvale-2025.5.3.dist-info/WHEEL +5 -0
- pyvale-2025.5.3.dist-info/licenses/LICENSE +21 -0
- 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]}")
|