• opencv实现人脸识别(c++实现)


    1 说明

    • 本文章基于opencv + VS2015 实现人脸检测

    2 效果

    请添加图片描述

    • 可以直接打开摄像头对人脸进行识别,这些标识框也会跟随你的人脸移动。隐私问题,我这里对图片进行了识别。

    3 相关类及函数介绍

    opencv中文文档

    3.1 cv::VideoCapture

    官方文档说明

    • 功能 :用于从视频文件、图像序列或摄像机捕获视频的类

    3.1.1 open

    • bool cv::VideoCapture::open(int index);
    • 功能 : 打开相机进行视频捕获
    • 参数介绍
      • index : 要打开的视频捕获设备的索引(0表示打开默认摄像机)

    3.1.2 read

    • bool cv::VideoCapture::read(OutputArray image);
    • 功能 : 抓取、解码并返回下一个视频帧
    • 参数介绍
      • image:图像视频帧在此处返回。如果未抓取任何帧,则图像将为空。

    3.1.3 release

    • cv::VideoCapture::release();
    • 功能 : 关闭视频文件或捕获设备

    3.2 cv::CascadeClassifier

    官方文档说明

    • 功能 : CascadeClassifier是opencv下objdetect模块中用来做目标检测的级联分类器的一个类, 早期opencv版本仅支持haar特征的目标检测,分别在opencv2.2和2.4之后开始支持LBP和HOG特征的目标检测.

    3.2.1 load

    • bool cv::CascadeClassifier::load(const String &filename);

    • 功能 : 从文件中加载级联分类器

    • 参数介绍

      • filename : 需要加载的分类器文件
    • opencv安装包中包含以及训练好的分类器文件(opencv\sources\data\haarcascades)

      • haarcascade_frontalface_alt.xml 检测人脸的分类器文件
      • haarcascade_eye.xml 检测眼睛的分类器文件
      • haarcascade_mcs_mouth.xml 检测嘴部的分类器文件(opencv安装包中没有携带, 可从github上去下载)
    • 分类器文件下载

    3.2.2 detectMultiScale

    • void cv::CascadeClassifier::detectMultiScale(const Mat& image, CV_OUT vector& objects, double scaleFactor = 1.1, int minNeighbors = 3, int flags = 0, Size minSize = Size(),Size maxSize = Size());
    • 功能 : 检测输入图像中不同大小的对象。检测到的对象将作为矩形列表返回
    • 参数介绍
      • image : 包含检测对象的图像的CV_8U类型矩阵
      • objects : 矩形的向量,其中每个矩形包含被检测的对象, 矩形可以部分位于原始图像之外
      • scaleFactor : 指定在每个图像缩放时的缩放比例. 默认为1.1 即每次搜索窗口扩大10%
      • minNeighbors : 指定每个候选矩形需要保留多少个相邻矩形(匹配成功所需要的周围矩形框的数目,每一个特征匹配到的区域都是一个矩形框,只有多个矩形框同时存在的时候,才认为是匹配成功,比如人脸,这个默认值是3)
      • flag
        • CASCADE_DO_CANNY_PRUNING : 利用canny边缘检测来排除一些边缘很少或者很多的图像区域
        • CASCADE_SCALE_IMAGE : 正常比例检测
        • CASCADE_FIND_BIGGEST_OBJECT : 只检测最大的物体
        • CASCADE_DO_ROUGH_SEARCH : 初略的检测
      • minSize : 目标区域最小范围
      • maxSize : 目标区域最大范围

    3.3 cv::waitKey

    • int cv::waitKey(int delay = 0);
    • 功能 : 等待按键按下
    • 参数介绍
      • delay : 超时时间, 单位为毫秒
    • 返回值 : 返回按下按键的值

    3.4 cv::imshow

    • void cv::imshow(const String &winname, InputArray mat);
    • 功能 : 将图片显示在窗口中,通过设备屏幕展现出来
    • 参数介绍
      • winname: 窗口名
      • mat:要显示的图片

    3.5 cv::destroyAllWindows

    • void cv::destroyAllWindows();
    • 功能 : 删除窗口

    3.6 cv::putText

    • void cv::putText(InputOutputArray img, const String& text, Point org, int fontFace, double fontScale, Scalar color, int thickness = 1, int lineType = LINE_8, bool bottomLeftOrigin = false);

    • 功能 : 给视频图像添加文字说明

    • 参数介绍

      • img : 需要添加文字说明的图形对象
      • text : 需要写入的文本内容
      • org : 第一个字符左下角坐标
      • fontFace : 字体类型
        • 衬线体就是有边角装饰的字体, 无衬线字体通常是机械和统一粗细的线条, 没有边角的装饰

        • FONT_HERSHEY_SIMPLEX : 正常大小的无衬线字体

        • FONT_HERSHEY_PLAIN : 小号无衬线字体

        • FONT_HERSHEY_DUPLEX : 正常大小的无衬线字体(比FONT_HERSHEY_SIMPLEX更复杂)

        • FONT_HERSHEY_COMPLEX : 正常大小的衬线字体

        • FONT_HERSHEY_TRIPLEX : 正常大小的衬线字体(比FONT_HERSHEY_COMPLEX更复杂)

        • FONT_HERSHEY_COMPLEX_SMALL : FONT_HERSHEY_COMPLEX的较小版本

        • FONT_HERSHEY_SCRIPT_SIMPLEX : 手写样式字体

        • FONT_HERSHEY_SCRIPT_COMPLEX : 更复杂的FONT_HERSHEY_SCRIPT_SIMPLEX变体

        • FONT_ITALIC : 斜体字体的标志

      • fontScale : 字体大小
      • color : 字体颜色
      • thickness : 字体粗细
      • lineType : 线型
        • LINE_4 : 4联通线型
        • LINE_8 : 8联通线型
        • LINE_AA : 抗锯齿线

    4 源代码

    • mian.cpp
    #include 
    #include 
    
    char* face_cascade_name = "D:\\opencv\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml";
    char* eyes_cascade_name = "D:\\opencv\\opencv\\sources\\data\\haarcascades\\haarcascade_eye.xml";
    char* mouth_cascade_name = "D:\\opencv\\opencv\\sources\\data\\haarcascades\\haarcascade_mcs_mouth.xml";
    
    void faceRecongize(cv::CascadeClassifier faceCascade, cv::CascadeClassifier eyesCascade, cv::CascadeClassifier mouthCascade, cv::Mat frame);
    
    int main(){
        cv::VideoCapture *videoCap = new cv::VideoCapture;
    
    	cv::CascadeClassifier faceCascade;
    	cv::CascadeClassifier eyesCascade;
    	cv::CascadeClassifier mouthCascade;
    
        // 加载脸部分类器文件
    	if (!faceCascade.load(face_cascade_name)) {
    		std::cout << "load face_cascade_name failed. " << std::endl;
    		return -1;
    	}
    
        // 加载眼睛部分分类器文件
    	if (!eyesCascade.load(eyes_cascade_name)) {
    		std::cout << "load eyes_cascade_name failed. " << std::endl;
    		return -1;
    	}
    
        // 加载嘴部分类器文件
    	if (!mouthCascade.load(mouth_cascade_name)) {
    		std::cout << "load mouth_cascade_name failed. " << std::endl;
    		return -1;
    	}
    
        // 打开摄像机
    	videoCap->open(0);
    
    
    	if (!videoCap->isOpened()) {
    		videoCap->release();
    		std::cout << "open camera failed"<< std::endl;
            return -1;
    	}
    
    	std::cout << "open camera success"<< std::endl;
    
        while(1){
    		cv::Mat frame;
    		//读取视频帧
    		videoCap->read(frame);
    
    		if (frame.empty()) {
    			videoCap->release();
    			return -1;
    		}
    
            //进行人脸识别
    		faceRecongize(faceCascade, eyesCascade, mouthCascade, frame);
    
            //窗口进行展示
            imshow("face", frame);
    
            //等待回车键按下退出程序
    		if (cv::waitKey(30) == 13) {
    			cv::destroyAllWindows();
    			return 0;
    		}
        }
    
        system("pause");
        return 0;
    }
    
    void faceRecongize(cv::CascadeClassifier faceCascade, cv::CascadeClassifier eyesCascade, cv::CascadeClassifier mouthCascade, cv::Mat frame) {
    	std::vector faces;
    
        // 检测人脸
    	faceCascade.detectMultiScale(frame, faces, 1.1, 2, 0 | cv::CASCADE_SCALE_IMAGE, cv::Size(30, 30));
    	for (int i = 0; i < faces.size(); i++) {
    		
            // 用椭圆画出人脸部分
            cv::Point center(faces[i].x + faces[i].width / 2, faces[i].y + faces[i].height / 2);
    		ellipse(frame, center, cv::Size(faces[i].width / 2, faces[i].height / 2), 0, 0, 360, cv::Scalar(255, 0, 255), 4, 8, 0);
    		
    		cv::Mat faceROI = frame(faces[i]);
    		std::vector eyes;
    
            // 检测眼睛
    		eyesCascade.detectMultiScale(faceROI, eyes, 1.1, 2, 0 | cv::CASCADE_SCALE_IMAGE, cv::Size(30, 30));
    		for (int j = 0; j < eyes.size(); j++)
    		{
                // 用圆画出眼睛部分
    			cv::Point eye_center(faces[i].x + eyes[j].x + eyes[j].width / 2, faces[i].y + eyes[j].y + eyes[j].height / 2);
    			int radius = cvRound((eyes[j].width + eyes[j].height)*0.25);
    			circle(frame, eye_center, radius, cv::Scalar(255, 0, 0), 4, 8, 0);
    		}
    
    		cv::Mat mouthROI = frame(faces[i]);
    		std::vector mouth;
    
            // 检测嘴部
    		mouthCascade.detectMultiScale(mouthROI, mouth, 1.1, 2, 0 | cv::CASCADE_SCALE_IMAGE, cv::Size(30, 30));
    		for (int k = 0; k < mouth.size(); k++)
    		{
                //用长方形画出嘴部
    			cv::Rect rect(faces[i].x + mouth[k].x, faces[i].y + mouth[k].y, mouth[k].width, mouth[k].height);
    			rectangle(frame, rect, cv::Scalar(0, 255, 0), 2, 8, 0);
    		}
    
            // 检测到两个眼睛和一个嘴巴, 可认为检测到有效人脸
    		if (eyes.size() >= 2 && mouth.size() >= 1) {
                
                // 人脸上方区域写字进行标识
    			cv::Point centerText(faces[i].x + faces[i].width / 2 - 40, faces[i].y - 20);
    			cv::putText(frame, "face", centerText, cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 0, 255), 2);
    		}
    
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • CMakeLists.txt
    cmake_minimum_required (VERSION 3.5)
    project (faceRecongize2015)
    
    MESSAGE(STATUS "PROJECT_SOURCE_DIR " ${PROJECT_SOURCE_DIR})
    SET(SRC_LISTS ${PROJECT_SOURCE_DIR}/src/main.cpp)
    
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
    
    # 配置头文件目录
    include_directories(${PROJECT_SOURCE_DIR}/src)
    include_directories("D:\\opencv\\opencv\\build\\include")
    include_directories("D:\\opencv\\opencv\\build\\include\\opencv2")
    
    # 设置不显示命令框
    if(MSVC)
    	set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")
    endif()
    
    # 添加库文件
    set(PRO_OPENCV_LIB "D:\\opencv\\opencv\\build\\x64\\vc15\\lib\\opencv_world460.lib" "D:\\opencv\\opencv\\build\\x64\\vc15\\lib\\opencv_world460.lib")
    
    IF(WIN32)
        # 生成可执行程序
    	ADD_EXECUTABLE(faceRecongize2015 ${SRC_LISTS})
    	# 链接库文件
        TARGET_LINK_LIBRARIES(faceRecongize2015 ${PRO_OPENCV_LIB})
    ENDIF()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    5 编译说明

    • 编译前先安装opencv, cmake, Visual Studio 2015

    • 我的opencv的安装目录(D:\opencv), 源码安装比较麻烦, 建议直接下载安装包进行安装。

    • opencv安装包下载

    • opencv源码下载

    • 目录结构

    - src
      - mian.cpp
    - build_x64
    - CMakeLists
    
    • 1
    • 2
    • 3
    • 4
    • 编译命令(在build_x64目录下执行)
    cmake -G "Visual Studio 14 2015 Win64" ..
    cmake --build ./ --config Release
    
    • 1
    • 2
    • 说明
      • 编译成功后,将opencv\build\x64\vc15\bin下的opencv_world460.dll opencv_world460d.dll拷贝到生成的可执行程序目录下, 然后再运行程序。
      • 下载的opencv安装包中只包含了64位的库, 如果需要32位的库可下载源代码去编译。
  • 相关阅读:
    高压流变仪用TESCOM ER5000压力控制系统的国产化替代方案
    《OpenDRIVE1.6规格文档》2
    开关电源模块 遥控开/关电路
    CAS号:143364-95-8,十三肽KKSRGDYMTMQIG
    Golang web 项目中实现自定义 recovery 中间件
    【Lua基础 第6章】 Lua 数组、Lua的错误处理、Lua 模块与包、元表(Metatable)和元方法
    Java中的异常基础知识
    Linux权限的认识
    Flink处理函数(一)
    创维光伏:坚持科技创新,构建中国式现代化光伏生态体系
  • 原文地址:https://blog.csdn.net/new9232/article/details/127288336