超分辨率重建技術(Super-Resolution)是指從觀測到的低分辨率圖像重建出相應的高分辨率圖像。
SR可分為兩類:
1. 從多張低分辨率圖像重建出高分辨率圖像
2. 從單張低分辨率圖像重建出高分辨率圖像。
基於深度學習的SR,主要是基於單張低分辨率的重建方法,即Single Image Super-Resolution (SISR)
一、基於深度學習的超分辨率重建方法整理
1、SRCNN
Super-Resolution Convolutional Neural Network(PAMI 2016, 代碼)
該方法對於一個低分辨率圖像,先使用雙三次(bicubic)插值將其放大到目標大小,再通過三層卷積網絡做非線性映射,得到的結果作為高分辨率圖像輸出。
2、DRCN
Deeply-Recursive Convolutional Network for Image Super-Resolution(CVPR 2016, 代碼)
使用更多的卷積層增加網絡感受野(41x41),同時為了避免過多網絡參數,該文章提出使用遞歸神經網絡(RNN)。
與SRCNN類似,該網絡分為三個模塊,第一個是Embedding network,相當於特征提取,第二個是Inference network, 相當於特征的非線性變換,第三個是Reconstruction network,即從特征圖像得到最后的重建結果。其中的Inference network是一個遞歸網絡,即數據循環地通過該層多次。將這個循環進行展開,就等效於使用同一組參數的多個串聯的卷積層,如下圖所示:
其中的H1到HD是D個共享參數的卷積層。DRCN將每一層的卷積結果都通過同一個Reconstruction Net得到一個重建結果,從而共得到D個重建結果,再把它們加權平均得到最終的輸出。另外,受到ResNet的啟發,DRCN通過skip connection將輸入圖像與Hd的輸出相加后再作為Reconstruction Net的輸入,相當於使Inference Net去學習高分辨率圖像與低分辨率圖像的差,即恢復圖像的高頻部分。
3、ESPCN
Real-Time Single Image and Video Super-Resolution Using an Efficient Sub-Pixel Convolutional Neural Network(CVPR 2016, 代碼)
ESPCN的核心概念是亞像素卷積層(sub-pixel convolutional layer)。如上圖所示,網絡的輸入是原始低分辨率圖像,通過兩個卷積層以后,得到的特征圖像大小與輸入圖像一樣,但是特征通道為r^2 (r是圖像的目標放大倍數)。將每個像素的r^2 個通道重新排列成一個r x r的區域,對應於高分辨率圖像中的一個r x r大小的子塊,從而大小為r^2 x H x W的特征圖像被重新排列成1 x rH x rW大小的高分辨率圖像。這個變換雖然被稱作sub-pixel convolution, 但實際上並沒有卷積操作。
4、VESPCN
Real-Time Video Super-Resolution with Spatio-Temporal Networks and Motion Compensation(arxiv 2016)
上述幾種方法都只在單幅圖像上進行處理,而VESPCN提出使用視頻中的時間序列圖像進行高分辨率重建,並且能達到實時處理的效率要求。
5、SRGAN
Photo-Realistic Single Image Super-Resolution Using a Generative Adversarial Network(arxiv, 21 Nov, 2016)
本文將生成式對抗網絡(GAN)用於SR問題。其出發點是傳統的方法一般處理的是較小的放大倍數,當圖像的放大倍數在4以上時,很容易使得到的結果顯得過於平滑,而缺少一些細節上的真實感。因此SRGAN使用GAN來生成圖像中的細節。
github(tensorflow): https://github.com/zsdonghao/SRGAN
github(tensorflow): https://github.com/buriburisuri/SRGAN
github(torch): https://github.com/junhocho/SRGAN
github(caffe): https://github.com/ShenghaiRong/caffe_srgan
github(tensorflow): https://github.com/brade31919/SRGAN-tensorflow
github(keras): https://github.com/titu1994/Super-Resolution-using-Generative-Adversarial-Networks
github(pytorch): ai-tor/PyTorch-SRGAN
6、EDSR
Enhanced Deep Residual Networks for Single Image Super-Resolution, CVPRW2017
EDSR是NTIRE2017超分辨率挑戰賽上獲得冠軍的方案。如論文中所說,EDSR最有意義的模型性能提升是去除掉了SRResNet多余的模塊,從而可以擴大模型的尺寸來提升結果質量。
github(torch): https://github.com/LimBee/NTIRE2017
github(tensorflow): https://github.com/jmiller656/EDSR-Tensorflow
github(pytorch): https://github.com/thstkdgus35/EDSR-PyTorch
EDSR的網絡結構如下:
標准化輸入head:卷積×1
body:resblock(卷積×2+relu)*16
tail:卷積×(n+1)
標准化輸出
其上采樣部分集成在tail的前n次卷積中,其中每次卷積將channels提升4倍,然后轉化為放大2倍的feats(即將4個channels合並為一個長寬加倍的channel),重復log(n,2)次。借用ESPCN(上文有講)的一張圖示意一下這種方法,順便一提,下面的WDSR上采樣層也是用的這個原理:
EDSR去掉了ResBlock中的bn層,僅在resblock輸出位置添加一個relu激活,源碼如下,
class ResBlock(nn.Module): def __init__( self, conv, n_feats, kernel_size, bias=True, bn=False, act=nn.ReLU(True), res_scale=1): super(ResBlock, self).__init__() m = [] for i in range(2): m.append(conv(n_feats, n_feats, kernel_size, bias=bias)) if bn: # EDSR 的觀點bn層對低抽象任務意義不大 m.append(nn.BatchNorm2d(n_feats)) if i == 0: m.append(act) # conv->conv->relu self.body = nn.Sequential(*m) self.res_scale = res_scale def forward(self, x): res = self.body(x).mul(self.res_scale) res += x return res
7、WDSR
Wide Activation for Efficient and Accurate Image Super-Resolution,CVPRW2018
建構於超分辨 EDSR 算法,亦即 NTIRE 2018 年的冠軍模型,最主要的改進是在殘差模塊中 ReLU 激活函數前增大特征圖。
github(pytorch):https://github.com/JiahuiYu/wdsr_ntire2018
一篇參考文章:https://blog.csdn.net/leviopku/article/details/85048846
WDSR_b網絡結構如下:
標准化輸入
head:卷積×1
body:block(卷積+relu+卷積×2)*16
tail:卷積×1
skip:卷積×1
標准化輸出
tail部分僅有一次卷積,實際放大思路同EDSR,不過是一次卷積得到足夠的channels(3*n^2),一步重建為3通道的圖像。
其結構中有幾個有意思的部分:
i. 其卷積層都外接了weight_norm層(w = g*v/||v||),據說可以一定程度緩解樣本不均衡問題,並有防止過擬合的功能(可以看作一種正則化)。
ii. skip 結構實際上是一個單層卷積(channels變化為:3->3*n^2),從輸入圖片位置直接映射到tail的輸出,其輸出和tail輸出尺寸完全一致,參照ResNet的方法合並,作為網絡的輸出
iii. 其Block對通常的ResBlock有修改,首先和EDSR的ResBlock結構就不一致(EDSR的ResBlock也和經典的有一定出入),其次其channels安排不是常規的沙漏結構(輸入和輸出channels一致且大於中間的channel,可能目的是假定中間層提取抽象特征),而是中間更大,為了獲取更多的基礎特征(作者認為對於超像素重建這種低抽象任務需要更多的底層信息來反映特征)。
class Block(nn.Module): def __init__( self, n_feats, kernel_size, wn, act=nn.ReLU(True), res_scale=1): super(Block, self).__init__() self.res_scale = res_scale body = [] expand = 6 linear = 0.8 body.append( wn(nn.Conv2d(n_feats, n_feats*expand, 1, padding=1//2))) # channels:64->64*6 body.append(act) body.append( # channels:64*6->64*0.8 wn(nn.Conv2d(n_feats*expand, int(n_feats*linear), 1, padding=1//2))) body.append( # channels:64*0.8->64 wn(nn.Conv2d(int(n_feats*linear), n_feats, kernel_size, padding=kernel_size//2))) self.body = nn.Sequential(*body) def forward(self, x): res = self.body(x) * self.res_scale res += x return res
8、DBPN
Deep Back-Projection Networks For Super-Resolution, CVPR2018
github(caffe): https://github.com/alterzero/DBPN-caffe
github(pytorch): https://github.com/alterzero/DBPN-Pytorch
二、Pytorch實現的EDSR/WDSR實驗
github:https://github.com/Hellcatzm/EDSR-PyTorch
其實就是網上開源的 EDSR 和 WDSR 兩個項目我合並了一下,有以下幾點注意:
本項目 fork 自網上開源項目,以 EDSR 算法為基准,在原工程基礎上添加了 WDSR 算法,並部分添加了注釋,訓練方法在 /src/demo.sh 下記錄,注意不要去執行這個文件,該文件里面記錄了工程的各種啟動方式,選擇想要執行的拷貝到命令行即可。
由於項目涉及大量的多進程操作,使得本工程在 windows 下不能正常執行,請在 Linux 下測試本工程。
如需使用 WDSR ,把命令行指令相應位置的 EDSR 改寫為 WDSR_a 或者 WDSR_b 即可(不區分大小寫)。
測試時我們首先在 EDSR 項目目錄下新建 test 文件夾,存入低分辨率圖片,然后在 src 目錄下運行如下命令:
python main.py
--model 模型名稱(不區分大小寫)
--pre_train 已保存模型路徑
--test_only
--save_results
--data_test Demo
生成的圖片將保存在 experiment/results-Demo 文件夾下。
由於兩個網絡我們上面已經介紹了,對源碼感興趣的可以再 src 的 model 下瀏覽各個模型的核心實現,其代碼由 model.__init__ 里的通用部分加 model.模型名稱 里的各個模型的分支實現組成,由於 Pytorch 語法足夠簡潔且超分辨率重建網絡並不復雜(最討厭看目標檢測的代碼了,哈哈),所以不再長篇講解源碼了,我的項目里適當的給出了注釋,這里貼個重建對比圖,超分辨率重建效果都是有一點糊,好像油畫一樣,且細節不足,這項技術遠遠沒有達到成熟。