반응형

@23_사진에서 얼굴 찾아 모자이크 하기

 

- 드디어 OpenCV 를 써 본다.

- Python에서 비주얼 한 프로그램을 만드는 것. 

- 뭐 별게 있겠냐마는 왠지 모르게 비주얼 프로그램에 대한 두려움(?) 같은게 있었다.

- 써 보니 쉽네. 예전에 맬랩(MatLab) 썼던 느낌이랄까? 

 

1. 얼굴이 여러 개 나온 사진에서 얼굴과 눈을 찾아 표시하기

2. 얼굴을 모자이크 처리하기


1. 이미지에서 얼굴과 눈 찾기

import numpy as np
import cv2

# 얼굴 찾는 함수
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
# 눈 찾는 함수
eye_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_eye.xml')

# 한글이 있는 경로를 못 읽어와서 numpy 사용
ff = np.fromfile(r'기초프로그램\23_mosaic\sampleImg.jpg', np.uint8)
# np로 읽어온 파일에서 이미지를 변환하지 않고 가져오기
img = cv2.imdecode(ff, cv2.IMREAD_UNCHANGED)

# 리사이징인데, fx, fy (변환율 가로,세로)가 1.0 이므로 그대로 가져옴)
# 보간방법은 INTER_LINEAR(옆에 있는 픽셀값 그대로 가져오는 것)
img = cv2.resize(img, dsize=(0,0), fx=1.0, fy=1.0, interpolation=cv2.INTER_LINEAR)
# 회색조로 변환 - BGR은 Blue, Green, Red (RGB가 아니라 BGR)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)


# 얼굴 여러개 찾기
faces = face_cascade.detectMultiScale(gray, 1.2,5)

# 찾은 얼굴의 범위가 나옴(좌상단 좌표와 크기(w, h))
for (x,y,w,h) in faces:
    
    # 얼굴범위를 색상값 BGR(255, 0, 0) = Blue, 두께 2, 네모칸 그림
    # cv는 왜 RGB가 아니라 BGR로 하는지 모르겠네요 ...
    cv2.rectangle(img, (x,y), (x+w, y+h), (255,0,0), 2)
    
    #roi : Region Of Interest (관심영역) 
    # 그레이 스케일로 바꾼 이미지의 관심영역 (얼굴 1개)
    roi_gray = gray[y:y+h, x:x+w]

    # 원래 이미지의 관심영역 (얼굴 1개)
    roi_color = img[y:y+h, x:x+w]

    # 그레이 이미지 관심영역(현재 선택된 얼굴) 에서 눈 찾기
    eyes = eye_cascade.detectMultiScale(roi_gray)
    for(ex, ey, ew, eh) in eyes:

        # 찾은 위치 그래로 원래 이미지에 초록색 사각형으로 표시하기
        cv2.rectangle(roi_color, (ex, ey), (ex+ew, ey+eh), (0,255,0), 2)

        
# 윈도우 창을 열어 이미지를 보여준다. 창 이름은 'face find'        
cv2.imshow('face find', img)
# 키 입력을 기다렸다가
cv2.waitKey(0)
# 키 입력 받으면 모든 윈도우 닫기
cv2.destroyAllWindows()

결과.


2. 얼굴 하나하나 찾아서 모자이크 처리하기

- 모자이크 처리방법

 1> 얼굴 이미지를 찾아서

 2> 이미지를 우선 축소시킨다 - 이 때 이미 픽섹들이 날아간다.

 3> 축소되었던 이미지를 원래 크기로 키운다 - 이 때 비어있는 픽셀들을 선택한 보간법에 따라 채운다.

import numpy as np
import cv2

face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
eye_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_eye.xml')

ff = np.fromfile(r'기초프로그램\23_mosaic\sampleImg.jpg', np.uint8)
img = cv2.imdecode(ff, cv2.IMREAD_UNCHANGED)
img = cv2.resize(img, dsize=(0,0), fx=1.0, fy=1.0, interpolation=cv2.INTER_LINEAR)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)


# 얼굴 여러개 찾기
faces = face_cascade.detectMultiScale(gray, 1.2,5)

# 얼굴 축소 비율
fx = 0.05
fy = 0.05

for (x,y,w,h) in faces:
        
    print(f'얼굴가로 : {w}px\t축소가로(w*fx 반올림) : {round(w*fx)}px\n얼굴세로 : {h}px\t축소세로(h*fy 반올림) : {round(h*fy)}px\n\n')
    
    # 현재 선택된 얼굴
    face_img = img[y:y+h, x:x+w]

    # 현재 찾은 얼굴 보여주기
    cv2.imshow('Original Face', face_img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

    # 얼굴 축소시켜 보여주기
    face_img = cv2.resize(face_img, dsize=(0,0), fx=fx, fy=fy)
    cv2.imshow('Reduced Face', face_img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

    # 원래 크기로 돌리면서 모자란 픽셀들은 이웃보간법(옆에 있는 색상으로 채우기)으로 채우기
    face_img = cv2.resize(face_img, (w,h), interpolation = cv2.INTER_AREA)
    cv2.imshow('Enlarged Face (Mosaic effect)', face_img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

    # 원래 이미지를 모자이크된 이미지로 덮어쓰기
    img[y:y+h, x:x+w] = face_img
    
# 모자이크 처리된 전체 사진 표시
cv2.imshow('face find', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

결과.

- 가족은 4명인데, 목 부분이 두 개 잡혀서 모두 열굴이 6개라고 나옴

- 축소가로, 축소세로의 픽셀값이 확대된 이미지에서의 사각형 개수라고 보면 된다.

-- 왜냐하면 같은 색깔로 보간되었으므로

 

(원래 이미지에서 얼굴 찾음 : 264x264 픽셀)

(축소한 이미지 - 13x13 픽셀)

(INTER_AREA 보간법으로 다시 확대 - 264x264 픽셀)

(이때 네모로 보이는 칸의 개수를 세어 보면 가로 13개, 세로 13개임)

(축소한 이미지의 픽셀 13x13 을 그대로 확대했다고 보면 됨)

 

최종 결과.

 


예전에 이미지프로세싱 과목에서 MATLAB으로 여러가지 이미지변환을 했었던 기억이 있는데

코드에서 자세한 설명이 없는 부분에 대해

그 때 기억이 남아있어서 그런지 얼추 이해하고 찾아볼 수 있었다.

 

역시 공부는 해서 없어지는게 아니다.

머릿속 어딘가 꾸겨져 있을 뿐...

꺼내서 펴 봐야지 ㅎ

반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기