BusterNet影像篡改檢測介紹
- 文章說明
- 雙分支結構
- Mani-Det branch:
- 大致流程
- mask decoder模塊
- BN-Incep層
- 到這里,該分支的框架就介紹完畢了,基于tf2的代碼實作如下:
- Simi-Det branch
- Fusion Modle
- 總結與后續說明:
文章說明
BusterNet是2018年,由 Wael Abd-Almageed等人提出的,針對CMFD問題的端到端的深度神經網路解決方案,本文對其結構和其python模型代碼(基于TensorFlow2框架)進行說明和簡單講解,對其思路進行總結和簡單擴展,對相關概念進行介紹,用于交流學習,給初學者入門提供借鑒,
- 原文《BusterNet: Detecting Copy-Move Image Forgery with Source/Target Localization》可知知網查到,作者也在github中提供了模型的原碼,
下面直接進入正題:
雙分支結構
busternet的一大特點即是雙分支結構,分為操作檢測分支(Mani-Det branch)和相似性檢測分支( Simi-Det branch),如下圖所示(摘自busternet原論文,看不懂不要緊,下面我慢慢介紹):

中文版大致為(摘自學長畢設,在此再次對資源提供者表示感謝,我們總是站在巨人的肩膀上哈哈):

中文版的圖示僅幫助簡易理解,講解介紹以原作者英文圖示為主!!
Mani-Det branch:
大致流程
** 輸入影像(256,256,3)**到CNN feature extractor,這里的特征提取器使用的是VGG16神經網路的前4塊結構,輸出(16,16,512)的特征資訊,為了提高輸出結果的解析度采用mask decoder模塊(該模塊將在下面介紹),得到(256,256,6)的輸出,最后通過Binary Classifier(一個3*3的2D卷積層,+sigmoid激活函式)得到(256,256,1)的輸出結果,即為aux1;
mask decoder模塊
該模塊是由BN-Inception與BilinerUpPool2D交替組成,如圖:

BN-Incep層進行BN標準化操作,BilinerUpPool2D(2*2的核)作擴展操作,每次對寬和高的解析度提高一倍,4個則提高16倍,即16 *16=256輸出;
BN-Incep層
如下所示:可見是先BN操作,在并行經過3個卷積層后進行con-cat連接操作,(圖中n=8、6、4、2、2,可見特征維度也不斷下降,s1和s2和s3先為(1,3,5)最后一次為5,7,11,具體為什么這樣設定作者也沒說清楚,經驗吧,有懂得大佬可以評論或者發私信給我哦)

python代碼實作如下:
def BnInception(x, nb_inc=16, inc_filt_list=[(1,1), (3,3), (5,5)], name='uinc') :
'''Basic Google inception module with batch normalization
Input:
x = tensor4d, (n_samples, n_rows, n_cols, n_feats)
nb_inc = int, number of filters in individual Conv2D
inc_filt_list = list of kernel sizes, individual Conv2D kernel size
name = str, name of module
Output:
xn = tensor4d, (n_samples, n_rows, n_cols, n_new_feats)
'''
uc_list = []
for idx, ftuple in enumerate( inc_filt_list ) :
uc = Conv2D( nb_inc, ftuple, activation='linear', padding='same', name=name+'_c%d' % idx)(x)
uc_list.append(uc)
if ( len( uc_list ) > 1 ) :
uc_merge = Concatenate( axis=-1, name=name+'_merge')(uc_list)
else :
uc_merge = uc_list[0]
uc_norm = BatchNormalization(name=name+'_bn')(uc_merge)
xn = Activation('relu', name=name+'_re')(uc_norm)
return xn
到這里,該分支的框架就介紹完畢了,基于tf2的代碼實作如下:
def create_cmfd_manipulation_branch( img_shape=(256,256,3),
name='maniDet' ) :
'''Create the manipulation branch for copy-move forgery detection
'''
#---------------------------------------------------------
# Input
#---------------------------------------------------------
img_input = Input( shape = img_shape, name = name+'_in' )
#---------------------------------------------------------
# VGG16 Conv Featex
#---------------------------------------------------------
bname = name + '_cnn'
# Block 1
x1 = Conv2D(64, (3, 3), activation='relu', padding='same', name=bname+'_b1c1')(img_input)
x1 = Conv2D(64, (3, 3), activation='relu', padding='same', name=bname+'_b1c2')(x1)
x1 = MaxPooling2D((2, 2), strides=(2, 2), name=bname+'_b1p')(x1)
# Block 2
x2 = Conv2D(128, (3, 3), activation='relu', padding='same', name=bname+'_b2c1')(x1)
x2 = Conv2D(128, (3, 3), activation='relu', padding='same', name=bname+'_b2c2')(x2)
x2 = MaxPooling2D((2, 2), strides=(2, 2), name=bname+'_b2p')(x2)
# Block 3
x3 = Conv2D(256, (3, 3), activation='relu', padding='same', name=bname+'_b3c1')(x2)
x3 = Conv2D(256, (3, 3), activation='relu', padding='same', name=bname+'_b3c2')(x3)
x3 = Conv2D(256, (3, 3), activation='relu', padding='same', name=bname+'_b3c3')(x3)
x3 = MaxPooling2D((2, 2), strides=(2, 2), name=bname+'_b3p')(x3)
# Block 4
x4 = Conv2D(512, (3, 3), activation='relu', padding='same', name=bname+'_b4c1')(x3)
x4 = Conv2D(512, (3, 3), activation='relu', padding='same', name=bname+'_b4c2')(x4)
x4 = Conv2D(512, (3, 3), activation='relu', padding='same', name=bname+'_b4c3')(x4)
x4 = MaxPooling2D((2, 2), strides=(2, 2), name=bname+'_b4p')(x4)
#---------------------------------------------------------
# Deconvolution Network
#---------------------------------------------------------
patch_list = [(1,1),(3,3),(5,5)]
bname = name + '_dconv'
# MultiPatch Featex
f16 = BnInception( x4, 8, patch_list, name =bname+'_mpf')
# Deconv x2
f32 = BilinearUpSampling2D(name=bname+'_bx2')( f16 )
dx32 = BnInception( f32, 6, patch_list, name=bname+'_dx2')
# Deconv x4
f64 = BilinearUpSampling2D(name=bname+'_bx4')( dx32 )
dx64 = BnInception( f64, 4, patch_list, name=bname+'_dx4')
# Deconv x8
f128 = BilinearUpSampling2D(name=bname+'_bx8')( dx64 )
dx128 = BnInception( f128, 2, patch_list, name=bname+'_dx8')
# Deconv x16
f256 = BilinearUpSampling2D(name=bname+'_bx16')( dx128 )
dx256 = BnInception( f256, 2, [(5,5),(7,7),(11,11)], name=bname+'_dx16')
#---------------------------------------------------------
# Output for Auxiliary Task
#---------------------------------------------------------
pred_mask = Conv2D(1, (3,3), activation='sigmoid', name=bname+'_pred_mask', padding='same')(dx256)
#---------------------------------------------------------
# End to End
#---------------------------------------------------------
model = Model(inputs=img_input, outputs=pred_mask, name = bname)
return model
Simi-Det branch
- **input(256,256,3)**進行CNN特征提取(也是VGG16的前四塊)輸出特征資訊(16,16,512),
- 在進行自相關操作(皮爾遜相關性)得到(16,16,256)的自相關資訊【這里16*16代表每個特征點,每個特征點有256個相關資訊(即每一個點與其它點的相關性,16 * 16=256)】;
- ☆☆再經過Percentile Pool進行統計資訊提取,該層對自相關資訊進行了固定長度的有序化處理,作者說是便于后續DNN,既克服了圖片解析度不同而導致的維度變化的不確定性,也起到了對輸出固定維度的作用,得到(16,16,100)的輸出,其中100可理解為你想固定的排序長度,這里其實對之前的256維資訊進行了壓縮,因為我們其實只需要讓網路找到突變點即可,舉個例子:
一個特征數列為【1,1,1,2,3,4,4,5,5,9,9,10,10,11】,我們對其排序資訊進行壓縮為【1,2,3,4,5,9,10,11】可以更快的找到突變資訊,即這里的5到9的突變位置,這是我們所關心的, - 然后就是MaskDecoder操作和BinaryClassifier操作,和上一分支類似,
Fusion Modle
融合模塊綜合考慮兩個分支的輸出的特征,輸出最終能夠區分目標區域和源區域的掩碼,-需要說明的是,兩個分支輸入到融合模塊的特征并不是它們各自二進制分類器輸出的二進制掩碼,而是前一個的掩碼解碼器輸出的特征,-兩個分支的二進制分類器只在分支訓練時激活,不參與融合模塊的最終輸出,融合模塊的具體作業是,將兩個分支的輸出特征疊接,再用 BN-Inception 模型融合,最后通過一個三層的 3 *3 的卷積濾波器輸出最終的彩色掩碼(256,256,3),
總結與后續說明:
下一步會介紹對原論文模型的experiments驗證,因為原論文沒有給相關代碼,所以還是很值得分享的,在下一篇也會介紹機器學習相關的幾個性能指標及計算方法及編程實作,我們下一篇見哦!!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/259851.html
標籤:AI
上一篇:前端面試的資料結構與演算法
下一篇:智能車AI電磁部署學習 (一)
