컴굥일지
[모션 인식] Python과 OpenPose(OpenCV)를 사용하여 실시간 자세 추정하기 본문
1. 모션 인식 - OpenPose
OpenPose는 신체의 관절을 추론하는 기술입니다.
이후, 관절들을 선으로 이어서 보여줍니다.
OpenPose는 얼굴, 손, 몸의 skeleton을 그릴 수 있습니다.
자세 추정이 필요한 저희 팀은 이 기술을 사용하기로 결정했습니다. (with python)
2. OpenPose 설치하기
https://github.com/CMU-Perceptual-Computing-Lab/openpose
위 링크에 들어가서 파일들을 다운로드 받아야 합니다.
파일을 압축해제 후, models 폴더에 들어가서 getModels 파일을 실행해야 합니다.
윈도우 환경에서는 아래에 표시한 파일을 실행하고, 그 외의 경우에는 그 밑의 getModels.sh를 실행하면 됩니다.
파일을 실행하면 아래와 같은 창이 뜨면서 모델들이 다운로드됩니다.
OpenPose로 사용할 수 있는 모델의 종류는 body-25, coco, mpii 3가지가 있습니다.
body-25는 출력 관절이 25개, coco는 출력 관절이 18개, MPI는 출력 관절이 15개입니다.
저희 조는 mpii 모델을 사용했습니다.
위의 창에서 다운이 끝나면 caffemodel이 생겼을 겁니다.
(위쪽은 getModels 실행 전 폴더 상황, 아래는 실행 후 폴더 상황)
위의 사진에 보이는 파일 2개를 사용하도록 할 겁니다.
이후, OpenCV가 필요하므로 설치해야 합니다. (3.4.1 이상의 버전이 필요)
cmd 창에서 pip install opencv-python을 입력해주세요.
3. OpenPose 사용하기
이것이 제 폴더 구조입니다.
file이라는 폴더 안에 위에서 받은 모델이 들어있습니다.
저희 조는 웹캠을 통해 실시간으로 영상을 받아 자세를 검출해야 하므로 이와 관련된 코드를 아래에 기술하도록 하겠습니다. (openpose2_ex.py)
import cv2
from pathlib import Path
# MPII에서 각 파트 번호, 선으로 연결될 POSE_PAIRS
BODY_PARTS = { "Head": 0, "Neck": 1, "RShoulder": 2, "RElbow": 3, "RWrist": 4,
"LShoulder": 5, "LElbow": 6, "LWrist": 7, "RHip": 8, "RKnee": 9,
"RAnkle": 10, "LHip": 11, "LKnee": 12, "LAnkle": 13, "Chest": 14,
"Background": 15 }
POSE_PAIRS = [ ["Head", "Neck"], ["Neck", "RShoulder"], ["RShoulder", "RElbow"],
["RElbow", "RWrist"], ["Neck", "LShoulder"], ["LShoulder", "LElbow"],
["LElbow", "LWrist"], ["Neck", "Chest"], ["Chest", "RHip"], ["RHip", "RKnee"],
["RKnee", "RAnkle"], ["Chest", "LHip"], ["LHip", "LKnee"], ["LKnee", "LAnkle"] ]
# 각 파일 path
BASE_DIR=Path(__file__).resolve().parent
protoFile = str(BASE_DIR)+"/file/pose_deploy_linevec_faster_4_stages.prototxt"
weightsFile = str(BASE_DIR)+"/file/pose_iter_160000.caffemodel"
# 위의 path에 있는 network 모델 불러오기
net = cv2.dnn.readNetFromCaffe(protoFile, weightsFile)
#쿠다 사용 안하면 밑에 이미지 크기를 줄이는게 나을 것이다
# net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA) #벡엔드로 쿠다를 사용하여 속도향상을 꾀한다
# net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA) # 쿠다 디바이스에 계산 요청
###카메라랑 연결...?
capture = cv2.VideoCapture(0) #카메라 정보 받아옴
# capture.set(cv2.CAP_PROP_FRAME_WIDTH, 640) #카메라 속성 설정
# capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) # width:너비, height: 높이
inputWidth=320;
inputHeight=240;
inputScale=1.0/255;
#반복문을 통해 카메라에서 프레임을 지속적으로 받아옴
while cv2.waitKey(1) <0: #아무 키나 누르면 끝난다.
#웹캠으로부터 영상 가져옴
hasFrame, frame = capture.read()
#영상이 커서 느리면 사이즈를 줄이자
#frame=cv2.resize(frame,dsize=(320,240),interpolation=cv2.INTER_AREA)
#웹캠으로부터 영상을 가져올 수 없으면 웹캠 중지
if not hasFrame:
cv2.waitKey()
break
#
frameWidth = frame.shape[1]
frameHeight = frame.shape[0]
inpBlob = cv2.dnn.blobFromImage(frame, inputScale, (inputWidth, inputHeight), (0, 0, 0), swapRB=False, crop=False)
imgb=cv2.dnn.imagesFromBlob(inpBlob)
#cv2.imshow("motion",(imgb[0]*255.0).astype(np.uint8))
# network에 넣어주기
net.setInput(inpBlob)
# 결과 받아오기
output = net.forward()
# 키포인트 검출시 이미지에 그려줌
points = []
for i in range(0,15):
# 해당 신체부위 신뢰도 얻음.
probMap = output[0, i, :, :]
# global 최대값 찾기
minVal, prob, minLoc, point = cv2.minMaxLoc(probMap)
# 원래 이미지에 맞게 점 위치 변경
x = (frameWidth * point[0]) / output.shape[3]
y = (frameHeight * point[1]) / output.shape[2]
# 키포인트 검출한 결과가 0.1보다 크면(검출한곳이 위 BODY_PARTS랑 맞는 부위면) points에 추가, 검출했는데 부위가 없으면 None으로
if prob > 0.1 :
cv2.circle(frame, (int(x), int(y)), 3, (0, 255, 255), thickness=-1, lineType=cv2.FILLED) # circle(그릴곳, 원의 중심, 반지름, 색)
cv2.putText(frame, "{}".format(i), (int(x), int(y)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1, lineType=cv2.LINE_AA)
points.append((int(x), int(y)))
else :
points.append(None)
# 각 POSE_PAIRS별로 선 그어줌 (머리 - 목, 목 - 왼쪽어깨, ...)
for pair in POSE_PAIRS:
partA = pair[0] # Head
partA = BODY_PARTS[partA] # 0
partB = pair[1] # Neck
partB = BODY_PARTS[partB] # 1
#partA와 partB 사이에 선을 그어줌 (cv2.line)
if points[partA] and points[partB]:
cv2.line(frame, points[partA], points[partB], (0, 255, 0), 2)
cv2.imshow("Output-Keypoints",frame)
capture.release() #카메라 장치에서 받아온 메모리 해제
cv2.destroyAllWindows() #모든 윈도우 창 닫음
위 코드를 실행하면 아래와 같이 새로운 창이 뜨면서 웹캠으로 자신의 모습과 자세를 볼 수 있습니다.
위의 실행결과로 볼 수 있듯이, 자세 검출이 잘되고 있습니다.
Teachable Machine에 비해서 확실히 자세가 잘 검출됩니다.
다만 Teachable Machine과 달리, 우리가 원하는 자세인지 판단하는 코드를 따로 짜야한다는 단점이 있습니다.
개인적인 생각으로는 OpenPose가 훨씬 더 나은 것 같습니다.
OpenCV와 관련해서는 https://076923.github.io/posts/Python-opencv-1/ 이 링크를 보면 좀 더 도움이 될 것입니다.
'프로젝트 > 졸프 - 참여형 동화 서비스' 카테고리의 다른 글
[모션인식] PoseNet을 사용하여 실시간으로 자세 인식하기 (4) | 2022.05.11 |
---|---|
[모션인식] Django에서 OpenPose로 실시간 자세 검출하기 (2) | 2022.05.10 |
[모션 인식] Teachable Machine으로 자세 추정하기 (0) | 2022.05.06 |
참여형 동화 서비스 - 주제 변경 (0) | 2022.05.05 |
참여형 동화 서비스 - NLP(KoGPT2) (9) | 2021.11.25 |