스테레오 매칭 네트워크 학습을 목적으로 데이터를 작성하다가, 자주 사용되지는 않지만 deep에서 시차 데이터를 생성하는 방법을 정리하면 좋겠다는 생각에 이 글을 쓰게 되었습니다.
시뮬레이션된 데이터이든 Realsense로 직접 캡처한 데이터든 스테레오 설정에서 이미지와 깊이를 얻는 것은 쉽지만 차이를 얻는 것은 까다롭습니다. 초점거리와 기준선 길이를 이용해서 간단하게 변환하면 끝낼 수 있는데 왼쪽 시차와 오른쪽 시차가 일치하지 않으면 왼쪽에서 오른쪽으로, 오른쪽에서 왼쪽으로 와핑이 되지 않을 수 있습니다. 따라서 크로스 체크가 필요합니다.
def convert(depth, f, b):
disp = np.zeros_like(depth)
disp(depth!=0) = b*f / depth(depth!=0)
return disp
일반적으로 위의 공식에 의해 왼쪽 깊이와 오른쪽 깊이를 시차 맵으로 변경하는 것으로 끝나지만 한 단계가 더 필요합니다. (깊이가 비어있는 공간은 시차 0으로 처리합니다.)
def cross_check(ldisp_raw, rdisp_raw, disp_th=8):
ldisp = ldisp_raw.copy()
rdisp = rdisp_raw.copy()
img_h, img_w = np.shape(ldisp)(:2)
### forward-backward
forward = np.argwhere(ldisp != 0) # rc
forward_disp = -1*ldisp(forward(:,0), forward(:,1)).astype(np.int32)
backward = forward.copy()
backward(:, 1) = backward(:, 1) + forward_disp
valid = (backward(:,0) < img_h) * (backward(:,0) > 0) * (backward(:, 1) < img_w) * (backward(:,1) > 0)
backward = backward(valid)
backward_disp = rdisp(backward(:,0), backward(:,1)).astype(np.int32)
forward = forward(valid)
forward_disp = forward_disp(valid)
forward_backward = np.abs(forward_disp + backward_disp)
check = forward_backward < disp_th
left_valid = forward(check)
right_valid = backward(check)
lvalid = ldisp(left_valid(:,0), left_valid(:,1))
rvalid = rdisp(right_valid(:, 0), right_valid(:, 1))
ldisp *= 0
rdisp *= 0
ldisp(left_valid(:, 0), left_valid(:, 1)) = lvalid
rdisp(right_valid(:, 0), right_valid(:, 1)) = rvalid
### backward_forward
backward = np.argwhere(rdisp != 0) # rc
backward_disp = rdisp(backward(:, 0), backward(:, 1)).astype(np.int32) # positive
forward = backward.copy()
forward(:, 1) = forward(:, 1) + backward_disp
valid = (forward(:, 0) < img_h) * (forward(:, 0) > 0) * (forward(:, 1) < img_w) * (forward(:, 1) > 0)
forward = forward(valid)
forward_disp = ldisp(forward(:, 0), forward(:, 1)).astype(np.int32)
backward = backward(valid)
backward_disp = backward_disp(valid)
backward_forward = np.abs(backward_disp - forward_disp)
check = backward_forward < disp_th
left_valid = forward(check)
right_valid = backward(check)
lvalid = ldisp(left_valid(:, 0), left_valid(:, 1))
rvalid = rdisp(right_valid(:, 0), right_valid(:, 1))
ldisp *= 0
rdisp *= 0
ldisp(left_valid(:, 0), left_valid(:, 1)) = lvalid
rdisp(right_valid(:, 0), right_valid(:, 1)) = rvalid
return ldisp, rdisp
그런 다음 왼쪽 시차를 이용하여 오른쪽으로 휜 영상을 생성하고, 이를 이용하여 우측 휜 영상을 왼쪽으로 휜 영상으로 변환하면 원본 좌측 영상과 동일한지 확인한다. 약간 희소하다는 단점이 있지만 품질을 보장하기 위해 수행해야 합니다.
주의
- 왼쪽 시차는 보통 이미지로 저장되기 때문에 양수 값으로 표현되지만 실제로는 음수 값임을 잊지 말자.
(오른쪽 카메라는 왼쪽 카메라보다 왼쪽을 더 멀리 볼 수 없습니다.) - 차이는 정수 값입니다. 교차 확인 프로세스에서 분할하는 동안 정보 손실을 후회하는 경우 보간을 포함하십시오.
def vis_disparity(limg, rimg, disp, show=False):
limg = np.asarray(limg)
rimg = np.asarray(rimg)
warpred = np.zeros_like(limg) # (H, W, 3)
img_h, img_w = np.shape(limg)(:2)
u,v = np.meshgrid(np.arange(0, img_w), np.arange(0, img_h))
warp_uv = np.argwhere(disp != 0)
uw = (u-disp)(warp_uv(:,0), warp_uv(:,1))
vw = v(warp_uv(:,0), warp_uv(:,1))
uw = uw.astype(np.int32)
vw = vw.astype(np.int32)
warpred(vw, uw) = rimg(vw, uw)
canvas = np.concatenate((limg, warpred, rimg), axis=0)
if show:
cv2.imshow("vis disparity", canvas)
cv2.waitKey(0)
return canvas
완성된 시차를 시각적으로 보고 싶다면 위의 기능을 이용하여 왜곡된 이미지 형태로 표시할 수 있습니다. 입력 시차는 왼쪽 시차입니다.
끝!