와챠의 우당탕탕 코딩 일기장

[OpenCV] 얼굴인식 스노우 카메라 쉽게 따라만들기 / 사물인식 YOLO v4 실습하는 영상 본문

이런 저런 공부

[OpenCV] 얼굴인식 스노우 카메라 쉽게 따라만들기 / 사물인식 YOLO v4 실습하는 영상

minWachya 2023. 3. 22. 17:17
반응형

3.얼굴인식 스노우 카메라 쉽게 따라만들기 - Python

https://www.youtube.com/watch?v=tpWVyJqehG4 

 

# 사용할 라이브러리 선언
import cv2, dlib, sys
import numpy as np

# 영상 크기 10분의 3만큼 줄이기
scaler = 0.3

# detector 초기화
detector = dlib.get_frontal_face_detector()
# 학습된 모델 넣기
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')

# 영상 로드
# cv2.VideoCapture(0) 이면 웹캠
cap = cv2.VideoCapture('samples/A.mp4')
# 얼굴 위에 붙일 png 이미지 로드
overlay = cv2.imread('samples/ryan_transparent.png', cv2.IMREAD_UNCHANGED)

face_roi = []
face_sizes = []

# 무한 반복
while True:
  # 프레임 단위로 읽기
  ret, img = cap.read()
  # 영상 끝나면 종료
  if not ret:
    break

  # 프레임 10분의 3만큼 축소
  img = cv2.resize(img, (int(img.shape[1] * scaler), int(img.shape[0] * scaler)))
  # 원본 이미지 저장
  ori = img.copy()

  # 얼굴 찾기
  if len(face_roi) == 0:
    faces = detector(img, 1)
  else:
    roi_img = img[face_roi[0]:face_roi[1], face_roi[2]:face_roi[3]]
    # cv2.imshow('roi', roi_img)
    faces = detector(roi_img)

  # 얼굴 없을 경우
  if len(faces) == 0:
    print('no faces!')

  # 얼굴 특징점(랜드마크) 추출
  for face in faces:
    if len(face_roi) == 0:
      dlib_shape = predictor(img, face)
      shape_2d = np.array([[p.x, p.y] for p in dlib_shape.parts()])
    else:
      dlib_shape = predictor(roi_img, face)
      shape_2d = np.array([[p.x + face_roi[2], p.y + face_roi[0]] for p in dlib_shape.parts()])

	# 얼굴에 68개의 점 그리기
    for s in shape_2d:
      cv2.circle(img, center=tuple(s), radius=1, color=(255, 255, 255), thickness=2, lineType=cv2.LINE_AA)

    # 얼굴 중심 구하기
    center_x, center_y = np.mean(shape_2d, axis=0).astype(np.int)

    # compute face boundaries
    min_coords = np.min(shape_2d, axis=0)
    max_coords = np.max(shape_2d, axis=0)

    # draw min, max coords
    cv2.circle(img, center=tuple(min_coords), radius=1, color=(255, 0, 0), thickness=2, lineType=cv2.LINE_AA)
    cv2.circle(img, center=tuple(max_coords), radius=1, color=(255, 0, 0), thickness=2, lineType=cv2.LINE_AA)

    # 얼굴 크기 계산(자연스럽게 스티커 붙이기 위함)
    face_size = max(max_coords - min_coords)
    face_sizes.append(face_size)
    if len(face_sizes) > 10:
      del face_sizes[0]
    mean_face_size = int(np.mean(face_sizes) * 1.8)

    # compute face roi
    face_roi = np.array([int(min_coords[1] - face_size / 2), int(max_coords[1] + face_size / 2), int(min_coords[0] - face_size / 2), int(max_coords[0] + face_size / 2)])
    face_roi = np.clip(face_roi, 0, 10000)

    # 얼굴에 스티커 붙이기(자연스러운 위치 넣으려고 +8,  -25로 이동)
    result = overlay_transparent(ori, overlay, center_x + 8, center_y - 25, overlay_size=(mean_face_size, mean_face_size))

  # 원본, 랜드마크, 스티커 붙인 화면 출력
  cv2.imshow('original', ori)
  cv2.imshow('facial landmarks', img)
  cv2.imshow('result', result)
  if cv2.waitKey(1) == ord('q'):
    sys.exit(1)
    
# ----------
    
# 얼굴 가릴 스티커를 영상에 띄우는 함수
# background_img를 center x, center y, 중심으로 overlay_size사이즈만큼 리사이즈해서 영상에 붙여줌
def overlay_transparent(background_img, img_to_overlay_t, x, y, overlay_size=None):
  bg_img = background_img.copy()
  # convert 3 channels to 4 channels
  if bg_img.shape[2] == 3:
    bg_img = cv2.cvtColor(bg_img, cv2.COLOR_BGR2BGRA)

  if overlay_size is not None:
    img_to_overlay_t = cv2.resize(img_to_overlay_t.copy(), overlay_size)

  b, g, r, a = cv2.split(img_to_overlay_t)

  mask = cv2.medianBlur(a, 5)

  h, w, _ = img_to_overlay_t.shape
  roi = bg_img[int(y-h/2):int(y+h/2), int(x-w/2):int(x+w/2)]

  img1_bg = cv2.bitwise_and(roi.copy(), roi.copy(), mask=cv2.bitwise_not(mask))
  img2_fg = cv2.bitwise_and(img_to_overlay_t, img_to_overlay_t, mask=mask)

  bg_img[int(y-h/2):int(y+h/2), int(x-w/2):int(x+w/2)] = cv2.add(img1_bg, img2_fg)

  # convert 4 channels to 4 channels
  bg_img = cv2.cvtColor(bg_img, cv2.COLOR_BGRA2BGR)

  return bg_img

 

 

4.  사물인식 YOLO v4 실습하는 영상

https://www.youtube.com/watch?v=hxwEqXCgQO4 

 

import tensorflow as tf
import core.utils as utils
from tensorflow.python.saved_model import tag_constants
import cv2
import numpy as np

# config 상수화
MODEL_PATH = './checkpoints/yolov4-416'
IOU_THRESHOLD = 0.45
SCORE_THRESHOLD = 0.25
INPUT_SIZE = 416

# 모델 로드
saved_model_loaded = tf.saved_model.load(MODEL_PATH, tags=[tag_constants.SERVING])
infer = saved_model_loaded.signatures['serving_default']

def main(video_path):
	# 비디오 로드
	cap = cv2.VideoCapture(vidio_path)
    
    # 캡쳐가 오픈 되어있을 때까지 루프
    while cap.isOpend():
    	# 캡쳐 됐는지...
    	ret, img = cap.read()
        # 캡쳐 안 됐으면 끝
        if not ret:
        	breke

        # 전처리
        # 이미지 읽기
        img = cv2.imread(video_path)
        # 색 채널 변경
        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        # INPUT_SIZE만큼 리사이즈
        img_input = cv2.resize(img, (INPUT_SIZE, INPUT_SIZE))

        img_input = img_input / 255.
        # 차원 추가
        img_input = img_input[np.newaxis, ...].astype(np.float32)
        # 넘파이 배열을 텐서로 변경
        img_input = tf.constant(img_input)

        # 로드한 모델에 넣기
        pred_bbox = infer(img_input)

        # pred_bbox 후처리
        for key, value in pred_bbox.items():
            boxes = value[:, :, 0:4]
            pred_conf = value[:, :, 4:]

        # nms 사용해서 IOU_THRESHOLD 만큼 SCORE_THRESHOLD 넘는 것만 고르기
        boxes, scores, classes, valid_detections = tf.image.combined_non_max_suppression(
            boxes=tf.reshape(boxes, (tf.shape(boxes)[0], -1, 1, 4)),
            scores=tf.reshape(
                pred_conf, (tf.shape(pred_conf)[0], -1, tf.shape(pred_conf)[-1])),
            max_output_size_per_class=50,
            max_total_size=50,
            iou_threshold=IOU_THRESHOLD,
            score_threshold=SCORE_THRESHOLD
        )

        # 기준 넘는 거 박스 그리기
        pred_bbox = [boxes.numpy(), scores.numpy(), classes.numpy(), valid_detections.numpy()]
        result = utils.draw_bbox(img, pred_bbox)

        # 출력
        result = cv2.cvtColor(np.array(result), cv2.COLOR_RGB2BGR)

        cv2.imshow('result.png', result)
        if cv2.waitKey('q') == ord('q'):
            break

if __name__ == '__main__':
    img_path = './data/A.mp4'
    main(img_path)

....

반응형
Comments