由于获取的数据(比如图片分辨率),大多不一致,为了更好的训练模型,我们常常需要对数据进行简单的处理,本次人脸模型数据训练处理方式如下:
归一化
平时我们图片一般是RGB的,每个像素的取值范围为0-255,由于现在的模型深度比较深,所以在计算的时候,由于底层的一点点小的变化,都会导致高层的剧烈变化,甚至超出数据的最大范围。所以我们需要对数据处理一下。
我们处理数据主要的方式“数据归一化”,数据归一化方式很多,我们这里不再展开,直接将数据范围缩小到[0,1]之间
image = np.asarray(image, dtype='float64')/256
改变图片为统一大小
模型中,数据的输入在编译后,对输入的数据就必须大小统一,所以我们需要修改图片大小,缩小容易,但是放大却需要填充像素,常用的填充像素的方式有最近邻插值、双线性插值(默认)等
image = cv2.resize(image, input_shape)
变为灰色
灰度图像依然能够完好地展示图像中的各个部分的轮廓、纹理、形状等关键特征,同时灰度图片结构相对于彩色图片更为简单(3通道变为1通道)。所以我们经常将图片转换为灰度图像,这样可以极大的减少计算量。
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
处理标签(y_train,y_test)为One-hot形式
训练模型时,为方便计算,我们经常将标签的值修改One-hot形式,比如有3中不同的标签:
- 当标签为0时:我们修改为[0,0,1]
- 当标签为1时:我们修改为[0,1,0]
- 当标签为2时:我们修改为[1,0,0]
from keras.utils import to_categorical
y = to_categorical(y)
- 前面3种处理方式,我们统一在一个方法中
def preprocess_image(input_shape, image):
assert len(input_shape) == 3
if input_shape[-1] == 1:
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
input_shape = input_shape[:2]
image = cv2.resize(image, input_shape)
image = np.asarray(image, dtype='float64')/256
if len(image.shape) < 3:
image = np.expand_dims(image, -1)
return image
- 最后,我们其实希望在加载图片的时候,就将图片处理好,于是修改前面博客中的load_dataset方法,如下:
from keras.utils import to_categorical
def load_dataset(img_path):
input_shape = (224,224,1)
img_dirs = os.listdir(img_path)
X = []
y = []
for img_name in img_dirs:
img = cv2.imread(img_path + "/" + img_name)
img = preprocess_image(input_shape,img)
X.append(img)
row = int(img_name.split("_")[1]) #原图(olivettifaces)中第row行的
count = int(img_name.split("_")[2].split(".")[0]) #原图(olivettifaces)中第count列的
y.append(int(row * 2 + count / 10)) #每个数字,代表一个人脸,图中每行2个人
X = np.array(X)
y = np.array(to_categorical(y))
return X,y