OpenCV从图像中获取人脸,并通过模型进行预测。

问题描述 投票:0回答:1

从灰度图像中获取人脸的那段代码(已经转换为cv::Mat)工作起来很奇怪,我做错了什么?

// in initializer list 
model(cv::face::FisherFaceRecognizer::create())
// ....
const cv::Mat grayscale = cv::imread("photo_15.jpeg",cv::IMREAD_GRAYSCALE);

std::vector<cv::Rect> faceCandidates;
m_cascade.detectMultiScale(grayscale, faceCandidates);

uint32 label = -1;         
double confidence = 0.0;
// this line for the testing purposes only
model->predict(grayscale, label, confidence);

这个工作很好:标签指的是正确的人,置信度在10以内,但让我们继续这个函数代码。

for (auto &faceCandidateRegion : faceCandidates) {
    cv::Mat faceResized;
    // size_ is a member and contains 1280x720 for my case, equal to model trained photos. 
    cv::resize( cv::Mat(grayscale, faceCandidateRegion), faceResized, cv::Size(size_.width(), size_.height()));

    // Recognize current face.
    m_model->predict(faceResized, label, confidence);
// ... other processing 

这段代码绝对是错误的: 它总是产生错误的标签和信心,即使我使用训练照片集的识别照片也是约45-46K

任何知道我在这里做错了什么吗? 测试:我试着用fisher、eigen和lbph来执行这个测试,结果都是一样的错误。

更新:应用中的每个模型都是几个用户的组,其中每个用户由2-6张照片呈现,所以这也是我在模型中训练几个用户的原因。

这里是一段训练模型的代码。

std::size_t
Recognizer::extractFacesAndConvertGrayscale(const QByteArray &rgb888, std::vector<cv::Mat> &faces)
{
    cv::Mat frame = cv::imdecode(std::vector<char>{rgb888.cbegin(), rgb888.cend()}, cv::IMREAD_GRAYSCALE);
    std::vector<cv::Rect> faceCandidates;
    m_cascade.detectMultiScale(frame, faceCandidates);
    int label = 0;
    for(const auto &face : faceCandidates) {
        cv::Mat faceResized;
        cv::resize(cv::Mat{frame, face}, faceResized,
                   cv::Size(this->m_size.width(), this->m_size.height()));

        faces.push_back(faceResized);
    }

    return faceCandidates.size();
}

bool Recognizer::train(const std::vector<qint32> &labels, const std::vector<QByteArray> &rgb888s)
{
    if (labels.empty() || rgb888s.empty() || labels.size() != rgb888s.size())
        return false;

    std::vector<cv::Mat> mats = {};
    std::vector<int32_t> processedLabels = {};
    std::size_t i = 0;
    for(const QByteArray &data : rgb888s)
    {
        std::size_t count = this->extractFacesAndConvertGrayscale(data, mats);
        if (count)
            std::fill_n(std::back_inserter(processedLabels), count, labels[i++]);
    }
    m_model->train(mats, processedLabels);

    return true;
}
c++ opencv face-recognition
1个回答
1
投票

我们在注释中解决了这个问题,但是为了以后参考。

事实上,这一行

// this line for the testing purposes only
model->predict(grayscale, label, confidence);

胜过

// Recognize current face.
m_model->predict(faceResized, label, confidence);

发生的原因是模型是用非裁剪的图像进行训练的,而检测器则对人脸进行了裁剪。

与其使用整幅图像与预测,来匹配输入,不如使用裁剪过的人脸来训练模型。

  • 由于多尺度检测,分类器的执行与原始图像中人脸的大小无关;即图像中人脸的大小和位置成为不变因素。
  • 背景不会对分类产生干扰。原始输入的纵横比为16:9,所以至少图像的侧面会在描述符中产生噪声。
© www.soinside.com 2019 - 2024. All rights reserved.