Disparity

스테레오 매칭 네트워크 학습을 목적으로 데이터를 작성하다가, 자주 사용되지는 않지만 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

완성된 시차를 시각적으로 보고 싶다면 위의 기능을 이용하여 왜곡된 이미지 형태로 표시할 수 있습니다. 입력 시차는 왼쪽 시차입니다.

끝!