쇼츠 c3086822: 관측 그래프 단절과 방향 관측

2026-10-23 조사. 개발 기준 52a31b5, 보고된 사이트 실행 a47140754d94c4133be2ea15688fa65f21befb81의 세션 창 이동 코드를 대조했다. TypeShade는 기존 d36ac5027356b96e87a9ad900dfd8e6ea4ab55dc를 유지한다. GitHub에서 connected observation graph, infinity를 검색했을 때 일치하는 이슈/PR은 없었다. 외부 등록, 머지, 배포는 포함하지 않는다.

실패 근거

제공된 RGB 영상은 H.264, 1080 × 1920, 60 fps, 비디오 트랙 41초다. 기록 20261023125519351-c3086822는 360 × 640에서 4 fps로 분석하고, 32개 카메라·2,068개 점·8,703개 관측을 보고한 뒤 다음 추가에서 중단됐다.

GPU BA requires one connected observation graph
operation: bundle #133
last submitted kernel: triangulateTracks
input frame: 124 (31.0 seconds); keyframe 33

마지막 커널은 triangulateTracks이지만 실패 원인은 BA의 호스트 연결성 검사다. 기록에 장치 손실이나 GPU 오류 이벤트는 없다. 원래 실행은 NVIDIA/Turing, fallbackAdapter=false로 보고됐고 로컬 재생은 Google/SwiftShader 소프트웨어 WebGPU다. 두 환경의 시간으로 속도 개선을 주장하지 않는다.

저장된 부분 지도 JSON도 읽어 기록의 SHA-256 43cc1bed56b18f36739b623ef6e46958a9b92816ae36a376df565ff300b562d7와 대조했다. 원본 영상, 프레임, 다운로드한 지도와 클라이언트 기록은 저장소에 추가하지 않는다.

부분 지도는 이미 한 카메라에 3D 관측이 없었다. 세션과 같은 순서로 다음 창을 계산하면 기준 카메라는 100/112로 이동하고 남은 29개 기존 카메라·1,489개 점의 관측 그래프는 8개 성분이 된다. 4개는 점이 있는 성분, 4개는 관측점 없는 단독 카메라다. 오래된 관측 삭제와 재검증은 연결성을 보존하지 않는다.

이 재현은 저장된 지도에서 창을 이동시킨 직후의 BA 입력 검사다. 33번째 프레임의 RGB 특징점·매칭·재검증·PnP까지 정확히 재생한 결과는 아니다.

수정과 기본 동작

src/reconstruction/local-bundle.ts::planConnectedBundles를 CPU mapper, scene mapper, 같은 요청 프로토콜의 GPU mapper에 연결했다. 기존 BA와 수학 구현을 재사용한다.

  • 연결된 입력은 원래 문제와 옵션을 그대로 전달한다.
  • 기존 지도에서 관측만 분리되면 성분별로 BA를 실행한다. 성분마다 기존 카메라 자세를 최소 두 개 고정해 좌표계를 유지한다. 새 정렬이나 공간 연결을 추정하지 않는다.
  • 로컬 BA는 원래 고정 경계에서 비영 기준선을 확보해야 한다. 제약이 부족한 성분과 관측점 없는 카메라는 보존하고 최적화를 보류한다.
  • 분리된 성분마다 공유 초점거리가 따로 바뀌지 않도록 해당 패스의 초점거리 정련은 보류한다.
  • diagnostics.bundlePartitions에 components, fixedViewIds, deferredViewIds, sharedFocalDeferred를 기록한다. 직접 호출하는 bundleAdjust/bundleAdjustGpu는 단절된 입력을 계속 거부한다.

오류 수정으로 기본 적용한다. 선택 사항인 자세 정련과 조건부 깊이 제한의 기본값은 유지한다. 고정 자세는 이전 추정에 조건을 두는 것이며 그 자세나 성분 간 배치의 정확성을 새로 검증하지 않는다. 고립된 카메라에 현재 3D 지지가 있다고 해석하면 안 된다.

같은 관측 집합으로 재생하면 기존 BA 거부 → 4개 성분 BA 완료, 4개 카메라 보류다. 고정 자세와 관측 소속을 보존했고 활성 버퍼가 0으로 돌아왔다. 재생 수치의 잔차 감소는 최적화 확인이며 정답 기하 정확도 증거가 아니다.

npm run build
TYPESHADE_CHROMIUM=/usr/bin/chromium node scripts/replay-window-bundle.mjs \
  --input=/private/typecv-reconstruction.json --next-id=124 --output=/tmp/window-replay.json
node --test tests/bundle-partitions.test.ts tests/direction-only-observations.test.ts
TYPESHADE_CHROMIUM=/usr/bin/chromium node --test tests/typeshade/bundle-partitions-webgpu.test.mjs

실행한 검증

아래 개수와 TODO는 당시 변경의 실행 기록이다. 후속 검증과 실험 옵션의 현재 범위는 유한/방향 분리에 별도로 기록한다.

  • 전체 코어 290개 중 289개 통과, 아래 혼합 관측 목표 1개 TODO. 이를 통과한 기능으로 세지 않는다.
  • 영향받는 TypeShade CPU 검사 9개 통과. 실제 WGSL을 실행하는 SwiftShader 분할 BA 검사 통과.
  • 타입 검사, 포맷 검사, 코어/GPU 빌드 통과. 사이트 85페이지 빌드 통과.
  • 원래 작업 디렉터리의 변경 파일 25개는 SHA-256 대조로 보존했다.

원본 RGB도 로컬 Lab 워커에서 자동 초점거리, SIFT 첫 옥타브 -1, guided matching, phase gate, 4 fps, 360 × 640으로 다시 실행했다. 마스크·정답 포즈·정답 깊이는 입력하지 않았다. 소프트웨어 WebGPU에서 20분 실행 제한에 도달했다. 마지막 완료는 26.0초의 입력 104, 28번째 키프레임 요청이며 카메라 27개가 등록됐다고 보고했다. 최종 지도와 기하 정확도는 검증하지 못했고, 원래 실패한 33번째 키프레임에도 도달하지 못했다. 부분 실행 기록을 전체 영상 성공이나 원래 GPU 대비 성능 개선으로 해석하면 안 된다. CPU 검사 일부가 이 실행과 겹쳤다.

품질 한계

저장된 관측 중 5,825/8,703개(66.9%)가 고정 제목과 검은 배경이 있는 상단 1/4에 있다. 수동 확인한 영역 통계이며 자동 분류 결과가 아니다. 등록 수와 재투영 오차만으로 배경 구조의 정확도를 판정할 수 없다. 이번 변경은 제목/HUD 자동 검출, 플레이어/무기 운동 분리, 편집 크롭 보정, 조준 화각 변화, 컷 연결을 구현하지 않는다. 기존 cameraObservationMasks로 지정한 관측은 분리할 수 있지만 이 실행에 자동 마스크가 사용된 것은 아니다.

무한원점은 관측 모델의 문제

동차 좌표의 점을 [d, ρ]로 쓰면 투영은 π(K (R d + ρ t))다. ρ = 0이면 병진항이 사라져 방향/회전만 제약한다. 거대한 유한 XYZ를 넣는 방식으로 대체하지 않는다. 영상만으로는 아주 먼 유한점과 무한원점을 구별하지 못할 수도 있다.

화면에 고정된 HUD는 카메라 좌표에서 고정된 픽셀이다. 월드 방향이 고정된 무한원점은 카메라 회전에 따라 영상에서 움직여야 한다. 무시차라는 이유만으로 HUD까지 무한원 배경으로 채택하면 안 되며, 다른 기하 관측으로 추정한 회전과의 일치도 검증해야 한다.

현재는 미삼각측량 2D 트랙과 보정된 회전 가설을 유지한다. 무한원점을 BA의 방향 요인으로 사용하는 구현은 없다. 회전 가설은 시드 부적격 쌍에서 생성하고 지도 PnP는 유한 XYZ를 사용한다. 자동 초점거리 탐색에서는 보정된 회전 추적이 기본 비활성이다.

tests/direction-only-observations.test.ts는 알려진 K와 대응관계를 사용하는 기하 검증이다.

조건 확인 결과
카메라는 이동하지만 모든 대응이 방향만 따름 CPU/scene 초기화 보류, 보정 모드에서 방향 가설과 깊이 미확정 60트랙 유지
특징점 없는 입력 카메라/깊이를 채우지 않고 보류
유한점 60개 + 무한원 방향 60개 당시 초기화 보류를 재현. 후속 유한/방향 분리 실험 옵션에서 이 회귀 목표를 구현·검증

마지막 사례의 수정 전 CPU src/sfm/two-view.ts::recoverTwoViewGeometry와 GPU src/gpu/recovery.shade.ts::chooseTwoViewPose는 모든 E 인라이어 중 60%에 양의 유한 깊이를 요구한다. 120개 중 유한점 60개만 있어도 잘못된 대응이라는 뜻은 아니다. 회전 가설의 기본 최소 지지 비율 0.6도 방향 절반을 따로 보존하지 못한다.

후속 유한/방향 분리는 현재 자세에서의 양방향 회전 전이 픽셀 오차로 깊이 보류 관측을 분리한다. 전자에는 깊이 부호·최소 개수·시차·재투영 검사를 유지하고 후자는 2D 트랙으로 보존한다. 60% 상수 자체를 낮추지 않았다. 큰 잡음이나 잘못된 보정에서의 오확정과 방향 요인을 사용하는 BA는 이 후속 단계 이후에도 남는 조건이다.

작업 순서는 (1) 유한/방향 관측의 분리와 자세 후보 검증, (2) 병진 자코비안이 0인 방향 요인의 BA 연결, (3) 재관측에서 역깊이를 다시 평가하는 순서로 나눈다. 기하 벤치마크는 유한점 60개에 방향 관측 0/30/60/180개를 더하고, 노이즈 0/0.2/1 px와 K의 알려짐/추정을 분리한다. 순수 회전, 실제 병진, 아주 먼 유한점, 틀린 매칭, 화면 고정 HUD에서 미확정 상태의 오확정 비율과 회전·깊이 오차를 CPU/GPU 양쪽에서 비교해야 한다.