该部分承接(一),将会实现视频图像的处理以及人脸的识别
目录
四、图像处理
为了减轻处理器的负担,使得程序运行更加流畅,并提高检测的准确率,我们需要将采集的图片进行灰度处理和均衡化处理。这需要用到两个函数:cvtColor和equalizeHist。这两个函数在官方文档的图像处理部分(imgproc. Image Processing)
1. cvtColor
该函数的官方接口为:
C++: void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0 )
Parameters: |
|
---|
所以我们需要再声明一个Mat类的对象来保存灰度图片,根据官方文档所说,将RGB图片转换成灰度图片可使用CV_RGB2GRAY,因此,代码为:
Mat grayImg;
cvtColor(img,grayImg,CV_BGR2GRAY); //灰度处理
2. equalizeHist
该函数的官方接口为:
C++: void equalizeHist(InputArray src, OutputArray dst)
同样,我们需要声明一个Mat类的对象来保存均衡化后的图片,代码为:
Mat equalizeImg;
equalizeHist(grayImg,equalizeImg); //均衡化处理
因此,该部分的完整代码为:
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
int main()
{
VideoCapture cap(0); // open the default camera
if(!cap.isOpened()) // check if we succeeded
{
cout<<"Camera open failed!"<<endl;
return -1;
}
cout<<"Camera open successfully!"<<endl;
Mat img;
Mat grayImg;
Mat equalizeImg;
for(;;)
{
cap >> img; // get a new img from camera
cvtColor(img, grayImg, CV_BGR2GRAY); //灰度处理
equalizeHist(grayImg,equalizeImg); //均衡化处理
imshow("video", equalizeImg); //在video窗口中展示图片
waitKey(40); //设置帧率(40ms读取一帧)
}
return 0;
}
值得注意的是,该部分使用了新的库文件,所以编译时需要加上-lopencv_imgproc,即
g++ main.cpp -o main -lopencv_highgui -lopencv_core -lopencv_imgproc
五、脸部识别
1. 导入训练文件
在官方文档的objdetect. Object Detection中,找到CascadeClassifier 。CascadeClassifier是opencv下objdetect模块中用来做目标检测的级联分类器的一个类,它可以帮助我们检测例如车牌、眼睛、人脸等物体。它的大概原理就是判别某个物体是否属于某个分类。以人脸为例,我们可以把眼睛、鼻子、眉毛、嘴巴等属性定义成一个分类器,如果检测到一个模型符合定义人脸的所有属性,那么就认为它是一个人脸。
我们需要实例化该分类器,并使用OpenCV训练好的文件,该文件在/usr/share/opencv/haarcascades/ 目录中,我们选择其中的面部识别的xml文件:haarcascade_frontalface_alt2.xml
相应代码为
CascadeClassifier classifier("/usr/share/opencv/haarcascades/haarcascade_frontalface_alt2.xml");
2. 绘制人脸框
接下来要想实现将人脸检测到,需要借助detectMultiScale函数,该函数的官方接口为:
C++: void CascadeClassifier::detectMultiScale(const Mat& image, vector<Rect>& objects, double scaleFactor=1.1, int minNeighbors=3, int flags=0, Size minSize=Size(), Size maxSize=Size())
根据函数说明,我们需要声明vector<Rect>, 其余参数均有默认值,在此不加以修改,则
Vector<Rect> faces;
classifier.detectMultiScale(equalizeImg, faces); //检测人脸并返回在facas中
接下来需要将得到的人脸框出来,显示在图像上。这需要使用rectangle函数,官方接口为
C++: void rectangle(Mat& img, Rect rec, const Scalar& color, int thickness=1, int lineType=8, int shift=0 )
根据函数说明,我们的代码为:
rectangle(equalizeImg, faces[0], Scalar(255,255,255));
因为1. 导入训练文件中使用了objdetect. Object Detection部分的函数,所以编译命令需要变为:
g++ main.cpp -o main -lopencv_highgui -lopencv_core -lopencv_imgproc -lopencv_objdetect
但是此时会出现一个问题,当运行程序后,一开始摄像头未检测到人脸时,程序会报错。这是因为,当未检测到人脸时,faces里为空,rectangle函数调用faces[0]时出现地址越界错误,因此需要加一个优化。
if(faces.size())
{
rectangle(equalizeImg, faces[0], Scalar(255,255,255));
}
else
cout<<"No face detected!"<<endl;
3. 截取人脸并转换格式
在该部分,我们需要将识别到的人脸截取出来,方便上传比对。
我们需要声明一个Mat对象,专门用于存放人脸图像,接下来将绘制出的人脸信息存放进去。
此外,我们需要将图像进行编码,这里需要使用imencode函数,官方接口为:
C++: bool imencode(const string& ext, InputArray img, vector<uchar>& buf, const vector<int>& params=vector<int>())
我们需要指定编码的格式为jpg,新定义一个存放编码后图片的容器vector<uchar>,该部分的代码为:
Mat faceImg;
vector<uchar> jpgBuf;
if(faces.size())
{
rectangle(equalizeImg, faces[0], Scalar(255,255,255));
faceImg = equalizeImg(faces[0]);
imencode(".jpg", faceImg, jpgBuf);
}
else
cout<<"No face detected!"<<endl;
所以,该部分目前为止的总代码为:
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
int main()
{
VideoCapture cap(0); // open the default camera
if(!cap.isOpened()) // check if we succeeded
{
cout<<"Camera open failed!"<<endl;
return -1;
}
cout<<"Camera open successfully!"<<endl;
Mat img;
Mat grayImg;
Mat equalizeImg;
vector<Rect> faces;
Mat faceImg;
vector<uchar> jpgBuf;
CascadeClassifier classifier("/usr/share/opencv/haarcascades/haarcascade_frontalface_alt2.xml");
for(;;)
{
cap >> img; // get a new img from camera
cvtColor(img, grayImg, CV_BGR2GRAY); //灰度处理
equalizeHist(grayImg,equalizeImg); //均衡化处理
classifier.detectMultiScale(equalizeImg, faces); //检测人脸并返回在facas中
if(faces.size())
{
rectangle(equalizeImg, faces[0], Scalar(255,255,255)); //绘制矩形框
faceImg = equalizeImg(faces[0]);
imencode(".jpg", faceImg, jpgBuf); //将图片编码为jpg格式后存到jpgBuf中
}
else
cout<<"No face detected!"<<endl;
imshow("video", equalizeImg); //在video窗口中展示图片
waitKey(40); //设置帧率(40ms读取一帧)
}
return 0;
}
重新编译运行即可