SAPIEN에서 한 물체가 여러 분할 라벨로 보인다면 먼저 메시 단위와 actor 단위 중 무엇을 읽었는지 확인해야 합니다. 공식 Camera 예제의 Segmentation 출력에서 채널 0은 visual shape를 구분하는 메시 수준 ID, 채널 1은 actor 수준 ID입니다. 여러 visual shape를 가진 actor 하나를 대상으로 마스크를 만들 때는 채널 1에서 해당 actor ID를 고릅니다.
같은 카메라와 장면을 사용해도 어느 채널을 고르는지에 따라 “물체 하나”의 픽셀 집합이 달라집니다. 이 선택은 분할 모델을 평가하거나 로봇이 조작할 물체의 관측 영역을 추출할 때 쓰는 정답의 단위를 결정합니다.
같은 actor의 두 메시를 하나의 마스크로 묶기
SAPIEN 공식 Camera 문서는 camera.get_picture("Segmentation")이 높이×너비×4 형태의 배열을 반환한다고 설명하고, 앞의 두 채널에 각각 mesh-level과 actor-level이라는 주석을 붙입니다. 시각적 모양을 나타내는 visual shape의 ID와 그 모양이 속한 actor의 ID를 함께 읽을 수 있는 구조입니다.
다음은 가상 장면의 라벨과 픽셀 수입니다. 컵 몸통과 손잡이를 서로 다른 visual shape로 만들되, 둘 다 actor 7에 속하게 했다고 가정합니다. 옆의 상자는 actor 8입니다.
| 화면에 보이는 부분 | 채널 0의 visual ID | 채널 1의 actor ID | 해당 부분의 픽셀 수 |
|---|---|---|---|
| 컵 몸통 | 12 | 7 | 600 |
| 컵 손잡이 | 13 | 7 | 150 |
| 옆 상자 | 14 | 8 | 400 |
이 구성에서 visual ID == 12로 얻는 마스크는 몸통 600픽셀입니다. actor ID == 7로 얻는 마스크는 몸통과 손잡이의 합집합인 750픽셀입니다. 손잡이만 인식하는 문제에는 첫 번째 채널의 13이 유용하고, 컵 actor 전체의 보이는 영역을 찾는 문제에는 두 번째 채널의 7이 맞습니다.
위 가상 ID를 사용하는 마스크 추출은 다음처럼 표현할 수 있습니다. camera는 장면 상태가 렌더러에 동기화되고 take_picture()가 끝난 카메라를 뜻합니다.
seg = camera.get_picture("Segmentation")
visual_ids = seg[..., 0]
actor_ids = seg[..., 1]
cup_visible_mask = actor_ids == 7
handle_visible_mask = visual_ids == 13
actor의 구성도 함께 봐야 합니다. 컵 몸통과 손잡이를 서로 다른 actor로 만들었다면 하나의 actor ID 비교로 둘을 합칠 수 없습니다. 이 경우 데이터 생성 쪽에서 두 actor가 같은 평가 대상이라는 대응표를 만들고, 그 ID들의 마스크를 합쳐야 합니다. 물리 장면을 구성한 단위와 데이터셋에서 평가할 물체 단위를 연결하는 단계입니다.
색상 PNG와 원시 ID 배열은 용도가 다르다
공식 예제는 분할 결과를 보여 주기 위해 ID 채널을 uint8로 바꾸고, 그 값을 색상 팔레트의 인덱스로 사용합니다. 이 경로의 결과는 라벨을 눈으로 구별하기 위한 색상 영상입니다. 마스크 계산과 저장에는 변환 전의 ID 배열을 사용하는 편이 명확합니다.
8비트 정수는 0부터 255까지만 표현합니다. 가상의 원시 ID가 12와 268이라면, NumPy의 astype(np.uint8) 변환에서는 둘 다 12가 됩니다. 원래 다른 ID가 표시용 배열에서 같은 값이 되는 사례입니다. 색칠한 PNG만 남겼다면 두 대상의 차이를 그 파일에서 복원하기 어렵습니다.
평가용으로는 원시 라벨의 값을 보존하는 배열 형식과 ID 대응표를 남기고, 미리보기용으로 별도의 색상 영상을 만들 수 있습니다. 예를 들어 이번 프레임에 나타난 고유 ID를 모아 짧은 팔레트 인덱스에 대응시키면, 원시 번호의 크기와 표시 색을 분리할 수 있습니다. 이때도 팔레트 번호가 아니라 원시 ID를 대상으로 물체 마스크를 계산합니다.
해당 문서의 uint8 변환은 시각화 코드의 선택입니다. 그 줄만 보고 카메라가 처음부터 8비트 라벨을 반환한다고 해석하지 않도록, 원본 배열과 표시용 배열에 다른 변수 이름을 붙이는 것이 좋습니다.
장면 ID를 데이터셋의 의미 라벨로 연결하기
actor ID 7은 장면에서 선택한 actor를 가리킵니다. “컵”이라는 의미 범주를 만들려면 어떤 actor들이 컵인지 별도로 대응시켜야 합니다. 같은 범주의 컵 세 개를 구별하려는 인스턴스 분할과, 세 컵을 하나의 범주로 합치는 의미 분할은 필요한 대응표가 다릅니다.
| 독자가 만들려는 정답 | 사용할 정보 | 예시의 결과 |
|---|---|---|
| 컵 actor 하나의 보이는 영역 | actor ID → 평가 대상 | actor 7의 픽셀 집합 |
| 컵의 손잡이 부분 | visual ID → 부품 이름 | visual 13의 픽셀 집합 |
| 장면 안 모든 컵의 영역 | 여러 actor ID → 컵 범주 | 컵으로 등록한 actor들의 합집합 |
여러 에피소드를 저장한다면 장면을 구성한 시점의 ID 대응표도 각 에피소드에 연결합니다. 공식 Camera 페이지는 장면을 다시 불러왔을 때 같은 숫자가 같은 물체에 영구히 배정된다는 규칙을 제시하지 않습니다. 따라서 데이터셋의 고정된 물체 이름은 애플리케이션이 관리하고, 렌더러의 ID는 그 시점의 이름에 대응시키는 설계가 필요합니다.
카메라 분할 마스크가 세는 것은 해당 화면에서 라벨을 받은 픽셀입니다. 컵 뒤쪽이나 다른 물체에 가려진 손잡이까지 포함한 전체 표면적과는 측정 대상이 다릅니다. 앞의 750픽셀도 가정한 시점에 보이는 영역의 합입니다. 가림이 바뀐 두 프레임을 비교할 때는 actor가 동일한지와 보이는 영역이 달라졌는지를 나누어 볼 수 있습니다.
마스크를 깊이와 함께 쓰면 특정 actor에 속한 거리 샘플을 고를 수 있습니다. 이때 두 배열이 같은 카메라·해상도·촬영 상태에 대응해야 합니다. 깊이가 만들어지는 방식과 반환 좌표를 연결하는 내용은 SAPIEN 정답 깊이와 능동 스테레오의 차이에서 이어집니다.
자료 확인: 2026년 10월 16일의 SAPIEN 공식 Camera 페이지를 기준으로 채널과 시각화 코드를 해석했습니다. 이 글을 위해 SAPIEN을 실행하거나 분할 영상을 렌더링하지 않았습니다.