从灰度图像中获取人脸的那段代码(已经转换为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;
}
我们在注释中解决了这个问题,但是为了以后参考。
事实上,这一行
// this line for the testing purposes only
model->predict(grayscale, label, confidence);
胜过
// Recognize current face.
m_model->predict(faceResized, label, confidence);
发生的原因是模型是用非裁剪的图像进行训练的,而检测器则对人脸进行了裁剪。
与其使用整幅图像与预测,来匹配输入,不如使用裁剪过的人脸来训练模型。