OpenCV 从图像中获取人脸并用模型进行预测
OpenCV get faces from image and predict with model
从灰度图像(已转换为 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);
发生的原因是模型是使用未裁剪的图像训练的,而检测器裁剪了面部。
为了匹配输入,而不是使用整个图像进行预测,模型应该使用裁剪的面孔进行训练:
- 由于多尺度检测,分类器的执行与原始图像中人脸的大小无关;即图像中人脸的大小和位置成为不变量。
- 背景不影响分类。原始输入具有 16:9 宽高比,因此至少图像的侧面会在描述符中产生噪声。
从灰度图像(已转换为 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);
发生的原因是模型是使用未裁剪的图像训练的,而检测器裁剪了面部。
为了匹配输入,而不是使用整个图像进行预测,模型应该使用裁剪的面孔进行训练:
- 由于多尺度检测,分类器的执行与原始图像中人脸的大小无关;即图像中人脸的大小和位置成为不变量。
- 背景不影响分类。原始输入具有 16:9 宽高比,因此至少图像的侧面会在描述符中产生噪声。