command-tracker는 스트리트파이터라는 1대1 격투 게임 영상에서 플레이어의 커맨드 입력을 자동 추출해 주는 서비스입니다.
일반적으로 커맨드가 영상에 포함되지 않은 경우, 녹화된 영상을 보며 수동으로 입력을 추정해야 하며, 이는 초보자에게 높은 진입장벽이 됩니다.
이 서비스는 RTMPose 기반의 관절 추출 모델과 후처리 로직을 활용하여, 플레이어의 동작을 분석하고 이를 커맨드로 변환, 최종적으로 자막 형태로 영상에 삽입해 줍니다. 이로써 초보자들도 원하는 캐릭터의 커맨드를 손쉽게 확인해 볼 수 있습니다.
RTM-Pose는 사람의 관절 위치를 추정해주는 최신 인체 포즈 추정 AI 모델입니다.
웹사이트 | 클라이언트 레포지토리 | 서버 레포지토리
- 사용자가 분석할 유튜브 영상 주소를 입력하고 커맨드를 추출할 부분을 컷 편집할 수 있는 웹 UI 제공합니다.
- 사용자가 영상을 제출하고, 결과를 받을 이메일을 입력하는 인터페이스 제공합니다.
- 주요 기능
- 유튜브 영상 링크 입력 UI
- 이메일 입력 및 제출
- 클라이언트의 요청을 받아 저장하고, 작업 요청을 RabbitMQ로 발송하거나 결과를 수신하여 이메일로 최종 영상을 전송하는 Express API 서버입니다.
- 클라이언트와 AI 서버를 직접 연결하지 않고, 역할을 분담하여 유지보수성과 안정성을 증가. 이를 위한 중계 서버 역할을 합니다.
- 주요 기능
- Youtube 영상 다운로드 처리
- AI 서버로 작업 요청 메시지를 RabbitMQ에 발행
- 추출 완료된 최종 영상의 URL을 받아 이메일로 전송
- RabbitMQ로부터 수신한 작업 요청을 기반으로, RTM-pose로 관절 추출 및 커맨드 인식을 수행하는 Python 서버입니다.
- 고성능 모델을 실행하고 비동기 큐 기반으로 독립된 연산 서버가 필요하여 별도로 분리된 서버입니다.
- 주요 기능
- RTM-pose로 관절 위치 추정
- 관절 위치 정보를 기반으로 커맨드 추정
- 추정 결과를 자막에 담아 최종 영상 URL을 메시지 큐로 전송
영상 속 관절 추정을 하는 작업은 굉장히 오래 걸리는 작업입니다. 웹 요청으로 처리할 때 요청과 응답이 될 때까지 기다려야 할 뿐만 아니라 양측 서버 모두 안정성에 악영향을 끼칠 수 있습니다. 영상 분석 작업을 분리함으로써, 서버의 안정성을 확보했습니다.
AI 서버는 단순히 큐를 소비하고, 결과물을 응답만 하면 되기 때문에, 웹 프레임워크 없이 동작할 수 있습니다. 이에 따라 AI 서버가 가벼워지고 라우팅 처리, HTTP 처리 등을 하지 않고 영상 분석 같은 주 로직에만 집중할 수 있습니다.
사용자가 입력한 유튜브 링크에서 원하는 구간만 잘라 커맨드 추정에 사용하는 기능이 필요했습니다. 유튜브 영상의 길이는 다양하고, 전체 영상을 처리하기에는 자원 낭비가 크기 때문에 컷 편집은 필수였습니다. 처음에는 ffmpeg
를 사용하여 유튜브 스트림을 그대로 pipe 처리하였고, 출력 확장자는 일반적으로 많이 사용하는 .mp4
를 선택했습니다. 그러나 이 방식에서는 영상이 저장되지 않거나, 저장되더라도 영상이 깨지거나 디코딩 오류가 발생하는 문제가 반복되었습니다.
초기에는 스트림 처리 방식 자체에 문제가 있다고 판단하여, 임시 디렉터리에 파일로 저장한 후 편집을 수행해 보았습니다. 이 방식은 안정적으로 동작했지만, 사용자 요청마다 서버에 영상 파일이 남는 문제가 있었습니다. 이에 문제의 근본 원인을 찾기 위해 확장자를 조사하였고, 스트리밍 환경에 적합한 포맷인 .webm
의 존재를 확인했습니다. 실험 결과 .webm
확장자를 사용할 때 pipe 스트리밍 방식에서도 영상이 안정적으로 저장되고 편집되는 것을 확인하였고, 이를 최종 구조로 채택하였습니다.
현재는 Node.js 서버에서 클라이언트로부터 전달받은 시작 점과 종료 점을 기반으로 ffmpeg
명령어를 실행하고, .webm
포맷으로 출력된 편집 영상 파일을 Google Cloud Storage 버킷에 업로드하고 있습니다.
개선해야 할 점은 영상 편집에 대한 문제입니다. 현재 컷 편집에만 수십 초가 소요되며, 이에 따라 사용자에게 응답이 늦어지는 문제가 있습니다. 이를 개선하기 위해서는 해상도를 낮춰야 하지만, 해상도를 낮추는 건 사용자 측면과 AI 영상 분석 성능에 악영향을 끼치기 때문에, 다음과 같이 해결할 계획입니다. 요청과 동시에 성공 응답을 먼저 반환하고, 이후 내부적으로 컷 편집과 분석을 진행하여 UI적으로 해결할 예정입니다.
게임 속 캐릭터의 커맨드를 추정하기 위해서는, 먼저 해당 캐릭터가 어떤 자세를 취하고 있는지를 AI가 인식할 수 있어야 했습니다. 그리고 AI 모델을 활용하기 위해서는, 해당 객체가 사람이라는 전제하에 관절을 추정할 수 있어야 했습니다. 즉, 분석 과정은 객체 식별 → 관절 추정 → 커맨드 분류의 흐름으로 구성됩니다.
하지만 대상이 실제 인물이 아닌 게임 캐릭터였기 때문에 문제가 발생했습니다. 사람으로는 불가능한 과장된 동작을 취하거나, 외형 자체가 일반적인 사람과는 달라서 관절 추정 정확도가 낮아지는 경우가 빈번했습니다.
이를 해결하기 위해 초기에 팀원과 함께 직접 라벨링 및 학습을 수행했고, 약 3,000장의 학습 데이터를 수집해 하나의 캐릭터에 대해 객체 식별이 가능하도록 학습시켰습니다. 이 방식은 외형이 고정된 상태에서는 높은 정확도를 보였지만, 스킨 변경이나 다른 캐릭터에 대해서는 인식률이 저하되었고, 전체 게임 다양성을 고려할 때 확장성에 큰 제약이 있었습니다.
결국 범용성과 유지보수를 고려해, 캐릭터를 좌측/우측으로 단순히 구분하는 구조로 전환하였습니다. 게임이 1:1 구조이기 때문에, 사용자가 분석 요청 시 좌측 캐릭터인지, 우측 캐릭터인지 선택하면 이를 기준으로 후속 AI 분석이 진행됩니다.
관절 추정에는 RTMPose
를 사용했습니다. 해당 모델은 프레임 단위로 2D 관절 좌표(x, y)를 출력하며, 추출된 데이터를 바탕으로 특정 커맨드를 판단하는 후처리 로직을 구현하였습니다.
예를 들어 팔을 뻗는 동작은 어깨–팔꿈치–손목의 각도를 계산하고, 해당 각도가 일정 범위에 들어오면 조건문 기반 분기 처리로 커맨드를 판별하는 구조입니다.
다만 개선이 필요한 부분도 존재합니다. 현재는 좌측/우측 캐릭터를 사용자가 수동으로 선택해야 하며, 플레이 도중 캐릭터의 위치가 바뀔 때는 대응이 어렵습니다. 기술적으로는 프레임 단위로 캐릭터의 위치 변화를 추적하거나, 이전처럼 객체 라벨링을 통한 ID 매칭 로직을 적용하는 방법도 있습니다. 하지만, 이 방식은 개발 자원이 크고, 처리 시간과 정확도가 높지 않다는 점에서 모두 위험이 크기 때문에 실제 서비스에 적용하기에는 부담이 크다고 판단 했습니다. 따라서 현재는 UI에서 사용자가 명확하게 좌/우를 선택하도록 하는 방식으로 문제를 해결하고 있습니다.
또한 커맨드 판별은 각도 기반 조건문 기반으로 처리되며, 캐릭터마다 30개 이상의 동작을 직접 정의해야 하는 구조입니다. 이 영역은 자동화하거나 템플릿화하기 어려운 특성상, 캐릭터가 추가되거나 동작이 바뀔 때마다 직접 커맨드 분기 로직을 추가해 줘야 합니다. 따라서 유지보수 비용은 계속 발생하지만, 그만큼 커맨드 동작의 판별 기준을 정밀하게 조정할 수 있는 유연성도 함께 확보할 수 있습니다.
RTM-Pose는 사람의 관절 위치를 추정해주는 최신 인체 포즈 추정 AI 모델입니다.
커맨드 추정이 완료되면, 캐릭터의 동작과 함께 해당 커맨드를 사용자도 확인할 수 있도록 자막을 생성하고, 이를 영상에 삽입하는 과정을 거칩니다. 이때 자막은 특정 시간 구간에만 표시되는 방식이 아니라, 스택형 자막 방식으로 구현하여 이전 자막 위에 새로운 커맨드가 누적되어 쌓이는 형태로 처리됩니다. 이러한 방식은 1:1 격투 게임의 연습 모드에서 흔히 사용되는 입력 커맨드 표기 형태를 그대로 빌린 것으로, 사용자에게 익숙한 형태로 커맨드를 보여줄 수 있다는 장점이 있습니다.
자막 포맷은 .ass
를 사용하였습니다. 흔히 사용되는 .srt
와 달리 .ass
는 정밀한 자막 위치 제어 및 스타일링이 가능하므로, 스택형 자막처럼 복잡한 자막 구성에 적합하다고 판단했습니다. 최종적으로는 ffmpeg를 사용하여 자막이 삽입된 영상을 렌더링하고, 완성된 영상은 Google Cloud Storage 버킷에 업로드됩니다. 이후 사용자에게는 signed URL을 발급하여, 24시간 동안 영상 결과물을 확인할 수 있도록 구현하였습니다.
현재 구현된 스택형 자막 방식을 사용하면 사용자에게 익숙한 형태로 보여줄 수 있다고 생각했으나, 실제로 확인해 본 결과, 실제 게임 내 커맨드 입력 UI와의 차이로 오히려 불편하게 느껴질 수 있다고 생각했습니다. 자막이 단순 텍스트 형태로 누적되어 쌓이기 때문에 몰입감이 떨어지고, 커맨드 흐름도 깔끔하게 전달되지 않는 한계가 있었습니다. 이를 개선하기 위해 일반적인 자막처럼 표시 구간을 지정하고, 특정 시간 범위에만 자막이 등장하고 사라지는 구간형 자막 방식으로 변경할 계획입니다. 이를 통해 자막이 자연스럽게 나타나며, 사용자 경험도 보다 향상될 것으로 기대하고 있습니다.
-
깃 브랜치 전략
Github Flow 전략을 채택했습니다. Git Flow는 develop, release, hotfix 등 브랜치가 많아서 관리가 복잡하고 작은 팀에서는 오히려 비효율적이라 생각했습니다. 반면 Github Flow는 main 브랜치를 기준으로 병합하기 때문에 빠른 개발 사이클을 가져갈 수 있어 개발 기간을 확보할 수 있다고 생각하여 적합하다고 판단했습니다.
-
PR 규칙
PR 작성 시 이슈 번호를 반드시 포함하고 템플릿을 지켜 작성하였습니다. 내용에는 변경된 내용과 코드 리뷰어가 확인해야 할 부분을 간단히 명시하였습니다. 또한 팀원의 승인이 반드시 있어야 병합할 수 있도록 하여 실수로 인한 병합을 예방하였습니다.
-
협업 시 신경 썼던 부분
제가 생각하는 협업에서 가장 중요한 것은 관계를 원만하게 유지하는 것입니다. 이를 위해 대화할 때는 감정을 최대한 배제하려고 했고, 저도 모르게 가정이 섞인 말투가 나왔을 때는 곧바로 사과드렸습니다. 코드에서는 변수명이 다소 길어지더라도 팀원이 쉽게 이해할 수 있도록 명확하게 작성하려고 했고, 수정이 필요한 경우에는 먼저 팀원에게 공유하고, 확인을 받은 후 진행했습니다. 설명이 필요한 경우에는 관련 링크나 스크린샷 같은 참고자료를 함께 공유하여 소통이 불필요하게 길어지는 것을 방지했습니다.
진행 기간 : 5주
팀원 : 차준우, 조성경 (총 2명)
- 1주차
- 아이디어 선정
- POC 진행 - 캐릭터의 커맨드를 추정하기 위한 관절 데이터 추출 성능 확인
- 2주차
- POC 진행 - 캐릭터의 커맨드를 추정하기 위한 관절 데이터 추출 성능 확인
- 칸반 작성
- 기술 스택 조사
- 3주차
- 프로젝트 환경 세팅
- 공통 컴포넌트 구현
- 영상 편집 구현
- 영상 업로드 구현
- 결과물 확인 링크 메일 전송 구현
- 4주차
- 영상 분석하여 관절 데이터 추출 구현
- Re-ID 성능 테스트
- 동작 학습 데이터 수집 및 AI 기반 커맨드 추출 테스트
- 관절 데이터 기반 커맨드 추출 구현
- 5주차
- 배포
이번 프로젝트를 통해 단순히 기능을 구현하는 것을 넘어, 실제 사용자가 어떤 문제를 겪고 있는지를 정의하고, 그에 맞는 해결책을 설계하는 것이 얼마나 중요한지 체감했습니다. 단순히 동작하는 코드를 작성하는 데서 그치지 않고, 결과물이 사용자에게 어떤 경험을 줄 것인지까지 고민하게 된 계기였습니다.
커맨드 추정을 위해 AI 기반 관절 추정 기능을 도입했을 때, 처음에는 라벨링을 통해 캐릭터를 직접 학습시키는 방식을 시도했습니다. 하지만 캐릭터가 바뀔 때마다 라벨링과 학습을 반복해야 했고, 이에 따라 확장성과 유지보수에 큰 한계가 있었습니다. 이에 캐릭터를 좌측/우측으로 구분하는 구조로 전환하면서, 기술적인 정답만이 아닌 현실적인 상황에 맞춘 구조적 변경이 더 효율적일 수 있다는 것을 깨달았습니다. 이 경험을 통해 운영과 확장성까지 고려한 문제 해결 관점을 넓힐 수 있었습니다.
아쉬웠던 점은, AI를 이용한 커맨드 추정의 정확도에 대한 확신이 부족하여 POC 단계에 너무 많은 시간을 소모했다는 것입니다. 그 결과 설계가 늦어졌고, 개발 기간이 짧아지면서 코드 정리나 UX 적인 세부 사항을 충분히 다듬지 못한 부분이 있었습니다.
보완할 점으로는 커맨드 조건을 더욱 정교하게 정의하여 정확도를 높이는 작업과, 현재 다소 어색한 스택형 자막 UI를 구간형 자막 방식으로 개선하는 작업이 있습니다. 또한 영상 편집이 완료될 때까지 사용자가 기다려야 하는 구조도, 요청 후 내부적으로 처리하고 완료되면 결과만 전달하는 방식으로 전환해 UX를 개선할 필요가 있습니다.