TT Lab
요금제

한국어

시작하기
블로그

블로그

자세와 라켓: RTMPose 의 SimCC, MediaPipe 의 두 단계, RacketVision 의 라켓 5점

상태: 초안 (2026-10-13), 일부 실측 반영. 자세 실험(2026-10-11–12)과 코칭 화면의 속도는 직접 잰 값입니다. RacketVision 은 데이터만 세어 보았고 모델은 돌려 보지 않았습니다(미실측). 논문 수치는 「논문」으로 표시했습니다. 작성 규칙: 실측 데이터가 기본이고, 못 잰 것은 「미실측」으로 표시합니다.

목차

1. 왜 사람과 라켓을 보려 하나

5편에서 자세히 보겠지만, 지금 엔진이 틀리는 가장 큰 이유는 이벤트 추출입니다. 그중에서도 「테이블 위에서 라켓에 맞은 공을 바운드로 읽는」 실수가 많았습니다. 공의 궤적만 보면 둘 다 화면에서 「내려오다 올라가는」 V 자를 그립니다. 엔진은 「바운드는 가로 방향을 유지하고, 타구는 뒤집는다」는 규칙으로 대부분 거르지만 다 거르지는 못합니다.

사람은 이 둘을 쉽게 가릅니다. 공 옆에 라켓이 있고 손목이 휘둘러졌으면 타구입니다. 그래서 자세(사람의 관절 좌표)와 라켓 위치를 보조 신호로 넣으려는 것입니다. 쓰임새는 셋입니다.

신호 쓰고 싶은 곳
손목이 공 곁에 있나 타구와 바운드 가르기
선수의 서브 자세, 서 있는 쪽 누가 서브하나, 랠리 중인가 쉬는 중인가
라켓 면과 공 공이 선수에 가려 안 보일 때 타구 확인

그리고 점수와 별개로, TT Lab 의 자세 코칭 화면이 같은 모델을 씁니다.

2. RTMPose: 좌표를 두 개의 1D 분류로

위에서 아래로(top-down)

RTMPose(arXiv 2303.07399, MMPose, Apache-2.0)는 두 단계입니다. 먼저 사람 검출기(RTMDet)가 사람 상자를 찾고, 그 상자를 잘라 키포인트 모델이 관절 17개를 찾습니다. 사람이 화면 한쪽에 작게 찍혀도 상자를 잘라 키우므로 관절이 또렷해집니다. 연습 영상처럼 빠른 팔이 흐리고 사람이 작은 영상에 강합니다.

SimCC: 2D 지도 대신 1D 벡터 두 개

2편의 공 찾기는 2D 히트맵을 그렸습니다. 관절 17개마다 2D 지도를 그리면 계산이 많고, 지도의 해상도가 곧 위치의 해상도가 됩니다. 정밀하게 하려면 지도를 키워야 하고, 그만큼 비쌉니다.

SimCC(arXiv 2107.03332)는 질문을 바꿉니다. 「이 관절의 x 좌표는 몇 번 칸인가」, 「y 좌표는 몇 번 칸인가」를 각각 분류 문제로 풉니다. 관절마다 길이 W·k 와 H·k 인 1D 벡터 두 개를 내고, 각 벡터에서 가장 높은 칸을 고릅니다. k 는 화소 하나를 몇 칸으로 쪼갤지이고(MMPose 의 simcc_split_ratio, 기본 2.0), k = 2 면 반 화소 해상도를 얻습니다. 2D 지도를 키우지 않고도 화소보다 정밀한 위치를 얻는 셈입니다. 2편의 TTNet 이 공 위치를 x·y 1D 벡터 두 개로 낸 것과 같은 생각입니다.

디코딩은 정말 단순합니다.

# open-mmlab/mmpose mmpose/codecs/utils/post_processing.py get_simcc_maximum() 에서(Apache-2.0)
x_locs = np.argmax(simcc_x, axis=1)
y_locs = np.argmax(simcc_y, axis=1)
locs = np.stack((x_locs, y_locs), axis=-1).astype(np.float32)
max_val_x = np.amax(simcc_x, axis=1)
max_val_y = np.amax(simcc_y, axis=1)
mask = max_val_x > max_val_y
max_val_x[mask] = max_val_y[mask]          # 신뢰도 = 두 축 최댓값 중 작은 쪽
vals = max_val_x
locs[vals <= 0.] = -1

그다음 keypoints /= simcc_split_ratio 로 칸 번호를 화소로 되돌립니다. 신뢰도를 두 축 중 작은 쪽으로 잡는 것이 눈여겨볼 점입니다. x 는 확실한데 y 가 애매하면 그 관절은 애매한 것입니다.

수치

RTMPose-m 은 1,359만 파라미터, 1.93 GFLOPs, COCO AP 74.9 입니다. 지연은 데스크톱 CPU(ONNX Runtime) 11.06ms, 데스크톱급 GPU(TensorRT FP16) 2.29ms 입니다(공식 README, 256×192 입력). 논문 초록의 75.8 AP 는 학습 데이터가 다른 판의 값이라, 어느 판을 말하는지 맞춰 인용해야 합니다.

3. MediaPipe Pose: 찾기와 따라가기를 나눈다

MediaPipe Pose Landmarker(BlazePose, arXiv 2006.10204, 코드 Apache-2.0)는 휴대폰 브라우저에서 도는 것을 목표로 만든 모델입니다. 생각은 이렇습니다.

  1. 찾기(detector): 처음 한 번, 또는 사람을 놓쳤을 때만 돕니다. 얼굴 검출기를 사람 검출의 대리로 쓰고, 골반 중심과 몸을 감싸는 원의 반지름·기울기를 함께 예측해 사람 자리를 정합니다.
  2. 따라가기(tracker): 매 프레임 돕니다. 관절 33개와 「사람이 아직 있나」, 그리고 다음 프레임에서 볼 영역을 함께 예측합니다. 사람이 없다고 하면 다음 프레임에 찾기를 다시 돌립니다.

무거운 찾기를 매 프레임 돌리지 않는 것이 속도의 비결입니다. 화면 좌표 외에 골반을 원점으로 한 미터 단위 3D 좌표(world landmarks)도 줍니다.

라이선스 주의: 코드는 Apache-2.0 이지만, 모델 파일에는 별도의 모델 카드가 붙어 있습니다. 그 카드의 이용 조건은 우리가 아직 확인하지 못했습니다(미확인).

4. RacketVision: 라켓을 다섯 점으로

RacketVision(arXiv 2511.17045, AAAI 2026, 코드·데이터 카드 MIT)은 탁구·테니스·배드민턴 중계 영상에 공 위치와 라켓 상자 + 다섯 점을 단 데이터셋과 기준 모델입니다. 다섯 점은 위(top)·아래(bottom)·손잡이(handle)·왼쪽(left)·오른쪽(right) 입니다. 위·아래·왼쪽·오른쪽 네 점이 라켓 면의 윤곽을, 손잡이가 방향을 정합니다. 면이 보이는 각도와 방향이 있으면 「공이 라켓 면 근처에 있나」를 물을 수 있습니다.

탁구 부분을 직접 세어 보니(2026-10-13)

받아 둔 탁구 부분의 주석 파일을 읽기 전용으로 세었습니다(원자료와 스크립트는 7편 참고).

항목 값
클립 / 경기 780 / 50
프레임 / 길이 170,027 / 3,878초. 클립 길이 중앙 5.0초
해상도 / fps 모두 1920×1080. fps 는 25(209클립)·60(201)·50(191)·30(112)·59.94(67)로 섞여 있다
주석이 달린 프레임 16,961(공 CSV 19,495행 중 「보임」과 같은 수). 프레임 간격 중앙 10
라켓이 있는 주석 프레임 / 라켓 수 6,648 / 8,060(한 프레임에 0개 12,847, 1개 5,409, 2개 1,084, 3개 이상 155)
라켓 하나에 보이는 점 수 4점 6,187(77%), 5점 1,400, 3점 467
점별로 보이는 비율 위 99.6%, 왼쪽 99.7%, 오른쪽 99.2%, 손잡이 73.7%, 아래 39.1%
라켓 상자 넓이 중앙 1,876px²(약 43×43px), 10% 883, 90% 4,665

다섯 점이라고 하지만 실제로는 넷만 보이는 라켓이 대부분입니다. 중계 시점에서 라켓의 아래쪽 끝은 손에 가리거나 면에 겹치기 때문으로 보입니다. 논문도 왼쪽·오른쪽 점의 정확도(PCK@0.2 약 65–80%)가 위·아래 같은 구조 점(92% 넘음)보다 낮다고 보고했습니다. 1080p 에서 라켓 상자가 한 변 43px 남짓이니, 휴대폰 옆면 영상에서 다섯 점을 다 찾기는 더 어려울 것입니다(추정).

논문의 다른 결과 하나가 설계에 중요합니다. 공의 다음 궤적을 예측할 때 라켓 특징을 그냥 이어 붙이면 공만 쓸 때보다 나빠지고, 교차 어텐션으로 합쳐야 나아졌습니다(탁구, 과거 80프레임 → 미래 20프레임, ADE/FDE 113.9/184.3 → 101.3/161.3px, 논문). 신호를 더한다고 저절로 좋아지지 않는다는, 아래 우리 실측과 같은 결론입니다.

5. 우리가 실제로 쓴 곳과 결과

점수 엔진: 지우면 손해, 표시만 하면 이득(2026-10-11–12)

사람 검출기(RTMDet)의 ONNX 파일은 그래프 안의 NMS 연산을 OpenCV DNN 이 읽지 못했고, 실험 이미지에 ONNX Runtime 도 없었습니다. 그래서 사람 상자 대신 공을 가운데 둔 540×720 상자를 RTMPose-m 에 넣어 「공 곁에 손목이 있나」만 물었습니다. CPU(OpenCV DNN)로 상자 하나에 74ms(다른 작업과 나눠 쓴 CPU, 중앙값)라, 엔진이 낸 바운드 후보 2,499개 프레임에만 돌렸습니다.

먼저 학습 5경기에서 손목이 공을 가를 수 있는지 보았습니다. 바운드 후보 1,982개는 정답 바운드 1,481개, 타구를 바운드로 읽은 가짜 27개, 그 밖의 가짜 474개였습니다. 「손목 점수 0.5 이상, 손목–공 60px 이내」를 지우면 정답 10개, 타구 가짜 5개, 기타 가짜 24개가 지워졌습니다. 정답과 가짜를 거의 가르지 못했습니다. 엔진이 이미 타구 가짜 대부분을 걸러 남은 것이 27개뿐인 탓도 있습니다.

실제 12편 275랠리의 결과입니다.

규칙 승자 맞음 확인 없이 틀림 확인 필요
기준(자세 없음) 93.1% 10 41.1%
자세로 바운드를 지움, 60px 92.0% 11 42.9%
자세로 바운드를 지움, 90px 87.6% 12 44.0%
자세는 「확인 필요」로만, 60 / 90 / 120px 93.1% 10 / 9 / 6 44.0 / 49.1 / 58.2%

결론은 두 줄입니다. 지금 수준의 자세 신호로 바운드를 지우면 손해입니다. 판정을 바꾸지 않고 사람에게 다시 보라고 표시만 하면, 확인 없이 틀린 판정 4건을 사람 앞으로 끌어옵니다. 대신 확인 필요가 17%p 늘어납니다. 그래서 엔진은 「자세는 바운드를 지우지 않는다(확인 필요로만)」를 규칙으로 두었습니다. 사람 검출기를 제대로 붙인 판은 미실측입니다.

자세 코칭: 브라우저는 MediaPipe, 서버는 RTMPose

갈래 모델 왜 실측
실시간 골격(브라우저 안) MediaPipe Pose Landmarker 영상이 브라우저 밖으로 나가지 않는다. 33점과 미터 단위 3D 좌표를 준다. T3Set 데이터셋의 자세 자료가 같은 MediaPipe 3D 좌표라 같은 잣대로 비교할 수 있다 노트북의 헤드리스 Chrome(GPU 대리자) 프레임당 12–15ms. 실제 휴대폰은 미실측
정밀 분석(서버) RTMDet-m + RTMPose-m(ONNX Runtime) 흐리고 작은 사람에 강한 top-down. mmcv 빌드가 필요 없고, ONNX 는 피클이 아니라 가중치가 코드를 실행할 길이 없다 서버 GPU(나눠 쓸 때) 사람 찾기 50–98ms, 키포인트 6–10ms/프레임. 사람 찾기를 5프레임마다로 줄여 30초 클립 21–36초

6. 정리: 무엇을 어디에

모델 원리 한 줄 지금 쓰는 곳 점수 엔진에서
RTMPose 사람 상자 → 관절마다 x·y 1D 분류(SimCC) 코칭 정밀 분석, 자세 실험 「확인 필요」 신호로만
MediaPipe Pose 가끔 찾고 매번 따라가기, 33점 + 3D 코칭 실시간 골격 쓰지 않음
RacketVision 라켓 5점 라켓 상자 + 다섯 점, 공과 교차 어텐션 데이터만 받아 셈 미실측. 공이 가려진 타구 확인 후보

공·자세·라켓을 한꺼번에 받아 「누가 언제 쳤나」를 내는 모델은 탁구에도 나오고 있습니다(예: 공·탁구대·상체 키포인트로 라켓 접촉 시각을 내는 EventNet, arXiv 2610.08286, 중계 데이터 LATTE-MV 에서 ±3프레임 F1 91.16, 논문). 이런 모델을 우리 옆면 영상에서 재 보는 것이 다음 실험 후보입니다(진행 중).

티티 한마디. 손목이 공 옆에 있다고 바로 「타구!」라고 외치면 안 돼요. 그럴 땐 「한번 봐 주세요」라고 부탁하는 게 점수를 지키는 길이었어요.

참고

로그인하면 좋아요를 누를 수 있습니다

댓글

아직 댓글이 없습니다.

로그인하면 댓글을 쓸 수 있습니다