【Python+OpenCV+sklearn+easygui】人脸(口罩)识别+口罩下人脸补全的系统设计

【写在前面:笔者是一个才接触python半年之久的编程菜鸡,刚好这学期的课程需要用到python做一些有关计算机视觉的设计,于是就根据自己所学,同时借鉴了一些CSDN上各位大佬的思路和代码,做了一个简单的涉及人脸识别,口罩识别,口罩下人脸预测的小系统。一是作为学习记录,二是希望对大家有点帮助,对于不足之处,也希望各路大佬可以不吝赐教。本文为作者原创文章,文中所示的图片、代码皆来自网络或笔者自制,仅做学习、记录使用,如果某些东西涉及侵权,请作者大大告知笔者,可以对此进行补充说明。如有人私自引入商业使用构成侵权或违法犯罪,则笔者概不负责。】

完整代码在文章后面有
源文件:
1、(代币充足的老板麻烦点这个,赏个代币,谢谢谢谢老板!!!!)CSDN下载地址
2、(像我一样没币的就百度盘吧,哭了…)百度网盘 提取码:gno7
3、 GitHub等以后有机会再传吧

一、先看一下实现的核心效果

首先是UI交互界面,本来想用个HTML做的,但是由于HTML与python的交互过于复杂,时间不大够,所以最后就做了个简单的。效果如下
在这里插入图片描述
人脸识别部分的实现情况比较正常,用opencv库提供的xml,实现情况如下
在这里插入图片描述
口罩识别则用的博主Cheney-渣渣杰训练出来的xml,效果如下
在这里插入图片描述
最后就是口罩预测部分,效果如下
在这里插入图片描述

二、原理介绍

2.1人脸识别

人脸识别是计算机视觉中一个相对完整的模块,基本上所有学习计算机视觉的课程都会涉及到人脸识别这块的内容。在百度百科中是这么定义的:人脸识别,是基于人的脸部特征信息进行身份识别的一种生物识别技术。用摄像机或摄像头采集含有人脸的图像或视频流,并自动在图像中检测和跟踪人脸,进而对检测到的人脸进行脸部识别的一系列相关技术,通常也叫做人像识别、面部识别。

简单来说,这就是图像识别的一个部分,利用图像差值等图像处理的方法,对具有特定特征的图像进行提取,然后再将这些特征信息保存好,在需要的时候,就可以调用该文件中保存好的训练特征,对目标图像进行匹配,从而找出在图像中我们所需要的特征。就比如在这个系统中的人脸。

具体的算法和方程在此我就不写了,大家找找文献和博客应该有很多很详细的方法介绍。

然后在这个系统中,主要是用博主柒澈言写的人脸识别之笑脸检测中的代码为主体框架搭建的。细节之处再根据具体需求具体改。

2.2口罩识别

口罩识别的具体方法同人脸识别大抵相同。这个系统中用的是博主Cheney-渣渣杰训练出来的数据,用起来效果一般,从他的博文中也可以看到,由于也是今年疫情这种大环境下的突发奇想,所以训练的数据量并不算很大,导致最终识别口罩时稍微有一点不灵敏。不过还是很感谢他的分享(至少不用我自己练数据了嘿嘿),用来做个作业够用了。详细的情况可以去他的博客看看。对识别精度有要求的朋友建议另找一下其他训练数据。

然而对于口罩识别这块的实现,最初我是想了两种解决方法的,第一是能够直接找到这种训练好的数据自然是最好的,实在不行自己训练就比较麻烦。第二是识别眼睛,直接使用opencv中开源出来的文件,去识别眼睛,然后在画框的时候画多一点就好了。

但是经过测试,opencv中开源的文件去识别眼睛、额头等都识别的不算好(好吧个人觉得识别效果巨烂),且如果用这个逻辑去写,会出现两个问题。其一是识别精度不高,容易产生误判,这没什么好说的,精度问题;其二是说不定只是露个眼睛出来,然后被识别到了判定成戴口罩,这就会带来两个结果,好的地方是,如果识别精度够高,我们只需要很少的特征就可以判定这个是不是人,且判断是否为全脸(用于后期补全),不好的地方则是,误判几率会很大,比如给个侧脸,识别到了眼睛,然后就被判定为带口罩了。

所以综合考虑,第一种方法的时间复杂度比较小,难度也比较小(找到了训练好的数据简直不能更舒服),所以选择执行第一种方案。

2.3人脸补全

人脸补全这一块用的是python中的sklearn库,可以说是数据处理中的一个经典库。

其主要原理就是机器学习,机器学习分为有监督学习和无监督学习,人脸补全是属于有监督学习的一种(上面说的识别应该也是监督学习的一种)。具体公式性的算法解释我也不在这写了,网上资料蛮全的。

实现思路大概是这样的,由于人在带上口罩后也就遮住了鼻子往下的部分,大致上可以看成是上下对半开的脸,上半部分露出来,下半部分被挡住。这样一来,我们就可以用人脸补全的方法进行补全。首先用原始图像训练模型,然后将识别出来的戴口罩的人脸图像截出来,将图像规格修改成训练图像相同的图像,然后代回到模型中进行预测就可以了,其大致流程与网络毒刘的这篇文章基本一致,这套代码基本上算是满大街都是了,是很经典的一个机器学习的例子。所以在笔者设计的这个系统中,将其稍加修改就可以用来预测人脸了。

2.4交互界面

这个部分算是整个系统中最简单的一个部分,直接调用easygui库就可以了。使用起来也很简单,一行代码搞定,不得不说Life is short,use python诚不欺我。

三、系统实现过程中的思考和遇到的问题

首先附上流程草图(时间不够,只完成了一条线,后续部分以后有时间再补)
在这里插入图片描述

3.1是否戴口罩的判定问题

按照正常的逻辑来讲,这一步只需要一个if结构就可以了,但是在实际实现的过程中,笔者发现opencv的识别人脸能力太强,而口罩识别的识别能力太弱。即有时候会出现戴口罩的人能被人脸识别识别到但口罩识别无反应的情况,或者两个识别同时生效的情况。这样,就会导致如果简单用一个if进行判定,极其容易就造成误判。

笔者认为这里可能的原因有几个:

1、笔者的人脸识别用错了文件。在设计中,笔者对比过opencv开源的人脸特征识别中几个文件的识别情况,有好有坏,最终由于haarcascade_frontalface_default.xml文件的识别效果较好,所以用了这个文件。可能在这个训练集中,就是可以识别口罩的。由于缺乏具体测试,所以笔者也没办法证明这一点。

2、口罩识别的训练模型精度尚缺。如同前文所述,该口罩识别的模型用的是网友提供的模型,在其博文中也提到了,训练的图片数量不算特别多,且图片素材均是在网上找的。所以其精度不高也是情理之中、预料之内的。作为作业来说足以,无可厚非。

3.2人脸补全时的问题

这个问题算是整个系统中问题最大的地方。一开始想用的是sklearn中提供的人脸数据,仿照那个上半张脸预测下半张脸的程序去做,然后将训练好的模型保存,再在系统设计中调用就好了。但是总会遇到特征不符合的情况。报出如(ValueError: query data dimension must match training data dimension)这类的错误。接下来说一下人脸补全的过程和笔者的解决方法。

3.2.1人脸补全的详细过程

导包不说了,能看到这里的朋友应该不至于导包出问题。第一步是导入数据,这里的数据无论是自己输入还是从sklearn上调用,都是数组类型的数据,在sklearn上的人脸数据,是400组的64x64的彩色数据。对于彩色图像,即RGB图像,其数据是像下面写的三维数组的形式(例为64x64x3的三维数组)

[[[174 174 174]
[165 165 165]
[123 123 123]

[156 156 156]
[167 167 167]
[167 167 167]]

[[ 41 41 41]
[ 46 46 46]
[ 59 59 59]

[ 37 37 37]
[ 49 49 49]
[ 58 58 58]]]

利用cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)对图像进行降维处理,将会使得彩色的图像降成灰度图像,即三维数组降成二维数组,其数据形式如下所示(例为64x64的二维数组)

[[174 165 123 … 156 167 167]
[176 173 111 … 152 164 172]
[174 139 104 … 148 169 163]

[ 43 55 57 … 37 47 45]
[ 32 49 53 … 45 41 53]
[ 41 46 59 … 37 49 58]]

其中具体的降维算法这里就不细说了,可以查得到,基本上我们知道其数据形式是怎么样的就足够了。

降维之后,我们需要将数据进行切分,这里将数据切分成了上下两个部分,由于这里用的是64x64的数据,所以将直接用行切片即可。

X = data[:,:32].reshape(400,-1)   #上半张脸
y = data[:,32:].reshape(400,-1)   #下半张脸

由于sklearn中的是400个图像,所以这里将整体切片(data是400x64x64的三维数组),然后将图像reshape成一个400行2048(32x64)列的二维数组。如下所示

[[0.30991736 0.3677686 0.41735536 … 0.61157024 0.59917355 0.55785125]
[0.45454547 0.47107437 0.5123967 … 0.18181819 0.18181819 0.18181819]
[0.3181818 0.40082645 0.49173555 … 0.5785124 0.58264464 0.58677685]

[0.5 0.53305787 0.607438 … 0.42975205 0.4338843 0.446281 ]
[0.21487603 0.21900827 0.21900827 … 0.74380165 0.7355372 0.7066116 ]
[0.5165289 0.46280992 0.28099173 … 0.6528926 0.59090906 0.57438016]]

这样一来我们只需要根据index去抽取数据进行训练(fit)、预测(predict)就可以了。值得注意的是:这里无论是训练还是预测,都是以1行2048列的二维数组的形式传入,如果不是二维数组,就是发生上文写到的特征不匹配的问题。 只要注意好这个问题,其他的东西就直接跟着例子来就可以了。

3.2.2人脸补全过程中的问题及选择

由于人脸补全这块有很多种回归方法可以使用,所以首先对比了一下各种回归方法的效果,其中的参数按默认的来,效果如下
在这里插入图片描述
如上图所示,可以看出,KNN、岭回归、决策树的预测效果相对来说较好,但是由于岭回归的时间复杂度会相对较高(好吧也不尽然是,主要是当时岭回归的时候数据报错,我以为是回归出问题了,换了个回归试试,后面也没换回来),决策树的方式出现了两个一模一样的预测(第五行和第九行,可能是决策树原理的问题)。所以最终选择了KNN作为回归方法。

为了调整KNN中n_neighbor的系数,笔者做了以下的对比图
在这里插入图片描述
从图中可以很明显的看出当n_neighbor的系数为1时预测的效果比较好。所以系数敲定为1。

由于最初出现数据特征不匹配的问题,考虑到sklearn上提供的人脸图片数据无法获取(好吧其实是当时没想到怎么获取,print一下就可以了),所以最后选择自己在百度上下载图片然后进行数据训练。结果如下图所示
在这里插入图片描述
(别骂了别骂了,我知道预测图片是真的丑…)

这个训练结果是利用已经做好的人脸识别程序扣出其中的可被识别的人脸部分,将图片降为二维(灰度图),图片大小统一控制成64x64像素,保存到output文件夹中,如图所示,再人为剔除一些劣质头像图,得到的最原始的140张可训练的图像。其原图和处理后的图像分别如下所示
在这里插入图片描述
在这里插入图片描述
由于数据量才140份,最后成功导入python进行训练的数据才120份,所以才会得到上面哪样的歪瓜裂枣的结果,但是总的来说并不碍事,至少最终口罩预测出来的结果不算太离谱(如第一部分所示)

在这个系统中,笔者用的方法比较笨(因为最开始出问题了,为了完成不择手段),是将目标图像的上半脸append到整个数据组中,在共121份数据中,切前120份作为训练组,最后一个,即目标图像作为预测组进行预测。这样做的结果就是这个系统做出来的效果。当然也可以将训练好的模型包保存,最后再调用predict就好了。在源文件的cascades文件夹中也有几个用sklearn训练好的模型,有需要的朋友可以下载调用。由于最后的结果都差不多,所以在这个系统中我就没有改代码了,就直接用这种笨方法完成了系统。

3.3交互界面的问题

在交互上,最初我想的是用HTML+python的方法去做,这样可用css使得交互页面更加美观,也可以用js提升交互体验,不像现在这样操作过分简单。但是在查阅了相关资料后发现,HTML与Python的交互目前是比较差的,没有什么方法可以直接让数据在HTML和Python中进行交互,可行的方法是将数据保存至本地的txt中,再上传到HTML端或者Python端。然而这种方法对于图片来说实在太过鸡肋,实现起来也相对麻烦和费时,故放弃了这种用HTML作为交互端的方法。

四、总结

  • 从结果上看,在不考虑预测准度的情况下,这个系统还是可以很好的给出一个参考的预测图像的。结合在设计过程中遇到的问题(最开始在切分图像时数据出了很大问题,所以方法换了很多次),笔者认为,假如将sklearn上的训练出的预测模型运用到这里,可能会有更好的预测效果。

  • 在识别口罩中,用的是网友提供的训练模型,由于其训练的图片数量也不算大,所以会经常出现口罩识别失灵的状况,在face文件夹中的数张口罩图片,仅仅能够成功识别一个,这样的识别率无疑太低了一点。且由于opencv提供的人脸识别模型过于强大,所以常常会出现人脸识别成功但是口罩识别失败的问题,导致有些判断结构没办法完成,对于这一点也是可以在后续进一步改进的。

  • 在后续的设计中,只要将原始人脸数据的规模加大,再仔细调整n_neighbors的参数,或者采用其他回归方法进行预测,应该也可以得到更加精细、准确的预测图像。

  • 在图像切分上,由于问题已被解决,所以可以对代码进行优化,使得代码更为美观、简洁。

五、完整代码

注释应该算蛮完整的,应该不难看懂

编译器:pycharm 2019.3.3
opencv-python:4.2.0.34
numpy:1.18.5
scipy:1.4.1
matplotlib:3.2.1
easygui:0.98.1
scikit-learn:0.23.1

1、主程序

import easygui as eg
import cv2
import glob
import numpy as np
import matplotlib.pyplot as plt
from sklearn.neighbors import KNeighborsRegressor

def face_recognition(paths):    #人脸识别函数
    judge = True   #判定是否检测到人脸
    # 人脸检测器
    faceCascade = cv2.CascadeClassifier('./cascades/haarcascade_frontalface_default.xml')
    count=0

    paths = paths.replace('\\','/')  #修改路径中的斜杠,用 \ 在opencv中会报错
    img =cv2.imread(paths)   #读取照片
    gray= cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  #灰度处理

    # 首先检测人脸,返回的是框住人脸的矩形框
    faces = faceCascade.detectMultiScale(
    gray,
    scaleFactor= 1.1,
    minNeighbors=8,
    minSize=(55, 55),
    flags=cv2.CASCADE_SCALE_IMAGE
    )

    # 画出每一个人脸,提取出人脸所在区域
    for (x, y, w, h) in faces:
        cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
        cv2.imshow('Smile%d'%count, img)
        count += 1
        judge = False

    cv2.waitKey(0)
    cv2.destroyAllWindows()
    return judge

def select_path():   #文件路径选择函数
    paths = eg.fileopenbox()
    return paths

def select_module():   #模块选择函数
    module = eg.buttonbox(msg='                                请选择相应的模块', title='摄像测量_识别项目', choices=('人脸识别', '车牌识别', '敬请期待...'),images='6b9140dc984e48589c6a6fe4b0c9317c_th.gif', default_choice=('Button[2]'), cancel_choice=None,callback=None, run=True)
    return module

def camera_face_recognition():  #开摄像头的人脸识别
    cap = cv2.VideoCapture(0)
    eg.msgbox('                                 按q退出摄像头', ok_button='确定')
    while (True):
        # Capture frame-by-frame  逐帧截取
        ret, frame = cap.read()

        # Our operations on the frame come here
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

        xmlfile = r'./cascades/haarcascade_frontalface_default.xml'  #人脸识别mode
        xmlfile_1 = r'./cascades/cascade.xml'   #口罩识别mode

        # 人脸识别
        face_cascade = cv2.CascadeClassifier(xmlfile)
        faces = face_cascade.detectMultiScale(
            gray,
            scaleFactor=1.15,
            minNeighbors=5,
            minSize=(5, 5),
        )

        #框出人脸,绿色框
        for (x, y, w, h) in faces:
            cv2.rectangle(frame, (x, y), (x + w, y + w), (0, 255, 0), 2)

        # 口罩识别
        face_cascade01 = cv2.CascadeClassifier(xmlfile_1)
        faces01 = face_cascade01.detectMultiScale(
            gray,
            scaleFactor=1.15,
            minNeighbors=5,
            minSize=(5, 5),
        )

        #框出口罩,红色框
        for (x, y, w, h) in faces01:
            cv2.rectangle(frame, (x, y), (x + w, y + w), (0, 0, 255), 2)

        cv2.imshow("frame", frame)
        # Display the resulting frame
        if cv2.waitKey(1) & 0xFF == ord('q'):   #按q退出摄像头
            break

    # When everything done, release the capture
    cap.release()
    cv2.destroyAllWindows()

def face_predict(paths):     #人脸预测
    # 人脸检测器
    faceCascade = cv2.CascadeClassifier('./cascades/cascade.xml')

    # paths = glob.glob('./faces/girl4.jpg')
    count = 0

    data_path = glob.glob('./output/*.jpg')
    data_origin = []

    # 总数据,120份
    for i in data_path:
        img = cv2.imread(i)
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        data_origin.append(gray)

    # 写入需要预测的图像
    paths = paths.replace('\\', '/')  # 修改路径中的斜杠,用 \ 在opencv中会报错
    img = cv2.imread(paths)
    # 读取照片
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # 首先检测戴口罩的人脸,返回的是框住人脸的矩形框
    faces = faceCascade.detectMultiScale(
        gray,
        scaleFactor=1.1,
        minNeighbors=8,
        minSize=(55, 55),
        flags=cv2.CASCADE_SCALE_IMAGE
    )

    # 画出每一个人脸,提取出人脸所在区域
    for (x, y, w, h) in faces:
        cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 2)
        # #提取脸部区域
        roi_gray = gray[y:y + h, x:x + w]  # 用于检测笑脸,减少计算量
        roi_test = cv2.resize(roi_gray, (64, 64))
        path_save = './' + str(count) + '.jpg'
        cv2.imwrite(path_save, roi_test)

    data_test = glob.glob(path_save)

    for i in data_test:
        img = cv2.imread(i)
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        data_origin.append(gray)

    data_origin = np.array(data_origin)
    X = data_origin[:, :32].reshape(121, -1)  # 上半张脸
    y = data_origin[:, 32:].reshape(121, -1)  # 下半张脸

    #121组数据中,前120组为训练组,最后一个为预测组,即目标预测对象
    X_train = X[:120, :]
    X_test = X[120:121, :]
    y_train = y[:120, :]
    y_test = y[120:121, :]

    #可尝试加入其它回归进行预测
    estimators = {}
    estimators['predict'] = KNeighborsRegressor(n_neighbors=1)  # KNN算法

    predict_ = {}
    for key, model in estimators.items():
        model.fit(X_train, y_train)
        y_ = model.predict(X_test)  # 根据上半张脸预测下半张脸的数据
        predict_[key] = y_

    # 可视化
    plt.figure(figsize=(3 * 2, 1 * 2))  # 1行3列

    for i in range(1):
        # 第一列  原图
        ax = plt.subplot(1, 3, 1 + 3 * i)
        face_up = X_test.reshape(32, 64)
        face_down = y_test.reshape(32, 64)
        ax.imshow(np.concatenate([face_up, face_down], axis=0), cmap=plt.cm.gray)
        # 如果想去掉刻度 可以用 ax.axis('off')
        if i == 0:
            ax.set_title('Original_image')  # 在第一行添加title

        # 第二列  上半脸
        ax = plt.subplot(1, 3, 2 + 3 * i)
        ax.imshow(face_up, cmap=plt.cm.gray)
        if i == 0:
            ax.set_title('Face_up')

        # 第三列  预测的全脸
        for j, key in enumerate(predict_):
            ax = plt.subplot(1, 3, 3 + j + 3 * i)
            y_ = predict_[key]
            face_down_ = y_.reshape(32, 64)
            ax.imshow(np.concatenate([face_up, face_down_], axis=0), cmap=plt.cm.gray)

            if i == 0:
                ax.set_title(key)
    plt.show()
    # plt.savefig('./预测图.jpg', dpi=500)  # 存图

def mask_recogniton(paths):      #口罩识别
    mask = False
    # 口罩检测器
    faceCascade = cv2.CascadeClassifier('./cascades/cascade.xml')

    # paths = glob.glob('./faces/u=*.jpg')
    count = 0

    paths = paths.replace('\\','/')  #修改路径中的斜杠,用 \ 在opencv中会报错
    img = cv2.imread(paths)
    # 读取照片
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # 首先检测人脸,返回的是框住人脸的矩形框
    faces = faceCascade.detectMultiScale(
        gray,
        scaleFactor=1.1,
        minNeighbors=8,
        minSize=(55, 55),
        flags=cv2.CASCADE_SCALE_IMAGE
    )

    # 画出每一个人脸,提取出人脸所在区域
    for (x, y, w, h) in faces:
        cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 2)
        cv2.imshow('Smile%d' % count, img)
        count += 1
        mask = True

    cv2.waitKey(0)
    cv2.destroyAllWindows()
    return mask

def image_selection():  #图片选择函数
    selection = eg.buttonbox(msg='                                请选择图像打开方式', title='摄像测量_识别项目',
                             choices=('图片', '摄像头'),
                             default_choice=('Button[2]'), cancel_choice=None, callback=None, run=True)
    return selection

if __name__ == '__main__':
    #模块选择
    while(True):
        module = select_module()
        if(module == None):  #选择x则退出程序
            break

        elif(module == '6b9140dc984e48589c6a6fe4b0c9317c_th.gif'):  #按图片无效,继续循环
            pass

        elif(module == '人脸识别'):  #人脸识别

            selection = image_selection()

            #图片/摄像机 选择
            if (selection == '图片'):
                paths = select_path()
                judge = face_recognition(paths)
                # if judge:   #if judge = = true即没有检测到人脸  由于这里mask检测不是很灵敏,但是人脸检测灵敏过头,会出现带着口罩也被判为人脸的情况,所以这判定去掉
                mask = mask_recogniton(paths)
                if mask:
                    face_predict(paths)
                pass
            elif(selection == '摄像头'):
                camera_face_recognition()
            else:
                pass
            pass

        elif (module == '车牌识别'):   #车牌识别,没做好,继续循环
            pass

        elif(module == '敬请期待...'):
            pass
        else:
            pass

2、人脸预测(sklearn的方法)

import numpy as np
import matplotlib.pyplot as plt
import joblib

import sklearn.datasets as datasets
import scipy.io as sio

from sklearn.linear_model import LinearRegression,Ridge,Lasso
from sklearn.neighbors import KNeighborsRegressor
from sklearn.model_selection import train_test_split
from sklearn.svm import SVR
from sklearn import tree
from sklearn.metrics import precision_recall_curve
from sklearn.metrics import classification_report
from sklearn.model_selection import train_test_split

face = datasets.fetch_olivetti_faces()  #联网请求,获取数据

data = face['images']
index = np.random.randint(400,size = 1)[0]  #随机抽取图片观察
plt.imshow(data[index],cmap = plt.cm.gray)  #灰度处理

#切分图片  因为图片shape是(400,64,64)
X = data[:,:32].reshape(400,-1)   #上半张脸
y = data[:,32:].reshape(400,-1)   #下半张脸

X_train,X_test,y_train,y_test = train_test_split(X,y,test_size = 10)  #留10组数据做测试

#切分数据
index = np.random.randint(390,size = 1)[0]

face_up = X_train[index].reshape(32,64)
face_down = y_train[index].reshape(32,64)

ax = plt.subplot(1,2,1)
ax.imshow(face_up,cmap = plt.cm.gray)

ax = plt.subplot(1,2,2)
ax.imshow(face_down,cmap = plt.cm.gray)

#生成算法 放入字典中
estimators = {}
estimators['KNN'] = KNeighborsRegressor(n_neighbors = 5)  #KNN算法
estimators['lr'] = LinearRegression()  #线性回归
estimators['Ridge'] = Ridge(alpha = 0.1)  #岭回归
estimators['Lasso'] = Lasso(alpha = 0.1)  #罗斯回归
'''支持向量机的非线性回归不清楚什么原因无法训练处模型,会出现数据量不对等的报错'''
# estimators['rbf'] = SVR(kernel='rbf')  #高斯  非线性
# estimators['poly'] = SVR(kernel='poly')  #多项式  非线性
# estimators['sigmoid'] = SVR(kernel='sigmoid')  #Sigmoid核函数  非线性
estimators['tree'] = tree.DecisionTreeRegressor()  #决策树

#数据训练,训练出来的结果放入字典中,方便后期plt呈现
predict_ = {}
for key, model in estimators.items():
    model.fit(X_train, y_train)

    y_ = model.predict(X_test)  # 根据上半张脸预测下半张脸的数据

    predict_[key] = y_

# 可视化
plt.figure(figsize=(7 * 2, 10 * 2))  # 10行6列  X_test中有10个样本 1列真实数据 2列是半张脸 34567是不同算法预测的

for i in range(10):
    # 第一列
    ax = plt.subplot(10, 7, 1 + 7 * i)  # 10行7列 索引为1+7i
    face_up = X_test[i].reshape(32, 64)
    face_down = y_test[i].reshape(32, 64)
    ax.imshow(np.concatenate([face_up, face_down], axis=0), cmap=plt.cm.gray)
    # 如果想去掉刻度 可以用 ax.axis('off')
    if i == 0:
        ax.set_title('True')  # 在第一行添加title

    # 第二列
    ax = plt.subplot(10, 7, 2 + 7 * i)
    ax.imshow(face_up, cmap=plt.cm.gray)
    if i == 0:
        ax.set_title('Face_up')

    # 第三、四、五、六列
    for j, key in enumerate(predict_):
        ax = plt.subplot(10, 7, 3 + j + 7 * i)
        y_ = predict_[key]
        face_down_ = y_[i].reshape(32, 64)
        ax.imshow(np.concatenate([face_up, face_down_], axis=0), cmap=plt.cm.gray)

        if i == 0:
            ax.set_title(key)

plt.savefig('./Desktop/回归图.jpg', dpi=500)  # 存图

'''对比之后发现决策树的效果可能更好,故保存该模型'''
tree_module = tree.DecisionTreeRegressor()  #决策树
tree_module.fit(X_train,y_train)
joblib.dump(tree_module, './tree_module.pkl')

3、用于训练模型的原始人脸数据处理

import cv2
import glob

# 人脸检测器
faceCascade = cv2.CascadeClassifier('./cascades/haarcascade_frontalface_default.xml')

paths = glob.glob('./face_origin_data_*/*.jpg')
count = 0
for path in paths:
    img = cv2.imread(path)
    # 读取照片
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # 首先检测人脸,返回的是框住人脸的矩形框
    faces = faceCascade.detectMultiScale(
        gray,
        scaleFactor=1.1,
        minNeighbors=8,
        minSize=(55, 55),
        flags=cv2.CASCADE_SCALE_IMAGE
    )

    # 画出每一个人脸,提取出人脸所在区域
    for (x, y, w, h) in faces:
        cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 2)
        # #提取脸部区域
        roi_gray = gray[y:y+h, x:x+w]#用于检测笑脸,减少计算量
        # roi_color = img[y:y+h, x:x+w]#用于画笑脸,因为用提取的区域进行分类,返回的参数是根据这个区域的

        roi_test = cv2.resize(roi_gray,(64,64))
        path_save = './output/'+ str(count) + '.jpg'
        cv2.imwrite(path_save,roi_test)
        # 全部显示出来
        # cv2.imshow('Smile%d' % count, roi_test)
        count += 1

c = cv2.waitKey(0)
cv2.destroyAllWindows()

【参考资料】

感谢以下博主提供的灵感和代码(博主+文章标题+网址)

[1] yzy_1996, HTML网页调用本地Python程序,https://blog.csdn.net/yzy_1996/article/details/80223053

[2] 柒澈言, 人脸识别之笑脸检测, https://blog.csdn.net/weixin_43493559/article/details/106599574

[3] 行动π, python 可视化界面学习简易教程, https://blog.csdn.net/wenqiangxin/article/details/84555128

[4] weixin_30782871, python 可视化界面, https://blog.csdn.net/weixin_30782871/article/details/99562137?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159290748119724839260348%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=159290748119724839260348&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-3-99562137.first_rank_v2_rank_v25&utm_term=python+%E5%8F%AF%E8%A7%86%E5%8C%96%E7%95%8C%E9%9D%A2

[5] 考古学家lx, Python 调用摄像头进行人脸识别, https://blog.csdn.net/weixin_43582101/article/details/88913164

[6] 姬小野, python openCV调用摄像头进行人脸识别, https://blog.csdn.net/wjh2622075127/article/details/90712424

[7] Cheney-渣渣杰, 基于Opencv的口罩佩戴识别系统, https://blog.csdn.net/cj151525/article/details/104984897

[8] 心静禅定ing, python实现人脸口罩检测(基于opencv和深度学习两种方法), https://blog.csdn.net/qq_43987474/article/details/106649335

[9] 网络毒刘, 【机器学习】六种算法在人脸补全中的应用比较(K近邻,线性,决策树,岭回归,套索回归,ElasticNet), https://blog.csdn.net/qq_41856814/article/details/103299271?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159299804019724843341245%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=159299804019724843341245&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_v2~rank_v25-8-103299271.first_rank_v2_rank_v25&utm_term=%E4%BA%BA%E8%84%B8%E8%A1%A5%E5%85%A8

[10] 蜂口小程序_ IT, 怎样降低遮挡对人脸识别的影响,人脸图像算法研究, https://blog.csdn.net/qq_43019117/article/details/82746795?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159299870219725222436468%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=159299870219725222436468&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_v2~rank_v25-5-82746795.first_rank_v2_rank_v25&utm_term=%E4%BA%BA%E8%84%B8%E8%A1%A5%E5%85%A8

[11] Data_IT_Farmer, 机器学习-训练模型的保存与恢复(sklearn), https://blog.csdn.net/helloxiaozhe/article/details/80658438?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159300301919195188413798%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=159300301919195188413798&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_v2~rank_v25-1-80658438.first_rank_v2_rank_v25&utm_term=%E5%9B%9E%E5%BD%92%E8%AE%AD%E7%BB%83%E5%87%BA%E6%9D%A5%E7%9A%84%E6%A8%A1%E5%9E%8B%E4%BF%9D%E5%AD%98

[12] pentiumCM, 机器学习之训练好的模型保存与加载, https://blog.csdn.net/pentiumCM/article/details/104370401?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159301052219725250109770%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=159301052219725250109770&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-1-104370401.first_rank_v2_rank_v25&utm_term=python%E4%BF%9D%E5%AD%98%E8%AE%AD%E7%BB%83%E5%A5%BD%E7%9A%84%E6%A8%A1%E5%9E%8B

[13] TheRebel_, k-svd实现人脸缺失像素补全, https://blog.csdn.net/Anonymity_/article/details/85196505?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159305814519195264552496%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=159305814519195264552496&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_v2~rank_v25-20-85196505.first_rank_v2_rank_v25&utm_term=%E4%BA%BA%E8%84%B8%E8%A1%A5%E5%85%A8

[14] Simonn_z, python+opencv 识别圆形物体并将图像抠出, https://blog.csdn.net/BOB_sm/article/details/106722952

[15] DXT00, OpenCV检测图像中的长方形画布或纸张并提取图像内容, https://blog.csdn.net/qq_32095699/article/details/80262429?ops_request_misc=&request_id=&biz_id=102&utm_term=%E8%AF%86%E5%88%AB%E6%96%B9%E7%89%A9%E4%BD%93%E5%B9%B6%E5%B0%86%E5%9B%BE%E5%83%8F%E6%8A%A0%E5%87%BA&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-1-80262429

[16] 菜鸟Jon, python爬取百度图片, https://blog.csdn.net/csdnmgq/article/details/93197047?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159350775819726869063583%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=159350775819726869063583&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_click~default-1-93197047.first_rank_v2_rank_v25&utm_term=%E7%88%AC%E7%99%BE%E5%BA%A6%E5%9B%BE%E7%89%87

[17] 一颗小树x, python 对文件夹下图片批量重命名, https://blog.csdn.net/qq_41204464/article/details/85483480?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159350904619195265964145%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=159350904619195265964145&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v3~pc_rank_v2-2-85483480.first_rank_ecpm_v3_pc_rank_v2&utm_term=%E5%B0%86%E6%96%87%E4%BB%B6%E5%A4%B9%E7%9A%84%E5%9B%BE%E7%89%87%E9%87%8D%E5%91%BD%E5%90%8D

[18] 倔强的小彬雅, 机器学习入门-用KNN实现手写数字图片识别, https://blog.csdn.net/Snow_yuki/article/details/89789071?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159351794319725250140434%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=159351794319725250140434&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v3~pc_rank_v2-11-89789071.first_rank_ecpm_v3_pc_rank_v2&utm_term=%E7%94%A8%E6%9C%AC%E5%9C%B0%E5%9B%BE%E7%89%87%E5%81%9A%E6%9C%BA%E5%99%A8%E8%AE%AD%E7%BB%83

  • 12
    点赞
  • 82
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值