逻辑:用灰度直方图并增加对比度来提高识别成功率;将灰度图中已经被识别的部分涂黑再进行下一次识别以防止多个分类器重复识别同一张人脸。
需先配置OpenCV。
C++代码:
#include <iostream>
#include <opencv2\opencv.hpp>
#include <opencv2\imgproc\types_c.h>
#include <opencv2\objdetect\objdetect.hpp>
#include <opencv2\calib3d\calib3d.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat image,image_gray; //定义两个Mat变量,用于存储每一帧的图像
int a=0;
string c = "9.png"; //图片路径
image = imread(c);
cvtColor(image, image_gray, CV_BGR2GRAY);//转为灰度图
equalizeHist(image_gray, image_gray);//直方图均衡化,增加对比度方便处理
CascadeClassifier face_cascade1; //载入分类器1
//加载分类训练器,OpenCv官方文档提供的xml文档,可以直接调用
//xml文档路径 opencv\sources\data\haarcascades
if (!face_cascade1.load("D:\\OpenCV\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml")) //需要将xml文档放在自己指定的路径下
{
cout << "Load haarcascade_frontalface_alt.xml failed!" << endl;
return 0;
}
CascadeClassifier face_cascade2; //载入分类器2
if (!face_cascade2.load("D:\\OpenCV\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt2.xml")) //需要将xml文档放在自己指定的路径下
{
cout << "Load haarcascade_frontalface_alt.xml failed!" << endl;
return 0;
}
//vector 是个类模板 需要提供明确的模板实参 vector<Rect>则是个确定的类 模板的实例化
vector<Rect> faceRect1;
vector<Rect> faceRect2;
//检测关于脸部位置
face_cascade1.detectMultiScale(image_gray,faceRect1);
a = a + faceRect1.size();
for (size_t i = 0; i < faceRect1.size(); i++)
{
rectangle(image, faceRect1[i], Scalar(0, 255, 0)); //用矩形画出检测到的位置
rectangle(image_gray, faceRect1[i], Scalar(0, 0, 0),-1,4); //在灰度图中涂黑
}
face_cascade2.detectMultiScale(image_gray, faceRect2);
for (size_t i = 0; i < faceRect2.size(); i++)
{
rectangle(image, faceRect2[i], Scalar(0, 0, 255)); //用矩形画出检测到的位置
}
a = a + faceRect2.size();
imshow("find", image); //显示当前帧
cout << "find " << a << " faces";
//imwrite(c,image);
waitKey(0);
return 0;
}
测试结果:
JAVA代码:
package FaceDetect;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.objdetect.CascadeClassifier;
public class FaceDetect {
public static void main(String[] args) {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
System.out.println("\nRunning FaceDetector");
String xmlPath1 = "D:\\workspace\\videoStreamDetector\\haarcascade_frontalface_alt.xml"; //分类器1
String xmlPath2 = "D:\\workspace\\videoStreamDetector\\haarcascade_frontalface_alt2.xml"; //分类器2
CascadeClassifier faceDetector1 = new CascadeClassifier(xmlPath1);
CascadeClassifier faceDetector2 = new CascadeClassifier(xmlPath2);
String imgPath = "30.png"; //图片路径
Mat image = Imgcodecs.imread(imgPath);
Mat image_gray=new Mat();
Imgproc.cvtColor(image, image_gray, Imgproc.COLOR_BGR2GRAY);
Imgproc.equalizeHist(image_gray,image_gray);
MatOfRect faceDetections1 = new MatOfRect();
faceDetector1.detectMultiScale(image_gray, faceDetections1);
int a=faceDetections1.toArray().length;
for (Rect rect : faceDetections1.toArray()) {
Imgproc.rectangle(image, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height),new Scalar(0, 255, 0));
Imgproc.rectangle(image_gray, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height),new Scalar(0, 0, 0),-1,4);
}
MatOfRect faceDetections2 = new MatOfRect();
faceDetector2.detectMultiScale(image_gray, faceDetections2);
a=a+faceDetections2.toArray().length;
for (Rect rect : faceDetections2.toArray()) {
Imgproc.rectangle(image, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height),new Scalar(0, 0, 255));
}
System.out.println(String.format("Detected %s faces",a));
String filename = "ouput.png";
System.out.println(String.format("Writing %s", filename));
Imgcodecs.imwrite(filename, image);
}
}
JAVA中没有imshow,所以只能通过imwrite保存结果图片来观察测试结果。
总结:利用同样的逻辑可用多个分类器对图像进行识别,提高识别到人脸的概率,缺点是所有分类器中错误识别的结果都会被返回,可以通过修改detectMultiScale的参数在一定程度上减少错误识别的情况。
C++人脸检测部分代码参考:OpenCv 之(图片人脸识别)和 (摄像头读入)
JAVA配置环境及部分代码参考:利用Java调用OpenCV进行人脸识别