Неделя 10 - Калибровка камеры и 3D реконструкция
1. Калибровка камеры
1.1. Теория искажений
Камеры вносят два основных типа искажений:
Радиальные искажения (выпуклость/вогнутость)
Тангенциальные искажения (смещение линзы)
1.2. Подготовка калибровочных изображений
Необходимы снимки шахматной доски (не менее 10-15 под разными углами):
python
Copy
import cv2
import numpy as np
import glob
# Настройки шахматной доски (внутренние углы)
chessboard_size = (9,6) # Для доски 9x6 внутренних углов
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
# Подготовка 3D точек
objp = np.zeros((chessboard_size[0]*chessboard_size[1], 3), np.float32)
objp[:,:2] = np.mgrid[0:chessboard_size[0], 0:chessboard_size[1]].T.reshape(-1,2)
# Массивы для хранения точек
objpoints = [] # 3D точки в реальном мире
imgpoints = [] # 2D точки на изображении
images = glob.glob('calibration_images/*.jpg')
for fname in images:
img = cv2.imread(fname)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Поиск углов шахматной доски
ret, corners = cv2.findChessboardCorners(gray, chessboard_size, None)
if ret:
objpoints.append(objp)
# Уточнение позиции углов
corners2 = cv2.cornerSubPix(gray, corners, (11,11), (-1,-1), criteria)
imgpoints.append(corners2)
# Визуализация
cv2.drawChessboardCorners(img, chessboard_size, corners2, ret)
cv2.imshow('Chessboard', img)
cv2.waitKey(500)
1.3. Расчет параметров камеры
python
Copy
# Калибровка камеры
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(
objpoints, imgpoints, gray.shape[::-1], None, None)
# Сохранение параметров
np.savez('calibration.npz', mtx=mtx, dist=dist, rvecs=rvecs, tvecs=tvecs)
print("Матрица камеры:\n", mtx)
print("\nКоэффициенты искажений:\n", dist)
1.4. Устранение искажений
python
Copy
# Загрузка параметров
with np.load('calibration.npz') as data:
mtx, dist = data['mtx'], data['dist']
# Пример коррекции искажений
img = cv2.imread('test_image.jpg')
h, w = img.shape[:2]
# Оптимальная новая матрица камеры
new_mtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (w,h), 1, (w,h))
# Коррекция искажений
undistorted = cv2.undistort(img, mtx, dist, None, new_mtx)
# Обрезка изображения
x,y,w,h = roi
undistorted = undistorted[y:y+h, x:x+w]
2. Стереозрение и 3D реконструкция
2.1. Стереокалибровка
python
Copy
# Для двух камер (левый и правый снимки)
stereo_criteria = (cv2.TERM_CRITERIA_MAX_ITER + cv2.TERM_CRITERIA_EPS, 100, 1e-5)
stereo_flags = cv2.CALIB_FIX_INTRINSIC
ret, _, _, _, _, R, T, E, F = cv2.stereoCalibrate(
objpoints_left, imgpoints_left,
objpoints_right, imgpoints_right,
mtx_left, dist_left,
mtx_right, dist_right,
image_size,
criteria=stereo_criteria,
flags=stereo_flags)
2.2. Стереоректификация
python
Copy
# Вычисление ректификации
R1, R2, P1, P2, Q, _, _ = cv2.stereoRectify(
mtx_left, dist_left,
mtx_right, dist_right,
image_size, R, T)
# Создание карт ректификации
map1_left, map2_left = cv2.initUndistortRectifyMap(
mtx_left, dist_left, R1, P1, image_size, cv2.CV_16SC2)
map1_right, map2_right = cv2.initUndistortRectifyMap(
mtx_right, dist_right, R2, P2, image_size, cv2.CV_16SC2)
# Ректификация изображений
img_left_rect = cv2.remap(img_left, map1_left, map2_left, cv2.INTER_LINEAR)
img_right_rect = cv2.remap(img_right, map1_right, map2_right, cv2.INTER_LINEAR)
2.3. Карта глубины (Disparity Map)
python
Copy
# Настройки для StereoSGBM
window_size = 3
min_disp = 0
num_disp = 16*5
stereo = cv2.StereoSGBM_create(
minDisparity=min_disp,
numDisparities=num_disp,
blockSize=window_size,
P1=8*3*window_size**2,
P2=32*3*window_size**2,
disp12MaxDiff=1,
uniquenessRatio=10,
speckleWindowSize=100,
speckleRange=32
)
# Вычисление disparity
disparity = stereo.compute(img_left_rect, img_right_rect).astype(np.float32) / 16.0
# Визуализация
disparity_vis = (disparity - min_disp)/num_disp
cv2.imshow('Disparity', disparity_vis)
2.4. Восстановление 3D координат
python
Copy
# Создание 3D точек
points_3d = cv2.reprojectImageTo3D(disparity, Q)
# Фильтрация точек
mask = disparity > disparity.min()
out_points = points_3d[mask]
out_colors = img_left_rect[mask]
# Сохранение в PLY формат (для просмотра в MeshLab)
def write_ply(filename, points, colors):
with open(filename, 'w') as f:
f.write("ply\n")
f.write("format ascii 1.0\n")
f.write(f"element vertex {len(points)}\n")
f.write("property float x\n")
f.write("property float y\n")
f.write("property float z\n")
f.write("property uchar red\n")
f.write("property uchar green\n")
f.write("property uchar blue\n")
f.write("end_header\n")
for (x,y,z), (b,g,r) in zip(points, colors):
f.write(f"{x} {y} {z} {r} {g} {b}\n")
write_ply('reconstruction.ply', out_points, out_colors)
3. Практическое задание
1. Снимите 15+ калибровочных изображений шахматной доски
2. Проведите калибровку камеры и сохраните параметры
3. Примените коррекцию искажений к тестовому изображению
4. (Дополнительно) Используя два изображения одной сцены:
o Проведите стереокалибровку
o Постройте карту глубины
o Восстановите 3D облако точек
4. Итоги
Калибровка камеры позволяет получить точные измерения
Стереозрение дает возможность восстанавливать 3D структуру
Карта глубины - основа для многих AR-приложений
OpenCV предоставляет полный набор инструментов для 3D реконструкции
Следующая тема: Детекция и распознавание объектов с использованием машинного обучения