TT Lab
요금제

한국어

시작하기
블로그

블로그

사람 자세 1: 히트맵으로 관절 찾기 — OpenPose 의 PAF, HRNet, 그리고 위에서 아래로 대 아래에서 위로

상태: 초안 (2026-10-13). 논문 수치는 원문을 열어 조건과 함께 확인했습니다. 직접 해 본 것은 노트북 CPU 의 numpy 예제(code/07_heatmap_decode.py, 10초 안팎)입니다. TT Score 에서 자세 모델을 실제로 쓴 결과는 TT Score 모델 해부 4편의 실측을 인용했습니다. 시리즈 「비전 모델 읽기 2」 7편. 다음 편: 사람 자세 2. HRNet 의 구조(여러 해상도를 끝까지 나란히 두기) 자체는 비전 모델 읽기 1이 다룹니다. 이 편은 「관절을 어떻게 학습시키고 꺼내나」에 집중합니다.

사람 자세 1: 히트맵으로 관절 찾기

목차

1. 직관: 좌표 대신 지도

자세 추정(pose estimation)은 그림 속 사람의 관절(코, 어깨, 팔꿈치, 손목, 엉덩이, 무릎, 발목 …) 위치를 찾는 일입니다. COCO 데이터셋 기준으로 사람마다 17점입니다.

가장 곧은 방법은 망이 좌표 34개(17점 × x, y)를 바로 내게 하는 것입니다. 2014년의 DeepPose 가 그렇게 했습니다. 사람 상자로 정규화한 좌표를 제곱 오차로 회귀하고, 예측 둘레를 다시 잘라 한 번 더 고치는 단계를 두었습니다(논문).

같은 해 Tompson 외는 다른 길을 냈습니다. 관절마다 그림과 같은 모양의 지도(히트맵) 를 그리게 하고, 정답도 관절 자리에 작은 가우시안 언덕을 그린 지도로 만들어 화소마다 제곱 오차로 비교했습니다. 그리고 좌표를 바로 회귀하는 방식은 아주 정밀한 영역에서 약하다고 지적했습니다(논문). 이후 10년 가까이 자세 추정의 기본은 히트맵이었습니다.

히트맵이 강한 이유는 TT Score 모델 해부 2편에서 공 찾기에 대해 설명한 것과 같습니다. 화소마다 학습 신호가 생기고, 「여기는 아니다」가 자연스럽게 표현되며, 후보가 여럿이어도 됩니다. 사람 자세에는 하나가 더 있습니다. 합성곱은 그림의 위치 관계를 그대로 지키므로, 위치를 위치로 내는 출력이 망의 구조와 잘 맞습니다.

2. 그림: 여러 사람을 다루는 두 길

사람부터 찾나, 관절부터 찾나 위에서 아래로(top-down) 사람 검출기 상자 n개 상자마다 잘라서 한 사람 모델 × n 정확, 시간 ∝ 사람 수 HRNet · RTMPose 아래에서 위로(bottom-up) 그림 전체 한 번만 모든 관절 히트맵 + 묶기 단서(PAF) 사람별로 짝 맞추기 OpenPose 등 PAF(팔다리 친밀도 장) 팔뚝 위 화소마다 「팔꿈치 → 손목」 방향의 단위 벡터 팔꿈치 손목 A 손목 B 후보 선분을 따라 「PAF · 선분 방향」 을 적분해 점수를 낸다 팔꿈치–손목 A 는 높고, B 는 낮다 → A 와 잇는다 팔다리마다 따로 짝 맞추기(헝가리안 알고리즘)
그림: 위에서 아래로(사람 먼저)와 아래에서 위로(관절 먼저), 그리고 PAF 로 관절 묶기

화면에 사람이 여럿이면 문제가 하나 더 생깁니다. 「이 손목은 누구의 손목인가.」

3. OpenPose: 팔다리 방향을 지도로 그린다

OpenPose(Cao 외, CVPR 2017)의 묶는 단서가 PAF(Part Affinity Field, 팔다리 친밀도 장) 입니다. 팔뚝 같은 팔다리마다 2채널 지도를 하나 그립니다. 팔뚝 위에 있는 화소에는 「팔꿈치에서 손목 방향」의 단위 벡터를, 그 밖의 화소에는 0을 넣습니다. 사람이 겹치면 벡터를 평균합니다.

시험 때는 이렇게 묶습니다.

  1. 관절 히트맵의 봉우리에서 팔꿈치 후보들과 손목 후보들을 뽑습니다.
  2. 팔꿈치 하나와 손목 하나를 잇는 선분마다, 선분 위를 따라 「PAF 벡터 · 선분 방향」을 적분해 점수를 냅니다. 같은 사람의 팔이면 PAF 가 선분과 같은 방향이라 점수가 큽니다.
  3. 전체를 한꺼번에 푸는 일은 너무 어려워서(NP-hard), 팔다리마다 따로 이분 짝 맞추기(헝가리안 알고리즘)로 풀고 이어 붙입니다(논문).

학습은 단순합니다. 관절 히트맵과 PAF 두 갈래를 여러 단계에 걸쳐 고쳐 가며 내고, 단계마다 정답 지도와의 제곱 오차를 겁니다(중간 감독). 라벨이 없는 사람이 있는 영역은 손실에서 가립니다. 라벨이 없다고 「관절이 없다」고 가르치면 안 되니까요.

속도 이야기도 흥미롭습니다. 사람 19명이 나오는 영상에서 노트북용 GPU 로 8.8fps 였고(368×654 입력), 사람 9명일 때 묶는 단계는 0.58ms, 망은 99.6ms 였습니다(논문). 망은 한 번이고 묶기는 아주 싸다는 bottom-up 의 장점이 숫자로 보입니다.

4. 어떻게 학습시키나: 가우시안 정답과 OKS

위에서 아래로의 표준형: SimpleBaseline 과 HRNet

SimpleBaseline(2018)은 이름처럼 단순합니다. ResNet 뒤에 디컨볼루션 층 3개를 붙여 입력 256×192 에서 64×48 히트맵(¼ 해상도)을 냅니다. HRNet(2019)은 해상도를 줄였다 키우는 대신 높은 해상도 갈래를 끝까지 유지하며 여러 해상도 갈래를 계속 섞습니다(구조는 시리즈 1에서).

학습은 둘 다 같습니다.

정답 히트맵 Hⱼ(p) = exp(−‖p − 관절 j 의 위치‖² / (2σ²))     (히트맵 칸 단위)
L = Σⱼ Σ_p (예측 Ĥⱼ(p) − Hⱼ(p))²                              (화소마다 제곱 오차)

HRNet 논문 본문은 σ 를 1화소로 적었습니다(공식 코드의 설정값은 확인하지 않았습니다). 증강은 회전, 크기 0.65–1.35배, 좌우 뒤집기(왼쪽·오른쪽 관절 라벨도 바꿔야 합니다), 상체·하체만 남기기였습니다(논문).

평가: OKS 와 AP

자세는 「맞았다/틀렸다」를 정하는 기준이 필요합니다. COCO 는 OKS(Object Keypoint Similarity) 를 씁니다.

OKS = 관절들에 대한 평균 exp( −d² / (2 · s² · (2σᵢ)²) )
      d = 예측과 정답의 거리, s² = 사람의 면적, σᵢ = 관절마다 정한 상수

σᵢ 는 사람들이 그 관절을 얼마나 일정하게 찍는지에서 정한 값입니다. 손목(0.062)처럼 위치가 분명한 관절은 작고, 엉덩이(0.107)처럼 옷에 가려 애매한 관절은 큽니다. 같은 거리 오차라도 손목은 더 크게 깎입니다. AP 는 OKS 문턱을 0.50 부터 0.95 까지 바꿔 가며 잰 평균 정밀도를 다시 평균한 것입니다.

5. 직접 해 보기: 히트맵에서 좌표 꺼내기

히트맵을 ¼ 해상도로 그리면 칸 하나가 입력 4화소입니다. 가장 밝은 칸(argmax)을 고르면 그것만으로 최대 2화소 남짓의 오차가 생깁니다. 이를 줄이는 관행이 둘 있습니다.

code/07_heatmap_decode.py 로 셋을 비교했습니다. 참 위치를 소수점까지 무작위로 3,000번 두고, 그 자리에 가우시안을 그린 완벽한 예측과 잡음(표준편차 0.05)을 섞은 예측을 디코딩했습니다(입력 화소 단위의 평균 오차, code/07_heatmap_decode.out.txt).

히트맵(칸 = 입력 몇 화소) σ 잡음 argmax ¼ 칸 밀기 DARK
64×48(4화소) 1 없음 1.52 0.76 0.00
64×48(4화소) 1 0.05 1.58 0.85 0.20
64×48(4화소) 2 0.05 1.97 1.29 0.21
32×24(8화소) 1 0.05 3.16 1.67 0.41
32×24(8화소) 2 0.05 4.03 2.64 0.41

같은 히트맵에서 디코딩만 바꿔도 오차가 1.5화소에서 0.2화소까지 달라집니다. 칸이 거칠수록(8화소) 차이가 더 커집니다. DARK 의 0.00 은 완벽한 가우시안이라 테일러 전개가 정확히 맞기 때문이고, 실제 망의 출력은 가우시안이 아니라서 이렇게 좋지는 않습니다.

이 오차가 점수에 얼마나 중요한지 OKS 로 환산해 봤습니다(사람 면적을 상자 256×192 의 절반으로 가정).

오차  2화소: 손목 0.995 · 엉덩이 0.998
오차  4화소: 손목 0.979 · 엉덩이 0.993
오차  8화소: 손목 0.919 · 엉덩이 0.972

OKS 0.95 문턱(AP 의 가장 엄한 칸)에서는 손목 오차 4화소와 8화소가 「맞음」과 「틀림」으로 갈립니다. 몇 화소의 디코딩 차이가 AP 몇 점으로 나타나는 이유입니다.

6. 논문 수치

모두 COCO 의 사람 17관절, OKS 기반 AP 입니다. 위에서 아래로 방식은 사람 상자의 품질에 따라 결과가 달라지므로 검출기의 AP 도 함께 적습니다.

모델 AP 조건(논문)
OpenPose(bottom-up) test-dev 61.8, 저널판 64.2 2016년 COCO 대회. 중간 크기 사람에서 top-down 보다 약함
Associative Embedding(bottom-up) test-dev 65.5 관절마다 「누구 것인지」 를 나타내는 꼬리표 값을 함께 냄, 다중 크기 시험
SimpleBaseline ResNet-152 test-dev 73.7 384×288, 사람 검출기 AP 60.9
HRNet-W32 / W48 val 74.4 / 76.3 256×192 / 384×288. W32 를 ImageNet 사전학습 없이 학습하면 73.4
HRNet-W48 test-dev 75.5, 외부 데이터 추가 77.0 384×288
HRNet-W32 + DARK val 61.2 → 66.9 → 70.7 128×96 입력. 밀기 없음 → ¼ 칸 밀기 → DARK 전체
HRNet-W32 + DARK val 74.4 → 75.6 256×192 입력
HigherHRNet-W48(bottom-up) test-dev 70.5 640px, 다중 크기. 히트맵을 ½ 해상도까지 키워 작은 사람에 대응

두 가지가 보입니다.

7. 한계

8. 우리 프로젝트와의 연결

티티 한마디. 히트맵에서 가장 밝은 칸만 고르면, 칸이 4화소일 때 평균 1.5화소쯤 틀려요. 「둘째로 밝은 쪽으로 4분의 1칸」이라는 작은 요령 하나로 반이 줄고, 그게 AP 5점이었어요. 작은 요령이 큰 차이를 만드는 곳이에요.

참고 문헌

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

댓글

아직 댓글이 없습니다.

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