OpenCV:为什么 Haar 分类器只检测到一张脸和一只眼睛?
OpenCV: Why does Haar classifier only detect one face and one eye?
我是 OpenCV 和 Haar 分类器的新手。我已经复制了下面的代码,它基本上可以正常工作,但它只有 returns 一张脸和一只眼睛。第二只眼睛和另一张脸呢?
const char[] eyesCascadeFilename = "haarcascade_eye.xml";
const char[] faceCascadeFilename = "haarcascade_frontalface_alt2.xml";
const int HaarOptions = CV_HAAR_DO_ROUGH_SEARCH;
// prepare the image for fast processing
Mat grayImage;
cvtColor(colorImage, grayImage, CV_BGR2GRAY);
equalizeHist(grayImage, grayImage);
// detect the faces on the image
std::vector<cv::Rect> faces;
faceCascade.detectMultiScale(grayImage, faces, 1.1, 2, HaarOptions, cv::Size(60, 60));
for (int i = 0; i < faces.size(); i++) {
// visualize the faces
cv::Point pt1(faces[i].x + faces[i].width, faces[i].y + faces[i].height);
cv::Point pt2(faces[i].x, faces[i].y);
cv::rectangle(colorImage, pt1, pt2, cvScalar(0, 255, 0, 0), 1, 8 ,0);
// detect the eyes within the facial roi
cv::Rect rect(faces[i].x, faces[i].y, faces[i].width, faces[i].height);
cv::Mat roi = grayImage(rect);
std::vector<cv::Rect> eyes;
// here's a problem ...:
eyesCascade.detectMultiScale(roi, eyes, 1.1, 2, HaarOptions, cv::Size(30, 30));
//eyesCascade.detectMultiScale(roi, eyes);
for (int i = 0; i < eyes.size(); i++) {
// visualize the eyes
cv::Point pt1(faces[i].x + eyes[i].x + eyes[i].width, faces[i].y + eyes[i].y + eyes[i].height);
cv::Point pt2(faces[i].x + eyes[i].x, faces[i].y + eyes[i].y);
cv::rectangle(colorImage, pt1, pt2, cvScalar(0, 210, 255, 0), 1, 8 ,0);
}
}
这是它的样子:
编辑
在您的代码中,在内部 for
循环中,您实际上是在创建一个与外部 for
循环 (i
) 的迭代变量同名的新变量. 因为它们在不同的范围内,这是允许的,并且内部范围内的变量"owns"名称。您将无法访问内部范围内的外部范围 i
。
for 循环声明本身是 for 循环范围的一部分,因此在第二个 i
.
的情况下算作内部范围的一部分
在你的例子中,这意味着你一次只能为一张给定的脸画一只眼睛,即使检测到两只眼睛也是如此。你的脸 (1) 够不到眼睛 (2)。您实际上很幸运您的代码没有崩溃:这只是因为您的面部和眼睛向量的大小相同 (2)。
在调试模式下你得到 eye.size == 1
可能只是因为在特定时刻算法只能检测到一只眼睛。在下一次迭代中,eye.size
很可能是 2。
所以,比方说,在你的内部循环中使用 int j = 0 来遍历眼睛向量,你会没事的!
编辑结束
这是我自己的这个算法的(工作)版本:
#include "FaceDetectionHaar.h"
FaceDetectionHaar::FaceDetectionHaar()
{
face_cascade_name = "haarcascade_frontalface_alt.xml";
eyes_cascade_name = "haarcascade_eye_tree_eyeglasses.xml";
if( !face_cascade.load( face_cascade_name ) ){ printf("--(!)Error loading\n");};
if( !eyes_cascade.load( eyes_cascade_name ) ){ printf("--(!)Error loading\n");};
}
void FaceDetectionHaar::execute(IplImage in)
{
Mat imgMat(&in);
std::vector<Rect> faces;
Mat frame_gray;
cvtColor( imgMat, frame_gray, CV_BGR2GRAY );
equalizeHist( frame_gray, frame_gray );
//-- Detect faces
face_cascade.detectMultiScale( frame_gray, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, Size(30, 30) );
for( int i = 0; i < faces.size(); i++ )
{
Point center( faces[i].x + faces[i].width*0.5, faces[i].y + faces[i].height*0.5 );
ellipse( imgMat, center, Size( faces[i].width*0.5, faces[i].height*0.5), 0, 0, 360, Scalar( 255, 0, 255 ), 4, 8, 0 );
Mat faceROI = frame_gray( faces[i] );
std::vector<Rect> eyes;
//-- In each face, detect eyes
eyes_cascade.detectMultiScale( faceROI, eyes, 1.1, 2, 0 |CV_HAAR_SCALE_IMAGE, Size(30, 30) );
for( int j = 0; j < eyes.size(); j++ )
{
Point center( faces[i].x + eyes[j].x + eyes[j].width*0.5, faces[i].y + eyes[j].y + eyes[j].height*0.5 );
int radius = cvRound( (eyes[j].width + eyes[i].height)*0.25 );
circle( imgMat, center, radius, Scalar( 255, 0, 0 ), 4, 8, 0 );
}
}
in = imgMat;
}
对于 ROI 部分,该代码比您的代码简单得多。也许使用 Haar 选项 CV_HAAR_SCALE_IMAGE
而不是 CV_HAAR_DO_ROUGH_SEARCH
会有所帮助。
此代码大部分是 OpenCV website 上给出的代码的副本。您也应该试试他们提供的 Haar Cascades xml 文件,包括面部和眼睛。
好吧,我现在也用我的算法解决了这个问题......非常尴尬,我对眼睛循环使用了相同的迭代变量"i",就像外部循环迭代面部一样......: -/ 奇怪的是编译器没有给我一个变量 "i" 已经定义的错误...!
这是工作代码:
const char[] eyesCascadeFilename = "haarcascade_eye.xml";
const char[] faceCascadeFilename = "haarcascade_frontalface_alt2.xml";
const int HaarOptions = CV_HAAR_DO_ROUGH_SEARCH;
// prepare the image for fast processing
Mat grayImage;
cvtColor(colorImage, grayImage, CV_BGR2GRAY);
equalizeHist(grayImage, grayImage);
// detect the faces on the image
std::vector<cv::Rect> faces;
faceCascade.detectMultiScale(grayImage, faces, 1.1, 2, HaarOptions, cv::Size(60, 60));
for (int i = 0; i < faces.size(); i++) {
// visualize the faces
cv::Point pt1(faces[i].x + faces[i].width, faces[i].y + faces[i].height);
cv::Point pt2(faces[i].x, faces[i].y);
cv::rectangle(colorImage, pt1, pt2, cvScalar(0, 255, 0, 0), 1, 8 ,0);
// detect the eyes within the facial roi
cv::Rect rect(faces[i].x, faces[i].y, faces[i].width, faces[i].height);
cv::Mat roi = grayImage(rect);
std::vector<cv::Rect> eyes;
// here's a problem ...:
eyesCascade.detectMultiScale(roi, eyes, 1.1, 2, HaarOptions, cv::Size(30, 30));
//eyesCascade.detectMultiScale(roi, eyes);
for (int j = 0; j < eyes.size(); j++) {
// visualize the eyes
cv::Point pt1(faces[i].x + eyes[j].x + eyes[j].width, faces[i].y + eyes[j].y + eyes[j].height);
cv::Point pt2(faces[i].x + eyes[j].x, faces[i].y + eyes[j].y);
cv::rectangle(colorImage, pt1, pt2, cvScalar(0, 210, 255, 0), 1, 8 ,0);
}
}
我是 OpenCV 和 Haar 分类器的新手。我已经复制了下面的代码,它基本上可以正常工作,但它只有 returns 一张脸和一只眼睛。第二只眼睛和另一张脸呢?
const char[] eyesCascadeFilename = "haarcascade_eye.xml";
const char[] faceCascadeFilename = "haarcascade_frontalface_alt2.xml";
const int HaarOptions = CV_HAAR_DO_ROUGH_SEARCH;
// prepare the image for fast processing
Mat grayImage;
cvtColor(colorImage, grayImage, CV_BGR2GRAY);
equalizeHist(grayImage, grayImage);
// detect the faces on the image
std::vector<cv::Rect> faces;
faceCascade.detectMultiScale(grayImage, faces, 1.1, 2, HaarOptions, cv::Size(60, 60));
for (int i = 0; i < faces.size(); i++) {
// visualize the faces
cv::Point pt1(faces[i].x + faces[i].width, faces[i].y + faces[i].height);
cv::Point pt2(faces[i].x, faces[i].y);
cv::rectangle(colorImage, pt1, pt2, cvScalar(0, 255, 0, 0), 1, 8 ,0);
// detect the eyes within the facial roi
cv::Rect rect(faces[i].x, faces[i].y, faces[i].width, faces[i].height);
cv::Mat roi = grayImage(rect);
std::vector<cv::Rect> eyes;
// here's a problem ...:
eyesCascade.detectMultiScale(roi, eyes, 1.1, 2, HaarOptions, cv::Size(30, 30));
//eyesCascade.detectMultiScale(roi, eyes);
for (int i = 0; i < eyes.size(); i++) {
// visualize the eyes
cv::Point pt1(faces[i].x + eyes[i].x + eyes[i].width, faces[i].y + eyes[i].y + eyes[i].height);
cv::Point pt2(faces[i].x + eyes[i].x, faces[i].y + eyes[i].y);
cv::rectangle(colorImage, pt1, pt2, cvScalar(0, 210, 255, 0), 1, 8 ,0);
}
}
这是它的样子:
编辑
在您的代码中,在内部 for
循环中,您实际上是在创建一个与外部 for
循环 (i
) 的迭代变量同名的新变量. 因为它们在不同的范围内,这是允许的,并且内部范围内的变量"owns"名称。您将无法访问内部范围内的外部范围 i
。
for 循环声明本身是 for 循环范围的一部分,因此在第二个 i
.
在你的例子中,这意味着你一次只能为一张给定的脸画一只眼睛,即使检测到两只眼睛也是如此。你的脸 (1) 够不到眼睛 (2)。您实际上很幸运您的代码没有崩溃:这只是因为您的面部和眼睛向量的大小相同 (2)。
在调试模式下你得到 eye.size == 1
可能只是因为在特定时刻算法只能检测到一只眼睛。在下一次迭代中,eye.size
很可能是 2。
所以,比方说,在你的内部循环中使用 int j = 0 来遍历眼睛向量,你会没事的!
编辑结束
这是我自己的这个算法的(工作)版本:
#include "FaceDetectionHaar.h"
FaceDetectionHaar::FaceDetectionHaar()
{
face_cascade_name = "haarcascade_frontalface_alt.xml";
eyes_cascade_name = "haarcascade_eye_tree_eyeglasses.xml";
if( !face_cascade.load( face_cascade_name ) ){ printf("--(!)Error loading\n");};
if( !eyes_cascade.load( eyes_cascade_name ) ){ printf("--(!)Error loading\n");};
}
void FaceDetectionHaar::execute(IplImage in)
{
Mat imgMat(&in);
std::vector<Rect> faces;
Mat frame_gray;
cvtColor( imgMat, frame_gray, CV_BGR2GRAY );
equalizeHist( frame_gray, frame_gray );
//-- Detect faces
face_cascade.detectMultiScale( frame_gray, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, Size(30, 30) );
for( int i = 0; i < faces.size(); i++ )
{
Point center( faces[i].x + faces[i].width*0.5, faces[i].y + faces[i].height*0.5 );
ellipse( imgMat, center, Size( faces[i].width*0.5, faces[i].height*0.5), 0, 0, 360, Scalar( 255, 0, 255 ), 4, 8, 0 );
Mat faceROI = frame_gray( faces[i] );
std::vector<Rect> eyes;
//-- In each face, detect eyes
eyes_cascade.detectMultiScale( faceROI, eyes, 1.1, 2, 0 |CV_HAAR_SCALE_IMAGE, Size(30, 30) );
for( int j = 0; j < eyes.size(); j++ )
{
Point center( faces[i].x + eyes[j].x + eyes[j].width*0.5, faces[i].y + eyes[j].y + eyes[j].height*0.5 );
int radius = cvRound( (eyes[j].width + eyes[i].height)*0.25 );
circle( imgMat, center, radius, Scalar( 255, 0, 0 ), 4, 8, 0 );
}
}
in = imgMat;
}
对于 ROI 部分,该代码比您的代码简单得多。也许使用 Haar 选项 CV_HAAR_SCALE_IMAGE
而不是 CV_HAAR_DO_ROUGH_SEARCH
会有所帮助。
此代码大部分是 OpenCV website 上给出的代码的副本。您也应该试试他们提供的 Haar Cascades xml 文件,包括面部和眼睛。
好吧,我现在也用我的算法解决了这个问题......非常尴尬,我对眼睛循环使用了相同的迭代变量"i",就像外部循环迭代面部一样......: -/ 奇怪的是编译器没有给我一个变量 "i" 已经定义的错误...!
这是工作代码:
const char[] eyesCascadeFilename = "haarcascade_eye.xml";
const char[] faceCascadeFilename = "haarcascade_frontalface_alt2.xml";
const int HaarOptions = CV_HAAR_DO_ROUGH_SEARCH;
// prepare the image for fast processing
Mat grayImage;
cvtColor(colorImage, grayImage, CV_BGR2GRAY);
equalizeHist(grayImage, grayImage);
// detect the faces on the image
std::vector<cv::Rect> faces;
faceCascade.detectMultiScale(grayImage, faces, 1.1, 2, HaarOptions, cv::Size(60, 60));
for (int i = 0; i < faces.size(); i++) {
// visualize the faces
cv::Point pt1(faces[i].x + faces[i].width, faces[i].y + faces[i].height);
cv::Point pt2(faces[i].x, faces[i].y);
cv::rectangle(colorImage, pt1, pt2, cvScalar(0, 255, 0, 0), 1, 8 ,0);
// detect the eyes within the facial roi
cv::Rect rect(faces[i].x, faces[i].y, faces[i].width, faces[i].height);
cv::Mat roi = grayImage(rect);
std::vector<cv::Rect> eyes;
// here's a problem ...:
eyesCascade.detectMultiScale(roi, eyes, 1.1, 2, HaarOptions, cv::Size(30, 30));
//eyesCascade.detectMultiScale(roi, eyes);
for (int j = 0; j < eyes.size(); j++) {
// visualize the eyes
cv::Point pt1(faces[i].x + eyes[j].x + eyes[j].width, faces[i].y + eyes[j].y + eyes[j].height);
cv::Point pt2(faces[i].x + eyes[j].x, faces[i].y + eyes[j].y);
cv::rectangle(colorImage, pt1, pt2, cvScalar(0, 210, 255, 0), 1, 8 ,0);
}
}