目录
介绍
获取数据集
准备解析器
分类数据集
下一步?
如果您看过《少数派报告》电影,您可能还记得汤姆·克鲁斯(Tom Cruise)走进一家Gap商店的场景。视网膜扫描仪读取他的眼睛,并为他播放定制的广告。好吧,这是2020年。我们不需要视网膜扫描仪,因为我们拥有人工智能(AI)和机器学习(ML)!
在本系列中,我们将向您展示如何使用深度学习进行面部识别,然后基于被识别的面部,使用神经网络语音合成(TTS)引擎播放自定义广告。
我们假设您熟悉AI/ML的基本概念,并且可以找到使用Python的方法。
在上一篇文章中,我们描述了检测图像中人脸的过程。现在,我们知道如何从较大的图片或视频中获取裁剪的面部图像,让我们假设已经完成了本练习,最后得到了一个数据集(面部集)来训练我们的CNN。但是,在训练之前,我们需要处理此数据集以对数据进行分类和规范化。在本文中,我们将创建一个数据集解析器/处理器,并在Yale Face数据集上运行它,其中包含15个不同人的165张灰度图像。这个数据集很小,但足以满足我们的学习目的。
数据集解析器将位于两个类中,一个是抽象类,另一个是更通用的类,另一个类处理所选数据集的细节。让我们看一下父类的构造函数。
class FaceDataSet(metaclass=abc.ABCMeta):
def __init__(self, path, extension_list, n_classes):
self.path = path
self.ext_list = extension_list
self.n_classes = n_classes
self.objects = []
self.labels = []
self.obj_validation = []
self.labels_validation = []
self.number_labels = 0
构造函数参数为:
我们还创建下一个类对象:
get_data()方法是我们在实例化FaceDataSet类之后调用的方法。
def get_data(self):
img_path_list = os.listdir(self.path)
self.objects, self.labels = self.fetch_img_path(img_path_list, self.path, vgg_img_processing)
self.process_data(vgg_img_processing)
self.print_dataSet()
该方法由两个主要调用组成:从定义的路径获取图像并进行处理。要获取图像,我们遍历path-defined文件夹中的文件。然后,我们使用SK-Image将这些文件加载为灰度图像。该调用返回一个NumPy数组,其中包含图像中的每个像素。
def fetch_img_path(self, img_path_list, path, vgg_img_processing):
images = []
labels = []
for img_path in img_path_list:
if self.__check_ext(img_path):
img_abs_path = os.path.abspath(os.path.join(path, img_path))
image = io.imread(img_abs_path, as_gray=True)
label = self.process_label(img_path)
images.append(image)
labels.append(label)
return images, labels
def __check_ext(self, file_path):
for ext in self.ext_list:
if file_path.endswith(ext):
return True
return False
process_label()是FaceDataSet类中的抽象方法;它的实现发生在YaleDataSet类中,在该类中我们从数据集中解析图像文件的名称。文件名采用“subjectXX.*”格式。该方法从文件名中提取“XX”号并将其分配给图像。
class YaleFaceDataSet(FaceDataSet):
def __init__(self, path, ext_list, n_classes):
super().__init__(path, ext_list, n_classes)
def process_label(self, img_path):
val = int(os.path.split(img_path)[1].split(".")[0].replace("subject", "")) - 1
if val not in self.labels:
self.number_labels+=1
return val
最后,process_data()方法如下所示:
def split_training_set(self):
return train_test_split(self.objects, self.labels, test_size=0.3,
random_state=random.randint(0, 100))
def process_data(self, vgg_img_processing):
self.objects, self.img_obj_validation, self.labels, self.img_labels_validation = \
self.split_training_set()
self.labels = np_utils.to_categorical(self.labels, self.n_classes)
self.labels_validation = np_utils.to_categorical(self.img_labels_validation, self.n_classes)
self.objects = Common.reshape_transform_data(self.objects)
self.obj_validation = Common.reshape_transform_data(self.img_obj_validation)
在这种方法中,我们将数据集分为两部分。第二部分包含用于验证训练结果的图像。我们使用Scikit-Learn提供的train_test_split()方法,并将标签转换为分类变量。如果图像的分类为“2”(来自subject02),则其分类变量将为[0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] –第15维(类数)的向量,其中第二部分。
class Common:
@staticmethod
def reshape_transform_data(data):
data = numpy.array(data)
result = Common.reshape_data(data)
return Common.to_float(result)
@staticmethod
def reshape_data(data):
return data.reshape(data.shape[0], constant.IMG_WIDTH, constant.IMG_HEIGHT, 1)
@staticmethod
def to_float(value):
return value.astype('float32')/255
reshape_transform_data()方法可对数据进行整形以适合灰度模式。在图像处理中,彩色图像被认为是3通道网格。换句话说,它们分为3种颜色(RGB)。灰度图像只有一个通道。因此,最初的彩色图像需要在最后用“1”整形。
to_float()方法通过将每个像素值除以255(像素值介于0到255之间)来标准化数据,这会将整个像素矩阵带到0-1空间,以实现更好的数值输入和更快的收敛。现在,我们可以在main.py文件中设置数据集,数据集将作为我们应用程序的入口点。
ext_list = ['gif', 'centerlight', 'glasses', 'happy', 'sad', 'leflight',
'wink', 'noglasses', 'normal', 'sleepy', 'surprised', 'rightlight']
n_classes = 15
# Set up dataSet
dataSet = YaleFaceDataSet(constant.FACE_DATA_PATH, ext_list, n_classes)
...
现在,我们已经有一个经过处理的分类数据集,可用于CNN训练。在接下来的文章中,我们将一起把我们的CNN和训练它的人脸识别。敬请关注!