입력 프레임 데이터 요구 사항
외부 프레임 데이터 소스가 정상적으로 작동하기 위해서는 데이터의 정확성을 보장하는 것이 가장 중요하면서도 까다로운 부분입니다. 이 문서는 외부 프레임 데이터 소스의 입력 프레임 데이터 요구 사항을 설명합니다.
시작하기 전에
- 카메라, 입력 프레임과 같은 기본 개념을 이해합니다.
- 외부 프레임 데이터 소스의 기본 개념과 일반적인 유형을 이해합니다.
입력 프레임 데이터 유형
Unity에서 외부 프레임 데이터 소스는 일반적으로 서로 다른 시간에 서로 다른 데이터를 수신해야 합니다. 외부 데이터 입력 시간과 데이터 특성에 따라 이 두 그룹의 데이터를 다음과 같이 부릅니다:
- 카메라 프레임 데이터(camera frame data)
- 렌더링 프레임 데이터(rendering frame data)
다른 유형의 외부 프레임 데이터 소스는 이 두 데이터 그룹에 대해 다른 요구 사항을 가집니다:
- 이미지 및 장치 모션 데이터 입력 확장: 카메라 프레임 데이터 및 렌더링 프레임 데이터 모두 필요
- 이미지 입력 확장: 카메라 프레임 데이터만 필요
카메라 프레임 데이터
데이터 요구 사항:
- 타임스탬프(timestamp)
- 원본 물리적 카메라 이미지 데이터(raw camera image data)
- 내부 파라미터(intrinsics, 이미지 크기, 초점 거리, 주점 포함. 왜곡이 있는 경우 왜곡 모델 및 왜곡 매개변수 필요)
- 외부 파라미터(extrinsics, Tcw 또는 Twc, 보정된 행렬로 물리적 카메라의 장치/헤드 pose 원점에 대한 물리적 오프셋 표현)
- 트래킹 상태(tracking status)
- 장치 포즈(device pose)
데이터 시간:
- 물리적 카메라 노출 중점
데이터 사용:
- API 호출 시간: 외부 코드 설계에 따라 변경 가능. 대부분 장치에서 사용하는 일반적인 방법은 3D 엔진의 렌더링 업데이트 시점에 쿼리한 다음 장치 데이터의 타임스탬프를 기반으로 추가 데이터 처리 여부를 결정하는 것임
- API 호출 스레드: 3D 엔진의 game thread 또는 사용되는 모든 외부 API가 스레드 안전(thread-safe)한 경우 다른 스레드
Unity에서 API 호출 예시는 다음과 같습니다:
void TryInputCameraFrameData()
{
double timestamp;
if (timestamp == curTimestamp) { return; }
curTimestamp = timestamp;
PixelFormat format;
Vector2Int size;
Vector2Int pixelSize;
int bufferSize;
var bufferO = TryAcquireBuffer(bufferSize);
if (bufferO.OnNone) { return; }
var buffer = bufferO.Value;
IntPtr imageData;
buffer.tryCopyFrom(imageData, 0, 0, bufferSize);
var historicalHeadPose = new Pose();
MotionTrackingStatus trackingStatus = (MotionTrackingStatus)(-1);
using (buffer)
using (var image = Image.create(buffer, format, size.x, size.y, pixelSize.x, pixelSize.y))
{
HandleCameraFrameData(deviceCamera, timestamp, image, cameraParameters, historicalHeadPose, trackingStatus);
}
}
렌더링 프레임 데이터
데이터 요구 사항:
- 타임스탬프(timestamp)
- 트래킹 상태(tracking status)
- 디바이스 포즈(device pose)
데이터 시간:
- 화면 출력 시각. TimeWarp는 계산에서 제외됨. 동일 시각의 device pose 데이터는 가상 카메라의 transform을 설정하여 현재 프레임을 렌더링하기 위해 외부(예: 장치 SDK)에서 사용됨.
참고
TimeWarp(종종 Reprojection 또는 ATW/PTW로도 불림)은 VR/AR 헤드셋에서 지연 시간을 줄이기 위해 일반적으로 사용되는 기술입니다. 이는 렌더링 완료 후 최신 헤드 포즈를 기반으로 이미지를 다시 왜곡하여 렌더링 중 발생한 헤드 움직임을 보상합니다. EasyAR에는 TimeWarp 후 실제 화면 출력 시점이 아닌, 렌더링 시작 시 가상 카메라를 설정하는 데 사용된 포즈에 해당하는 시점이 필요합니다.
데이터 사용:
- API 호출 시간: 3D 엔진의 각 렌더링 프레임
- API 호출 스레드: 3D 엔진의 game thread
Unity에서 API 호출 예시는 다음과 같습니다:
private void InputRenderFrameMotionData()
{
double timestamp = 0e-9;
var headPose = new Pose();
MotionTrackingStatus trackingStatus = (MotionTrackingStatus)(-1);
HandleRenderFrameData(timestamp, headPose, trackingStatus);
}
데이터 요구 사항 세부 사항
물리적 카메라 이미지 데이터:
- 이미지 좌표계: 센서가 수평일 때 캡처된 데이터도 수평이어야 함. 데이터는 좌상단을 원점으로 하여 행 우선(row-major)으로 저장되어야 함. 이미지가 뒤집히거나 뒤집어져서는 안됨.
- 이미지 FPS: 일반적으로 30 또는 60 fps가 적합함. 높은 fps가 특별한 영향을 미치는 경우, 합리적인 알고리즘 효과를 위해 최소 허용 프레임 속도는 2임. 2보다 높은 fps 사용을 권장하며, 일반적으로 원본 데이터 프레임 속도를 사용하는 것이 좋음.
- 이미지 크기: 더 나은 계산 결과를 얻기 위해 최대 변 길이가 960 이상이어야 함. 데이터 파이프라인에서 시간이 오래 걸리는 이미지 크기 조정은 권장하지 않으며, 전체 크기 데이터 복사 시간이 너무 길지 않은 한 원본 데이터를 직접 사용하는 것이 좋음. 이미지 해상도는 640*480보다 작을 수 없음.
- 픽셀 포맷: 트래킹 성능과 종합적인 성능을 고려할 때, 일반적으로 포맷 우선순위는 YUV > RGB > RGBA > Gray(YUV의 Y 채널) 순임. YUV 데이터 사용 시 데이터 패킹 및 패딩 세부 사항을 포함한 완전한 데이터 정의가 필요함. 단일 채널 이미지에 비해 컬러 이미지를 사용하면 Mega 효과가 더 좋지만 다른 기능에는 큰 영향이 없음.
- 데이터 접근: 데이터 포인터 또는 동등한 구현. 데이터 파이프라인에서 불필요한 복사본 생성을 모두 제거하는 것이 가장 좋음. HandleRenderFrameData에서 EasyAR은 데이터 사본을 생성한 후 비동기적으로 사용하며, 이 동기적 호출이 완료되면 이미지 데이터를 더 이상 사용하지 않음. 데이터 소유권에 유의.
타임스탬프:
- 모든 타임스탬프는 클럭 동기화되어야 하며, 가능하면 하드웨어 동기화가 바람직합니다. 데이터 단위는 초(seconds)이지만, 정확도는 나노초 수준이거나 가능한 한 높아야 합니다.
추적 상태:
- 추적 상태는 장치에 의해 정의되며, 추적 손실(VIO 사용 불가) 상태를 포함해야 합니다. 더 많은 등급이 있다면 더 좋습니다.
장치 포즈:
- 모든 포즈(포함하여 3D 엔진 내 가상 카메라의 변환)는 동일한 원점을 사용해야 합니다.
- 모든 포즈 및 외부 파라미터는 동일한 좌표축 시스템을 사용해야 합니다.
- Unity에서, 포즈 데이터의 좌표축 시스템 유형은 Unity 좌표축 시스템 또는 EasyAR 좌표축 시스템이어야 합니다. 입력 확장이 EasyAR에 의해 구현되고 다른 좌표축 시스템 정의를 사용하는 경우, 명확한 좌표축 시스템 정의를 제공하거나 Unity 좌표축 시스템 또는 EasyAR 좌표축 시스템으로 변환하는 방법을 제공해야 합니다.
- Unity에서, Unity XR 프레임워크를 사용하는 경우, XROrigin.TrackingOriginMode.Device 모드와의 호환성만 필요합니다.
내부 파라미터:
- 모든 값은 이미지 데이터와 일치해야 합니다. 필요한 경우 EasyAR에 입력하기 전에 내부 파라미터를 스케일링해야 합니다.
- 입력 확장이 EasyAR에 의해 구현되는 경우, 내부 파라미터가 매 프레임마다 변경되는지 여부를 명시해야 합니다 (해당 API를 한 번 호출해야 하는지 매 프레임 호출해야 하는지의 차이).
외부 파라미터:
- 헤드셋에서는 실제 데이터를 제공해야 합니다.
- 이는 물리적 카메라의 장치/헤드 포즈 원점에 대한 물리적 오프셋을 표현하는 보정 행렬입니다. 장치의 포즈와 물리적 카메라 포즈가 동일한 경우, 이는 단위 행렬(identity matrix)이어야 합니다.
- Apple Vision Pro에 대응하는 인터페이스는 CameraFrame.Sample.Parameters.extrinsics이며, 그 데이터 정의와 인터페이스에 필요한 데이터 간에 차이가 있음에 유의해야 합니다. EasyAR 내부에서는 변환을 수행한 후 사용합니다.
- Unity에서, 외부 파라미터의 좌표축 시스템 유형은 Unity 좌표축 시스템 또는 EasyAR 좌표축 시스템이어야 합니다. 입력 확장이 EasyAR에 의해 구현되고 다른 좌표축 시스템 정의를 사용하는 경우, 명확한 좌표축 시스템 정의를 제공하거나 Unity 좌표축 시스템 또는 EasyAR 좌표축 시스템으로 변환하는 방법을 제공해야 합니다.
- 헤드셋 장치에는 일반적으로 좌표 원점, 방향, 좌우손 표현 등이 서로 다른 여러 좌표계 정의가 존재합니다. 외부 파라미터는 동일한 좌표계 내에서 계산되어야 하며, 이 인터페이스 데이터는 서로 다른 정의를 가진 두 좌표계 간의 변환 행렬이 아닌, 동일한 좌표계 내의 좌표 변환이 필요합니다.
성능:
- 데이터는 최적의 효율성으로 제공되어야 합니다. 대부분의 구현에서 API 호출은 렌더링 과정에서 발생하므로, 하위 레벨에서 시간이 오래 걸리는 작업이 필요하더라도 API 호출을 차단하지 않거나 합리적인 방식으로 이러한 API를 사용하는 것이 좋습니다.
- 입력 확장이 EasyAR에 의해 구현되는 경우, 시간이 오래 걸리는 모든 API 호출에 대해 설명해야 합니다.
다중 카메라:
- 최소한 하나의 카메라 데이터가 필요합니다. 이 카메라는 RGB 카메라, VST 카메라, 포지셔닝 카메라 등 어떤 것이든 될 수 있습니다. 헤드셋에서 단일 카메라 데이터만 입력하는 경우, 일반적으로 중앙에 있거나 눈 근처에 위치한 RGB 카메라나 VST 카메라를 사용하는 것이 권장됩니다.
- 다중 카메라 사용은 EasyAR 알고리즘의 효과를 향상시킬 수 있습니다. 사용 가능한 모든 카메라의 특정 시점의 카메라 프레임 데이터는 동일한 시간에 동시에 입력되어야 합니다.
다중 카메라 지원은 현재 완전히 지원되지 않습니다. 자세한 내용은 EasyAR에 문의하십시오.
다음 단계
- 이미지 및 장치 모션 데이터 입력 확장 생성
- 이미지 입력 확장 생성
- 헤드셋 확장 패키지 생성
관련 주제
- EasyAR 좌표계
- 이미지 입력 확장 예제 Workflow_FrameSource_ExternalImageStream