2019年4月24日 星期三

[Python][Keras] 影像前資料前處理


影像前處理可以使用CV2套件, 
這裡也把keras做影像資料增強的說明也放進來

解壓縮
import zipfile
with zipfile.ZipFile(open('aia-cnn-classification.zip', 'rb')) as f: f.extractall(".")

讀取實體位置檔案
import os
import cv2
import numpy as np
import pandas as pd
from glob import glob

from sklearn.utils import shuffle
from sklearn.model_selection import train_test_split

import tensorflow as tf

from time import time

import warnings
warnings.filterwarnings('ignore')

"""
資料夾及檔案路徑變數
"""

"""放置全部資料集的資料夾"""
data_dir_path = '//data/aia-data/may_the_4_be_with_u/where_am_i'


target_label_file_name = 'mapping.txt'
target_label_file_path = '/'.join((data_dir_path, target_label_file_name))

train_dir = '/'.join((data_dir_path, 'train'))
testset_dir = '/'.join((data_dir_path, 'testset'))

num_classes = 15
epochs = 100
batch_size = 32

img_size = 224

def load_data(Gray2RGB=False, mean_proc=False, test_size=0.25, img_size=img_size):
    """ Load target labels """
    with open(target_label_file_path) as f:
        all_lines = [line.split(', ') for line in f.read().splitlines()]

    target_labels = dict()
    for line in all_lines:
        target_class, target_label = line
        target_labels[target_class] = target_label

    """ Create training data list """
    train_list = []
    img_paths = []
    img_labels = []
    for key in target_labels.keys():
        for img_path in glob('{}/{}/*.jpg'.format(train_dir, key)):
            train_list.append([img_path, target_labels[key]])
            img_paths.append(img_path)
            img_labels.append(target_labels[key])
               
    """ Split the list into training set and validation set """
    train_img_paths, valid_img_paths, y_train, y_valid = train_test_split(img_paths, img_labels, test_size=test_size)
    
    X_train = []
    for path in train_img_paths:
        img = cv2.imread(path, 0) # 0=灰階
        img = cv2.resize(img, (img_size, img_size)) #壓縮圖片
        
        if Gray2RGB == True:
            img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB) #imagenet是RGB要相同
        
        img = img.astype(np.float32)
            
        if mean_proc == 'VGG16_ImageNet':
            img = img - np.array([123.68, 116.779, 103.939])
            img = img[:,:,::-1]  # RGB to BGR
            img = (img - np.min(img)) / np.max(img)
        if mean_proc == 'DenseNet':
            img /= 255.
            mean = [0.485, 0.456, 0.406]
            std = [0.229, 0.224, 0.225]
            img = (img - mean) / std
        else:
            img /= 255.
            img -= 0.5
            img *= 2.
        X_train.append(img)
    X_train = np.array(X_train, dtype=np.float32)
    
    X_valid = []
    if float(test_size) != 0.:
        for path in valid_img_paths:
            img = cv2.imread(path, 0)
            img = cv2.resize(img, (img_size, img_size))

            if Gray2RGB == True:
                img = cv2.cvtColor(img,cv2.COLOR_GRAY2RGB)
            
            img = img.astype(np.float32)
            
            if mean_proc == 'VGG16_ImageNet':
                img = img - np.array([123.68, 116.779, 103.939])
                img = img[:,:,::-1]  # RGB to BGR
                img = (img - np.min(img)) / np.max(img)
            if mean_proc == 'DenseNet':
                img /= 255.
                mean = [0.485, 0.456, 0.406]
                std = [0.229, 0.224, 0.225]
                img = (img - mean) / std
            else:
                img /= 255.
                img -= 0.5
                img *= 2.
            X_valid.append(img)
    X_valid = np.array(X_valid, dtype=np.float32)

    if Gray2RGB == False:
        X_train = np.reshape(X_train, X_train.shape+(1,))
        X_valid = np.reshape(X_valid, X_valid.shape+(1,))
    
    y_train = tf.keras.utils.to_categorical(y_train, num_classes)
    y_valid = tf.keras.utils.to_categorical(y_valid, num_classes)
    
    return X_train, y_train, X_valid, y_valid


testset_list = []
test_id_list = []
for img_path in glob('{}/*.jpg'.format(testset_dir)):
    testset_list.append(img_path)
    id = img_path.split('/')[-1].split('.')[0]
    test_id_list.append(id)
testset_df = pd.DataFrame({'id': test_id_list, 'path': testset_list}).sort_values(by='id')


def load_test_data(Gray2RGB=False, mean_proc=False, img_size=img_size):
    img_path_list = []
    for img_path in glob('{}/*.jpg'.format(testset_dir)):
        img_path_list.append(img_path)
    X_test = []
    X_id = []
    for path in img_path_list:
        img = cv2.imread(path, 0)
        img = cv2.resize(img, (img_size, img_size))
        
        if Gray2RGB == True:
            img = cv2.cvtColor(img,cv2.COLOR_GRAY2RGB)
        img = img.astype(np.float32)

        if mean_proc == 'VGG16_ImageNet':
            img = img - np.array([123.68, 116.779, 103.939])
            img = img[:,:,::-1]  # RGB to BGR
            img = (img - np.min(img)) / np.max(img)
        if mean_proc == 'DenseNet':
            img /= 255.
            mean = [0.485, 0.456, 0.406]
            std = [0.229, 0.224, 0.225]
            img = (img - mean) / std
        else:
            img /= 255.
            img -= 0.5
            img *= 2.
            
        img_id = path.split('/')[-1].split('.')[0]
        X_test.append(img)
        X_id.append(img_id)
        
    X_test = np.array(X_test, dtype=np.float32)
    
    if Gray2RGB == False:
        X_test = np.reshape(X_test, X_test.shape+(1,))
    
    return X_test, X_id
將資料清單隨機打亂
rand_seed = int(time())
data_list = shuffle(data_list, random_state=rand_seed)
data_list.head(10)
one hot encoding
# np.eye(10) 生成10x10對角矩陣
y_train = np.eye(10)[y_train[:]]
y_test = np.eye(10)[y_test[:]]
ImageDataGenerator產生器從目錄中讀取影像 使用kersa資料增強
train_datagen = ImageDataGenerator(
    rescale=1./255,#像素(0~255)壓縮到[0,1]之間
    rotation_range=40,#隨機旋轉角度值
    width_shift_range=0.2,#水平平移(總寬度的百分比)
    height_shift_range=0.2,#垂直平移
    shear_range=0.2,#隨機傾斜(順時鐘傾斜角度)
    zoom_range=0.2,#隨機縮放(縮小放大比率)
    horizontal_flip=True,#隨機水平翻轉(非對稱才有效)
    fill_mode=nearest) #旋轉平移後出現空白填補像素的方法

test_datagen = ImageDataGenerator(rescale=1./255) # 請注意!驗證資料不應該擴充!!!

train_generator = train_datagen.flow_from_directory(
 train_dir,    # 目標目錄
 target_size=(150, 150), # 所有圖像大小調整成 150×150 
 batch_size=32,
 class_mode='binary') # 因為使用二元交叉熵 binary_crossentropy 作為損失,所以需要二元標籤


validation_generator = test_datagen.flow_from_directory(
 validation_dir,
 target_size=(150, 150),
 batch_size=32,
 class_mode='binary')

# 訓練
history = model.fit_generator(   
 train_generator,
 steps_per_epoch=100,
 epochs=100,
 validation_data=validation_generator,
 validation_steps=50)
顯示隨機擴充的訓練影像
from keras.preprocessing import image

fnames = [os.path.join(train_cats_dir, fname) for
    fname in os.listdir(train_cats_dir)]

img_path = fnames[3]

img = image.load_img(img_path, target_size=(150, 150))

x = image.img_to_array(img)

x = x.reshape((1, ) + x.shape)

i = 0
for batch in datagen.flow(x, batch_size=1):
    plt.figure(i)
    imgplot = plt.imshow(image.array_to_img(batch[0]))
    i += 1
    if i % 4 == 0:
        break

plt.show()


Ref: 

沒有留言:

張貼留言