Java 和 haarcascade 面部和嘴巴检测 - 嘴巴作为鼻子
Java and haarcascade face and mouth detection - mouth as the nose
今天我开始测试在Java和OpenCv中检测微笑的项目。识别面部和嘴巴项目使用 haarcascade_frontalface_alt 和 haarcascade_mcs_mouth 但我不明白为什么在某些原因项目检测鼻子作为嘴巴。
我有两个方法:
private ArrayList<Mat> detectMouth(String filename) {
int i = 0;
ArrayList<Mat> mouths = new ArrayList<Mat>();
// reading image in grayscale from the given path
image = Highgui.imread(filename, Highgui.CV_LOAD_IMAGE_GRAYSCALE);
MatOfRect faceDetections = new MatOfRect();
// detecting face(s) on given image and saving them to MatofRect object
faceDetector.detectMultiScale(image, faceDetections);
System.out.println(String.format("Detected %s faces", faceDetections.toArray().length));
MatOfRect mouthDetections = new MatOfRect();
// detecting mouth(s) on given image and saving them to MatOfRect object
mouthDetector.detectMultiScale(image, mouthDetections);
System.out.println(String.format("Detected %s mouths", mouthDetections.toArray().length));
for (Rect face : faceDetections.toArray()) {
Mat outFace = image.submat(face);
// saving cropped face to picture
Highgui.imwrite("face" + i + ".png", outFace);
for (Rect mouth : mouthDetections.toArray()) {
// trying to find right mouth
// if the mouth is in the lower 2/5 of the face
// and the lower edge of mouth is above of the face
// and the horizontal center of the mouth is the enter of the face
if (mouth.y > face.y + face.height * 3 / 5 && mouth.y + mouth.height < face.y + face.height
&& Math.abs((mouth.x + mouth.width / 2)) - (face.x + face.width / 2) < face.width / 10) {
Mat outMouth = image.submat(mouth);
// resizing mouth to the unified size of trainSize
Imgproc.resize(outMouth, outMouth, trainSize);
mouths.add(outMouth);
// saving mouth to picture
Highgui.imwrite("mouth" + i + ".png", outMouth);
i++;
}
}
}
return mouths;
}
并检测微笑
private void detectSmile(ArrayList<Mat> mouths) {
trainSVM();
CvSVMParams params = new CvSVMParams();
// set linear kernel (no mapping, regression is done in the original feature space)
params.set_kernel_type(CvSVM.LINEAR);
// train SVM with images in trainingImages, labels in trainingLabels, given params with empty samples
clasificador = new CvSVM(trainingImages, trainingLabels, new Mat(), new Mat(), params);
// save generated SVM to file, so we can see what it generated
clasificador.save("svm.xml");
// loading previously saved file
clasificador.load("svm.xml");
// returnin, if there aren't any samples
if (mouths.isEmpty()) {
System.out.println("No mouth detected");
return;
}
for (Mat mouth : mouths) {
Mat out = new Mat();
// converting to 32 bit floating point in gray scale
mouth.convertTo(out, CvType.CV_32FC1);
if (clasificador.predict(out.reshape(1, 1)) == 1.0) {
System.out.println("Detected happy face");
} else {
System.out.println("Detected not a happy face");
}
}
}
示例:
为了那张照片
正确检测到这个山:
但在其他图片中
检测到鼻子
您认为问题是什么?
很可能它在你的照片上检测错了,因为面部的比例(与眼睛之间的距离相比,眼睛到嘴巴的距离太长)。使用haar检测器检测嘴巴和鼻子不是很稳定,因此算法通常使用人脸的几何模型,为每个面部特征选择最佳候选特征组合。如果没有找到候选嘴巴,某些实现甚至可以尝试根据眼睛预测嘴巴位置。
Haar 检测器并不是目前最新和最著名的特征检测器。尝试使用可变形零件模型实现。试试这个,他们有带有高效 C++ 优化函数的 matlab 代码:
https://www.ics.uci.edu/~xzhu/face/
今天我开始测试在Java和OpenCv中检测微笑的项目。识别面部和嘴巴项目使用 haarcascade_frontalface_alt 和 haarcascade_mcs_mouth 但我不明白为什么在某些原因项目检测鼻子作为嘴巴。 我有两个方法:
private ArrayList<Mat> detectMouth(String filename) {
int i = 0;
ArrayList<Mat> mouths = new ArrayList<Mat>();
// reading image in grayscale from the given path
image = Highgui.imread(filename, Highgui.CV_LOAD_IMAGE_GRAYSCALE);
MatOfRect faceDetections = new MatOfRect();
// detecting face(s) on given image and saving them to MatofRect object
faceDetector.detectMultiScale(image, faceDetections);
System.out.println(String.format("Detected %s faces", faceDetections.toArray().length));
MatOfRect mouthDetections = new MatOfRect();
// detecting mouth(s) on given image and saving them to MatOfRect object
mouthDetector.detectMultiScale(image, mouthDetections);
System.out.println(String.format("Detected %s mouths", mouthDetections.toArray().length));
for (Rect face : faceDetections.toArray()) {
Mat outFace = image.submat(face);
// saving cropped face to picture
Highgui.imwrite("face" + i + ".png", outFace);
for (Rect mouth : mouthDetections.toArray()) {
// trying to find right mouth
// if the mouth is in the lower 2/5 of the face
// and the lower edge of mouth is above of the face
// and the horizontal center of the mouth is the enter of the face
if (mouth.y > face.y + face.height * 3 / 5 && mouth.y + mouth.height < face.y + face.height
&& Math.abs((mouth.x + mouth.width / 2)) - (face.x + face.width / 2) < face.width / 10) {
Mat outMouth = image.submat(mouth);
// resizing mouth to the unified size of trainSize
Imgproc.resize(outMouth, outMouth, trainSize);
mouths.add(outMouth);
// saving mouth to picture
Highgui.imwrite("mouth" + i + ".png", outMouth);
i++;
}
}
}
return mouths;
}
并检测微笑
private void detectSmile(ArrayList<Mat> mouths) {
trainSVM();
CvSVMParams params = new CvSVMParams();
// set linear kernel (no mapping, regression is done in the original feature space)
params.set_kernel_type(CvSVM.LINEAR);
// train SVM with images in trainingImages, labels in trainingLabels, given params with empty samples
clasificador = new CvSVM(trainingImages, trainingLabels, new Mat(), new Mat(), params);
// save generated SVM to file, so we can see what it generated
clasificador.save("svm.xml");
// loading previously saved file
clasificador.load("svm.xml");
// returnin, if there aren't any samples
if (mouths.isEmpty()) {
System.out.println("No mouth detected");
return;
}
for (Mat mouth : mouths) {
Mat out = new Mat();
// converting to 32 bit floating point in gray scale
mouth.convertTo(out, CvType.CV_32FC1);
if (clasificador.predict(out.reshape(1, 1)) == 1.0) {
System.out.println("Detected happy face");
} else {
System.out.println("Detected not a happy face");
}
}
}
示例:
为了那张照片
正确检测到这个山:
但在其他图片中
检测到鼻子
您认为问题是什么?
很可能它在你的照片上检测错了,因为面部的比例(与眼睛之间的距离相比,眼睛到嘴巴的距离太长)。使用haar检测器检测嘴巴和鼻子不是很稳定,因此算法通常使用人脸的几何模型,为每个面部特征选择最佳候选特征组合。如果没有找到候选嘴巴,某些实现甚至可以尝试根据眼睛预测嘴巴位置。
Haar 检测器并不是目前最新和最著名的特征检测器。尝试使用可变形零件模型实现。试试这个,他们有带有高效 C++ 优化函数的 matlab 代码: https://www.ics.uci.edu/~xzhu/face/