저번 글을 통해 Mediapipe를 이용해서 얼굴을 인식하여 모자이크 처리를 해 보았습니다.
이번에는 Mediapipe를 이용하여 손을 인식하여 보겠습니다.
설치는
아래처럼 라이브러리를 설치해주면 끝!
pip install mediapipe
이번엔 손 인식에 대한 코드를 작성해 보겠습니다.
기본적으로 아래처럼 라이브러리를 통해 손 인식 모듈을 불러와 줍시다.
import cv2
import mediapipe as mp
mp_drawing = mp.solutions.drawing_utils
mp_drawing_styles = mp.solutions.drawing_styles
mp_hands = mp.solutions.hands
다음은 모듈을 설정해 줍시다.
hands = mp_hands.Hands(
static_image_mode=True,
max_num_hands=10,
min_detection_confidence=0.01)
여기에는 많은 옵션들이 있는데 아래와 같습니다.
static_image_mode (정적이미지 모드)
false로 설정된 경우 솔루션은 입력 이미지를 비디오 스트림으로 처리합니다. 첫 번째 입력 이미지에서 손을 감지하고 탐지가 성공하면 손 랜드마크의 위치를 추가로 파악합니다. 후속 영상에서 max_num_hands만큼의 손이 감지되고 해당 손 랜드마크가 기준이 되면 손을 추적할 수 없을 때까지 새로 기준을 잡지 않고 랜드마크만 추적한다. 따라서 대기 시간이 단축되고 비디오 프레임 처리에 이상적입니다. true로 설정하면 모든 입력 이미지에서 손 감지가 실행되므로 이미지 별로 관련 없는 이미지 일괄 처리에 이상적입니다. 기본값은 false입니다.
( >> 만약 처리하려는 이미지가 비디오 프레임단위의 이미지들이라면! 설정하는 부분인것 같습니다.)
max_num_hands (손 최대 갯수)
탐지할 수 있는 최대 손 수입니다. 기본값은 2입니다.
model_complexity (모델복잡성)
핸드 랜드마크 모델의 복잡성은 0 또는 1입니다. 랜드마크 정확도와 추론 지연 시간은 모델 복잡성과 함께 증가합니다. 기본값은 1입니다.
(사람인식의 경우 모델 복잡성이 2까지 지원되지만 손은 0과 1까지만 지원합니다.)
min_detection_confidence (최소탐지 신뢰도)
탐지가 성공한 것으로 간주되는 손 감지 모델의 최소 신뢰 값([0.0, 1.0]). 기본값은 0.5입니다.
min_trackin_confidence (최소_추척_신뢰도)
손 랜드마크 추적 모델의 최소 신뢰 값([0.0, 1.0])이 성공적으로 추적된 것으로 간주됩니다 만약 그렇지 않다면 다음 입력 영상에서 기준 손 탐지가 자동으로 호출됩니다. 이 솔루션을 높은 값으로 설정하면 지연 시간이 길어지는 대신 솔루션의 정확성을 높일 수 있습니다. static_image_mode가 True라면 무시됩니다. 여기서 손 감지는 모든 이미지에 대해 실행됩니다. 기본값은 0.5입니다.
(이 옵션이 가장 난해 한 것 같은데,
static_image_mode와 관련있는 것으로 보아
만약 입력되는 이미지들이 비디오 프레임 이미지들일 경우, 추적하여 인식해주는 정도로 min_detection_confidence와 동일한 역할을 하는것 같습니다.)
이렇게 설정을 끝내고 나면 아래처럼 이미지를 넣어 실행해주면 끝!
file=['testHands.jpg'] ## 파일 추가 가능~
for idx, file in enumerate(IMAGE_FILES):
image = cv2.flip(cv2.imread(file), 1)
results = hands.process(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
# 손으로 프린트하고 이미지에 손 랜드마크를 그립니다.
print('Handedness:', results.multi_handedness)
if not results.multi_hand_landmarks:
continue
image_height, image_width, _ = image.shape
annotated_image = image.copy()
for hand_landmarks in results.multi_hand_landmarks:
mp_drawing.draw_landmarks(
annotated_image,
hand_landmarks,
mp_hands.HAND_CONNECTIONS,
mp_drawing_styles.get_default_hand_landmarks_style(),
mp_drawing_styles.get_default_hand_connections_style())
cv2.imwrite(
'annotated_image' + str(idx) + '.png', cv2.flip(annotated_image, 1))
아래처럼 손 관절 부분이 그려지며 인식되는것을 볼 수 있습니다!
사각박스로만 표시하고 싶다면
함수를 하나추가해서
def get_bbox_coordinates(handLadmark, image_shape):
all_x, all_y = [], []
for hnd in mp_hands.HandLandmark:
all_x.append(int(handLadmark.landmark[hnd].x * image_shape[1]))
all_y.append(int(handLadmark.landmark[hnd].y * image_shape[0]))
return min(all_x), min(all_y), max(all_x), max(all_y)
아래 부분을 주석처리하고
# mp_drawing.draw_landmarks(
# annotated_image,
# hand_landmarks,
# mp_hands.HAND_CONNECTIONS,
# mp_drawing_styles.get_default_hand_landmarks_style(),
# mp_drawing_styles.get_default_hand_connections_style())
그자리에 이렇게 추가하면 cv2를 이용해서 그려줄 수 있습니다.
bboxC=get_bbox_coordinates(hand_landmarks,image.shape) ## 손 따라 잡기
cv2.rectangle(annotated_image, (bboxC[0], bboxC[1]), (bboxC[2], bboxC[3]), (255, 0, 255), 2)
끝!
대부분의 손을 Mediapipe로 인식할 수 있지만 테스트해보니 너무가깝거나, 멀리 있는 손의 경우 인식하지 못했습니다.
정확하지 않지만 30~60cm 사이에 있는 손의 경우는 대부분 인식하는것 같습니다.
손이 인식되지 못하는 경우는 이미지 내의 범위를 지정하여 잘라서 그부분을 따로 인식하는 분할 인식 방법으로 해결 할 수 있을것 같습니다.
<ALL>
import cv2
import mediapipe as mp
mp_drawing = mp.solutions.drawing_utils
mp_drawing_styles = mp.solutions.drawing_styles
mp_hands = mp.solutions.hands
def get_bbox_coordinates(handLadmark, image_shape):## 박스
all_x, all_y = [], []
for hnd in mp_hands.HandLandmark:
all_x.append(int(handLadmark.landmark[hnd].x * image_shape[1]))
all_y.append(int(handLadmark.landmark[hnd].y * image_shape[0]))
return min(all_x), min(all_y), max(all_x), max(all_y)
def opHand(IMAGE_FILES):
for idx, file in enumerate(IMAGE_FILES):
image = cv2.flip(cv2.imread(file), 1)
results = hands.process(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
# 손으로 프린트하고 이미지에 손 랜드마크를 그립니다.
print('Handedness:', results.multi_handedness)
if not results.multi_hand_landmarks:
continue
image_height, image_width, _ = image.shape
annotated_image = image.copy()
for hand_landmarks in results.multi_hand_landmarks:
# mp_drawing.draw_landmarks(
# annotated_image,
# hand_landmarks,
# mp_hands.HAND_CONNECTIONS,
# mp_drawing_styles.get_default_hand_landmarks_style(),
# mp_drawing_styles.get_default_hand_connections_style())
bboxC=get_bbox_coordinates(hand_landmarks,image.shape) ## 손 따라 잡기
cv2.rectangle(annotated_image, (bboxC[0], bboxC[1]), (bboxC[2], bboxC[3]), (255, 0, 255), 2)
cv2.imwrite(
'annotated_image' + str(idx) + '.png', cv2.flip(annotated_image, 1))
file=['testHands.jpg']
opHand(file)
<미디어파이프 git>
https://github.com/google/mediapipe/blob/master/docs/solutions/hands.md
'공부공부 > 2023 쌓여가는 나의 지식~' 카테고리의 다른 글
Fastapi를 이용한 웹페이지 구성 (2) - 웹 페이지 연결 및 구성 & Get/Post (1) | 2023.12.07 |
---|---|
Fastapi를 이용한 웹페이지 구성 (1) - 설치 및 사용 (1) | 2023.12.06 |
리눅스(Linux) 데이터 베이스(Mysql) 사용해보기 (0) | 2023.10.26 |
Mediapipe를 이용한 얼굴 모자이크(Blur)처리 (0) | 2023.10.13 |
Python 영상 프레임 단위 분할 [Labelme Tool 사용 및 수정(2)] (0) | 2023.10.11 |
댓글