이 카메라의 영문을 알 수 없는 점은, 케이블에 따라 컴퓨터에 연결이 되기도 하고 안 되기도 한다는 점입니다... 파워 케이블이 아니라 데이터 케이블임을 계속 확인했음에도 불구하고, 알 수 없는 이유로 케이블을 가립니다...
아무튼 연결이 되었다면 ls /dev 를 이용해서 이름 (video0, video1,.. 등) 을 확인한 후 캘리브레이션을 진행합니다.
Calibration
체커보드 사진을 촬영하고 사진들을 폴더에 저장합니다. 이후 사진을 읽어들여서 캘리브레이션을 수행할 수 있도록 다음 코드를 실행합니다.
이 코드는 폴더 내부의 사진을 읽어들여서 캘리브레이션을 진행하고, 추출한 코너 정보를 포함하는 사진을 새로 저장하고 결과값을 출력합니다.
import cv2
import numpy as np
import glob
import os
# Number of inner corners per a chessboard row and column
CHECKERBOARD = (6,9) # 이 부분을 사용하는 체커보드에 맞게 수정합니다.
# 3D point real world coordinates
objpoints = []
# 2D point image plane coordinates
imgpoints1, imgpoints2 = [], []
objp = np.zeros((1, CHECKERBOARD[0]*CHECKERBOARD[1], 3), np.float32)
objp[0,:,:2] = np.mgrid[0:CHECKERBOARD[0], 0:CHECKERBOARD[1]].T.reshape(-1, 2) * 20 # 이 부분을 실제 체커보드 사이즈에 맞게 (mm단위) 수정합니다.
images = glob.glob('/home/jiwon/socap_ws/src/python_stereo_camera_calibrate/frames_prev/*.png') # 경로를 수정합니다.
images.sort()
gray_l = None
gray_r = None
# Create directory to save images with drawn corners
os.makedirs("/home/jiwon/socap_ws/src/python_stereo_camera_calibrate/corners", exist_ok=True)
for i, img_path in enumerate(images):
img = cv2.imread(img_path)
h, w = img.shape[:2]
img_l = img[:, :w//2] # Left half
img_r = img[:, w//2:] # Right half
gray_l = cv2.cvtColor(img_l, cv2.COLOR_BGR2GRAY)
gray_r = cv2.cvtColor(img_r, cv2.COLOR_BGR2GRAY)
# 체스보드 코너 추출
ret_l, corners_l = cv2.findChessboardCorners(gray_l, CHECKERBOARD, cv2.CALIB_CB_ADAPTIVE_THRESH + cv2.CALIB_CB_FAST_CHECK + cv2.CALIB_CB_NORMALIZE_IMAGE)
ret_r, corners_r = cv2.findChessboardCorners(gray_r, CHECKERBOARD, cv2.CALIB_CB_ADAPTIVE_THRESH + cv2.CALIB_CB_FAST_CHECK + cv2.CALIB_CB_NORMALIZE_IMAGE)
if ret_l and ret_r:
objpoints.append(objp)
imgpoints1.append(corners_l)
imgpoints2.append(corners_r)
# Draw and display the corners
cv2.drawChessboardCorners(img_l, CHECKERBOARD, corners_l, ret_l)
cv2.drawChessboardCorners(img_r, CHECKERBOARD, corners_r, ret_r)
# Stitch images back together
img_combined = np.concatenate((img_l, img_r), axis=1)
# Save image with drawn corners
cv2.imwrite(f"/home/jiwon/socap_ws/src/python_stereo_camera_calibrate/corners/corners_{i}.png", img_combined)
if imgpoints1 and imgpoints2: # Calibration is only performed if there are points
# Perform camera calibration
ret, mtx1, dist1, _, _ = cv2.calibrateCamera(objpoints, imgpoints1, gray_l.shape[::-1], None, None)
ret, mtx2, dist2, _, _ = cv2.calibrateCamera(objpoints, imgpoints2, gray_r.shape[::-1], None, None)
# Stereo calibration
retval, _, _, _, _, R, T, E, F = cv2.stereoCalibrate(objpoints, imgpoints1, imgpoints2, mtx1, dist1, mtx2, dist2, gray_l.shape[::-1])
# Print intrinsic parameters
print("Intrinsic parameters for camera 1:\n", mtx1)
print("Distortion coefficients for camera 1:\n", dist1)
print("Intrinsic parameters for camera 2:\n", mtx2)
print("Distortion coefficients for camera 2:\n", dist2)
# Print extrinsic parameters
print("Rotation matrix:\n", R)
print("Translation vector:\n", T)
else:
print("No chessboard could be detected in one or more images.")
코너가 잘 추출된 것을 볼 수 있습니다.
결과
사용한 ELP 스테레오 카메라의 캘리브레이션 결과는 다음과 같습니다.
Intrinsic parameters for camera 1:
[[608.48750953 0. 346.97177753]
[ 0. 609.30750258 292.6478 ]
[ 0. 0. 1. ]]
Distortion coefficients for camera 1:
[[ 0.00588765 0.45781552 -0.01111286 -0.01784361 -0.74075112]]
Intrinsic parameters for camera 2:
[[618.1437757 0. 376.95327818]
[ 0. 622.6234544 290.76871985]
[ 0. 0. 1. ]]
Distortion coefficients for camera 2:
[[ 8.93213509e-02 3.01508457e-01 -3.72771266e-05 -7.69577151e-04
-9.83399362e-01]]
Rotation matrix:
[[ 9.99600363e-01 -7.57917527e-04 -2.82584318e-02]
[ 9.24993227e-05 9.99722857e-01 -2.35414733e-02]
[ 2.82684427e-02 2.35294514e-02 9.99323401e-01]]
Translation vector:
[[-59.83977288]
[ 1.11698986]
[ 11.2134471 ]]