- ์ ๊ฒฝ๋ง์ ํ์ต ๋ฐฉ๋ฒ์ ๋ํ ์ ๋ฐ์ ์ธ ์ ์ฐจ๋ฅผ ์๊ณ ์์ด์ผ ํ๋ค.
- CNN, GAN์ ๋ํ ๊ธฐ๋ณธ์ ์ธ ๊ฐ๋ ์ ์๊ณ ์์ด์ผ ํ๋ค.
- Tensorflow์์ ๋ชจ๋ธ์ ๊ตฌ์ฑํ ๋ ์ฌ์ฉํ๋ Sequential, Functional API์ ๋ํด ์๊ณ ์์ด์ผ ํ๋ค.
- Tensorflow์ GradientTape API๋ฅผ ์ด์ฉํ ํ์ต ์ ์ฐจ๋ฅผ ์ดํดํ ์ ์์ด์ผ ํ๋ค.
- Super Resolution๊ณผ ๊ทธ ๊ณผ์ ์ํ์ ํ์ํ ๊ธฐ๋ณธ ๊ฐ๋ ์ ์ดํดํ๋ค.
- Super Resolution์ ์ฌ์ฉ๋๋ ๋ํ์ ์ธ 2๊ฐ์ ๊ตฌ์กฐ(SRCNN, SRGAN)์ ๋ํด ์ดํดํ๊ณ ํ์ฉํ๋ค.
$ pip install tensorflow-datasets
$ python
>> import tensorflow_datasets as tfds
>> tfds.load("div2k/bicubic_x4")
Super Resolution์์ Resolution์ ํด์๋๋ฅผ ์ด์ผ๊ธฐํ๋ค.
- ์ฐธ๊ณ ์๋ฃ: ๋ชจ๋ํฐ์ ํต์ฌ, ๋์คํ๋ ์ด์ ์คํ ๋ฐ๋ผ์ก๊ธฐ
- ์ฐธ๊ณ ์๋ฃ: ๊ทธ๋ฆผ์ผ๋ก ์ฝ๊ฒ ์์๋ณด๋ HD ํด์๋์ ์ฐจ์ด
์์์ ์ด์ฉํด ์ด๋ ํ ์ผ์ ํ๋์ง์ ๋ฐ๋ผ ์์ ์ ๋ณด์ ์์ค์ ์ต๋ํ ์ค์ด๊ธฐ ์ํด ๊ณ ํด์๋ ์์์ ํ์๋ก ํ ์ ์๋ค. ์ฐ๋ฆฌ๊ฐ ํํ ์ ํ๋ธ ์์์ ์์ฒญํ๋ ๊ฒฝ์ฐ๋ ๊ณ ํด์๋ ์์์ ์ ํธํ๋ค.
์ด๋ ๋ฏ ๋๋ถ๋ถ์ด ๊ณ ํด์๋ ์์์ ์ํ์ง๋ง ํญ์ ์ข์ ์ ๋ง ์๋ ๊ฒ์ ์๋๋ค. ๊ณ ํด์๋ ์์์ ์ ํด์๋ ์์๋ณด๋ค ํฌ๊ธฐ๊ฐ ํจ์ฌ ๋ ํฌ๊ธฐ ๋๋ฌธ์ ์ธํฐ๋ท ํ๊ฒฝ์ ๋ฐ๋ผ ์ ์ก์ ๋ง์ ์๊ฐ์ด ํ์ํ๋ค. ์ด๋ฐ ๊ฒฝ์ฐ์ ์ค๋ ํ์ตํ Super Resolution ๊ธฐ์ ์ ์ข์ ํด๊ฒฐ ๋ฐฉ๋ฒ ์ค ํ๋๊ฐ ๋ ์ ์๋ค. Super Resolution์ด๋ ์ ํด์๋ ์์์ ๊ณ ํด์๋ ์์์ผ๋ก ๋ณํํ๋ ์์ ๋๋ ๊ทธ๋ฌํ ๊ณผ์ ์ ๋งํ๋ค.
์ ํด์๋์ ์ ํ๋ธ ์์์ ๋น ๋ฅด๊ฒ ๋ฐ์ Super Resolution ๊ธฐ์ ๋ก ๊ณ ํด์๋ ์์์ ์์ฑํ ์ ์๋ค๋ฉด ์ต์ ์ ์ธํฐ๋ท ํ๊ฒฝ์์๋ ์ถฉ๋ถํ ๊ณ ํด์๋์ ์์์ ์์ฒญํ ์ ์๋ค.
์ฐ๋ฆฌ๋๋ผ์์ ๊ฐ์ฅ ๋ํ์ ์ผ๋ก ๊ผฝํ๋ Super Resolution ํ์ฉ ์ฌ๋ก๋ <ํ์๊ฑฐํ>์ด๋ผ๋ ๋๋ผ๋ง์ ๋ฆฌ๋ง์คํฐ๋ง์ด๋ค. 2007๋ ์ฒ์ ๋ฐฉ์ก ๋น์ HD ํ์ง๋ก ์ก์ถ๋์๋ <ํ์๊ฑฐํ>์ UHD ํ์ง๋ก ํฅ์๋์ด 2018๋ ์ฌ๋ฐฉ์ก ๋์๋ค. ์ฌ๊ธฐ์๋ Super Resolution ๊ธฐ์ ๋ฟ๋ง ์๋๋ผ ๋ ธ์ด์ฆ ์ ๊ฑฐ ๋ฑ์ ์ฌ๋ฌ ์์ ์ด ๊ฑฐ์ณ์ก๋ค๊ณ ํ๋ค. ์ด์ ๋ํด ์์ธํ ์๊ณ ์ถ๋ค๋ฉด ํ์๊ฑฐํ ๋ฆฌ๋ง์คํฐ๋ง ์ ์๊ธฐ๋ฅผ ์์ธํ ์ฝ์ด๋ณด์.
๊ฐ์ ๋ฐ ๋ณด์ ์์คํ ์์ ํํ ์ฌ์ฉ๋๋ CCTV๋ ๋์์ ๊ฑฐ๋ฆฌ๊ฐ ๋ฉ์ด์ง์ ๋ฐ๋ผ ํ๋ํ ์์์ ํด์๋๊ฐ ์ ํ๋๋ ํ์์ด ๋ฐ์ํ๋ค. ์ ๋ณด ์์ค์ด ๋ง์ ์ ํด์๋ ์์์ ํ์ฉํ๋ค๋ฉด ์ฐจ๋์ ๋ฒํธํ์ด๋ ์ผ๊ตด์ ์ธ์ํ๋ ๋ฐ ํฐ ์ด๋ ค์์ ๊ฒช๊ฑฐ๋ ์ฌ์ง์ด ์ธ์ ์์ฒด๊ฐ ๋ถ๊ฐ๋ฅํ ์ ์๋ค. ์ด๋ฌํ ๋ฌธ์ ๋ฅผ ๊ทน๋ณตํ๊ธฐ ์ํด Super Resolution ๊ธฐ์ ์ ์ ์ฉํ์ฌ ๊ณ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ์์ฑํด ์ธ์ ์ฑ๋ฅ์ ๋์ด๋ ค๋ ๋ง์ ์ฐ๊ตฌ๊ฐ ์งํ๋๊ณ ์๋ค.
๋์ ํด์๋๋ฅผ ๊ฐ๋ ์๋ฃ ์์์ ์ด์ฉํ๋ฉด ๊ตฌ์กฐ ์ ๋ณด๋ฅผ ์์ธํ๊ฒ ๊ด์ฐฐํ ์ ์์ผ๋ฏ๋ก, ์ ๋์ ์ธ ์ด๋ฏธ์ง ๋ถ์ ๋ฐ ์ง๋จ ๋ฑ์ ์์ฌ ๊ฒฐ์ ์ ๋ง์ ๋์์ ์ค ์ ์๋ค. ์ผ๋ฐ์ ์ผ๋ก ๊ณ ํด์๋์ ์๋ฃ ์์์ ์ป๋๋ฐ ๋งค์ฐ ๊ธด ์ค์บ ์๊ฐ์ด ํ์ํ๊ฑฐ๋, ๋ง์ ๋ฐฉ์ฌ์ ์ด ํ์์ ๋ชธ์ ๋ ธ์ถ๋์ด ๋ค๋ฅธ ๋ถ์์ฉ์ ์ด๋ํ ์ ์๋ค. Super Resolution ๊ธฐ์ ์ ์ด๋ฌํ ๋จ์ ์ ๊ทน๋ณตํ ์ ์๋ ๊ธฐ์ ์ค ํ๋๋ก ์ฌ์ฉ๋๋ค.
์ฒซ ๋ฒ์งธ ์ด๋ ค์ด ์ ์ ํ๋์ ์ ํด์๋ ์ด๋ฏธ์ง์ ๋ํด ์ฌ๋ฌ ๊ฐ์ ๊ณ ํด์๋ ์ด๋ฏธ์ง๊ฐ ๋์ฌ ์ ์๋ค๋ ๊ฒ์ด๋ค. ์ ๊ทธ๋ฆผ์ 1๊ฐ์ ์ ํด์๋ ์ด๋ฏธ์ง(์๋จ ์ด๋ฏธ์ง)์ ๋์ํ๋ 3๊ฐ์ ๊ณ ํด์๋ ์ด๋ฏธ์ง(ํ๋จ ์ด๋ฏธ์ง)๋ฅผ ๋ํ๋๋ค. 3๊ฐ์ ๊ณ ํด์๋ ์ด๋ฏธ์ง ์ฌ์ด์์๋ ๋์ผ๋ก ๋ณผ ๋ ๊ฑฐ์ ์ฐจ์ด๋ฅผ ๋ํ๋ด์ง ์์ง๋ง, ์๋ ํ๋ํ ์ด๋ฏธ์ง๋ฅผ ๋ณด๋ฉด ์ธ๋ถ์ ์ผ๋ก ํฝ์ ์ ๊ฐ์ด ๊ฐ๊ฐ ๋ค๋ฅธ ๊ฒ์ ์ ์ ์๋ค. ํ๋์ ์ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ๊ณ ํด์๋ ์ด๋ฏธ์ง๋ก ๋ง๋๋๋ฐ ๋งค์ฐ ๋ค์ํ ๊ฒฝ์ฐ์ ์๊ฐ ์๋ค๋ ๊ฒ์ Super Resolution์ด ๊ฐ์ง ํฐ ํน์ง์ด๋ฉฐ, ์ด๋ฌํ ๋ฌธ์ ๋ฅผ ill-posed (inverse) problem์ด๋ผ ๋ถ๋ฅธ๋ค.
์ผ๋ฐ์ ์ผ๋ก Super Resolution ๋ชจ๋ธ์ ํ์ต์ํค๊ธฐ ์ํ ๋ฐ์ดํฐ๋ฅผ ๊ตฌ์ฑํ๋ ๊ณผ์ ์, ๋จผ์ ๊ณ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ์ค๋นํ๊ณ ํน์ ํ ์ฒ๋ฆฌ ๊ณผ์ ์ ๊ฑฐ์ณ ์ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๋ฉฐ, ์์ฑ๋ ์ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ์ ๋ ฅ์ผ๋ก ์๋์ ๊ณ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ๋ณต์ํ๋๋ก ํ์ต์ ์งํํ๋ค.
๋ ๋ฒ์งธ ์ด๋ ค์ด ์ ์ Super Resolution ๋ฌธ์ ์ ๋ณต์ก๋์ด๋ค. ์ ๊ทธ๋ฆผ์ 2x2 ํฌ๊ธฐ์ ์ด๋ฏธ์ง๋ฅผ ์ด์ฉํด 3x3, 4x4, 5x5 ํฌ๊ธฐ์ ์ด๋ฏธ์ง๋ก Super Resolution ํ๋ ๊ณผ์ ์ ๊ฐ๋ตํ๊ฒ ๋ํ๋๋ค. ๋ น์์ผ๋ก ๋ํ๋ 2x2 ์ด๋ฏธ์ง ํฝ์ ์ ์ ๋ ฅ์ผ๋ก 3x3 ํฌ๊ธฐ์ ์ด๋ฏธ์ง ๋ง๋๋ ๊ฒฝ์ฐ ์๋กญ๊ฒ ์์ฑํด์ผ ํ๋ ์ ๋ณด๋ ์ต์ 5๊ฐ ํฝ์ (ํ์)์ด๋ฉฐ, 4x4์ ๊ฒฝ์ฐ 12๊ฐ, 5x5์ ๊ฒฝ์ฐ 21๊ฐ์ ์ ๋ณด๋ฅผ ์์ฑํด์ผ ํ๋ค. ์๋ ๊ฐ์ง ์ ํ๋ ์ ๋ณด(๋ น์ ํฝ์ )๋ง์ ์ด์ฉํด ๋ง์ ์ ๋ณด(ํ์ ํฝ์ )๋ฅผ ๋ง๋ค์ด๋ด๋ ๊ณผ์ ์ ๋งค์ฐ ๋ณต์กํ๋ฉฐ ๊ทธ๋งํผ ์๋ชป๋ ์ ๋ณด๋ฅผ ๋ง๋ค์ด ๋ผ ๊ฐ๋ฅ์ฑ ๋ํ ๋๋ค. ์ด ๋ฌธ์ ๋ ์๋ ๊ฐ์ง ์ด๋ฏธ์ง์ ํด์๋ ๋ณด๋ค ๋์ฑ๋ ๋์ ํด์๋๋ก Super Resolution ํ ์๋ก ์ ์ ์ฌํด์ง๋ค.
์ ์ด๋ฏธ์ง์ ์ฒซ ๋ฒ์งธ ๋ฐ ๋ค ๋ฒ์งธ ์ด๋ฏธ์ง๋ ์ ํด์๋ ๋ฐ ๊ณ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ๋ํ๋ด๋ฉฐ, ๋ ๋ฒ์งธ ๋ฐ ์ธ ๋ฒ์งธ ์ด๋ฏธ์ง๋ ๊ฐ๊ฐ ๋ค๋ฅธ ๋ฅ๋ฌ๋ ๋ชจ๋ธ์ ์ด์ฉํด Super Resolution ํ์ฌ ์์ฑํ ๊ฒฐ๊ณผ ์ด๋ฏธ์ง๋ค. ๋ฅ๋ฌ๋ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ๊ฒฐ๊ณผ(๋ ๋ฒ์งธ ๋ฐ ์ธ ๋ฒ์งธ ์ด๋ฏธ์ง)๋ฅผ ๋น๊ตํ๋ค๋ฉด, ์๊ฐ์ ์ผ๋ก ์ด๋ค ์ด๋ฏธ์ง๊ฐ ๋ ๊ณ ํด์๋์ ๊ฐ๊น์ด๊ฐ? ๋๋ถ๋ถ ๊ฒฐ๊ณผ 2 ์ด๋ฏธ์ง๊ฐ ๋ถ๋ช ๋์ฑ ์ธ๋ฐํ ์ ๋ณด๋ฅผ ์ ํํํ์ฌ ํด์๋๊ฐ ๋๋ค๊ณ ์๊ฐํ ์ ์์ต๋๋ค. ๋ง์ Super Resolution ์ฐ๊ตฌ์์ ์ฌ์ฉ๋๋ ๋ ๊ฐ์ ์ ๋์ ํ๊ฐ ๊ฒฐ๊ณผ๊ฐ ๋ ๋ฒ์งธ ๋ฐ ์ธ ๋ฒ์งธ ์ด๋ฏธ์ง ์ ๋ชฉ์ ๋ํ๋ ์๋ค. ๊ฒฐ๊ณผ 2์ ์ด๋ฏธ์ง์ ์ธ๋ฐํ ์ ๋ณด๊ฐ ์ ํํ๋์๋ค๊ณ ์๊ฐํ์ง๋ง ์ค์ ํ๊ฐ ๊ฒฐ๊ณผ๋ ๊ฒฐ๊ณผ 1 ์ด๋ฏธ์ง์ ์ฐ์ธ ์ซ์๊ฐ ๋ ๋์ ๊ฒ์ ํ์ธํ ์ ์๋ค. ์ด ํ๊ฐ ์ฒ๋๋ ๊ฐ๊ฐ ๋์์๋ก ๋ ์๋ณธ ์ด๋ฏธ์ง์ ๋น์ทํจ์ ๋งํ๋ฉฐ, ์ ๋์ ์ผ๋ก ๊ฒฐ๊ณผ 1์ด ๋ ์ข์ ๊ฒฐ๊ณผ๋ผ๋ ๋ป์ด๋ค. ๋ง์ง๋ง์ผ๋ก Super Resolution์ ์ํํ๋ ๋ฐ ์ด๋ ค์ด ์ ์ ์ ๊ทธ๋ฆผ๊ณผ ๊ฐ์ด ๊ฒฐ๊ณผ๋ฅผ ํ๊ฐํ๋ ๋ฐ ์์ด ํํ ์ฌ์ฉ๋๋ ์ ๋์ ํ๊ฐ ์ฒ๋์ ์ฌ๋์ด ์๊ฐ์ ์ผ๋ก ๊ด์ฐฐํ์ฌ ๋ด๋ฆฐ ํ๊ฐ๊ฐ ์ ์ผ์นํ์ง ์๋๋ค๋ ๊ฒ์ด๋ค.
Super Resolution์ ์ํํ๋ ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ์์ Interpolation ์ ์ด์ฉํ๋ ๊ฒ์ด๋ค.
์ด๋ฒ์๋ OpenCV ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ด์ฉํด interpolation์ ์ ์ฉํด ๋ณด์. ์ ์ฉํ ์ด๋ฏธ์ง๋ scikit-image์์ ์ ๊ณตํ๋ ์์ ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฉํ๋ค. ๋ง์ฝ ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ค์น๋์ด ์์ง ์๋ค๋ฉด ์๋์ ๊ฐ์ด ๋จผ์ ์ค์นํ์.
$ pip install opencv-python
$ pip install scikit-image
from skimage import data
import matplotlib.pyplot as plt
hr_image = data.chelsea() # skimage์์ ์ ๊ณตํ๋ ์์ ์ด๋ฏธ์ง๋ฅผ ๋ถ๋ฌ์ต๋๋ค.
hr_shape = hr_image.shape[:2]
print(hr_image.shape) # ์ด๋ฏธ์ง์ ํฌ๊ธฐ๋ฅผ ์ถ๋ ฅํฉ๋๋ค.
plt.figure(figsize=(6,3))
plt.imshow(hr_image)
# ํ์ง ์ดํ์ํค๊ธฐ
import cv2
lr_image = cv2.resize(hr_image, dsize=(150,100)) # (๊ฐ๋ก ํฝ์
์, ์ธ๋ก ํฝ์
์)
print(lr_image.shape)
plt.figure(figsize=(3,1))
plt.imshow(lr_image)
# Interpolation
bilinear_image = cv2.resize(
lr_image,
dsize=(451, 300), # (๊ฐ๋ก ํฝ์
์, ์ธ๋ก ํฝ์
์)
interpolation=cv2.INTER_LINEAR # bilinear interpolation ์ ์ฉ
)
bicubic_image = cv2.resize(
lr_image,
dsize=(451, 300), # (๊ฐ๋ก ํฝ์
์, ์ธ๋ก ํฝ์
์)
interpolation=cv2.INTER_CUBIC # bicubic interpolation ์ ์ฉ
)
images = [bilinear_image, bicubic_image, hr_image]
titles = ["Bilinear", "Bicubic", "HR"]
plt.figure(figsize=(16,3))
for i, (image, title) in enumerate(zip(images, titles)):
plt.subplot(1,3,i+1)
plt.imshow(image)
plt.title(title, fontsize=20)
Bilinear ๋ฐ bicubic interpolation์ ์ ์ฉํ ์ด๋ฏธ์ง์ ์๋ ๊ณ ํด์๋ ์ด๋ฏธ์ง(์ ๊ทธ๋ฆผ์ HR)๋ฅผ ์๊ฐํํ ๊ฒฐ๊ณผ, ์ด๋ฏธ์ง๊ฐ ์์ ์๊ฐ์ ์ผ๋ก ํด์๋์ ํฐ ์ฐจ์ด๊ฐ ์์ด ๋ณด์ธ๋ค. ์๋ ์ฝ๋๋ฅผ ์ด์ฉํด ํน์ ๋ถ๋ถ์ ์๋ผ๋ด์ด ์๊ฐํํด๋ณด๋ฉด ์ฐจ์ด๋ฅผ ์ ์ ์๋ค.
# ํน์ ์์ญ์ ์๋ผ๋ผ ํจ์๋ฅผ ์ ์ํฉ๋๋ค.
def crop(image, left_top, x=50, y=100):
return image[left_top[0]:(left_top[0]+x), left_top[1]:(left_top[1]+y), :]
# ์๋ผ๋ผ ์์ญ์ ์ขํ๋ฅผ ์ ์ํฉ๋๋ค.
left_tops = [(220,200)] *3 + [(90,120)] *3 + [(30,200)] *3
plt.figure(figsize=(16,10))
for i, (image, left_top, title) in enumerate(zip(images*3, left_tops, titles*3)):
plt.subplot(3,3,i+1)
plt.imshow(crop(image, left_top))
plt.title(title, fontsize=20)
Interpolation ๋ฐฉ๋ฒ์ ์ด์ฉํ Super Resolution ๊ฒฐ๊ณผ๋ ์ด๋ฏธ์ง๋ง ํฌ๊ฒ ๋ง๋ค์ด์ค ๋ฟ ์ธ๋ฐํ ์ ๋ณด๋ ๊ฑฐ์ ์ฐพ์๋ณผ ์ ์๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
SRCNN์ 2014๋ ๋ฐํ๋ "Image Super-Resolution Using Deep Convolutional Networks" ๋ ผ๋ฌธ์์ ์ฌ์ฉ๋์๋ค. Super Resolution Convolutional Neural Networks์ ์๊ธ์๋ฅผ ๋ฐ์ SRCNN์ด๋ผ๊ณ ๋ถ๋ฆฌ๋ฉฐ, ๋งค์ฐ ๊ฐ๋จํ ๋ชจ๋ธ ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํ์์๋ ๊ธฐ์กด ๊ฒฐ๊ณผ์ ๋นํด ํฐ ์ฑ๋ฅ ํฅ์์ ์ด๋ค๋๋ค. ์ง๊ธ ์ด ์ฐ๊ตฌ๋ฅผ ๋ณด๋ฉด ๋๋ฌด ๊ฐ๋จํด ๋ณด์ด์ง๋ง, Super Resolution ๋ฌธ์ ์ ๊ฐ์ฅ ์ฒ์ ๋ฅ๋ฌ๋์ ์ ์ฉํ ์ฐ๊ตฌ๋ก์จ ์ดํ ๋ง์ ๋ฅ๋ฌ๋ ๊ธฐ๋ฐ์ Super Resolution ์ฐ๊ตฌ์ ํฐ ์ํฅ์ ์ค ์ ๋ง ๋ฉ์ง ์ํ์ด๋ค.
์๋ ๊ทธ๋ฆผ์ด SRCNN ๊ตฌ์กฐ์ด๋ค.
๊ฐ์ฅ ๋จผ์ ์ ํด์๋ ์ด๋ฏธ์ง(๊ทธ๋ฆผ์ LR)๋ฅผ bicubic interpolation ํ์ฌ ์ํ๋ ํฌ๊ธฐ๋ก ์ด๋ฏธ์ง๋ฅผ ๋๋ฆฐ๋ค. SRCNN์ ์ด ์ด๋ฏธ์ง(๊ทธ๋ฆผ์ ILR)๋ฅผ ์ ๋ ฅ์ผ๋ก ์ฌ์ฉํ๋ค. ์ดํ 3๊ฐ์ convolutional layer๋ฅผ ๊ฑฐ์ณ ๊ณ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ์์ฑํด ๋ธ๋ค. ์์ฑ๋ ๊ณ ํด์๋ ์ด๋ฏธ์ง์ ์ค์ ๊ณ ํด์๋ ์ด๋ฏธ์ง ์ฌ์ด์ ์ฐจ์ด๋ฅผ ์ญ์ ํ ํ์ฌ ์ ๊ฒฝ๋ง์ ๊ฐ์ค์น๋ฅผ ํ์ตํ๋ค. ์ต๊ทผ ๋ฐํ๋๋ ์ ๋ฐฑ ๊ฐ ์ด์์ convolutional layer๋ฅผ ๊ฐ๋ CNN๊ณผ ๋น๊ตํ๋ฉด SRCNN์ ๋งค์ฐ ๊ฐ๋จํ๋ค.
SRCNN์ 3๊ฐ์ง ์ฐ์ฐ์ผ๋ก ๊ตฌ์ฑ๋๋ค.
- Patch extraction and representation : ์ ํด์๋ ์ด๋ฏธ์ง์์ patch๋ฅผ ์ถ์ถํ๋ค.
- Non-linear mapping : patch๋ฅผ ๋ค๋ฅธ ์ฐจ์์ patch๋ก ๋น์ ํ ๋งคํํ๋ค.
- Reconstruction : patch๋ก๋ถํฐ ๊ณ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๋ค.
VDSR(Very Deep Super Resolution)
SRCNN๊ณผ ๋์ผํ๊ฒ interpolation์ ํตํด ์ ํด์๋ ์ด๋ฏธ์ง์ ํฌ๊ธฐ๋ฅผ ๋๋ ค ์ ๋ ฅ์ผ๋ก ์ฌ์ฉํ๋ค. ์ด์ ๋ณด๋ค ํจ์ฌ ๋ง์ 20๊ฐ์ convolutional layer๋ฅผ ์ฌ์ฉํ๊ณ , ์ต์ข ๊ณ ํด์๋ ์ด๋ฏธ์ง ์์ฑ ์ง์ ์ ์ฒ์ ์ ๋ ฅ ์ด๋ฏธ์ง๋ฅผ ๋ํ๋ residual learning์ ์ด์ฉํ๋ค. ์ด๋ฌํ ๊น์ ๊ตฌ์กฐ๋ฅผ ์ด์ฉํด SRCNN์ ๋นํด ํฐ ์ฑ๋ฅ ํฅ์์ ์ด๋์ด ๋๋ค.
RDN (Residual Dense Network)
RDN์ ์ ํด์๋ ์ด๋ฏธ์ง๊ฐ ์ ๋ ฅ๋๋ฉด, ์ฌ๋ฌ ๋จ๊ณ์ convolutional layer๋ฅผ ๊ฑฐ์น๋๋ฐ ๊ฐ layer์์ ๋์ค๋ ์ถ๋ ฅ์ ์ต๋ํ ํ์ฉํ๋๋ก ํ๋ค. ๊ทธ๋ฆผ๊ณผ ๊ฐ์ด ๊ฐ๊ฐ์ convolution layer ์ถ๋ ฅ ๊ฒฐ๊ณผ๋ก ์์ฑ๋ ํน์ง๋ค์ด ํ์ดํ๋ฅผ ๋ฐ๋ผ ์ดํ ์ฐ์ฐ์์ ์ฌ๋ฌ ๋ฒ ์ฌํ์ฉ ํ๋ ๊ฒ์ ๋ณผ ์ ์๋ค. (ํ ๊ณณ์ผ๋ก๋ถํฐ ๋์จ ํ์ดํ๊ฐ ์ฌ๋ฌ ๊ณณ์ ํฅํ๊ณ ์๋ค)
RCAN (Residual Channel Attention Networks)
RCAN ๊ตฌ์กฐ ๋ํ ๋ง์ convolutional layer๋ฅผ ๊ฑฐ์น๋ฉฐ ํ์ตํ๋ค. ์ ๊ตฌ์กฐ๋ค๊ณผ ๋ค๋ฅธ ํน๋ณํ ์ ์ convolutional layer์ ๊ฒฐ๊ณผ์ธ ๊ฐ๊ฐ์ ํน์ง ๋งต์ ๋์์ผ๋ก ์ฑ๋ ๊ฐ์ ๋ชจ๋ ์ ๋ณด๊ฐ ๊ท ์ผํ ์ค์๋๋ฅผ ๊ฐ๋ ๊ฒ์ด ์๋๋ผ ์ผ๋ถ ์ค์ํ ์ฑ๋์๋ง ์ ํ์ ์ผ๋ก ์ง์คํ๋๋ก ์ ๋ํ๋ค (๋งจ ์์ Channel attention์ด๋ผ ์ฐ์ธ ๋ถ๋ถ). CNN Attention ๋ฑ์ ํค์๋๋ก ๊ฒ์ํ๋ฉด RCAN ๊ตฌ์กฐ์ ๋น์ทํ ๋ง์ attention ๊ธฐ์ ์ ๋ํ ์ ๋ณด๋ค์ ์ฐพ์๋ณผ ์ ์๋ค.
์ด๋ฒ์๋ GAN(Generative Adversarial Networks) ์ ํ์ฉํ Super Resolution ๊ณผ์ ์ ๋ํด ๋ค๋ค๋ณด๋ ค ํ๋ค. ๊ณ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ๋ง๋ค์ด ๋ด๋ ๋ฐ GAN์ด ์ด๋ป๊ฒ ํ์ฉ๋ ์ ์๊ณ , ์ด๋ฅผ ํ์ฉํ์ ๋ ์ด๋ ํ ์ฅ์ ์ด ์๋์ง ํ์ต์ ํตํด ์์๋ณด์.
SRGAN = Super Resolution + GAN
์ต๊ทผ Super Resolution ๋ถ์ผ์์ GAN์ ๋งค์ฐ ๋ง์ด ํ์ฉ๋๊ณ ์๋ค. ์ด๋ฒ์๋ ๊ฐ์ฅ ์ฒ์์ผ๋ก Super Resolution์ GAN์ ์ด์ฉํ ์ฐ๊ตฌ์ธ SRGAN์ ๋ํด ์์๋ณด์. SRGAN์ 2016๋ ๋ฐํ๋ "Photo-Realistic Single Image Super-Resolution Using a Generative Adversarial Network" ๋ ผ๋ฌธ์์ ์ ์๋์์ผ๋ฉฐ, ์๋ ๊ทธ๋ฆผ๊ณผ ๊ฐ์ด ์ด์ ์ ํ์ตํ SRCNN ๋ณด๋ค ์กฐ๊ธ ๋ณต์กํ ๊ตฌ์กฐ๋ฅผ ๊ฐ๋๋ค.
๊ทธ๋ฆผ์ Generator Network์ Discriminator Network๋ ๊ฐ๊ฐ ์์์ ๋น์ ํ๋ ์์กฐ์งํ๋ฒ(์์ฑ ๋ชจ๋ธ)๊ณผ ๊ฒฝ์ฐฐ(๋ถ๋ฅ/ํ๋ณ ๋ชจ๋ธ)์ด๋ค. Generator๊ฐ ์ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ์ ๋ ฅ ๋ฐ์ (๊ฐ์ง)๊ณ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ์์ฑํด ๋ด๋ฉด, Discriminator๋ ์์ฑ๋ (๊ฐ์ง)๊ณ ํด์๋ ์ด๋ฏธ์ง์ ์ค์ (์ง์ง) ๊ณ ํด์๋ ์ด๋ฏธ์ง ์ค ์ง์ง๋ฅผ ํ๋ณํ๋ค.
Generator๋ Discriminator๋ฅผ ์์ด๋ คํ๊ณ Discriminator๋ ์ง์ง๋ฅผ ๊ฐ๋ ค๋ด๋ ค๋ ํ์ต์ด ์งํ๋ ์๋ก ์๋ก ๊ฒฝ์์๊ฐ ๋์ด ๋ ๋ชจ๋๊ฐ ์ ์ ๋ฐ์ ํ๋ค. ํ์ต์ด ๊ฑฐ์ ์๋ฃ ๋๋ฉด ์ต์ข ์ ์ผ๋ก Generator๊ฐ ์์ฑํด๋ธ (๊ฐ์ง)๊ณ ํด์๋ ์ด๋ฏธ์ง๋ Discriminator๊ฐ ์ง์ง์ธ์ง ๊ฐ์ง์ธ์ง๋ฅผ ๊ตฌ๋ถํ๊ธฐ ํ๋ค ์ ๋๋ก ๋งค์ฐ ์ข์ ํ์ง์ ๊ฐ์ง ๊ณ ํด์๋ ์ด๋ฏธ์ง๊ฐ ๋๋ค.
SRGAN์์ ์ฌ์ฉํ๋ loss function์ ์กฐ๊ธ ํน๋ณํ๋ค.
์ ์์ ๋ณด๋ฉด ํฌ๊ฒ content loss์ adversarial loss๋ก ๊ตฌ์ฑ๋์ด ์๊ณ , ์ด ์ค adversarial loss๋ ์ฐ๋ฆฌ๊ฐ ์ผ๋ฐ์ ์ผ๋ก ์๊ณ ์๋ GAN์ loss์ด๋ฉฐ, ์กฐ๊ธ ํน๋ณํ ๋ถ๋ถ์ ์๋ ๊ทธ๋ฆผ์ผ๋ก ๋ํ๋ธ content loss ๋ถ๋ถ ์ด๋ค.
content loss
๋ Generator๋ฅผ ์ด์ฉํด ์ป์ด๋ธ (๊ฐ์ง) ๊ณ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ์ค์ (์ง์ง) ๊ณ ํด์๋ ์ด๋ฏธ์ง์ ์ง์ ๋น๊ตํ๋ ๊ฒ์ด ์๋๋ผ, ๊ฐ ์ด๋ฏธ์ง๋ฅผ ์ด๋ฏธ์ง๋ท์ผ๋ก ์ฌ์ ํ์ต๋(pre-trained) VGG ๋ชจ๋ธ์ ์
๋ ฅํ์ฌ ๋์ค๋ feature map์์์ ์ฐจ์ด๋ฅผ ๊ณ์ฐํ๋ค. ์ฆ, ์ด์ ์ ํ์ตํ๋ SRCNN์ ์์ฑํด๋ธ ๊ณ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ์๋ ๊ณ ํด์๋ ์ด๋ฏธ์ง์ ์ง์ ๋น๊ตํ์ฌ loss๋ฅผ ๊ณ์ฐํ์ง๋ง, SRGAN์์๋ ์์ฑ๋ ๊ณ ํด์๋ ์ด๋ฏธ์ง์ ์ค์ ๊ณ ํด์๋ ์ด๋ฏธ์ง๋ฅผ VGG์ ์
๋ ฅํ์ฌ ๋ชจ๋ธ ์ค๊ฐ์์ ์ถ์ถํด๋ธ ํน์ง์ ๋น๊ตํด์ loss๋ฅผ ๊ณ์ฐํ๋ค. SRGAN์ VGG๋ฅผ ์ด์ฉํ content loss
๋ฐ GAN์ ์ฌ์ฉํจ์ผ๋ก์จ ๋ฐ์ํ๋ adversarial loss
๋ฅผ ํฉํ์ฌ ์ต์ข
์ ์ผ๋ก perceptual loss
๋ผ๊ณ ์ ์ํ๋ฉฐ ์ด๋ฅผ ํ์ต์ ์ด์ฉํ๋ค.
tensorflow-datasets
๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ์ฐ๋ฆฌ๊ฐ ์ฌ์ฉํด ๋ณผ ๋ฐ์ดํฐ์
์ DIV2K ์ด๋ค. DIV2K ๋ฐ์ดํฐ์
์ ๋ง์ Super Resolution ์ฐ๊ตฌ์์ ํ์ต ๋ฐ ํ๊ฐ์ ์ฌ์ฉ๋๋ ๋ฐ์ดํฐ์
์ด๋ฉฐ 800๊ฐ์ ํ์ต์ฉ ๋ฐ์ดํฐ์
๋ฐ 100๊ฐ์ ๊ฒ์ฆ์ฉ ๋ฐ์ดํฐ์
์ผ๋ก ๊ตฌ์ฑ๋์ด ์๋ค.
์์ ๋ค์ด๋ก๋ ํ ๋ฐ์ดํฐ์ ์ div2k/bicubic_x4 ์ด๋ฉฐ, ์ด๋ DIV2K ๋ฐ์ดํฐ์ ์ค์์ ์ค์ ๊ณ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ๋์์ผ๋ก bicubic interpolation์ ์ด์ฉํด ๊ฐ๋ก ๋ฐ ์ธ๋ก ํฝ์ ์๋ฅผ 1/4๋ฐฐ๋ก ์ค์ธ ๋ฐ์ดํฐ์ ์ด๋ค. ์ด๋ ๊ฒ ๋ง๋ค์ด์ง ์ ํด์๋ ์ด๋ฏธ์ง์ ์๋ ๊ณ ํด์๋ ์ด๋ฏธ์ง๊ฐ ์๋ก ํ ์์ผ๋ก ๊ตฌ์ฑ๋์ด ์๋ค.
๋ฐ์ดํฐ์ ์ ๋ํ ์์ธํ ์ ๋ณด๋ ์๋์์ ํ์ธํ์ค ์ ์์ต๋๋ค.
import cv2
import numpy as np
import matplotlib.pyplot as plt
import tensorflow_datasets as tfds
# ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ต๋๋ค.
train, valid = tfds.load(
"div2k/bicubic_x4",
split=["train","validation"],
as_supervised=True
)
# ์๊ฐํ๋ฅผ ์ํด ํ ๊ฐ์ ๋ฐ์ดํฐ๋ง ์ ํํฉ๋๋ค.
for i, (lr, hr) in enumerate(valid):
if i == 6: break
# ์ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ๊ณ ํด์๋ ์ด๋ฏธ์ง ํฌ๊ธฐ๋ก bicubic interpolation ํฉ๋๋ค.
hr, lr = np.array(hr), np.array(lr)
bicubic_hr = cv2.resize(
lr,
dsize=(hr.shape[1], hr.shape[0]), # ๊ณ ํด์๋ ์ด๋ฏธ์ง ํฌ๊ธฐ๋ก ์ค์
interpolation=cv2.INTER_CUBIC # bicubic ์ค์
)
# ์ ํด์๋ ๋ฐ ๊ณ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ์๊ฐํํฉ๋๋ค.
plt.figure(figsize=(20,10))
plt.subplot(1,2,1); plt.imshow(bicubic_hr)
plt.subplot(1,2,2); plt.imshow(hr)
์ด๋ฏธ์ง ํฌ๊ธฐ๊ฐ ๊ฝค ํฌ๊ธฐ ๋๋ฌธ์ ์ด๋ ดํ์ด ๋ด์๋ ์ ๋ช ํจ์ ์ฐจ์ด๊ฐ ํฌ์ง ์์ ๊ฒ ๊ฐ๋ค. ์๋ ์ฝ๋๋ฅผ ์ด์ฉํด ๊ฐ ์ด๋ฏธ์ง์ ํน์ ๋ถ๋ถ์ ํ๋ํด๋ณด์.
# ์ด๋ฏธ์ง์ ํน์ ๋ถ๋ถ์ ์๋ผ๋ด๋ ํจ์๋ฅผ ์ ์ํฉ๋๋ค.
def crop(image, left_top, x=200, y=200):
return image[left_top[0]:(left_top[0]+x), left_top[1]:(left_top[1]+y), :]
# interpolation๋ ์ด๋ฏธ์ง์ ๊ณ ํด์๋ ์ด๋ฏธ์ง์ ๋์ผํ ๋ถ๋ถ์ ๊ฐ๊ฐ ์๋ผ๋
๋๋ค.
left_top = (400, 500)
crop_bicubic_hr = crop(bicubic_hr, left_top)
crop_hr = crop(hr, left_top)
# ์๋ผ๋ธ ๋ถ๋ถ์ ์๊ฐํ ํฉ๋๋ค.
plt.figure(figsize=(15,25))
plt.subplot(1,2,1); plt.imshow(crop_bicubic_hr); plt.title("Bicubic", fontsize=30)
plt.subplot(1,2,2); plt.imshow(crop_hr); plt.title("HR", fontsize=30)
Bicubic interpolation ๋ฐฉ๋ฒ์ ์ด์ฉํ ๊ฒฐ๊ณผ๋ HR ์ด๋ฏธ์ง์ ๋น๊ตํ๋ฉด ๋งค์ฐ ์ ๋ช ํ์ง ์์ ๊ฒ์ ํ์ธํ ์ ์๋ค. SRCNN์ ์ด์ฉํด ํ์ตํ ๊ฒฐ๊ณผ๋ ์ผ๋ง๋ ์ข์์ง ํ์ธํด๋ณด์.
SRCNN์ ์ ๋ ฅ์ ์ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ๊ทธ๋๋ก ์ฌ์ฉํ๋ ๊ฒ์ด ์๋, ๋ง๋ค๊ณ ์ ํ๋ ๊ณ ํด์๋ ์ด๋ฏธ์ง ํฌ๊ธฐ์ ๋ง๊ฒ interpolation์ด ์ ์ฉ๋ ์ด๋ฏธ์ง์ด๋ค.
import tensorflow as tf
def preprocessing(lr, hr):
# ์ด๋ฏธ์ง์ ํฌ๊ธฐ๊ฐ ํฌ๋ฏ๋ก (96,96,3) ํฌ๊ธฐ๋ก ์์ ์์ญ์ ์๋ผ๋ด์ด ์ฌ์ฉํฉ๋๋ค.
hr = tf.image.random_crop(hr, size=[96, 96, 3])
hr = tf.cast(hr, tf.float32) / 255.
# ์๋ผ๋ธ ๊ณ ํด์๋ ์ด๋ฏธ์ง์ ๊ฐ๋ก, ์ธ๋ก ํฝ์
์๋ฅผ 1/4๋ฐฐ๋ก ์ค์๋ค๊ฐ
# interpolation์ ์ด์ฉํด ๋ค์ ์๋ ํฌ๊ธฐ๋ก ๋๋๋ฆฝ๋๋ค.
# ์ด๋ ๊ฒ ๋ง๋ ์ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ์
๋ ฅ์ผ๋ก ์ฌ์ฉํฉ๋๋ค.
lr = tf.image.resize(hr, [96//4, 96//4], "bicubic")
lr = tf.image.resize(lr, [96, 96], "bicubic")
return lr, hr
train = train.map(preprocessing).shuffle(buffer_size=10).batch(16)
valid = valid.map(preprocessing).batch(16)
SRCNN์ 3๊ฐ convolutional layer๋ฅผ ์ฌ์ฉํ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง๊ณ ์๋ค. ๋ฐ๋ผ์ ์๋ ์ฝ๋์ ๊ฐ์ด Sequential API๋ฅผ ํ์ฉํด ๊ฐ๋จํ๊ฒ ๊ตฌํํ ์ ์๋ค.
from tensorflow.keras import layers, Sequential
# 3๊ฐ์ convolutional layer๋ฅผ ๊ฐ๋ Sequential ๋ชจ๋ธ์ ๊ตฌ์ฑํฉ๋๋ค.
srcnn = Sequential()
# 9x9 ํฌ๊ธฐ์ ํํฐ๋ฅผ 128๊ฐ ์ฌ์ฉํฉ๋๋ค.
srcnn.add(layers.Conv2D(128, 9, padding="same", input_shape=(None, None, 3)))
srcnn.add(layers.ReLU())
# 5x5 ํฌ๊ธฐ์ ํํฐ๋ฅผ 64๊ฐ ์ฌ์ฉํฉ๋๋ค.
srcnn.add(layers.Conv2D(64, 5, padding="same"))
srcnn.add(layers.ReLU())
# 5x5 ํฌ๊ธฐ์ ํํฐ๋ฅผ 64๊ฐ ์ฌ์ฉํฉ๋๋ค.
srcnn.add(layers.Conv2D(3, 5, padding="same"))
srcnn.summary()
srcnn.compile(
optimizer="adam",
loss="mse"
)
srcnn.fit(train, validation_data=valid, epochs=1)
SRCNN์ ํ์ต์๋ ๊ฝค๋ ์ค๋์๊ฐ์ด ์์๋๊ธฐ ๋๋ฌธ์ ์ด๋ฏธ ํ์ต์ด ์๋ฃ๋ SRCNN ๋ชจ๋ธ์ ์ด์ฉํ์ฌ ํ ์คํธํด๋ณธ๋ค.
import tensorflow as tf
import os
model_file = os.getenv('HOME')+'/aiffel/super_resolution/srcnn.h5'
srcnn = tf.keras.models.load_model(model_file)
def apply_srcnn(image):
sr = srcnn.predict(image[np.newaxis, ...]/255.)
sr[sr > 1] = 1
sr[sr < 0] = 0
sr *= 255.
return np.array(sr[0].astype(np.uint8))
srcnn_hr = apply_srcnn(bicubic_hr)
# ์์ธํ ์๊ฐํ ํ๊ธฐ ์ํด 3๊ฐ ์์ญ์ ์๋ผ๋
๋๋ค.
# ์๋๋ ์๋ผ๋ธ ๋ถ๋ถ์ ์ข์๋จ ์ขํ 3๊ฐ ์
๋๋ค.
left_tops = [(400,500), (300,1200), (0,1000)]
images = []
for left_top in left_tops:
img1 = crop(bicubic_hr, left_top, 200, 200)
img2 = crop(srcnn_hr , left_top, 200, 200)
img3 = crop(hr, left_top, 200, 200)
images.extend([img1, img2, img3])
labels = ["Bicubic", "SRCNN", "HR"] * 3
plt.figure(figsize=(18,18))
for i in range(9):
plt.subplot(3,3,i+1)
plt.imshow(images[i])
plt.title(labels[i], fontsize=30)
์๊ฐํ ๊ฒฐ๊ณผ bicubic interpolation ๊ฒฐ๊ณผ๋ณด๋ค ์กฐ๊ธ ๋ ์ ๋ช ํด์ก์ง๋ง ์๋ ๊ณ ํด์๋ ์ด๋ฏธ์ง์ ๋นํด ๋ง์กฑํ ๋งํ ์ฑ๋ฅ์ ์๋ ๊ฒ ๊ฐ๋ค. DIV2K ๋ฐ์ดํฐ์ ์ด ๋น๊ต์ ์ธ๋ฐํ ๊ตฌ์กฐ์ ์ด๋ฏธ์ง๊ฐ ๋ง์ SRCNN๊ณผ ๊ฐ์ด ๊ฐ๋จํ ๊ตฌ์กฐ๋ก๋ ๋ ์ด์ ํ์ต๋์ง ์๋ ๊ฒ์ผ๋ก ๋ณด์ธ๋ค. ์ค์ ๋ก SRCNN ๋ ผ๋ฌธ์์๋ ์๋์ ๊ฐ์ด ๋น๊ต์ ๊ฐ๋จํ ๊ตฌ์กฐ์ ์ด๋ฏธ์ง์ ๋ํด์๋ ๊ฝค๋ ๋ง์กฑํ ๋งํ ์ฑ๋ฅ์ ๋ณด์ฌ์ค๋ค.
SRCNN์ ์ด์ด์ ๊ฐ๋ตํ๊ฒ ์์๋ณธ SRGAN์ ๊ตฌํํ๊ณ ์คํํด๋ณด์. ๋ง์ฐฌ๊ฐ์ง๋ก ์ด์ SRCNN์ ์ฌ์ฉํ๋ DIV2K ๋ฐ์ดํฐ์ ์ ์ฌ์ฉํ๋ค.
SRCNN์ ์ ํด์๋ ์ด๋ฏธ์ง์ ๋ํด interpolationํ์ฌ ๊ณ ํด์๋ ์ด๋ฏธ์ง ํฌ๊ธฐ๋ก ๋ง์ถ ํ ์ ๋ ฅ์ผ๋ก ์ฌ์ฉํ์ง๋ง, SRGAN์ ๊ทธ๋ฌํ ๊ณผ์ ์ ๊ฑฐ์น์ง ์๋๋ค.
train, valid = tfds.load(
"div2k/bicubic_x4",
split=["train","validation"],
as_supervised=True
)
def preprocessing(lr, hr):
hr = tf.cast(hr, tf.float32) /255.
# ์ด๋ฏธ์ง์ ํฌ๊ธฐ๊ฐ ํฌ๋ฏ๋ก (96,96,3) ํฌ๊ธฐ๋ก ์์ ์์ญ์ ์๋ผ๋ด์ด ์ฌ์ฉํฉ๋๋ค.
hr_patch = tf.image.random_crop(hr, size=[96,96,3])
# ์๋ผ๋ธ ๊ณ ํด์๋ ์ด๋ฏธ์ง์ ๊ฐ๋ก, ์ธ๋ก ํฝ์
์๋ฅผ 1/4๋ฐฐ๋ก ์ค์
๋๋ค
# ์ด๋ ๊ฒ ๋ง๋ ์ ํด์๋ ์ด๋ฏธ์ง๋ฅผ SRGAN์ ์
๋ ฅ์ผ๋ก ์ฌ์ฉํฉ๋๋ค.
lr_patch = tf.image.resize(hr_patch, [96//4, 96//4], "bicubic")
return lr_patch, hr_patch
train = train.map(preprocessing).shuffle(buffer_size=10).repeat().batch(8)
valid = valid.map(preprocessing).repeat().batch(8)
๋จผ์ , ์ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ์ ๋ ฅ๋ฐ์ ๊ณ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๋ Generator๋ฅผ ๊ตฌํํด๋ณด์. SRGAN์ Generator ๋ถ๋ถ์ ์๋์ ๊ฐ๋ค.
๊ทธ๋ฆผ ๋ด์ k9n64s1
๋ผ๋ ํ๊ธฐ๋ Convolutional layer ๋ด์ hyperparameter ์ค์ ์ ๋ํ ์ ๋ณด์ด๋ฉฐ, k๋ kernel size, n์ ์ฌ์ฉ ํํฐ์ ์, s๋ stride๋ฅผ ๋ํ๋ธ๋ค. Tensorflow๋ก ๊ตฌํํ๋ค๋ฉด Conv2D(filters=64, kernel_size=9, strides=1, padding="same")
์ฒ๋ผ ์์ฑํ ์ ์๋ค. ์ถ๊ฐ๋ก ๋ชจ๋ stride๊ฐ 1์ธ convolutional layer์๋ ํจ๋ฉ์ ํตํด ์ถ๋ ฅ์ ํฌ๊ธฐ๋ฅผ ๊ณ์ ์ ์งํ๋ค.
SRGAN์ Generator์๋ skip-connection์ ๊ฐ์ง๊ณ ์์ผ๋ฉฐ, ์ด๋ Sequential API๋ก ๊ตฌํํ ์ ์์ผ๋ฏ๋ก Functional API๋ฅผ ์ด์ฉํด ์๋์ ๊ฐ์ด ๊ตฌํํ๋ค. ์ Generator ๊ทธ๋ฆผ์์ ๊ฐ layer๋ฅผ ๋ฐ๋ผ ๋น๊ตํ๋ฉด์ ์๋ ์ฝ๋๋ฅผ ์ดํดํด ๋ณด์.
from tensorflow.keras import Input, Model
# ๊ทธ๋ฆผ์ ํ๋์ ๋ธ๋ก์ ์ ์ํฉ๋๋ค.
def gene_base_block(x):
out = layers.Conv2D(64, 3, 1, "same")(x)
out = layers.BatchNormalization()(out)
out = layers.PReLU(shared_axes=[1,2])(out)
out = layers.Conv2D(64, 3, 1, "same")(out)
out = layers.BatchNormalization()(out)
return layers.Add()([x, out])
# ๊ทธ๋ฆผ์ ๋ค์ชฝ ์ฐ๋์ ๋ธ๋ก์ ์ ์ํฉ๋๋ค.
def upsample_block(x):
out = layers.Conv2D(256, 3, 1, "same")(x)
# ๊ทธ๋ฆผ์ PixelShuffler ๋ผ๊ณ ์ฐ์ฌ์ง ๋ถ๋ถ์ ์๋์ ๊ฐ์ด ๊ตฌํํฉ๋๋ค.
out = layers.Lambda(lambda x: tf.nn.depth_to_space(x, 2))(out)
return layers.PReLU(shared_axes=[1,2])(out)
# ์ ์ฒด Generator๋ฅผ ์ ์ํฉ๋๋ค.
def get_generator(input_shape=(None, None, 3)):
inputs = Input(input_shape)
out = layers.Conv2D(64, 9, 1, "same")(inputs)
out = residual = layers.PReLU(shared_axes=[1,2])(out)
for _ in range(5):
out = gene_base_block(out)
out = layers.Conv2D(64, 3, 1, "same")(out)
out = layers.BatchNormalization()(out)
out = layers.Add()([residual, out])
for _ in range(2):
out = upsample_block(out)
out = layers.Conv2D(3, 9, 1, "same", activation="tanh")(out)
return Model(inputs, out)
print("โ
")
์ด๋ฒ์๋ ์์ฑ๋ ๊ณ ํด์๋ ์ด๋ฏธ์ง์ ์ง์ง ๊ณ ํด์๋ ์ด๋ฏธ์ง ์ฌ์ด์์ ์ง์ง๋ฅผ ํ๋ณํด๋ด๋ Discriminator๋ฅผ ์๋ ๊ทธ๋ฆผ์ ๋ฐ๋ผ ๊ตฌํํด ๋ณด์. ๋ง์ฐฌ๊ฐ์ง๋ก Functional API๋ฅผ ์ฌ์ฉํ๋ค.
# ๊ทธ๋ฆผ์ ํ๋์ ๋ธ๋ก์ ์ ์ํฉ๋๋ค.
def disc_base_block(x, n_filters=128):
out = layers.Conv2D(n_filters, 3, 1, "same")(x)
out = layers.BatchNormalization()(out)
out = layers.LeakyReLU()(out)
out = layers.Conv2D(n_filters, 3, 2, "same")(out)
out = layers.BatchNormalization()(out)
return layers.LeakyReLU()(out)
# ์ ์ฒด Discriminator ์ ์ํฉ๋๋ค.
def get_discriminator(input_shape=(None, None, 3)):
inputs = Input(input_shape)
out = layers.Conv2D(64, 3, 1, "same")(inputs)
out = layers.LeakyReLU()(out)
out = layers.Conv2D(64, 3, 2, "same")(out)
out = layers.BatchNormalization()(out)
out = layers.LeakyReLU()(out)
for n_filters in [128, 256, 512]:
out = disc_base_block(out, n_filters)
out = layers.Dense(1024)(out)
out = layers.LeakyReLU()(out)
out = layers.Dense(1, activation="sigmoid")(out)
return Model(inputs, out)
SRGAN์ VGG19๋ฅผ ์ด์ฉํด content loss๋ฅผ ๊ณ์ฐํ๋ค. Tensorflow๋ ์ด๋ฏธ์ง๋ท ๋ฐ์ดํฐ๋ก๋ถํฐ ์ ํ์ต๋ VGG19๋ฅผ ์ ๊ณตํ๋ฏ๋ก ์ด๋ฅผ ์ด์ฉํด๋ณด์.
from tensorflow.python.keras import applications
def get_feature_extractor(input_shape=(None, None, 3)):
vgg = applications.vgg19.VGG19(
include_top=False,
weights="imagenet",
input_shape=input_shape
)
# ์๋ vgg.layers[20]์ vgg ๋ด์ ๋ง์ง๋ง convolutional layer ์
๋๋ค.
return Model(vgg.input, vgg.layers[20].output)
์ด์ ๋ถํฐ๋ ์์์ ์ ์ํ ์ ๊ฒฝ๋ง๋ค์ ์ด์ฉํด SRGAN์ ํ์ตํด๋ณด์. ์ด์ ์ SRCNN๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ํ์ต์ ๊ฝค๋ ์ค๋ ์๊ฐ์ด ์์๋๋ฏ๋ก SRGAN์ ํ์ต์ ์ฒ์๋ถํฐ ์ ๋ถ ์งํํ์ง ์๋๋ค. ์ฌ๊ธฐ์๋ 200๋ฒ์ ๋ฐ๋ณต๋ง ์งํํด๋ณธ๋ค.
from tensorflow.keras import losses, metrics, optimizers
generator = get_generator()
discriminator = get_discriminator()
vgg = get_feature_extractor()
# ์ฌ์ฉํ loss function ๋ฐ optimizer ๋ฅผ ์ ์ํฉ๋๋ค.
bce = losses.BinaryCrossentropy(from_logits=False)
mse = losses.MeanSquaredError()
gene_opt = optimizers.Adam()
disc_opt = optimizers.Adam()
def get_gene_loss(fake_out):
return bce(tf.ones_like(fake_out), fake_out)
def get_disc_loss(real_out, fake_out):
return bce(tf.ones_like(real_out), real_out) + bce(tf.zeros_like(fake_out), fake_out)
@tf.function
def get_content_loss(hr_real, hr_fake):
hr_real = applications.vgg19.preprocess_input(hr_real)
hr_fake = applications.vgg19.preprocess_input(hr_fake)
hr_real_feature = vgg(hr_real) / 12.75
hr_fake_feature = vgg(hr_fake) / 12.75
return mse(hr_real_feature, hr_fake_feature)
@tf.function
def step(lr, hr_real):
with tf.GradientTape() as gene_tape, tf.GradientTape() as disc_tape:
hr_fake = generator(lr, training=True)
real_out = discriminator(hr_real, training=True)
fake_out = discriminator(hr_fake, training=True)
perceptual_loss = get_content_loss(hr_real, hr_fake) + 1e-3 * get_gene_loss(fake_out)
discriminator_loss = get_disc_loss(real_out, fake_out)
gene_gradient = gene_tape.gradient(perceptual_loss, generator.trainable_variables)
disc_gradient = disc_tape.gradient(discriminator_loss, discriminator.trainable_variables)
gene_opt.apply_gradients(zip(gene_gradient, generator.trainable_variables))
disc_opt.apply_gradients(zip(disc_gradient, discriminator.trainable_variables))
return perceptual_loss, discriminator_loss
gene_losses = metrics.Mean()
disc_losses = metrics.Mean()
for epoch in range(1, 2):
for i, (lr, hr) in enumerate(train):
g_loss, d_loss = step(lr, hr)
gene_losses.update_state(g_loss)
disc_losses.update_state(d_loss)
# 10ํ ๋ฐ๋ณต๋ง๋ค loss๋ฅผ ์ถ๋ ฅํฉ๋๋ค.
if (i+1) % 10 == 0:
print(f"EPOCH[{epoch}] - STEP[{i+1}] \nGenerator_loss:{gene_losses.result():.4f} \nDiscriminator_loss:{disc_losses.result():.4f}", end="\n\n")
if (i+1) == 200:
break
gene_losses.reset_states()
disc_losses.reset_states()
SRGAN์ ํฌ๊ฒ ๋ ๊ฐ์ ์ ๊ฒฝ๋ง(Generator, Discriminator)์ผ๋ก ๊ตฌ์ฑ๋์ด ์์ง๋ง, ํ ์คํธ์๋ ์ ํด์๋ ์ ๋ ฅ์ ๋ฃ์ด ๊ณ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ์ถ๋ ฅํ๋ Generator๋ง ์ด์ฉํ๋ค. ์๋ srgan_G.h5 ํ์ผ์ ํ์ต์ด ์๋ฃ๋ Generator์ด๋ฉฐ, ์ด๋ฅผ ๋ค์ด๋ก๋๋ฐ์ ์ฝ๋๋ฅผ ์คํํด ํ์ต ์๋ฃ๋ ๋ชจ๋ธ์ ๋ถ๋ฌ์จ๋ค.
import tensorflow as tf
import os
model_file = os.getenv('HOME')+'/aiffel/super_resolution/srgan_G.h5'
srgan = tf.keras.models.load_model(model_file)
์๋ ์ฝ๋์ ๊ฐ์ด ํ ์คํธ ๊ณผ์ ์ ์งํํ๋ ํจ์๋ฅผ ๊ฐ๋จํ๊ฒ ์ ์ํ๊ณ , ์ด ํจ์๋ฅผ ์ด์ฉํด ์ด์ ์ ์ฌ์ฉํ๋ ์ด๋ฏธ์ง์ ๋ํด SRGAN์ ๊ณ ํด์๋ ๊ฒฐ๊ณผ๋ฅผ ์์ฑํ๋ค.
def apply_srgan(image):
image = tf.cast(image[np.newaxis, ...], tf.float32)
sr = srgan.predict(image)
sr = tf.clip_by_value(sr, 0, 255)
sr = tf.round(sr)
sr = tf.cast(sr, tf.uint8)
return np.array(sr)[0]
train, valid = tfds.load(
"div2k/bicubic_x4",
split=["train","validation"],
as_supervised=True
)
for i, (lr, hr) in enumerate(valid):
if i == 6: break
srgan_hr = apply_srgan(lr)
์ด๋ฏธ์ง ์ ์ฒด๋ฅผ ์๊ฐํํ์ ๋ ์ธ๋ถ์ ์ธ ์ ๋ช ํจ์ด ๋์ ๋์ง ์์๊ธฐ ๋๋ฌธ์, ์ผ๋ถ ์์ญ์ ์๋ผ๋ด์ด ์๊ฐ์ ์ผ๋ก ๋น๊ตํด๋ณด์. ์๋ ์ฝ๋๋ฅผ ์ด์ฉํด 3๊ฐ ์ด๋ฏธ์ง(bicubic interpolation์ ๊ฒฐ๊ณผ, SRGAN์ ๊ฒฐ๊ณผ, ์๋ ๊ณ ํด์๋ ์ด๋ฏธ์ง)๋ฅผ ๋๋ํ ์๊ฐํํ๋ค.
# ์์ธํ ์๊ฐํ ํ๊ธฐ ์ํด 3๊ฐ ์์ญ์ ์๋ผ๋
๋๋ค.
# ์๋๋ ์๋ผ๋ธ ๋ถ๋ถ์ ์ข์๋จ ์ขํ 3๊ฐ ์
๋๋ค.
left_tops = [(400,500), (300,1200), (0,1000)]
images = []
for left_top in left_tops:
img1 = crop(bicubic_hr, left_top, 200, 200)
img2 = crop(srgan_hr , left_top, 200, 200)
img3 = crop(hr, left_top, 200, 200)
images.extend([img1, img2, img3])
labels = ["Bicubic", "SRGAN", "HR"] * 3
plt.figure(figsize=(18,18))
for i in range(9):
plt.subplot(3,3,i+1)
plt.imshow(images[i])
plt.title(labels[i], fontsize=30)
์๊ฐํ ๊ฒฐ๊ณผ bicubic interpolation๋ณด๋ค ํจ์ฌ ๋ ์๋ ๊ณ ํด์๋ ์ด๋ฏธ์ง์ ๊ฐ๊น์ด, ๊ฝค๋ ๋ง์กฑํ ๋งํ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ๊ฒ ๊ฐ๋ค. ์ด์ ์ ์ฌ์ฉํ๋ SRCNN ๋ณด๋ค ๋ ๊น์ ์ ๊ฒฝ๋ง ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํ๊ณ , GAN ๋ฐ VGG ๊ตฌ์กฐ๋ฅผ ์ด์ฉํ ์์ค ํจ์๋ฅผ ์ฌ์ฉํด ๋ณต์กํ๊ฒ ํ์ต ๊ณผ์ ์ ๊ตฌ์ฑํ ์๋ฏธ๊ฐ ์๋ ๊ฒ ๊ฐ๋ค.
์ ๊ทธ๋ฆผ์ SRGAN ๋ ผ๋ฌธ์์ ์ธ๋ถ์ ์ผ๋ก ์คํํ ๊ฒฐ๊ณผ๋ฅผ ๋ํ๋ธ๋ค. ๊ฐ์ฅ ์ฒซ ๋ฒ์งธ SRResNet์ SRGAN์ Generator๋ฅผ ๋ปํ๋ฉฐ, Generator ๊ตฌ์กฐ๋ง ์ด์ฉํด SRCNN๊ณผ ๋น์ทํ๊ฒ MSE ์์คํจ์๋ก ํ์ตํ ๊ฒฐ๊ณผ๋ค. ์ค๋ฅธ์ชฝ์ผ๋ก ๊ฐ์๋ก GAN ๋ฐ VGG ๊ตฌ์กฐ๋ฅผ ์ด์ฉํ์ฌ ์ ์ ๋ ์ด๋ฏธ์ง ๋ด ์ธ๋ถ์ ์ธ ๊ตฌ์กฐ๊ฐ ์ ๋ช ํด์ง์ ์ ์ ์๋ค. (VGG22๋ VGG54์ ๋นํด ๋ low-level์ ํน์ง์์ ์์ค์ ๊ณ์ฐํ๋ค)
Super Resolution ๊ฒฐ๊ณผ๊ฐ ์ผ๋ง๋ ์ข์์ง ๋ง์ ์ฐ๊ตฌ๋ค์์ ์ฌ์ฉ๋๋ ์ ๋์ ์ธ ํ๊ฐ ์ฒ๋๊ฐ ๋ช ๊ฐ์ง ์๋ค. ์ด๋ฒ์๋ ์ด๋ฌํ ์ฒ๋์ ๋ํด ๊ฐ๋ตํ๊ฒ ์์๋ณด๊ณ ์ด๋ฅผ ํ์ฉํด ์์ ์งํํ SRCNN๊ณผ SRGAN ๋ชจ๋ธ ๊ฐ๊ฐ์ด ๋ง๋ค์ด๋ธ ๊ณ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ๋น๊ตํด ๋ณด์.
PSNR(Peak Signal-to-Noise Ratio)์ ์์ ๋ด ์ ํธ๊ฐ ๊ฐ์ง ์ ์๋ ์ต๋ ์ ํธ์ ๋ํ ์ก์(noise)์ ๋น์จ์ ๋ํ๋ธ๋ค. ์ผ๋ฐ์ ์ผ๋ก ์์์ ์์ถํ์ ๋ ํ์ง์ด ์ผ๋ง๋ ์์ค๋์๋์ง ํ๊ฐํ๋ ๋ชฉ์ ์ผ๋ก ์ฌ์ฉ๋๋ค. ๋ฐ์๋ฒจ(db) ๋จ์๋ฅผ ์ฌ์ฉํ๋ฉฐ, PSNR ์์น๊ฐ ๋์์๋ก ์๋ณธ ์์์ ๋นํด ์์ค์ด ์ ๋ค๋ ์๋ฏธ์ด๋ค (๊ฐ์ด ๋์์๋ก ์ข๋ค).
SSIM(Structural Similarity Index Map)์ ์์์ ๊ตฌ์กฐ ์ ๋ณด๋ฅผ ๊ณ ๋ คํ์ฌ ์ผ๋ง๋ ๊ตฌ์กฐ ์ ๋ณด๋ฅผ ๋ณํ์ํค์ง ์์๋์ง๋ฅผ ๊ณ์ฐํ๋ค. ํน์ ์์์ ๋ํ SSIM๊ฐ์ด ๋์์๋ก ์๋ณธ ์์์ ํ์ง์ ๊ฐ๊น๋ค๋ ์๋ฏธ์ด๋ค (๋ง์ฐฌ๊ฐ์ง๋ก ๊ฐ์ด ๋์์๋ก ์ข๋ค).
- ์ต๋์ ํธ๋์ก์๋น(PSNR)์ ์ด๋ฏธ์ง ํ์ง
- 2D ์ด๋ฏธ์ง ํ์ง ํ๊ฐ์ ๊ตฌ์กฐ๋ณํ๋ฅผ ๋ฐ์ํ๋ SSIM๊ณผ ๊ทธ์ ๋ณํ๋ค
PSNR๊ณผ SSIM์ scikit-image ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ด์ฉํด ์ฝ๊ฒ ๊ณ์ฐํ ์ ์๋ค.
from skimage import data
import matplotlib.pyplot as plt
hr_cat = data.chelsea() # skimage์์ ์ ๊ณตํ๋ ์์ ์ด๋ฏธ์ง๋ฅผ ๋ถ๋ฌ์ต๋๋ค.
hr_shape = hr_cat.shape[:2]
print(hr_cat.shape) # ์ด๋ฏธ์ง์ ํฌ๊ธฐ๋ฅผ ์ถ๋ ฅํฉ๋๋ค.
plt.figure(figsize=(8,5))
plt.imshow(hr_cat)
# ๋์ผํ ์ด๋ฏธ์ง๋ก ๋น๊ต
from skimage.metrics import peak_signal_noise_ratio, structural_similarity
print("**๋์ผ ์ด๋ฏธ์ง ๋น๊ต**")
print("PSNR :", peak_signal_noise_ratio(hr_cat, hr_cat))
print("SSIM :", structural_similarity(hr_cat, hr_cat, multichannel=True))
PSNR๊ณผ SSIM ๋ชจ๋ ๋์ ๊ฐ์ ๊ฐ์ง์๋ก ์๋ณธ ์ด๋ฏธ์ง์ ๊ฐ๊น๋ค๋ ๊ฒ์ ์๋ฏธํ๋ฉฐ, ๋์ผํ ์ด๋ฏธ์ง๋ฅผ ๋น๊ตํ๊ธฐ ๋๋ฌธ์ ๋ ๊ฒฐ๊ณผ๋ ๊ฐ๊ฐ ๊ฐ์ง ์ ์๋ ์ต๋๊ฐ์ ๊ฐ์ง๋ค. PSNR์ ์ํ๊ฐ์ด ์๊ณ , SSIM์ 0~1 ์ฌ์ด์ ๊ฐ์ ๊ฐ์ง๊ธฐ ๋๋ฌธ์ ๊ฐ๊ฐ inf์ 1์ด ๊ณ์ฐ๋๋ค.
์ด๋ฒ์๋ ์๋ ์ฝ๋๋ฅผ ์ด์ฉํด ๊ณ ์์ด์ ๊ฐ๋ก ์ธ๋ก ํฝ์ ์๋ฅผ ๊ฐ๊ฐ 1/2, 1/4, 1/8๋ก ์ค์ด๊ณ , bicubic interpolation์ ์ด์ฉํด ์๋ ํฌ๊ธฐ๋ก ๋ณต์ํ๋ค. ๊ฐ๊ฐ ์ฒ๋ฆฌ๋ ์ด๋ฏธ์ง์ ๋ํด ์๋ณธ ์ด๋ฏธ์ง์์ PSNR๊ณผ SSIM์ ๊ณ์ฐํ๊ณ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ์ ๋ชฉ์ ํ์ํด ๋ณด์.
import cv2
# ์ด๋ฏธ์ง๋ฅผ ํน์ ํฌ๊ธฐ๋ก ์ค์ด๊ณ ๋ค์ ๋๋ฆฌ๋ ๊ณผ์ ์ ํจ์๋ก ์ ์ํฉ๋๋ค.
def interpolation_xn(image, n):
downsample = cv2.resize(
image,
dsize=(hr_shape[1]//n, hr_shape[0]//n)
)
upsample = cv2.resize(
downsample,
dsize=(hr_shape[1], hr_shape[0]),
interpolation=cv2.INTER_CUBIC
)
return upsample
lr2_cat = interpolation_xn(hr_cat, 2) # 1/2๋ก ์ค์ด๊ณ ๋ค์ ๋ณต์
lr4_cat = interpolation_xn(hr_cat, 4) # 1/4๋ก ์ค์ด๊ณ ๋ค์ ๋ณต์
lr8_cat = interpolation_xn(hr_cat, 8) # 1/8๋ก ์ค์ด๊ณ ๋ค์ ๋ณต์
images = [hr_cat, lr2_cat, lr4_cat, lr8_cat]
titles = ["HR", "x2", "x4", "x8"]
# ๊ฐ ์ด๋ฏธ์ง์ ๋ํด PSNR์ ๊ณ์ฐํ๊ณ ๋ฐ์ฌ๋ฆผํฉ๋๋ค.
psnr = [round(peak_signal_noise_ratio(hr_cat, i), 3) for i in images]
# ๊ฐ ์ด๋ฏธ์ง์ ๋ํด SSIM์ ๊ณ์ฐํ๊ณ ๋ฐ์ฌ๋ฆผํฉ๋๋ค.
ssim = [round(structural_similarity(hr_cat, i, multichannel=True), 3) for i in images]
# ์ด๋ฏธ์ง ์ ๋ชฉ์ PSNR๊ณผ SSIM์ ํฌํจํ์ฌ ์๊ฐํ ํฉ๋๋ค.
plt.figure(figsize=(16,10))
for i in range(4):
plt.subplot(2,2,i+1)
plt.imshow(images[i])
plt.title(titles[i] + f" [{psnr[i]}/{ssim[i]}]", fontsize=20)
๊ฐ ์ด๋ฏธ์ง์ ์ ๋ชฉ์ PSNR๊ณผ SSIM์ด ์์๋๋ก ๋ํ๋ฌ๋ค. ํด์๋๋ฅผ ์ค์ผ์๋ก ๊ทธ ์ด๋ฏธ์ง๋ฅผ ์๋ ํฌ๊ธฐ๋ก interploation ํ์ ๋, ๊ฐ๊ฐ์ ๊ณ์ฐ ๊ฒฐ๊ณผ๊ฐ ๋์ ๋๊ฒ ๊ฐ์ํ๋ ๊ฒ์ ์ ์ ์๋ค.
์ด๋ฒ์๋ ์์ ์คํํ๋ SRCNN๊ณผ SRGAN์ ๊ฒฐ๊ณผ๋ฅผ ๋จผ์ ์๊ฐ์ ์ผ๋ก๋ง ๋น๊ตํด ๋ณด์. ์ด์ ์ ๋ถ๋ฌ์จ DIV2K ๋ฐ์ดํฐ์ ๋ด์์ ํ์ต์ ์ฌ์ฉํ์ง ์์ ๊ฒ์ฆ์ฉ ๋ฐ์ดํฐ์ ์ ์ด์ฉํ๋ฉฐ, ๋ช ๊ฐ ์ด๋ฏธ์ง๋ง ๋ฝ์์ Super Resolution์ ์งํํ ํ ํน์ ๋ถ๋ถ์ ์๋ผ๋ด์ด ํ๋ํ๋ค.
for i, (lr, hr) in enumerate(valid):
if i == 12: break # 12๋ฒ์งธ ์ด๋ฏธ์ง๋ฅผ ๋ถ๋ฌ์ต๋๋ค.
lr_img, hr_img = np.array(lr), np.array(hr)
# bicubic interpolation
bicubic_img = cv2.resize(
lr_img,
(hr.shape[1], hr.shape[0]),
interpolation=cv2.INTER_CUBIC
)
# ์ ์ฒด ์ด๋ฏธ์ง๋ฅผ ์๊ฐํํฉ๋๋ค.
plt.figure(figsize=(20,15))
plt.subplot(311); plt.imshow(hr_img)
# SRCNN์ ์ด์ฉํด ๊ณ ํด์๋๋ก ๋ณํํฉ๋๋ค.
srcnn_img = apply_srcnn(bicubic_img)
# SRGAN์ ์ด์ฉํด ๊ณ ํด์๋๋ก ๋ณํํฉ๋๋ค.
srgan_img = apply_srgan(lr_img)
images = [bicubic_img, srcnn_img, srgan_img, hr_img]
titles = ["Bicubic", "SRCNN", "SRGAN", "HR"]
left_top = (700, 1090) # ์๋ผ๋ผ ๋ถ๋ถ์ ์ผ์ชฝ ์๋จ ์ขํ๋ฅผ ์ง์ ํฉ๋๋ค.
# bicubic, SRCNN, SRGAN ์ ์ ์ฉํ ์ด๋ฏธ์ง์ ์๋์ ๊ณ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ์๊ฐํํฉ๋๋ค.
plt.figure(figsize=(20,20))
for i, pind in enumerate([321, 322, 323, 324]):
plt.subplot(pind)
plt.imshow(crop(images[i], left_top, 200, 350))
plt.title(titles[i], fontsize=30)
์๋์ฐจ์ ์๋ถ๋ถ์ ์๋ผ๋ด์ด ํ๋ํ ๊ฒฐ๊ณผ ๊ณ ํด์๋ ์ด๋ฏธ์ง์ ๋น๊ตํ ๋ Bicubic๊ณผ SRCNN์ ๋ง์ด ํ๋ฆฟํ์ง๋ง SRGAN์ ๊ฒฐ๊ณผ๋ ๋งค์ฐ ๋น์ทํ๋ค.
for i, (lr, hr) in enumerate(valid):
if i == 15: break
lr_img, hr_img = np.array(lr), np.array(hr)
bicubic_img = cv2.resize(
lr_img,
(hr.shape[1], hr.shape[0]),
interpolation=cv2.INTER_CUBIC
)
plt.figure(figsize=(20,15))
plt.subplot(311); plt.imshow(hr_img)
srcnn_img = apply_srcnn(bicubic_img)
srgan_img = apply_srgan(lr_img)
images = [bicubic_img, srcnn_img, srgan_img, hr_img]
titles = ["Bicubic", "SRCNN", "SRGAN", "HR"]
left_top = (600, 1500)
plt.figure(figsize=(20,20))
for i, pind in enumerate([321, 322, 323, 324]):
plt.subplot(pind)
plt.imshow(crop(images[i], left_top, 200, 350))
plt.title(titles[i], fontsize=30)
for i, (lr, hr) in enumerate(valid):
if i == 8: break
lr_img, hr_img = np.array(lr), np.array(hr)
bicubic_img = cv2.resize(
lr_img,
(hr.shape[1], hr.shape[0]),
interpolation=cv2.INTER_CUBIC
)
plt.figure(figsize=(20,15))
plt.subplot(311); plt.imshow(hr_img)
srcnn_img = apply_srcnn(bicubic_img)
srgan_img = apply_srgan(lr_img)
images = [bicubic_img, srcnn_img, srgan_img, hr_img]
titles = ["Bicubic", "SRCNN", "SRGAN", "HR"]
left_top = (900, 1500)
plt.figure(figsize=(20,20))
for i, pind in enumerate([321, 322, 323, 324]):
plt.subplot(pind)
plt.imshow(crop(images[i], left_top, 200, 350))
plt.title(titles[i], fontsize=30)
for i, (lr, hr) in enumerate(valid):
if i == 24: break
lr_img, hr_img = np.array(lr), np.array(hr)
bicubic_img = cv2.resize(
lr_img,
(hr.shape[1], hr.shape[0]),
interpolation=cv2.INTER_CUBIC
)
plt.figure(figsize=(20,15))
plt.subplot(311); plt.imshow(hr_img)
srcnn_img = apply_srcnn(bicubic_img)
srgan_img = apply_srgan(lr_img)
images = [bicubic_img, srcnn_img, srgan_img, hr_img]
titles = ["Bicubic", "SRCNN", "SRGAN", "HR"]
left_top = (700, 1300)
plt.figure(figsize=(20,20))
for i, pind in enumerate([321, 322, 323, 324]):
plt.subplot(pind)
plt.imshow(crop(images[i], left_top, 200, 350))
plt.title(titles[i], fontsize=30)
# ์ง์ ํด๋ณด๊ธฐ
for i, (lr, hr) in enumerate(valid):
# ๋ถ๋ฌ์ฌ ์ด๋ฏธ์ง์ ์ธ๋ฑ์ค๋ฅผ ์ง์ ํฉ๋๋ค.
# ์์์ ์๊ฐํ ํ๋ 8, 12, 15, 24 ๋ฒ์ ์ ์ธํ ๋ค๋ฅธ ์ซ์๋ฅผ ๋ฃ์ด๋ด
์๋ค
if i == ##TODO## :
break
lr_img, hr_img = np.array(lr), np.array(hr)
bicubic_img = cv2.resize(
lr_img,
(hr.shape[1], hr.shape[0]),
interpolation=cv2.INTER_CUBIC
)
plt.figure(figsize=(20,15))
plt.subplot(311); plt.imshow(hr_img)
srcnn_img = apply_srcnn(bicubic_img)
srgan_img = apply_srgan(lr_img)
images = [bicubic_img, srcnn_img, srgan_img, hr_img]
titles = ["Bicubic", "SRCNN", "SRGAN", "HR"]
# ์๋ผ๋ผ ๋ถ๋ถ์ ์ผ์ชฝ ์๋จ ์ขํ๋ฅผ ์ง์ ํฉ๋๋ค.
left_top = ##TODO##
plt.figure(figsize=(20,20)) # ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ ์กฐ์ ํ ์ ์์ต๋๋ค.
for i, pind in enumerate([321, 322, 323, 324]):
plt.subplot(pind)
# crop ํจ์ ๋ด์ ์ธ๋ฒ์งธ ๋ค๋ฒ์งธ ์ธ์๋ฅผ ์์ ํด ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ ์กฐ์ ํฉ๋๋ค.
plt.imshow(crop(images[i], left_top, 200, 350))
plt.title(titles[i], fontsize=30)
์ด๋ฒ์๋ ๊ฐ Super Resolution ๊ฒฐ๊ณผ์ ์๋ ๊ณ ํด์๋ ์ด๋ฏธ์ง ์ฌ์ด์ PSNR, SSIM์ ๊ณ์ฐํด ๋ณด์. ์ด์ ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ์๋ ์ฝ๋๋ฅผ ์ด์ฉํด ๊ฐ ์ด๋ฏธ์ง์ ์ ๋ชฉ์ ํ๊ฐ ๊ฒฐ๊ณผ๋ฅผ ํจ๊ป ํ์ํ๋๋ก ํ๋ค.
for i, (lr, hr) in enumerate(valid):
if i == 24: break
lr_img, hr_img = np.array(lr), np.array(hr)
bicubic_img = cv2.resize(
lr_img,
(hr.shape[1], hr.shape[0]),
interpolation=cv2.INTER_CUBIC
)
srcnn_img = apply_srcnn(bicubic_img)
srgan_img = apply_srgan(lr_img)
images = [bicubic_img, srcnn_img, srgan_img, hr_img]
titles = ["Bicubic", "SRCNN", "SRGAN", "HR"]
# ๊ฐ ์ด๋ฏธ์ง์ ๋ํด PSNR์ ๊ณ์ฐํ๊ณ ๋ฐ์ฌ๋ฆผํฉ๋๋ค.
psnr = [round(peak_signal_noise_ratio(hr_img, i), 3) for i in images]
# ๊ฐ ์ด๋ฏธ์ง์ ๋ํด SSIM์ ๊ณ์ฐํ๊ณ ๋ฐ์ฌ๋ฆผํฉ๋๋ค.
ssim = [round(structural_similarity(hr_img, i, multichannel=True), 3) for i in images]
# ์ด๋ฏธ์ง ์ ๋ชฉ์ PSNR๊ณผ SSIM์ ํฌํจํ์ฌ ์๊ฐํ ํฉ๋๋ค.
plt.figure(figsize=(18,13))
for i in range(4):
plt.subplot(2,2,i+1)
plt.imshow(images[i])
plt.title(titles[i] + f" [{psnr[i]}/{ssim[i]}]", fontsize=30)
์๊ฐ์ ์ผ๋ก ๊ฐ์ฅ ๊ณ ํด์๋ ์ด๋ฏธ์ง์ ๊ฐ๊น์ ๋ SRGAN์ ๊ฒฐ๊ณผ๊ฐ ๋ค๋ฅธ ๋ฐฉ๋ฒ๋ค์ ๋นํด ๋ฎ์ PSNR๊ณผ SSIM ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ก๋ค. ์๋์์ ์ด ์ด๋ฏธ์ง์ ๋ํด ํน์ ๋ถ๋ถ์ ์๋ผ๋ด๊ณ , ์๋ผ๋ธ ์ด๋ฏธ์ง๋ก PSNR, SSIM์ ๊ณ์ฐํด๋ณด์.
left_top = (620, 570)
crop_images = [crop(i, left_top, 150, 250) for i in images]
psnr = [round(peak_signal_noise_ratio(crop_images[-1], i), 3) for i in crop_images]
ssim = [round(structural_similarity(crop_images[-1], i, multichannel=True), 3) for i in crop_images]
plt.figure(figsize=(18,10))
for i in range(4):
plt.subplot(2,2,i+1)
plt.imshow(crop_images[i])
plt.title(titles[i] + f" [{psnr[i]}/{ssim[i]}]", fontsize=30)
SRCNN ๊ฒฐ๊ณผ์ ๊ฒฝ์ฐ ์ฝ๊ฐ ์ ๋ช ํด์ก์ง๋ง ์ ์ฒด์ ์ผ๋ก ์ฌ์ ํ ๊ณ ํด์๋ ์์์ ๋นํด ํ๋ฆฟํ๋ค. SRCNN์ ํ์ต์ Mean Squared Error๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์, ์์ฑํด์ผ ํ ํฝ์ ๊ฐ๋ค์ ๊ณ ํด์๋ ์ด๋ฏธ์ง์ ๋น๊ตํด ๋จ์ํ ํ๊ท ์ ์ผ๋ก ์ ๋ง์ถ๋ ๋ฐฉํฅ์ผ๋ก ์์ธกํ๊ธฐ ๋๋ฌธ์ด๋ค. ์ด๋ฌํ ๋ฌธ์ ๋ SRCNN ๋ฟ๋ง ์๋๋ผ MSE๋ง์ ์ฌ์ฉํด ํ์ตํ๋ ๋๋ถ๋ถ์ ์ ๊ฒฝ๋ง์์ ๋ฐ์ํ๋ ํ์์ด๊ธฐ๋ ํ๋ค.
SRGAN ๊ฒฐ๊ณผ์ ๊ฒฝ์ฐ ๋งค์ฐ ์ ๋ช
ํ๊ฒ ์ด์ํจ์ ํ์ธํ ์ ์๋ค. ์ด๋ Generator๊ฐ ๊ณ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๋ ๊ณผ์ ์์ Discriminator๋ฅผ ์์ด๊ธฐ ์ํด ์ด๋ฏธ์ง๋ฅผ ์ง์ง ๊ฐ์ด ์ ๋ช
ํ๊ฒ ๋ง๋ค๋๋ก ํ์ต ๋์๊ธฐ ๋๋ฌธ์ด๋ค. ์ถ๊ฐ๋ก ์์ ์ค๋ช
ํ๋ฏ์ด VGG๊ตฌ์กฐ๋ฅผ ์ด์ฉํ content loss
๋ฅผ ํตํด ํ์ตํ ๊ฒ ๋ํ ์ฌ์ค์ ์ธ ์ด๋ฏธ์ง๋ฅผ ํ์ฑํ๋๋ฐ ํฌ๊ฒ ๊ธฐ์ฌํ๋ค๊ณ ๋ณผ ์ ์๋ค. ๋ค๋ง, ์
๋ ฅ๋์๋ ์ ํด์๋ ์ด๋ฏธ์ง๊ฐ ๋งค์ฐ ์ ํ๋ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์๊ธฐ์ ๊ณ ํด์๋ ์ด๋ฏธ์ง์ ์ธ๋ถ์ ์ผ๋ก ๋์ผํ ๋ชจ์์ผ๋ก ์ ๋ช
ํ์ง ์์ ๊ฒ์ด๋ค.
for i, (lr, hr) in enumerate(valid):
# ๋ถ๋ฌ์ฌ ์ด๋ฏธ์ง์ ์ธ๋ฑ์ค๋ฅผ ์ง์ ํฉ๋๋ค.
# ์์์ ์๊ฐํ ํ๋ 8, 12, 15, 24 ๋ฒ์ ์ ์ธํ ๋ค๋ฅธ ์ซ์๋ฅผ ๋ฃ์ด๋ด
์๋ค
if i == ##TODO## :
break
lr_img, hr_img = np.array(lr), np.array(hr)
bicubic_img = cv2.resize(
lr_img,
(hr.shape[1], hr.shape[0]),
interpolation=cv2.INTER_CUBIC
)
# ํ๋ํ ๋ถ๋ถ์ ์ผ์ชฝ ์๋จ ์ขํ๋ฅผ ์ง์ ํฉ๋๋ค.
left_top = ##TODO##
# crop ํจ์ ๋ด์ ์ธ๋ฒ์งธ ๋ค๋ฒ์งธ ์ธ์๋ฅผ ์์ ํด ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ ์กฐ์ ํฉ๋๋ค.
crop_images = [crop(i, left_top, 150, 250) for i in images]
titles = ["Bicubic", "SRCNN", "SRGAN", "HR"]
psnr = [round(peak_signal_noise_ratio(crop_images[-1], i), 3) for i in crop_images]
ssim = [round(structural_similarity(crop_images[-1], i, multichannel=True), 3) for i in crop_images]
plt.figure(figsize=(18,10)) # ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ ์กฐ์ ํ ์ ์์ต๋๋ค.
for i in range(4):
plt.subplot(2,2,i+1)
plt.imshow(crop_images[i])
plt.title(titles[i] + f" [{psnr[i]}/{ssim[i]}]", fontsize=30)
์ด์ ์ ํ์ตํ๋ Super Resolution ๋ฐฉ๋ฒ๋ค์ ์ธ๋ถ์ ์ผ๋ก SISR(Single Image Super Resolution) ๋ฐฉ๋ฒ์ ์ํ๋ค. ๋จ์ด ๋ป ๊ทธ๋๋ก ํ ์ฅ์ ์ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ์ด์ฉํด ๊ณ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๋ค๋ ๊ฒ์ด๋ค. ๋ง์ฝ ์ฌ๋ฌ ์ฅ์ ์ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ์ ํ์ฉํด ๊ณ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๋ค๋ฉด ๋ ์ข์ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์์ ๊ฒ์ด๋ค.
RefSR(Reference-based Super Resolution)์ ์ด๋ฌํ ์ง๋ฌธ์ ๋ต์ด ๋ ์ ์๋ ๋ฐฉ๋ฒ ์ค ํ๋์ด๋ค. ๋ชจ๋ธ์ด ์ ํด์๋ ์ด๋ฏธ์ง๋ง์ ๋ฐ์์ ๊ณ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๋ ๊ฒ์ด ์๋๋ผ, ํด์๋๋ฅผ ๋์ด๋ ๋ฐ ์ฐธ๊ณ ํ ๋งํ ๋ค๋ฅธ ์ด๋ฏธ์ง๋ฅผ ๊ฐ์ด ์ ๊ณตํด ์ฃผ๋ ๊ฒ์ด๋ค.
์ด๋ฐ ๋ฐฉ๋ฒ์ ํ์ฉํ ์ฐ๊ตฌ ์ค 'Image Super-Resolution by Neural Texture Transfer' ๋ ผ๋ฌธ์์ ์ ์ํ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ฉด ์๋ ๊ทธ๋ฆผ๊ณผ ๊ฐ์ด ๋งค์ฐ ์ ๋ช ํ ๊ณ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ์ป์ ์ ์๋ค. Ref images๋ผ๊ณ ๋ํ๋ ๋ ์ด๋ฏธ์ง๋ฅผ ์ ๋ ฅ์ผ๋ก Super Resolution์ ์ํํ์ผ๋ฉฐ, SRNTT๋ผ๊ณ ๋ํ๋ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด ์ด์ ์ ํ์ตํ๋ SRGAN ๋ณด๋ค ํจ์ฌ ๋ ์ ๋ช ํ ๊ฒ์ ํ์ธํ ์ ์๋ค.
์ธ๊ณต์ง๋ฅ์ด ๊ฐ์ง ๋ฌธ์ ๋ค ์ค ํ๋๋ ์ฐจ๋ณ์ ๊ดํ ๊ฒ์ด๋ค. ์ธ๊ณต์ง๋ฅ ํ์ต์ ๊ฐ์ฅ ์ค์ํ ์ํฅ์ ์ฃผ๋ ๋ช ๊ฐ์ง ์์ธ๋ค ์ค ํ๋๋ ํ์ต์ ์ฌ์ฉํ๋ ๋ฐ์ดํฐ์ด๋ฉฐ, ์ด๋ฌํ ๋ฐ์ดํฐ๊ฐ ํธํฅ(bias)์ ๋ด๊ณ ์๋ค๋ฉด ๊ทธ๋ก๋ถํฐ ํ์ต๋ ์ธ๊ณต์ง๋ฅ์ ์๋ฌด๋ ์ง๋ ์๊ฒ ์ฐจ๋ณ์ ํ๊ฒ ๋๋ค.
์๋ฅผ ๋ค๋ฉด ์๋ง์กด์ด ๊ฐ๋ฐํ ์ธ๊ณต์ง๋ฅ ์ฑ์ฉ/์ธ์ฌ ์์คํ ์ด ์ฌ์ฑ์ ๋ํด ํธ๊ฒฌ์ ๊ฐ์ง๊ณ ์๋ค๋ ์ฑ์ฐจ๋ณ์ ์ฌ๋ก๊ฐ ์์๊ณ , ๊ตฌ๊ธ์ ์ด๋ฏธ์ง ์ธ์ ๋ชจ๋ธ์ด ์๋ ๊ทธ๋ฆผ๊ณผ ๊ฐ์ด ์์ ํผ๋ถ์์ ๋ฐ๋ผ ์ฒด์จ๊ณ๋ฅผ ์ด์ผ๋ก ์ธ์ํ๋ ์ธ์ข ์ฐจ๋ณ์ ์ฌ๋ก๊ฐ ์์๋ค (๋ฐฑ์ธ๊ณผ ๋ฌ๋ฆฌ ํ์ธ์ ์์๋ ์ด์ ๋ค๊ณ ์๋ค๊ณ ์ธ์).
์ค๋ ์ฐ๋ฆฌ๊ฐ ํ์ตํ Super Resolution ๋ฌธ์ ์์๋ ์ด๋ฌํ ์ฐจ๋ณ ์ฌ๋ก๊ฐ ์กด์ฌํ๋ค. ๋ฌธ์ ๊ฐ ๋ ๋ฐฉ๋ฒ์ 2020๋ ์ด์ ๋ฐํ๋ PULSE ๋ผ๋ ๊ตฌ์กฐ์ด๋ค. ์ด ๋ฐฉ๋ฒ์ ์๋ ๊ทธ๋ฆผ๊ณผ ๊ฐ์ด Super Resolution ๋ฌธ์ ์์ ๋งค์ฐ ์ข์ ์ฑ๋ฅ์ ๊ฐ๋๋ค. ์ ํด์๋ ์ด๋ฏธ์ง ๋ด์ ๊ฑฐ์ ์๋ ์ ๋ณด๋ฅผ ์์ ํ ์๋กญ๊ฒ ์์ฑํ๋ ์์ค์ด๋ค.
๋ฌธ์ ๋ ์ ํด์๋ ์ผ๊ตด ์ด๋ฏธ์ง๋ฅผ ์ ๋ ฅํ์ ๋, ๋ชจ๋ ๋ฐฑ์ธ์ผ๋ก ๋ง๋ค์ด ๋ธ๋ค๋ ๊ฒ์ด๋ค. ์๋ ์ฒซ ๋ฒ์งธ ๊ทธ๋ฆผ์ ์ ํด์๋ ์ด๋ฏธ์ง๋ ์ค๋ฐ๋ง ์ ๋ฏธ๊ตญ ๋ํต๋ น์ผ๋ก ๋ณด์ด๋๋ฐ, ์ด๋ฅผ ๊ณ ํด์๋๋ก ์์ฑํ์ ๋ ๊ฒฐ๊ณผ ์ด๋ฏธ์ง๋ก ๋ฐฑ์ธ์ด ๋ฑ์ฅํ๋ค. ์ ํด์๋ ์ ๋ ฅ ์ด๋ฏธ์ง๋ก ๋์์ธ์ด๋ ์บ๋ฆญํฐ๋ฅผ ๋ฃ์ด๋ ๋ง์ฐฌ๊ฐ์ง๋ก ๋ฐฑ์ธ์ด ์์ฑ๋จ์ ์๋ ๊ทธ๋ฆผ์ผ๋ก ํ์ธํ ์ ์๋ค.
PULSE ์ ์ฐ๊ตฌ์๋ค์ ์ด๋ฌํ ํ์์ด ํ์ตํ๋ ๋ฐ์ดํฐ์ ์์ ๊ธฐ์ธํ ๊ฒ์ด๋ผ ์ด์ผ๊ธฐํ๋ค. ๋ฐฑ์ธ ์์ฃผ๋ก ๊ตฌ์ฑ๋ ํ์ต๋ ๋ฐ์ดํฐ๋ก ์ธํด ์ ํด์๋ ์ผ๊ตด ์ด๋ฏธ์ง์์ ๋ง๋ค์ด์ผ ํ ์๋ก์ด ํฝ์ ๋ค์ด ๊ธฐ๋ณธ์ ์ผ๋ก ํฐ์์ ๊ฐ๊น๊ฒ ์ค์ ๋๊ฑฐ๋, ๋ฐฑ์ธ๊ณผ ๋น์ทํ ์ด๋ชฉ๊ตฌ๋น๊ฐ ํ์ฑ๋๋ ๊ฒ์ด๋ค. ์ด์ฉ๋ฉด ๋ฐฑ์ธ๋ค์ด ์ ์ธ๊ณ ์ธ๊ณต์ง๋ฅ ์ฐ๊ตฌ์ ๊ฝค ๋ง์ ๋ถ๋ถ์ ์ฐจ์งํ๊ณ ์๊ธฐ ๋๋ฌธ์ ์ด๋ฌํ ๊ฒฐ๊ณผ๊ฐ ์์ฐ์ค๋ฌ์ด ๊ฒ ๊ฐ๊ธฐ๋ ํ๋ค.
- ์ฐธ๊ณ ์๋ฃ: PR12 - SRCNN
- ์ฐธ๊ณ ์๋ฃ: PR12 - SRGAN
- ์ฐธ๊ณ ์๋ฃ: EDSR
- ์ฐธ๊ณ ์๋ฃ: ๋ฅ๋ฌ๋ Super Resolution ์ด๋๊น์ง ์๋?
- ๋ ธ๋๋ฅผ ์งํํ๊ธฐ ์ ์ ์ด๋ฏธ SRCNN์ผ๋ก ๋ง๋ค์ด์ง waifu2x ๋ผ๋ ์ฑ์ ์๊ณ ์์๊ธฐ ๋๋ฌธ์ ๋ ธ๋๋ฅผ ์งํํ๋๋ฐ ์์ด์ ์ด๋ ค์์ด ์์๋ค.
- ์ค์ ์๋ ์๋ฆฌ์ ๋ํด์๋ ์ ์์ง ๋ชปํ์๋๋ฐ ์ด๋ฒ ๋ ธ๋๋ฅผ ํตํด์ ํ์คํ๊ฒ ์ดํดํ ๊ฒ ๊ฐ๋ค.
- ์ด๋ฏธ์ง ๋ถ์ผ์์๋ CNN์ด ์ ๋ง ๋ง๋ฅ์ฒ๋ผ ๋ณด์ธ๋ค. ์ด๋ ๋ถ์ผ์์๋ ์ง ์ฌ์ฉ๋ง ํ๋ฉด ๊ฒฐ๊ณผ๋ฌผ์ ๋ฐ๋ก ๋ณผ ์ ์์ด์ ๊ทธ๋ฐ์ง ๋ ์ฒด๊ฐ์ด ํฐ ๊ฒ ๊ฐ๋ค.
http://blog.lgdisplay.com/2014/03/๋ชจ๋ํฐ-ํต์ฌ-๋์คํ๋ ์ด์-์คํ-๋ฐ๋ผ์ก๊ธฐ-ํด์๋/
https://blog.lgdisplay.com/2014/07/๊ทธ๋ฆผ์ผ๋ก-์ฝ๊ฒ-์์๋ณด๋-hd-ํด์๋์-์ฐจ์ด/
https://bskyvision.com/789 ์ ํ๋ณด๊ฐ๋ฒ ๋ฐ ์ผ์ฐจ๋ณด๊ฐ๋ฒ
https://blog.naver.com/dic1224/220882679460 ์์ ํ๋ณด๊ฐ๋ฒ
https://docs.opencv.org/master/da/d54/group__imgproc__transform.html#ga5bb5a1fea74ea38e1a5445ca803ff121 OpenCV Interpolation