Skip to content

Latest commit

ย 

History

History

exploration_16

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

16. ํ๋ฆฐ ์‚ฌ์ง„์„ ์„ ๋ช…ํ•˜๊ฒŒ

ํ•™์Šต ์ „์ œ

  • ์‹ ๊ฒฝ๋ง์˜ ํ•™์Šต ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ „๋ฐ˜์ ์ธ ์ ˆ์ฐจ๋ฅผ ์•Œ๊ณ  ์žˆ์–ด์•ผ ํ•œ๋‹ค.
  • 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 ์ด๋ž€?


Super Resolution์—์„œ Resolution์€ ํ•ด์ƒ๋„๋ฅผ ์ด์•ผ๊ธฐํ•œ๋‹ค.

image00

์˜์ƒ์„ ์ด์šฉํ•ด ์–ด๋– ํ•œ ์ผ์„ ํ•˜๋Š”์ง€์— ๋”ฐ๋ผ ์˜์ƒ ์ •๋ณด์˜ ์†์‹ค์„ ์ตœ๋Œ€ํ•œ ์ค„์ด๊ธฐ ์œ„ํ•ด ๊ณ ํ•ด์ƒ๋„ ์˜์ƒ์„ ํ•„์š”๋กœ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ํ”ํžˆ ์œ ํŠœ๋ธŒ ์˜์ƒ์„ ์‹œ์ฒญํ•˜๋Š” ๊ฒฝ์šฐ๋„ ๊ณ ํ•ด์ƒ๋„ ์˜์ƒ์„ ์„ ํ˜ธํ•œ๋‹ค.

image01

์ด๋ ‡๋“ฏ ๋Œ€๋ถ€๋ถ„์ด ๊ณ ํ•ด์ƒ๋„ ์˜์ƒ์„ ์›ํ•˜์ง€๋งŒ ํ•ญ์ƒ ์ข‹์€ ์ ๋งŒ ์žˆ๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ๊ณ ํ•ด์ƒ๋„ ์˜์ƒ์€ ์ €ํ•ด์ƒ๋„ ์˜์ƒ๋ณด๋‹ค ํฌ๊ธฐ๊ฐ€ ํ›จ์”ฌ ๋” ํฌ๊ธฐ ๋•Œ๋ฌธ์— ์ธํ„ฐ๋„ท ํ™˜๊ฒฝ์— ๋”ฐ๋ผ ์ „์†ก์— ๋งŽ์€ ์‹œ๊ฐ„์ด ํ•„์š”ํ•˜๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ์— ์˜ค๋Š˜ ํ•™์Šตํ•  Super Resolution ๊ธฐ์ˆ ์€ ์ข‹์€ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค. Super Resolution์ด๋ž€ ์ €ํ•ด์ƒ๋„ ์˜์ƒ์„ ๊ณ ํ•ด์ƒ๋„ ์˜์ƒ์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์ž‘์—… ๋˜๋Š” ๊ทธ๋Ÿฌํ•œ ๊ณผ์ •์„ ๋งํ•œ๋‹ค.

์ €ํ•ด์ƒ๋„์˜ ์œ ํŠœ๋ธŒ ์˜์ƒ์„ ๋น ๋ฅด๊ฒŒ ๋ฐ›์•„ Super Resolution ๊ธฐ์ˆ ๋กœ ๊ณ ํ•ด์ƒ๋„ ์˜์ƒ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ตœ์•…์˜ ์ธํ„ฐ๋„ท ํ™˜๊ฒฝ์—์„œ๋„ ์ถฉ๋ถ„ํžˆ ๊ณ ํ•ด์ƒ๋„์˜ ์˜์ƒ์„ ์‹œ์ฒญํ•  ์ˆ˜ ์žˆ๋‹ค.

Super Resolution์˜ ํ™œ์šฉ ์‚ฌ๋ก€


image02

์šฐ๋ฆฌ๋‚˜๋ผ์—์„œ ๊ฐ€์žฅ ๋Œ€ํ‘œ์ ์œผ๋กœ ๊ผฝํžˆ๋Š” Super Resolution ํ™œ์šฉ ์‚ฌ๋ก€๋Š” <ํ•˜์–€๊ฑฐํƒ‘>์ด๋ผ๋Š” ๋“œ๋ผ๋งˆ์˜ ๋ฆฌ๋งˆ์Šคํ„ฐ๋ง์ด๋‹ค. 2007๋…„ ์ฒ˜์Œ ๋ฐฉ์†ก ๋‹น์‹œ HD ํ™”์งˆ๋กœ ์†ก์ถœ๋˜์—ˆ๋˜ <ํ•˜์–€๊ฑฐํƒ‘>์€ UHD ํ™”์งˆ๋กœ ํ–ฅ์ƒ๋˜์–ด 2018๋…„ ์žฌ๋ฐฉ์†ก ๋˜์—ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” Super Resolution ๊ธฐ์ˆ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋…ธ์ด์ฆˆ ์ œ๊ฑฐ ๋“ฑ์˜ ์—ฌ๋Ÿฌ ์ž‘์—…์ด ๊ฑฐ์ณ์กŒ๋‹ค๊ณ  ํ•œ๋‹ค. ์ด์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ๊ณ  ์‹ถ๋‹ค๋ฉด ํ•˜์–€๊ฑฐํƒ‘ ๋ฆฌ๋งˆ์Šคํ„ฐ๋ง ์ œ์ž‘๊ธฐ๋ฅผ ์ž์„ธํžˆ ์ฝ์–ด๋ณด์ž.

image03

๊ฐ์‹œ ๋ฐ ๋ณด์•ˆ ์‹œ์Šคํ…œ์—์„œ ํ”ํžˆ ์‚ฌ์šฉ๋˜๋Š” CCTV๋Š” ๋Œ€์ƒ์˜ ๊ฑฐ๋ฆฌ๊ฐ€ ๋ฉ€์–ด์ง์— ๋”ฐ๋ผ ํš๋“ํ•œ ์˜์ƒ์˜ ํ•ด์ƒ๋„๊ฐ€ ์ €ํ•˜๋˜๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ•œ๋‹ค. ์ •๋ณด ์†์‹ค์ด ๋งŽ์€ ์ €ํ•ด์ƒ๋„ ์˜์ƒ์„ ํ™œ์šฉํ•œ๋‹ค๋ฉด ์ฐจ๋Ÿ‰์˜ ๋ฒˆํ˜ธํŒ์ด๋‚˜ ์–ผ๊ตด์„ ์ธ์‹ํ•˜๋Š” ๋ฐ ํฐ ์–ด๋ ค์›€์„ ๊ฒช๊ฑฐ๋‚˜ ์‹ฌ์ง€์–ด ์ธ์‹ ์ž์ฒด๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ๊ทน๋ณตํ•˜๊ธฐ ์œ„ํ•ด Super Resolution ๊ธฐ์ˆ ์„ ์ ์šฉํ•˜์—ฌ ๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•ด ์ธ์‹ ์„ฑ๋Šฅ์„ ๋†’์ด๋ ค๋Š” ๋งŽ์€ ์—ฐ๊ตฌ๊ฐ€ ์ง„ํ–‰๋˜๊ณ  ์žˆ๋‹ค.

image04

๋†’์€ ํ•ด์ƒ๋„๋ฅผ ๊ฐ–๋Š” ์˜๋ฃŒ ์˜์ƒ์„ ์ด์šฉํ•˜๋ฉด ๊ตฌ์กฐ ์ •๋ณด๋ฅผ ์ƒ์„ธํ•˜๊ฒŒ ๊ด€์ฐฐํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ์ •๋Ÿ‰์ ์ธ ์ด๋ฏธ์ง€ ๋ถ„์„ ๋ฐ ์ง„๋‹จ ๋“ฑ์˜ ์˜์‚ฌ ๊ฒฐ์ •์— ๋งŽ์€ ๋„์›€์„ ์ค„ ์ˆ˜ ์žˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ๊ณ ํ•ด์ƒ๋„์˜ ์˜๋ฃŒ ์˜์ƒ์„ ์–ป๋Š”๋ฐ ๋งค์šฐ ๊ธด ์Šค์บ” ์‹œ๊ฐ„์ด ํ•„์š”ํ•˜๊ฑฐ๋‚˜, ๋งŽ์€ ๋ฐฉ์‚ฌ์„ ์ด ํ™˜์ž์˜ ๋ชธ์— ๋…ธ์ถœ๋˜์–ด ๋‹ค๋ฅธ ๋ถ€์ž‘์šฉ์„ ์ดˆ๋ž˜ํ•  ์ˆ˜ ์žˆ๋‹ค. Super Resolution ๊ธฐ์ˆ ์€ ์ด๋Ÿฌํ•œ ๋‹จ์ ์„ ๊ทน๋ณตํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ์ˆ  ์ค‘ ํ•˜๋‚˜๋กœ ์‚ฌ์šฉ๋œ๋‹ค.

Super Resolution์„ ์–ด๋ ต๊ฒŒ ๋งŒ๋“œ๋Š” ์š”์ธ๋“ค


image05

์ฒซ ๋ฒˆ์งธ ์–ด๋ ค์šด ์ ์€ ํ•˜๋‚˜์˜ ์ €ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€์— ๋Œ€ํ•ด ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€๊ฐ€ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ์œ„ ๊ทธ๋ฆผ์€ 1๊ฐœ์˜ ์ €ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€(์ƒ๋‹จ ์ด๋ฏธ์ง€)์— ๋Œ€์‘ํ•˜๋Š” 3๊ฐœ์˜ ๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€(ํ•˜๋‹จ ์ด๋ฏธ์ง€)๋ฅผ ๋‚˜ํƒ€๋ƒˆ๋‹ค. 3๊ฐœ์˜ ๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€ ์‚ฌ์ด์—์„œ๋Š” ๋ˆˆ์œผ๋กœ ๋ณผ ๋•Œ ๊ฑฐ์˜ ์ฐจ์ด๋ฅผ ๋‚˜ํƒ€๋‚ด์ง€ ์•Š์ง€๋งŒ, ์•„๋ž˜ ํ™•๋Œ€ํ•œ ์ด๋ฏธ์ง€๋ฅผ ๋ณด๋ฉด ์„ธ๋ถ€์ ์œผ๋กœ ํ”ฝ์…€์˜ ๊ฐ’์ด ๊ฐ๊ฐ ๋‹ค๋ฅธ ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ํ•˜๋‚˜์˜ ์ €ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€๋ฅผ ๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€๋กœ ๋งŒ๋“œ๋Š”๋ฐ ๋งค์šฐ ๋‹ค์–‘ํ•œ ๊ฒฝ์šฐ์˜ ์ˆ˜๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์€ Super Resolution์ด ๊ฐ€์ง„ ํฐ ํŠน์ง•์ด๋ฉฐ, ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ill-posed (inverse) problem์ด๋ผ ๋ถ€๋ฅธ๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ Super Resolution ๋ชจ๋ธ์„ ํ•™์Šต์‹œํ‚ค๊ธฐ ์œ„ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๊ณผ์ •์€, ๋จผ์ € ๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€๋ฅผ ์ค€๋น„ํ•˜๊ณ  ํŠน์ •ํ•œ ์ฒ˜๋ฆฌ ๊ณผ์ •์„ ๊ฑฐ์ณ ์ €ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•˜๋ฉฐ, ์ƒ์„ฑ๋œ ์ €ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€๋ฅผ ์ž…๋ ฅ์œผ๋กœ ์›๋ž˜์˜ ๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€๋ฅผ ๋ณต์›ํ•˜๋„๋ก ํ•™์Šต์„ ์ง„ํ–‰ํ•œ๋‹ค.

image06

๋‘ ๋ฒˆ์งธ ์–ด๋ ค์šด ์ ์€ Super Resolution ๋ฌธ์ œ์˜ ๋ณต์žก๋„์ด๋‹ค. ์œ„ ๊ทธ๋ฆผ์€ 2x2 ํฌ๊ธฐ์˜ ์ด๋ฏธ์ง€๋ฅผ ์ด์šฉํ•ด 3x3, 4x4, 5x5 ํฌ๊ธฐ์˜ ์ด๋ฏธ์ง€๋กœ Super Resolution ํ•˜๋Š” ๊ณผ์ •์„ ๊ฐ„๋žตํ•˜๊ฒŒ ๋‚˜ํƒ€๋ƒˆ๋‹ค. ๋…น์ƒ‰์œผ๋กœ ๋‚˜ํƒ€๋‚œ 2x2 ์ด๋ฏธ์ง€ ํ”ฝ์…€์„ ์ž…๋ ฅ์œผ๋กœ 3x3 ํฌ๊ธฐ์˜ ์ด๋ฏธ์ง€ ๋งŒ๋“œ๋Š” ๊ฒฝ์šฐ ์ƒˆ๋กญ๊ฒŒ ์ƒ์„ฑํ•ด์•ผ ํ•˜๋Š” ์ •๋ณด๋Š” ์ตœ์†Œ 5๊ฐœ ํ”ฝ์…€(ํšŒ์ƒ‰)์ด๋ฉฐ, 4x4์˜ ๊ฒฝ์šฐ 12๊ฐœ, 5x5์˜ ๊ฒฝ์šฐ 21๊ฐœ์˜ ์ •๋ณด๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•œ๋‹ค. ์›๋ž˜ ๊ฐ€์ง„ ์ œํ•œ๋œ ์ •๋ณด(๋…น์ƒ‰ ํ”ฝ์…€)๋งŒ์„ ์ด์šฉํ•ด ๋งŽ์€ ์ •๋ณด(ํšŒ์ƒ‰ ํ”ฝ์…€)๋ฅผ ๋งŒ๋“ค์–ด๋‚ด๋Š” ๊ณผ์ •์€ ๋งค์šฐ ๋ณต์žกํ•˜๋ฉฐ ๊ทธ๋งŒํผ ์ž˜๋ชป๋œ ์ •๋ณด๋ฅผ ๋งŒ๋“ค์–ด ๋‚ผ ๊ฐ€๋Šฅ์„ฑ ๋˜ํ•œ ๋†’๋‹ค. ์ด ๋ฌธ์ œ๋Š” ์›๋ž˜ ๊ฐ€์ง„ ์ด๋ฏธ์ง€์˜ ํ•ด์ƒ๋„ ๋ณด๋‹ค ๋”์šฑ๋” ๋†’์€ ํ•ด์ƒ๋„๋กœ Super Resolution ํ• ์ˆ˜๋ก ์ ์  ์‹ฌํ•ด์ง„๋‹ค.

image07

์œ„ ์ด๋ฏธ์ง€์˜ ์ฒซ ๋ฒˆ์งธ ๋ฐ ๋„ค ๋ฒˆ์งธ ์ด๋ฏธ์ง€๋Š” ์ €ํ•ด์ƒ๋„ ๋ฐ ๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€๋ฅผ ๋‚˜ํƒ€๋‚ด๋ฉฐ, ๋‘ ๋ฒˆ์งธ ๋ฐ ์„ธ ๋ฒˆ์งธ ์ด๋ฏธ์ง€๋Š” ๊ฐ๊ฐ ๋‹ค๋ฅธ ๋”ฅ๋Ÿฌ๋‹ ๋ชจ๋ธ์„ ์ด์šฉํ•ด Super Resolution ํ•˜์—ฌ ์ƒ์„ฑํ•œ ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€๋‹ค. ๋”ฅ๋Ÿฌ๋‹ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•œ ๊ฒฐ๊ณผ(๋‘ ๋ฒˆ์งธ ๋ฐ ์„ธ ๋ฒˆ์งธ ์ด๋ฏธ์ง€)๋ฅผ ๋น„๊ตํ•œ๋‹ค๋ฉด, ์‹œ๊ฐ์ ์œผ๋กœ ์–ด๋–ค ์ด๋ฏธ์ง€๊ฐ€ ๋” ๊ณ ํ•ด์ƒ๋„์— ๊ฐ€๊นŒ์šด๊ฐ€? ๋Œ€๋ถ€๋ถ„ ๊ฒฐ๊ณผ 2 ์ด๋ฏธ์ง€๊ฐ€ ๋ถ„๋ช… ๋”์šฑ ์„ธ๋ฐ€ํ•œ ์ •๋ณด๋ฅผ ์ž˜ ํ‘œํ˜„ํ•˜์—ฌ ํ•ด์ƒ๋„๊ฐ€ ๋†’๋‹ค๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŽ์€ Super Resolution ์—ฐ๊ตฌ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๋‘ ๊ฐœ์˜ ์ •๋Ÿ‰์  ํ‰๊ฐ€ ๊ฒฐ๊ณผ๊ฐ€ ๋‘ ๋ฒˆ์งธ ๋ฐ ์„ธ ๋ฒˆ์งธ ์ด๋ฏธ์ง€ ์ œ๋ชฉ์— ๋‚˜ํƒ€๋‚˜ ์žˆ๋‹ค. ๊ฒฐ๊ณผ 2์˜ ์ด๋ฏธ์ง€์— ์„ธ๋ฐ€ํ•œ ์ •๋ณด๊ฐ€ ์ž˜ ํ‘œํ˜„๋˜์—ˆ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์ง€๋งŒ ์‹ค์ œ ํ‰๊ฐ€ ๊ฒฐ๊ณผ๋Š” ๊ฒฐ๊ณผ 1 ์ด๋ฏธ์ง€์— ์“ฐ์ธ ์ˆซ์ž๊ฐ€ ๋” ๋†’์€ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ํ‰๊ฐ€ ์ฒ™๋„๋Š” ๊ฐ๊ฐ ๋†’์„์ˆ˜๋ก ๋” ์›๋ณธ ์ด๋ฏธ์ง€์™€ ๋น„์Šทํ•จ์„ ๋งํ•˜๋ฉฐ, ์ •๋Ÿ‰์ ์œผ๋กœ ๊ฒฐ๊ณผ 1์ด ๋” ์ข‹์€ ๊ฒฐ๊ณผ๋ผ๋Š” ๋œป์ด๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ Super Resolution์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐ ์–ด๋ ค์šด ์ ์€ ์œ„ ๊ทธ๋ฆผ๊ณผ ๊ฐ™์ด ๊ฒฐ๊ณผ๋ฅผ ํ‰๊ฐ€ํ•˜๋Š” ๋ฐ ์žˆ์–ด ํ”ํžˆ ์‚ฌ์šฉ๋˜๋Š” ์ •๋Ÿ‰์  ํ‰๊ฐ€ ์ฒ™๋„์™€ ์‚ฌ๋žŒ์ด ์‹œ๊ฐ์ ์œผ๋กœ ๊ด€์ฐฐํ•˜์—ฌ ๋‚ด๋ฆฐ ํ‰๊ฐ€๊ฐ€ ์ž˜ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

๊ฐ€์žฅ ์‰ฌ์šด 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)

image08

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)

image09

Interpolation ๋ฐฉ๋ฒ•์„ ์ด์šฉํ•œ Super Resolution ๊ฒฐ๊ณผ๋Š” ์ด๋ฏธ์ง€๋งŒ ํฌ๊ฒŒ ๋งŒ๋“ค์–ด์ค„ ๋ฟ ์„ธ๋ฐ€ํ•œ ์ •๋ณด๋Š” ๊ฑฐ์˜ ์ฐพ์•„๋ณผ ์ˆ˜ ์—†๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

Deep Learning์„ ์ด์šฉํ•œ Super Resolution

(1) SRCNN


SRCNN์€ 2014๋…„ ๋ฐœํ‘œ๋œ "Image Super-Resolution Using Deep Convolutional Networks" ๋…ผ๋ฌธ์—์„œ ์‚ฌ์šฉ๋˜์—ˆ๋‹ค. Super Resolution Convolutional Neural Networks์˜ ์•ž๊ธ€์ž๋ฅผ ๋”ฐ์„œ SRCNN์ด๋ผ๊ณ  ๋ถˆ๋ฆฌ๋ฉฐ, ๋งค์šฐ ๊ฐ„๋‹จํ•œ ๋ชจ๋ธ ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ–ˆ์Œ์—๋„ ๊ธฐ์กด ๊ฒฐ๊ณผ์— ๋น„ํ•ด ํฐ ์„ฑ๋Šฅ ํ–ฅ์ƒ์„ ์ด๋ค„๋ƒˆ๋‹ค. ์ง€๊ธˆ ์ด ์—ฐ๊ตฌ๋ฅผ ๋ณด๋ฉด ๋„ˆ๋ฌด ๊ฐ„๋‹จํ•ด ๋ณด์ด์ง€๋งŒ, Super Resolution ๋ฌธ์ œ์— ๊ฐ€์žฅ ์ฒ˜์Œ ๋”ฅ๋Ÿฌ๋‹์„ ์ ์šฉํ•œ ์—ฐ๊ตฌ๋กœ์จ ์ดํ›„ ๋งŽ์€ ๋”ฅ๋Ÿฌ๋‹ ๊ธฐ๋ฐ˜์˜ Super Resolution ์—ฐ๊ตฌ์— ํฐ ์˜ํ–ฅ์„ ์ค€ ์ •๋ง ๋ฉ‹์ง„ ์ž‘ํ’ˆ์ด๋‹ค.

์•„๋ž˜ ๊ทธ๋ฆผ์ด SRCNN ๊ตฌ์กฐ์ด๋‹ค.

image10

๊ฐ€์žฅ ๋จผ์ € ์ €ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€(๊ทธ๋ฆผ์˜ 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๋กœ๋ถ€ํ„ฐ ๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

(2) SRCNN ์ดํ›„ ์ œ์•ˆ๋œ ๊ตฌ์กฐ๋“ค


VDSR(Very Deep Super Resolution)

image11

SRCNN๊ณผ ๋™์ผํ•˜๊ฒŒ interpolation์„ ํ†ตํ•ด ์ €ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€์˜ ํฌ๊ธฐ๋ฅผ ๋Š˜๋ ค ์ž…๋ ฅ์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค. ์ด์ „๋ณด๋‹ค ํ›จ์”ฌ ๋งŽ์€ 20๊ฐœ์˜ convolutional layer๋ฅผ ์‚ฌ์šฉํ–ˆ๊ณ , ์ตœ์ข… ๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€ ์ƒ์„ฑ ์ง์ „์— ์ฒ˜์Œ ์ž…๋ ฅ ์ด๋ฏธ์ง€๋ฅผ ๋”ํ•˜๋Š” residual learning์„ ์ด์šฉํ–ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊นŠ์€ ๊ตฌ์กฐ๋ฅผ ์ด์šฉํ•ด SRCNN์— ๋น„ํ•ด ํฐ ์„ฑ๋Šฅ ํ–ฅ์ƒ์„ ์ด๋Œ์–ด ๋ƒˆ๋‹ค.

RDN (Residual Dense Network)

image12

RDN์€ ์ €ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€๊ฐ€ ์ž…๋ ฅ๋˜๋ฉด, ์—ฌ๋Ÿฌ ๋‹จ๊ณ„์˜ convolutional layer๋ฅผ ๊ฑฐ์น˜๋Š”๋ฐ ๊ฐ layer์—์„œ ๋‚˜์˜ค๋Š” ์ถœ๋ ฅ์„ ์ตœ๋Œ€ํ•œ ํ™œ์šฉํ•˜๋„๋ก ํ•œ๋‹ค. ๊ทธ๋ฆผ๊ณผ ๊ฐ™์ด ๊ฐ๊ฐ์˜ convolution layer ์ถœ๋ ฅ ๊ฒฐ๊ณผ๋กœ ์ƒ์„ฑ๋œ ํŠน์ง•๋“ค์ด ํ™”์‚ดํ‘œ๋ฅผ ๋”ฐ๋ผ ์ดํ›„ ์—ฐ์‚ฐ์—์„œ ์—ฌ๋Ÿฌ ๋ฒˆ ์žฌํ™œ์šฉ ํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. (ํ•œ ๊ณณ์œผ๋กœ๋ถ€ํ„ฐ ๋‚˜์˜จ ํ™”์‚ดํ‘œ๊ฐ€ ์—ฌ๋Ÿฌ ๊ณณ์„ ํ–ฅํ•˜๊ณ  ์žˆ๋‹ค)

RCAN (Residual Channel Attention Networks)

image13

RCAN ๊ตฌ์กฐ ๋˜ํ•œ ๋งŽ์€ convolutional layer๋ฅผ ๊ฑฐ์น˜๋ฉฐ ํ•™์Šตํ•œ๋‹ค. ์œ„ ๊ตฌ์กฐ๋“ค๊ณผ ๋‹ค๋ฅธ ํŠน๋ณ„ํ•œ ์ ์€ convolutional layer์˜ ๊ฒฐ๊ณผ์ธ ๊ฐ๊ฐ์˜ ํŠน์ง• ๋งต์„ ๋Œ€์ƒ์œผ๋กœ ์ฑ„๋„ ๊ฐ„์˜ ๋ชจ๋“  ์ •๋ณด๊ฐ€ ๊ท ์ผํ•œ ์ค‘์š”๋„๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ผ๋ถ€ ์ค‘์š”ํ•œ ์ฑ„๋„์—๋งŒ ์„ ํƒ์ ์œผ๋กœ ์ง‘์ค‘ํ•˜๋„๋ก ์œ ๋„ํ–ˆ๋‹ค (๋งจ ์œ„์˜ Channel attention์ด๋ผ ์“ฐ์ธ ๋ถ€๋ถ„). CNN Attention ๋“ฑ์˜ ํ‚ค์›Œ๋“œ๋กœ ๊ฒ€์ƒ‰ํ•˜๋ฉด RCAN ๊ตฌ์กฐ์™€ ๋น„์Šทํ•œ ๋งŽ์€ attention ๊ธฐ์ˆ ์— ๋Œ€ํ•œ ์ •๋ณด๋“ค์„ ์ฐพ์•„๋ณผ ์ˆ˜ ์žˆ๋‹ค.

(3) SRGAN


์ด๋ฒˆ์—๋Š” 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 ๋ณด๋‹ค ์กฐ๊ธˆ ๋ณต์žกํ•œ ๊ตฌ์กฐ๋ฅผ ๊ฐ–๋Š”๋‹ค.

image14

๊ทธ๋ฆผ์˜ Generator Network์™€ Discriminator Network๋Š” ๊ฐ๊ฐ ์œ„์—์„œ ๋น„์œ ํ–ˆ๋˜ ์œ„์กฐ์ง€ํ๋ฒ”(์ƒ์„ฑ ๋ชจ๋ธ)๊ณผ ๊ฒฝ์ฐฐ(๋ถ„๋ฅ˜/ํŒ๋ณ„ ๋ชจ๋ธ)์ด๋‹ค. Generator๊ฐ€ ์ €ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€๋ฅผ ์ž…๋ ฅ ๋ฐ›์•„ (๊ฐ€์งœ)๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•ด ๋‚ด๋ฉด, Discriminator๋Š” ์ƒ์„ฑ๋œ (๊ฐ€์งœ)๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€์™€ ์‹ค์ œ(์ง„์งœ) ๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€ ์ค‘ ์ง„์งœ๋ฅผ ํŒ๋ณ„ํ•œ๋‹ค.

Generator๋Š” Discriminator๋ฅผ ์†์ด๋ คํ•˜๊ณ  Discriminator๋Š” ์ง„์งœ๋ฅผ ๊ฐ€๋ ค๋‚ด๋ ค๋Š” ํ•™์Šต์ด ์ง„ํ–‰๋  ์ˆ˜๋ก ์„œ๋กœ ๊ฒฝ์Ÿ์ž๊ฐ€ ๋˜์–ด ๋‘˜ ๋ชจ๋‘๊ฐ€ ์ ์  ๋ฐœ์ „ํ•œ๋‹ค. ํ•™์Šต์ด ๊ฑฐ์˜ ์™„๋ฃŒ ๋˜๋ฉด ์ตœ์ข…์ ์œผ๋กœ Generator๊ฐ€ ์ƒ์„ฑํ•ด๋‚ธ (๊ฐ€์งœ)๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€๋Š” Discriminator๊ฐ€ ์ง„์งœ์ธ์ง€ ๊ฐ€์งœ์ธ์ง€๋ฅผ ๊ตฌ๋ถ„ํ•˜๊ธฐ ํž˜๋“ค ์ •๋„๋กœ ๋งค์šฐ ์ข‹์€ ํ’ˆ์งˆ์„ ๊ฐ€์ง„ ๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€๊ฐ€ ๋œ๋‹ค.

SRGAN์—์„œ ์‚ฌ์šฉํ•˜๋Š” loss function์€ ์กฐ๊ธˆ ํŠน๋ณ„ํ•˜๋‹ค.

image15

์œ„ ์‹์„ ๋ณด๋ฉด ํฌ๊ฒŒ content loss์™€ adversarial loss๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๊ณ , ์ด ์ค‘ adversarial loss๋Š” ์šฐ๋ฆฌ๊ฐ€ ์ผ๋ฐ˜์ ์œผ๋กœ ์•Œ๊ณ  ์žˆ๋Š” GAN์˜ loss์ด๋ฉฐ, ์กฐ๊ธˆ ํŠน๋ณ„ํ•œ ๋ถ€๋ถ„์€ ์•„๋ž˜ ๊ทธ๋ฆผ์œผ๋กœ ๋‚˜ํƒ€๋‚ธ content loss ๋ถ€๋ถ„ ์ด๋‹ค.

image16

content loss๋Š” Generator๋ฅผ ์ด์šฉํ•ด ์–ป์–ด๋‚ธ (๊ฐ€์งœ) ๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€๋ฅผ ์‹ค์ œ (์ง„์งœ) ๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€์™€ ์ง์ ‘ ๋น„๊ตํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ๊ฐ ์ด๋ฏธ์ง€๋ฅผ ์ด๋ฏธ์ง€๋„ท์œผ๋กœ ์‚ฌ์ „ ํ•™์Šต๋œ(pre-trained) VGG ๋ชจ๋ธ์— ์ž…๋ ฅํ•˜์—ฌ ๋‚˜์˜ค๋Š” feature map์—์„œ์˜ ์ฐจ์ด๋ฅผ ๊ณ„์‚ฐํ•œ๋‹ค. ์ฆ‰, ์ด์ „์— ํ•™์Šตํ–ˆ๋˜ SRCNN์€ ์ƒ์„ฑํ•ด๋‚ธ ๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€๋ฅผ ์›๋ž˜ ๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€์™€ ์ง์ ‘ ๋น„๊ตํ•˜์—ฌ loss๋ฅผ ๊ณ„์‚ฐํ–ˆ์ง€๋งŒ, SRGAN์—์„œ๋Š” ์ƒ์„ฑ๋œ ๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€์™€ ์‹ค์ œ ๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€๋ฅผ VGG์— ์ž…๋ ฅํ•˜์—ฌ ๋ชจ๋ธ ์ค‘๊ฐ„์—์„œ ์ถ”์ถœํ•ด๋‚ธ ํŠน์ง•์„ ๋น„๊ตํ•ด์„œ loss๋ฅผ ๊ณ„์‚ฐํ•œ๋‹ค. SRGAN์€ VGG๋ฅผ ์ด์šฉํ•œ content loss ๋ฐ GAN์„ ์‚ฌ์šฉํ•จ์œผ๋กœ์จ ๋ฐœ์ƒํ•˜๋Š” adversarial loss๋ฅผ ํ•ฉํ•˜์—ฌ ์ตœ์ข…์ ์œผ๋กœ perceptual loss๋ผ๊ณ  ์ •์˜ํ•˜๋ฉฐ ์ด๋ฅผ ํ•™์Šต์— ์ด์šฉํ•œ๋‹ค.

SRCNN์„ ์ด์šฉํ•ด Super Resolution ๋„์ „ํ•˜๊ธฐ

tensorflow-datasets ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•ด ๋ณผ ๋ฐ์ดํ„ฐ์…‹์€ DIV2K ์ด๋‹ค. DIV2K ๋ฐ์ดํ„ฐ์…‹์€ ๋งŽ์€ Super Resolution ์—ฐ๊ตฌ์—์„œ ํ•™์Šต ๋ฐ ํ‰๊ฐ€์— ์‚ฌ์šฉ๋˜๋Š” ๋ฐ์ดํ„ฐ์…‹์ด๋ฉฐ 800๊ฐœ์˜ ํ•™์Šต์šฉ ๋ฐ์ดํ„ฐ์…‹ ๋ฐ 100๊ฐœ์˜ ๊ฒ€์ฆ์šฉ ๋ฐ์ดํ„ฐ์…‹์œผ๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋‹ค.

์•ž์„œ ๋‹ค์šด๋กœ๋“œ ํ•œ ๋ฐ์ดํ„ฐ์…‹์€ div2k/bicubic_x4 ์ด๋ฉฐ, ์ด๋Š” DIV2K ๋ฐ์ดํ„ฐ์…‹ ์ค‘์—์„œ ์‹ค์ œ ๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€๋ฅผ ๋Œ€์ƒ์œผ๋กœ bicubic interpolation์„ ์ด์šฉํ•ด ๊ฐ€๋กœ ๋ฐ ์„ธ๋กœ ํ”ฝ์…€ ์ˆ˜๋ฅผ 1/4๋ฐฐ๋กœ ์ค„์ธ ๋ฐ์ดํ„ฐ์…‹ ์ด๋‹ค. ์ด๋ ‡๊ฒŒ ๋งŒ๋“ค์–ด์ง„ ์ €ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€์™€ ์›๋ž˜ ๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€๊ฐ€ ์„œ๋กœ ํ•œ ์Œ์œผ๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋‹ค.

๋ฐ์ดํ„ฐ์…‹์— ๋Œ€ํ•œ ์ž์„ธํ•œ ์ •๋ณด๋Š” ์•„๋ž˜์—์„œ ํ™•์ธํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

(1) ๋ฐ์ดํ„ฐ ์ค€๋น„ํ•˜๊ธฐ


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)

image17

์ด๋ฏธ์ง€ ํฌ๊ธฐ๊ฐ€ ๊ฝค ํฌ๊ธฐ ๋•Œ๋ฌธ์— ์–ด๋ ดํ’‹์ด ๋ด์„œ๋Š” ์„ ๋ช…ํ•จ์˜ ์ฐจ์ด๊ฐ€ ํฌ์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™๋‹ค. ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ด์šฉํ•ด ๊ฐ ์ด๋ฏธ์ง€์˜ ํŠน์ • ๋ถ€๋ถ„์„ ํ™•๋Œ€ํ•ด๋ณด์ž.

# ์ด๋ฏธ์ง€์˜ ํŠน์ • ๋ถ€๋ถ„์„ ์ž˜๋ผ๋‚ด๋Š” ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
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)

image18

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)

(2) SRCNN ๊ตฌํ˜„ํ•˜๊ธฐ


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()

(3) SRCNN ํ•™์Šตํ•˜๊ธฐ


srcnn.compile(
    optimizer="adam", 
    loss="mse"
)

srcnn.fit(train, validation_data=valid, epochs=1)

(4) SRCNN ํ…Œ์ŠคํŠธํ•˜๊ธฐ


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)

image19

์‹œ๊ฐํ™” ๊ฒฐ๊ณผ bicubic interpolation ๊ฒฐ๊ณผ๋ณด๋‹ค ์กฐ๊ธˆ ๋” ์„ ๋ช…ํ•ด์กŒ์ง€๋งŒ ์›๋ž˜ ๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€์— ๋น„ํ•ด ๋งŒ์กฑํ•  ๋งŒํ•œ ์„ฑ๋Šฅ์€ ์•„๋‹Œ ๊ฒƒ ๊ฐ™๋‹ค. DIV2K ๋ฐ์ดํ„ฐ์…‹์ด ๋น„๊ต์  ์„ธ๋ฐ€ํ•œ ๊ตฌ์กฐ์˜ ์ด๋ฏธ์ง€๊ฐ€ ๋งŽ์•„ SRCNN๊ณผ ๊ฐ™์ด ๊ฐ„๋‹จํ•œ ๊ตฌ์กฐ๋กœ๋Š” ๋” ์ด์ƒ ํ•™์Šต๋˜์ง€ ์•Š๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ธ๋‹ค. ์‹ค์ œ๋กœ SRCNN ๋…ผ๋ฌธ์—์„œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๋น„๊ต์  ๊ฐ„๋‹จํ•œ ๊ตฌ์กฐ์˜ ์ด๋ฏธ์ง€์— ๋Œ€ํ•ด์„œ๋Š” ๊ฝค๋‚˜ ๋งŒ์กฑํ•  ๋งŒํ•œ ์„ฑ๋Šฅ์„ ๋ณด์—ฌ์ค€๋‹ค.

image20

SRGAN์„ ์ด์šฉํ•ด Super Resolution ๋„์ „ํ•˜๊ธฐ

SRCNN์— ์ด์–ด์„œ ๊ฐ„๋žตํ•˜๊ฒŒ ์•Œ์•„๋ณธ SRGAN์„ ๊ตฌํ˜„ํ•˜๊ณ  ์‹คํ—˜ํ•ด๋ณด์ž. ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ด์ „ SRCNN์— ์‚ฌ์šฉํ–ˆ๋˜ DIV2K ๋ฐ์ดํ„ฐ์…‹์„ ์‚ฌ์šฉํ•œ๋‹ค.

(1) ๋ฐ์ดํ„ฐ ์ค€๋น„ํ•˜๊ธฐ


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)

(2) SRGAN ๊ตฌํ˜„ํ•˜๊ธฐ


๋จผ์ €, ์ €ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€๋ฅผ ์ž…๋ ฅ๋ฐ›์•„ ๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•˜๋Š” Generator๋ฅผ ๊ตฌํ˜„ํ•ด๋ณด์ž. SRGAN์˜ Generator ๋ถ€๋ถ„์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

image21

๊ทธ๋ฆผ ๋‚ด์˜ 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๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

image22

# ๊ทธ๋ฆผ์˜ ํŒŒ๋ž€์ƒ‰ ๋ธ”๋ก์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
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)

(3) SRGAN ํ•™์Šตํ•˜๊ธฐ


์ด์ œ๋ถ€ํ„ฐ๋Š” ์•ž์—์„œ ์ •์˜ํ•œ ์‹ ๊ฒฝ๋ง๋“ค์„ ์ด์šฉํ•ด 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()

(4) SRGAN ํ…Œ์ŠคํŠธํ•˜๊ธฐ


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)

image23

์‹œ๊ฐํ™” ๊ฒฐ๊ณผ bicubic interpolation๋ณด๋‹ค ํ›จ์”ฌ ๋” ์›๋ž˜ ๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€์— ๊ฐ€๊นŒ์šด, ๊ฝค๋‚˜ ๋งŒ์กฑํ• ๋งŒํ•œ ๊ฒฐ๊ณผ๋ฅผ ์–ป์€ ๊ฒƒ ๊ฐ™๋‹ค. ์ด์ „์— ์‚ฌ์šฉํ–ˆ๋˜ SRCNN ๋ณด๋‹ค ๋” ๊นŠ์€ ์‹ ๊ฒฝ๋ง ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ–ˆ๊ณ , GAN ๋ฐ VGG ๊ตฌ์กฐ๋ฅผ ์ด์šฉํ•œ ์†์‹ค ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด ๋ณต์žกํ•˜๊ฒŒ ํ•™์Šต ๊ณผ์ •์„ ๊ตฌ์„ฑํ•œ ์˜๋ฏธ๊ฐ€ ์žˆ๋Š” ๊ฒƒ ๊ฐ™๋‹ค.

image24

์œ„ ๊ทธ๋ฆผ์€ SRGAN ๋…ผ๋ฌธ์—์„œ ์„ธ๋ถ€์ ์œผ๋กœ ์‹คํ—˜ํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค. ๊ฐ€์žฅ ์ฒซ ๋ฒˆ์งธ SRResNet์€ SRGAN์˜ Generator๋ฅผ ๋œปํ•˜๋ฉฐ, Generator ๊ตฌ์กฐ๋งŒ ์ด์šฉํ•ด SRCNN๊ณผ ๋น„์Šทํ•˜๊ฒŒ MSE ์†์‹คํ•จ์ˆ˜๋กœ ํ•™์Šตํ•œ ๊ฒฐ๊ณผ๋‹ค. ์˜ค๋ฅธ์ชฝ์œผ๋กœ ๊ฐˆ์ˆ˜๋ก GAN ๋ฐ VGG ๊ตฌ์กฐ๋ฅผ ์ด์šฉํ•˜์—ฌ ์ ์  ๋” ์ด๋ฏธ์ง€ ๋‚ด ์„ธ๋ถ€์ ์ธ ๊ตฌ์กฐ๊ฐ€ ์„ ๋ช…ํ•ด์ง์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. (VGG22๋Š” VGG54์— ๋น„ํ•ด ๋” low-level์˜ ํŠน์ง•์—์„œ ์†์‹ค์„ ๊ณ„์‚ฐํ–ˆ๋‹ค)

Super Resolution ๊ฒฐ๊ณผ ํ‰๊ฐ€ํ•˜๊ธฐ

Super Resolution ๊ฒฐ๊ณผ๊ฐ€ ์–ผ๋งˆ๋‚˜ ์ข‹์€์ง€ ๋งŽ์€ ์—ฐ๊ตฌ๋“ค์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์ •๋Ÿ‰์ ์ธ ํ‰๊ฐ€ ์ฒ™๋„๊ฐ€ ๋ช‡ ๊ฐ€์ง€ ์žˆ๋‹ค. ์ด๋ฒˆ์—๋Š” ์ด๋Ÿฌํ•œ ์ฒ™๋„์— ๋Œ€ํ•ด ๊ฐ„๋žตํ•˜๊ฒŒ ์•Œ์•„๋ณด๊ณ  ์ด๋ฅผ ํ™œ์šฉํ•ด ์•ž์„œ ์ง„ํ–‰ํ•œ SRCNN๊ณผ SRGAN ๋ชจ๋ธ ๊ฐ๊ฐ์ด ๋งŒ๋“ค์–ด๋‚ธ ๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€๋ฅผ ๋น„๊ตํ•ด ๋ณด์ž.

(1) PSNR๊ณผ SSIM


PSNR(Peak Signal-to-Noise Ratio)์€ ์˜์ƒ ๋‚ด ์‹ ํ˜ธ๊ฐ€ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋Š” ์ตœ๋Œ€ ์‹ ํ˜ธ์— ๋Œ€ํ•œ ์žก์Œ(noise)์˜ ๋น„์œจ์„ ๋‚˜ํƒ€๋‚ธ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์˜์ƒ์„ ์••์ถ•ํ–ˆ์„ ๋•Œ ํ™”์งˆ์ด ์–ผ๋งˆ๋‚˜ ์†์‹ค๋˜์—ˆ๋Š”์ง€ ํ‰๊ฐ€ํ•˜๋Š” ๋ชฉ์ ์œผ๋กœ ์‚ฌ์šฉ๋œ๋‹ค. ๋ฐ์‹œ๋ฒจ(db) ๋‹จ์œ„๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ, PSNR ์ˆ˜์น˜๊ฐ€ ๋†’์„์ˆ˜๋ก ์›๋ณธ ์˜์ƒ์— ๋น„ํ•ด ์†์‹ค์ด ์ ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค (๊ฐ’์ด ๋†’์„์ˆ˜๋ก ์ข‹๋‹ค).

SSIM(Structural Similarity Index Map)์€ ์˜์ƒ์˜ ๊ตฌ์กฐ ์ •๋ณด๋ฅผ ๊ณ ๋ คํ•˜์—ฌ ์–ผ๋งˆ๋‚˜ ๊ตฌ์กฐ ์ •๋ณด๋ฅผ ๋ณ€ํ™”์‹œํ‚ค์ง€ ์•Š์•˜๋Š”์ง€๋ฅผ ๊ณ„์‚ฐํ•œ๋‹ค. ํŠน์ • ์˜์ƒ์— ๋Œ€ํ•œ 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)

image25

๊ฐ ์ด๋ฏธ์ง€์˜ ์ œ๋ชฉ์— PSNR๊ณผ SSIM์ด ์ˆœ์„œ๋Œ€๋กœ ๋‚˜ํƒ€๋‚ฌ๋‹ค. ํ•ด์ƒ๋„๋ฅผ ์ค„์ผ์ˆ˜๋ก ๊ทธ ์ด๋ฏธ์ง€๋ฅผ ์›๋ž˜ ํฌ๊ธฐ๋กœ interploation ํ–ˆ์„ ๋•Œ, ๊ฐ๊ฐ์˜ ๊ณ„์‚ฐ ๊ฒฐ๊ณผ๊ฐ€ ๋ˆˆ์— ๋„๊ฒŒ ๊ฐ์†Œํ•˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

SRCNN ๋ฐ SRGAN ๊ฒฐ๊ณผ ๋น„๊ตํ•˜๊ธฐ


์ด๋ฒˆ์—๋Š” ์•ž์„œ ์‹คํ—˜ํ–ˆ๋˜ 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)

image26

์ž๋™์ฐจ์˜ ์•ž๋ถ€๋ถ„์„ ์ž˜๋ผ๋‚ด์–ด ํ™•๋Œ€ํ•œ ๊ฒฐ๊ณผ ๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€์™€ ๋น„๊ตํ•  ๋•Œ 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)

image27

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)

image28

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)

image29

# ์ง์ ‘ ํ•ด๋ณด๊ธฐ
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)

image30

์‹œ๊ฐ์ ์œผ๋กœ ๊ฐ€์žฅ ๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€์— ๊ฐ€๊นŒ์› ๋˜ 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)

image31

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)

ํ•™์Šต ๋‚ด์šฉ ์ •๋ฆฌ

(1) ๋‹ค๋ฅธ ์ด๋ฏธ์ง€๋ฅผ ์ฐธ๊ณ ํ•œ๋‹ค๋ฉด?


์ด์ „์— ํ•™์Šตํ–ˆ๋˜ 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 ๋ณด๋‹ค ํ›จ์”ฌ ๋” ์„ ๋ช…ํ•œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

image32

(2) ์ฐจ๋ณ„์„ ์žฌ์ƒ์„ฑํ•˜๋Š” ์ธ๊ณต์ง€๋Šฅ


์ธ๊ณต์ง€๋Šฅ์ด ๊ฐ€์ง„ ๋ฌธ์ œ๋“ค ์ค‘ ํ•˜๋‚˜๋Š” ์ฐจ๋ณ„์— ๊ด€ํ•œ ๊ฒƒ์ด๋‹ค. ์ธ๊ณต์ง€๋Šฅ ํ•™์Šต์— ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์˜ํ–ฅ์„ ์ฃผ๋Š” ๋ช‡ ๊ฐ€์ง€ ์š”์ธ๋“ค ์ค‘ ํ•˜๋‚˜๋Š” ํ•™์Šต์— ์‚ฌ์šฉํ•˜๋Š” ๋ฐ์ดํ„ฐ์ด๋ฉฐ, ์ด๋Ÿฌํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ํŽธํ–ฅ(bias)์„ ๋‹ด๊ณ  ์žˆ๋‹ค๋ฉด ๊ทธ๋กœ๋ถ€ํ„ฐ ํ•™์Šต๋œ ์ธ๊ณต์ง€๋Šฅ์€ ์•„๋ฌด๋ ‡์ง€๋„ ์•Š๊ฒŒ ์ฐจ๋ณ„์„ ํ•˜๊ฒŒ ๋œ๋‹ค.

์˜ˆ๋ฅผ ๋“ค๋ฉด ์•„๋งˆ์กด์ด ๊ฐœ๋ฐœํ•œ ์ธ๊ณต์ง€๋Šฅ ์ฑ„์šฉ/์ธ์‚ฌ ์‹œ์Šคํ…œ์ด ์—ฌ์„ฑ์— ๋Œ€ํ•ด ํŽธ๊ฒฌ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋Š” ์„ฑ์ฐจ๋ณ„์  ์‚ฌ๋ก€๊ฐ€ ์žˆ์—ˆ๊ณ , ๊ตฌ๊ธ€์˜ ์ด๋ฏธ์ง€ ์ธ์‹ ๋ชจ๋ธ์ด ์•„๋ž˜ ๊ทธ๋ฆผ๊ณผ ๊ฐ™์ด ์†์˜ ํ”ผ๋ถ€์ƒ‰์— ๋”ฐ๋ผ ์ฒด์˜จ๊ณ„๋ฅผ ์ด์œผ๋กœ ์ธ์‹ํ•˜๋Š” ์ธ์ข…์ฐจ๋ณ„์  ์‚ฌ๋ก€๊ฐ€ ์žˆ์—ˆ๋‹ค (๋ฐฑ์ธ๊ณผ ๋‹ฌ๋ฆฌ ํ‘์ธ์˜ ์†์—๋Š” ์ด์„ ๋“ค๊ณ  ์žˆ๋‹ค๊ณ  ์ธ์‹).

image33

์˜ค๋Š˜ ์šฐ๋ฆฌ๊ฐ€ ํ•™์Šตํ•œ Super Resolution ๋ฌธ์ œ์—์„œ๋„ ์ด๋Ÿฌํ•œ ์ฐจ๋ณ„ ์‚ฌ๋ก€๊ฐ€ ์กด์žฌํ•œ๋‹ค. ๋ฌธ์ œ๊ฐ€ ๋œ ๋ฐฉ๋ฒ•์€ 2020๋…„ ์ดˆ์— ๋ฐœํ‘œ๋œ PULSE ๋ผ๋Š” ๊ตฌ์กฐ์ด๋‹ค. ์ด ๋ฐฉ๋ฒ•์€ ์•„๋ž˜ ๊ทธ๋ฆผ๊ณผ ๊ฐ™์ด Super Resolution ๋ฌธ์ œ์—์„œ ๋งค์šฐ ์ข‹์€ ์„ฑ๋Šฅ์„ ๊ฐ–๋Š”๋‹ค. ์ €ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€ ๋‚ด์— ๊ฑฐ์˜ ์—†๋Š” ์ •๋ณด๋ฅผ ์™„์ „ํžˆ ์ƒˆ๋กญ๊ฒŒ ์ƒ์„ฑํ•˜๋Š” ์ˆ˜์ค€์ด๋‹ค.

image34

๋ฌธ์ œ๋Š” ์ €ํ•ด์ƒ๋„ ์–ผ๊ตด ์ด๋ฏธ์ง€๋ฅผ ์ž…๋ ฅํ–ˆ์„ ๋•Œ, ๋ชจ๋‘ ๋ฐฑ์ธ์œผ๋กœ ๋งŒ๋“ค์–ด ๋‚ธ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ์•„๋ž˜ ์ฒซ ๋ฒˆ์งธ ๊ทธ๋ฆผ์˜ ์ €ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€๋Š” ์˜ค๋ฐ”๋งˆ ์ „ ๋ฏธ๊ตญ ๋Œ€ํ†ต๋ น์œผ๋กœ ๋ณด์ด๋Š”๋ฐ, ์ด๋ฅผ ๊ณ ํ•ด์ƒ๋„๋กœ ์ƒ์„ฑํ–ˆ์„ ๋•Œ ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€๋กœ ๋ฐฑ์ธ์ด ๋“ฑ์žฅํ•œ๋‹ค. ์ €ํ•ด์ƒ๋„ ์ž…๋ ฅ ์ด๋ฏธ์ง€๋กœ ๋™์–‘์ธ์ด๋‚˜ ์บ๋ฆญํ„ฐ๋ฅผ ๋„ฃ์–ด๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ฐฑ์ธ์ด ์ƒ์„ฑ๋จ์„ ์•„๋ž˜ ๊ทธ๋ฆผ์œผ๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

image35

PULSE ์˜ ์—ฐ๊ตฌ์ž๋“ค์€ ์ด๋Ÿฌํ•œ ํ˜„์ƒ์ด ํ•™์Šตํ–ˆ๋˜ ๋ฐ์ดํ„ฐ์…‹์—์„œ ๊ธฐ์ธํ•œ ๊ฒƒ์ด๋ผ ์ด์•ผ๊ธฐํ–ˆ๋‹ค. ๋ฐฑ์ธ ์œ„์ฃผ๋กœ ๊ตฌ์„ฑ๋œ ํ•™์Šต๋œ ๋ฐ์ดํ„ฐ๋กœ ์ธํ•ด ์ €ํ•ด์ƒ๋„ ์–ผ๊ตด ์ด๋ฏธ์ง€์—์„œ ๋งŒ๋“ค์–ด์•ผ ํ•  ์ƒˆ๋กœ์šด ํ”ฝ์…€๋“ค์ด ๊ธฐ๋ณธ์ ์œผ๋กœ ํฐ์ƒ‰์— ๊ฐ€๊น๊ฒŒ ์„ค์ •๋˜๊ฑฐ๋‚˜, ๋ฐฑ์ธ๊ณผ ๋น„์Šทํ•œ ์ด๋ชฉ๊ตฌ๋น„๊ฐ€ ํ˜•์„ฑ๋˜๋Š” ๊ฒƒ์ด๋‹ค. ์–ด์ฉŒ๋ฉด ๋ฐฑ์ธ๋“ค์ด ์ „ ์„ธ๊ณ„ ์ธ๊ณต์ง€๋Šฅ ์—ฐ๊ตฌ์˜ ๊ฝค ๋งŽ์€ ๋ถ€๋ถ„์„ ์ฐจ์ง€ํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Ÿฌํ•œ ๊ฒฐ๊ณผ๊ฐ€ ์ž์—ฐ์Šค๋Ÿฌ์šด ๊ฒƒ ๊ฐ™๊ธฐ๋„ ํ•˜๋‹ค.

(3) ์ฐธ๊ณ ์ž๋ฃŒ


ํ”„๋กœ์ ํŠธ : SRGAN ํ™œ์šฉํ•˜๊ธฐ

ํšŒ๊ณ ๋ก

  • ๋…ธ๋“œ๋ฅผ ์ง„ํ–‰ํ•˜๊ธฐ ์ „์— ์ด๋ฏธ 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