【时间】2018.10.26
【题目】keras中实现3D卷积(Con3D)以及如何将输入数据转化为3D卷积的输入(附实现代码)
概述
keras中实现3D卷积使用的是keras.layers.convolutional.Conv3D 函数。而在‘channels_last’模式下,3D卷积输入应为形如(samples,input_dim1,input_dim2, input_dim3,channels)的5D张量。本文讲述了Con3D的使用方法,但更主要的是讲述如何将输入数据转化为符合3D卷积的输入的形式。
一、Keras中的Con3D层
(注:此部分的内容来自《Keras中文文档》
链接为:https://keras-cn.readthedocs.io/en/latest/layers/convolutional_layer/)
keras.layers.convolutional.Conv3D(filters, kernel_size, strides=(1, 1, 1), padding='valid', data_format=None, dilation_rate=(1, 1, 1), activation=None, use_bias=True, kernel_initializer='glorot_uniform', bias_initializer='zeros', kernel_regularizer=None, bias_regularizer=None, activity_regularizer=None, kernel_constraint=None, bias_constraint=None)
三维卷积对三维的输入进行滑动窗卷积,当使用该层作为第一层时,应提供input_shape参数。例如input_shape = (3,10,128,128)代表对10帧128*128的彩色RGB图像进行卷积。数据的通道位置仍然有data_format参数指定。
参数
-
filters:卷积核的数目(即输出的维度)
-
kernel_size:单个整数或由3个整数构成的list/tuple,卷积核的宽度和长度。如为单个整数,则表示在各个空间维度的相同长度。
-
strides:单个整数或由3个整数构成的list/tuple,为卷积的步长。如为单个整数,则表示在各个空间维度的相同步长。任何不为1的strides均与任何不为1的dilation_rate均不兼容
-
padding:补0策略,为“valid”, “same” 。“valid”代表只进行有效的卷积,即对边界数据不处理。“same”代表保留边界处的卷积结果,通常会导致输出shape与输入shape相同。
-
activation:激活函数,为预定义的激活函数名(参考激活函数),或逐元素(element-wise)的Theano函数。如果不指定该参数,将不会使用任何激活函数(即使用线性激活函数:a(x)=x)
-
dilation_rate:单个整数或由3个整数构成的list/tuple,指定dilated convolution中的膨胀比例。任何不为1的dilation_rate均与任何不为1的strides不兼容。
-
data_format:字符串,“channels_first”或“channels_last”之一,代表数据的通道维的位置。该参数是Keras 1.x中的image_dim_ordering,“channels_last”对应原本的“tf”,“channels_first”对应原本的“th”。以128x128x128的数据为例,“channels_first”应将数据组织为(3,128,128,128),而“channels_last”应将数据组织为(128,128,128,3)。该参数的默认值是~/.keras/keras.json中设置的值,若从未设置过,则为“channels_last”。
-
use_bias:布尔值,是否使用偏置项
-
kernel_initializer:权值初始化方法,为预定义初始化方法名的字符串,或用于初始化权重的初始化器。参考initializers
-
bias_initializer:权值初始化方法,为预定义初始化方法名的字符串,或用于初始化权重的初始化器。参考initializers
-
kernel_regularizer:施加在权重上的正则项,为Regularizer对象
-
bias_regularizer:施加在偏置向量上的正则项,为Regularizer对象
-
activity_regularizer:施加在输出上的正则项,为Regularizer对象
-
kernel_constraints:施加在权重上的约束项,为Constraints对象
-
bias_constraints:施加在偏置上的约束项,为Constraints对象
输入shape
‘channels_first’模式下,输入应为形如(samples,channels,input_dim1,input_dim2, input_dim3)的5D张量
‘channels_last’模式下,输入应为形如(samples,input_dim1,input_dim2, input_dim3,channels)的5D张量
这里的输入shape指的是函数内部实现的输入shape,而非函数接口应指定的input_shape。
二、如何将输入数据转化为符合3D卷积的输入的形式
3D卷积输入应为形如(samples,input_dim1,input_dim2, input_dim3,channels)的5D张量,如(10000,10,128,,128,3)表示输入是10帧 128*128的彩色RGB图像构成的图像块,共有10000个图像块。而一般我们的彩色RGB图像为3D张量,如(128,128,3),那么如何将它转化为符合3D卷积输入的5D张量呢?这里主要使用numpy中的reshape()函数改变图像array的shape,在使用numpy中的concatenate()函数进行数组array合并。具体如下:(以(128,128,3)---》(10000,10,128,,128,3)为例)
1、获取图片中所有的文件名,这里可以使用os.listdir()函数,如:
# image_path是文件路径
filenames = os.listdir(image_path)
2、读取图片文件
这里可以使用cv2.imread()函数进行读取,得到的结果是类似于(128,128,3)的数组array,如:
im1= cv2.imread('C:/01.jpg')
im2= cv2.imread('C:/02.pg')
3、使用np.reshape()改变数组的维度,改变为(1,128,128,3),如:
im1 = im1.reshape((1,128,128,3))
im2 = im2.reshape((1,128,128,3))
4、使用np.concatenate()函数进行合并,如:
# im1,im2表示要合并的array,axis表示要合并的维度
im10 = np.concatenate((im1,im2), axis = 0)
5、每合并完10张图片,都将得到类似于(10,128,128,3)的4D张量,这时,只需要再进行一次reshape和concatenate即可的到想要的5D张量,如
im10_1 = reshape(1,10,128,128,3)
im10_2 = reshape(1,10,128,128,3)
im =np.concatenate((im10_1,im10_2), axis = 0)
【最终的代码】:
import cv2
import os
import numpy as np
# image_path是文件路径,此路径中有690张图片
image_path = "F:\\image"
def image2array(image_path ):
filenames = os.listdir(image_path)
image_num = len(filenames)
cube_num = int(image_num /10)
image_name = image_path + '\\' + filenames[0]
Img = cv2.imread(image_name)
Img =Img.reshape(1,Img.shape[0], Img.shape[1],Img.shape[2])
Img10 = Img
for k in range(1, 10):
image_name = image_path + '\\' + filenames[k]
Img = cv2.imread(image_name)
Img = Img.reshape(1, Img.shape[0], Img.shape[1], Img.shape[2])
Img10 = np.concatenate((Img10, Img), axis=0)
cube = Img10.reshape(1,Img10.shape[0], Img10.shape[1], Img10.shape[2], Img10.shape[3])
for i in range(1, cube_num):
index = 10 * i
image_name = image_path + '\\' + filenames[index]
Img = cv2.imread(image_name)
Img = Img.reshape(1, Img.shape[0], Img.shape[1], Img.shape[2])
Img10 = Img
for k in range(1, 10):
image_name = image_path + '\\' + filenames[index+k]
Img = cv2.imread(image_name)
Img = Img.reshape(1, Img.shape[0], Img.shape[1], Img.shape[2])
Img10 = np.concatenate((Img10, Img), axis=0)
Img10 = Img10.reshape(1, Img10.shape[0], Img10.shape[1], Img10.shape[2], Img10.shape[3])
cube = np.concatenate((cube,Img10), axis=0)
return cube
if __name__ == "__main__" :
cube = image2array(image_path)
print(cube.shape)
【运行结果】: