目錄
1. 問題引出
最近在做一個圖像分類的項目,由於性能比較差,因此需要嘗試將彩色圖轉爲灰度圖進行訓練,從而屏蔽掉顏色對分類結果的影響而着重關注紋理、結構等信息。由於樣本數量較少,只有幾百張的樣子,如果自己搭網絡的話從頭訓練的話,勢必會因爲樣本數量的問題,無法達到一個滿意的效果,因此必須借鑑Imagenet的預訓練權重。但是在Imagenet上預訓練的模型(Xception, Resnet, VGG等)都是處理的彩色圖,如果要使用預訓練模型就必須要3通道的圖像。
搜索了一下,基本上目前的解決方法:
暴力的將單通道的圖複製爲3份,然後合成爲一張RGB圖。顯然,該圖3個通道的數值完全相等,這樣存在很多冗餘計算,我們稱之爲“僞RGB圖”。爲了方便起見,自己實現了兩種方法,完成如下轉換:
RGB圖 → 灰度圖 → 僞RGB圖
其中,轉換爲灰度圖時,均使用的是如下標準公式:
2. 解決方案
首先,導入必要的包:
from multiprocessing import Pool from PIL import Image import numpy as np import os
2.1. 直接使用convert將L轉爲RGB
def fakeRgb1(path, dst): ''' 方法1:直接使用convert將L轉爲RGB :param path:圖片輸出路徑 :param dst:圖片輸出路徑 :return:rgb3個通道值相等的rgb圖像 ''' b = Image.open(path) # L代表轉換爲灰度圖 if b.mode != 'L': L = b.convert('L') L = L.convert('RGB') # 將圖像轉爲數組 rgb_array = np.asarray(L) # 將數組轉換爲圖像 rgb_image = Image.fromarray(rgb_array) rgb_image.save(dst + '\\' + path.split('\\')[-1]) print(dst + '\\' + path.split('\\')[-1])
2.2. 數組拼接方法
def fakeRgb2(path, dst): ''' 方法二:最原始的拼接數組方法 :param path:圖片輸入路徑 :param dst:圖片輸出路徑 :return:rgb3個通道值相等的rgb圖像 ''' b = Image.open(path) # L代表轉換爲灰度圖 if b.mode != 'L': L = b.convert('L') # 將圖像轉爲數組 b_array = np.asarray(L) # 將3個二維數組重疊爲一個三維數組 rgb_array = np.zeros((b_array.shape[0], b_array.shape[1], 3), "uint8") rgb_array[:, :, 0], rgb_array[:, :, 1], rgb_array[:, :, 2] = b_array, b_array, b_array rgb_image = Image.fromarray(rgb_array) rgb_image.save(dst + '\\' + path.split('\\')[-1]) print(dst + '\\' + path.split('\\')[-1])
3. 多進程加速運行
由於是批量處理,因此可能會遇到同時轉換很多張圖片,那麼這個時候就必須使用多進程加速了,具體的加速方法看我的這篇博客:
本文的加速代碼如下:
def get_image_paths(folder): return [os.path.join(folder, f) for f in os.listdir(folder)] if __name__ == '__main__': # 多線程,多參數,starmap版本 images = get_image_paths(path) output = [src for i in images] zip_args = list(zip(images, output)) pool = Pool() pool.starmap(fakeRgb2, zip_args) pool.close() pool.join()
4.使用預訓練模型訓練
這部分就和訓練普通RGB圖像一樣即可,在這裏不贅述。