【问题标题】:OpenCV: Why does Haar classifier only detect one face and one eye?OpenCV:为什么 Haar 分类器只检测一张脸和一只眼睛?
【发布时间】:2015-05-24 06:25:48
【问题描述】:

我是 OpenCV 和 Haar 分类器的新手。我已经复制了以下代码,它基本上可以正常工作,但它只返回一张脸和一只眼睛。第二只眼睛和另一张脸呢?

    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);
        }

    }

它是这样的:

【问题讨论】:

  • 您是否尝试删除最小尺寸以进行检测?
  • 是的,我做到了。黄色矩形变小了,但它仍然只检测到一只或另一只眼睛,而不是同时检测到...
  • 是的,调试时eyes.size==1...
  • 使用detectMultiScale怎么样?
  • 这是什么意思?有没有其他选择?

标签: c++ opencv haar-classifier


【解决方案1】:

编辑

在您的代码中,在内部 for 循环中,您实际上是在创建一个与外部 for 循环 (i) 的迭代变量同名的新变量。 由于它们在不同的范围内,这是允许的,并且内部范围内的变量“拥有”名称。您将无法访问内部范围内的外部i

for 循环声明本身是 for 循环范围的一部分,因此在第二个 i 的情况下算作内部范围的一部分。

在您的情况下,这意味着您一次只能为给定的脸画一只眼睛,即使检测到两只眼睛也是如此。您无法通过眼睛(2)找到脸部(1)。你真的很幸运你的代码没有崩溃:这只是因为你的脸和眼睛向量的大小相同(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 文件,包括面部和眼睛。

【讨论】:

  • 不知道这些标志。 CV_HAAR_DO_ROUGH_SEARCH 可能是问题!!!
  • 我也这么认为。总之值得一试! :)
  • 我现在已将 Haar 选项设置为 0 和 -1,但仍然是同样的问题。我会试试你的算法......但这是一个非常奇怪的问题。
  • 好的,我现在用你的算法试了一下,效果很好:) 我想知道区别在哪里——我看不出来...用 (0 | CV_HAAR_SCALE_IMAGE) 作为标志尝试了我的在detectMultiScale,但没有成功。顺便提一句。你的算法比我的快一半,不要问我为什么......
  • @CTZStef:非常感谢您的详细解释!我不知道 C++ 以这种方式处理范围。我总是很高兴能学到新东西:)
【解决方案2】:

好的,我现在也用我的算法解决了这个问题...非常尴尬,我为眼睛循环使用了相同的迭代变量“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);
        }

    }

【讨论】:

  • 啊!是的!当然!现在我看到了!看看我上面编辑的答案......!
猜你喜欢
  • 2014-06-27
  • 1970-01-01
  • 2023-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-29
  • 2012-08-27
相关资源
最近更新 更多