一、背景

人脸表情识别网上已有很多教程,大多基于fer2013数据集展开的。现在的问题就在于fer2013数据集的数量太少,表情的区分度不够明显,大部分基于此数据集的模型,其识别精度仅有70%左右。

因此我想自己从零开始制作人脸表情,而且是非常夸张,有趣的人脸表情,用于后续的表情识别实验。这一篇仅仅介绍如何在没有任何数据的情况下,从零开始制作人脸表情数据集。

二、数据获取

首先没有任何数据的情况下,该如何开始数据的获取呢?其实就两种思路:一种是自己采集,例如用摄像头抓帧,另一种是爬虫爬取数据。实验采用爬虫爬取百度图片中的数据。

然后自己设计自己需要的表情,我自己设置了10类。这里以“吃惊”表情为例,在百度图片搜索中可以看到:

有一部分人脸数据,当然还有很多非人脸数据,这里我们先不管那么多,直接全部爬取下来,爬取的程序采用:

# 导入需要的库
import requests
import os
import json# 爬取百度图片,解析页面的函数
def getManyPages(keyword, pages):'''参数keyword:要下载的影像关键词参数pages:需要下载的页面数'''params = []for i in range(30, 30 * pages + 30, 30):params.append({'tn': 'resultjson_com','ipn': 'rj','ct': 201326592,'is': '','fp': 'result','queryWord': keyword,'cl': 2,'lm': -1,'ie': 'utf-8','oe': 'utf-8','adpicid': '','st': -1,'z': '','ic': 0,'word': keyword,'s': '','se': '','tab': '','width': '','height': '','face': 0,'istype': 2,'qc': '','nc': 1,'fr': '','pn': i,'rn': 30,'gsm': '1e','1488942260214': ''})url = 'https://image.baidu.com/search/acjson'urls = []for i in params:try:urls.append(requests.get(url, params=i).json().get('data'))except json.decoder.JSONDecodeError:print("解析出错")return urls# 下载图片并保存
def getImg(dataList, localPath):'''参数datallist:下载图片的地址集参数localPath:保存下载图片的路径'''if not os.path.exists(localPath):  # 判断是否存在保存路径,如果不存在就创建os.mkdir(localPath)x = 0for list in dataList:for i in list:if i.get('thumbURL') != None:print('正在下载:%s' % i.get('thumbURL'))ir = requests.get(i.get('thumbURL'))open(localPath + '%d.jpg' % x, 'wb').write(ir.content)x += 1else:print('图片链接不存在')# 根据关键词来下载图片
if __name__ == '__main__':dataList = getManyPages('吃惊', 20)     # 参数1:关键字,参数2:要下载的页数getImg(dataList, './data/chijing/')            # 参数2:指定保存的路径

之前我用这段程序爬取过皮卡丘图像,因此不再多做介绍,详细可以参见:对抗神经网络学习(四)——WGAN+爬虫生成皮卡丘图像(tensorflow实现)。这里爬取好的图像直接保存在根目录下的'./data/chijing/'文件夹中。

同样的思路,可以爬取其余9种表情。

三、人脸裁剪及预处理

爬取完人脸表情之后,我们需要裁剪处图像中的人脸,这里设置裁剪大小为128*128。裁剪过程需要用到opencv的人脸识别工具,即haarcascade_frontalface_alt.xml,关于该文件,可从opencv库的根目录中查找,具体查找方法可以参见我之前的文章:深度学习(一)——deepNN模型实现摄像头实时识别人脸表情(C++和python3.6混合编程)。将该文件复制到project的根目录下,然后裁剪人脸,具体的裁剪程序为:

import os
import cv2# 读取图像,然后将人脸识别并裁剪出来, 参考https://blog.csdn.net/wangkun1340378/article/details/72457975
def clip_image(input_dir, floder, output_dir):images = os.listdir(input_dir + floder)for imagename in images:imagepath = os.path.join(input_dir + floder, imagename)img = cv2.imread(imagepath)path = "haarcascade_frontalface_alt.xml"hc = cv2.CascadeClassifier(path)faces = hc.detectMultiScale(img)i = 1image_save_name = output_dir + floder + imagenamefor face in faces:imgROI = img[face[1]:face[1] + face[3], face[0]:face[0] + face[2]]imgROI = cv2.resize(imgROI, (128, 128), interpolation=cv2.INTER_AREA)cv2.imwrite(image_save_name, imgROI)i = i + 1print("the {}th image has been processed".format(i))def main():input_dir = "data/"floder = "chijing/"output_dir = "output/"if not os.path.exists(output_dir + floder):os.makedirs(output_dir + floder)clip_image(input_dir, floder, output_dir)if __name__ == '__main__':main()

如果要将该方法用于其余9种表情,只需自己修改main函数中的相关路径即可。这样裁剪之后的影像中,难免混有一些非人脸图像,只需手动删除即可。这样处理之后的效果为:

四、数据增广

经过以上三步,基本可以得到人脸数据集了,但是有的表情的数据量很少,进行模型训练的时候必然会因为数据不足带来影响,因此还需要进行数据增广处理。

一般地,数据增广处理的方法包括:旋转,镜像,随机裁剪,噪声,变形,颜色变化,对比度拉伸等方法。对于人脸来说,这里所选择的处理方法仅有:镜像,即左右反转;随机裁剪,将128*128影响随机裁剪为120*120,再将其resize成128*128;噪声,添加少量的随机噪声。考虑到人脸数据集的特殊性,其他方法暂时没有选择。

这里直接给出数据增广的代码:

# 参考https://blog.csdn.net/qq_36219202/article/details/78339459
import os
from PIL import Image,ImageEnhance
import skimage
import random
import numpy as np
import cv2# 随机镜像
def random_mirror(root_path, img_name):img = Image.open(os.path.join(root_path, img_name))filp_img = img.transpose(Image.FLIP_LEFT_RIGHT)filp_img = np.asarray(filp_img, dtype="float32")return filp_img# 随机平移
def random_move(root_path, img_name, off):img = Image.open(os.path.join(root_path, img_name))offset = img.offset(off, 0)offset = np.asarray(offset, dtype="float32")return offset# # 随机转换
# def random_transform( image, rotation_range, zoom_range, shift_range, random_flip ):
#     h,w = image.shape[0:2]
#     rotation = numpy.random.uniform( -rotation_range, rotation_range )
#     scale = numpy.random.uniform( 1 - zoom_range, 1 + zoom_range )
#     tx = numpy.random.uniform( -shift_range, shift_range ) * w
#     ty = numpy.random.uniform( -shift_range, shift_range ) * h
#     mat = cv2.getRotationMatrix2D( (w//2,h//2), rotation, scale )
#     mat[:,2] += (tx,ty)
#     result = cv2.warpAffine( image, mat, (w,h), borderMode=cv2.BORDER_REPLICATE )
#     if numpy.random.random() < random_flip:
#         result = result[:,::-1]
#     return result# # 随机变形
# def random_warp( image ):
#     assert image.shape == (256,256,3)
#     range_ = numpy.linspace( 128-80, 128+80, 5 )
#     mapx = numpy.broadcast_to( range_, (5,5) )
#     mapy = mapx.T
#
#     mapx = mapx + numpy.random.normal( size=(5,5), scale=5 )
#     mapy = mapy + numpy.random.normal( size=(5,5), scale=5 )
#
#     interp_mapx = cv2.resize( mapx, (80,80) )[8:72,8:72].astype('float32')
#     interp_mapy = cv2.resize( mapy, (80,80) )[8:72,8:72].astype('float32')
#
#     warped_image = cv2.remap( image, interp_mapx, interp_mapy, cv2.INTER_LINEAR )
#
#     src_points = numpy.stack( [ mapx.ravel(), mapy.ravel() ], axis=-1 )
#     dst_points = numpy.mgrid[0:65:16,0:65:16].T.reshape(-1,2)
#     mat = umeyama( src_points, dst_points, True )[0:2]
#
#     target_image = cv2.warpAffine( image, mat, (64,64) )
#
#     return warped_image, target_image# 随机旋转
def random_rotate(root_path, img_name):img = Image.open(os.path.join(root_path, img_name))rotation_img = img.rotate(180)rotation_img = np.asarray(rotation_img, dtype="float32")return rotation_img# 随机裁剪
def random_clip(root_path, floder, imagename):# 可以使用crop_img = tf.random_crop(img,[280,280,3])img = cv2.imread(root_path + floder + imagename)count = 1               # 随机裁剪的数量while 1:y = random.randint(1, 8)x = random.randint(1, 8)cropImg = img[(y):(y + 120), (x):(x + 120)]image_save_name = root_path + floder + 'clip' + str(count) + imagename# BGR2RGB# cropImg = cv2.cvtColor(cropImg, cv2.COLOR_BGR2RGB)cropImg = cv2.resize(cropImg, (128, 128))cv2.imwrite(image_save_name, cropImg)count += 1print(count)if count > 3:break# 随机噪声
def random_noise(root_path, img_name):image = Image.open(os.path.join(root_path, img_name))im = np.array(image)means = 0sigma = 10r = im[:, :, 0].flatten()g = im[:, :, 1].flatten()b = im[:, :, 2].flatten()# 计算新的像素值for i in range(im.shape[0] * im.shape[1]):pr = int(r[i]) + random.gauss(means, sigma)pg = int(g[i]) + random.gauss(means, sigma)pb = int(b[i]) + random.gauss(means, sigma)if (pr < 0):pr = 0if (pr > 255):pr = 255if (pg < 0):pg = 0if (pg > 255):pg = 255if (pb < 0):pb = 0if (pb > 255):pb = 255r[i] = prg[i] = pgb[i] = pbim[:, :, 0] = r.reshape([im.shape[0], im.shape[1]])im[:, :, 1] = g.reshape([im.shape[0], im.shape[1]])im[:, :, 2] = b.reshape([im.shape[0], im.shape[1]])gaussian_image = Image.fromarray(np.uint8(im))return gaussian_image# 随机调整对比度
def random_adj(root_path, img_name):image = skimage.io.imread(os.path.join(root_path, img_name))gam = skimage.exposure.adjust_gamma(image, 0.5)log = skimage.exposure.adjust_log(image)gam = np.asarray(gam, dtype="float32")log = np.asarray(log, dtype="float32")return gam, log# 运行
def main():root_dir = "output/"floder = "chijing/"images = os.listdir(root_dir + floder)for imagename in images:mirror_img = random_mirror(root_dir + floder, imagename)image_save_name = root_dir + floder + "mirror" + imagenamemirror_img = cv2.cvtColor(mirror_img, cv2.COLOR_BGR2RGB)cv2.imwrite(image_save_name, mirror_img)random_clip(root_dir, floder, imagename)noise_img = random_noise(root_dir + floder, imagename)noise_img = np.asarray(noise_img, dtype="float32")image_save_name = root_dir + floder + "noise" + imagenamenoise_img = cv2.cvtColor(noise_img, cv2.COLOR_BGR2RGB)cv2.imwrite(image_save_name, noise_img)print("image preprocessing")if __name__ == '__main__':main()

很多处理方法都是参考网上的代码,只不过我将这些方法整合到了一起。对于其余9种表情,需要设置的仅仅只是main函数种的路径参数。

随机裁剪3张、镜像1张、随机噪声1张的处理结果如下:

最终的“吃惊”表情处理结果:

整个处理之后的数据量还是非常可观的,当然了,如果自己觉得数据量还不够,还可以再进行进一步处理,例如对镜像图像进行随机裁剪,不同程度的噪声影像,以及对比度拉伸等方法。

以上仅仅是一种表情的数据集制作,同理制作其余的表情数据集即可。准备好了数据集之后,即可开始进行模型的训练了~

从零开始制作人脸表情的数据集相关推荐

  1. 人脸表情识别数据集:CK+

    CK+有123的子类(人),每个人提供1~7种表情,每种表情是一组序列(总共有593个图像序列,其中327个序列是有表情标签的):从自然缓慢变化到给定表情 比如上图是人S026做出的某类表情,第一张是 ...

  2. 深度学习(二)——从零自己制作数据集到利用deepNN实现夸张人脸表情的实时监测(tensorflow实现)

    一.背景介绍 这篇文章主要参考我的上一篇文章:深度学习(一)--deepNN模型实现摄像头实时识别人脸表情(C++和python3.6混合编程).由于上一篇文章的模型所采用的数据集为fer2013,前 ...

  3. 【人脸表情识别】基于图片的人脸表情识别,基本概念和数据集

    大家好,欢迎来到我们人脸表情识别的专栏,这是专栏的第一篇文章,今天我们讨论的问题是关于表情识别的基本概念和数据集. 作者&编辑 | Menpinland 在较早之前,有三AI已经有一篇< ...

  4. 【杂谈】从CV小白到人脸表情识别专栏作者,我与有三AI的故事

    各位有三AI的读者朋友大家好呀~我是刚刚更新完结的[人脸表情识别]专栏的作者,一名仍然在读的研究生.在分享完我的专栏内容后,分享一下我这枚CV小白与有三 AI 的故事. 认识有三AI 我本科的专业是软 ...

  5. 【完结】如何掌握基于图像和视频的人脸表情识别,这9篇文章可以作为一个参考...

    文/编辑 | 言有三 人脸表情识别(Facial Expression Recognition,FER)作为人脸识别技术中的一个重要组成部分,近年来在人机交互.安全.机器人制造.自动化.医疗.通信和驾 ...

  6. 【人脸表情识别】情绪识别相关会议、比赛汇总(2018-2020)

    前面专栏中,我们介绍了有关基于图片/视频的人脸表情识别的相关内容,也了解了通过回归的方式来理解表情的方式--基于连续模型的人脸表情识别.在专栏的最后一篇文章中,我们将分享计算机视觉领域中围绕情绪识别主 ...

  7. 基于卷积神经网络的人脸表情识别应用--AR川剧变脸(一)

    1.摘要 本项目将在Android上实现一种通过识别表情类别,从而给人脸戴上不同样式脸谱的AR软件,效果如下: 基于表情识别的脸谱换脸AR安卓APP效果演示 通过深度学习和Keras训练一个人脸表情识 ...

  8. 【人脸表情识别】基于回归模型的人脸表情识别方法

    前面几篇专栏中,我们介绍了有关基于图片/视频的人脸表情识别的相关内容,这两个领域采用解决分类问题的方法来对表情进行识别.这篇文章,我们将介绍通过回归的方式来理解表情的方式--基于连续模型的人脸表情识别 ...

  9. 【人脸表情识别】如何做好表情识别任务的图片预处理工作

    上一篇专栏文章中,我们介绍了人脸表情识别的相关概念以及研究现状并了解了目前基于图片的人脸表情识别领域最常用的几个数据集.本文将介绍基于图片的人脸表情识别中最常用的预处理方式和对应的方法. 作者& ...

最新文章

  1. 国际财务报告准则 IFRS 与信息系统
  2. git远程仓库和分支
  3. 观察者模式重复调用mysql问题,2、观察者模式
  4. C语言博客作业05--指针
  5. ruby sinatra mysql_一分钟开始持续集成之旅系列之:Ruby + Sinatra 应用
  6. linux邮件加密码,linux系统的邮件服务器的加密与验证
  7. 《Linux命令行与shell脚本编程大全》第十二章 使用结构化命令
  8. 接地气的大数据来了:如何预报雾霾
  9. beini安装破*WIFI
  10. 微信小程序云开发——打卡小程序
  11. 全球最顶级的十大创新公司
  12. PHP 获取客户端的真实IP
  13. Charles 限制网络速度(Throttle设置)
  14. 进程通信实例之父子进程通信
  15. thinkpad硬件测试软件,Lenovo Diagnostics Windows(联想硬件诊断工具)
  16. commvault备份mysql数据库_2-CommVault备份项目实施方案-XXXX.docx
  17. 小学6年级之圆锥体积公式
  18. 潘超和你聊 DeFi
  19. mysql触发器联立删除_mysql触发器删除实例1
  20. IE调试网页之六:使用 F12 开发人员工具调试 HTML 和 CSS (Windows)

热门文章

  1. 云计算/边缘计算/雾计算
  2. 即时通讯软件,专注于企业信息安全可靠的企业IM
  3. 两台计算机共享公文包,公文包怎么共享,给其它电脑使用_公文包什么人使用
  4. WINCE 注册表编辑器
  5. IPO(INPUT PROCESS OUTPUT)图
  6. 洗地机最好的品牌有哪些、智能家居品牌排行
  7. Scaled dot-product Attention、Self-Attention辨析
  8. 李永乐数学基础过关660题高等数学填空题
  9. sitemap网站地图提交工具1.0
  10. 【java并发】AQS中acquire方法解析