Browsing Tag

머신러닝

NCLOUD

[NCLOUD] Ncloud Pose Estimation API를 활용한 이미지 분석 및 주요 신체 부위 좌표를 파악해 보자

안녕하세요. MANVSCLOUD 김수현입니다.

이전 포스팅 ‘CLOVA Face Recognition (CFR)의 유명인 얼굴 인식을 활용하여 닮은꼴 연예인 찾기’에 이어 또 다른 AI 서비스를 준비했습니다.

오늘 사용하게될 서비스는 네이버 클라우드 플랫폼의 Ncloud Pose Estimation입니다.
이번 포스팅을 통해 해당 서비스를 간단하게 사용해보고 어떻게 활용하면 좋을지 아이디어를 얻는 시간이 되길 바랍니다.


Ncloud Pose Estimation

Ncloud Pose Estimation은 사람의 위치를 분석하고 인식된 대상이 취하고 있는 자세로부터
각 신체의 좌표와 정확도를 제공하는 네이버 클라우드 플랫폼의 AI 서비스입니다.

아래 주요 신체 부위 18개의 좌표를 제공합니다.

필드 이름설명
predictions[n][‘0’]
predictions[n][‘1’]
predictions[n][‘2’]오른쪽 어깨
predictions[n][‘3’]오른쪽 팔꿈치
predictions[n][‘4’]오른쪽 손목
predictions[n][‘5’]왼쪽 어깨
predictions[n][‘6’]왼쪽 팔꿈치
predictions[n][‘7’]왼쪽 손목
predictions[n][‘8’]오른쪽 엉덩이
predictions[n][‘9’]오른쪽 무릎
predictions[n][’10’]오른쪽 발목
predictions[n][’11’]왼쪽 엉덩이
predictions[n][’12’]왼쪽 무릎
predictions[n][’13’]왼쪽 발목
predictions[n][’14’]오른쪽 눈
predictions[n][’15’]왼쪽 눈
predictions[n][’16’]오른쪽 귀
predictions[n][’17’]왼쪽 귀

신체 좌표(x,y) 외 신뢰도를 나타내는 정확도 점수(score)도 함께 제공되며
포즈 인식에 사용되는 이미지 크기는 최대 300KB의 용량만 지원됩니다.


A to Z

# VPC, Server 생성에 대한 가이드는 생략합니다.
# ACG 설정은 (Inbound) 22, 10000 / (Outbound) 80, 443이 허용되었습니다.
# Python은 3.7.13 버전이 사용되었습니다.
# 해당 A to Z는 Python 개발 환경 구성이 완료되었다는 가정하에 진행됩니다.
(Python 개발 환경 구성에 대한 가이드가 필요할 경우 아래 링크에서
“3. Python 개발 환경 구성” 부분을 참고 부탁드립니다. )

이제 Ncloud Pose Estimation API를 활용하여 이미지 분석 및 주요 신체 부위 좌표를 파악해보도록 합시다.

1. AI·NAVER API에서 [Application 등록]

Application 등록 버튼을 눌러 Application 이름과 사용할 AI Service를 선택합니다.
이번 과정에서는 Ncloud Pose Estimation만 사용하며 하단에 서비스 환경 등록은 따로 설정하지 않겠습니다.

2. 서비스 만들기 (Flask + HTML + Ncloud Pose Estimation)

다음과 같이 간단한 구조로 준비하였습니다.

.
├── app.py
├── templates
│   └── index.html
└── test.jpg

test.jpg는 테스트 시 사용할 이미지 파일입니다.
이번 Ncloud Pose Estimation 포스팅에도 손흥민 이미지가 함께합니다.

1) python 패키지 설치

pip install flask requests opencv-python

2) app.py

app.py코드는 다음과 같이 준비했습니다.

  • 준비된 이미지를 Ncloud Pose Estimation API로 분석합니다.
  • 분석된 결과 좌표를 OpenCV를 이용하여 그려줍니다.
  • 0부터 17까지(각 신체 부위)의 필드가 모두 인식되지 않을 수 있습니다.
    즉, try-except를 이용하여 비인식 부위로 인한 KeyError 발생 시 예외 처리하도록 합니다.
  • 포트는 Default 5000 에서 10000으로 변경하였습니다.
from flask import Flask, render_template
import cv2
import base64
import io
import os
import requests
import json

app = Flask(__name__)

@app.route('/')
def index():

    # ImageFile
    image_file = "test.jpg"

    #Ncloud Pose Estimation
    client_id = os.environ['AI_CLIENT_ID']
    client_secret = os.environ['AI_CLIENT_KEY']
    url = "https://naveropenapi.apigw.ntruss.com/vision-pose/v1/estimate"
    files = {'image': (open(image_file, 'rb'))}
    headers = {'X-NCP-APIGW-API-KEY-ID': client_id, 'X-NCP-APIGW-API-KEY': client_secret}
    response = requests.post(url, files=files, headers=headers)

    data = json.loads(response.text)

    # OpenCV Show Location
    img = cv2.imread(image_file)

    w=10
    h=10
    img_height, img_width, _ = img.shape

    # 0-17 Nose-Left Ear

    for i in range(18):
        try:
            x = data["predictions"][0][f"{i}"]["x"]
            y = data["predictions"][0][f"{i}"]["y"]

            x_px = int(x * img_width)
            y_px = int(y * img_height)

            roi = img[y_px:y_px+h, x_px:x_px+w]
            cv2.rectangle(roi, (0,0), (h-5, w-5), (0,255,0))

        except KeyError:
            continue

    # Convert the OpenCV image to a Matplotlib image
    _, img_encoded = cv2.imencode('.png', img)
    img_base64 = base64.b64encode(img_encoded).decode('utf-8')

    # Render the image in a template
    return render_template('index.html', image=img_base64)

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=10000)

3) index.html

다음은 templates/index.html 입니다.

<!DOCTYPE html>
<html>
<head>
    <title>Flask OpenCV Example</title>
</head>
<body>
    <img src="data:image/png;base64,{{ image }}" alt="image">
</body>
</html>

3. python app.py

app.py를 실행하여 http://서버IP:10000로 접속해봅시다!

[참고 1] 이미지 분석까지 다소 시간이 소요된다.
[참고 2] 위 코드는 1인 대상 분석을 기준으로 단순하게 짜여진 코드이므로
2명 이상 인식될 경우 Error가 발생할 수 있으니 필요 시 원하는 방향에 맞게 수정하자!


Result

보이십니까? 각 부위별로 Ncloud Pose Estimation이 인식한 신체 부위들입니다.
눈, 코, 귀, 목, 어깨, 팔꿈치, 무릎 등 인식된 부위에 좌표가 표시되고 있습니다.

API를 이용하여 위 좌표들을 Json 형태로 보게되면 다음과 같은 결과를 얻을 수 있습니다.

import os
import requests

image='test.jpg'
client_id = os.environ['AI_CLIENT_ID']
client_secret = os.environ['AI_CLIENT_KEY']
url = "https://naveropenapi.apigw.ntruss.com/vision-pose/v1/estimate"
files = {'image': (open(image, 'rb'))}
headers = {'X-NCP-APIGW-API-KEY-ID': client_id, 'X-NCP-APIGW-API-KEY': client_secret}
response = requests.post(url, files=files, headers=headers)

print(response.text)

<Json 결과>

{
    "predictions": [
        {
            "0": {
                "score": 0.6248959898948669,
                "x": 0.46875,
                "y": 0.20294117647058824
            },
            "1": {
                "score": 0.682578980922699,
                "x": 0.5390625,
                "y": 0.24705882352941178
            },
            "2": {
                "score": 0.5946630239486694,
                "x": 0.42578125,
                "y": 0.2647058823529412
            },
            "3": {
                "score": 0.5219699740409851,
                "x": 0.33203125,
                "y": 0.35
            },
            "4": {
                "score": 0.5029489994049072,
                "x": 0.26171875,
                "y": 0.39705882352941174
            },
            "5": {
                "score": 0.537896990776062,
                "x": 0.6484375,
                "y": 0.22941176470588234
            },
            "6": {
                "score": 0.5460799932479858,
                "x": 0.77734375,
                "y": 0.24705882352941178
            },
            "7": {
                "score": 0.46914198994636536,
                "x": 0.88671875,
                "y": 0.3088235294117647
            },
            "8": {
                "score": 0.36182901263237,
                "x": 0.5,
                "y": 0.5147058823529411
            },
            "9": {
                "score": 0.3729259967803955,
                "x": 0.328125,
                "y": 0.7
            },
            "10": {
                "score": 0.6009839773178101,
                "x": 0.17578125,
                "y": 0.8823529411764706
            },
            "11": {
                "score": 0.337242990732193,
                "x": 0.66015625,
                "y": 0.538235294117647
            },
            "12": {
                "score": 0.5896649956703186,
                "x": 0.53125,
                "y": 0.6882352941176471
            },
            "13": {
                "score": 0.40395501255989075,
                "x": 0.296875,
                "y": 0.8352941176470589
            },
            "14": {
                "score": 0.6011859774589539,
                "x": 0.44921875,
                "y": 0.18235294117647058
            },
            "15": {
                "score": 0.5642120242118835,
                "x": 0.49609375,
                "y": 0.18235294117647058
            },
            "17": {
                "score": 0.7845849990844727,
                "x": 0.55078125,
                "y": 0.1676470588235294
            }
        }
    ]
}

각 신체 부위별 x,y 위치 그리고 정확도 점수를 확인할 수 있습니다.
보시다시피 위 Json 결과를 보면 16(오른쪽 귀)가 인식되지 않았습니다.
(이미지에 오른쪽 귀가 나오지않았기 때문)

인식되지 않은 부위는 결과에 포함되지 않는 점 참고할 필요가 있습니다.


Personal Comments

이전 포스팅에서 배운 CLOVA Face Recognition(CFR) 서비스에 이어 Hands-On Lab 형태로 AI 서비스를 하나 더 배워보았습니다.

해당 포스팅을 통해 Ncloud Pose Estimation 서비스를 어떻게 사용하면 좋을지 아이디어가 떠오르셨나요?

저는 이 서비스를 피트니스, 의학, 일상 생활에서 자세교정이나 이상행동감지 등 다양하게 사용할 수 있을 것같습니다.

다음 포스팅은 더 흥미로운 AI 포스팅을 준비해보도록 하겠습니다.

긴 글 읽어주셔서 감사합니다.