第15课:Tensorflow人脸识别实战之人脸数据录入

在这里我们主要用简单的CNN神经网络来训练数据

人脸的一些操作,主要通过使用dlib来完成,dlib的使用又依赖opencv,所以这两个module都要安装

也可以单独使用opencv来识别人脸,在实际使用过程中,dlib的识别效果比opencv的好,但opencv识别的速度会快很多,获取10000张人脸照片的情况下,dlib大约花费了1小时,而opencv的花费时间大概只有20分钟。opencv可能会识别一些奇怪的部分,所以综合考虑之后我使用了dlib来识别人脸


Dlib安装步骤:
1.安装依赖包 pip install boost  opencv也要安装
2.下载dlib 下载地址:https://pypi.python.org/pypi/dlib/19.6.0
    安装 pip install whl文件路径  
当然了,也可以直接用pip install dlib安装,不过可能大部分人会出错哦

mac下安装稍微麻烦点,但是步骤1还是相同的,都是先安装依赖包
如果没有装cmake还要pip install cmake
然后git clone https://github.com/davisking/dlib.git
cd dlib/examples
mkdir build
cd build
cmake .. 
cmake --build . --config Release
安装python模块
cd dlib
sudo python setup.py install

然后pip list看下有没有dlib


会用到opencv,这里有坑,运行时报错:
OpenCV Error: Unspecified error (The function is not implemented. Rebuild the library with Windows, GTK+ 2.x or Carbon support. If you are on Ubuntu or Debian, install libgtk2.0-dev and pkg-config, then re-run cmake or configure script) in cvShowImage

mac解决方法:
Brew install pkg-config
GTK安装:
https://www.gtk.org/download/macos.php

Sklearn如果版本低,也是会报错的,解决方法很简单 pip install -U sklearn

安装好环境之后,我们就开始获取数据了
1.先录入自己脸的数据
# -- coding: utf-8 --
import cv2
import dlib
import os
import sys
import random

output_dir = './my_faces'
size = 64

if not os.path.exists(output_dir):
    os.makedirs(output_dir)

#改变图片的亮度与对比度
def relight(img, light=1, bias=0):
    w = img.shape[1]
    h = img.shape[0]
    #image = []
    for i in range(0,w):
        for j in range(0,h):
            for c in range(3):
                tmp = int(img[j,i,c]*light + bias)
                if tmp > 255:
                    tmp = 255
                elif tmp < 0:
                    tmp = 0
                img[j,i,c] = tmp
    return img

#使用dlib自带的frontal_face_detector作为我们的特征提取器,进行人脸矩形框的提取
detector = dlib.get_frontal_face_detector()
# 打开摄像头 参数为输入流,可以为摄像头或视频文件
# OpenCV读取视频, 获得视频的格式, 读取视频的每一帧, 播放控制; 使用VideoCapture类和read()函数;
#
# 获取视频属性(码率\尺寸)使用VideoCapture的get()方法;
#
# "avi"是所有系统都会支持的视频格式;
#
# OpenCV写视频, 需要指定视频的格式, 可以从原视频中获取; 使用VideoWriter类和write()函数
#
# VideoWriter类写入视频时, 需要提供视频名, 格式, 码率(fps), 帧的尺寸等参数;
camera = cv2.VideoCapture(0)

index = 1
while True:
    #if (index <= 10000):
    if (index <= 200):
        print('Being processed picture %s' % index)
        # 从摄像头读取照片
        success, img = camera.read()
        # 转为灰度图片
        gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        # 使用detector进行人脸检测
        dets = detector(gray_img, 1)

        for i, d in enumerate(dets): #enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中
            x1 = d.top() if d.top() > 0 else 0
            y1 = d.bottom() if d.bottom() > 0 else 0
            x2 = d.left() if d.left() > 0 else 0
            y2 = d.right() if d.right() > 0 else 0

            face = img[x1:y1,x2:y2]
            # 调整图片的对比度与亮度,对比度与亮度值都取随机数,这样能增加样本的多样性
            face = relight(face, random.uniform(0.5, 1.5), random.randint(-50, 50))

            face = cv2.resize(face, (size,size))#图片缩放
            cv2.imshow('image', face)#显示face缩略图
            cv2.imwrite(output_dir+'/'+str(index)+'.jpg', face)#文件写入对应目录
            index += 1
        key = cv2.waitKey(30) & 0xff #waitKey()函数的功能是不断刷新图像,频率时间为delay,单位为ms,返回值为当前键盘按键值。
        if key == 27:
            break
    else:
        print('Finished!')
        break

2.再录入其他人脸
# -- coding: utf-8 --
import sys
import os
import cv2
import dlib

input_dir = './input_img'
output_dir = './other_faces'
size = 64

if not os.path.exists(output_dir):
    os.makedirs(output_dir)

#使用dlib自带的frontal_face_detector作为我们的特征提取器
detector = dlib.get_frontal_face_detector()

index = 1
for (path, dirnames, filenames) in os.walk(input_dir):
    for filename in filenames:
        if filename.endswith('.jpg'):
            print('Being processed picture %s' % index)
            img_path = path+'/'+filename
            # 从文件读取图片
            img = cv2.imread(img_path)
            # 转为灰度图片
            gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            # 使用detector进行人脸检测 dets为返回的结果
            dets = detector(gray_img, 1)

            #使用enumerate 函数遍历序列中的元素以及它们的下标
            #下标i即为人脸序号
            #left:人脸左边距离图片左边界的距离 ;right:人脸右边距离图片左边界的距离 
            #top:人脸上边距离图片上边界的距离 ;bottom:人脸下边距离图片上边界的距离
            for i, d in enumerate(dets):
                x1 = d.top() if d.top() > 0 else 0
                y1 = d.bottom() if d.bottom() > 0 else 0
                x2 = d.left() if d.left() > 0 else 0
                y2 = d.right() if d.right() > 0 else 0
                # img[y:y+h,x:x+w]
                face = img[x1:y1,x2:y2]
                # 调整图片的尺寸
                face = cv2.resize(face, (size,size))
                cv2.imshow('image',face)
                # 保存图片
                cv2.imwrite(output_dir+'/'+str(index)+'.jpg', face)
                index += 1

            key = cv2.waitKey(30) & 0xff
            if key == 27:
                sys.exit(0)