klampt.model.calibrate module
Functions for extrinsic calibration of cameras.
New in version 0.9.
- class klampt.model.calibrate.PointMarker(link=None, local_coordinates=None)[source]
Bases:
object
A physical point marker that can be detected in an image.
- link
link on which this is located. None means attached to the world frame.
- Type:
int or str, optional
- size
used only for visual debugging, default 0.01 (1cm)
- Type:
float
- local_coordinates
position relative to link
- Type:
3-vector, optional
- variable
whether this should be optimized
- Type:
bool
- class klampt.model.calibrate.TransformMarker(link=None, local_coordinates=None, local_features=None)[source]
Bases:
object
A physical marker with some orientation, and either the transform or points of features on the marker can be detected in an image.
- link
link on which this is located. None means attached to the world frame.
- Type:
int or str, optional
- size
used only for visual debugging, default 0.01 (1cm)
- Type:
float
- local_coordinates
pose relative to link
- Type:
se3 element, optional
- local_features
feature points relative to marker
- Type:
list of 3-vectors
- variable
whether this should be optimized
- Type:
bool
- class klampt.model.calibrate.CameraInfo(link, intrinsics=None, local_coordinates=None)[source]
Bases:
object
Stores info for a camera in a calibration.
- link
link on which this is located. None means attached to the world frame.
- Type:
int or str, optional
- intrinsics
dict with keys ‘fx’, ‘fy’, ‘cx’, ‘cy’ giving the camera intrinsics.
- Type:
dict
- local_coordinates
pose relative to link
- Type:
se3 element, optional
- variable
whether this should be optimized
- Type:
bool
- class klampt.model.calibrate.PointObservation(value, camera_id, frame_id, marker_id, feature_id=None)[source]
Bases:
object
A 3D point measurement in the frame of a camera.
X is to the right, Y is down, Z is forward. Units are in m.
- class klampt.model.calibrate.TransformObservation(value, camera_id, frame_id, marker_id)[source]
Bases:
object
A 3D SE(3) transform measurement in the frame of a camera.
X is to the right, Y is down, Z is forward. Translation units are in m.
- class klampt.model.calibrate.PixelObservation(value, camera_id, frame_id, marker_id, feature_id=None)[source]
Bases:
object
A 2D pixel measurement in the frame of a camera.
X is to the right, Y is down. Units are in pixels.
- class klampt.model.calibrate.RobotExtrinsicCalibration[source]
Bases:
object
Stores a calibration dataset and helps perform extrinsic (hand-eye) calibration.
Usage for a world-attached camera, Aruco marker on end effector:
calib = RobotExtrinsicCalibration() calib.robot = #set the robot model here calib.cameras[0] = CameraInfo(link=None,intrinsics=intrinsics) ee_link = # set the ee link index or name here calib.markers[tag_id] = TransformMarker(ee_link) calib.visualize() #this will show a visualization of the markers and camera calib.editTrajectory() #this will pop up an editing window controller = MyRobotInterface() #setup the robot controller here controller.initialize() def take_camera_picture(): #TODO: take the picture from the camera here return image #TODO: setup aruco_detector... see Aruco documentation for more details camparam = aruco.CameraParameters() camparam.readFromXMLFile('cam_params.yml') detector = aruco.MarkerDetector() detector.setDictionary("my_markers.dict") def detect_aruco_marker(image): #return all detected markers markers = aruco_detector.detect(image) results = [] for marker in markers: marker.calculateExtrinsics(0.15, camparam) mtx = marker.getTransformMatrix() Tmarker = se3.from_homogeneous(mtx) #convert to klampt.se3 results.append((marker.id,Tmarker)) return results #if you just want to run detection on the pictures offline, use #take_camera_picture = None and detect_aruco_marker = None calib.executeTrajectory(controller,take_camera_picture,detect_aruco_marker) calib.editCalibration() #visual editing of initial guesses calib.calibrate() #optimize the calibration calib.save('my_calibration.json')
To use reprojection error instead:
intrinsics = {'fx':fx,'fy':fy,'cx':cx,'cy':cy} #intrinsics are needed if you are using pixels
If you want to load a set of configurations and marker transforms from disk manually:
... do calib robot and marker setup ... configs = klampt.io.loader.load('calibration.configs') transforms = [] with open('marker_transforms.txt','r') as f: for line in f.readlines(): if len(line.strip()) > 0: T = klampt.io.loader.read(line,'RigidTransform') transforms.append(T) for i,(q,T) in enumerate(zip(configs,transforms)): calib.frames.append(None) calib.configurations.append(q) calib.addDetection(T,frame_id=i,marker_id=0) calib.editCalibration() #visual editing of initial guesses calib.calibration() #optimize the calibration calib.save('my_calibration.json')
To visualize the calibration:
... do calib robot and marker setup ... calib.load('my_calibration.json') calib.visualize()
To fix the marker transform during optimization, e.g. at local coordinates [x,y,z]:
calib.markers[0].local_coordinates = (so3.identity(),[x,y,z]) calib.markers[0].variable = False calib.calibrate()
A similar flag can be used for fixing the camera.
- cameraFromRobot(sensors=None)[source]
Sets up the camera(s) from the robot model.
- Return type:
None
- Parameters:
sensors (str, int, list of str, or list of int, optional) – specifies one or more sensors to use. If None, just uses the first camera. If ‘all’, uses all cameras.
- editTrajectory(world=None, name='calibration_trajectory')[source]
Returns a RobotTrajectory that passes through all calibration configurations.
Note: the executed trajectory stops at all milestones.
- Return type:
- executeTrajectory(controller, traj, camera_fn, detect_fn=None, speed=1.0, wait=0.0)[source]
Executes a trajectory on a controller, optionally taking images along the way.
TODO: specify times to actually stop.
- Return type:
None
- visualize(world=None, edit=False)[source]
Pops up a visualization window showing the calibration setup.
- Return type:
None
- addFrame(frame, q=None, camera_id=None, detect_fn=None)[source]
Add a frame and configuration, automatically using forward kinematics to determine camera / marker transforms. This is the easiest way to add frames and detections.
- Return type:
None
- Parameters:
frame (Image) – the image for the frame.
q (configuration, optional) – the robot’s configuration. If not given, the observations’ hand_eye_transform must be filled in manually.
camera_id (int or str, optional) – the camera ID, 0 by default.
detect_fn (callable, optional) – if given, a function detect(frame) which returns a list of detected observations. Each observation can be a PixelObservation, PointObservation, TransformObservation, or a (marker,value) pair. To indicate a detected feature on a marker, a ((marker,feature),value) pair is returned.
- addDetection(value, frame_id, marker_id, feature_id=None, camera_id=None, error=None)[source]
Manually adds a detection for a given camera / frame / marker / feature. Automatically determines a hand_eye_transform for the observation if a robot and configuration are already provided for this frame.
- Return type:
Union
[PixelObservation
,PointObservation
,TransformObservation
]- Parameters:
value (2-list, 3-list, or SE3 element) – the pixel, point, or transform of the detection, given in camera coordinates.
frame_id (int) – the index of the frame
marker_id (int or str) – the index of the marker
feature_id (int, optional) – the index of the feature on the marker.
camera_id (int or str, optional) – the camera that observed this feature (default 0)
error (float or list, optional) – the standard deviation of the observation error. If a float is given, noise is assumed to be isotropic.
- Returns:
The configured detection object.
- cameraTransforms(world=False)[source]
Returns a dict of camera transforms, in either world or link- local coordinates. World coordinates use the robot’s current configuration.
- Return type:
Dict
[Union
[int
,str
],Tuple
[Sequence
[float
],Sequence
[float
]]]
- markerTransforms(world=False)[source]
Returns a dict of marker transforms, in either world or link- local coordinates. World coordinates use the robot’s current configuration.
- Return type:
Dict
[int
,Tuple
[Sequence
[float
],Sequence
[float
]]]
- setCameraTransform(camera, T, world=False)[source]
Sets the camera transform for the specified camera. World coordinates use the robot’s current configuration.
- setMarkerTransform(marker, T, world=False)[source]
Sets the transform / coordinates for the specified marker. World coordinates use the robot’s current configuration.
- predictedObservations(camera_transforms=None, marker_transforms=None, noise=False)[source]
Returns a list of predicted observations for a given set of camera and marker transforms.
- Return type:
List
[Union
[PointObservation
,PixelObservation
,TransformObservation
]]- Parameters:
camera_transforms (dict key->se3 elements, optional) – keys matching self.cameras. If None, then it is assumed that all cameras have transforms (local_coordinates) specified.
marker_transforms (dict key->se3 elements, optional) – keys matching self.markers. If None, then it is assumed that all markers have transforms (local_coordinates) specified.
noise (bool or float) – if not False, then noise is injected into the prediction. This is useful for generating synthetic data and understanding the observation error model.
- Returns:
A list of configured observation objects, corresponding to the values in self.observations.
- predictedResiduals(camera_transforms=None, marker_transforms=None)[source]
Returns a list of predicted residuals for a given set of camera and marker transforms.
- Return type:
List
[Sequence
[float
]]- Parameters:
camera_transforms (list of se3 elements, optional) – length len(self.cameras). If None, then it is assumed that all cameras have transforms (local_coordinates) specified.
marker_transforms (list of se3 elements, optional) – length len(self.markers). If None, then it is assumed that all markers have transforms (local_coordinates) specified.
- Returns:
A list of residuals (prediction - observed value) corresponding to the values in self.observations.
- predictedLogLikelihoods(camera_transforms=None, marker_transforms=None)[source]
Returns a list of predicted observation log-likelihoods for a given set of camera and marker transforms.
- Return type:
List
[float
]- Parameters:
camera_transforms (list of se3 elements, optional) – length len(self.cameras). If None, then it is assumed that all cameras have transforms (local_coordinates) specified.
marker_transforms (list of se3 elements, optional) – length len(self.markers). If None, then it is assumed that all markers have transforms (local_coordinates) specified.
- Returns:
A list of log likelihoods of residuals corresponding to the values in self.observations.
- optimize(maxIters=100, tol=1e-07, regularizationFactor=0.0, store=True)[source]
Optimizes the calibrated transforms.
Requires scipy.
- Return type:
Tuple
[float
,Dict
[Union
[int
,str
],Tuple
[Sequence
[float
],Sequence
[float
]]],Dict
[Union
[int
,str
],Tuple
[Sequence
[float
],Sequence
[float
]]]]- Returns:
A tuple of the RMSE, camera transform dictionary, and marker transform dictionary.
- updateRobotSensors()[source]
Uses the current camera transforms to update the robot model’s sensors.
- Return type:
None