Mediapipe를 사용해 무엇이든 만들라는 프로젝트를 진행했다.
Mediapipe란?
https://ai.google.dev/edge/mediapipe/solutions/guide?hl=ko
MediaPipe 솔루션 가이드 | Google AI Edge | Google AI for Developers
LiteRT 소개: 온디바이스 AI를 위한 Google의 고성능 런타임(이전 명칭: TensorFlow Lite)입니다. 이 페이지는 Cloud Translation API를 통해 번역되었습니다. 의견 보내기 MediaPipe 솔루션 가이드 의견 보내기 달
ai.google.dev
Mediapipe는 라이브러리로 사용될 수도 있고, 모델로도 사용될 수 있다.
나는 YOLO를 모델로 사용하고 Mediapipe를 라이브러리로 불러왔다.
[Mediapipe 활용]
- 얼굴 인식
눈, 코, 입, 이주(귀 앞 부분)와 얼굴 위치를 인식할 수 있다.
이를 사용해 1차로 얼굴을 인식하고, YOLO모델로 2차 마스크를 판별하는 이차검증을 했다.
- 얼굴 랜드마크 감지
478개의 얼굴 특징 3D 좌표 값을 출력할 수 있다.
원래는 마스크 미착용 시 눈, 코, 입의 랜드마크 값을 구하고, 마스크 착용 시 코와 입의 랜드마크 값이 나오지 않는 것을 이용해 마스크 착용 여부를 판단하려고 했다.
하지만 마스크를 착용했음에도 코와 입을 인식해서 마스크를 착용하지 않았다고 했다.
그래서 다른 모델을 만들기로 결심했다.
- Mediapipe Pose
신체의 특징을 나타내는 33개의 신체 랜드마크 위치를 추적해서 신체의 대략적인 위치를 3D 좌표값을 나타낼 수 있다.
0 - nose
1 - left eye (inner)
2 - left eye
3 - left eye (outer)
4 - right eye (inner)
5 - right eye
6 - right eye (outer)
7 - left ear
8 - right ear
9 - mouth (left)
10 - mouth (right)
11 - left shoulder
12 - right shoulder
13 - left elbow
14 - right elbow
15 - left wrist
16 - right wrist
17 - left pinky
18 - right pinky
19 - left index
20 - right index
21 - left thumb
22 - right thumb
23 - left hip
24 - right hip
25 - left knee
26 - right knee
27 - left ankle
28 - right ankle
29 - left heel
30 - right heel
31 - left foot index
32 - right foot index
- 손 랜드마크 작업
21개의 손 랜드마크 값을 얻을 수 있다.
손의 제스처를 사용해 프로젝트를 진행한 팀이 꽤 있었다.
제스처로 암호를 만들어서 부원 인식 프로그램, 본인인증 등의 프로젝트가 있었다.
프로젝트 주제 : 실시간 안면 인식을 통한 마스크 착용 여부 검출
데이터셋 : AI-Hub
AI-Hub
샘플 데이터 ? ※샘플데이터는 데이터의 이해를 돕기 위해 별도로 가공하여 제공하는 정보로써 원본 데이터와 차이가 있을 수 있으며, 데이터에 따라서 민감한 정보는 일부 마스킹(*) 처리가 되
www.aihub.or.kr
데이터 용량이 너무 커서 테스트 이미지용으로는 샘플 데이터를, 학습 이미지용으로는 VS1이미지를 사용했다.
시간이 없어서 SPO폴더 안에 있는 정면 이미지로 사용하였다.
처음엔 미디어파이프의 얼굴 랜드마크 추출을 이용한 모델을 만들려고 했다.
코와 입의 랜드마크 값이 없으면 마스크 착용으로 인식하는 모델을 만들고 싶었는데, 마스크를 써도 코와 입을 인식했다.
그래서 계속 코드를 수정하다가 다른 방법을 찾게 되었는데, 시간이 너무 부족해서 또 욜로를 사용하였다. ((벌써 세 번째 ...))
익숙한 roboflow를 사용해 410장의 데이터를 빠르게 라벨링을 했다. 하도 많이 해서 그런가 혼자 했는데도 금방 끝났다.
이미지 크기는 224 사이즈로, 증강은 크롭+블러+노이즈를 해 980장까지 증강했다. 이미지가 좀 적은가? 싶었지만 어차피 정면만 인식하는 거니까 괜찮겠지..라고 생각하며 학습 모델을 돌렸다.
욜로 세번째만에 early stopping을 알게 되었다.
!yolo task=detect model=train model=yolov8s.pt data={dataset.location}/data.yaml epochs=100 imgsz=224 patience=10
맨 마지막에 있는 patience인데, 모델의 성능 개선이 10번동안 되지 않으면 멈추게 할 수 있다.
학습을 돌리고 최적의 모델인 best.pt가 나왔다. 54번째에 나왔다.
!yolo task=detect mode=predict model=/content/runs/detect/train/weights/best.pt conf=0.25 source=/content/test_images save=True imgsz=224
conf값을 매번 헷갈렸는데 이번에 정확하게 알게 되었다.
conf값은 얼마나 이 객체가 마스크라고 확신하는지에 대한 확률이다.
conf값이 높을수록 강한 확신을 할 때만 화면에 표시를 한다.
그래서 conf값을 0.25로 꽤 낮게 설정해 더 많은 결과를 표시할 수 있게 하였다.
미디어파이프와 결합하지 않고 욜로만 사용했을 때가 인식이 더 잘 되는 것 같은 느낌이다.
3초동안 마스크를 쓰지 않고 있으면 웹 소켓으로 알림을 보내는 기능도 있었는데 웹 서버의 주소가 나와서 그건 빼고 올리는 코드!
# Mediapipe + YOLO
import cv2
from ultralytics import YOLO
import mediapipe as mp
import time
# YOLOv8 모델 로드
model = YOLO("best.pt") # YOLOv8 모델 파일
# Mediapipe 초기화
mp_face_detection = mp.solutions.face_detection
mp_drawing = mp.solutions.drawing_utils
# 웹캠 열기
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("웹캠을 열 수 없습니다.")
exit()
print("웹캠 연결 성공. q 키를 눌러 종료하세요.")
# 깜빡임 상태 변수
show_wait = True
last_toggle_time = time.time()
with mp_face_detection.FaceDetection(min_detection_confidence=0.25) as face_detection:
while True:
ret, frame = cap.read()
if not ret:
print("프레임을 읽을 수 없습니다.")
break
# Mediapipe로 얼굴 탐지
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # Mediapipe는 RGB 이미지를 요구
results = face_detection.process(frame_rgb)
if results.detections:
for detection in results.detections:
# 얼굴 바운딩 박스 가져오기
bboxC = detection.location_data.relative_bounding_box
ih, iw, _ = frame.shape
x, y, w, h = (
int(bboxC.xmin * iw),
int(bboxC.ymin * ih),
int(bboxC.width * iw),
int(bboxC.height * ih),
)
# 얼굴 영역 크롭
face_roi = frame[y:y + h, x:x + w]
# 욜로 모델 이미지 리사이즈
face_roi_resized = cv2.resize(face_roi, (224, 224)) # YOLO 모델 학습 시 사용된 크기로 리사이즈
# YOLOv8 모델 추론 (얼굴 영역만)
results = model(face_roi_resized)
# 결과 시각화 및 처리
for result in results:
for box in result.boxes:
class_id = int(box.cls[0]) # 클래스 ID (0: no_mask, 1: with_mask)
confidence = box.conf[0] # 신뢰도
if class_id == 0: # No Mask
label = "No Mask"
color = (0, 0, 255) # 빨간색
cv2.putText(frame, "Please put on your mask", (50, 50),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
elif class_id == 1: # With Mask
label = "With Mask"
color = (0, 255, 0) # 초록색
cv2.putText(frame, "PASS", (50, 50),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
# 바운딩 박스와 라벨 그리기
cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2)
cv2.putText(frame, f"{label} ({confidence:.2f})", (x, y - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, color, 2)
else:
# 얼굴이 탐지되지 않은 경우 "Wait" 메시지 표시
current_time = time.time()
if current_time - last_toggle_time > 0.5:
show_wait = not show_wait
last_toggle_time = current_time
if show_wait:
cv2.putText(frame, "Wait", (220, 150),
cv2.FONT_HERSHEY_SIMPLEX, 4, (0, 0, 255), 3)
# 결과 화면 출력
cv2.imshow("Mask Detection", frame)
# q 키로 종료
if cv2.waitKey(1) & 0xFF == ord('q'):
print("프로그램 종료")
break
# 리소스 해제
cap.release()
cv2.destroyAllWindows()
이건 욜로만 사용해서 인식 짱짱 잘 되는 코드!
# 인식 안되면 Wait 뜨게 만든거
import cv2
from ultralytics import YOLO
import time
# YOLOv8 모델 로드
model = YOLO("best.pt") # YOLOv8 모델 파일
# 웹캠 열기
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("웹캠을 열 수 없습니다.")
exit()
print("웹캠 연결 성공. q 키를 눌러 종료하세요.")
# 깜빡임 상태 변수
show_wait = True
last_toggle_time = time.time()
while True:
ret, frame = cap.read()
if not ret:
print("프레임을 읽을 수 없습니다.")
break
# YOLOv8 모델 추론
results = model(frame)
# 결과 시각화 및 처리
for result in results:
for box in result.boxes:
# 바운딩 박스 좌표 및 클래스 ID
x1, y1, x2, y2 = map(int, box.xyxy[0]) # 바운딩 박스 좌표
class_id = int(box.cls[0]) # 클래스 ID (0: no_mask, 1: with_mask)
confidence = box.conf[0] # 신뢰도
if class_id == 0: # No Mask
label = "No Mask"
color = (0, 0, 255) # 빨간색
# 깜빡임 상태 토글 (0.5초마다)
current_time = time.time()
if current_time - last_toggle_time > 0.5: # 0.5초 간격으로 토글
show_wait = not show_wait
last_toggle_time = current_time
# "Wait" 메시지를 깜빡이도록 표시
if show_wait:
cv2.putText(frame, "wait", (220, 150),
cv2.FONT_HERSHEY_SIMPLEX, 4, (0, 0, 255), 3)
cv2.putText(frame, "please put on your mask", (120, 200),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
elif class_id == 1: # With Mask
label = "OK Mask"
color = (0, 255, 0) # 초록색
cv2.putText(frame, "PASS", (240, 170),
cv2.FONT_HERSHEY_SIMPLEX, 3, (0, 255, 0), 3)
# 바운딩 박스와 라벨 그리기
cv2.rectangle(frame, (x1, y1), (x2, y2), color, 2)
cv2.putText(frame, f"{label} ({confidence:.2f})", (x1, y1 - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, color, 2)
# 결과 화면 출력
cv2.imshow("Mask Detection", frame)
# q 키로 종료
if cv2.waitKey(1) & 0xFF == ord('q'):
print("프로그램 종료")
break
# 리소스 해제
cap.release()
cv2.destroyAllWindows()
미디어파이프로 모델이라도 만들었으면 뭔가 했다는 느낌이 들을 거 같은데 이번에도 욜로를 쓰고 코드는 거의 지피티가 짜주고 그래서.. 사실 이번 프로젝트 때 한 게 없다...
자잘자잘한 오류 고치는 데 시간을 거의 쓴 거 같다. 이것저것 시도도 꽤 많이 했는데 결국 다 실패 😭😭
데이터셋 150GB다운받느라 노트북 저장공간 부족으로 코드는 하나에서 계속 편집해서 이전 버전도 없고 ㅜㅜ
이제 데이터셋 다 지웠으니까 다음 프로젝트 할 때는 버전별로 잘 기록해둬야겠다,,,😭😭
그나마 배운 것을 생각하자면 나스라는 스토리지 처음 써본 것, 어떻게 하면 욜로 학습 더 잘 시키는 방법을 알게 되었다.
또, 좋은 팀원들을 만나서 다음주부터 시작할 보안 교육에서 모르는 것들을 도움받을 수 있을 거 같다!
그리구 프로젝트 기간에는 뭔갈 배워가는 시간이 아니라 내가 알고 있는 지식을 총집합해서 써먹는 기간이라는 것을 깨달았다.
평소에 열심히 하길...! 아자아자 😿
'파이썬스터디' 카테고리의 다른 글
개인정보 국외 이전에 대한 개인정보보호법 위반 사례 - 카카오페이&알리페이 (1) | 2025.02.22 |
---|---|
OWASP LLM Top 10 (2025) 각 취약점 예시, 대응 방안 (0) | 2025.02.07 |
Active Directory 취약점, 보안 사고 사례 (0) | 2025.01.21 |
12.1 unsupervised learning (비지도 학습) : k-means 알고리즘 (0) | 2024.11.14 |
캐글 타이타닉 필사 1. Dataset check (7) | 2024.09.28 |