OpenCV получает лица из изображения и прогнозирует с помощью модели - PullRequest
0 голосов
/ 03 мая 2020

Часть кода, которая извлекает лица из изображения в градациях серого (уже преобразованного в 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-46К, даже если я использую фотографию для распознавания из набора обучающих фотографий

Есть идеи, что я здесь не так делаю? для тестирования: я пытался выполнить это с fisher, eigen и lbph с одинаковым неправильным результатом * обновление 1009 *

: каждая модель в приложении - это группа из нескольких пользователей, где каждый пользователь представлен 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;
}

1 Ответ

1 голос
/ 03 мая 2020

Мы решили это в комментариях, но для дальнейшего использования:

Тот факт, что эта строка

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

имела большую достоверность, чем

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

, произошел потому, что модель обучалась с необрезанными изображениями, в то время как детектор обрезает лица.

Вместо того, чтобы использовать целое изображение с предсказанием, чтобы соответствовать вводу, модель должна быть обучена с обрезанными лицами:

  • Классификатор работает независимо от размера лиц в исходном изображении из-за обнаружения нескольких масштабов; т.е. размер и положение граней на изображении становятся инвариантами.
  • Фон не мешает классификации. Исходный ввод имел соотношение сторон 16: 9, поэтому, по крайней мере, стороны изображения будут создавать шум в дескрипторах.
...