이 프로젝트는 Camera Calibration과 Disparity Map, Depth Map을 생성하는 프로젝트이다.

Camera Calibration

먼저, 체커보드를 이용해서 Camera Calibration을 수행한다. 6개의 체커보드 이미지가 있고, 모서리를 찾아서 이를 평면좌표(world point)로 만들어주는 homography matrix를 찾고, 그 matrix에서 intrinsic, extrinsic 파라미터를 찾는 과정이다. Zhang’s method를 사용하여 수행할 수 있다.

Homography Calculation

먼저 $s\tilde{q}=H\tilde{p}$를 만족하는 행렬 $H$를 찾아야 한다. ($\tilde{q}$는 world point, $\tilde{p}$는 체커보드 좌표)

으로 표현되고, $\min_H\sum_{j=1}^m\left|\left|q_j-\hat{q_j}\right|\right|^2$를 최소화하는 $H$를 찾으면 된다. (, )

이를 정리하면,

이 되는데, 각 항을 풀어보면

이라고 쓸 수 있다. 앞에 곱해진 행렬을 $L_j$라고 하면 이 문제는 $\min_{\mathbf{x}}||L\mathbf{x}||^2$ 문제가 된다. ($L$은 $L_j$를 세로로 늘어뜨린 행렬) 따라서 $L^TL$의 가장 작은 eigenvalue중 가장 작은 것에 대응하는 eigenvector를 찾으면 된다.

이 때의 $H$ 행렬은 한 이미지당 하나를 찾을 수 있으므로 이 프로젝트에서는 6개의 $H$ 행렬이 나오게 된다.

Intrinsic Parameter

우리는 $H$행렬을 알고 있고, 이다. 그리고 , 이라는 제약을 갖고 있으므로, 우리는 intrinsic matrix $K$를 알아낼 수 있다.

먼저 이라고 하자. $h_1=Kr_1$, $h_2=Kr_2$이기 때문에 $r_1=K^{-1}h_1$, $r_2=K^{-1}h_2$이다.

위 조건들을 대입해 보면

라는 식을 만들어낼 수 있다.

이라고 하면,

이다. (이므로)

$B_{11}, B_{12}, B_{13}, B_{22}, B_{23}, B_{33}$만 알면 $K$의 변수들을 구할 수 있으므로 를 구하는 것을 목표로 한다.

두 개의 조건을 압축해서

이라고 쓸 수 있다. ()

라고 하면 각 $V$들은 이미지당 하나씩 있으므로, 우리는 총 6개의 $V$를 가지고 $B$를 찾을 수 있다. 이 $V$들을 세로로 합쳐서 $V’$행렬을 만들고, 문제를 풀면 $b$를 구할 수 있다. 이 때의 해는 $V’^TV’$의 eigenvalue중 가장 작은 것에 대응하는 eigenvector를 구하면 된다.

이렇게 구한 b를 이용해서 각각의 변수에

를 대입하면 intrinsic matrix 를 구할 수 있다.

Extrinsic Parameter

지금까지 구한 $H$와 $K$로 extrinsic parameter들을 구할 수 있다. 먼저 정규화를 위한 상수 를 구한다. 그 후에는

을 이용해 extrinsic parameter들을 구한다.

여기서 구한 rotation matrix 은 일반적으로 rotation matrix의 성질을 만족하지 않으므로, 보정을 해줘야 한다. $R=U\Sigma V^T$로 분해할 수 있는데, 여기서 $R’=UV^T$를 구하면 된다.

Maximum Likelihood Estimation (MLE)

우리가 위에서 구한 값은 그저 방정식을 푼 것이지, 물리적으로 아무 의미가 없는 숫자이다. 따라서 MLE를 통해 값을 보정해줄 필요가 있다. MLE추정은 를 통해 할 수 있다. (사실 이 식은 $H$를 찾을 때 썼던 식이다.)

코드에서는 intrinsic, extrinsic 파라미터들을 벡터로 만들어 넘겨서 lsqnonlin 함수를 사용하여 최적화했다.(Matlab)

Depth Map

Depth map을 구하기 위한 과정은 다음과 같다. (좌, 우에서 찍은 이미지가 주어진다.)

  1. 이미지를 흑백화시킨다.
  2. cost function을 정해서 cost volume을 만든다.
  3. cost aggregation을 한다.
  4. 최소 cost를 갖는 인덱스를 골라 disparity map을 만든다.
  5. disparity map을 카메라 파라미터를 이용해 depth map으로 변환시킨다.

Preprocessing

단순히 두 이미지를 흑백화시킨다.

Cost Volume

좌측 이미지를 기준으로 한다. 좌측 이미지의 모든 픽셀에 대하여 오른쪽 이미지에서는 왼쪽으로 $d$만큼 떨어진 픽셀을 고른다. (좌측 이미지에서 $(10,5)$에 대해, $d=5$라면 우측 이미지에서는 $(5,5)$를 고르는 셈.) 좌우 이미지 모두 해당 픽셀 주변의 window크기만큼의 행렬을 골라 벡터화시킨 후, cost를 계산해 cost volume에 저장한다. 이 계산을 minDisparity부터 maxDisparity까지 수행해 cost volume에 저장한다. (이 프로젝트에서 window 크기는 15로 지정하였고, minDisparity는 11, maxDisparity는 140으로 지정하였다. cost 대신에 를 사용하였다.)

Cost Aggregation

각 layer의 cost를 filter를 이용하여 aggregation한다. 이 프로젝트에서는 imguidedfilter 함수에 해당 이미지를 가이드로 사용해서 필터링하였다.

Disparity Map

각 픽셀에 대하여 가장 작은 cost를 가지는 disparity를 고른다. (이 프로젝트에서는 NCC를 사용하였으므로 값이 가장 큰 것을 고른다.)

Depth Map

각 픽셀에 대하여 $Z=\frac{fT}{d}$ 공식을 적용하여 depth map을 만든다.

Result

위 표는 카메라 파라미터 측정에 대한 결과이다.

위 이미지는 각각 좌, 우에서 찍은 이미지이다.

위 이미지는 disparity map이다.

위 이미지는 depth map이다.


이 프로젝트에 대한 코드는 링크에서 볼 수 있다.