Konsla Hobby

konsla99 님의 블로그 입니다.

Computer Vision/캘리브레이션

카메라 캘리브레이션 - 왜곡 제거

Konsla99 2026. 3. 15. 22:16

카메라 왜곡 제거

왜곡 제거 방법

캘리브레이션으로 왜곡 계수를 구한 후 다음 함수들로 왜곡을 보정할 수 있다:

  • cv::undistort() - 올인원 함수
  • cv::initUndistortRectifyMap() + cv::remap() - 2단계 방식
  • cv::undistortPoints() - 특정 점만 처리
왜곡 제거 지도 (Undistortion Map)
개념

왜곡 제거 지도는 출력 이미지의 각 픽셀이 입력 이미지의 어느 좌표를 참조할지 저장한 매핑 테이블이다.

왜 역방향 매핑인가?

입력 이미지를 직접 변환하면 픽셀이 분산되어 출력 이미지에 구멍이 생긴다. 따라서 출력 이미지의 각 픽셀 위치에서 입력 이미지의 참조 위치를 찾는 역방향 매핑이 필요하다.

계산 과정
  1. 픽셀 → 이미지 평면: 출력 픽셀 좌표를 카메라 내부 파라미터 역행렬($K^{-1}$)로 정규화
  2. 왜곡 적용: 정규화된 좌표에 왜곡 계수를 적용하여 왜곡된 정규화 좌표 계산
  3. 이미지 평면 → 픽셀: 왜곡된 정규화 좌표를 카메라 내부 파라미터($K$)로 픽셀 좌표 변환
  4. 매핑 저장: 출력 좌표와 입력 좌표의 대응 관계를 mapX, mapY에 저장

함수별 특징

cv::initUndistortRectifyMap()

왜곡 제거 지도(mapX, mapY)를 계산한다. 실제 왜곡 제거는 수행하지 않고 매핑 테이블만 생성한다.

cv::Mat mapX, mapY;
cv::initUndistortRectifyMap(
    cameraMatrix, distCoeffs, cv::Mat(), 
    cameraMatrix, imageSize, CV_32FC1, mapX, mapY
);
cv::remap()

생성된 왜곡 제거 지도를 사용하여 실제로 이미지 왜곡을 제거한다.

cv::Mat undistorted;
cv::remap(distorted, undistorted, mapX, mapY, cv::INTER_LINEAR);
cv::undistort()

왜곡 제거 지도 계산과 적용을 한 번에 수행한다.

사용 시기:

  • 이미지 1~2장 처리 시 (간편함)
  • 각 이미지의 카메라 파라미터가 다를 때 (매핑 재사용 불가)
cv::Mat undistorted;
cv::undistort(distorted, undistorted, cameraMatrix, distCoeffs);
cv::undistortPoints()

전체 이미지가 아닌 특정 점들만 왜곡 제거한다. Feature 기반 알고리즘에서 효율적이다.

std::vector<cv::Point2f> distorted_pts = {{320, 240}, {450, 180}};
std::vector<cv::Point2f> undistorted_pts;
cv::undistortPoints(distorted_pts, undistorted_pts, cameraMatrix, distCoeffs);
cv::convertMaps()

왜곡 제거 지도의 데이터 타입이나 포맷을 변환한다.

사용 가이드

상황 추천 방법 이유
같은 카메라, 여러 이미지 initUndistortRectifyMap + remap 매핑 재사용으로 빠름
이미지 1~2장 undistort 코드 간단
카메라마다 다른 파라미터 undistort 매핑 재사용 불가
실시간 비디오 initUndistortRectifyMap + remap 최고 성능
특징점만 처리 undistortPoints 필요한 점만 계산

예제

// 방법 1: 간단한 왜곡 제거
cv::Mat img = cv::imread("distorted.jpg");
cv::Mat undist;
cv::undistort(img, undist, K, dist);

// 방법 2: 비디오 처리 (효율적)
cv::Mat mapX, mapY;
cv::initUndistortRectifyMap(K, dist, cv::Mat(), K, size, CV_32FC1, mapX, mapY);

cv::VideoCapture cap(0);
cv::Mat frame, undist;
while (cap.read(frame)) {
    cv::remap(frame, undist, mapX, mapY, cv::INTER_LINEAR);
    cv::imshow("Undistorted", undist);
}

// 방법 3: 특징점만 처리
std::vector<cv::Point2f> corners;
cv::findChessboardCorners(img, patternSize, corners);
std::vector<cv::Point2f> corners_undist;
cv::undistortPoints(corners, corners_undist, K, dist, cv::noArray(), K);
반응형
END