Django와 openCV로 얼굴에 스티커 붙이기

Ahyeon, Jung·2023년 9월 21일
post-thumbnail

OpenCV

Open Source Computer Vision Library
오픈 소스 컴퓨터 비전 및 머신 러닝 라이브러리
실시간 이미지 처리, 객체 검출, 얼굴 인식, 자동차 번호판 인식, 동작 인식 등 다양한 컴퓨터 비전 작업을 수행하는데 사용

  • 영상 처리: 이미지의 필터링, 변환, 크기 조정, 회전, 히스토그램 분석 등과 같은 영상 처리 작업을 지원
  • 특징 검출 및 기술자(Descriptor) 추출: SIFT, SURF, ORB와 같은 특징 검출 및 기술자 추출 알고리즘을 제공하여 객체 인식 및 매칭에 사용
  • 객체 검출: 얼굴 검출, 물체 검출, 동작 검출과 같은 객체 검출 작업을 위한 다양한 알고리즘 지원
  • 머신 러닝: 머신 러닝 모델을 훈련하고 사용하는데 필요한 기능 지원. 딥러닝 프레임워크와 통합 가능
  • 카메라 캘리브레이션: 카메라 렌즈 왜곡을 보정하는데 사용. 컴퓨터 비전 작업의 정확성을 향상시킴
  • 비디오 스트림 처리 및 분석을 위한 기능을 제공
  • 실시간 이미지 및 비디오 스트림 처리를 지원하므로 실시간 응용 프로그램 개발에 적합

Computer Vision

컴퓨터와 디지털 이미지 또는 비디오를 사용하여 시각적 정보를 처리, 해석 및 이해하는 분야
컴퓨터를 사용하여 이미지나 비디오 데이터에서 패턴, 객체, 얼굴, 텍스트 등을 자동으로 인식하고 이해하는 기술을 개발하는데 중점

웹캠에서 openCV 사용하기

주피터 노트북의 경우, 가상환경 및 GPU를 따로 설치할 필요없이 진행가능해서 편리
최근 구글 코랩으로 넘어가는 느낌

웹캠 오픈

import cv2
import numpy as np

# 웹캠을 오픈
cap = cv2.VideoCapture(0)

# 얼굴을 감지하는 tool
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')

스티커 붙이기

# 스티커 이미지 가져오기
sticker = cv2.imread('face.png', cv2.IMREAD_UNCHANGED)

while True:
    ret, frame = cap.read()  # 웹캠을 읽음

    if not ret:
        break

    # 영상을 흑백으로 변환
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # 영상에서 얼굴 감지
    faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))

    # 해당 인식된 부분에 스티커 이미지를 합성하기
    for (x, y, w, h) in faces:
        # 얼굴 주위에 이미지를 합성하기 위한 좌표
        x_offset = x
        y_offset = y - int(h * 0.2) 

        # 이미지 크기 조정 (얼굴 크기에 맞춤)
        sticker = cv2.resize(sticker, (w, h))

        # 합성할 영역 선택
        roi = frame[y_offset:y_offset + sticker.shape[0], x_offset:x_offset + sticker.shape[1]]

        # 실제로 스티커이미지 합성
        for c in range(0, 3):
            roi[:, :, c] = roi[:, :, c] * (1 - sticker[:, :, 3] / 255.0) + sticker[:, :, c] * (sticker[:, :, 3] / 255.0)

    # 영상 표시
    cv2.imshow('Look at Your Face', frame)

    # 'q' 키를 누르면 종료
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# 작업이 끝나면 웹캠 해제
cap.release()
cv2.destroyAllWindows()

Django에서 openCV 사용하기

가상환경활성화 과정 필요

출력화면 생성

// 이미지 input 화면
<!DOCTYPE html>
<html>
  <head>
    <title>이미지를 처리해보도록 하자</title>
  </head>
  <body>
    <form method="post" enctype="multipart/form-data">
      {% csrf_token %}
      <label for="image">이미지 업로드를 하세요!</label>
      <input type="file" name="image" required />
      <br />
      <input type="submit" value="업로드" />
    </form>
  </body>
</html>

// 이미지 처리 이후 출력 화면
<!DOCTYPE html>
<html>
  <head>
    <title>이미지를 보여주도록 하자</title>
  </head>
  <body>
    <h1>업로드한 이미지</h1>
    <img src="{{ image_url }}" alt="업로드한 이미지" />
  </body>
</html>

이미지 처리 후 렌더링

def index(request):
    uploaded_image = request.FILES.get("image")
    if uploaded_image:
        sticker_image = apply_sticker(uploaded_image)

        image_instance = ImageModel()

        image_instance.save_image_from_bytes(sticker_image, "sticker_image.jpeg")

        image_url = image_instance.get_image_url()

        response = HttpResponse(sticker_image, content_type="image/jpeg")
        return render(
            request, "image.html", {"image_url": image_url, "image_response": response}
        )

    else:
        return render(request, "index.html")

실제 이미지 처리

def apply_sticker(image_data):
    image = cv2.imdecode(np.frombuffer(image_data.read(), np.uint8), cv2.IMREAD_COLOR)

    face_cascade = cv2.CascadeClassifier(
        cv2.data.haarcascades + "haarcascade_frontalface_default.xml"
    )

    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    faces = face_cascade.detectMultiScale(
        gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30)
    )

    sticker = cv2.imread("./face.png", -1)

    if sticker is not None:
        for x, y, w, h in faces:
            sticker_resized = cv2.resize(sticker, (w, h))

            for c in range(0, 3):
                image[y : y + h, x : x + w, c] = image[y : y + h, x : x + w, c] * (
                    1 - sticker_resized[:, :, 3] / 255.0
                ) + sticker_resized[:, :, c] * (sticker_resized[:, :, 3] / 255.0)
    else:
        print("스티커 이미지를 읽어올 수 없습니다.")

    _, encoded_image = cv2.imencode(".jpeg", image)
    return encoded_image.tobytes()

결과

profile
https://a-honey.tistory.com/

0개의 댓글