ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 카메라 캘리브레이션(Camera Calibration)
    지식저장소 2023. 6. 27. 19:13
    728x90

    calibration

    1. 카메라 캘리브레이션이란?

    - 간단하게는 카메라의 파라미터(parameters)를 추정하는 과정을 카메라 캘리브레이션이라고 합니다.

     

    우리가 보는 실제세계는 3D와 Camera로 캡처한 이미지 2D(픽셀)간의 관계를 결정하는데 필요하는

    카메라에 대한 모든 정보(EX. 파라미터, 계수)를 말합니다.

     

    여기서 두가지 파라미터를 가집니다.

    1. 내부 파라미터(Internal parameters): 초점 거리(Focal Lenth), 광학 중심(optical center), 렌즈의 반사 왜곡 계수(Radial distortion coefficents of the lens)

    *Normalized plane은 원점으로 부터 거리가 1인 가상의 평면을 의미

     

    - 초점 거리(Focal Length): fx, fy

    - 주점(principal point): cx, cy

    - 비대칭계수(skew coefficient): skew_c = tan a

    위 그림 기준으로 설명을 진행하면

    카메라 좌표계에서 한점(Xc, Yc, Zc)를 변환할때  Xc, Yc룰 각각 Zc로 나눠주면 그것이 Normalized plane상에서의 좌표값입니다. 그 후 초점거리f를 곱하면 우리가 원하는 이미지 좌표를 구할 수 있습니다.

    하지만 여기서 픽셀좌표계의 중심은 좌상단에 위치함으로 실제 좌표계는 

    x = fx(X/Z)+cx,

    y = fy(Y/Z)+cy

     

    2. 외부 파라미터(External parameters): 카메라 좌표계와 월드 좌표계 사이의 변환 관계를 나타내는 파라미터입니다.

    두 좌표계 사이의 회전(Rotation) 및 평행이동(Translation) 변환으로 나타냅니다.

    *OpenCV에 있는 solvePnP함수를 이용하면 변환행렬에 대한 계산을 구할 수 있습니다. 

     

     

    Tip)카메라 캘리브레이션 팁

    거리가 가까울수록 좋은 결과를 얻을 수 있습니다.영상을 정밀하게 코너점의 위치를 찾을 수 있기 떄문입니다.

    다양한 각도로 4~20장 정도 준비하시는게 좋습니다.

     

    https://darkpgmr.tistory.com/32

     

    카메라 캘리브레이션 (Camera Calibration)

    카메라 캘리브레이션 (camera calibration)은 영상처리, 컴퓨터 비전 분야에서 번거롭지만 꼭 필요한 과정중의 하나입니다. 본 포스팅에서는 카메라 캘리브레이션의 개념, 카메라 내부 파라미터, 외

    darkpgmr.tistory.com

    해당 글을 다크 프로그래머님의 글을 보고 공부해서 정리한 글입니다. 모든 저작권은 다크프로그래머님에게 있습니다.

     

    실제 테스트)

    import cv2
    import numpy as np
    
    import json
    from glob import glob
    
    def calibration_info(image_path=None, CHESSBOARD_W=9, CHESSBOARD_H=6):
        img_list = glob(image_path+"/grid/*.png")
        #img_file = image_path+"/1.jpg"
        # print(img_list)
        CHESSBOARD_H = 6
        CHESSBOARD_W = 9
        SQUARE_SIZE = 0.021 #meter
        visualize = True
    
        #왜곡 보정을 위한 criteria
        criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
    
        # 2D/3D 빈 배열
        img_points = list()
        obj_points = list()
    
        
        #3D 실제좌표
        obj_points_grid = np.zeros((CHESSBOARD_H * CHESSBOARD_W, 3), np.float32)
        obj_points_grid[:, :2] = np.mgrid[0:CHESSBOARD_W, 0:CHESSBOARD_H].T.reshape(-1,2) *SQUARE_SIZE
    
        for img_file in img_list:
            img = cv2.imread(img_file, cv2.IMREAD_ANYCOLOR)
            gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
            ret, corners = cv2.findChessboardCorners(gray, (CHESSBOARD_W, CHESSBOARD_H), None)
    
            if ret:
                obj_points.append(obj_points_grid)
                img_points.append(corners)
    
                if visualize:
                    corners2 = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
                    cv2.drawChessboardCorners(img, (CHESSBOARD_W, CHESSBOARD_H), corners2, ret)
                    cv2.imshow("draw chessboard corners", img)
                    cv2.waitKey(0)    
    
            # get calibration information
            ret, camera_matrix, distcoffs, rvecs, tvecs = cv2.calibrateCamera(
                obj_points, img_points, gray.shape[::-1], None, None
            )
            for rvec, tvec, op, ip in zip(rvecs, tvecs, obj_points, img_points):
                imagePoints, jacobian = cv2.projectPoints(op, rvec, tvec, camera_matrix, distcoffs)
    
    
            calibration = dict()
    
            intrinsic_info = dict()
            intrinsic_info['fx'] = camera_matrix[0, 0]
            intrinsic_info['fy'] = camera_matrix[1, 1]
            intrinsic_info['cx'] = camera_matrix[0, 2]
            intrinsic_info['cy'] = camera_matrix[1, 2]
            calibration["intrinsic"] = intrinsic_info
            
            extrinsic_info = dict()
            rvecs_list = [rvec.tolist() for rvec in rvecs]
            extrinsic_info['rvecs'] = rvecs_list
            tvecs_list = [tvec.tolist() for tvec in tvecs]
            extrinsic_info['tvecs'] = tvecs_list
            distcoffs = distcoffs.tolist()
            extrinsic_info['distortion_coff'] = distcoffs
            calibration["extrinsic"] = extrinsic_info
    
            with open("./calibration.json", "w") as config_file:
                json.dump(calibration, config_file, indent=4)
    
    if __name__ == "__main__":
        calibration_info("./img")

    결과물)

     

    핵심) 그렇다면 왜 Calibration이 필요한 과정일까?

    - 2D 기준으로는 앞서 언급했던 것처럼 실제세계는 3D좌표계인데 이 과정에서 역할은

    왜곡 보정, 초점거리 추정, 스테레오 비전 등등 필요로 하기때문입니다.

    여기서 스테레오 비전은 카메라 두개를 사용해서 깊이를 추정하는 것인데 여기서 각 카메라의 내부 및 외부 매개변수를 정확하게 알아야 활용이 가능합니다.

     

    즉 우리의 실제세계와 카메라의 관계를 나타내는 것 입니다.

     

     

    추가) ROS Camera Calibration 수행

     

    1. roscore 실행

    2. usb_cam launch 실행

    #roscore 실행
    roscore
    
    #webcam 실행
    roslaunch usb_cam usb_cam-test.launch
    
    #calibration 실행
    rosrun camera_calibration cameracalibrator.py --size 8x6 --square 0.028 image:=/usb_cam/image_raw camera:=/usb_cam

    *추가설명)

    - size(체커보드 사이즈): 아래 예시 이미지가 8x6이고 가로,세로 각각 사각형 갯수를 세고 -1한 값이라고 생각하면 편하다.

    - square(사각형 크기): 사각형 한개의 변의 길이를 말하며 단위는 m이다. 즉 2.8cm라면 0.028이라 입력해야함. 

    - image(토픽명): 수행할 카메라의 raw 이미지를 불러오도록 토픽명을 맞춰야함.

     

    왼쪽 위부터 가로: 9개 -1 = 8

    왼쪽 위부터 세로: 7개 -1 = 6

    8x6 사이즈 (사이즈 입력이 틀릴 경우 체커보드 인식을 못하게 된다.)

    8x6 체커보드

    728x90
Designed by Tistory.