CVBpy 15.0
foundation/MetricCalibrationInclinationLaserPlane
1"""
2CVBpy Example Script for AQS12 Calibration - Use Case 2.
3
4This example shows how to calibrate range maps acquired by a compact 3D
5sensor where the intrinsic calibration parameters are given, but the
6laser plane is not exactly vertical to the direction of movement.
7
8See also use case 2 described in the CVB Metric documentation:
9https://help.commonvisionblox.com/NextGen/15.0/md_theory_of_operation_tools__metric.html#calibration_setup
10
11This example program estimates an affine transformation.
12The affine transformation:
13- corrects errors induced by an incline laser plane
14- corrects scaling in x, y, z
15- moves the point cloud to the coordinate system given by the reference
16points of the AQS12
17"""
18
19import os
20
21import cvb
22import cvb.foundation
23
24
25def print_trafo(trafo: cvb.AffineMatrix3D) -> None:
26 print("Estimated transformation:")
27 print("Translation:")
28 print(f"[{trafo.translation.x}, {trafo.translation.y}, "
29 f"{trafo.translation.z}]")
30 print("Transformation matrix:")
31 print(f"[[{trafo.matrix.at(0, 0)}, "
32 f"{trafo.matrix.at(0, 1)}, "
33 f"{trafo.matrix.at(0, 2)}],")
34 print(f"[{trafo.matrix.at(1, 0)}, "
35 f"{trafo.matrix.at(1, 1)}, "
36 f"{trafo.matrix.at(1, 2)}],")
37 print(f"[{trafo.matrix.at(2, 0)}, "
38 f"{trafo.matrix.at(2, 1)}, "
39 f"{trafo.matrix.at(2, 2)}]]")
40
41
42def print_trafo_parameters(atp: cvb.AffineTransformationParameters) -> None:
43 print("Rotation angles about X, Y, Z axis in degrees:")
44 print(f"{atp.rotation_angles.x}, {atp.rotation_angles.y}, "
45 f"{atp.rotation_angles.z}")
46 print("Shear Syx, Syz:")
47 print(f"{atp.s_yx}, {atp.s_yz}")
48 print("Inclination of laser plane about X, Z axis in degrees:")
49 print(f"{atp.inclination_x}, {atp.inclination_z}")
50 print("Scale in X, Y, Z:")
51 print(f"{atp.scale.x}, {atp.scale.y}, {atp.scale.z}")
52
53
54def print_point_3d_list(points: list[cvb.Point3D]) -> None:
55 data_list = list()
56 for p in points:
57 data_list.append(f"[{p.x}, {p.y}, {p.z}]")
58 delimiter = ",\n"
59 print(f"[{delimiter.join(data_list)}]")
60
61
62def print_residuals(points: list[cvb.Point3D]) -> None:
63 print("Residuals:")
64 print_point_3d_list(points)
65
66
67def print_aqs12_points(points: list[cvb.Point3D]) -> None:
68 print("AQS12 points:")
69 print_point_3d_list(points)
70
71
72def create_aqs12():
73 # list of known point coordinates of the AQS12
74 points = [
75 cvb.Point3D(20.0018, 44.9941, 15.0000),
76 cvb.Point3D(24.0018, 39.9942, 14.9994),
77 cvb.Point3D(23.9994, 24.9972, 15.0001),
78 cvb.Point3D(20.0021, 20.0035, 15.0011),
79 cvb.Point3D(15.9994, 25.0079, 15.0016),
80 cvb.Point3D(16.0000, 39.9919, 15.0010),
81 cvb.Point3D(20.0095, 59.9985, 4.9902),
82 cvb.Point3D(32.0093, 44.9958, 4.9909),
83 cvb.Point3D(32.0052, 19.9925, 4.9920),
84 cvb.Point3D(20.0021, 4.9961, 4.9939),
85 cvb.Point3D(8.0024, 19.9980, 5.0009),
86 cvb.Point3D(8.0065, 45.0009, 4.9984)]
87 return cvb.foundation.AQS12Piece(points, 0)
88
89
90def check_accuracy(residuals, desired_accuracy):
91 for point in residuals:
92 if (abs(point.x) > desired_accuracy or
93 abs(point.y) > desired_accuracy or
94 abs(point.z) > desired_accuracy):
95 return False
96 return True
97
98
99# If you like to save intermediate and final results, turn this flag on:
100save = False
101
102print("Estimation of an affine transformation (correcting an inclined laser "
103 "plane)")
104
105# load range map of the calibration target AQS12
106print("Loading range map and calibration file.")
107range_map_file = os.path.join(cvb.install_path(),
108 "tutorial", "Metric", "Images",
109 "RangeMapCalibrationPattern.tif")
110
111range_map = cvb.Image(range_map_file)
112
113print(f"Range map loaded with size of {range_map.width} x {range_map.height} "
114 f"from {range_map_file}.")
115
116# create calibration configuration object
117aqs12 = create_aqs12()
119config.is_homography_calculated = False
120
121# create (intrinsically) calibrated dense point cloud
122calibrator_file = os.path.join(cvb.install_path(),
123 "tutorial", "Metric", "Images",
124 "SICalibration.json")
125calibrator = cvb.Calibrator3D.load(calibrator_file)
126calibrator.range_map_ignore_value = 0
127cloud_intrinsic = cvb.PointCloudFactory.create_dense(
128 range_map.planes[0], calibrator,
129 cvb.PointCloudFlags.Float)
130
131print("Dense point cloud created from range map and calibration file "
132 f"with {cloud_intrinsic.num_points} points.")
133
134# create AQS12 object with known reference coordinates of corner points
135aqs12 = create_aqs12()
136
137# create segmentor (segmenting AQS12 faces on dense point cloud)
139 cvb.foundation.SegmentationMethod.KmeansClustering)
140
141# estimate calibration parameters
142print("Estimating affine transformation.")
143transformation_, residuals_, transformation_parameters_ = \
145 cloud_intrinsic, segmentor, config)
146
147calibrator.correction_of_laser_plane_inclination = \
148 transformation_, transformation_parameters_
149
150# show results
151if transformation_:
152 print_trafo(transformation_)
153
154if transformation_parameters_:
155 print_trafo_parameters(transformation_parameters_)
156
157# check residuals
158desired_accuracy_ = 0.05 # mm
159if residuals_:
160 print_residuals(residuals_)
161 if check_accuracy(residuals_, desired_accuracy_):
162 print("The calibration was successful and accuracy is < "
163 f"{desired_accuracy_} mm.")
164
165 # create calibrated cloud
166 print("Creating calibrated point cloud.")
167 calibrator_cloud = cvb.PointCloudFactory.create(
168 range_map.planes[0], calibrator,
169 cvb.PointCloudFlags.Float | cvb.PointCloudFlags.XYZConfidence)
170
171 # save calibrated point cloud
172 if save:
173 calibrator_cloud.save("cloud.ply")
174 else:
175 print(
176 "Results do not have desired accuracy. Check face segmentation and "
177 "extracted AQS12 points...")
178
179 # segment AQS12 faces map
180 print("Extracting AQ12 faces on intrinsically calibrated point cloud.")
181 faces_aqs12 = segmentor.face_segmentation_from_piece(cloud_intrinsic)
182
183 # save image with segmented faces:
184 if save:
185 faces_aqs12.save("AQS12faces.bmp")
186
187 # extract AQS12 points on range map (might take some time...)
188 print("Extracting AQ12 corner points on intrinsically calibrated "
189 "point cloud.")
190 points_aqs12 = segmentor.extract_projected_points_from_piece(
191 cloud_intrinsic)
192 print_aqs12_points(points_aqs12)
193
Union[cvb.Calibrator3DAT, cvb.LaserPlaneHomographyCalibrator3D, cvb.LaserPlaneZigZagCalibrator3D, cvb.FactorsCalibrator3D, cvb.MatrixCalibrator3D, cvb.PinholeCameraCalibrator3D] load(str file_name)
Loads a 3D calibration from file.
Definition: __init__.py:671
The Common Vision Blox image.
Definition: __init__.py:2097
Multi-purpose 3D vector class.
Definition: __init__.py:4322
Union[cvb.PointCloud, cvb.DensePointCloud, cvb.SparsePointCloud] create(cvb.ImagePlane range_map, cvb.Calibrator3D calibrator, int flags, Union[Type[cvb.PointCloud|cvb.DensePointCloud|cvb.SparsePointCloud]] point_cloud_type=DensePointCloud)
Creates a new Cartesian 3D point cloud from the given 2.5D range map image.
Definition: __init__.py:4701
cvb.DensePointCloud create_dense(cvb.ImagePlane range_map, cvb.Calibrator3D calibrator, int flags)
Creates a new dense Cartesian 3D point cloud from the given 2.5D range map image.
Definition: __init__.py:4732
cvb.foundation.AQS12DensePointCloudSegmentor create(int method)
Creates an AQS12 segmentor for dense point clouds based on given segmentation method.
Definition: __init__.py:18
Object to collect all input parameters for the AQS12 calibration piece.
Definition: __init__.py:76
cvb.foundation.CalibrationConfiguration create(cvb.foundation.AQS12Piece aqs12)
Creates a calibration configuration object.
Definition: __init__.py:272
Common Vision Blox Foundation module for Python.
Definition: __init__.py:1
Tuple[cvb.AffineMatrix3D, Optional[List[cvb.Point3D]], Optional[cvb.AffineTransformationParameters]] calculate_correction_of_laser_plane_inclination_from_aqs12_piece(cvb.DensePointCloud cloud, cvb.foundation.AQS12DensePointCloudSegmentor segmentor, cvb.foundation.CalibrationConfiguration config, Optional[cvb.Rect] aoi=None)
Calculates an extrinsic calibration and the correction for the laser plane inclination (affine transf...
Definition: __init__.py:2212
str install_path()
Directory Common Vision Blox has been installed to.
Definition: __init__.py:8318