728x90
학습 내용
- 인물사진의 구현 방식을 이해해본다
- instance segmentation을 이해한다
- cv2 완벽 활용기
개요
- 인물사진의 구현 방식에 대해 이해하면서 OpenCV에 대해 이해해보자
- 기존 모델을 불러와서 인물사진을 만드는 기본적인 방식을 이해해보는 시간을 가졌다
인물 사진 구현방식 요약
- 이미지/모델 불러오기
- 피사체 분리 (image segmentation으로 사람만 분리해내자)
- 배경 흐리게
- 이미지 합성
이미지 불러오기
import os
import urllib
import cv2
import numpy as np
from pixellib.semantic import semantic_segmentation
from matplotlib import pyplot as plt
img_path = os.getenv('HOME')+'/aiffel/human_segmentation/images/cat.jpeg'
img_orig = cv2.imread(img_path)
plt.imshow(cv2.cvtColor(img_orig, cv2.COLOR_BGR2RGB))
plt.show()
- cv2.COLOR_BGR2RGB: 이미지 색상 채널을 변경 (BGR 형식을 RGB 형식으로 변경)
- plt.imshow(): 저장된 데이터를 이미지의 형식으로 표시, 입력은 RGB(A) 데이터 혹은 2D 스칼라 데이터
모델 불러오기
- urllib 패키지 내에 있는 request 모듈의 urlretrieve 함수를 이용
- model_url에 있는 파일을 다운로드 해서 model_file 파일명으로 저장
# 저장할 파일 이름을 결정
model_dir = os.getenv('HOME')+'/aiffel/human_segmentation/models'
model_file = os.path.join(model_dir, 'deeplabv3_xception_tf_dim_ordering_tf_kernels.h5')
# PixelLib가 제공하는 모델의 url입니다
model_url = 'https://github.com/ayoolaolafenwa/PixelLib/releases/download/1.1/deeplabv3_xception_tf_dim_ordering_tf_kernels.h5'
# 다운로드 시작
urllib.request.urlretrieve(model_url, model_file)
- PixelLib 라이브러리 에서 가져온 클래스를 가져와서 semantic segmentation을 수행하는 클래스 인스턴스를 만듦
- pascal voc에 대해 훈련된 예외 모델(model_file)을 로드하는 함수를 호출
- 입력된 이미지를 분할, 분할 출력의 배열을 가져옴, 분할 은 pacalvoc 데이터로 학습된 모델을 이용
model = semantic_segmentation()
model.load_pascalvoc_model(model_file)
segvalues, output = model.segmentAsPascalvoc(img_path)
pascalvoc 데이터의 라벨종류
LABEL_NAMES = [
'background', 'aeroplane', 'bicycle', 'bird', 'boat', 'bottle', 'bus',
'car', 'cat', 'chair', 'cow', 'diningtable', 'dog', 'horse', 'motorbike',
'person', 'pottedplant', 'sheep', 'sofa', 'train', 'tv'
]
len(LABEL_NAMES) # 21개
Segmentation 결과확인
plt.imshow(output)
plt.show()
#segvalues에 있는 class_ids를 담겨있는 값을 통해 pacalvoc에 담겨있는 라벨을 출력
for class_id in segvalues['class_ids']:
print(LABEL_NAMES[class_id])
background
cat
person
- 사람손까지 아주 잘 인식한 것을 볼 수 있다
컬러맵 만들기
colormap = np.zeros((256, 3), dtype = int)
ind = np.arange(256, dtype=int)
for shift in reversed(range(8)):
for channel in range(3):
colormap[:, channel] |= ((ind >> channel) & 1) << shift
ind >>= 3
colormap[:20] #생성한 20개의 컬러맵 출력
array([[ 0, 0, 0],
[128, 0, 0],
[ 0, 128, 0],
[128, 128, 0],
[ 0, 0, 128],
[128, 0, 128],
[ 0, 128, 128],
[128, 128, 128],
[ 64, 0, 0],
[192, 0, 0],
[ 64, 128, 0],
[192, 128, 0],
[ 64, 0, 128],
[192, 0, 128],
[ 64, 128, 128],
[192, 128, 128],
[ 0, 64, 0],
[128, 64, 0],
[ 0, 192, 0],
[128, 192, 0]])
- 위 코드를 통해 컬러맵을 만들었고 라벨과 인덱스가 일치하는 형태이다
- 예를 들어 colormap[15] 는 사람이고 colormap[8] 은 고양이 이다
colormap[8] # 고양이
array([64, 0, 0])
색상순서 변경
- colormap의 배열은 RGB 순이며 output의 배열은 BGR 순서로 채널 배치가 되어 있어서 색상 순서를 변경해줘야 한다
- 고양이 컬러맵이 [64, 0, 0]이므로 (0, 0, 64)를 저장한다
seg_color = (0,0,64)
# output의 픽셀 별로 색상이 seg_color와 같다면 1(True), 다르다면 0(False)이 된다
# seg_color 값이 cat을 나타내는 값이므로 고양이가 있는 위치를 제외하고는 gray로 출력
# cmap 값을 변경하면 다른 색상으로 확인이 가능함
seg_map = np.all(output==seg_color, axis=-1)
print(seg_map.shape)
plt.imshow(seg_map, cmap='gray')
plt.show()
배경 흐리게 하기
img_orig_blur = cv2.blur(img_orig, (13,13))
# cv2.COLOR_BGR2RGB: 원본이 BGR 순서로 픽셀을 읽다보니 이미지 색상 채널을 변경해야함 (BGR 형식을 RGB 형식으로 변경)
plt.imshow(cv2.cvtColor(img_orig_blur, cv2.COLOR_BGR2RGB))
plt.show()
최종 결과물
- np.where(조건, 참일때, 거짓일때)
- 세그멘테이션 마스크가 255인 부분만 원본 이미지 값을 가지고 오고 아닌 영역은 블러된 이미지 값을 사용합니다.
img_concat = np.where(img_mask_color==255, img_orig, img_bg_blur)
plt.imshow(cv2.cvtColor(img_concat, cv2.COLOR_BGR2RGB))
plt.show()
최종 정리
- instance segmentation을 통해 어떻게 인물 사진을 구현하는지 기본적인 방식에 대해 이해해 볼 수 있었다.
- 이후에는 추가적으로 현재 방식의 문제점을 파악해보고 이에 대한 개선 방향에 대해 이야기 해보고자 한다
참고자료 / 최종 결과물
실습 과정 코드
728x90
'AIFFLE > PROJECT' 카테고리의 다른 글
[CV] 고양이 수염 스티커 합성하기 (OpenCV 완전 정복기) (0) | 2024.06.08 |
---|---|
[kaggle] Bike Sharing Demand (자전거 수요 예측) (0) | 2024.05.28 |
[sklearn] 선형회귀와 경사하강법 직접 구현하기 (diabetes dataset) (0) | 2024.05.28 |
[kaggle] 포켓몬 분류하기 프로젝트 (Tree 모델들의 Feature importance를 확인해보자) (2) | 2024.05.28 |