[TIL #44] 딥러닝 이미지 필터 씌우기

안떽왕·2023년 5월 19일
0

Today I Learned

목록 보기
44/76

오늘은 콜로세움의 사진을 가지고 고흐의 '별이 빛나는 밤에' 느낌이 나게끔 바꿔보겠습니다.

import cv2
import numpy as np

# dnn모델 사용, Torch로부터 읽는다, Torch로 만들어진 딥러닝모델을 로드
net = cv2.dnn.readNetFromTorch('models/eccv16/starry_night.t7')

img = cv2.imread('imgs/01.jpg')

h, w, c = img.shape # 높이, 너비, 채널

# 이미지 비율을 유지하면서 크기 변경, 소수가 될수도 있으니 int를 붙혀줌
img = cv2.resize(img, dsize=(500, int(h / w * 500)))


MEAN_VALUE = [103.939, 116.779, 123.680]

# 전처리 함수, 이미지 각 픽셀에서 MEAN_VALUE를 빼줌
# 차원변형을 통해 컴퓨터가 알아 들을 수 있는 형태로 변환
blob = cv2.dnn.blobFromImage(img, mean=MEAN_VALUE)  


net.setInput(blob)
output = net.forward()

# 후처리, 사람이 보기 쉬운 이미지로 변환
output = output.squeeze().transpose((1, 2, 0))
output += MEAN_VALUE

output = np.clip(output, 0, 255)    # 255가 넘는 값은 255로 제한
output = output.astype('uint8') # 정수형태로 바뀌며 사람이 볼 수 있는 이미지가 됨

cv2.imshow('output', output)
cv2.waitKey(0)

먼저 opencv인 cv2와 내장모듈인 numpy를 import합니다.

import cv2
import numpy as np

그리고 딥러닝 모델을 로드해줘야합니다. 저는 깃허브에 올라와져있는 딥러닝 모델을 가져와 만들었는데 starry_night.t7 이라고 하는 고흐풍으로 사진을 바꿔주는 딥러닝 모델입니다.

net = cv2.dnn.readNetFromTorch('models/eccv16/starry_night.t7')

img = cv2.imread('imgs/01.jpg')

cv2의 dnn모델을 사용해 torch로 만들어진 starry_night.t7 모델을 읽어오고, img에 가지고있는 이미지를 할당해줬습니다.


그리고 이미지를 딥러닝 모델이 잘 이해할 수 있도록 이미지의 사이즈를 조절하고 딥러닝 모델에 최적화된 값을 적어주겠습니다.

h, w, c = img.shape # 높이, 너비, 채널

# 이미지 비율을 유지하면서 크기 변경, 소수가 될수도 있으니 int를 붙혀줌
img = cv2.resize(img, dsize=(500, int(h / w * 500)))


MEAN_VALUE = [103.939, 116.779, 123.680] 

MEAN_VALUE는 제가 최적화를 시킨게 아니라 요리 레서피처럼 특정 값을 넣었을 때 잘 작동한다라고 이미 알려진 값입니다.


이제 전처리 함수를 대입해 차원변형을 진행한 후 컴퓨터에게 전달하겠습니다.

# 전처리 함수, 이미지 각 픽셀에서 MEAN_VALUE를 빼줌
# 차원변형을 통해 컴퓨터가 알아 들을 수 있는 형태로 변환
blob = cv2.dnn.blobFromImage(img, mean=MEAN_VALUE)  

net.setInput(blob)
output = net.forward()

파라미터로 mean에는 아까 작성했던 MEAN_VALUE를 입력해줬습니다.

그리고 딥러닝 모델을 넣어줬던 net에 차원변형을 한 데이터인 blob을 넣어주고, forward()함수를 사용해 net을 실행시켜줬습니다.


이제 후처리에 들어가는데 컴퓨터가 보내준 데이터를 사람이 볼 수 있는 데이터로 바꿔주는 작업입니다.

# 후처리, 사람이 보기 쉬운 이미지로 변환
output = output.squeeze().transpose((1, 2, 0))
output += MEAN_VALUE

output = np.clip(output, 0, 255) # 255가 넘는 값은 255로 제한
output = output.astype('uint8') # 정수형태로 바뀌며 사람이 볼 수 있는 이미지가 됨

cv2.imshow('output', output)
cv2.waitKey(0)

컴퓨터가 보내준 값에 squeeze를 사용해 아까 차원변형해준 것을 원래대로 되돌리고 transpose를 사용해 채널, 높이, 너비 순서에서 높이, 너비, 채널로 변경해줍니다.
그리고 아까 빼주었던 MEAN_VALUE도 다시 더해줬습니다.

그렇게 변환된 값을 가지고 clip함수를 이용해 0보다 작은값은 0으로 고정하고 255보다 높은 값은 255로 고정시킵니다.

astype('uint8')은 배열의 각 요소를 8비트 부호 없는 정수로 변환시키는데 이 또한 사람이 볼 수 있는 이미지로 표현하기 위한 방법이라고 생각하시면 좋을 것 같습니다.

그리고 드디어 작업했던 결과물을 스크린으로 볼수있게 코드를 작성하고 waitkey로 창이 바로 꺼지지 않게 잡아줍니다. 아무키나 누르면 이미지 창을 끌 수 있습니다.

그리고 작업한 결과물을 공개합니다.

원본

변환 후

profile
이제 막 개발 배우는 코린이

0개의 댓글