๊ฐœ๋ฐœ Code/์ธ๊ณต์ง€๋Šฅ A.I.

[Python][AI] OpenCV YuNet์„ ํ™œ์šฉํ•œ ์–ผ๊ตด ํƒ์ง€

5hr1rnp 2025. 2. 17. 22:15
๋ฐ˜์‘ํ˜•

์ถœ์ฒ˜ : https://pixabay.com/ko/photos/

2025.02.17 - [๊ฐœ๋ฐœ Code/์ธ๊ณต์ง€๋Šฅ A.I.] - [Python][AI] OpenCV: ์ปดํ“จํ„ฐ ๋น„์ „ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์†Œ๊ฐœ

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): ๋ชจ๋ธ ์ €์žฅ

์ด์ œ ์–ผ๊ตด ํƒ์ง€๋ฅผ ์ˆ˜ํ–‰ํ•  ์ค€๋น„๊ฐ€ ์™„๋ฃŒ๋จ.


728x90
๋ฐ˜์‘ํ˜•

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"): ์ถ•์„ ์ œ๊ฑฐํ•˜์—ฌ ๋ณด๊ธฐ ์‰ฝ๊ฒŒ ์ถœ๋ ฅ

OpenCV YuNet Face Detection Result

 


7. ๊ฒฐ๋ก 


โœ… YuNet์„ ์‚ฌ์šฉํ•˜์—ฌ Jupyter Notebook์—์„œ ์–ผ๊ตด ํƒ์ง€๋ฅผ ์‰ฝ๊ฒŒ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Œ.
โœ… ๋ณ„๋„์˜ ์ถ”๊ฐ€ ์„ค์น˜ ์—†์ด OpenCV๋งŒ์œผ๋กœ ๋™์ž‘ ๊ฐ€๋Šฅ.
โœ… ONNX ๋ชจ๋ธ์„ ๋‹ค์šด๋กœ๋“œํ•˜์—ฌ ๊ฐ„ํŽธํ•˜๊ฒŒ ํ™œ์šฉ ๊ฐ€๋Šฅ.

 

๋‹ค์Œ ๊ธ€์—์„œ๋Š” ํƒ์ง€๋œ ์–ผ๊ตด์„ ๋ชจ์ž์ดํฌ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋‹ค๋ฃฐ ์˜ˆ์ •์ž„.

๋ฐ˜์‘ํ˜•