1 说明
- 本文章基于opencv + VS2015 实现人脸检测
2 效果
- 可以直接打开摄像头对人脸进行识别,这些标识框也会跟随你的人脸移动。隐私问题,我这里对图片进行了识别。
3 相关类及函数介绍
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 <iostream>
#include <opencv2/opencv.hpp>
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<cv::Rect> 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<cv::Rect> 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<cv::Rect> 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);
}
}
}
- 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()
5 编译说明
-
编译前先安装opencv, cmake, Visual Studio 2015
-
我的opencv的安装目录(D:\opencv), 源码安装比较麻烦, 建议直接下载安装包进行安装。
-
目录结构
- src
- mian.cpp
- build_x64
- CMakeLists
- 编译命令(在build_x64目录下执行)
cmake -G "Visual Studio 14 2015 Win64" ..
cmake --build ./ --config Release
- 说明
- 编译成功后,将opencv\build\x64\vc15\bin下的opencv_world460.dll opencv_world460d.dll拷贝到生成的可执行程序目录下, 然后再运行程序。
- 下载的opencv安装包中只包含了64位的库, 如果需要32位的库可下载源代码去编译。
转载:https://blog.csdn.net/new9232/article/details/127288336