Cats vs. Dogs(猫狗大战)数据集下载地址为https://www.kaggle.com/c/dogs-vs-cats/data。这个数据集是Kaggle大数据竞赛某一年的一道赛题,利用给定的数据集,用算法实现猫和狗的识别。 其中包含了训练集和测试集,训练集中猫和狗的图片数量都是12500张且按顺序排序,测试集中猫和狗混合乱序图片一共12500张。
数据集中的图片尺寸都不尽相同,没有进行统一的裁剪。在神经网络模型的训练中,在输入层要求输入的数据大小是固定的,因此需要对数据集中的所有图片按照固定的大小裁剪。例如,AlexNet模型的输入图片大小是[227,227],在这里我们按照这个大小进行裁剪。代码如下:
import cv2
import os
# 数据预处理,把图片数据集的所有图片修剪成固定大小形状
def image_tailor(input_dir, out_dir):
for root, dirs, files in os.walk(input_dir):
for file in files:
# file为root目录中的文件
filepath = os.path.join(root, file) # 连接两个或更多的路径名组件,filepath路径为/root/file
try:
image = cv2.imread(filepath) # 根据输入路径读取照片
dim = (227, 227) # 裁剪的尺寸
resized = cv2.resize(image, dim) # 按比例将原图缩放成227*227
path = os.path.join(out_dir, file) # 保存的路径和相应的文件名
cv2.imwrite(path, resized) # 进行保存
except:
print(filepath)
os.remove(filepath)
cv2.waitKey()
input_patch = 'F:\\data\\kaggle\\test1' # 数据集的地址
out_patch = 'F:\\data\\fixdata\\tailor' # 图片裁剪后保存的地址
image_tailor(input_patch, out_patch)
print('reshape finished')
运行以上代码,就能自动的完成图片的裁剪,并保存到相应的文件夹中。os.walk()
函数是一个简单易用的文件、目录遍历器,可以帮助我们高效的处理文件、目录方面的事情。
对测试集完成剪裁后的部分图片如图:
从裁剪后的图片与前文未裁剪的图片对比可以看到,裁剪只是对原图片按照一定的比例缩放到固定的尺寸,很好的保留了原图的信息。
在第一步中,我们已经将尺寸大小不规则的图片缩放成固定大小,以满足神经网络模型AlexNet固定输入大小形式。在这一步中,我们需要对裁剪好的数据集中的图片的位置进行读取,并给图片打上标签。使用数组对图片的位置和标签进行保存,为后续的batch读取数据集做好准备。
完成代码如下:
# 用来读取数据集中所有图片的路径和标签
def get_file(file_dir):
images = [] # 存放的是每一张图片对应的地址和名称
temp = [] # 存放的是文件夹地址
for root, sub_folders, files in os.walk(file_dir):
# image directories
for name in files:
images.append(os.path.join(root, name))
#print(images)
#print(files)
#print(images)
# 读取当前目录选的文件夹
for name in sub_folders:
temp.append(os.path.join(root, name))
#print(temp)
print(sub_folders)
print('a--------------a')
print(images)
print(temp)
print('--------------finish---------------')
# 为数据集打标签,cat为0,dog为1
labels = []
error = 0
for one_folder in temp:
n_img = len(os.listdir(one_folder)) # os.listdir()返回指定的文件夹包含的文件或文件夹的名字的列表,再用len求该文件夹里面图像的数目
print(one_folder)
print(n_img)
letter = one_folder.split('\\')[-1] # 对路径进行切片,[-1]为取切片后的最后一个元素(也就是文件夹名称)。用于根据名称去判断数据集的样本类型
#print(letter)
if letter == 'cat':
labels = np.append(labels, n_img * [0]) # 向labels里面添加1*n_img个0
elif letter == 'dog':
labels = np.append(labels, n_img * [1])
else:
error = error + 1
print(labels)
print(error)
temp = np.array([images, labels])
#print(temp)
temp = temp.transpose() # 矩阵转置
#print(temp)
np.random.shuffle(temp) # shuffle() 是将序列的所有元素随机排序。
#print(temp)
image_list = list(temp[:, 0]) # 所有行,第0列
label_list = list(temp[:, 1]) # 所有行,第1列
print(label_list) # ['1.0', '1.0', '1.0', '0.0', '0.0', '0.0']
label_list = [int(float(i)) for i in label_list] # 把字符型标签转化为整型
print(label_list) # [1, 1, 1, 0, 0, 0]
return image_list, label_list
images_list, labels_list = get_file('F:\\data\\testdata')
print('image transform finished', images_list)
print('label transform finished', labels_list)
上述代码中,首先对数据集图片的位置进行读取,之后根据文件夹名称的不同将不同文件夹中的图片标签设置为0或1,最后以矩阵的形式返回数据集存储图片的路径和对应的标签。
在这里就需要对下载好的原数据集进行调整,把train集
里面的猫和狗图片分两个文件夹,一个cat文件夹全部装猫的图片,另外一个dog文件装狗的图片,程序就是根据ca
t和dog
这两个名称对图片进行打标签。为了提高网络的分类精度,训练时最好把数据集打乱,这里就使用了np.random.shufle()
对读入的数据集进行乱序操作。
另外一个更简洁的做法是不需要对train集
里的猫、狗图片进行单独存储,直接对train集
的所有猫、狗数据进行操作,标签是按图片的名称不同来打标签,cat为0,dog为1。代码基本和上面的差不多。
# 获取文件路径和标签
def get_files(file_dir):
# file_dir: 文件夹路径
# return: 乱序后的图片和标签
cats = []
label_cats = []
dogs = []
label_dogs = []
# 载入数据路径并写入标签值
for file in os.listdir(file_dir): # file_dir文件夹下所有的文件
name = file.split(sep='.') # 对文件名以'.'做划分
print(name)
if name[0] == 'cat':
#cats.append(file_dir + file)
cats.append(os.path.join(file_dir,file))
label_cats.append(0)
elif name[0] == 'dog':
#dogs.append(file_dir + file)
dogs.append(os.path.join(file_dir,file))
label_dogs.append(1)
print("There are %d cats\nThere are %d dogs" % (len(cats), len(dogs)))
print('cats:', cats)
print('label_cats:', label_cats)
print('dogs:', dogs)
print('label_cats:', label_dogs)
# 打乱文件顺序
image_list = np.hstack((cats, dogs)) # 将cats和dogs矩阵按水平拼接
print('image_list:', image_list)
label_list = np.hstack((label_cats, label_dogs))
print(label_list)
temp = np.array([image_list, label_list])
temp = temp.transpose() # 转置
np.random.shuffle(temp) # 打乱顺序
image_list = list(temp[:, 0])
label_list = list(temp[:, 1])
label_list = [int(i) for i in label_list]
return image_list, label_list
file_dir = 'F:\\data\\testdata3\\train'
image_list, label_list = get_files(file_dir)
print(image_list)
print(label_list)