로봇에게 "저기"는 너무 모호하다
사람은 화면 속 물체를 보고도 자연스럽게 말합니다. "저 컵을 집어 줘." "상자 오른쪽에 있는 병을 치워 줘." 우리는 사진 속 물체가 실제 공간 어딘가에 있다는 사실을 별로 의식하지 않습니다. 하지만 로봇팔에게는 이 말이 아직 충분하지 않습니다.
이전 장에서 우리는 세그멘테이션을 통해 물체의 영역을 픽셀 단위로 분리했습니다. 예를 들어 빨간 컵의 마스크를 얻었다고 해 봅시다. 이제 로봇은 컵이 이미지의 어느 픽셀에 있는지 압니다. 중심 픽셀이 (u=420, v=260) 근처라는 것도 계산할 수 있습니다. 그런데 로봇팔은 픽셀 좌표만으로 움직일 수 없습니다.
로봇팔이 실제로 필요한 정보는 이런 형태입니다.
컵이 카메라 기준으로 오른쪽으로 몇 cm 떨어져 있는가
컵이 카메라 앞쪽으로 몇 cm 떨어져 있는가
컵의 높이는 어느 정도인가
그리퍼를 어디까지 접근시켜야 충돌하지 않고 집을 수 있는가
즉, 이미지의 2D 좌표를 실제 공간의 3D 좌표로 바꾸어야 합니다. 이때 필요한 것이 바로 깊이 정보입니다.
2D 카메라는 "어느 방향에 물체가 보이는지"를 알려 줍니다. 깊이 카메라는 거기에 하나를 더해 "그 방향으로 얼마나 멀리 있는지"를 알려 줍니다. 방향과 거리가 만나면 비로소 공간상의 점이 됩니다. 로봇 비전에서 이 순간은 꽤 중요합니다. 화면 속 그림이 로봇이 만질 수 있는 세계로 바뀌는 지점이기 때문입니다.

Depth Camera는 무엇을 더 보는가
일반 RGB 카메라는 각 픽셀마다 색상 값을 기록합니다. 빨강, 초록, 파랑의 조합으로 이미지를 만드는 방식입니다. 반면 Depth Camera, 즉 깊이 카메라는 각 픽셀마다 거리 값을 제공합니다. 여기서 거리란 보통 카메라에서 물체 표면까지의 깊이를 뜻합니다.
RGB 이미지가 다음과 같은 질문에 답한다면,
"이 픽셀은 무슨 색인가?"
Depth 이미지는 다음 질문에 답합니다.
"이 픽셀에 보이는 표면은 카메라에서 얼마나 떨어져 있는가?"
예를 들어 테이블 위에 컵이 있고, 컵 뒤에 벽이 있다고 해 봅시다. RGB 이미지에서는 컵도 보이고 벽도 보입니다. Depth 이미지에서는 컵 영역의 픽셀에는 가까운 거리 값이 들어가고, 벽 영역의 픽셀에는 더 먼 거리 값이 들어갑니다. 화면으로 보면 가까운 물체는 밝게, 먼 물체는 어둡게 표현하거나 반대로 표현하기도 합니다. 중요한 것은 색이 아니라 숫자입니다.
깊이 카메라의 방식은 장비마다 다릅니다. 어떤 카메라는 적외선 패턴을 쏘고 그 패턴이 어떻게 변형되는지 보며 깊이를 계산합니다. 어떤 카메라는 빛이 돌아오는 시간을 측정합니다. 또 어떤 시스템은 두 개의 카메라로 사람의 두 눈처럼 시차를 이용해 깊이를 추정합니다. 내부 원리는 조금씩 다르지만, 로봇 개발자가 주로 다루는 결과물은 비슷합니다. 바로 픽셀마다 깊이 값이 들어 있는 Depth 이미지입니다.
여기서 주의할 점이 있습니다. Depth 이미지는 완벽하지 않습니다. 반짝이는 금속, 투명한 유리컵, 검은색 물체, 너무 가까운 물체, 너무 먼 물체에서는 깊이 값이 비거나 튈 수 있습니다. 로봇이 컵을 잡으러 갔는데 실제로는 컵 뒤쪽 벽의 깊이를 읽고 있었다면 어떻게 될까요? 그리퍼는 컵을 지나쳐 엉뚱한 곳으로 가거나, 테이블에 부딪힐 수도 있습니다.
그래서 깊이 값은 "한 픽셀의 숫자 하나"만 믿기보다 주변 영역과 함께 안정적으로 해석해야 합니다. 이 장 후반부에서 마스크 영역과 깊이 필터링을 이용하는 이유가 바로 여기에 있습니다.
RGB-D 데이터: 색과 깊이가 함께 있는 이미지
로봇 비전에서 자주 등장하는 말이 RGB-D입니다. RGB-D에서 RGB는 색상 이미지, D는 Depth를 뜻합니다. 즉 RGB-D 데이터는 색상 정보와 깊이 정보가 함께 있는 데이터입니다.
보통 RGB-D 카메라를 사용하면 다음 두 종류의 이미지가 나옵니다.
RGB 이미지: 각 픽셀의 색상 정보
Depth 이미지: 각 픽셀의 거리 정보
카메라 정보: 초점거리, 중심점 같은 내부 파라미터
여기서 RGB 이미지와 Depth 이미지가 같은 해상도이고 같은 픽셀 위치를 공유하면 다루기 쉽습니다. 예를 들어 RGB 이미지에서 컵 중심이 (420, 260)이라면 Depth 이미지의 (420, 260) 위치에서 바로 거리 값을 읽을 수 있습니다.
하지만 실제 장비에서는 RGB 센서와 Depth 센서가 물리적으로 조금 떨어져 있는 경우가 많습니다. 이때 RGB 이미지와 Depth 이미지의 시야가 완전히 일치하지 않을 수 있습니다. 그래서 많은 카메라 SDK나 ROS2 드라이버는 정렬된 Depth 이미지를 제공합니다. 이를 흔히 aligned depth라고 부릅니다. 정렬된 Depth 이미지는 RGB 이미지의 픽셀 좌표에 맞게 깊이 값을 보정한 결과입니다.
로봇팔 프로젝트에서는 가능하면 RGB 이미지와 Depth 이미지가 정렬된 상태에서 시작하는 것이 좋습니다. 그래야 객체 검출이나 세그멘테이션으로 얻은 픽셀 위치를 그대로 깊이 이미지에 적용할 수 있습니다.
예를 들어 흐름은 이렇게 됩니다.
RGB 이미지에서 컵을 검출한다.
세그멘테이션으로 컵 마스크를 얻는다.
같은 픽셀 위치의 Depth 이미지에서 컵 영역의 깊이 값을 읽는다.
픽셀 좌표와 깊이 값을 이용해 카메라 기준 3D 좌표를 계산한다.
다음 단계에서 이 좌표를 로봇 좌표계로 변환한다.
이 장의 핵심은 4번입니다. "픽셀 하나와 깊이 값 하나가 어떻게 3D 점이 되는가?"를 이해하면, 이후 로봇팔 목표 위치 계산이 훨씬 선명하게 보입니다.
픽셀 좌표는 방향이고, 깊이는 거리다
이미지의 픽셀 좌표는 보통 (u, v)로 표현합니다. u는 이미지에서 가로 방향 위치, v는 세로 방향 위치입니다. 왼쪽 위 픽셀이 대개 (0, 0)이고, 오른쪽으로 갈수록 u가 커지며 아래로 갈수록 v가 커집니다.
하지만 픽셀 좌표 자체는 실제 길이가 아닙니다. (420, 260)이라는 좌표는 "이미지 안에서 이 위치에 보인다"는 뜻이지, "카메라 오른쪽 42cm, 아래쪽 26cm"라는 뜻이 아닙니다.
카메라를 작은 구멍으로 세상을 보는 장치라고 생각해 봅시다. 3D 공간의 한 점에서 나온 빛이 카메라 렌즈를 지나 이미지 평면의 한 픽셀에 맺힙니다. 이때 픽셀 좌표는 카메라에서 그 점을 바라보는 방향을 나타냅니다. 그리고 Depth 값은 그 방향으로 얼마나 떨어져 있는지를 나타냅니다.
방향과 거리를 알면 3D 위치를 복원할 수 있습니다. 이를 위해 필요한 것이 카메라 내부 파라미터입니다.
카메라 내부 파라미터 이해하기
카메라 내부 파라미터는 카메라가 3D 공간을 2D 이미지로 투영하는 방식을 설명하는 값입니다. 로봇에서 깊이 좌표를 계산할 때 가장 자주 쓰는 값은 네 가지입니다.
fx: x축 방향 초점거리fy: y축 방향 초점거리cx: 이미지 중심점의 x좌표cy: 이미지 중심점의 y좌표
여기서 초점거리라고 해서 반드시 우리가 손으로 자로 재는 렌즈의 물리적 길이만을 뜻하지는 않습니다. 이미지 좌표 계산에서는 보통 픽셀 단위의 초점거리로 표현됩니다. fx와 fy는 픽셀 좌표의 변화가 실제 카메라 시야에서 어느 정도 각도 변화에 해당하는지를 나타내는 값이라고 이해하면 됩니다.
cx, cy는 카메라의 광학 중심이 이미지에서 어디에 해당하는지를 나타냅니다. 이상적인 카메라라면 이미지 정중앙이겠지만, 실제 카메라에서는 약간 다를 수 있습니다. 그래서 캘리브레이션이나 카메라 드라이버가 제공하는 값을 사용하는 것이 안전합니다.
카메라 내부 파라미터는 보통 다음과 같은 행렬로 표현됩니다.
K = [ fx 0 cx ]
[ 0 fy cy ]
[ 0 0 1 ]이 행렬을 카메라 내부 행렬, 또는 intrinsic matrix라고 부릅니다. 이름은 조금 딱딱하지만, 역할은 단순합니다. 픽셀 좌표를 실제 카메라 기준 좌표로 되돌릴 때 필요한 기준표입니다.
픽셀과 깊이를 3D 좌표로 바꾸는 공식
이제 이미지의 한 픽셀 (u, v)와 그 픽셀의 깊이 값 Z가 있다고 하겠습니다. 카메라 내부 파라미터가 fx, fy, cx, cy로 주어졌다면 카메라 좌표계의 3D 점 (X, Y, Z)는 다음과 같이 계산할 수 있습니다.
X = (u - cx) * Z / fx
Y = (v - cy) * Z / fy
Z = depth(u, v)여기서 Z는 카메라 앞쪽 방향의 깊이입니다. X는 카메라 기준 좌우 방향, Y는 카메라 기준 위아래 방향입니다. 다만 좌표축의 방향은 사용하는 카메라 드라이버나 로봇 프레임 정의에 따라 달라질 수 있습니다. ROS에서 흔히 쓰는 optical frame에서는 Z가 카메라 앞쪽, X가 오른쪽, Y가 아래쪽을 향하는 경우가 많습니다.
공식을 말로 풀어 보면 이렇습니다. 픽셀 u가 이미지 중심 cx보다 오른쪽에 있으면 (u - cx)가 양수입니다. 그러면 3D 좌표의 X도 양수가 됩니다. 즉 물체가 카메라 오른쪽에 있다는 뜻입니다. 픽셀 v가 cy보다 아래에 있으면 Y가 양수가 됩니다. 광학 좌표계에서는 이것이 카메라 아래쪽을 뜻할 수 있습니다.
깊이 Z가 커질수록 같은 픽셀 차이도 더 큰 실제 거리로 변합니다. 멀리 있는 물체는 이미지에서 조금만 옆으로 벗어나 보여도 실제 공간에서는 꽤 멀리 옆에 있을 수 있습니다. 반대로 가까운 물체는 같은 픽셀 차이가 더 작은 실제 거리로 대응됩니다.
간단한 예를 들어 보겠습니다.
u = 420
v = 260
Z = 0.80 m
fx = 600
fy = 600
cx = 320
cy = 240그러면 다음과 같이 계산됩니다.
X = (420 - 320) * 0.80 / 600 = 0.133 m
Y = (260 - 240) * 0.80 / 600 = 0.027 m
Z = 0.80 m즉 이 점은 카메라 기준으로 오른쪽 약 13.3cm, 아래쪽 약 2.7cm, 앞쪽 80cm 지점에 있습니다. 이제 이 좌표는 단순한 이미지 위치가 아니라 실제 공간의 위치입니다. 물론 아직은 카메라 기준 좌표입니다. 로봇팔이 이 좌표를 사용하려면 다음 장에서 다룰 카메라-로봇 좌표 변환이 필요합니다.
깊이 값의 단위와 빈 값 처리
깊이 이미지를 다룰 때 가장 먼저 확인해야 할 것은 단위입니다. 어떤 카메라는 깊이 값을 미터 단위의 실수로 제공합니다. 어떤 카메라는 밀리미터 단위의 정수로 제공합니다. 예를 들어 Depth 이미지의 값이 800이라면 이것이 800m일 리는 없습니다. 보통 800mm, 즉 0.8m일 가능성이 큽니다.
단위를 잘못 해석하면 로봇의 움직임도 엉망이 됩니다. 컵이 80cm 앞에 있는데 800m 앞에 있다고 믿거나, 반대로 0.8mm 앞에 있다고 믿는 셈입니다. 로봇팔이 갑자기 이상한 목표를 향해 움직인다면, 복잡한 알고리즘을 의심하기 전에 깊이 단위부터 확인해야 합니다.
또 하나 중요한 문제는 유효하지 않은 깊이 값입니다. Depth 이미지에는 0, NaN, 너무 큰 값, 갑자기 튀는 값이 들어갈 수 있습니다. 이런 값은 계산에서 제외해야 합니다. 특히 투명한 컵, 반사되는 금속, 물체의 경계선 주변에서는 깊이 값이 불안정할 수 있습니다.
실전에서는 다음과 같은 기본 점검이 필요합니다.
깊이 값이 0이 아닌가
값이 카메라의 측정 가능 범위 안에 있는가
주변 픽셀과 비교했을 때 지나치게 튀지 않는가
단위가 미터인지 밀리미터인지 확인했는가
이런 확인을 거치지 않으면 3D 좌표 변환 공식이 아무리 정확해도 결과는 믿기 어렵습니다. 공식은 좋은 숫자가 들어왔을 때 좋은 결과를 냅니다. 나쁜 깊이 값은 그대로 나쁜 3D 좌표가 됩니다.
물체 중심점 하나만 믿으면 위험하다
객체 검출 장에서 우리는 바운딩 박스 중심점을 계산했습니다. 세그멘테이션 장에서는 마스크 영역의 중심도 구할 수 있었습니다. 그러면 단순히 중심 픽셀의 깊이 값을 읽으면 되지 않을까요?
작은 실험에서는 그렇게 해도 동작할 수 있습니다. 하지만 실제 로봇팔 작업에서는 중심점 하나만 믿는 방식이 종종 문제를 일으킵니다.
예를 들어 컵의 손잡이가 옆으로 나와 있고, 세그멘테이션 마스크의 중심이 컵의 빈 내부 쪽에 걸렸다고 해 봅시다. 그 픽셀의 깊이는 컵 표면이 아니라 컵 안쪽 바닥이나 뒤쪽 배경일 수 있습니다. 또는 물체가 얇은 상자라면 중심 픽셀이 로고의 반사 때문에 깊이 값을 잃을 수도 있습니다. 바운딩 박스 중심은 더 위험할 수 있습니다. 박스 안에는 물체뿐 아니라 배경도 함께 들어 있기 때문입니다.
따라서 물체의 3D 위치를 안정적으로 추정하려면 마스크 영역 전체를 활용하는 것이 좋습니다. 마스크가 알려 주는 것은 "이 픽셀들은 물체일 가능성이 높다"는 정보입니다. 이 영역에서 유효한 깊이 값들을 모아 대표 깊이를 계산하면, 한 픽셀의 오류에 덜 흔들립니다.
가장 단순하고 강력한 방법은 중앙값을 쓰는 것입니다. 평균은 튀는 값에 약합니다. 컵 대부분의 깊이가 0.8m인데 일부 픽셀이 2.5m로 잘못 측정되면 평균이 밀려납니다. 반면 중앙값은 값들을 정렬했을 때 가운데 값을 사용하므로 몇 개의 이상치에 더 강합니다.
마스크 영역으로 안정적인 3D 위치 구하기
세그멘테이션 마스크가 있다고 해 봅시다. 마스크에서 값이 1인 픽셀은 물체 영역이고, 0인 픽셀은 배경입니다. 이제 물체의 3D 위치를 다음 절차로 계산할 수 있습니다.
마스크에 해당하는 픽셀 좌표들을 모은다.
각 픽셀의 깊이 값을 Depth 이미지에서 읽는다.
유효하지 않은 깊이 값을 제거한다.
깊이 값의 중앙값 또는 일정 범위 안의 값만 남긴다.
남은 픽셀들의 3D 좌표를 계산한다.
3D 좌표들의 평균 또는 중앙값으로 물체 위치를 정한다.
여기서 두 가지 방식이 있습니다. 첫 번째는 2D 중심 픽셀을 정한 뒤, 깊이는 마스크 영역의 중앙값을 사용하는 방법입니다. 두 번째는 마스크 안의 여러 픽셀을 각각 3D 점으로 변환한 뒤, 그 3D 점들의 대표값을 구하는 방법입니다.
첫 번째 방식은 빠르고 단순합니다.
u_center = 마스크의 2D 중심 x좌표
v_center = 마스크의 2D 중심 y좌표
Z = 마스크 영역 깊이값의 중앙값
X = (u_center - cx) * Z / fx
Y = (v_center - cy) * Z / fy두 번째 방식은 조금 더 계산량이 있지만 물체의 실제 표면 분포를 더 잘 반영할 수 있습니다.
마스크 안의 각 픽셀 (u, v)에 대해:
Z = depth(u, v)
X = (u - cx) * Z / fx
Y = (v - cy) * Z / fy
3D 점 (X, Y, Z)을 저장
저장된 3D 점들의 대표값을 물체 위치로 사용로봇팔로 물체를 집는 상황에서는 두 방식을 섞어 쓰기도 합니다. 물체의 대략적인 위치는 마스크 전체의 3D 대표값으로 구하고, 실제 집기 지점은 물체의 윗면이나 가장 안정적인 영역에서 따로 찾습니다. 예를 들어 컵을 옆에서 잡을지, 위에서 잡을지에 따라 필요한 3D 지점이 달라집니다.
깊이 필터링: 이상한 숫자를 걸러내는 작은 방패
깊이 카메라는 훌륭하지만 변덕스럽습니다. 따라서 로봇은 깊이 값을 그대로 믿기보다 작은 방패를 하나 들고 있어야 합니다. 그 방패가 깊이 필터링입니다.
가장 기본적인 필터링은 범위 제한입니다. 예를 들어 책상 위 물체를 집는 로봇팔이라면 관심 거리가 대략 20cm에서 120cm 사이일 수 있습니다. 이 범위 밖의 깊이 값은 작업과 무관하거나 오류일 가능성이 높습니다. Z < 0.2m 또는 Z > 1.2m인 값은 제외할 수 있습니다.
다음으로는 중앙값 기준 필터링을 사용할 수 있습니다. 마스크 영역에서 유효한 깊이 값들의 중앙값을 구한 뒤, 그 중앙값과 너무 멀리 떨어진 값은 제거합니다. 예를 들어 중앙값이 0.75m인데 어떤 픽셀이 1.8m라면, 그 픽셀은 물체가 아니라 배경일 가능성이 큽니다.
마스크 경계도 조심해야 합니다. 물체와 배경이 만나는 경계에서는 한 픽셀 안에 두 표면이 섞이거나 센서 정렬 오차가 나타날 수 있습니다. 이럴 때는 마스크를 조금 줄인 뒤 깊이를 읽는 방법도 좋습니다. OpenCV의 erosion 연산처럼 마스크 외곽을 한두 픽셀 깎아내면 경계 오류를 줄일 수 있습니다.
정리하면 안정적인 물체 위치 추정을 위해 자주 쓰는 방법은 다음과 같습니다.
관심 거리 범위를 벗어난 깊이 값 제거
0,NaN, 무한대 같은 비정상 값 제거마스크 경계 영역을 줄여 배경 깊이 섞임 완화
중앙값을 기준으로 너무 튀는 깊이 값 제거
여러 픽셀의 3D 좌표를 대표값으로 요약
이런 과정은 화려해 보이지 않습니다. 하지만 로봇 시스템에서는 이런 작은 처리들이 성공률을 크게 좌우합니다. 딥러닝 모델이 물체를 잘 찾아도, 깊이 값 하나를 잘못 읽으면 로봇팔은 허공을 집습니다.
Python 형태로 보는 3D 위치 계산
아래 코드는 개념을 보여 주기 위한 예시입니다. 실제 프로젝트에서는 카메라 드라이버, ROS2 메시지 타입, 이미지 단위에 맞게 수정해야 합니다.
import numpy as np
def estimate_object_position(mask, depth, fx, fy, cx, cy, depth_scale=1.0):
# mask: 물체 영역이면 True인 2D 배열
# depth: depth 이미지
# depth_scale: depth 값을 미터로 바꾸기 위한 비율
# 예: depth가 mm 단위라면 depth_scale = 0.001
ys, xs = np.where(mask)
if len(xs) == 0:
return None
z_values = depth[ys, xs].astype(np.float32) * depth_scale
valid = np.isfinite(z_values)
valid &= z_values > 0.2
valid &= z_values < 1.5
xs = xs[valid]
ys = ys[valid]
z_values = z_values[valid]
if len(z_values) == 0:
return None
z_med = np.median(z_values)
near = np.abs(z_values - z_med) < 0.05
xs = xs[near]
ys = ys[near]
z_values = z_values[near]
if len(z_values) == 0:
return None
X = (xs - cx) * z_values / fx
Y = (ys - cy) * z_values / fy
Z = z_values
point = np.array([
np.median(X),
np.median(Y),
np.median(Z)
])
return point이 함수는 마스크 영역의 픽셀들을 모으고, 각 픽셀의 깊이를 읽은 뒤, 유효하지 않은 값을 제거합니다. 그다음 중앙값에서 너무 멀리 떨어진 깊이 값을 한 번 더 제거하고, 남은 픽셀들을 3D 좌표로 변환합니다. 마지막에는 각 축의 중앙값을 물체 위치로 반환합니다.
여기서 depth_scale은 특히 중요합니다. Depth 이미지가 밀리미터 단위라면 depth_scale=0.001로 두어 미터 단위로 바꿉니다. 이미 미터 단위라면 1.0을 사용하면 됩니다.
함수가 None을 반환하는 경우도 중요합니다. 이는 물체 위치를 안정적으로 계산할 수 없다는 뜻입니다. 로봇 시스템은 이 상황에서 억지로 움직이면 안 됩니다. 다시 관측하거나, 카메라 위치를 바꾸거나, 사용자에게 "물체 깊이를 확인할 수 없습니다"라고 알려야 합니다.
중심점, 표면점, 집기점은 다르다
여기서 한 가지를 분명히 해 두어야 합니다. 우리가 계산한 물체의 3D 위치는 대개 물체의 대표 위치입니다. 하지만 로봇팔이 실제로 필요한 것은 상황에 따라 다를 수 있습니다.
물체 중심점은 물체가 대략 어디 있는지 알려 줍니다. 표면점은 카메라에서 보이는 물체 표면 위의 한 점입니다. 집기점은 그리퍼가 실제로 접근해야 하는 위치입니다. 이 셋은 같을 수도 있지만, 많은 경우 다릅니다.
예를 들어 컵을 위에서 집으려면 컵의 윗부분 근처가 중요합니다. 상자를 집으려면 양쪽 면의 폭과 그리퍼가 닿을 수 있는 위치가 중요합니다. 납작한 물체를 집으려면 가장자리나 들어 올릴 수 있는 틈이 중요할 수 있습니다. 따라서 3D 위치 계산은 집기 전략의 출발점이지, 집기 문제 전체의 답은 아닙니다.
그럼에도 물체의 안정적인 3D 대표 위치를 구하는 일은 매우 중요합니다. 대표 위치가 안정적이어야 로봇팔이 접근 방향을 정하고, 충돌을 피하며, 그리퍼를 열고 닫을 타이밍을 잡을 수 있습니다.
RGB-D에서 포인트 클라우드로
마스크 안의 여러 픽셀을 모두 3D 좌표로 변환하면 점들이 모입니다. 이 점들의 집합을 포인트 클라우드라고 부릅니다. 포인트 클라우드는 말 그대로 공간에 흩어진 점구름입니다. 각 점은 카메라가 본 물체 표면의 일부를 나타냅니다.
포인트 클라우드를 사용하면 단순한 중심점보다 더 많은 정보를 얻을 수 있습니다. 물체가 얼마나 넓은지, 표면이 어느 방향을 향하는지, 테이블 평면과 물체가 어떻게 분리되는지 등을 분석할 수 있습니다. 로봇 조작에서는 포인트 클라우드를 이용해 집기 후보를 만들거나, 장애물을 피하는 경로 계획에 활용하기도 합니다.
하지만 처음부터 포인트 클라우드 전체를 복잡하게 다룰 필요는 없습니다. 이 책의 흐름에서는 먼저 RGB-D 이미지에서 물체의 3D 대표 위치를 안정적으로 얻는 데 집중합니다. 이후 로봇팔 조작과 Pick and Place 단계에서 필요에 따라 더 정교한 집기 후보를 다루게 됩니다.
중요한 것은 관점의 전환입니다. RGB 이미지는 "무엇이 보이는가"를 알려 줍니다. Depth 이미지는 "얼마나 떨어져 있는가"를 알려 줍니다. 둘을 합치면 "그 물체가 공간 어디에 있는가"를 말할 수 있습니다. 로봇팔은 바로 이 지점부터 행동할 수 있습니다.
실제 로봇에서 자주 생기는 문제들
깊이 카메라를 연결하고 공식을 적용하면 모든 것이 바로 해결될 것 같지만, 실제 작업대에서는 작은 함정들이 계속 등장합니다.
첫 번째는 RGB와 Depth의 정렬 문제입니다. RGB 이미지에서는 컵의 중심을 정확히 찾았는데, Depth 이미지의 같은 픽셀에는 컵이 아니라 배경 깊이가 들어 있을 수 있습니다. 카메라 드라이버에서 aligned depth를 사용하고 있는지 확인해야 합니다.
두 번째는 시간 차이입니다. 로봇이나 물체가 움직이는 중이라면 RGB 이미지와 Depth 이미지가 정확히 같은 순간의 데이터가 아닐 수 있습니다. 빠르게 움직이는 물체를 잡을 때는 이 차이가 오차로 나타납니다. 가능하면 동기화된 프레임을 사용하고, 움직임이 큰 상황에서는 최신 프레임을 기준으로 다시 계산해야 합니다.
세 번째는 카메라의 사각지대입니다. 깊이 카메라는 너무 가까운 곳이나 너무 먼 곳을 잘 측정하지 못합니다. 또한 물체의 옆면이나 깊게 파인 부분처럼 센서가 보기 어려운 영역은 값이 빠질 수 있습니다. 카메라 설치 위치와 각도는 알고리즘만큼 중요합니다.
네 번째는 좌표계 착각입니다. 카메라 좌표계에서 Y가 아래쪽을 향하는데, 로봇 좌표계에서는 Z가 위쪽을 향할 수 있습니다. 이 차이를 무시하면 로봇이 위로 가야 할 때 아래로 가는 식의 문제가 생깁니다. 이 장에서는 카메라 기준 3D 좌표까지만 계산했습니다. 다음 장에서는 이 좌표를 로봇 기준 좌표로 바꾸며 좌표계 문제를 본격적으로 다룹니다.
로봇팔을 위한 3D 위치 추정 흐름
이제 지금까지의 내용을 하나의 로봇팔 파이프라인으로 묶어 봅시다. 사용자가 "빨간 컵을 집어 줘"라고 말하면, 로봇은 먼저 카메라로 작업대를 봅니다. 객체 검출 모델이 컵 후보를 찾고, 세그멘테이션 모델이 컵의 픽셀 영역을 분리합니다. 여기까지는 이미지 안의 이야기입니다.
그다음 RGB-D 단계가 시작됩니다. 컵 마스크에 해당하는 Depth 값을 모읍니다. 이상한 값을 걸러냅니다. 중앙값과 마스크 내부 픽셀들을 이용해 컵의 카메라 기준 3D 위치를 계산합니다. 이 위치는 예를 들어 다음과 같은 형태가 됩니다.
camera_frame 기준 컵 위치:
X = 0.13 m
Y = 0.02 m
Z = 0.80 m이제 로봇은 컵이 카메라 앞쪽 80cm, 오른쪽 13cm 근처에 있다는 것을 압니다. 하지만 아직 끝이 아닙니다. 로봇팔의 베이스는 카메라와 다른 곳에 있습니다. 카메라가 로봇팔 손목에 붙어 있을 수도 있고, 작업대 위 고정된 위치에 있을 수도 있습니다. 따라서 카메라 기준 좌표를 로봇 기준 좌표로 변환해야 합니다.
다음 장의 주제는 바로 이것입니다. 카메라가 본 3D 점을 로봇팔이 이해하는 목표 위치로 바꾸는 과정입니다. 이 변환이 제대로 되어야 로봇은 이미지 속 컵을 실제로 집을 수 있습니다.
정리
깊이 정보는 로봇 비전이 실제 행동으로 이어지기 위한 다리입니다. 객체 검출과 세그멘테이션이 "무엇이 어디에 보이는지"를 알려 준다면, Depth 이미지는 "그 물체가 실제 공간에서 얼마나 떨어져 있는지"를 알려 줍니다.
RGB-D 데이터는 색상 이미지와 깊이 이미지를 함께 사용합니다. RGB 이미지에서 찾은 픽셀 위치나 마스크를 Depth 이미지와 결합하면 물체의 3D 위치를 계산할 수 있습니다. 이때 카메라 내부 파라미터 fx, fy, cx, cy가 필요하며, 픽셀 좌표 (u, v)와 깊이 Z는 다음 공식으로 카메라 좌표계의 3D 점이 됩니다.
X = (u - cx) * Z / fx
Y = (v - cy) * Z / fy
Z = depth(u, v)다만 실제 로봇에서는 한 픽셀의 깊이 값만 믿으면 위험합니다. 마스크 영역의 깊이 값을 모으고, 유효하지 않은 값을 제거하고, 중앙값이나 필터링을 이용해 안정적인 대표 위치를 구해야 합니다. 이렇게 얻은 3D 위치는 아직 카메라 기준 좌표입니다. 다음 단계에서는 이 좌표를 로봇팔 기준 좌표로 변환해, 실제 Pick and Place 동작의 목표로 사용할 것입니다.
이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.