1. YuNet์ ์ด์ฉํ ์ผ๊ตด ํ์ง ๊ฐ์
OpenCV๋ ๊ฐ๋ ฅํ ์ด๋ฏธ์ง ์ฒ๋ฆฌ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ฉฐ, cv2.FaceDetectorYN์ ์ด์ฉํ๋ฉด ๋ฅ๋ฌ๋ ๊ธฐ๋ฐ ์ผ๊ตด ํ์ง๋ฅผ ๊ฐ๋จํ๊ฒ ์ํํ ์ ์๋ค. ์ด๋ฒ ๊ธ์์๋ OpenCV์ YuNet ๋ชจ๋ธ์ ์ฌ์ฉํ์ฌ ์ด๋ฏธ์ง์์ ์ผ๊ตด์ ํ์งํ๋ ๋ฐฉ๋ฒ์ ๋ค๋ฃฌ๋ค.
2. ์คํ ํ๊ฒฝ ์ค๋น
(1) OpenCV ์ค์น
YuNet์ ์ฌ์ฉํ๋ ค๋ฉด opencv-python ํจํค์ง๋ง ์ค์นํ๋ฉด ๋จ. Jupyter Notebook์์ ๋ค์ ๋ช ๋ น์ด๋ฅผ ์คํํ์ฌ ์ค์นํ ์ ์์.
pip install opencv-python
์ค์น๊ฐ ์๋ฃ๋๋ฉด, OpenCV ๋ฒ์ ์ ํ์ธํ์ฌ ์ ์์ ์ผ๋ก ์ค์น๋์๋์ง ํ์ธํ ์ ์์.
import cv2
print(cv2.__version__)
# 4.11.0
3. YuNet ์ผ๊ตด ํ์ง ๋ชจ๋ธ ๋ค์ด๋ก๋
YuNet์ OpenCV์์ ์ ๊ณตํ๋ ONNX ๋ชจ๋ธ์ ์ฌ์ฉํ์ฌ ์ผ๊ตด์ ํ์งํจ. ๋ชจ๋ธ์ด ์์ ๊ฒฝ์ฐ, ์๋์ผ๋ก ๋ค์ด๋ก๋ํ์ฌ ์ฌ์ฉํ ์ ์๋๋ก ์ค์ ํ ๊ฒ์.
import os
import requests
# YuNet ๋ชจ๋ธ ํ์ผ ์ค์
model_filename = "face_detection_yunet_2023mar.onnx"
# ๋ชจ๋ธ ํ์ผ์ด ์์ ๊ฒฝ์ฐ ๋ค์ด๋ก๋
if not os.path.exists(model_filename):
url = "https://github.com/opencv/opencv_zoo/raw/main/models/face_detection_yunet/face_detection_yunet_2023mar.onnx"
print("YuNet ๋ชจ๋ธ ํ์ผ์ด ์์ต๋๋ค. ๋ค์ด๋ก๋๋ฅผ ์งํํฉ๋๋ค...")
response = requests.get(url, allow_redirects=True)
if response.status_code == 200:
with open(model_filename, "wb") as f:
f.write(response.content)
print("๋ชจ๋ธ ๋ค์ด๋ก๋ ์๋ฃ.")
else:
raise RuntimeError(f"๋ชจ๋ธ ๋ค์ด๋ก๋ ์คํจ: HTTP ์ํ ์ฝ๋ {response.status_code}")
์ค๋ช
- requests.get(url): YuNet ๋ชจ๋ธ ๋ค์ด๋ก๋
- os.path.exists(model_filename): ํ์ผ์ด ์กด์ฌํ๋์ง ํ์ธ
- with open(model_filename, "wb") as f: f.write(response.content): ๋ชจ๋ธ ์ ์ฅ
์ด์ ์ผ๊ตด ํ์ง๋ฅผ ์ํํ ์ค๋น๊ฐ ์๋ฃ๋จ.
4. ์ด๋ฏธ์ง ๋ถ๋ฌ์ค๊ธฐ
์ด๋ฒ ์์ ์์๋ Pixabay์์ ์ ๊ณตํ๋ ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฉํจ. ์ฌ์ง ๋ค์ด๋ก๋ ๋งํฌ
ํด๋น ์ฌ์ง์ ๋ค์ด๋ก๋ํ ํ, ๊ฐ์ ๋๋ ํ ๋ฆฌ์ ์ฌ์ง์ ์ฎ๊ฒจ๋์ ํ ๋ค์ ์ฝ๋ ์งํ.
๋ค์๊ณผ ๊ฐ์ ์ฝ๋๋ก ์ด๋ฏธ์ง๋ฅผ ๋ถ๋ฌ์ฌ ์ ์์.
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
# ์ด๋ฏธ์ง ํ์ผ ๊ฒฝ๋ก ์ค์
image_path = "portrait-5601950_1280.jpg"
# ์ด๋ฏธ์ง ๋ถ๋ฌ์ค๊ธฐ
image = cv.imread(image_path)
if image is None:
raise ValueError(f"์ด๋ฏธ์ง๋ฅผ ๋ถ๋ฌ์ฌ ์ ์์ต๋๋ค: {image_path}")
# ์ด๋ฏธ์ง ํฌ๊ธฐ ํ์ธ
h, w, _ = image.shape
print(f"์ด๋ฏธ์ง ํฌ๊ธฐ: {w}x{h}")
# ์ด๋ฏธ์ง ํฌ๊ธฐ: 834x1280
์ค๋ช
- cv.imread(image_path): ์ด๋ฏธ์ง๋ฅผ ๋ถ๋ฌ์ด
- image.shape: ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ ์ถ๋ ฅํ์ฌ ํ์ธ
5. YuNet์ ์ด์ฉํ ์ผ๊ตด ํ์ง
์ด์ OpenCV์ cv.FaceDetectorYN์ ์ฌ์ฉํ์ฌ ์ผ๊ตด์ ํ์งํ ๊ฒ์.
# ์ผ๊ตด ๊ฒ์ถ๊ธฐ ์์ฑ
face_detector = cv.FaceDetectorYN.create(
model=model_filename,
config="",
input_size=(w, h),
score_threshold=0.9,
nms_threshold=0.3,
top_k=5000,
backend_id=cv.dnn.DNN_BACKEND_OPENCV,
target_id=cv.dnn.DNN_TARGET_CPU
)
# ์
๋ ฅ ํฌ๊ธฐ ์ค์
face_detector.setInputSize((w, h))
# ์ผ๊ตด ํ์ง ์ํ
ret, results = face_detector.detect(image)
# ํ์ง๋ ์ผ๊ตด ๊ฐ์ ์ถ๋ ฅ
if results is None:
results = np.empty((0, 5))
print(f"{results.shape[0]} ๊ฐ์ ์ผ๊ตด ๊ฒ์ถ๋จ.")
# 1 ๊ฐ์ ์ผ๊ตด ๊ฒ์ถ๋จ.
์ค๋ช
- cv.FaceDetectorYN.create(): YuNet ๋ชจ๋ธ์ ๋ก๋ํ์ฌ ์ผ๊ตด ํ์ง๊ธฐ๋ฅผ ์์ฑ
- face_detector.setInputSize((w, h)): ์ ๋ ฅ ์ด๋ฏธ์ง ํฌ๊ธฐ ์ค์
- face_detector.detect(image): ์ผ๊ตด ํ์ง ์ํ
- results.shape[0]: ๊ฒ์ถ๋ ์ผ๊ตด ๊ฐ์ ์ถ๋ ฅ
6. ์ผ๊ตด ํ์ง ๊ฒฐ๊ณผ ํ์
๊ฒ์ถ๋ ์ผ๊ตด์ ์ด๋ฏธ์ง์ ๊ทธ๋ ค์ ํ์ธํด ๋ณด๊ฒ ์.
# ์ผ๊ตด์ ๊ฐ์ธ๋ ์ฌ๊ฐํ ๊ทธ๋ฆฌ๊ธฐ
for det in results:
x, y, w_box, h_box = det[:4].astype(int)
cv.rectangle(image, (x, y), (x + w_box, y + h_box), (0, 255, 0), 2)
# ๊ฒฐ๊ณผ ์ถ๋ ฅ (Jupyter Notebook)
plt.figure(figsize=(10, 10))
plt.imshow(cv.cvtColor(image, cv.COLOR_BGR2RGB))
plt.axis("off")
plt.show()
์ค๋ช
- cv.rectangle(image, (x, y), (x + w_box, y + h_box), (0, 255, 0), 2): ์ผ๊ตด์ ๊ฐ์ธ๋ ๋ฐ์ค ๊ทธ๋ฆฌ๊ธฐ
- plt.imshow(cv.cvtColor(image, cv.COLOR_BGR2RGB)): OpenCV์ BGR ์ด๋ฏธ์ง๋ฅผ RGB๋ก ๋ณํํ์ฌ ์ถ๋ ฅ
- plt.axis("off"): ์ถ์ ์ ๊ฑฐํ์ฌ ๋ณด๊ธฐ ์ฝ๊ฒ ์ถ๋ ฅ
7. ๊ฒฐ๋ก
โ
YuNet์ ์ฌ์ฉํ์ฌ Jupyter Notebook์์ ์ผ๊ตด ํ์ง๋ฅผ ์ฝ๊ฒ ์ํํ ์ ์์.
โ
๋ณ๋์ ์ถ๊ฐ ์ค์น ์์ด OpenCV๋ง์ผ๋ก ๋์ ๊ฐ๋ฅ.
โ
ONNX ๋ชจ๋ธ์ ๋ค์ด๋ก๋ํ์ฌ ๊ฐํธํ๊ฒ ํ์ฉ ๊ฐ๋ฅ.
๋ค์ ๊ธ์์๋ ํ์ง๋ ์ผ๊ตด์ ๋ชจ์์ดํฌ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ๋ค๋ฃฐ ์์ ์.