精华内容
下载资源
问答
  • 人脸识别控件

    热门讨论 2013-03-10 11:11:01
    微软人脸识别控件,Com方式添加引用,支持二次开发,好用
  • CRM营业前台人脸识别控件最新版
  • 测试和使用了虹软的人脸API在QT5环境下设计了一个简单的人脸识别软件,实现了对人脸的跟踪和人脸识别。摄像头的控制以及图像格式的转换使用了Opencv,图像显示使用的是QT5的Qimage控件。下面是详细介绍1基本流程(1)...

    测试和使用了虹软的人脸API在QT5环境下设计了一个简单的人脸识别软件,实现了对人脸的跟踪和人脸识别。摄像头的控制以及图像格式的转换使用了Opencv,图像显示使用的是QT5的Qimage控件。下面是详细介绍

    1基本流程

    (1)加载存储的参考图像数据和图像标签,这里简单的使用图像的名字作为标签

    (2)使用虹软人脸识别API计算参考图像的人脸位置数据并存储

    (3)使用opencv VideoCapture 类采集摄像头图像数据

    (2)采集的图像数据送入虹软人脸识别API 计算人脸位置,并和参考人脸数据计算相似距离,返回最相似的人脸标签

    2 Visual Studio 下构建Qt工程

    (1)工程目录如下图所示:

    c1ac6dd9739e?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

    在这里插入图片描述

    其中QtGuiApplication1.ui是界面文件,Header File文件夹中的amcomdef.h

    ammem.h arcsoft_fsdk_face_detection.h arcsoft_fsdk_face_recognition.h

    asvloffscreen.h merror.h 是从虹软库中拷贝的头文件未做任何修改

    FaceDiscern.h 和FaceDiscern.cpp是自定义的一个人脸识别类

    (2)工程属性配置

    点击工程属性->连接器->输入中出了QT5的库文件,添加opencv_world340d.lib

    c1ac6dd9739e?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

    在这里插入图片描述

    点击工程属性-》VC++目录添加OpenCV的头文件和库文件的路径,其中包含目录添加opencv的头文件路径,库目录添加opencv的dll路径,如下图

    c1ac6dd9739e?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

    在这里插入图片描述

    2工程类文件详解

    (1)QtGuiApplication1 ui类的源文件如下所示,其中Mat2QImage函数将opencv采集的图像数据转化为QImage支 持 的数据格式, VideoCapture 是Opencv用来操作摄像头的类,QImage用来显示采集的图像数据

    #pragma once

    #include

    #include "ui_QtGuiApplication1.h"

    #include "qmessagebox.h"

    #include "opencv2/core/core.hpp"

    #include "opencv2/highgui/highgui.hpp"

    #include "opencv2/imgproc/imgproc.hpp"

    #include

    #include "qtimer.h"

    #include "FaceDiscern.h"

    #include "qrect.h"

    #include "qpainter.h"

    using namespace cv;

    using namespace std;

    class QtGuiApplication1 : public QMainWindow

    {

    Q_OBJECT

    public:

    QtGuiApplication1(QWidget *parent = Q_NULLPTR);

    ~QtGuiApplication1();

    QImage Mat2QImage(cv::Mat cvImg); //图像格式转换

    QTimer *timer;

    Mat frame; //摄像头直接获得的数据

    FaceDiscern *facediscern; //人脸识别类

    private:

    Ui::QtGuiApplication1Class ui;

    VideoCapture capture; //采集摄像头的数据

    QImage qImg; //展示图像的控件

    //---槽函数 用作事件触发

    public slots :

    void openVideo();

    void stopVideo();

    void nextFrame();

    };

    (2)QtGuiApplication1.cpp

    #include "QtGuiApplication1.h"

    QtGuiApplication1::QtGuiApplication1(QWidget *parent)

    : QMainWindow(parent)

    {

    ui.setupUi(this);

    ui.image->setScaledContents(true); //fit video to label area

    facediscern = new FaceDiscern("F:\\trainimages");//加载参考图像数据和标签

    facediscern->Train();//计算参考数据图像数据的人脸位置等

    }

    QtGuiApplication1::~QtGuiApplication1()

    {

    if (capture.isOpened())

    capture.release();

    delete(timer);

    }

    void QtGuiApplication1::openVideo()

    {

    if (capture.isOpened())

    capture.release(); //decide if capture is already opened; if so,close it

    capture.open(0); //open the default camera

    if (capture.isOpened())

    {

    double rate = capture.get(CV_CAP_PROP_FPS);

    capture >> frame; //获得摄像头图像数据

    if (!frame.empty())

    {

    QImage image = Mat2QImage(frame); //将摄像头的图像数据转换为QImage支持的格式

    this->ui.image->setPixmap(QPixmap::fromImage(image));

    timer = new QTimer(this); //循环获得摄像头数据

    connect(timer, SIGNAL(timeout()), this, SLOT(nextFrame()));

    timer->start(40);

    }

    }

    }

    void QtGuiApplication1::stopVideo()

    {

    if (capture.isOpened())

    {

    capture.release();

    }

    }

    //循环获得摄像头数据

    void QtGuiApplication1::nextFrame()

    {

    capture >> frame;

    double rate = capture.get(CV_CAP_PROP_FPS);

    if (!frame.empty())

    {

    QImage image = Mat2QImage(frame);

    //通过人脸检测API获得人脸的位置并在Qimage上显示人脸框

    QRect rect;

    //RecognizeFace识别人脸的位置并计算人脸所属的标签

    string result = facediscern->RecognizeFace(&frame, rect);

    static QTextCodec *codecForCStrings;

    QString strQ = QString::fromLocal8Bit(result.c_str());

    QString s1 = strQ;//这是在qlabel中显示中文的办法

    this->ui.result->setText(s1); //在控件上显示人脸所属的标签

    QPainter painter(&image);

    // 设置画笔颜色

    painter.setPen(QColor(255, 0, 0));

    painter.drawRect(rect);//绘制人脸的框

    this->ui.image->setPixmap(QPixmap::fromImage(image));

    }

    }

    //将opencv 的cv::Mat 格式图像转换为QImage图像

    QImage QtGuiApplication1::Mat2QImage(cv::Mat cvImg)

    {

    if (cvImg.channels() == 3) //3 channels color image

    {

    cv::cvtColor(cvImg, cvImg, CV_BGR2RGB); //BGR 转为 RGB

    qImg = QImage((const unsigned char*)(cvImg.data),

    cvImg.cols, cvImg.rows,

    cvImg.cols*cvImg.channels(),

    QImage::Format_RGB888);

    }

    else if (cvImg.channels() == 1) //grayscale image

    {

    qImg = QImage((const unsigned char*)(cvImg.data),

    cvImg.cols, cvImg.rows,

    cvImg.cols*cvImg.channels(),

    QImage::Format_Indexed8);

    }

    else

    {

    qImg = QImage((const unsigned char*)(cvImg.data),

    cvImg.cols, cvImg.rows,

    cvImg.cols*cvImg.channels(),

    QImage::Format_RGB888);

    }

    return qImg;

    }

    (3) FaceDiscern.h

    FaceDiscern 是人脸识别的主类 执行了人脸位置检测和人脸相似度计算等功能

    #pragma once

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include "arcsoft_fsdk_face_recognition.h"

    #include "merror.h"

    #include "arcsoft_fsdk_face_detection.h"

    #include "opencv2/core/core.hpp"

    #include "opencv2/highgui/highgui.hpp"

    #include "opencv2/imgproc/imgproc.hpp"

    #include "qrect.h"

    //动态载入人脸识别的API库 libarcsoft_fsdk_face_detection是人脸检测库

    //libarcsoft_fsdk_face_recognition.lib是人脸识别库

    #pragma comment(lib,"libarcsoft_fsdk_face_detection.lib")

    #pragma comment(lib,"./libarcsoft_fsdk_face_recognition.lib")

    using namespace cv;

    #define WORKBUF_SIZE (40*1024*1024)

    class FaceDiscern

    {

    public:

    FaceDiscern(std::string _trainpath);

    ~FaceDiscern();

    //将cv::Mat格式的图像转换为Bitmap

    void ConvertMatToBitmap(cv::Mat *img, uint8_t **imageData, int *pWidth, int *pHeight);

    void getFiles(std::string path, std::vector<:string>& files, std::vector<:string> &ownname);

    void Train();

    bool readBmp24(const char* path, uint8_t **imageData, int *pWidth, int *pHeight);

    std::string RecognizeFace(cv::Mat *img, QRect &rect);

    //APPID是从网站上注册的免费使用id

    char APPID[45] = "9aEAsHDYzzzWapX9rH9BZHhdBz8CPTfws4WuF5xdmgnf";

    char SDKKey[45] = "61MrwdsfKaMT8cm41uKPQBdCm4rKMLSELtJqs12p7WoV"; //SDKKey

    char DETECTIONKKey[45] = "61MrwdsfKaMT8cm41uKPQBci7TocqKmAASGS7infomre";

    std::string trainpath = "F:\\trainimages";

    MRESULT nRet ;

    MHandle hEngine ;

    MInt32 nScale ;

    MInt32 nMaxFace ;

    MByte *pWorkMem;

    std::vector<:string> trainfullfiles;//完整路径名

    std::vector<:string> trainnamefiles;

    std::string *labels;

    std::map<:string std::string> dicfilenametoname;

    /* 初始化引擎和变量 */

    MRESULT detectionnRet;

    MHandle hdetectionEngine;

    MInt32 ndetetionScale;

    MInt32 ndetectionMaxFace ;

    MByte *pdetectionWorkMem;

    int trainCount = 0;

    LPAFR_FSDK_FACEMODEL *trainfaceModels;

    AFR_FSDK_FACEMODEL dectfaceModels;

    };

    (4)FaceDiscern.cpp

    #include "FaceDiscern.h"

    FaceDiscern::FaceDiscern(std::string _trainpath)

    {

    nRet = MERR_UNKNOWN;

    hEngine = nullptr;

    nScale = 16;

    nMaxFace = 10;

    pWorkMem = (MByte *)malloc(WORKBUF_SIZE);

    /* 初始化引擎和变量 */

    detectionnRet = MERR_UNKNOWN;

    hdetectionEngine = nullptr;

    ndetetionScale = 16;

    ndetectionMaxFace = 10;

    pdetectionWorkMem = (MByte *)malloc(WORKBUF_SIZE);

    dicfilenametoname.insert(std::pair<:string std::string>("bingbing.bmp", "冰冰女神"));

    dicfilenametoname.insert(std::pair<:string std::string>("fangfang.bmp", "村里有个姑娘叫小芳"));

    dicfilenametoname.insert(std::pair<:string std::string>("feifei.bmp", "刘亦菲"));

    dicfilenametoname.insert(std::pair<:string std::string>("huihui.bmp", "冷工"));

    dicfilenametoname.insert(std::pair<:string std::string>("shishi.bmp", "诗诗妹妹"));

    dicfilenametoname.insert(std::pair<:string std::string>("xiaxia.bmp", "天上掉下个林妹妹"));

    dicfilenametoname.insert(std::pair<:string std::string>("xudasong.bmp", "松哥"));

    dicfilenametoname.insert(std::pair<:string std::string>("likunpeng.bmp", "李工"));

    dicfilenametoname.insert(std::pair<:string std::string>("gaojianjun.bmp", "高建军"));

    dicfilenametoname.insert(std::pair<:string std::string>("liuzhen.bmp", "小鲜肉振哥"));

    dicfilenametoname.insert(std::pair<:string std::string>("liting.bmp", "女王婷姐"));

    dicfilenametoname.insert(std::pair<:string std::string>("wangxuetao.bmp", "雪涛"));

    dicfilenametoname.insert(std::pair<:string std::string>("guowei.bmp", "郭大侠"));

    dicfilenametoname.insert(std::pair<:string std::string>("mingxin.bmp", "宝宝鸣新"));

    this->trainpath = _trainpath;

    }

    FaceDiscern::~FaceDiscern()

    {

    /* 释放引擎和内存 */

    detectionnRet = AFD_FSDK_UninitialFaceEngine(hdetectionEngine);

    if (detectionnRet != MOK)

    {

    fprintf(stderr, "UninitialFaceEngine failed , errorcode is %d \n", detectionnRet);

    }

    free(pdetectionWorkMem);

    for (int i = 0; i < trainCount; i++)

    {

    if (trainfaceModels[i]->pbFeature != NULL)

    free(trainfaceModels[i]->pbFeature);

    }

    nRet = AFR_FSDK_UninitialEngine(hEngine);

    if (nRet != MOK)

    {

    fprintf(stderr, "UninitialFaceEngine failed , errorcode is %d \n", nRet);

    }

    }

    //加载所有的参考图像和图像名字作为参考库

    void FaceDiscern::getFiles(std::string path, std::vector<:string>& files, std::vector<:string> &ownname)

    {

    /*files存储文件的路径及名称(eg. C:\Users\WUQP\Desktop\test_devided\data1.txt)

    4 ownname只存储文件的名称(eg. data1.txt)*/

    //文件句柄

    long long hFile = 0;

    //文件信息

    struct _finddata_t fileinfo;

    std::string p;

    if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1)

    {

    do

    {

    //如果是目录,迭代之

    //如果不是,加入列表

    if ((fileinfo.attrib & _A_SUBDIR))

    { /*

    if(strcmp(fileinfo.name,".") != 0 && strcmp(fileinfo.name,"..") != 0)

    getFiles( p.assign(path).append("\\").append(fileinfo.name), files, ownname ); */

    }

    else

    {

    files.push_back(p.assign(path).append("\\").append(fileinfo.name));

    ownname.push_back(fileinfo.name);

    }

    } while (_findnext(hFile, &fileinfo) == 0);

    _findclose(hFile);

    }

    }

    //将cv::Mat转换为Bitmap

    void FaceDiscern::ConvertMatToBitmap(cv::Mat *img, uint8_t **imageData, int *pWidth, int *pHeight)

    {

    //======建立位图信息 ===========

    int width, height, depth, channel;

    width = img->cols;

    height = img->rows;

    depth = img->depth();

    channel = img->channels();

    *pWidth = width; //图像宽。高

    *pHeight = height;

    int linebyte = width * channel;

    *imageData = (uint8_t *)malloc(linebyte * (*pHeight));

    for (int i = 0; i

    for (int j = 0; j

    *((*imageData) + i * width*channel + j * channel) = (*img).at(i, j)[2];// (uint8_t)(*(img + i * width*channel + j * width + 2));

    *((*imageData) + i * width*channel + j * channel + 1) = (*img).at(i, j)[1];

    *((*imageData) + i * width*channel + j * channel + 2) = (*img).at(i, j)[0];

    } // end of line

    }

    }

    //从文件中读取图像并转化为bitmap

    bool FaceDiscern::readBmp24(const char* path, uint8_t **imageData, int *pWidth, int *pHeight)

    {

    if (path == NULL || imageData == NULL || pWidth == NULL || pHeight == NULL)

    {

    return false;

    }

    FILE *fp = fopen(path, "rb");

    if (fp == NULL)

    {

    return false;

    }

    fseek(fp, sizeof(BITMAPFILEHEADER), 0);

    BITMAPINFOHEADER head;

    fread(&head, sizeof(BITMAPINFOHEADER), 1, fp);

    *pWidth = head.biWidth;

    *pHeight = head.biHeight;

    int biBitCount = head.biBitCount;

    if (24 == biBitCount)

    {

    int lineByte = ((*pWidth) * biBitCount / 8 + 3) / 4 * 4;

    *imageData = (uint8_t *)malloc(lineByte * (*pHeight));

    uint8_t * data = (uint8_t *)malloc(lineByte * (*pHeight));

    fseek(fp, 54, SEEK_SET);

    fread(data, 1, lineByte * (*pHeight), fp);

    for (int i = 0; i < *pHeight; i++)

    {

    for (int j = 0; j < *pWidth; j++)

    {

    memcpy((*imageData) + i * (*pWidth) * 3 + j * 3, data + (((*pHeight) - 1) - i) * lineByte + j * 3, 3);

    }

    }

    free(data);

    }

    else

    {

    fclose(fp);

    return false;

    }

    fclose(fp);

    return true;

    }

    //加载所有的参考数据

    void FaceDiscern::Train()

    {

    if (pWorkMem == nullptr)

    {

    return;

    }

    nRet = AFR_FSDK_InitialEngine(APPID, SDKKey, pWorkMem, WORKBUF_SIZE, &hEngine); //初始化引擎

    if (nRet != MOK)

    {

    return;

    }

    getFiles(trainpath, trainfullfiles, trainnamefiles);

    //生成训练数据 特征集合

    if (trainfullfiles.size() > 0)

    {

    //参考图像数据的人脸特征和标签的存储

    trainfaceModels = new LPAFR_FSDK_FACEMODEL[trainfullfiles.size()];

    labels = new std::string[trainfullfiles.size()];

    }

    else

    {

    return ;

    }

    for (int i = 0; i < trainfullfiles.size(); i++)

    {

    std::string filename = trainfullfiles[i];

    /* 读取第一张静态图片信息,并保存到ASVLOFFSCREEN结构体 (以ASVL_PAF_RGB24_B8G8R8格式为例) */

    ASVLOFFSCREEN offInput = { 0 };

    offInput.u32PixelArrayFormat = ASVL_PAF_RGB24_B8G8R8;

    offInput.ppu8Plane[0] = nullptr;

    const char * path = filename.c_str();

    readBmp24(path, (uint8_t**)&offInput.ppu8Plane[0], &offInput.i32Width, &offInput.i32Height);

    if (!offInput.ppu8Plane[0])

    {

    fprintf(stderr, "fail to ReadBmp(%s)\n", path);

    AFR_FSDK_UninitialEngine(hEngine);

    free(pWorkMem);

    continue ;

    }

    offInput.pi32Pitch[0] = offInput.i32Width * 3;

    AFR_FSDK_FACEMODEL *faceModels = new AFR_FSDK_FACEMODEL();

    {

    AFR_FSDK_FACEINPUT faceInput;

    //第一张人脸信息通过face detection\face tracking获得

    faceInput.lOrient = AFR_FSDK_FOC_0;//人脸方向

    //人脸框位置

    faceInput.rcFace.left = 0;

    faceInput.rcFace.top = 0;

    faceInput.rcFace.right = offInput.i32Width - 2;;

    faceInput.rcFace.bottom = offInput.i32Height - 2;;

    //提取第一张人脸特征

    AFR_FSDK_FACEMODEL LocalFaceModels = { 0 };

    nRet = AFR_FSDK_ExtractFRFeature(hEngine, &offInput, &faceInput, &LocalFaceModels);

    if (nRet != MOK)

    {

    fprintf(stderr, "fail to Extract 1st FR Feature, error code: %d\n", nRet);

    }

    /* 拷贝人脸特征结果 */

    faceModels->lFeatureSize = LocalFaceModels.lFeatureSize;

    faceModels->pbFeature = (MByte*)malloc(faceModels->lFeatureSize);

    memcpy(faceModels->pbFeature, LocalFaceModels.pbFeature, faceModels->lFeatureSize);

    }

    trainfaceModels[i] = faceModels;

    labels[i] = trainnamefiles[i];

    trainCount++;

    }

    if (pdetectionWorkMem == nullptr)

    {

    return;

    }

    //人脸检测engine

    detectionnRet = AFD_FSDK_InitialFaceEngine(APPID, DETECTIONKKey, pdetectionWorkMem, WORKBUF_SIZE, &hdetectionEngine, AFD_FSDK_OPF_0_HIGHER_EXT, ndetetionScale, ndetectionMaxFace);

    if (detectionnRet != MOK)

    {

    return;

    }

    }

    //简单的通过距离相似计算出最相似的参考图像

    std::string FaceDiscern::RecognizeFace(cv::Mat *img, QRect &rect)

    {

    /* 读取静态图片信息,并保存到ASVLOFFSCREEN结构体 (以ASVL_PAF_RGB24_B8G8R8格式为例) */

    /* 人脸检测 */

    ASVLOFFSCREEN offInput = { 0 };

    offInput.u32PixelArrayFormat = ASVL_PAF_RGB24_B8G8R8;

    offInput.ppu8Plane[0] = nullptr;

    ConvertMatToBitmap(img, (uint8_t**)&offInput.ppu8Plane[0], &offInput.i32Width, &offInput.i32Height);

    if (!offInput.ppu8Plane[0])

    {

    return "";

    }

    offInput.pi32Pitch[0] = offInput.i32Width * 3;

    LPAFD_FSDK_FACERES FaceRes = nullptr;

    detectionnRet = AFD_FSDK_StillImageFaceDetection(hdetectionEngine, &offInput, &FaceRes);

    void *imgptr = offInput.ppu8Plane[0];

    识别人脸信息

    AFR_FSDK_FACEINPUT faceInput;

    faceInput.lOrient = AFR_FSDK_FOC_0;//人脸方向 //人脸框位置

    faceInput.rcFace.left =FaceRes->rcFace[0].left;

    faceInput.rcFace.top = FaceRes->rcFace[0].top;

    faceInput.rcFace.right = FaceRes->rcFace[0].right;

    faceInput.rcFace.bottom = FaceRes->rcFace[0].bottom;

    rect.setLeft(FaceRes->rcFace[0].left);

    rect.setTop(FaceRes->rcFace[0].top);

    rect.setRight(FaceRes->rcFace[0].right);

    rect.setBottom(FaceRes->rcFace[0].bottom);

    //提取人脸特征

    nRet = AFR_FSDK_ExtractFRFeature(hEngine, &offInput, &faceInput, &dectfaceModels);

    free(imgptr);

    if (nRet != MOK)

    {

    return "";

    }

    float maxscore = -1.0;

    int index = -1;

    for (int i = 0; i < trainCount; i++)

    {

    MFloat fSimilScore = 0.0f;

    nRet = AFR_FSDK_FacePairMatching(hEngine, &dectfaceModels, trainfaceModels[i], &fSimilScore);

    if (fSimilScore > maxscore)

    {

    maxscore = fSimilScore;

    index = i;

    }

    }

    if (index != -1)

    {

    double num = maxscore * 100.0;

    std::string str;

    char ctr[10];

    _gcvt(num, 6, ctr);

    str = ctr;

    std::string nameresult = labels[index];

    if (dicfilenametoname.find(nameresult) != dicfilenametoname.end())

    {

    nameresult = dicfilenametoname[nameresult];

    }

    return nameresult + "," + str;

    }

    //释放

    if(dectfaceModels.lFeatureSize>0)

    free(dectfaceModels.pbFeature);

    return "";

    }

    (3) 界面展示

    c1ac6dd9739e?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

    在这里插入图片描述

    最后是SDK下载地址 https://ai.arcsoft.com.cn/ucenter/user/reg?utm_source=csdn1&utm_medium=referral

    展开全文
  • 《百度AI人脸识别与检测》专栏为项目专栏,从零到一,从无到有开发一个学生人脸识别签到系统;主要用到的技术有百度开放平台中的人脸检测、人脸识别、Python图形界面开发PyQt5、线程的管理、以及通过python调用百度...

    《百度AI人脸识别与检测》专栏为项目专栏,从零到一,从无到有开发一个学生人脸识别签到系统;主要用到的技术有百度开放平台中的人脸检测、人脸识别、Python图形界面开发PyQt5、线程的管理、以及通过python调用百度接口实现人脸检测、百度开放平台中人脸检测技术文档的理解等,由浅入深、由局部到整体的一个项目学习过程,如果你想对人脸识别感兴趣,对python的图形界面设计感兴趣,可以订阅本专栏,因为对你可能有帮助哦!

    前文参考:

    百度AI人脸识别与检测一:学生人脸识别签到系统简介及百度AI开放平台账号注册和人脸实例应用创建
    百度AI人脸识别与检测二:学生人脸识别打卡签到系统主界面功能需求和设计以及通过Python实现界面运行

    上次博客,我们将学生人脸识别打卡签到系统的界面设计完成,并且通过python代码实现了界面的运行显示,也就是说,学生人脸识别打卡签到系统的界面设计部分已经完成,接下来要做的就是按照界面上的功能需求,实现这些功能。

    既然是人脸识别打开签到,就离不开摄像头画面数据的获取,而本项目主要通过电脑本身的摄像头进行打卡签到系统的模拟,因此,除了摄像头打开,还要将摄像头的数据进行实时显示,这就是本次博客需要将的内容,将摄像头捕获到的画面进行实时显示,并显示在界面设计上的画面显示框中,一起学习吧!



    一、摄像头的打开和实时数据获取

    在做项目的同时,我们需要注意到函数的分类与类的创建,在类中创建函数是每个程序员需要掌握的必要技能,通过类的对象调用函数,不仅能够对函数进行封装,还能够进行内容参数的加密

    1、创建操作摄像头的类

    1)、创建cameraVideo.py文件,该文件中主要用来进行摄像头系列操作
    在这里插入图片描述
    2)、创建类camera并进行类的初始化

    '''
    创建类对象
    open函数完成摄像头的配置打开
    '''
    class camera():
        '''
        类初始化,相当于构造函数
        '''
        def __init__(self):
            pass
    
    

    2、创建打开摄像头函数

    由于我们点击开始签到按钮摄像头画面就要进行实时显示,因此,我们需要将打开摄像头的操作写进初始化函数中,只要调用该函数,摄像头就自动进行打开并进行实时画面的显示

    '''
    创建类对象
    open函数完成摄像头的配置打开
    '''
    import cv2
    import numpy as np
    
    class camera():
        '''
        类初始化,相当于构造函数
        '''
        def __init__(self):
            self.open_camera()
        '''
            以下函数通过opencv打开笔记本电脑默认摄像头
        '''
        def open_camera(self):
            # 0表示内置默认摄像头,self.capture为全局变量
            self.capture = cv2.VideoCapture(0, cv2.CAP_DSHOW)
            # isopend()函数返回一个布尔值,来判断是否打开摄像头
            if self.capture.isOpened():
                print("摄像头打开成功")
            # 定义一个多维数组,用来存储获取的画面数据
            self.currentframe = np.array([])
    

    3、实现摄像头画面获取

    1)、摄像头数据获取
    在上面的self.capture得到结果中,我们需要进行结果的读取,通过self.capture.read() 读取摄像头画面,并且实现按帧读取,每一帧就是一副图像,当这些图像连接起来,就是一条视频图像,返回的结果为ret,pic_data,pic_data就是我们需要的结果,而ret主要用来判断去取状态,如果摄像头有数据,返回True,没有则返回Flase;因此我们需要得到它,并且将他返回

    '''
    创建类对象
    open函数完成摄像头的配置打开
    '''
    import cv2
    import numpy as np
    
    class camera():
        '''
        类初始化,相当于构造函数
        '''
        def __init__(self):
            self.open_camera()
        '''
            以下函数通过opencv打开笔记本电脑默认摄像头
        '''
        def open_camera(self):
            # 0表示内置默认摄像头,self.capture为全局变量
            self.capture = cv2.VideoCapture(0, cv2.CAP_DSHOW)
            # isopend()函数返回一个布尔值,来判断是否打开摄像头
            if self.capture.isOpened():
                print("摄像头打开成功")
            # 定义一个多维数组,用来存储获取的画面数据
            self.currentframe = np.array([])
    
        '''
            获取摄像头数据
        '''
        def read_camera(self):
            ret,pic_data=self.capture.read()
            if not ret:
                print("获取摄像头数据失败")
                return None
            return pic_data
    

    2)、摄像头图像格式转换
    因为在界面Label框中进行显示的图像格式是QPixmap的图像格式,而OpenCV读取的图像格式为像素数组格式的图像,因此需要进行转换才能在Label上进行显示:返回参数为qpix(用于Label框显示的格式图像)

    '''
    创建类对象
    open函数完成摄像头的配置打开
    '''
    import cv2
    import numpy as np
    from PyQt5.QtGui import QImage, QPixmap
    
    
    class camera():
        '''
        类初始化,相当于构造函数
        '''
        def __init__(self):
            self.open_camera()
        '''
            以下函数通过opencv打开笔记本电脑默认摄像头
        '''
        def open_camera(self):
            # 0表示内置默认摄像头,self.capture为全局变量
            self.capture = cv2.VideoCapture(0, cv2.CAP_DSHOW)
            # isopend()函数返回一个布尔值,来判断是否打开摄像头
            if self.capture.isOpened():
                print("摄像头打开成功")
            # 定义一个多维数组,用来存储获取的画面数据
            self.currentframe = np.array([])
    
        '''
            获取摄像头数据
        '''
        def read_camera(self):
            ret,pic_data=self.capture.read()
            if not ret:
                print("获取摄像头数据失败")
                return None
            return pic_data
    
        '''
            摄像头图像格式转换
        '''
        def camera_to_pic(self):
            pic=self.read_camera()
            #摄像头是BGR转换为RGB
            self.currentframe=cv2.cvtColor(pic,cv2.COLOR_BGR2RGB)
            #设置宽高
            #self.currentframe=cv2.cvtColor(self.currentframe,(521,411))
            height,width=self.currentframe.shape[:2]
            #转换格式(界面能够显示的格式)
            #先转换为QImage图片(画面)
            #QImage(data,width,height,format)创建:数据、快读、高度、格式
            qimg=QImage(self.currentframe,width,height,QImage.Format_RGB888)
            qpix=QPixmap.fromImage(qimg)
            return qpix
    

    3)、关闭摄像头
    点击关闭签到的同时,需要将摄像头进行关闭,释放摄像头

    '''
    创建类对象
    open函数完成摄像头的配置打开
    '''
    import cv2
    import numpy as np
    from PyQt5.QtGui import QImage, QPixmap
    
    
    class camera():
        '''
        类初始化,相当于构造函数
        '''
        def __init__(self):
            self.open_camera()
        '''
            以下函数通过opencv打开笔记本电脑默认摄像头
        '''
        def open_camera(self):
            # 0表示内置默认摄像头,self.capture为全局变量
            self.capture = cv2.VideoCapture(0, cv2.CAP_DSHOW)
            # isopend()函数返回一个布尔值,来判断是否打开摄像头
            if self.capture.isOpened():
                print("摄像头打开成功")
            # 定义一个多维数组,用来存储获取的画面数据
            self.currentframe = np.array([])
    
        '''
            获取摄像头数据
        '''
        def read_camera(self):
            ret,pic_data=self.capture.read()
            if not ret:
                print("获取摄像头数据失败")
                return None
            return pic_data
    
        '''
            摄像头图像格式转换
        '''
        def camera_to_pic(self):
            pic=self.read_camera()
            #摄像头是BGR转换为RGB
            self.currentframe=cv2.cvtColor(pic,cv2.COLOR_BGR2RGB)
            #设置宽高
            #self.currentframe=cv2.cvtColor(self.currentframe,(521,411))
            height,width=self.currentframe.shape[:2]
            #转换格式(界面能够显示的格式)
            #先转换为QImage图片(画面)
            #QImage(data,width,height,format)创建:数据、快读、高度、格式
            qimg=QImage(self.currentframe,width,height,QImage.Format_RGB888)
            qpix=QPixmap.fromImage(qimg)
            return qpix
        '''
            关闭摄像头
        '''
        def colse_camera(self):
            #释放摄像头
            self.capture.release()
    

    以上每一步的代码都覆盖前面一步的代码,因此,关闭摄像头的代码为该py文件的全部代码,如果需要代码作为参考,可以直接观看以上步骤的代码,实现OpenCV对摄像头的操作

    二、Label控件中摄像头数据的实时显示

    上面对摄像头的操作部分已经完毕,接下来,我们需要对打开签到和关闭签到进行按钮事件的绑定,实现打开按钮,Label可以进行笔记本摄像头数据的实时获取,关闭签到可以释放笔记本摄像头!

    1、打开签到按钮事件的绑定

    1)、打开function_window.py文件,编写打开签到实现的功能函数

    from PyQt5.QtCore import QTimer
    from PyQt5.QtWidgets import QMainWindow
    from cameraVideo import camera
    from mainWindow import Ui_MainWindow
    class function_window(Ui_MainWindow,QMainWindow):
        '''
        初始化函数
        '''
        def __init__(self):
            super(function_window, self).__init__()
            self.setupUi(self)
        '''
            打开签到
        '''
        def open_Sign(self):
            #启动摄像头
            self.cameravideo = camera()
    

    打开签到,直接启动摄像头
    在这里插入图片描述

    2)、实现摄像头数据显示Label框的函数

    from PyQt5.QtCore import QTimer
    from PyQt5.QtWidgets import QMainWindow
    from cameraVideo import camera
    from mainWindow import Ui_MainWindow
    class function_window(Ui_MainWindow,QMainWindow):
        '''
        初始化函数
        '''
        def __init__(self):
            super(function_window, self).__init__()
            self.setupUi(self)
        '''
            打开签到
        '''
        def open_Sign(self):
            #启动摄像头
            self.cameravideo = camera()
        '''
            摄像头数据显示
        '''
        def show_cameradata(self):
            #获取摄像头数据
            pic=self.cameravideo.camera_to_pic()
            #在lebel框中显示数据、显示画面
            self.label.setPixmap(pic)
    

    在这里插入图片描述
    那么该函数只是进行摄像头一帧图像的显示,而我们需求是要进行实时显示,因此,我们需要在打开摄像头的函数中加入定时器,没多少毫秒进行一帧数据的显示,连接起来就是视频流了
    3)、添加定时器,实现摄像头数据的实时显示,每隔10毫秒,调用一次图摄像头画面显示函数

    from PyQt5.QtCore import QTimer
    from PyQt5.QtWidgets import QMainWindow
    from cameraVideo import camera
    from mainWindow import Ui_MainWindow
    class function_window(Ui_MainWindow,QMainWindow):
        '''
        初始化函数
        '''
        def __init__(self):
            super(function_window, self).__init__()
            self.setupUi(self)
        '''
            打开签到
        '''
        def open_Sign(self):
            #启动摄像头
            self.cameravideo = camera()
            # 启动定时器进行定时,每隔多长时间进行一次获取摄像头数据进行显示
            self.timeshow = QTimer(self)
            self.timeshow.start(10)
            # 每隔10毫秒产生一个信号timeout
            self.timeshow.timeout.connect(self.show_cameradata)
        '''
            摄像头数据显示
        '''
        def show_cameradata(self):
            #获取摄像头数据
            pic=self.cameravideo.camera_to_pic()
            #在lebel框中显示数据、显示画面
            self.label.setPixmap(pic)
    

    在这里插入图片描述
    4)、现在我们对界面的打开签到按钮进行事件绑定吧,绑定到打开签到功能函数上面

    from PyQt5.QtCore import QTimer
    from PyQt5.QtWidgets import QMainWindow
    from cameraVideo import camera
    from mainWindow import Ui_MainWindow
    class function_window(Ui_MainWindow,QMainWindow):
        '''
        初始化函数
        '''
        def __init__(self):
            super(function_window, self).__init__()
            self.setupUi(self)
            self.label.setScaledContents(True)#设置图像自适应label显示框
            self.pushButton.clicked.connect(self.open_Sign)
        '''
            打开签到
        '''
        def open_Sign(self):
            #启动摄像头
            self.cameravideo = camera()
            # 启动定时器进行定时,每隔多长时间进行一次获取摄像头数据进行显示
            self.timeshow = QTimer(self)
            self.timeshow.start(10)
            # 每隔10毫秒产生一个信号timeout
            self.timeshow.timeout.connect(self.show_cameradata)
        '''
            摄像头数据显示
        '''
        def show_cameradata(self):
            #获取摄像头数据
            pic=self.cameravideo.camera_to_pic()
            #在lebel框中显示数据、显示画面
            self.label.setPixmap(pic)
    

    在这里插入图片描述

    现在运行我们的程序,点击打开签到试一下:
    在这里插入图片描述
    在这里插入图片描述
    我们可以看到,摄像头实时画面的获取已经在label框中进行显示了,而且只有10毫秒的延迟,这种延迟可以成为实时显示了,但目前还不能进行关闭,因此,我们只能点击设计的X按钮进行关闭,下面我们来实现停止签到实现摄像头的关闭

    2、关闭签到按钮事件的绑定

    1)、关闭签到函数功能函数实现
    摄像头的关闭需要注意,应该先关闭定时器,然后关闭定时器的链接函数,不进行摄像头画面的获取,最后再关闭摄像头,注意这样一个顺序

    from PyQt5.QtCore import QTimer
    from PyQt5.QtWidgets import QMainWindow
    from cameraVideo import camera
    from mainWindow import Ui_MainWindow
    class function_window(Ui_MainWindow,QMainWindow):
        '''
        初始化函数
        '''
        def __init__(self):
            super(function_window, self).__init__()
            self.setupUi(self)
            self.label.setScaledContents(True)#设置图像自适应label显示框
            self.pushButton.clicked.connect(self.open_Sign)
        '''
            打开签到
        '''
        def open_Sign(self):
            #启动摄像头
            self.cameravideo = camera()
            # 启动定时器进行定时,每隔多长时间进行一次获取摄像头数据进行显示
            self.timeshow = QTimer(self)
            self.timeshow.start(10)
            # 每隔10毫秒产生一个信号timeout
            self.timeshow.timeout.connect(self.show_cameradata)
        '''
            摄像头数据显示
        '''
        def show_cameradata(self):
            #获取摄像头数据
            pic=self.cameravideo.camera_to_pic()
            #在lebel框中显示数据、显示画面
            self.label.setPixmap(pic)
        '''
            关闭签到
        '''
        def close_Sign(self):
            #关闭定时器,不再获取摄像头的数据
            self.timeshow.stop()
            self.timeshow.timeout.disconnect(self.show_cameradata)
            # 关闭摄像头
            self.cameravideo.colse_camera()
    

    在这里插入图片描述
    2)、关闭签到按钮事件绑定,对关闭签到按钮绑定在关闭签到函数上

    from PyQt5.QtCore import QTimer
    from PyQt5.QtWidgets import QMainWindow
    from cameraVideo import camera
    from mainWindow import Ui_MainWindow
    class function_window(Ui_MainWindow,QMainWindow):
        '''
        初始化函数
        '''
        def __init__(self):
            super(function_window, self).__init__()
            self.setupUi(self)
            self.label.setScaledContents(True)#设置图像自适应label显示框
            self.pushButton.clicked.connect(self.open_Sign)#打开签到事件绑定
            self.pushButton_2.clicked.connect(self.close_Sign())#关闭签到事件绑定
        '''
            打开签到
        '''
        def open_Sign(self):
            #启动摄像头
            self.cameravideo = camera()
            # 启动定时器进行定时,每隔多长时间进行一次获取摄像头数据进行显示
            self.timeshow = QTimer(self)
            self.timeshow.start(10)
            # 每隔10毫秒产生一个信号timeout
            self.timeshow.timeout.connect(self.show_cameradata)
        '''
            摄像头数据显示
        '''
        def show_cameradata(self):
            #获取摄像头数据
            pic=self.cameravideo.camera_to_pic()
            #在lebel框中显示数据、显示画面
            self.label.setPixmap(pic)
        '''
            关闭签到
        '''
        def close_Sign(self):
            #关闭定时器,不再获取摄像头的数据
            self.timeshow.stop()
            self.timeshow.timeout.disconnect(self.show_cameradata)
            # 关闭摄像头
            self.cameravideo.colse_camera()
    

    在这里插入图片描述

    3、摄像头打开和关闭测试

    1)、点击打开签到,进行摄像头打开并获取实时数据
    在这里插入图片描述
    2)、点击关闭签到,进行摄像头的关闭
    在这里插入图片描述
    我们可以发现,关闭签到后,摄像头停止了,但图像画面停止在了最后获取的一帧图像,这不是我们需要的,因此,我们需要添加代码,当点击关闭签到后,我们的画面恢复原始画面或者为自己喜欢的图像
    3)、设置关闭签到后,Label显示自己设定的图像

    from PyQt5.QtCore import QTimer
    from PyQt5.QtGui import QPixmap
    from PyQt5.QtWidgets import QMainWindow, QMessageBox
    from cameraVideo import camera
    from mainWindow import Ui_MainWindow
    class function_window(Ui_MainWindow,QMainWindow):
        '''
        初始化函数
        '''
        def __init__(self):
            super(function_window, self).__init__()
            self.setupUi(self)
            self.label.setScaledContents(True)#设置图像自适应label显示框
            self.pushButton.clicked.connect(self.open_Sign)#打开签到事件绑定
            self.pushButton_2.clicked.connect(self.close_Sign)#关闭签到事件绑定
        '''
            打开签到
        '''
        def open_Sign(self):
            #启动摄像头
            self.cameravideo = camera()
            # 启动定时器进行定时,每隔多长时间进行一次获取摄像头数据进行显示
            self.timeshow = QTimer(self)
            self.timeshow.start(10)
            # 每隔10毫秒产生一个信号timeout
            self.timeshow.timeout.connect(self.show_cameradata)
        '''
            摄像头数据显示
        '''
        def show_cameradata(self):
            #获取摄像头数据
            pic=self.cameravideo.camera_to_pic()
            #在lebel框中显示数据、显示画面
            self.label.setPixmap(pic)
        '''
            关闭签到
        '''
        def close_Sign(self):
            #关闭定时器,不再获取摄像头的数据
            self.timeshow.stop()
            self.timeshow.timeout.disconnect(self.show_cameradata)
            # 关闭摄像头
            self.cameravideo.colse_camera()
            #判断定时器是否关闭,关闭,则显示为自己设定的图像
            if self.timeshow.isActive() == False:
                self.label.setPixmap(QPixmap("./1.jpg"))
            else:
                QMessageBox.about(self,"警告","关闭失败,存在部分没有关闭成功!")
    

    在这里插入图片描述
    再次测试,点击关闭签到之后,结果如下所示:
    在这里插入图片描述
    这不就点击关闭签到后,设置成了我们想要的图像了嘛,到这来,本次博客的教程就结束了,希望通过本次博客,大家能够实现摄像头的系列操作,包括打开摄像头、读取摄像头数据、关闭摄像头等等,同时,需要熟悉相关PyQt5中部分函数库的使用包括Label控件中图像的显示格式等。阅读本专栏,希望能够帮助到你!


    以上就是本次博客的全部内容,遇到问题的小伙伴记得留言评论,学长看到会为大家进行解答的,这个学长不太冷!

    由起点到夜晚,由山野到书房,一切问题的答案都很简单。我希望有个如你一般的人,贯彻未来,数遍生命的公路牌

    陈一月的又一天编程岁月^ _ ^

    展开全文
  • 什么是人脸识别人脸识别,是基于人的脸部特征信息进行身份识别的一种生物识别技术。用摄像机或摄像头采集含有人脸的图像或视频流,并自动在图像中检测和跟踪人脸,进而对检测到的人脸进行脸部识别的一系列相关技术,...

    什么是人脸识别

    人脸识别,是基于人的脸部特征信息进行身份识别的一种生物识别技术。用摄像机或摄像头采集含有人脸的图像或视频流,并自动在图像中检测和跟踪人脸,进而对检测到的人脸进行脸部识别的一系列相关技术,通常也叫做人像识别、面部识别。

    目前的人脸识别技术已经非常成熟了,还发展成3D人脸识别。而且现在各大厂商也都提供了人脸识别的API接口供我们调用,可以说几行代码就可以完成人脸识别。但是人脸识别的根本还是基于图像处理。在Python中最强大的图像处理库就是OpenCV。

    OpenCV简介

    OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉库,可以运行在Linux、Windows、Android和Mac OS操作系统上。OpenCV可用于开发实时的图像处理、计算机视觉以及模式识别程序。它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。

    OpenCV基本使用

    安装

    pip install opencv-python  # 基础库pip install opencv-contrib-python  # 扩展库pip install opencv-python-headless

    读取图片

    读取和显示图片是最基本的操作了,OpenCV当中使用imread和imshow实现该操作

    import cv2 as cv# 读取图片,路径不能含有中文名,否则图片读取不出来image = cv.imread('1111.jpg')# 显示图片cv.imshow('image', image)# 等待键盘输入,单位是毫秒,0表示无限等待cv.waitKey(0)# 因为最终调用的是C++对象,所以使用完要释放内存cv.destroyAllWindows()
    9c85d0d367ceb418e7ff99bc393e6cb7.png

    将图片转为灰度图

    OpenCV中数百中关于不同色彩控件之间转换的方法。目前最常用的有三种:灰度、BGR、HSV。

    • 灰度色彩空间是通过去除彩色信息来讲图片转换成灰阶,灰度图会大量减少图像处理中的色彩处理,对人脸识别很有效。
    • BGR每个像素都由一个三元数组来表示,分别代码蓝、绿、红三种颜色。python中还有一个库PIL,读取的图片通道是RGB,其实是一样的,只是颜色顺序不一样
    • HSV,H是色调,S是饱和度,V是黑暗的程度
      将图片转换为灰度图
    import cv2 as cv# 读取图片,路径不能含有中文名,否则图片读取不出来image = cv.imread('1111.jpg')# cv2读取图片的通道是BGR,# PIL读取图片的通道是RGB# code选择COLOR_BGR2GRAY,就是BGR to GRAYgray_image = cv.cvtColor(image, code=cv.COLOR_BGR2GRAY)# 显示图片cv.imshow('image', gray_image)# 等待键盘输入,单位是毫秒,0表示无限等待cv.waitKey(0)# 因为最终调用的是C++对象,所以使用完要释放内存cv.destroyAllWindows()
    0600bf05678ca86851ee70fa3708ad44.png

    绘制矩形

    image = cv.imread('1111.jpg')x, y, w, h = 50, 50, 80, 80# 绘制矩形cv.rectangle(image, (x, y, x+w, y+h), color=(0, 255, 0), thickness=2)# 绘制圆形cv.circle(image, center=(x + w//2, y + h//2), radius=w//2, color=(0, 0, 255), thickness=2)cv.imshow('image', image)cv.waitKey(0)cv.destroyAllWindows()
    edcd3f6bffb14070437a3ca3a1033b16.png

    人脸检测

    人脸检测实际上是对图像提取特征,Haar特征是一种用于实现实时人脸跟踪的特征。每个Haar特征都描述了相邻图像区域的对比模式。比如边、定点和细线都能生成具有判别性的特征。OpenCV给我们提供了Haar特征数据,在cv2/data目录下,使用特征数据的方法def detectMultiScale(self, image, scaleFactor=None, minNeighbors=None, flags=None, minSize=None, maxSize=None)

    • scaleFactor: 指定每个图像比例缩小多少图像
    • minNeighbors: 指定每个候选矩形必须保留多少个邻居,值越大说明精度要求越高
    • minSize:检测到的最小矩形大小
    • maxSize: 检测到的最大矩形大小

    检测图片中人脸

    import osimport cv2 as cvdef face_detect_demo(image):    # 将图片转换为灰度图    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)    # 加载特征数据    face_detector = cv.CascadeClassifier(os.path.join(cv.data.haarcascades, 'haarcascade_frontalface_default.xml'))    faces = face_detector.detectMultiScale(gray)    for x, y, w, h in faces:        cv.rectangle(image, (x, y), (x + w, y + h), color=(0, 255, 0), thickness=2)# 读取图片,路径不能含有中文名,否则图片读取不出来image = cv.imread('2222.jpg')face_detect_demo(image)# 显示图片cv.imshow('image', image)# 等待键盘输入,单位是毫秒,0表示无限等待cv.waitKey(0)# 因为最终调用的是C++对象,所以使用完要释放内存cv.destroyAllWindows()
    e60bcdb3fc1a726acc2a90024082fa45.png

    采用默认参数,检测人脸数据不全,需要调整detectMultiScale函数的参数,调整为faces = face_detector.detectMultiScale(gray, scaleFactor=1.02, minNeighbors=3)

    8424af87ee3ec3c4fefe5d0e4daa677c.png


    我们发现除了检测到人脸数据,还有一些其他的脏数据,这个时候可以打印检测出的人脸数据位置和大小

    faces = face_detector.detectMultiScale(gray, scaleFactor=1.02, minNeighbors=3)for x, y, w, h in faces:    print(x, y, w, h) # 打印每一个检测到的数据位置和大小    cv.rectangle(image, (x, y), (x + w, y + h), color=(0, 255, 0), thickness=2)
    69b12b4f4c2a1001617ad4a4bb939bdf.png

    从大小中我们看到最大的两个矩形,刚好是人脸数据,其余都是脏数据,那么继续修改函数参数faces = face_detector.detectMultiScale(gray, scaleFactor=1.02, minNeighbors=3, minSize=(80, 80))

    76a5f252fd2cff8e615410d38a90e3e2.png

    检测视频中人脸

    视频就是一张一张的图片组成的,在视频的帧上面重复这个过程就能完成视频中的人脸检测了。视频读取OpenCV为我们提供了函数VideoCapture,参数可以是视频文件或者0(表示调用摄像头)

    import cv2 as cv# 人脸检测def face_detect_demo(image):    try:        # 将图片转换为灰度图        gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)        # 加载特征数据        face_detector = cv.CascadeClassifier(os.path.join(cv.data.haarcascades, 'haarcascade_frontalface_default.xml'))        faces = face_detector.detectMultiScale(gray)        for x, y, w, h in faces:            print(x, y, w, h)            cv.rectangle(image, (x, y), (x + w, y + h), color=(0, 255, 0), thickness=2)    except Exception as e:        passcap = cv.VideoCapture('人脸识别.mp4')while cap.isOpened():    flag, frame = cap.read()    face_detect_demo(frame)    cv.imshow('result', frame)    if ord('q') == cv.waitKey(5):        breakcap.realse()cv.destroyAllWindows()
    a11804a763f0829408748dc2723043fe.gif

    这个我们是做的人脸识别,怎么把爱好都识别了,这么先进吗?很显然这不太符合我们的要求,爱好只能藏在心里,你给我检测出来就不行了。所以我们必须要进行优化处理。OpenCV为我们提供了一个机器学习的小模块,我们可以训练它,让它只识别我们需要的部分,不要乱猜测。

    训练数据

    训练数据就是我们把一些图片交给训练模型,让模型熟悉她,这样它就能更加准确的识别相同的图片。训练的数据一般我们可以从网上搜索:人脸识别数据库,或者从视频中保存美帧的数据作为训练集。所有的人脸识别算法在他们的train()函数中都有两个参数:图像数组和标签数组。这些标签标示进行识别时候的人脸ID,根据ID可以知道被识别的人是谁。

    获取训练集

    从视频中每隔5帧截取一个图片,保存成图片

    import cv2cap = cv2.VideoCapture('人脸识别.mp4')number = 100count = 1while cap.isOpened() and number > 0:    flag, frame = cap.read()    if not flag:        break    if count % 5 == 0:        # 按照视频图像中人脸的大体位置进行裁剪,只取人脸部分        img = frame[70:280, 520:730]        cv2.imwrite('data/{}.png'.format(number), img)        number -= 1    count += 1cap.release()cv2.destroyAllWindows()
    ffc5e9a06284c9f46e33cc765df8ab64.png

    使用LBPH训练模型

    def getImageAndLabels(path_list):    faces = []    ids = []    image_paths = [os.path.join(path_list, f) for f in os.listdir(path_list) if f.endswith('.png')]    face_detector = cv.CascadeClassifier(os.path.join(cv.data.haarcascades, 'haarcascade_frontalface_default.xml'))    for image in image_paths:        img = cv.imread(image)        gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)        faces = face_detector.detectMultiScale(gray)        _id = int(os.path.split(image)[1].split('.')[0])        for x, y, w, h in faces:            faces.append(gray[y:y+h, x:x+w])            ids.append(_id)    return faces, idsfaces, ids = getImageAndLabels('data')# 训练recognizer = cv.face.LBPHFaceRecognizer_create()recognizer.train(faces, np.array(ids))# 保存训练特征recognizer.write('trains/trains.yml')

    基于LBPH的人脸识别

    LBPH将检测到的人脸分为小单元,并将其与模型中的对应单元进行比较,对每个区域的匹配值产生一个直方图。调整后的区域中调用predict函数,该函数返回两个元素的数组,第一个元素是所识别的个体标签,第二个元素是置信度评分。所有的算法都有一个置信度评分阈值,置信度评分用来衡量图像与模型中的差距,0表示完全匹配。LBPH有一个好的识别参考值要低于50。基本步骤为:

    • cv.VideoCapture读取视频
    • Haar算法检测人脸数据
    • 基于LBPH训练集得到准确人脸数据,并输出标记此人是谁
    • 按置信度取准确度高的人脸标记出来
    import osimport cv2 as cvdef face_detect_demo(image):    try:        global number        # 将图片转换为灰度图        gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)        # 加载特征数据        faces = face_detector.detectMultiScale(gray, scaleFactor=1.02, minNeighbors=3)        for x, y, w, h in faces:            # 获取置信度,大于80表示取值错误            _id, confidence = recognizer.predict(gray[y:y + h, x:x + w])            if confidence < 80:                cv.rectangle(image, (x, y), (x + w, y + h), color=(0, 255, 0), thickness=2)    except Exception as e:        passdef check_face():    cap = cv.VideoCapture('人脸识别.mp4')    while cap.isOpened():        flag, frame = cap.read()        if not flag:            break        face_detect_demo(frame)        cv.imshow('img', frame)        cv.waitKey(2)    cv.destroyAllWindows()if __name__ == '__main__':    # 加载训练数据文件    recognizer = cv.face.LBPHFaceRecognizer_create()    recognizer.read('trains/trains.yml')    face_detector = cv.CascadeClassifier(os.path.join(cv.data.haarcascades, 'haarcascade_frontalface_default.xml'))    check_face()
    b6743ce0feae9024162da5ee79016ce7.gif

    总结

    通过上面一步步的学习,你是不是对OpenCV人脸识别有个基本的认识了呢?但是我们也看到了,整个人脸识别的主要算法还是基于Haar,而且准确度并不是特别高,主要是会检测出很多非人脸的数据。LBPH是让我们给某个人脸进行标记,告诉我们他是谁,并没有提高实际的检测准确度。现在机器学习是非常火爆的,基于OpenCV的机器学习人脸识别也精确度也很高,下次我们在来对比几种机器学习人脸识别的库。

    展开全文
  • 使用虹软人脸识别API和Qt5的人脸识别  测试和使用了虹软的人脸API在QT5环境下设计了一个简单的人脸识别软件,实现了对人脸的跟踪和人脸识别。摄像头的控制以及图像格式的转换使用了Opencv,图像显示使用的是QT5的...

                                使用虹软人脸识别API和Qt5的人脸识别

           测试和使用了虹软的人脸API在QT5环境下设计了一个简单的人脸识别软件,实现了对人脸的跟踪和人脸识别。摄像头的控制以及图像格式的转换使用了Opencv,图像显示使用的是QT5的Qimage控件。下面是详细介绍

    1基本流程

          (1)加载存储的参考图像数据和图像标签,这里简单的使用图像的名字作为标签

          (2)使用虹软人脸识别API计算参考图像的人脸位置数据并存储

          (3)使用opencv  VideoCapture  类采集摄像头图像数据

          (2)采集的图像数据送入虹软人脸识别API 计算人脸位置,并和参考人脸数据计算相似距离,返回最相似的人脸标签

    2  Visual Studio 下构建Qt工程

    (1)工程目录如下图所示:

     

           图1 QT工程目录

    其中QtGuiApplication1.ui是界面文件,Header File文件夹中的amcomdef.h

    ammem.h  arcsoft_fsdk_face_detection.h  arcsoft_fsdk_face_recognition.h 

    asvloffscreen.h  merror.h 是从虹软库中拷贝的头文件未做任何修改

    FaceDiscern.h 和FaceDiscern.cpp是自定义的一个人脸识别类

    (2)工程属性配置

       点击工程属性->连接器->输入中出了QT5的库文件,添加opencv_world340d.lib

     

       点击工程属性-》VC++目录添加OpenCV的头文件和库文件的路径,其中包含目录添加opencv的头文件路径,库目录添加opencv的dll路径,如下图

     

    2工程类文件详解

         (1)QtGuiApplication1 ui类的源文件如下所示,其中Mat2QImage函数将opencv采集的图像数据转化为QImage支          持    的数据格式, VideoCapture 是Opencv用来操作摄像头的类,QImage用来显示采集的图像数据

    #pragma once
    #include <QtWidgets/QMainWindow>
    #include "ui_QtGuiApplication1.h"
    #include "qmessagebox.h"
    #include "opencv2/core/core.hpp"  
    #include "opencv2/highgui/highgui.hpp"  
    #include "opencv2/imgproc/imgproc.hpp"  
    #include <iostream>
    #include "qtimer.h"
    #include "FaceDiscern.h"
    #include "qrect.h"
    #include "qpainter.h"
    using namespace cv;
    using namespace std;
    class QtGuiApplication1 : public QMainWindow
    {
    	Q_OBJECT
    public:
    	QtGuiApplication1(QWidget *parent = Q_NULLPTR);
    	~QtGuiApplication1();
    	QImage  Mat2QImage(cv::Mat cvImg); //图像格式转换
    	QTimer  *timer;
    	Mat     frame;            //摄像头直接获得的数据
    	FaceDiscern *facediscern; //人脸识别类
    private:
    	Ui::QtGuiApplication1Class ui;
    	VideoCapture capture; //采集摄像头的数据
    	QImage qImg;          //展示图像的控件
    	//---槽函数 用作事件触发
    public slots :
    		void openVideo();
    		void stopVideo();
    		void nextFrame();
    
    };

    (2)QtGuiApplication1.cpp

         

    #include "QtGuiApplication1.h"
    
    QtGuiApplication1::QtGuiApplication1(QWidget *parent)
    	: QMainWindow(parent)
    {
    	ui.setupUi(this);
    	ui.image->setScaledContents(true);  //fit video to label area
    	facediscern = new FaceDiscern("F:\\trainimages");//加载参考图像数据和标签
    	facediscern->Train();//计算参考数据图像数据的人脸位置等
    	
    }
    
    QtGuiApplication1::~QtGuiApplication1()
    {
    	if (capture.isOpened())
    		capture.release();
    	delete(timer);
    }
    
    void QtGuiApplication1::openVideo()
    {
    	if (capture.isOpened())
    		capture.release();     //decide if capture is already opened; if so,close it
    	capture.open(0);           //open the default camera
    	if (capture.isOpened())
    	{
    		double  rate = capture.get(CV_CAP_PROP_FPS);
    		capture >> frame;  //获得摄像头图像数据
    		if (!frame.empty())
    		{
    			QImage  image = Mat2QImage(frame); //将摄像头的图像数据转换为QImage支持的格式
    			this->ui.image->setPixmap(QPixmap::fromImage(image));
    
    			timer = new QTimer(this); //循环获得摄像头数据
    			connect(timer, SIGNAL(timeout()), this, SLOT(nextFrame()));
    			timer->start(40);
    		}
    	}
    }
    void QtGuiApplication1::stopVideo()
    {
    	if (capture.isOpened())
    	{
    		capture.release();
    	}
    }
    //循环获得摄像头数据
    void QtGuiApplication1::nextFrame()
    {
    	capture >> frame;
    	double  rate = capture.get(CV_CAP_PROP_FPS);
    	if (!frame.empty())
    	{
    		QImage  image = Mat2QImage(frame);
    		
            //通过人脸检测API获得人脸的位置并在Qimage上显示人脸框
    		QRect rect;
            //RecognizeFace识别人脸的位置并计算人脸所属的标签
    		string result = facediscern->RecognizeFace(&frame, rect);
            
    		static QTextCodec *codecForCStrings;
    		QString strQ = QString::fromLocal8Bit(result.c_str());
    		QString s1 = strQ;//这是在qlabel中显示中文的办法
    		this->ui.result->setText(s1); //在控件上显示人脸所属的标签
    
    		QPainter painter(&image);
    		// 设置画笔颜色
    		painter.setPen(QColor(255, 0, 0));
    		painter.drawRect(rect);//绘制人脸的框
    		this->ui.image->setPixmap(QPixmap::fromImage(image));
    
    	}
    
    }
    
    //将opencv 的cv::Mat 格式图像转换为QImage图像
    QImage  QtGuiApplication1::Mat2QImage(cv::Mat cvImg)
    {
    	if (cvImg.channels() == 3)                             //3 channels color image
    	{
    		cv::cvtColor(cvImg, cvImg, CV_BGR2RGB); //BGR 转为 RGB
    		qImg = QImage((const unsigned char*)(cvImg.data),
    			cvImg.cols, cvImg.rows,
    			cvImg.cols*cvImg.channels(),
    			QImage::Format_RGB888);
    	}
    	else if (cvImg.channels() == 1)                    //grayscale image
    	{
    		qImg = QImage((const unsigned char*)(cvImg.data),
    			cvImg.cols, cvImg.rows,
    			cvImg.cols*cvImg.channels(),
    			QImage::Format_Indexed8);
    	}
    	else
    	{
    		qImg = QImage((const unsigned char*)(cvImg.data),
    			cvImg.cols, cvImg.rows,
    			cvImg.cols*cvImg.channels(),
    			QImage::Format_RGB888);
    	}
    	return qImg;
    
    }

     (3) FaceDiscern.h

        FaceDiscern 是人脸识别的主类 执行了人脸位置检测和人脸相似度计算等功能

    #pragma once
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <Windows.h>
    #include <iostream>
    #include <vector>
    #include <string>
    #include <io.h>
    #include <map>
    #include "arcsoft_fsdk_face_recognition.h"
    #include "merror.h"
    #include "arcsoft_fsdk_face_detection.h"
    #include "opencv2/core/core.hpp"  
    #include "opencv2/highgui/highgui.hpp"  
    #include "opencv2/imgproc/imgproc.hpp" 
    #include "qrect.h"
    //动态载入人脸识别的API库 libarcsoft_fsdk_face_detection是人脸检测库
    //libarcsoft_fsdk_face_recognition.lib是人脸识别库
    #pragma comment(lib,"libarcsoft_fsdk_face_detection.lib")
    #pragma comment(lib,"./libarcsoft_fsdk_face_recognition.lib")
    using namespace cv;
    #define WORKBUF_SIZE        (40*1024*1024)
    
    class FaceDiscern
    {
    public:
    	FaceDiscern(std::string _trainpath);
    	~FaceDiscern();
        //将cv::Mat格式的图像转换为Bitmap
    	void ConvertMatToBitmap(cv::Mat *img, uint8_t **imageData, int *pWidth, int *pHeight);
        void  getFiles(std::string path, std::vector<std::string>& files, std::vector<std::string> &ownname);
    	void  Train();
    	bool  readBmp24(const char* path, uint8_t **imageData, int *pWidth, int *pHeight);
    	std::string  RecognizeFace(cv::Mat *img, QRect &rect);
         
        //APPID是从网站上注册的免费使用id 
        char APPID[45]  = "9aEAsHDYzzzWapX9rH9BZHhdBz8CPTfws4WuF5xdmgnf";
    	char SDKKey[45] = "61MrwdsfKaMT8cm41uKPQBdCm4rKMLSELtJqs12p7WoV";	//SDKKey
        char DETECTIONKKey[45] = "61MrwdsfKaMT8cm41uKPQBci7TocqKmAASGS7infomre";
    	std::string trainpath = "F:\\trainimages";
        MRESULT nRet ;
    	MHandle hEngine ;
    	MInt32  nScale ;
    	MInt32  nMaxFace ;
    	MByte  *pWorkMem;
    
    	std::vector<std::string>  trainfullfiles;//完整路径名
    	std::vector<std::string>  trainnamefiles;
    	std::string   *labels;
    	std::map<std::string, std::string> dicfilenametoname;
      
    	/* 初始化引擎和变量 */
    	MRESULT detectionnRet;
    	MHandle hdetectionEngine;
    	MInt32  ndetetionScale;
    	MInt32  ndetectionMaxFace ;
    	MByte   *pdetectionWorkMem;
    
    	int trainCount = 0;
    	LPAFR_FSDK_FACEMODEL  *trainfaceModels;
    
    	AFR_FSDK_FACEMODEL dectfaceModels;
    
    };

    (4)FaceDiscern.cpp

    #include "FaceDiscern.h"
    FaceDiscern::FaceDiscern(std::string _trainpath)
    {
    	nRet = MERR_UNKNOWN;
    	hEngine = nullptr;
    	nScale = 16;
    	nMaxFace = 10;
    	pWorkMem = (MByte *)malloc(WORKBUF_SIZE);
    
    	/* 初始化引擎和变量 */
    	 detectionnRet = MERR_UNKNOWN;
    	 hdetectionEngine = nullptr;
    	 ndetetionScale = 16;
    	 ndetectionMaxFace = 10;
    	 pdetectionWorkMem = (MByte *)malloc(WORKBUF_SIZE);
    	 dicfilenametoname.insert(std::pair<std::string, std::string>("bingbing.bmp", "冰冰女神"));
    	 dicfilenametoname.insert(std::pair<std::string, std::string>("fangfang.bmp", "村里有个姑娘叫小芳"));
    	 dicfilenametoname.insert(std::pair<std::string, std::string>("feifei.bmp", "刘亦菲"));
    	 dicfilenametoname.insert(std::pair<std::string, std::string>("huihui.bmp", "冷工"));
    	 dicfilenametoname.insert(std::pair<std::string, std::string>("shishi.bmp", "诗诗妹妹"));
    	 dicfilenametoname.insert(std::pair<std::string, std::string>("xiaxia.bmp", "天上掉下个林妹妹"));
    	 dicfilenametoname.insert(std::pair<std::string, std::string>("xudasong.bmp", "松哥"));
    	 dicfilenametoname.insert(std::pair<std::string, std::string>("likunpeng.bmp", "李工"));
    	 dicfilenametoname.insert(std::pair<std::string, std::string>("gaojianjun.bmp", "高建军"));
    	 dicfilenametoname.insert(std::pair<std::string, std::string>("liuzhen.bmp", "小鲜肉振哥"));
    	 dicfilenametoname.insert(std::pair<std::string, std::string>("liting.bmp", "女王婷姐"));
    	 dicfilenametoname.insert(std::pair<std::string, std::string>("wangxuetao.bmp", "雪涛"));
    	 dicfilenametoname.insert(std::pair<std::string, std::string>("guowei.bmp", "郭大侠")); 
    	 dicfilenametoname.insert(std::pair<std::string, std::string>("mingxin.bmp", "宝宝鸣新"));
    	this->trainpath = _trainpath;
    }
    
    
    FaceDiscern::~FaceDiscern()
    {
    	/* 释放引擎和内存 */
    	detectionnRet = AFD_FSDK_UninitialFaceEngine(hdetectionEngine);
    	if (detectionnRet != MOK)
    	{
    		fprintf(stderr, "UninitialFaceEngine failed , errorcode is %d \n", detectionnRet);
    	}
    	free(pdetectionWorkMem);
    
    	for (int i = 0; i < trainCount; i++)
    	{
    		if (trainfaceModels[i]->pbFeature != NULL)
    			free(trainfaceModels[i]->pbFeature);
    	}
    	nRet = AFR_FSDK_UninitialEngine(hEngine);
    	if (nRet != MOK)
    	{
    		fprintf(stderr, "UninitialFaceEngine failed , errorcode is %d \n", nRet);
    	}
    }
    
    //加载所有的参考图像和图像名字作为参考库
    void  FaceDiscern::getFiles(std::string path, std::vector<std::string>& files, std::vector<std::string> &ownname)
    {
    	/*files存储文件的路径及名称(eg.   C:\Users\WUQP\Desktop\test_devided\data1.txt)
    	4      ownname只存储文件的名称(eg.     data1.txt)*/
    	//文件句柄  
    	long long  hFile = 0;
    	//文件信息  
    	struct _finddata_t fileinfo;
    	std::string p;
    	if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1)
    	{
    		do
    		{
    			//如果是目录,迭代之  
    			//如果不是,加入列表  
    			if ((fileinfo.attrib &  _A_SUBDIR))
    			{  /*
    			   if(strcmp(fileinfo.name,".") != 0  &&  strcmp(fileinfo.name,"..") != 0)
    			   getFiles( p.assign(path).append("\\").append(fileinfo.name), files, ownname ); */
    			}
    			else
    			{
    				files.push_back(p.assign(path).append("\\").append(fileinfo.name));
    				ownname.push_back(fileinfo.name);
    			}
    		} while (_findnext(hFile, &fileinfo) == 0);
    		_findclose(hFile);
    	}
    
    
    }
    //将cv::Mat转换为Bitmap
    void  FaceDiscern::ConvertMatToBitmap(cv::Mat *img, uint8_t **imageData, int *pWidth, int *pHeight)
    {
    	//======建立位图信息 ===========
    	int width, height, depth, channel;
    	width = img->cols;
    	height = img->rows;
    	depth = img->depth();
    	channel = img->channels();
    	*pWidth = width; //图像宽。高
    	*pHeight = height;
    
    	int linebyte = width * channel;
    	*imageData = (uint8_t *)malloc(linebyte * (*pHeight));
    	for (int i = 0; i<height; i++) {
    		for (int j = 0; j<width; j++) {
    
    			*((*imageData) + i * width*channel + j * channel) = (*img).at<Vec3b>(i, j)[2];// (uint8_t)(*(img + i * width*channel + j * width + 2));
    			*((*imageData) + i * width*channel + j * channel + 1) = (*img).at<Vec3b>(i, j)[1];
    			*((*imageData) + i * width*channel + j * channel + 2) = (*img).at<Vec3b>(i, j)[0];
    		} // end of line                     
    	}
    }
    //从文件中读取图像并转化为bitmap
    bool FaceDiscern::readBmp24(const char* path, uint8_t **imageData, int *pWidth, int *pHeight)
    {
    	if (path == NULL || imageData == NULL || pWidth == NULL || pHeight == NULL)
    	{
    		return false;
    	}
    	FILE *fp = fopen(path, "rb");
    	if (fp == NULL)
    	{
    		return false;
    	}
    	fseek(fp, sizeof(BITMAPFILEHEADER), 0);
    	BITMAPINFOHEADER head;
    	fread(&head, sizeof(BITMAPINFOHEADER), 1, fp);
    	*pWidth = head.biWidth;
    	*pHeight = head.biHeight;
    	int biBitCount = head.biBitCount;
    	if (24 == biBitCount)
    	{
    		int lineByte = ((*pWidth) * biBitCount / 8 + 3) / 4 * 4;
    		*imageData = (uint8_t *)malloc(lineByte * (*pHeight));
    		uint8_t * data = (uint8_t *)malloc(lineByte * (*pHeight));
    		fseek(fp, 54, SEEK_SET);
    		fread(data, 1, lineByte * (*pHeight), fp);
    		for (int i = 0; i < *pHeight; i++)
    		{
    			for (int j = 0; j < *pWidth; j++)
    			{
    				memcpy((*imageData) + i * (*pWidth) * 3 + j * 3, data + (((*pHeight) - 1) - i) * lineByte + j * 3, 3);
    			}
    		}
    		free(data);
    	}
    	else
    	{
    		fclose(fp);
    		return false;
    	}
    	fclose(fp);
    	return true;
    }
    
    //加载所有的参考数据
    void FaceDiscern::Train()
    {
    	if (pWorkMem == nullptr)
    	{
    		return;
    	}
    	nRet = AFR_FSDK_InitialEngine(APPID, SDKKey, pWorkMem, WORKBUF_SIZE, &hEngine); //初始化引擎
    
    	if (nRet != MOK)
    	{
    		return;
    	}
    
    	getFiles(trainpath, trainfullfiles, trainnamefiles);
    	//生成训练数据 特征集合
    	
    	if (trainfullfiles.size() > 0)
    	{
            //参考图像数据的人脸特征和标签的存储
    		trainfaceModels = new LPAFR_FSDK_FACEMODEL[trainfullfiles.size()];
    		labels = new  std::string[trainfullfiles.size()];
    	}
    	else
    	{
    		return ;
    	}
    	for (int i = 0; i < trainfullfiles.size(); i++)
    	{
    		std::string filename = trainfullfiles[i];
    		/* 读取第一张静态图片信息,并保存到ASVLOFFSCREEN结构体 (以ASVL_PAF_RGB24_B8G8R8格式为例) */
    		ASVLOFFSCREEN offInput = { 0 };
    		offInput.u32PixelArrayFormat = ASVL_PAF_RGB24_B8G8R8;
    		offInput.ppu8Plane[0] = nullptr;
    		const char * path = filename.c_str();
    		readBmp24(path, (uint8_t**)&offInput.ppu8Plane[0], &offInput.i32Width, &offInput.i32Height);
    		if (!offInput.ppu8Plane[0])
    		{
    			fprintf(stderr, "fail to ReadBmp(%s)\n", path);
    			AFR_FSDK_UninitialEngine(hEngine);
    			free(pWorkMem);
    			continue ;
    		}
    		offInput.pi32Pitch[0] = offInput.i32Width * 3;
    		AFR_FSDK_FACEMODEL *faceModels = new AFR_FSDK_FACEMODEL();
    		{
    			AFR_FSDK_FACEINPUT faceInput;
    			//第一张人脸信息通过face detection\face tracking获得
    			faceInput.lOrient = AFR_FSDK_FOC_0;//人脸方向
    											   //人脸框位置
    			faceInput.rcFace.left = 0;
    			faceInput.rcFace.top = 0;
    			faceInput.rcFace.right = offInput.i32Width - 2;;
    			faceInput.rcFace.bottom = offInput.i32Height - 2;;
    			//提取第一张人脸特征
    			AFR_FSDK_FACEMODEL LocalFaceModels = { 0 };
    			nRet = AFR_FSDK_ExtractFRFeature(hEngine, &offInput, &faceInput, &LocalFaceModels);
    			if (nRet != MOK)
    			{
    				fprintf(stderr, "fail to Extract 1st FR Feature, error code: %d\n", nRet);
    			}
    			/* 拷贝人脸特征结果 */
    			faceModels->lFeatureSize = LocalFaceModels.lFeatureSize;
    			faceModels->pbFeature = (MByte*)malloc(faceModels->lFeatureSize);
    			memcpy(faceModels->pbFeature, LocalFaceModels.pbFeature, faceModels->lFeatureSize);
    		}
    		trainfaceModels[i] = faceModels;
    		labels[i] = trainnamefiles[i];
    		trainCount++;
    	}
    
    	if (pdetectionWorkMem == nullptr)
    	{
    		return;
    	}
    	//人脸检测engine
    	detectionnRet = AFD_FSDK_InitialFaceEngine(APPID, DETECTIONKKey, pdetectionWorkMem, WORKBUF_SIZE, &hdetectionEngine, AFD_FSDK_OPF_0_HIGHER_EXT, ndetetionScale, ndetectionMaxFace);
    	if (detectionnRet != MOK)
    	{
    		return;
    	}
    	
    }
    //简单的通过距离相似计算出最相似的参考图像
    std::string FaceDiscern::RecognizeFace(cv::Mat *img, QRect &rect)
    {
    	/* 读取静态图片信息,并保存到ASVLOFFSCREEN结构体 (以ASVL_PAF_RGB24_B8G8R8格式为例) */
    	/* 人脸检测 */
    
    	ASVLOFFSCREEN offInput = { 0 };
    	offInput.u32PixelArrayFormat = ASVL_PAF_RGB24_B8G8R8;
    	offInput.ppu8Plane[0] = nullptr;
    	ConvertMatToBitmap(img, (uint8_t**)&offInput.ppu8Plane[0], &offInput.i32Width, &offInput.i32Height);
    	if (!offInput.ppu8Plane[0])
    	{
    		return "";
    	}
    	offInput.pi32Pitch[0] = offInput.i32Width * 3;
    	LPAFD_FSDK_FACERES	FaceRes = nullptr;
    	detectionnRet = AFD_FSDK_StillImageFaceDetection(hdetectionEngine, &offInput, &FaceRes);
    	void *imgptr = offInput.ppu8Plane[0];
    	识别人脸信息
    	AFR_FSDK_FACEINPUT faceInput;
    	faceInput.lOrient = AFR_FSDK_FOC_0;//人脸方向							   //人脸框位置
    	faceInput.rcFace.left =FaceRes->rcFace[0].left;
    	faceInput.rcFace.top = FaceRes->rcFace[0].top;
    	faceInput.rcFace.right = FaceRes->rcFace[0].right;
    	faceInput.rcFace.bottom = FaceRes->rcFace[0].bottom;
    
    	rect.setLeft(FaceRes->rcFace[0].left);
    	rect.setTop(FaceRes->rcFace[0].top);
    	rect.setRight(FaceRes->rcFace[0].right);
    	rect.setBottom(FaceRes->rcFace[0].bottom);
    	//提取人脸特征
    	nRet = AFR_FSDK_ExtractFRFeature(hEngine, &offInput, &faceInput, &dectfaceModels);
    	free(imgptr);
    	
    	if (nRet != MOK)
    	{
    		return "";
    	}
    	float maxscore = -1.0;
    	int index = -1;
    	for (int i = 0; i < trainCount; i++)
    	{
    		MFloat  fSimilScore = 0.0f;
    		nRet = AFR_FSDK_FacePairMatching(hEngine, &dectfaceModels, trainfaceModels[i], &fSimilScore);
    		if (fSimilScore > maxscore)
    		{
    			maxscore = fSimilScore;
    			index = i;
    		}
    	}
    	if (index != -1)
    	{
    		double num = maxscore * 100.0;
    		std::string str;
    		char ctr[10];
    		_gcvt(num, 6, ctr);
    		str = ctr;
    		std::string nameresult = labels[index];
    		if (dicfilenametoname.find(nameresult) != dicfilenametoname.end())
    		{
    			nameresult = dicfilenametoname[nameresult];
    		}
    		return nameresult + "," + str;
    	}
    	//释放
    	if(dectfaceModels.lFeatureSize>0)
    	   free(dectfaceModels.pbFeature);
    
    	return "";
    }

     (3) 界面展示

           

     

    展开全文
  • 需求:现有VB6.0的项目需要实现人脸识别功能。 问题: 自身完成VB6.0人脸识别不行。故借助虹软SDK。虹软SDK不支持VB6.0,更没有Demo可看。所以下载C#2.2版本。 解决: 1.虹软SDK使用的是C#2.2, 已提取人脸特征放入...
  • opencv4.1实现人脸识别代码下载 MFC实现人脸识别,点击按钮打开图片,MFC控件显示Mat图片,点击按钮检测人脸和眼睛,并标注检测结果(使用VS2017开发)。
  • 知识背景:下载虹软人脸识别引擎下载地址: http://www.arcsoft.com.cn/ai/arcface.html目前虹软人脸识别引擎有3个平台,其中Windows与iOS是基于C++开发的,本文都是基于Windows版本下用C#实现人脸识别的,请大家...
  • C#人脸识别入门篇-Step ByStep人脸识别 引言 如今,基于人脸的技术和话题可以说是炙手可热,基于大数据和人工智能的人脸识别更是突破了我们的想象力的极限,如果应用中不能集成人脸识别,那就太跟不上潮流了。...
  • 《百度AI人脸识别与检测》专栏为项目专栏,从零到一,从无到有开发一个学生人脸识别签到系统;主要用到的技术有百度开放平台中的人脸检测、人脸识别、Python图形界面开发PyQt5、线程的管理、以及通过python调用百度...
  • C#人脸识别入门篇--提取人脸特征值及人脸识别

    万次阅读 多人点赞 2017-08-19 09:41:53
    人脸检测之后如何进行人脸识别人脸识别的算法复杂,如何能够在C#中使用,本文章将在人脸检测的基础上,讲解如何使用虹软人脸识别SDK完成人脸识别的功能的全过程。
  • vb人脸识别小程序

    2019-05-06 01:45:49
    vb人脸识别,很不错的一个人脸识别技术,大家看看上面的图像就知道大概功能了
  • 《百度AI人脸识别与检测》专栏为项目专栏,从零到一,从无到有开发一个学生人脸识别签到系统;主要用到的技术有百度开放平台中的人脸检测、人脸识别、Python图形界面开发PyQt5、线程的管理、以及通过python调用百度...
  • 人脸识别插件.zip

    2018-12-06 18:13:29
    人脸识别插件jquery.facedetection-master,很强大的人脸识别插件!!!快捷开发!!
  • 人脸识别项目总结

    万次阅读 多人点赞 2018-01-01 20:46:51
    这篇博客是记录如何将已有人脸识别算法的前提下,一步步搭建人脸识别系统,找人脸识别算法不用往下看了 作为一水硕,研究生两年就做了一个半成品的人脸识别演示项目,突然想写点什么给以后的自己看看。也许未来自己...
  • C# 人脸识别

    千次阅读 2018-10-21 21:01:50
    首先说明一下,该人脸识别算法不是用代码实现的,是调用微软云的人脸识别,此处仅仅叙述调用的方法,以及数据的处理。 话不多说,正文开始。 首先注册微软云的账户,在产品中查找“人脸”,获取账户的免费api使用...
  • delphi开发的离线人脸识别源代码。 基于lunxand控件 编译环境windows10 delphi 10.3.1(其他10.X版本也应该问题不大)
  • 人脸识别Demo解析C#

    2019-08-19 16:51:18
    人脸识别业界,通常由人脸识别提供商和人脸识别应用接入方组成,从头到尾研发人脸识别技术需要极强的专用技术知识和数学算法功底,对于大多数企业来说,选择人工智能AI公司现成的人脸识别技术引擎是一个比较适合的...
  • 人脸识别OCX.rar

    2020-07-14 11:35:19
    通过摄像头进行人脸识别,可在 vb 等其他语言中调用,本代码供大家学习,交流使用,交流使用,交流使用,交流使用,交流使用,交流使用,交流使用,交流使用,
  • Android使用OpenCV实现「人脸检测」和「人脸识别

    万次阅读 多人点赞 2016-07-06 19:28:42
    Android使用OpenCV实现「人脸检测」和「人脸识别」DEMOOpenCV+JavaCV实现人脸识别—————————-分割线———————————效果图 先上效果图,不好弄gif 在网上找了在Android平台上使用OpenCV相关的教程,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,087
精华内容 1,234
关键字:

下载人脸识别控件