Python cv2 實現圖像拼接——雙圖篡改任務數據準備(1)

    在之前的博客中我介紹了圖像篡改任務深度學習解決雙圖篡改問題的一般性思路,這篇博客講講對於雙圖篡改檢測任務如何做數據集。

1 概述

    深度學習是數據驅動的模型,數據集的製作有着舉足輕重的作用,在雙圖檢測篡改任務中,模型的輸入是 possible donor(潛在供體圖像)和 query (查詢)圖像、對應的 mask 以及判斷是否篡改的標籤 0 或者 1,如下圖所示的三種情況輸入[1],前面兩種是 postive, 第三種是 negative。

                                              

2 實現思路

    

    以第一種情況爲例,相同的篡改區域是前景部分,製作模型的輸入數據。原始數據爲 coco 數據,總體思路如下:

1. 一個文件夾放所有的 raw 圖片,一個文件夾放所有的 mask;

2. 對於 raw 圖片均分成3份,第一份爲 p, 第二份爲 q, 第三份爲 world;

3. 隨機選擇 mask 文件夾中的一個 mask ,crop mask 找到 mask 的 ROI, 將 ROI 做隨機定位,製作新的 mask,對於同一個 mask 做兩個 ROI 位置不一樣的新的 mask,這樣是爲了保證 p 和 q 的篡改區域不同;

4. 隨機選擇 world 文件夾中的一個 world 圖片, 兩個 mask 從world 中扣取相同的圖像,拼接到 p 和 q 上面。

3 代碼

"""
fig_path 爲原始圖片路徑
mask_paht 爲 mask 圖片路徑
把 fig_path 路徑文件夾下面的圖片等分3份,命名 p, q, world
隨機選取 mask 圖片一張和 world 的圖片一張,根據 mask 摳出 world 圖片上面的一個隨機區域,拼接到 p 和 q 中的每對圖片上面
此時篡改的區域是來自 world 的摳圖,相同的區域是前景
"""


import cv2
import numpy as np
import os


fig_path = "D:/AAAASXQ/SDL/raw_data/fig"
mask_path = "D:/AAAASXQ/SDL/raw_data/mask"
out_path = "D:/AAAASXQ/SDL/data_for_model_pos1"
try:
    os.makedirs(os.path.join(out_path, 'p')) 
    os.makedirs(os.path.join(out_path, 'p_maske')) 
    os.makedirs(os.path.join(out_path, 'q')) 
    os.makedirs(os.path.join(out_path, 'q_mask')) 
except:
    pass
out_p_path = os.path.join(out_path, 'p')
out_pmask_path = os.path.join(out_path, 'p_maske')
out_q_path = os.path.join(out_path, 'q')
out_qmask_path = os.path.join(out_path, 'q_mask')


p_list = os.listdir(fig_path)
mask_list = os.listdir(mask_path)
len_mask = len(mask_list)

l = len(pro_list)
l1 = int(l/3)

p = p_list[:l1]
q = p_list[l1: 2*l1]
world = p_list[2*l1:]

len_world = len(world)


def two(fig_path, mask_path, k):
    
    # 生成兩張原始 mask,後面增加隨機篡改區域
    mask1 = np.zeros((256, 256))
    mask2 = np.zeros((256, 256))
    
    # 獲取 mask 的 ROI
    n = np.random.randint(len_mask)
    mask = cv2.imread(os.path.join(mask_path, mask_list[n]),-1)
    mask = cv2.resize(mask, (256, 256), interpolation=cv2.INTER_NEAREST)
    y = mask.sum(axis=1)
    y_top = (y != 0).argmax(axis=0)
    y_btm = (y != 0).cumsum(axis=0).argmax(axis=0)
    x = mask.sum(axis=0)
    x_left = (x != 0).argmax(axis=0)
    x_right = (x != 0).cumsum(axis=0).argmax(axis=0)
    maskROI = mask[y_top:y_btm+1, x_left:x_right+1]
    
    # 讀取待篡改圖片兩張(按照順序),分別來自 p 和 q
    # 讀取摳圖對象圖片一張(隨機),來自 world
    fig1 = cv2.imread(os.path.join(fig_path, p[k]))
    fig1 = cv2.resize(fig1, (256, 256), interpolation=cv2.INTER_CUBIC)
    fig2 = cv2.imread(os.path.join(fig_path, q[k]))
    fig2 = cv2.resize(fig2, (256, 256), interpolation=cv2.INTER_CUBIC)
    w = cv2.imread(os.path.join(fig_path, world[np.random.randint(len_world)]))
    w = cv2.resize(w, (256, 256), interpolation=cv2.INTER_CUBIC)

    # 生成 p 的 mask
    try:    
        x1_begin = np.random.randint(256 - maskROI.shape[0] - 1)
        y1_begin = np.random.randint(256 - maskROI.shape[1] - 1)
    except:
        x1_begin = 1
        y1_begin = 1
        
    mask1[x1_begin:x1_begin + maskROI.shape[0], y1_begin:y1_begin + maskROI.shape[1]] = maskROI
    mask1 = mask1.astype(np.uint8)
    mask1_inv = cv2.bitwise_not(mask1)
    
    # 生成 q 的 mask
    try:
        x2_begin = np.random.randint(256 - maskROI.shape[0] - 1)
        y2_begin = np.random.randint(256 - maskROI.shape[1] - 1)
    except:
        x2_begin = 11
        y2_begin = 11

    mask2[x2_begin:x2_begin + maskROI.shape[0], y2_begin:y2_begin + maskROI.shape[1]] = maskROI
    mask2 = mask2.astype(np.uint8)
    mask2_inv = cv2.bitwise_not(mask2)
    
    # 生成篡改後的 p
    img1 = cv2.bitwise_and(w, w, mask=mask1) 
    img11 = cv2.bitwise_and(fig1, fig1, mask=mask1_inv) 
    pfig = cv2.add(img1, img11)

    # 生成篡改後的 q
    w[x2_begin:x2_begin + maskROI.shape[0], y2_begin:y2_begin + maskROI.shape[1], :] = w[x1_begin:x1_begin + maskROI.shape[0], y1_begin:y1_begin + maskROI.shape[1], :]
    img2 = cv2.bitwise_and(w, w, mask=mask2) 
    img22 = cv2.bitwise_and(fig2, fig2, mask=mask2_inv) 
    qfig = cv2.add(img2, img22)
    
    return pfig, mask1, qfig, mask2


fig_path = fig_path
mask_path = mask_path

for i in range(100): # 循環制作100次
    print(i)
    for j in range(l1): # 遍歷每個 p 圖片
        k = j
        try:
            p, mask1, q, mask2 = two(fig_path, mask_path, k)
            cv2.imwrite(out_p_path + '/' + str(i) + '_' + str(j) + '_' + 'p.jpg', p)
            cv2.imwrite(out_pmask_path + '/' + str(i) + '_' + str(j) + '_' + 'p_mask.png', mask1)
            cv2.imwrite(out_q_path + '/' + str(i) + '_' + str(j) + '_' + 'q.jpg', q)
            cv2.imwrite(out_qmask_path + '/' + str(i) + '_' + str(j) + '_' + 'q_mask.png', mask2)
        except:
            print('error',' ',i, j)
            pass

4 結果展示

    篡改後的 probe 和 query:

 

                                       

    對應的 mask:

                                       

5 缺點

    最重要的缺點在於拼接的圖像沒有邏輯......明眼人一看就知道圖像是篡改過的,哪還需要算法做判斷。。。後續訓練的模型對於真實場景的判斷效果可能有限。然而如果是手工製作逼真的篡改圖像,想必成本是非常高的。

6 改進

    採用分割數據集做訓練數據,這樣至少保證 P 中的圖像是真實的。數據集做縮放、旋轉等數據增廣操作。

 

 

參考資料:

[1] Y. Wu, W. Abd-Almageed, and P. Natarajan, “Deep matching and validation network: An end-to-end solution to constrained image splicing localization and detection,” in Proc. 25th ACM Int. Conf. Multimedia, Oct. 2017, pp. 1480–1502.
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章