CNN人脸识别项目(dlib+opencv)

CNN人脸识别

思路:一个CNN人脸识别项目首先必不可少的是数据集,获取的方式有网站数据库
PubFig:Public Figures Face Database、Large-scale CelebFaces Attribtes(CelebA) Dataset、BioID Face Database-FaceDB、YouTube Face

等待网站,或者抓取网页上的图片,根据需要对图片进行预处理。

[En]

Wait for the website, or grab the image on the web page and preprocess the image according to the demand.

然后是建立一个model用于训练数据集,根据精度大小判断网络模型的好坏

最后,选择一张或一批图片进行测试和可视化。

[En]

Finally, select a picture or a batch of pictures to test and visualize them.

获取数据集

这里首先以PubFig:Public Figures Face Database网站的数据集格式进行讲解,然后再选取自己的图片进行替换即可,不要问为什么不自己弄,一是拿来主义多好理解就行,而是人家是多少团队搞出来的肯定比自己制定的标准吧
开始正文:
在网站下载的数据集包括person Name.txt和url.txt两个文件,person Name.txt用于存储所有人脸图像的名字,类似标签文本,url.txt文件则包括人名、图片序号、URL地址、人脸坐标和MD5校验码

CNN人脸识别项目(dlib+opencv)
CNN人脸识别项目(dlib+opencv)

现在就需要对数据集进行处理了,因为网络模型需要的是标签和图像,标签有了,图像需要我们根据url.txt中的URl地址进行抓取了,然后将抓取的图像进行分类,根据不同人名建立文件夹进行存储获取到原始图片newddata,但是训练模型要求的其实人脸,所以还需要在原始图片上截取人脸,因为url.txt已经含有截取后的人脸坐标直接进行读取得到cutdata

CNN人脸识别项目(dlib+opencv)

cutdata

CNN人脸识别项目(dlib+opencv)

newdata 具体代码如下:

from urllib.request import urlretrieve
from urllib import request
from PIL import Image
import requests
import urllib
import socket
import re
import cv2
import os
import time
import random
import datetime

def get_headers():
    '''
    随机获取一个headers
    '''
    user_agents = [
                    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.3578.80 Safari/537.36',
                    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36',
                    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36',
                    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36'
                    ]
    headers = ('User-Agent', random.choice(user_agents))
    print(headers)
    return headers

headers = ("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36")

proxy_addr = "138.197.196.222"
post = '13499'

proxy = urllib.request.ProxyHandler({'http':(proxy_addr + ':' + post)})

opener = request.build_opener()

opener.addheaders = [headers]

request.install_opener(opener)

timeout = 10000
socket.setdefaulttimeout(timeout)

def callbackfunc(blocknum, blocksize, totalsize):
    '''回调函数
    @blocknum: 已经下载的数据块
    @blocksize: 数据块的大小
    @totalsize: 远程文件的大小
    '''
    time_stamp = datetime.datetime.now()
    percent = 100.0 * blocknum * blocksize / totalsize
    if percent > 100 or percent < 0 :
        percent = 100
    print("已完成:%.2f%%" % percent + "     " + time_stamp.strftime('%Y.%m.%d-%H:%M:%S'))

pic_data = []
with open('ch09\9 FaceRecognition\src\Preunder\data/url.txt') as f:
    for i in f.readlines():
        pic_data.append(i.strip('\r\n'))

new_data = []
for data in pic_data:
    if len(data.split()) == 6:
        name, surname, _, url, coord, _ = data.split()
        new_data.append(name + ' ' + surname + ' ' + url + ' ' + coord)

with open('ch09\9 FaceRecognition\src\Preunder\data/urlAdd.data', 'w') as f:
    for i in new_data:
        f.write(i)
        f.write('\n')

pic_data = []
with open('ch09\9 FaceRecognition\src\Preunder\data/urlAdd.data') as f:
    for i in f.readlines():
        pic_data.append(i.strip('\r\n'))

names = []
with open('ch09\9 FaceRecognition\src\Preunder\data/personName.txt') as f:
    for i in f.readlines():
        names.append(i.strip('\r\n'))

num = 0
sucess = 0
for name in names:

    if os.path.exists('../Preunder/data/newdata/' + name) == False:

        os.mkdir('D:\wendang/vscode\CV/face_opencv\ch09\9 FaceRecognition\src\Preunder\data/newdata/' + name)

    if os.path.exists('../Preunder/data/middata/' + name) == False:

        os.mkdir('D:\wendang/vscode\CV/face_opencv\ch09\9 FaceRecognition\src\Preunder\data\middata/' + name)

    if os.path.exists('../Preunder/data/cutdata/' + name) == False:

        os.mkdir('D:\wendang/vscode\CV/face_opencv\ch09\9 FaceRecognition\src\Preunder\data\cutdata/' + name)

    count = 200
    for data in pic_data:
        pname, surname, url, coord = data.split()
        url = str(url)
        coords = []
        coords = coord.split(',')

        if pname == name.split()[0] and surname == name.split()[1]:

            print('name:' + pname + ' ' + surname + '           count:%d' %(count-200))

            try:

                print(url)
                time_stamp = datetime.datetime.now()
                print("当前时间:" + time_stamp.strftime('%Y.%m.%d-%H:%M:%S'))

                print('saving.......')

                pic = urlretrieve(url=url, filename='../Preunder/data/newdata/' + name + '/%d.jpg' % count, reporthook=callbackfunc)

                print(pname + ' ' + surname + ': picture %d' %(count - 200))

                print('cuting.......')
                image = Image.open('../Preunder/data/newdata/' + name + '/%d.jpg' % count)

                img = image.crop((int(coords[0]), int(coords[1]), int(coords[2]), int(coords[3])))
                img.save('../Preunder/data/middata/' + name + '/%d.jpg' % count)

                faceimage = cv2.imread('../Preunder/data/middata/' + name + '/%d.jpg' % count)

                '''
                                    经过测试后得到脸部数据均小于128*128,
                                    所以暂时把灰度化和脸部截取统一大小改为后期进行或修改大小:64*64
                '''

                sp = faceimage.shape
                print('recuting.......')
                if sp[0] > 128 and sp[1] > 128:
                    gray = cv2.cvtColor(faceimage, cv2.COLOR_BGR2GRAY)
                    face = cv2.resize(gray, (128, 128), interpolation=cv2.INTER_CUBIC)
                    cv2.imwrite('../Preunder/data/cutdata/' + name + '/%d.jpg' % count, face)
                    print('save cutPic.......')
                else:
                    print("图片尺寸太小")
                sucess += 1
                count += 1

            except Exception as e:
                print(Exception, ':', e)
                num += 1

                post = random.randint(139, 16000)
                proxy = urllib.request.ProxyHandler({'http':(proxy_addr + ':' + str(post))})
                opener = request.build_opener()

                opener.addheaders = [get_headers()]

                request.install_opener(opener)
        else:
            count = 200

    print('采集对象  =====>>%s 成功次数:%d , 失败次数:%d' % (name, sucess, num))

if __name__ == '__main__':
    get_headers()

以上代码看似很多其实很多是为了可视化美观,真正内容就根据url.txt图片url是抓取图片、建立人名文件夹放入对应图片,并根据url.txt人脸坐标信息将人脸图片同样放到人名文件里得到训练集图片

如果训练自己的图片数据集可以按照以上格式先建立相应的原始图片文件夹,然后利用dlib框架来检测人脸得到每个人名的人脸图片

首先读取自己设置的所有的原始图片newdata到列表里
这里的读取图片的前提是已经建立newdata文件夹,且里面包含不同人名的子文件夹,每个文件夹包含对应人名的原始图片,且每次只能读取一个人名类别的所有图片,如果想一次性读取所有人名类别的文件夹则需要优化部分代码

import os
import cv2

def readAllImg(path,*suffix):
    try:

        s = os.listdir(path)
        resultArray = []
        fileName = os.path.basename(path)
        resultArray.append(fileName)

        for i in s:
            if endwith(i, *suffix):
                document = os.path.join(path, i)
                img = cv2.imread(document)
                resultArray.append(img)

    except IOError:
        print("读取失败!")

    else:
        print("读取成功!")
        return resultArray

def endwith(s,*endstring):
    resultArray = map(s.endswith,endstring)

    return resultArray

if __name__ == '__main__':

    result = readAllImg("ch09\shuju\LeiFeng_",'.jpg')
    print (result[0])
    cv2.namedWindow("Image")
    cv2.imshow("Image", result[1])
    cv2.waitKey(0)
    cv2.destroyAllWindows()

然后对图片检测人脸得到图片放入cutdata文件

import os
import cv2
import dlib
import time
from readImage import readAllImg

def readPicSaveFace(sourcePath,objectPath,*suffix):
    try:

        resultArray=readAllImg(sourcePath,*suffix)

        count = 1

        detector = dlib.get_frontal_face_detector()
        for i in resultArray:
            if type(i) != str:
                gray = cv2.cvtColor(i, cv2.COLOR_BGR2GRAY)

                dets = detector(gray, 1)
                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
                    listStr = [str(int(time.time())), str(count)]
                    fileName = ''.join(listStr)

                    f = cv2.resize(gray[x1:y1, x2:y2], (128, 128))
                    cv2.imwrite(objectPath+os.sep+'%s.jpg' % fileName, f)
                    count += 1

    except IOError:
        print("Error")

    else:
        print('Already read '+str(count-1)+' Faces to Destination '+objectPath)

if __name__ == '__main__':

    readPicSaveFace('ch09\shuju\LeiFeng',
                    'ch09\shuju\LeiFeng_',
                    '.jpg','.JPG','png','PNG')

读取数据集

将制定好的不同人名文件夹存储不同的人脸gray图片(128*128大小)读取文件名也就是人名作为标签和人脸图像作为数据

import os
import cv2
import numpy as np

from readImage import endwith

def readFile(path):
    img_list = []
    label_list = []
    dir_counter = 0
    IMG_SIZE = 128

    for child_dir in os.listdir(path):
        child_path = os.path.join(path, child_dir)

        for dir_image in  os.listdir(child_path):
            if endwith(dir_image,'jpg','JPG','png','PNG'):
                img = cv2.imread(os.path.join(child_path, dir_image))
                cv2image = cv2.cvtColor(img, cv2.COLOR_BGR2RGBA)

                recolored_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

                resized_img = cv2.resize(recolored_img, (IMG_SIZE, IMG_SIZE))
                img_list.append(resized_img)
                label_list.append(dir_counter)

        dir_counter += 1

    img_list = np.array(img_list)

    return img_list,label_list,dir_counter

def readNameList(path):
    nameList = []
    for child_dir in os.listdir(path):
        nameList.append(child_dir)
    return nameList

if __name__ == '__main__':
    img_list,label_list,counter = readFile('ch09\9 FaceRecognition\images')
    print(label_list)

数据预处理

将读取到的label与imgs、类别数继进行预处理
也即train_test_split划分数据集 ,对图片进行归一化,对标签进行二进制化

from readData import readFile
from sklearn.model_selection import train_test_split
from keras.utils import np_utils
import random

import keras.backend as K

class modelDataSet(object):

    def __init__(self,path):
        self.num_classes = None
        self.X_train = None
        self.X_test = None
        self.Y_train = None
        self.Y_test = None
        self.img_size = 128
        self.extract_data(path)

    def extract_data(self,path):

        imgs,labels,counter = readFile(path)

        X_train,X_test,y_train,y_test = train_test_split(imgs,labels,test_size=0.2,random_state=random.randint(0, 100))

        if K.image_data_format() == 'channels_first':

            X_train = X_train.reshape(X_train.shape[0], 1, self.img_size, self.img_size)/255.0
            X_test = X_test.reshape(X_test.shape[0], 1, self.img_size, self.img_size) / 255.0
        else:

            X_train = X_train.reshape(X_train.shape[0], self.img_size, self.img_size, 1)/255
            X_test = X_test.reshape(X_test.shape[0], self.img_size, self.img_size, 1)/255

        X_train = X_train.astype('float32')
        X_test = X_test.astype('float32')

        Y_train = np_utils.to_categorical(y_train, num_classes=counter)
        Y_test = np_utils.to_categorical(y_test, num_classes=counter)

        self.X_train = X_train
        self.X_test = X_test
        self.Y_train = Y_train
        self.Y_test = Y_test
        self.num_classes = counter

    def check(self):
        print('num of dim:', self.X_test.ndim)
        print('shape:', self.X_test.shape)
        print('size:', self.X_test.size)

        print('num of dim:', self.X_train.ndim)
        print('shape:', self.X_train.shape)
        print('size:', self.X_train.size)

建立模型进行预训练

from modelDataSet import modelDataSet
from keras.models import Sequential,load_model
from keras.layers import Dense,Activation,Conv2D,MaxPooling2D,Flatten,Dropout
from keras.optimizers import *
import numpy as np

class trainFaceModel(object):
    FILE_PATH = "ch09\9 FaceRecognition\image\model/model1.h5"
    IMAGE_SIZE = 128

    def __init__(self):
        self.model = None

    def read_trainData(self,modeldataset):
        self.modeldataset = modeldataset

    def build_model(self):

        self.model = Sequential()

        self.model.add(
            Conv2D(
                filters=64,
                kernel_size=(4, 4),
                padding='same',

                input_shape=self.modeldataset.X_train.shape[1:]
            )
        )
        self.model.add(Activation('relu'))
        self.model.add(
            MaxPooling2D(
                pool_size=(2, 2),
                strides=(2, 2),
                padding='same'
            )
        )

        self.model.add(
            Conv2D(
                filters=128,
                kernel_size=(4, 4),
                padding='same')
            )
        self.model.add(Activation('relu'))
        self.model.add(MaxPooling2D(
            pool_size=(2, 2),
            strides=(2, 2),
            padding='same'
            )
        )

        self.model.add(Flatten())

        self.model.add(Dense(2048))
        self.model.add(Activation('relu'))

        self.model.add(Dense(self.modeldataset.num_classes))

        self.model.add(Activation('softmax'))
        self.model.summary()

    def train_model(self):

        self.model.compile(
            optimizer='adam',

            loss='categorical_crossentropy',
            metrics=['accuracy'])

        self.model.fit(self.modeldataset.X_train,self.modeldataset.Y_train,epochs=3,batch_size=10)

    def evaluate_model(self):
        print('\n测试中---------------')
        loss, accuracy = self.model.evaluate(self.modeldataset.X_test, self.modeldataset.Y_test)

        print('测试损失度:', loss)
        print('测试精准度:', accuracy)
        return loss,accuracy

    def save(self, file_path=FILE_PATH):
        print('Model保存.')
        self.model.save(file_path)

    def load(self, file_path=FILE_PATH):
        print('Model加载.')
        self.model = load_model(file_path)

    def predict(self,img):
        img = img.reshape((1, self.IMAGE_SIZE, self.IMAGE_SIZE,1))
        img = img.astype('float32')
        img = img/255.0

        result = self.model.predict_proba(img)
        max_index = np.argmax(result)

        return max_index,result[0][max_index]

if __name__ == '__main__':
    modelDataSet = modelDataSet('ch09\9 FaceRecognition\images')
    model = trainFaceModel()
    model.read_trainData(modelDataSet)
    model.build_model()
    model.train_model()
    model.evaluate_model()
    model.save()

检测并可视化图片的面部

[En]

Detect and visualize the face of the picture

可以对一个图片或者批次的图片进行检测,在人脸检测时可以利用dlib或者opencv的级联检测器都可以这里选择dlib

from readData import readNameList,readFile
from trainFaceModel import trainFaceModel
import dlib
import cv2
detector = dlib.get_frontal_face_detector()
face_cascade = cv2.CascadeClassifier('D:\miniconda\envs\py3.6\Lib\site-packages\cv2\data\haarcascade_frontalface_default.xml')
IMAGE_SIZE = 128

def test_onePicture(path):
    model= trainFaceModel()
    model.load()
    img = cv2.imread(path)

    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    dets = detector(gray, 1)
    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

        ROI = gray[x1:y1, x2:y2]
        ROI = cv2.resize(ROI, (IMAGE_SIZE, IMAGE_SIZE), interpolation=cv2.INTER_LINEAR)
        label,prob = model.predict(ROI)
        if prob >0.775:
            name_list = readNameList('ch09\9 FaceRecognition\images')
            print(name_list[label],prob)
            cv2.putText(img, name_list[label]+":"+str(prob), (x2, x1), cv2.FONT_HERSHEY_SIMPLEX, 1, (150, 200, 56), 2)
            cv2.rectangle(img, (x2, x1), (y2, y1), (150, 200, 56), 2)
        else:
            print("无法识别此人!")

    cv2.imshow('Image', img)
    cv2.waitKey(0) & 0xff
    cv2.destroyAllWindows()

def test_onBatch(path):
    model= trainFaceModel()
    model.load()
    index = 0
    img_list, label_list, counter = readFile(path)
    for img in img_list:
        picType,prob = model.predict(img)
        if picType != -1:
            index += 1
            name_list = readNameList('ch09\9 FaceRecognition\images')
            print(name_list[picType])
        else:
            print("无法识别此人!")

    return index

if __name__ == '__main__':
    test_onePicture('ch09\shuju/testima\LeiFengTest.jpg')

运行结果得到

CNN人脸识别项目(dlib+opencv)

总结

总体设计思想可以用以下流程图来表示

[En]

The overall design idea can be represented by the following flow chart

CNN人脸识别项目(dlib+opencv)

Original: https://blog.csdn.net/m0_47709941/article/details/123800895
Author: 古月哥欠666
Title: CNN人脸识别项目(dlib+opencv)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/496919/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球