이 문서는 카카오 포즈(Pose) API 구현 방법을 안내합니다.
포즈 API는 SDK를 지원하지 않으며 REST API 방식으로 구현할 수 있습니다.
이 문서에 포함된 기능 일부는 [도구] > [REST API 테스트]를 통해 사용해 볼 수 있습니다.
POST /pose HTTP/1.1
Host: cv-api.kakaobrain.com
Authorization: KakaoAK ${REST_API_KEY}
이미지 분석하기 API는 하나의 이미지 내에서 사람들을 찾아 이미지에서 사람을 인식한 후, 사람의 코, 눈, 귀, 어깨, 팔꿈치, 손목, 골반, 무릎, 발목 총 17개의 키 포인트를 추출하여 사람의 자세(Pose)를 분석합니다.
요청 헤더에 REST API키를 담아 POST
로 이미지 분석을 요청합니다. 이미지 요청 시 이미지 파일(file)을 업로드 하거나 또는 이미지 URL(image_url)을 지정할 수 있습니다.
요청이 성공하면 응답 바디에 검출된 각 키 포인트의 좌표와 신뢰도가 JSON
객체(Person[])로 반환됩니다. 이미지에 사람이 여러 명 있을 경우, 검출된 사람들의 키 포인트 정보 값은 Person 객체의 목록으로 반환됩니다.
Name | Description | Required |
---|---|---|
Authorization | REST API 키 [내 애플리케이션] > [앱 키]에서 확인 가능 |
O |
Name | Type | Description | Required |
---|---|---|---|
image_url | String |
이미지 URL | O* |
file | Binary |
처리할 이미지 파일 | O* |
* 조건부: image_url / file 중 하나 필수
- file에 업로드되는 이미지와 image_url에 지정되는 이미지는 JPEG, PNG, HEIC, WebP 포맷만 지원합니다. - 업로드 할 수 있는 이미지의 최대 용량은 2MB 입니다. - 이미지의 가로와 세로 길이는 긴 변을 기준으로 최대 2048 pixel, 짧은 변을 기준으로 최소 320 pixel 이어야 합니다. - 이미지의 권장 비율은 가로:세로 기준 16:9 ~ 9:16 입니다. - file을 업로드하는 경우, Content-Type을 multipart/form-data로 요청합니다. - image_url로 호출하는 경우, Content-Type을 application/x-www-form-urlencoded로 요청합니다.
Name | Type | Description |
---|---|---|
area | Float |
키 포인트를 모두 포함하는 바운딩 박스(bounding box)의 넓이 |
bbox | Float[] |
키 포인트 중 가장 위쪽에 있는 키 포인트의 좌표(x,y)와 바운딩 박스의 너비(w)와 높이(h) [x, y, w, h] |
category_id | Int |
1 로 고정 1: Person |
keypoints | Float[] |
이미지에서 검출된 17개의 키 포인트의 좌표(x, y)와 정확도(score) [x_1, y_1, score_1, x_2, y_2, score_2, ..., x_17, y_17, score_17] x, y, score 값 뒤에 표기한 1부터 17까지의 키 포인트 ID는 사람의 각 신체 부위를 나타냄 (아래 keypoints 항목 참고) 예: [코의 x 좌표, 코의 y 좌표, 코의 키 포인트에 대한 신뢰도, 왼쪽 눈의 x 좌표, 왼쪽 눈의 y 좌표, 왼쪽 눈의 키 포인트에 대한 신뢰도, …, 오른쪽 발목의 x 좌표, 오른쪽 발목의 y 좌표, 오른쪽 발목의 키 포인트에 대한 신뢰도] |
score | Float |
키 포인트 데이터에 대한 신뢰도, 0부터 1 사이 값 |
키 포인트 ID | 신체 부위 |
---|---|
1 | nose |
2 | left_eye |
3 | right_eye |
4 | left_ear |
5 | right_ear |
6 | left_shoulder |
7 | right_shoulder |
8 | left_elbow |
9 | right_elbow |
10 | left_wrist |
11 | right_wrist |
12 | left_hip |
13 | right_hip |
14 | left_knee |
15 | right_knee |
16 | left_ankle |
17 | right_ankle |
curl -v -X POST "https://cv-api.kakaobrain.com/pose" \
-H "Content-Type: application/x-www-form-urlencoded" \
-H "Authorization: KakaoAK ${REST_API_KEY}" \
--data-urlencode "image_url=https://example.com/example.jpg"
curl -v -X POST "https://cv-api.kakaobrain.com/pose" \
-H "Content-Type: multipart/form-data" \
-H "Authorization: KakaoAK ${REST_API_KEY}" \
-F "file=@example_pose.jpg"
[
{
"area": 101090.2833,
"bbox": [719.4526, 244.1255, 182.7314, 553.2178],
"category_id": 1,
"keypoints": [
805.4897, 256.4165, 0.8422, 819.5366, 245.0034, 0.8773, 795.8325, 244.1255, 0.8664, 845.8745, 254.6606, 0.8105, 788.8091, 251.1489, 0.0631, 885.3813, 320.5054, 0.7525, 749.3022, 331.9185, 0.7706, 898.5503, 377.5708, 0.7825, 719.4526, 414.4438, 0.7897, 901.1841, 435.5142, 0.7782, 749.3022, 443.4155, 0.8086, 852.02, 504.8706, 0.6854, 785.2974, 511.894, 0.6738, 833.5835, 644.4614, 0.7899, 800.2222, 659.3862, 0.7655, 833.5835, 796.3433, 0.7055, 824.8042, 743.6675, 0.5165
],
"score": 0.7185
}
]
POST /pose/job HTTP/1.1
Host: cv-api.kakaobrain.com
Authorization: KakaoAK ${REST_API_KEY}
영상 분석하기 API는 영상을 다중 이미지로 처리하여 포즈를 분석하는 API입니다. 이 API는 영상을 분석하는 API로 작업 결과를 확인하려면 응답에서 전달 받은 job_id
를 담아 영상 분석 결과 확인하기 API를 호출해야 합니다.
콜백(callback_url
) 기능을 사용하여 영상 분석이 완료되었음을 확인한 후, 영상 분석 결과 확인하기 API를 호출하는 것을 권장합니다.
요청 헤더에 REST API키를 담아 분석할 POST
로 영상 분석을 요청합니다. 영상 요청 시 영상 파일(file)을 업로드 하거나 또는 영상 URL(video_url)을 지정할 수 있습니다. 요청이 성공하면 작업물에 대한 ID(job_id
)를 반환합니다.
Name | Description | Required |
---|---|---|
Authorization | REST API 키 [내 애플리케이션] > [앱 키]에서 확인 가능 |
O |
Name | Type | Description | Required |
---|---|---|---|
video_url | String | 처리할 영상의 URL HTTP(80포트)와 HTTPS(443 포트) 지원 |
O* |
file | Binary | 처리할 영상 파일 | O* |
smoothing | Boolean | 검출된 프레임 사이의 키 포인트 위치를 smoothing 처리할 것인지 여부, true 또는 false (기본값: true) | X |
callback_url | String | 요청 처리 결과를 받을 콜백(callback) URL HTTPS(443 포트) 사용 권장 아래 Sample: Callback과 같은 형태로 한 번 호출되며, 실패할 경우 재시도는 하지 않습니다. |
X |
* 조건부: video_url / file 중 하나 필수
- 무료 쿼터 사용 시, 영상은 최대 50MB 영상까지 업로드 할 수 있습니다. 최대 용량을 넘는 영상을 업로드할 경우, 에러가 발생하며, 더 큰 용량의 영상 처리를 위해서는 제휴 신청이 필요합니다. - 무료 쿼터 사용 시, 영상은 최대 30초까지만 처리됩니다. 최대 프레임 수를 넘는 영상을 업로드 할 경우, 앞 쪽 30초까지의 영상만 처리됩니다. 더 긴 영상 처리를 위해서는 제휴 신청이 필요합니다. - 영상의 가로와 세로 길이는 긴 변을 기준으로 최대 2048 pixel, 짧은 변을 기준으로 최소 320 pixel 이어야 합니다. - 영상의 권장 비율은 가로:세로 기준 16:9 ~ 9:16 입니다. - file을 업로드하는 경우, Content-Type을 multipart/form-data로 요청합니다. - video_url로 호출하는 경우, Content-Type을 application/x-www-form-urlencoded로 요청합니다.
카카오 브레인 서버에서 영상 분석이 완료되면 성공 여부와 상관없이 지정한 callback_url로 분석한 작업물의 ID와 함께 작업이 완료되었음을 알립니다. callback_url을 통해 영상 분석이 완료되었음을 확인한 후, 영상 분석 결과 확인하기 API를 통해 분석한 결과를 확인할 것을 권장합니다.
Name | Type | Description |
---|---|---|
job_id | String |
포즈 분석을 요청한 영상의 Job ID |
curl -v -X POST "https://cv-api.kakaobrain.com/pose/job" \
-H "Content-Type: application/x-www-form-urlencoded" \
-H "Authorization: KakaoAK ${REST_API_KEY}" \
--data-urlencode "video_url=http://example.com/example.mp4"
curl -v -X POST "https://cv-api.kakaobrain.com/pose/job" \
-H "Content-Type: multipart/form-data" \
-H "Authorization: KakaoAK ${REST_API_KEY}" \
-F "file=@example.mp4"
{
"job_id":"bb91c265-341d-4661-813b-870cff0de1d3"
}
curl -v -X GET "https://api.example.com/pose/callback?job_id=bb91c265-341d-4661-813b-870cff0de1d3"
GET /pose/job/${job_id} HTTP/1.1
Host: cv-api.kakaobrain.com
Authorization: KakaoAK ${REST_API_KEY}
영상 분석하기 API를 통해 요청한 작업물의 처리 상태와 결과를 반환하는 API입니다. 영상 분석하기 API 요청을 통해 전달 받은 job_id
를 URL에 담고, 요청 헤더에 REST API키를 담아 GET
으로 이미지 포즈 분석 결과를 확인합니다.
영상 분석이 성공적으로 완료되면 각 프레임 별로 사람들의 키 포인트에 대한 정보를 JSON
객체로 반환합니다.
Name | Description | Required |
---|---|---|
Authorization | REST API 키 [내 애플리케이션] > [앱 키]에서 확인 가능 |
O |
Name | Type | Description | Require |
---|---|---|---|
job_id | String |
영상 분석하기 API 응답으로 받은 Job ID | O |
Name | Type | Description |
---|---|---|
job_id | String |
포즈 분석을 요청한 영상의 Job ID |
status | String |
요청에 대한 응답 상태: waiting, processing, success, failed, not found 중 하나 - waiting: 내부에서 대기 중 - processing: 처리 중 - success: 정상 - failed: 처리 실패 - not found: 해당 Job ID로 찾을 수 없는 경우나 결과 보관 기간이 7일을 지난 경우 |
annotations | Annotation[] |
프레임 수만큼의 크기를 가진 배열로 각 프레임(Frame) 별로 검출한 키 포인트의 좌표와 신뢰도를 담은 객체들의 목록 아래 Annotations 항목 참고 "status: success"인 경우에만 반환 |
categories | Category[] |
키 포인트가 의미하는 정보를 담은 객체 아래 Categories 항목 참고 "status: success"인 경우에만 반환 |
info | Info |
생성된 작업물에 대한 정보(버전, 생성 날짜, URL, 설명 등)를 담은 객체 "status: success"인 경우에만 반환 |
video | Video |
요청한 영상의 프레임에 대한 정보(초당 진행되는 프레임의 수, 영상의 전체 프레임 수, 프레임의 가로/세로 길이)를 담은 객체 "status: success"인 경우에만 반환 |
description | String |
요청 처리 실패 사유 "status: failed"인 경우에만 반환 예: "Failed to get video" |
Name | Type | Description |
---|---|---|
frame_num | Int |
프레임의 번호, 0에서 n-1(n=프레임 수) |
objects | Person[] |
검출한 키 포인트의 좌표와 신뢰도를 담은 객체 객체에 대한 세부 파라미터는 이미지 분석하기 API의 Person 참고 |
Name | Type | Description |
---|---|---|
id | Int |
1로 고정 1: person |
keypoints | String[] |
17개의 키 포인트에 해당하는 신체 부위의 영문명을 담은 배열 ["nose", "left_eye", "right_eye", "left_ear", "right_ear", "left_shoulder", "right_shoulder", "left_elbow", "right_elbow", "left_wrist", "right_wrist", "left_hip", "right_hip", "left_knee", "right_knee", "left_ankle", "right_ankle"] |
name | String |
person 으로 고정 |
skeleton | List<Int[]> |
연결된 두 키 포인트 ID들을 담은 목록 예:[1, 2]는 코와 왼쪽 귀를 연결한 선을 의미 |
supercategory | String |
person 으로 고정 |
curl -v -X GET "https://cv-api.kakaobrain.com/pose/job/bb91c265-341d-4661-813b870cff0de1d3" \
-H "Authorization: KakaoAK ${REST_API_KEY}"
{
"annotations": [
{
"frame_num": 0,
"objects": [
{
"area": 211350.1765,
"bbox": [340.11, 22.28, 302.92, 697.72],
"category_id": 1,
"keypoints": [517.0, 185.81, 1.0, 524.27, 171.27, 1.0, 517.0, 171.27, 0.86, 560.61, 200.35, 1.0, 0.0, 0.0, 0.0, 582.41, 265.76, 1.0, 473.4, 243.95, 0.97, 596.95, 345.7, 1.0, 407.99, 164.01, 1.0, 524.27, 309.36, 1.0, 371.65, 84.06, 1.0, 546.08, 447.45, 0.87, 480.66, 432.92, 0.88, 531.54, 600.08, 1.0, 480.66, 541.94, 1.0, 524.27, 701.83, 1.0, 473.4, 607.35, 1.0],
"score": 0.9563
}
]
}
... // 첫 프레임 이후 결과는 생략
],
"categories": [
{
"id": 1,
"keypoints": ["nose", "left_eye", "right_eye", "left_ear", "right_ear", "left_shoulder", "right_shoulder", "left_elbow", "right_elbow", "left_wrist", "right_wrist", "left_hip", "right_hip", "left_knee", "right_knee", "left_ankle", "right_ankle"],
"name": "person",
"skeleton": [[1, 2], [1, 3], [2, 3], [2, 4], [3, 5], [4, 6], [5, 7], [6, 7], [6, 8], [6, 12], [7, 9], [7, 13], [8, 10], [9, 11], [12, 13], [14, 12], [15, 13], [16, 14], [17, 15]],
"supercategory": "person"
}
],
"info": {
"contributor": "Kakao Brain Corp.",
"date_created": "2020/05/26",
"description": "Human pose estimation result from Kakao Brain",
"url": "https://www.kakaobrain.com",
"version": "191227",
"year": 2020
},
"job_id": "bb91c265-341d-4661-813b-870cff0de1d3",
"status": "success",
"video": {
"fps": 29.97,
"frames": 30,
"height": 720,
"width": 1280
}
}
{
"description": "Failed to get video",
"job_id": "32b1dc9e-16c6-426b-9b06-d1c3e2abdfb4",
"status": "failed"
}
다음은 포즈 API 구현 예제입니다.
Python을 이용하여 포즈 API를 구현한 예제입니다. Python 버전은 3.5 이상을 권장합니다.
import requests
APP_KEY = '${REST_API_KEY}'
IMAGE_URL = 'http://example.com/example.jpg'
IMAGE_FILE_PATH = 'example.jpg'
session = requests.Session()
session.headers.update({'Authorization': 'KakaoAK ' + APP_KEY})
# URL로 이미지 입력시
response = session.post('https://cv-api.kakaobrain.com/pose', data={'image_url': IMAGE_URL})
print(response.status_code, response.json())
# 파일로 이미지 입력시
with open(IMAGE_FILE_PATH, 'rb') as f:
response = session.post('https://cv-api.kakaobrain.com/pose', files=[('file', f)])
print(response.status_code, response.json())
import os
import requests
APP_KEY = '${REST_API_KEY}'
VIDEO_URL = 'http://example.com/example.mp4'
VIDEO_FILE_PATH = 'example.mp4'
session = requests.Session()
session.headers.update({'Authorization': 'KakaoAK ' + APP_KEY})
# URL로 영상 입력시
response = session.post('https://cv-api.kakaobrain.com/pose/job', data={'video_url': VIDEO_URL})
print(response.status_code, response.json())
job_id = response.json()['job_id']
# 파일로 영상 입력시
assert os.path.getsize(VIDEO_FILE_PATH) < 5e7
with open(VIDEO_FILE_PATH, 'rb') as f:
response = session.post('https://cv-api.kakaobrain.com/pose/job', files=[('file', f)])
print(response.status_code, response.json())
job_id = response.json()['job_id']
import requests
APP_KEY = '${REST_API_KEY}'
session = requests.Session()
session.headers.update({'Authorization': 'KakaoAK ' + APP_KEY})
response = session.get('https://cv-api.kakaobrain.com/pose/job/' + job_id)
print(response.status_code, response.json())
COCO API를 활용하여 결과를 시각화하는 예제입니다. 이미지 분석하기 API를 이용한 이미지 결과 시각화와 영상 분석하기 API와 영상 분석 결과 확인하기 API를 활용한 영상 결과 시각화 예제를 소개합니다.
COCO API를 활용하려면 pycocotools 패키지가 필요합니다. 원활한 의존성 설치를 위해 pycocotools 설치 전 반드시 Cython과 NumPy를 먼저 설치합니다.
pip install Cython numpy
pip install matplotlib pycocotools requests pillow opencv-python
import cv2
import numpy as np
from matplotlib import pyplot as plt
from pycocotools.coco import COCO
from requests import Session
APP_KEY = '${REST_API_KEY}'
session = Session()
session.headers.update({'Authorization': 'KakaoAK ' + APP_KEY})
def inference(filename):
with open(filename, 'rb') as f:
response = session.post('https://cv-api.kakaobrain.com/pose', files={'file': f})
response.raise_for_status()
return response.json()
def visualize(filename, annotations, threshold=0.2):
# 낮은 신뢰도를 가진 keypoint들은 무시
for annotation in annotations:
keypoints = np.asarray(annotation['keypoints']).reshape(-1, 3)
low_confidence = keypoints[:, -1] < threshold
keypoints[low_confidence, :] = [0, 0, 0]
annotation['keypoints'] = keypoints.reshape(-1).tolist()
# COCO API를 활용한 시각화
image = cv2.cvtColor(cv2.imread(filename, cv2.IMREAD_COLOR), cv2.COLOR_BGR2RGB)
plt.imshow(image)
plt.axis('off')
coco = COCO()
coco.dataset = {
"categories": [
{
"supercategory": "person",
"id": 1,
"name": "person",
"keypoints": ["nose", "left_eye", "right_eye", "left_ear", "right_ear", "left_shoulder",
"right_shoulder", "left_elbow", "right_elbow", "left_wrist", "right_wrist", "left_hip",
"right_hip", "left_knee", "right_knee", "left_ankle", "right_ankle"],
"skeleton": [[1, 2], [1, 3], [2, 3], [2, 4], [3, 5], [4, 6], [5, 7], [6, 7], [6, 8], [6, 12], [7, 9],
[7, 13], [8, 10], [9, 11], [12, 13], [14, 12], [15, 13], [16, 14], [17, 15]]
}
]
}
coco.createIndex()
coco.showAnns(annotations)
plt.show()
IMAGE_FILE_PATH = 'example_pose.jpg'
result = inference(IMAGE_FILE_PATH)
visualize(IMAGE_FILE_PATH, result)
import os
import time
import numpy as np
from matplotlib import pyplot as plt
from pycocotools.coco import COCO
from requests import Session
APP_KEY = '${REST_API_KEY}'
session = Session()
session.headers.update({'Authorization': 'KakaoAK ' + APP_KEY})
def submit_job_by_url(video_url):
response = session.post('https://cv-api.kakaobrain.com/pose/job', data={'video_url': video_url})
response.raise_for_status()
return response.json()
def submit_job_by_file(video_file_path):
assert os.path.getsize(video_file_path) < 5e7
with open(video_file_path, 'rb') as f:
response = session.post('https://cv-api.kakaobrain.com/pose/job', files=[('file', f)])
response.raise_for_status()
return response.json()
# 실제 연동시엔 콜백을 이용한 방식으로 구현하시는 것을 권장합니다
def get_job_result(job_id):
while True:
response = session.get('https://cv-api.kakaobrain.com/pose/job/' + job_id)
response.raise_for_status()
response = response.json()
if response['status'] in {'waiting', 'processing'}:
time.sleep(10)
else:
return response
def visualize(resp, threshold=0.2):
# COCO API를 활용한 시각화
coco = COCO()
coco.dataset = {'categories': resp['categories']}
coco.createIndex()
width, height = resp['video']['width'], resp['video']['height']
# 낮은 신뢰도를 가진 keypoint들은 무시
for frame in resp['annotations']:
for annotation in frame['objects']:
keypoints = np.asarray(annotation['keypoints']).reshape(-1, 3)
low_confidence = keypoints[:, -1] < threshold
keypoints[low_confidence, :] = [0, 0, 0]
annotation['keypoints'] = keypoints.reshape(-1).tolist()
plt.axis('off')
plt.title("frame: " + str(frame['frame_num'] + 1))
plt.xlim(0, width)
plt.ylim(height, 0)
coco.showAnns(frame['objects'])
plt.show()
VIDEO_URL = 'http://example.com/example.mp4'
VIDEO_FILE_PATH = 'example.mp4'
# URL로 영상 지정 시
submit_result = submit_job_by_url(VIDEO_URL)
# 파일로 영상 업로드 시
submit_result = submit_job_by_file(VIDEO_FILE_PATH)
job_id = submit_result['job_id']
job_result = get_job_result(job_id)
if job_result['status'] == 'success':
visualize(job_result)
else:
print(job_result)