양안 시차 (Binocular Disparity)

이미지 출처: OpenCV official docs
양안 시차는 인간과 같은 양안 시각 시스템에서 두 눈이 약간 다른 각도에서 대상을 보는 데서 발생하는 시각적 차이를 의미한다. 가까운 사물일 수록 시차(Disparity)가 크고, 멀리에 있는 사물일 수록 시차가 작다.
와 : 3D 공간 상의 한 점(Scene Point)이 두 카메라에서 투영된 이미지 평면 상의 좌표 : 두 카메라 센터 간의 거리 (Baseline) : 카메라의 초점 거리(Focal Length) 깊이(Depth): 3D 공간 상의 한 점(Scene Point)에서 카메라까지의 거리
The Sum of Squared Differences (제곱 차 합)
기본 개념으로 왼쪽, 오른쪽 이미지가 유사하지 않을 수록 거리가 가깝고, 유사할 수록 거리가 멀다고 설명했다.
여기서 핵심은 "두 이미지 간 유사도" 라고 볼 수 있다.
필자는 이번에 MSE(평균제곱오차) 방식으로 유사도를 구하였다.
: 왼쪽 이미지 : 오른쪽 이미지 : Block size(블록 사이즈); 비교할 이미지 크기 : Disparity(깊이)
OpenCV로 구현
from matplotlib import pyplot as plt
import numpy as np
import cv2
# Load images
imgL = cv2.imread('./data/tsukuba_l.png',0)
imgR = cv2.imread('./data/tsukuba_r.png',0)
# Compute disparity
stereo = cv2.StereoBM_create(numDisparities=16, blockSize=15)
disparity = stereo.compute(imgL,imgR)
# Display the plots
plt.imshow(disparity,'inferno')
plt.show()

Numpy로 구현
import numpy as np
import matplotlib.pyplot as plt
def compute_disparity(imgL, imgR, num_disparities, block_size):
"""
Computes the disparity map between a pair of rectified stereo images.
Args:
imgL (np.ndarray): Left grayscale image.
imgR (np.ndarray): Right grayscale image.
num_disparities (int): Maximum disparity range to search.
block_size (int): Size of the square block for block matching.
Returns:
np.ndarray: Disparity map with the same dimensions as the input images.
"""
# Ensure the images are numpy arrays and have float32 type
imgL = np.asarray(imgL, dtype=np.float32)
imgR = np.asarray(imgR, dtype=np.float32)
# Get the dimensions of the images
height, width = imgL.shape
# Initialize the disparity map with zeros
disparity_map = np.zeros((height, width), dtype=np.float32)
# Calculate half of the block size for easier indexing
half_block = block_size // 2
# Loop over each pixel in the left image
for y in range(half_block, height - half_block):
for x in range(half_block, width - half_block):
# Define the block region in the left image
blockL = imgL[y - half_block:y + half_block + 1, x - half_block:x + half_block + 1]
# Initialize variables for the best match
min_ssd = float('inf')
best_disparity = 0
# Search for the best disparity in the range [0, num_disparities)
for d in range(num_disparities):
if x - d - half_block