1 前言
Hi,大家好,這里是丹成學長,今天向大家介紹
基于深度學的影像修復 影像補全
大家可用于 畢業設計
2 什么是影像內容填充修復
內容識別填充(譯注: Content-aware fill ,是 photoshop 的一個功能)是一個強大的工具,設計師和攝影師可以用它來填充圖片中不想要的部分或者缺失的部分,在填充圖片的缺失或損壞的部分時,影像補全和修復是兩種密切相關的技術,有很多方法可以實作內容識別填充,影像補全和修復,
- 首先我們將影像理解為一個概率分布的樣本,
- 基于這種理解,學*如何生成偽圖片,
- 然后我們找到最適合填充回去的偽圖片,

自動洗掉不需要的部分(海灘上的人)

最經典的人臉補充
補充前:

補充后:

3 原理分析
3.1 第一步:將影像理解為一個概率分布的樣本
你是怎樣補全缺失資訊的呢?
在上面的例子中,想象你正在構造一個可以填充缺失部分的系統,你會怎么做呢?你覺得人類大腦是怎么做的呢?你使用了什么樣的資訊呢?
在博文中,我們會關注兩種資訊:
語境資訊:你可以通過周圍的像素來推測缺失像素的資訊,
感知資訊:你會用“正常”的部分來填充,比如你在現實生活中或其它圖片上看到的樣子,
兩者都很重要,沒有語境資訊,你怎么知道填充哪一個進去?沒有感知資訊,通過同樣的背景關系可以生成無數種可能,有些機器學*系統看起來“正常”的圖片,人類看起來可能不太正常,
如果有一種確切的、直觀的演算法,可以捕獲前文影像補全步驟介紹中提到的兩種屬性,那就再好不過了,對于特定的情況,構造這樣的演算法是可行的,但是沒有一般的方法,目前最好的解決方案是通過統計和機器學習來得到一個類似的技術,

從這個分布中采樣,就可以得到一些資料,需要搞清楚的是PDF和樣本之間的聯系,

從正態分布中的采樣

2維影像的PDF和采樣, PDF 用等高線圖表示,樣本點畫在上面,
3.2 補全影像
首先考慮多變數正態分布, 以求得到一些啟發,給定 x=1 , 那么 y 最可能的值是什么?我們可以固定x的值,然后找到使PDF最大的 y,

在多維正態分布中,給定x,得到最大可能的y
這個概念可以很自然地推廣到影像概率分布,我們已知一些值,希望補全缺失值,這可以簡單理解成一個最大化問題,我們搜索所有可能的缺失值,用于補全的影像就是可能性最大的值,
從正態分布的樣本來看,只通過樣本,我們就可以得出PDF,只需挑選你喜歡的 統計模型, 然后擬合資料即可,
然而,我們實際上并沒有使用這種方法,對于簡單分布來說,PDF很容易得出來,但是對于更復雜的影像分布來說,就十分困難,難以處理,之所以復雜,一部分原因是復雜的條件依賴:一個像素的值依賴于影像中其它像素的值,另外,最大化一個一般的PDF是一個非常困難和棘手的非凸優化問題,
3.3 快速生成假影像
在未知概率分布情況下,學習生成新樣本
除了學如何計算PDF之外,統計學中另一個成熟的想法是學怎樣用 生成模型 生成新的(隨機)樣本,生成模型一般很難訓練和處理,但是后來深度學*社區在這個領域有了一個驚人的突破,Yann LeCun 在這篇 Quora 回答中對如何進行生成模型的訓練進行了一番精彩的論述,并將它稱為機器學習領域10年來最有意思的想法,
3.4 生成對抗網路(Generative Adversarial Net, GAN) 的架構
使用微步長卷積,對影像進行上采樣

現在我們有了微步長卷積結構,可以得到G(z)的表達,以一個向量z~pz 作為輸入,輸出一張 64x64x3 的RGB影像,

3.5 使用G(z)生成偽影像
基于DCGAN的人臉代數運算 DCGAN論文 ,

4 在Tensorflow上構建DCGANs
部分代碼:
def generator(self, z):
self.z_, self.h0_w, self.h0_b = linear(z, self.gf_dim*8*4*4, 'g_h0_lin', with_w=True)
self.h0 = tf.reshape(self.z_, [-1, 4, 4, self.gf_dim * 8])
h0 = tf.nn.relu(self.g_bn0(self.h0))
self.h1, self.h1_w, self.h1_b = conv2d_transpose(h0,
[self.batch_size, 8, 8, self.gf_dim*4], name='g_h1', with_w=True)
h1 = tf.nn.relu(self.g_bn1(self.h1))
h2, self.h2_w, self.h2_b = conv2d_transpose(h1,
[self.batch_size, 16, 16, self.gf_dim*2], name='g_h2', with_w=True)
h2 = tf.nn.relu(self.g_bn2(h2))
h3, self.h3_w, self.h3_b = conv2d_transpose(h2,
[self.batch_size, 32, 32, self.gf_dim*1], name='g_h3', with_w=True)
h3 = tf.nn.relu(self.g_bn3(h3))
h4, self.h4_w, self.h4_b = conv2d_transpose(h3,
[self.batch_size, 64, 64, 3], name='g_h4', with_w=True)
return tf.nn.tanh(h4)
def discriminator(self, image, reuse=False):
if reuse:
tf.get_variable_scope().reuse_variables()
h0 = lrelu(conv2d(image, self.df_dim, name='d_h0_conv'))
h1 = lrelu(self.d_bn1(conv2d(h0, self.df_dim*2, name='d_h1_conv')))
h2 = lrelu(self.d_bn2(conv2d(h1, self.df_dim*4, name='d_h2_conv')))
h3 = lrelu(self.d_bn3(conv2d(h2, self.df_dim*8, name='d_h3_conv')))
h4 = linear(tf.reshape(h3, [-1, 8192]), 1, 'd_h3_lin')
return tf.nn.sigmoid(h4), h4
當我們初始化這個類的時候,將要用到這兩個函式來構建模型,我們需要兩個判別器,它們共享(復用)引數,一個用于來自資料分布的小批影像,另一個用于生成器生成的小批影像,
self.G = self.generator(self.z)
self.D, self.D_logits = self.discriminator(self.images)
self.D_, self.D_logits_ = self.discriminator(self.G, reuse=True)
接下來,我們定義損失函式,這里我們不用求和,而是用D的預測值和真實值之間的交叉熵(cross entropy),因為它更好用,判別器希望對所有“真”資料的預測都是1,對所有生成器生成的“偽”資料的預測都是0,生成器希望判別器對兩者的預測都是1 ,
self.d_loss_real = tf.reduce_mean(
tf.nn.sigmoid_cross_entropy_with_logits(self.D_logits,
tf.ones_like(self.D)))
self.d_loss_fake = tf.reduce_mean(
tf.nn.sigmoid_cross_entropy_with_logits(self.D_logits_,
tf.zeros_like(self.D_)))
self.g_loss = tf.reduce_mean(
tf.nn.sigmoid_cross_entropy_with_logits(self.D_logits_,
tf.ones_like(self.D_)))
self.d_loss = self.d_loss_real + self.d_loss_fake
下面我們遍歷資料,每一次迭代,我們采樣一個小批資料,然后使用優化器來更新網路,有趣的是,如果G只更新一次,鑒別器的損失不會變成0,另外,我認為最后呼叫 d_loss_fake 和 d_loss_real 進行了一些不必要的計算, 因為這些值在 d_optim 和 g_optim 中已經計算過了, 作為Tensorflow 的一個聯系,你可以試著優化這一部分,并發送PR到原始的repo,
for epoch in xrange(config.epoch):
...
for idx in xrange(0, batch_idxs):
batch_images = ...
batch_z = np.random.uniform(-1, 1, [config.batch_size, self.z_dim]) \
.astype(np.float32)
# Update D network
_, summary_str = self.sess.run([d_optim, self.d_sum],
feed_dict={ self.images: batch_images, self.z: batch_z })
# Update G network
_, summary_str = self.sess.run([g_optim, self.g_sum],
feed_dict={ self.z: batch_z })
# Run g_optim twice to make sure that d_loss does not go to zero (different from paper)
_, summary_str = self.sess.run([g_optim, self.g_sum],
feed_dict={ self.z: batch_z })
errD_fake = self.d_loss_fake.eval({self.z: batch_z})
errD_real = self.d_loss_real.eval({self.images: batch_images})
errG = self.g_loss.eval({self.z: batch_z})
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/302714.html
標籤:AI
