如何在tensorflow2.0制作自己的数据集

如何在tensorflow2.0制作自己的数据集

  1. 运行环境
    Windows10
    PyCharm 2019.2.3
  2. 需要用到的库
    opencv4.1.2_python3.7

图片获取

首先我们需要获取到自己需要的图片,图片格式大小必须统一,获取方式不限,我们这里利用opencv进行人脸照片的捕获,size为64*64,另外没有安装opencv_python库的可以点击这里,选择相应的版本进行下载,我选择的是opencv_python-4.1.2-cp37-cp37m-win_amd64.whl,具体安装方法可以去百度。安装好opencv库之后,就开始贴代码了,我已经在代码里写了相应的注释,大家仔细看哦!

import random
import numpy as np
import cv2
import os

IMGSIZE = 64


# 创建目录
def createdir(*args):
    for item in args:
        if not os.path.exists(item):
            os.makedirs(item)


def relight(imgsrc, alpha=1, bias=0):
    imgsrc = imgsrc.astype(float)
    imgsrc = imgsrc * alpha + bias
    imgsrc[imgsrc < 0] = 0
    imgsrc[imgsrc > 255] = 255
    imgsrc = imgsrc.astype(np.uint8)
    return imgsrc


def getfacefromcamera(outdir):
    createdir(outdir)
    camera = cv2.VideoCapture(0)
    haar = cv2.CascadeClassifier('D:/haarcascades/haarcascade_frontalface_default.xml')
    n = 1
    while 1:
        # 创建20064*64图片
        if n <= 200:
            print('It`s processing %s image.' % n)
            success, img = camera.read()
            gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            faces = haar.detectMultiScale(gray_img, 1.3, 5)
            # f_x, f_y, f_w, f_h分别为获取面部的左上角x, y坐标值,宽高值(原点(00)在图片左上角)
            for f_x, f_y, f_w, f_h in faces:
                # 截取面部图片,先写y方向,再写x方向,别写反了(可以尝试尝试写反获取的图片)
                face = img[f_y:f_y+f_h, f_x:f_x+f_w]
                # 修改图片大小为64*64
                face = cv2.resize(face, (IMGSIZE, IMGSIZE))
                # 随机改变图片的明亮程度,增加图片复杂度
                face = relight(face, random.uniform(0.5, 1.5), random.randint(-50, 50))
                # 保存图片
                cv2.imwrite(os.path.join(outdir, str(n)+'.jpg'), face)
                # 在原图img面部上方20处写下你的名字
                cv2.putText(img, 'haha', (f_x, f_y-20), cv2.FONT_HERSHEY_COMPLEX, 1, 255, 2)
                # 画出方框,框选出你的face
                img = cv2.rectangle(img, (f_x, f_y), (f_x + f_w, f_y + f_h), (255, 0, 0), 2)
                n += 1
            cv2.imshow('img', img)
            key = cv2.waitKey(30) & 0xff
            if key == 27:
                break
        else:
            break
    camera.release()
    cv2.destroyAllWindows()


if __name__ == '__main__':
    # 输入你的名字,创建属于你的face文件夹
    name = input('please input your name: ')
    # 执行这段代码前必须在当前目录手动创建一个‘face_images’文件夹,否则下面代码找不到‘face_images'
    getfacefromcamera(os.path.join('face_images', name))

在这里面需要用到一个人脸识别的haarcascade_frontalface_default.xml文件,在一般的C++版本安装包…\opencv\sources\data\下就可以找到,但是我们安装的这个opencv_python似乎没有(我没找到),所以我就从其他的地方拷了过来,在代码里写下其绝对路径就行了。
运行后的结果是这样的
如何在tensorflow2.0制作自己的数据集_第1张图片
如何在tensorflow2.0制作自己的数据集_第2张图片
我这里就采集了两个人的面部数据,大家可根据自己的需求做相应的修改,到此我们已经有自己的数据了,接下来我们利用这些数据制作我们自己的数据集。

数据集制作

废话不多说,先贴代码

import tensorflow as tf
import  glob
import random
import csv
import cv2
import os

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

root_img = 'D:\\tensorflow\\My_Work\\Target_Detect\\face_images\\'
img_mean = tf.constant([0.485, 0.456, 0.406])
img_std = tf.constant([0.229, 0.224, 0.225])


# root为我们之前获得图片数据的根目录face_images,filename为我们要加载的csv文件,
# name2label为我们获取的图片类型字典
def load_csv(root, filename, name2label):
    # 如果根目录root下不存在filename文件,那么创建一个filename文件
    if not os.path.exists(os.path.join(root, filename)):
        # 创建一个图片路径的列表images
        images = []
        # 遍历字典里所有的元素,例如我的第一个为'xu',第二个为‘zheng’
        for name in name2label.keys():
            # 将路径下所有的jpg图片的路径写至images列表中
            images += glob.glob(os.path.join(root, name, '*.jpg'))
        print(len(images), images)
        # 对images进行随机打乱
        random.shuffle(images)
        with open(os.path.join(root, filename), mode='w', newline='') as f:
            writer = csv.writer(f)
            for img in images:
                # 获取路径最底层文件夹的名字
                # os.sep为路径的分隔符,split函数以给定分隔符进行切片(默认以空格切片),取从右往左数第二个
                # img = '...a/b/c/haha.jpg' =>['...a', 'b', 'c', 'haha.jpg'], -2指的是'c'
                name = img.split(os.sep)[-2]
                # 查找字典对应元素的值
                label = name2label[name]
                # 添加到路径的后面
                writer.writerow([img, label])
            print('written into csv file:', filename)
    # 如果存在filename文件,将其读取至imgs, labels这两个列表中
    imgs, labels = [], []
    with open(os.path.join(root, filename)) as f:
        reader = csv.reader(f)
        for row in reader:
            # 读取路径和对应的label值
            img, label = row
            label = int(label)
            # 将其分别压入列表中,并返回出来
            imgs.append(img)
            labels.append(label)
    return imgs, labels


def load_faceimg(root, mode='train'):
    # 创建图片类型字典,准备调用load_csv方法
    name2label = {}
    for name in sorted(os.listdir(os.path.join(root))):
        # 跳过root目录下不是文件夹的文件
        if not os.path.isdir(os.path.join(root, name)):
            continue
        # name为根目录下各个文件夹的名字
        # name2label.keys表示字典name2label里所有的元素,len表示字典所有元素的个数
        # 一开始字典是没有元素的,所以'xu'的值为0, 之后字典元素有个一个,所以'zheng'的值为1
        name2label[name] = len(name2label.keys())
    # 调用load_csv方法,返回值images为储存图片的目录的列表,labels为储存图片种类编码的列表
    images, labels = load_csv(root, 'images.csv', name2label)
    # 我们将前60%取为训练集,后20%取为验证集,最后20%取为测试集,并返回
    if mode == 'train':
        images = images[:int(0.6 * len(images))]
        labels = labels[:int(0.6 * len(labels))]
    elif mode == 'val':
        images = images[int(0.6 * len(images)):int(0.8 * len(images))]
        labels = labels[int(0.6 * len(labels)):int(0.8 * len(labels))]
    else:
        images = images[int(0.8 * len(images)):]
        labels = labels[int(0.8 * len(labels)):]
    return images, labels, name2label


def normalize(x, mean=img_mean, std=img_std):
    # 标准化
    # x: [64, 64, 3]
    # mean: [64, 64, 3], std: [3]
    x = (x - mean) / std
    return x


# x:图片的路径List, y: 图片种类的数字编码List
def get_tensor(x, y):
    # 创建一个列表ims
    ims = []
    for i in x:
        # 读取路径下的图片
        p = tf.io.read_file(i)
        # 对图片进行解码,RGB3通道
        p = tf.image.decode_jpeg(p, channels=3)
        # 修改图片大小为64*64
        p = tf.image.resize(p, [64, 64])
        # 将图片压入ims列表中
        ims.append(p)
    # 将List类型转换为tensor类型,并返回
    ims = tf.convert_to_tensor(ims)
    y = tf.convert_to_tensor(y)
    return ims, y


# 预处理函数,x, y均为tensor类型
def preprocess(x, y):
    # 数据增强
    x = tf.image.random_flip_left_right(x)  # 左右镜像
    x = tf.image.random_crop(x, [64, 64, 3])  # 随机裁剪
    # x: [0,255]=>0~1,将其值转换为float32
    x = tf.cast(x, dtype=tf.float32) / 255.
    # 0~1 => D(0, 1)
    x = normalize(x)
    # 将其值转换为int32
    y = tf.cast(y, dtype=tf.int32)
    return x, y


# 加载图片,获得图片路径与图片种类编码的列表
images_train, labels_train, name2label = load_faceimg(root_img, mode='train')
images_val, labels_val, _ = load_faceimg(root_img, mode='val')
images_test, labels_test, _ = load_faceimg(root_img, mode='test')

# 从对应路径读取图片,并将列表转换为张量
x_train, y_train = get_tensor(images_train, labels_train)
x_val, y_val = get_tensor(images_val, labels_val)
x_test, y_test = get_tensor(images_test, labels_test)

# 可输出查看它们的shape
print('x_train:', x_train.shape, 'y_train:', y_train.shape)
print('x_val:', x_val.shape, 'y_val:', y_val.shape)
print('x_test:', x_test.shape, 'y_test:', y_test.shape)

# 切分传入参数的第一个维度,并进行随机打散,预处理和打包处理
db_train = tf.data.Dataset.from_tensor_slices((x_train, y_train))
db_train = db_train.shuffle(1000).map(preprocess).batch(10)

db_val = tf.data.Dataset.from_tensor_slices((x_val, y_val))
db_val = db_val.map(preprocess).batch(10)

db_test = tf.data.Dataset.from_tensor_slices((x_test, y_test))
db_test = db_test.map(preprocess).batch(10)

# 创建一个迭代器,可以查看其shape大小
sample_train = next(iter(db_train))
sample_val = next(iter(db_val))
sample_test = next(iter(db_test))
print('sample_train:', sample_train[0].shape, sample_train[1].shape)
print('sample_val:', sample_val[0].shape, sample_val[1].shape)
print('sample_test:', sample_test[0].shape, sample_test[1].shape)

创建的csv文件如下
如何在tensorflow2.0制作自己的数据集_第3张图片
输出结果为

x_train: (240, 64, 64, 3) y_train: (240,)
x_val: (80, 64, 64, 3) y_val: (80,)
x_test: (80, 64, 64, 3) y_test: (80,)
sample_train: (10, 64, 64, 3) (10,)
sample_val: (10, 64, 64, 3) (10,)
sample_test: (10, 64, 64, 3) (10,)

因为我就取了两个人的脸部数据,所以总共有400张,训练集为60%故有240张,验证集和测试集分别为20%,故为80张。
如若大家嫌opencv_python库下载慢,或者找不到人脸识别的xml文件,我这里提供了一个百度云链接
https://pan.baidu.com/s/1TjTB2V0nbtifQDQX5f9YmA(虽然百度云也很慢,哈哈)
我贴在这里的代码,如果你看懂了正常来说是可以运行的,我也是才开始学tensorflow2.0,如果有什么问题,欢迎私信找我讨论,一起加油哦!

你可能感兴趣的:(深度学习)