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

[Python][AI] OpenCV YuNet์„ ํ™œ์šฉํ•œ ๋™์˜์ƒ ์–ผ๊ตด ๋ชจ์ž์ดํฌ ์ฒ˜๋ฆฌ

5hr1rnp 2025. 2. 17. 23:59
๋ฐ˜์‘ํ˜•

OpenCV YuNet Mosaic Result โ˜ ์ถœ์ฒ˜ : https://pixabay.com/ko/videos/ํšŒ์˜-์ผ๋ณธ-์ผํ•˜๋‹ค-์‚ฌ๋žŒ๋“ค-34685/

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

2025.02.17 - [๊ฐœ๋ฐœ Code/์ธ๊ณต์ง€๋Šฅ A.I.] - [Python][AI] OpenCV YuNet์„ ํ™œ์šฉํ•œ ์–ผ๊ตด ํƒ์ง€

2025.02.17 - [๊ฐœ๋ฐœ Code/์ธ๊ณต์ง€๋Šฅ A.I.] - [Python][AI] OpenCV YuNet์„ ํ™œ์šฉํ•œ ์–ผ๊ตด ๋ชจ์ž์ดํฌ ์ฒ˜๋ฆฌ

 

1. ๋™์˜์ƒ ์–ผ๊ตด ๋ชจ์ž์ดํฌ ๊ฐœ์š”


์ด์ „ ๊ธ€์—์„œ๋Š” ์ •์ ์ธ ์ด๋ฏธ์ง€ ๋˜๋Š” ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ์–ผ๊ตด์„ ํƒ์ง€ํ•˜๊ณ  ๋ชจ์ž์ดํฌ๋ฅผ ์ ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋‹ค๋ฃจ์—ˆ๋‹ค. ์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ๋™์˜์ƒ์—์„œ ์–ผ๊ตด์„ ์ž๋™์œผ๋กœ ํƒ์ง€ํ•˜๊ณ  ๋ชจ์ž์ดํฌ๋ฅผ ์ ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋‹ค๋ฃฌ๋‹ค.

OpenCV์˜ YuNet ์–ผ๊ตด ํƒ์ง€ ๋ชจ๋ธ์„ ํ™œ์šฉํ•˜์—ฌ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์–ผ๊ตด์„ ๊ฐ์ง€ํ•˜๊ณ , ํ•ด๋‹น ์˜์—ญ์„ ๋ชจ์ž์ดํฌ ์ฒ˜๋ฆฌํ•œ ํ›„ ์ƒˆ๋กœ์šด ๋™์˜์ƒ์„ ์ €์žฅํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ง„ํ–‰ํ•œ๋‹ค.


2. ์‹คํ–‰ ํ™˜๊ฒฝ ์ค€๋น„


(1) OpenCV ์„ค์น˜

YuNet์„ ํ™œ์šฉํ•˜๊ธฐ ์œ„ํ•ด opencv-python ์„ค์น˜

pip install opencv-python

 

 

(2) ๋™์˜์ƒ ๋‹ค์šด๋กœ๋“œ

๋งํฌ : https://pixabay.com/ko/videos/ํšŒ์˜-์ผ๋ณธ-์ผํ•˜๋‹ค-์‚ฌ๋žŒ๋“ค-34685/

 

https://pixabay.com/ko/videos/ํšŒ์˜-์ผ๋ณธ-์ผํ•˜๋‹ค-์‚ฌ๋žŒ๋“ค-34685/

3. YuNet ์–ผ๊ตด ํƒ์ง€ ๋ชจ๋ธ ๋‹ค์šด๋กœ๋“œ


YuNet ๋ชจ๋ธ์ด ์—†์„ ๊ฒฝ์šฐ ์ž๋™์œผ๋กœ ๋‹ค์šด๋กœ๋“œํ•˜๋„๋ก ์„ค์ •ํ•จ.

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}")

 


4. ์–ผ๊ตด ํƒ์ง€ ๋ฐ ๋ชจ์ž์ดํฌ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜


YuNet์„ ์‚ฌ์šฉํ•˜์—ฌ ๋™์˜์ƒ ํ”„๋ ˆ์ž„์—์„œ ์–ผ๊ตด์„ ํƒ์ง€ํ•˜๊ณ , ๋ชจ์ž์ดํฌ ํšจ๊ณผ๋ฅผ ์ ์šฉํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•จ.

import cv2 as cv
import numpy as np

# ์–ผ๊ตด ๊ฒ€์ถœ๊ธฐ ์ƒ์„ฑ ํ•จ์ˆ˜
def create_face_detector(frame_width, frame_height):
    detector = cv.FaceDetectorYN.create(
        model=model_filename,
        config="",
        input_size=(frame_width, frame_height),  # ์ž…๋ ฅ ํฌ๊ธฐ ์„ค์ •
        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
    )
    return detector

# ๋ชจ์ž์ดํฌ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜
def apply_mosaic(img, bbox, scale=0.1):
    x, y, w_box, h_box = bbox[:4].astype(int)
    x = max(0, x)
    y = max(0, y)
    w_box = min(w_box, img.shape[1] - x)
    h_box = min(h_box, img.shape[0] - y)
    if w_box <= 0 or h_box <= 0:
        return img
    face_region = img[y:y+h_box, x:x+w_box]
    # downscale ํ›„ upscaleํ•˜์—ฌ ๋ชจ์ž์ดํฌ ํšจ๊ณผ ์ ์šฉ
    small = cv.resize(face_region, None, fx=scale, fy=scale, interpolation=cv.INTER_LINEAR)
    mosaic = cv.resize(small, (w_box, h_box), interpolation=cv.INTER_NEAREST)
    img[y:y+h_box, x:x+w_box] = mosaic
    return img

 


728x90
๋ฐ˜์‘ํ˜•

5. ๋™์˜์ƒ ์–ผ๊ตด ๋ชจ์ž์ดํฌ ์ฒ˜๋ฆฌ


์ด์ œ ํŠน์ • ๋™์˜์ƒ์—์„œ ์–ผ๊ตด์„ ํƒ์ง€ํ•˜๊ณ  ๋ชจ์ž์ดํฌ๋ฅผ ์ ์šฉํ•œ ํ›„ ์ƒˆ๋กœ์šด ๋™์˜์ƒ์œผ๋กœ ์ €์žฅํ•˜๋Š” ์ฝ”๋“œ์ž„.

# ๋™์˜์ƒ ์–ผ๊ตด ๋ชจ์ž์ดํฌ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜
def process_video(video_path, output_video_path, mosaic_scale=0.1):
    cap = cv.VideoCapture(video_path)
    if not cap.isOpened():
        raise ValueError(f"๋™์˜์ƒ์„ ์—ด ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {video_path}")

    # ๋™์˜์ƒ ์ •๋ณด ํš๋“
    frame_width = int(cap.get(cv.CAP_PROP_FRAME_WIDTH))
    frame_height = int(cap.get(cv.CAP_PROP_FRAME_HEIGHT))
    fps = cap.get(cv.CAP_PROP_FPS)
    frame_count = int(cap.get(cv.CAP_PROP_FRAME_COUNT))
    print(f"๋™์˜์ƒ ์ •๋ณด: {frame_width}x{frame_height}, {fps} FPS, ์ด {frame_count} ํ”„๋ ˆ์ž„")

    # ๋™์˜์ƒ ์ €์žฅ ๊ฐ์ฒด ์ƒ์„ฑ
    fourcc = cv.VideoWriter_fourcc(*"mp4v")
    out = cv.VideoWriter(output_video_path, fourcc, fps, (frame_width, frame_height))

    # ์–ผ๊ตด ํƒ์ง€๊ธฐ ์ƒ์„ฑ
    face_detector = create_face_detector(frame_width, frame_height)

    # ๋™์˜์ƒ ํ”„๋ ˆ์ž„ ์ฒ˜๋ฆฌ
    frame_idx = 0
    while True:
        ret, frame = cap.read()
        if not ret:
            break

        # ๊ฐ ํ”„๋ ˆ์ž„์— ๋Œ€ํ•ด ์–ผ๊ตด ๊ฒ€์ถœ ์ˆ˜ํ–‰
        face_detector.setInputSize((frame.shape[1], frame.shape[0]))
        ret_detect, results = face_detector.detect(frame)
        if results is None:
            results = np.empty((0, 5))

        # ๊ฒ€์ถœ๋œ ์–ผ๊ตด์— ๋Œ€ํ•ด ๋ชจ์ž์ดํฌ ์ ์šฉ
        for det in results:
            frame = apply_mosaic(frame, det, mosaic_scale)

        # ์ฒ˜๋ฆฌ๋œ ํ”„๋ ˆ์ž„์„ ์ €์žฅ
        out.write(frame)

        frame_idx += 1
        if frame_idx % 30 == 0:
            print(f"{frame_idx}/{frame_count} ํ”„๋ ˆ์ž„ ์ฒ˜๋ฆฌ๋จ.")

    # ์ž์› ํ•ด์ œ
    cap.release()
    out.release()
    cv.destroyAllWindows()
    print(f"๋ชจ์ž์ดํฌ ์ฒ˜๋ฆฌ ๋™์˜์ƒ ์ €์žฅ ์™„๋ฃŒ: {output_video_path}")

# ์‹คํ–‰ (๋™์˜์ƒ ์ฒ˜๋ฆฌ)
video_path = "34685-403408160_small.mp4"  # ์›๋ณธ ๋™์˜์ƒ ํŒŒ์ผ
output_video_path = "output_video.mp4"  # ๋ชจ์ž์ดํฌ ์ฒ˜๋ฆฌ๋œ ๋™์˜์ƒ ํŒŒ์ผ
process_video(video_path, output_video_path)
 

์„ค๋ช…

  • cv.VideoCapture(video_path): ๋™์˜์ƒ ํŒŒ์ผ์„ ๋ถˆ๋Ÿฌ์˜ด
  • cv.VideoWriter(): ์ƒˆ๋กœ์šด ๋™์˜์ƒ ํŒŒ์ผ์„ ์ƒ์„ฑ
  • face_detector.detect(frame): ๊ฐ ํ”„๋ ˆ์ž„์—์„œ ์–ผ๊ตด ํƒ์ง€ ์ˆ˜ํ–‰
  • apply_mosaic(frame, det, mosaic_scale): ์–ผ๊ตด์— ๋ชจ์ž์ดํฌ ์ ์šฉ
  • out.write(frame): ์ฒ˜๋ฆฌ๋œ ํ”„๋ ˆ์ž„์„ ์ €์žฅ

6. ๊ฒฐ๊ณผ ํ™•์ธ


์ด์ œ ์‹คํ–‰ํ•˜๋ฉด ์›๋ณธ ๋™์˜์ƒ์˜ ์–ผ๊ตด ๋ถ€๋ถ„์ด ์ž๋™์œผ๋กœ ๋ชจ์ž์ดํฌ ์ฒ˜๋ฆฌ๋˜์–ด ์ƒˆ๋กœ์šด ๋™์˜์ƒ์ด ์ƒ์„ฑ๋จ.

 

๊ฒฐ๊ณผ ํŒŒ์ผ
โœ… ์ถœ๋ ฅ ๋™์˜์ƒ: output_video.mp4

 

 

OpenCV YuNet Face Detection Mosaic Result

7. ๊ฒฐ๋ก 


โœ… YuNet์„ ํ™œ์šฉํ•˜์—ฌ ๋™์˜์ƒ์—์„œ ์–ผ๊ตด์„ ์ž๋™์œผ๋กœ ํƒ์ง€ํ•˜๊ณ  ๋ชจ์ž์ดํฌ๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Œ.
โœ… ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋™์˜์ƒ์„ ์ฒ˜๋ฆฌํ•˜๋ฉด์„œ๋„ ๋น ๋ฅด๊ฒŒ ๋™์ž‘ํ•จ.
โœ… MP4 ํ˜•์‹์œผ๋กœ ์ €์žฅ ๊ฐ€๋Šฅํ•˜๋ฉฐ, ์›๋ณธ ๋™์˜์ƒ์˜ ํ•ด์ƒ๋„์™€ FPS๋ฅผ ์œ ์ง€ํ•จ.

 

๋ฐ˜์‘ํ˜•