Notice
Recent Posts
Recent Comments
Link
«   2024/06   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30
Archives
Today
Total
관리 메뉴

mignon의 CS학습

Python, OpenPose를 활용하여 인체의 자세 감지하기 본문

캡스톤디자인프로젝트

Python, OpenPose를 활용하여 인체의 자세 감지하기

mignon.e 2021. 5. 25. 19:06

안녕하세요.

2021학년도 1학기 캡스톤디자인프로젝트B를 수강 중인, START 10팀 'PIXIE'의 조원입니다.

저희 조의 목표는 라즈베리파이로 구현한 CCTV상에서 동작하는 딥러닝 기반 쓰레기 무단 투기를 감지 어플을 개발하는 것입니다.

 

쓰레기 무단 투기를 감지하는 방법으로, 다음 두 가지를 고안했습니다.

1. 영상 속 사람과 쓰레기를 각각 감지하여, 쓰레기와 사람 간의 거리가 멀어지면 무단 투기로 인식

2. 사람이 쓰레기를 무단투기하는 행위를 학습하여, 영상 속 사람 해당 움직임을 보이면 무단 투기로 인식

 

저는 객체 인식 알고리즘인 SSD를 이용하여 2번을 구현하고자, 영상 속 사람의 행위를 파악할 수 있는 방법이 필요했습니다.

이 목표를 실현하기 위하여, 영상 속 사람의 주요 포인트들을 따서 사람의 움직임을 감지하는 방법에 대해 학습하였습니다.

 

학습에 앞서, 저는 구글 코랩을 사용하였습니다.

구글 코랩 사용시 구글 드라이브에 있는 파일을 이용하기 위해서는 우선 코랩과 구글 드라이브를 연동해야합니다.

 

from google.colab import drive

drive.mount('/gdrive', force_remount=True)

 

OpenPose란,

Caffe와 OpenCV를 기반으로 구성된 손, 얼굴 포함 몸의 움직임을 추적해주는 API입니다.

 

위의 영상은 OpenCV를 사용하여 사람의 동작을 감지한 예시입니다.

신체의 주요 포인트(어깨, 발목, 무릎, 손목 등과 같은 관절)을 감지하여 사람의 포즈를 추정합니다.

 

이때 널리 이용되는 데이터 세트는 다음과 같습니다.

  1. COCO
  2. MPII
  3. VGG

COCO 모델은 18 포인트를, MPII 모델은 15 포인트를 출력합니다.

다음은 출력된 포인트의 예시입니다.

코코 출력 형식: 코 – 0, 목 – 1, 오른쪽 어깨 – 2, 오른쪽 팔꿈치 – 3, 오른쪽 손목 – 4, 왼쪽 어깨 – 5, 왼쪽 팔꿈치 – 6, 왼쪽 손목 – 7, 오른쪽 엉덩이 – 8, 오른쪽 무릎 – 9, 오른쪽 발목 – 10, 왼쪽 엉덩이 – 11, 왼쪽 무릎 – 12, 왼쪽 발목 – 13, 오른쪽 눈 – 14, 왼쪽 눈 – 15, 오른쪽 귀 – 16, 왼쪽 귀 – 17, 배경 – 18 

MPII 출력 형식: 머리 – 0, 목 – 1, 오른쪽 어깨 – 2, 오른쪽 팔꿈치 – 3, 오른쪽 손목 – 4, 왼쪽 어깨 – 5, 왼쪽 팔꿈치 – 6, 왼쪽 손목 – 7, 오른쪽 엉덩이 – 8, 오른쪽 무릎 – 9, 오른쪽 발목 – 10, 왼쪽 엉덩이 – 11, 왼쪽 무릎 – 12, 왼쪽 발목 – 13

 

3. OpenCV에서 인간의 포즈 추정에 대한 코드

1. 모델 가중치 다운로드

아래의 GitHub에 들어가 OpenPose를 다운받습니다.

[openpose] https://github.com/CMU-Perceptual-Computing-Lab/openpose

 

CMU-Perceptual-Computing-Lab/openpose

OpenPose: Real-time multi-person keypoint detection library for body, face, hands, and foot estimation - CMU-Perceptual-Computing-Lab/openpose

github.com

압축 해제 후, models 폴더의 getModels를 실행시켜 각 폴더에 모든 모델 가중치를 다운로드합니다.

(Window환경이라면 getModels, Linux 환경이라면 getModels.sh를 실행시킵니다.)

getModels 위치

getModels 실행이 완료되면, 창이 자동으로 꺼집니다.

models/pose/의 하위 폴더인 body_25, coco, mpi 모델들의 폴더를 확인하여 모델 바이너리(.caffemodel 파일)가 다운로드되었는지 확인합니다. 

2. 훈련된 네트워크 세팅

OpenCV를 사용하기 위해 import합니다.

import cv2

from google.colab.patches import cv2_imshow

 

구글 코랩에서는 cv2.imshow() 함수를 사용할 수 없습니다.

.imshow()를 사용하면 이미지가 새 윈도우 창에 출력되야하는데, 이때 crash로 인한 오류가 납니다.

따라서 이미지를 출력하기 위해 from google.colab.patches import cv2_imshow를 사용합니다.

 

현재 사용중인 카페 딥 러닝 프레임워크에서 훈련된 모델에는 2개의 파일이 있습니다 .

  1. 신경망의 아키텍처를 지정하는 .prototxt 파일
  2. 모델의 가중치를 저장하는 .caffemodel 파일

저는 googlecolab을 이용했기 때문에, /gdrive에 마운트 후 경로를 설정하였습니다.

 

protoFile = "/gdrive/MyDrive/PIXIE/pose_deploy_linevec_faster_4_stages.prototxt"

weightsFile = "/gdrive/MyDrive/PIXIE/pose_iter_160000.caffemodel"

net = cv2.dnn.readNetFromCaffe(protoFile, weightsFile)

 

3. 이미지 읽기 및 네트워크에 대한 입력 준비

OpenCV를 사용하여 읽은 입력 프레임은 네트워크에 넣으려면 Blob(예: Caffe)으로 변환해야 합니다. 

먼저 픽셀 값(0,1)을 정규화하고, 이미지의 크기를 지정한 후, 평균 값 (0,0,0)를 뺍니다.

OpenCV와 Caffe는 모두 BGR 형식을 사용하기 때문에 색상 채널 R, B는 교체하지 않습니다.

 

# 테스트 이미지 읽기

image = cv2.imread("/gdrive/MyDrive/PIXIE/test.jpg")

 

# 테스트 이미지에서 height, width, color 정보 파악

imageHeight, imageWidth, imageColor = image.shape

 

# 테스트 이미지를 network에 넣기 위해 전처리

inpBlob = cv2.dnn.blobFromImage(image, 1.0 / 255, (imageWidth, imageHeight), (0, 0, 0), swapRB=False, crop=False)

 

# 테스트 이미지를 network에 넣어줌

net.setInput(inpBlob)

 

# 결과 받아오기

output = net.forward()

 

H = output.shape[2]

W = output.shape[3]

 

 

제 테스트 이미지는 다음 사진을 이용하였습니다.

4. 키 포인트 검출

# 검출된 관절 포인트를 테스트 이미지에 그려주기

points = []

for i in range(0, 15):

    # 해당 관절 신뢰도 얻기

    probMap = output[0, i, :, :]

 

    # global maxima 찾기

    minVal, prob, minLoc, point = cv2.minMaxLoc(probMap)

 

    # 원래 이미지에 맞게 점 위치 변경

    x = (imageWidth * point[0]) / W

    y = (imageHeight * point[1]) / H

 

    # 키포인트 검출한 결과가 threshold(0.1)보다 크면(검출한곳이 위 BODY_PARTS랑 맞는 부위면) points에 추가, 검출했는데 부위가 없으면 None으로

    if prob > 0.1 :    

        cv2.circle(image, (int(x), int(y)), 3, (0, 255, 255), thickness=-1, lineType=cv2.FILLED)       # circle(그릴곳, 원의 중심, 반지름, 색)

        cv2.putText(image, "{}".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)

 

 

cv2_imshow(image)

cv2.waitKey(0)

플롯된 MPI 모델을 사용하여 키포인트가 감지된 이미지입니다.

정확도가 떨어짐을 확인하였습니다.

5. 스켈레톤 그리기

위에서 감지한 포인트를 이어, 인체 골격을 그립니다.

 

# 관절들을 선으로 연결해주기

for pair in POSE_PAIRS:

    partA = pair[0]  # Head

    partA = BODY_PARTS[partA]  # 0

    partB = pair[1]  # Neck

    partB = BODY_PARTS[partB]  # 1

 

    # print(partA," 와 ", partB, " 연결\n")

    if points[partA] and points[partB]:

        cv2.line(image, points[partA], points[partB], (255, 0, 0), 2)

 

cv2_imshow(image)

cv2.waitKey(0)

cv2.destroyAllWindows()

키포인트가 제대로 검출되지 않은 상태에서 골격을 그리니, 인체의 자세를 전혀 감지할 수 없었습니다.

 

보다 명확한 사진으로 동일한 코드를 다시 돌려보았습니다.

결과는 다음과 같습니다.

인체의 정확한 자세를 감지함을 확인하였습니다.

'캡스톤디자인프로젝트' 카테고리의 다른 글

YOLOv5 Data Augmentation  (0) 2021.11.06
Comments