| name | camera-intrinsic-calibration |
| description | 相机内参标定技能 - Kalibr、ROS2 标定工具、单目/双目标定 |
| argument-hint | 相机标定 OR intrinsic OR Kalibr OR 单目标定 OR 双目标定 |
| user-invocable | true |
相机内参标定技能
相机内参标定理论与 ROS2 实现
何时使用
当需要以下帮助时使用此技能:
- 单目相机标定
- 双目相机标定
- 畸变校正
- Kalibr 工具使用
- ROS2 标定
核心实现
ROS2 相机标定
sudo apt install ros-humble-camera-calibration
ros2 run camera_calibration cameracalibrator --size 9x6 --square 0.025 \
--ros-args -p image:=/camera/image_raw \
-p camera:=/camera
ros2 run camera_calibration stereocalibrator --size 9x6 --square 0.025 \
--ros-args -p left:=/stereo/left/image_raw \
-p right:=/stereo/right/image_raw
Kalibr 标定
cat > target.yaml << EOF
target_type: 'checkerboard'
targetCols: 6
targetRows: 4
targetSpacing: 0.03
EOF
ros2 bag record /camera/image_raw /camera/camera_info -o calibration.bag
kalibr_calibrate_cameras --target target.yaml \
--bag calibration.bag \
--topic /camera/image_raw \
--output-path kalibr_results/
Python 标定实现
import numpy as np
import cv2
import glob
class CameraCalibrator:
def __init__(self, board_size=(9, 6), square_size=0.025):
self.board_size = board_size
self.square_size = square_size
self.objp = self.create_object_points()
def create_object_points(self):
"""创建标定板三维坐标点"""
objp = np.zeros((self.board_size[0] * self.board_size[1], 3), np.float32)
objp[:, :2] = np.mgrid[0:self.board_size[0], 0:self.board_size[1]].T.reshape(-1, 2)
objp *= self.square_size
return objp
def calibrate(self, image_paths):
"""标定相机"""
objpoints = []
imgpoints = []
for fname in image_paths:
img = cv2.imread(fname)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, corners = cv2.findChessboardCorners(gray, .board_size, )
ret:
objpoints.append(.objp)
corners2 = cv2.cornerSubPix(gray, corners, (, ), (-, -),
criteria=(cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, , ))
imgpoints.append(corners2)
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(
objpoints, imgpoints, gray.shape[::-], , )
{
: mtx,
: dist,
: rvecs,
: tvecs,
: ret
}
():
h, w = image.shape[:]
newK, roi = cv2.getOptimalNewCameraMatrix(K, dist, (w, h), , (w, h))
dst = cv2.undistort(image, K, dist, , newK)
x, y, w, h = roi
dst = dst[y:y+h, x:x+w]
dst
双目标定
class StereoCalibrator:
def __init__(self, board_size=(9, 6), square_size=0.025):
self.board_size = board_size
self.square_size = square_size
self.objp = self.create_object_points()
def calibrate_stereo(self, left_images, right_images):
"""双目标定"""
retL, mtxL, distL, _, _ = self.calibrate_single(left_images)
retR, mtxR, distR, _, _ = self.calibrate_single(right_images)
objpoints = []
imgpointsL = []
imgpointsR = []
for lImg, rImg in zip(left_images, right_images):
grayL = cv2.cvtColor(lImg, cv2.COLOR_BGR2GRAY)
grayR = cv2.cvtColor(rImg, cv2.COLOR_BGR2GRAY)
retL, cornersL = cv2.findChessboardCorners(grayL, self.board_size, None)
retR, cornersR = cv2.findChessboardCorners(grayR, self.board_size, None)
if retL and retR:
objpoints.append(self.objp)
cornersL2 = cv2.cornerSubPix(grayL, cornersL, (11, 11), (-1, -1),
criteria=(cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001))
cornersR2 = cv2.cornerSubPix(grayR, cornersR, (11, ), (-, -),
criteria=(cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, , ))
imgpointsL.append(cornersL2)
imgpointsR.append(cornersR2)
ret, mtxL, distL, mtxR, distR, R, T, E, F = cv2.stereoCalibrate(
objpoints, imgpointsL, imgpointsR,
mtxL, distL, mtxR, distR, grayL.shape[::-])
baseline = np.linalg.norm(T)
fx = mtxL[, ]
{
: mtxL, : mtxR,
: distL, : distR,
: R, : T,
: E, : F,
: baseline,
: ret
}