added additionalInfo in faceRecognition
This commit is contained in:
@@ -948,6 +948,14 @@ namespace cv
|
|||||||
// Deserializes this object from a given cv::FileStorage.
|
// Deserializes this object from a given cv::FileStorage.
|
||||||
virtual void load(const FileStorage& fs) = 0;
|
virtual void load(const FileStorage& fs) = 0;
|
||||||
|
|
||||||
|
// Sets additions information as pairs label - info.
|
||||||
|
virtual void setLabelsInfo(const std::map<int, string>& additionalInfo) = 0;
|
||||||
|
|
||||||
|
// Gets string information by label
|
||||||
|
virtual string getLabelInfo(const int label) = 0;
|
||||||
|
|
||||||
|
// Gets labels by string
|
||||||
|
virtual vector<int> getLabelsByString(const string str) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
CV_EXPORTS_W Ptr<FaceRecognizer> createEigenFaceRecognizer(int num_components = 0, double threshold = DBL_MAX);
|
CV_EXPORTS_W Ptr<FaceRecognizer> createEigenFaceRecognizer(int num_components = 0, double threshold = DBL_MAX);
|
||||||
|
@@ -18,6 +18,43 @@
|
|||||||
#include "precomp.hpp"
|
#include "precomp.hpp"
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
|
struct LabelInfo
|
||||||
|
{
|
||||||
|
LabelInfo():label(-1), value("") {}
|
||||||
|
LabelInfo(int _label, std::string _value): label(_label), value(_value) {}
|
||||||
|
std::string value;
|
||||||
|
int label;
|
||||||
|
void write(cv::FileStorage& fs) const
|
||||||
|
{
|
||||||
|
fs << "{" << "label" << label << "value" << value << "}";
|
||||||
|
}
|
||||||
|
void read(const cv::FileNode& node)
|
||||||
|
{
|
||||||
|
label = (int)node["label"];
|
||||||
|
value = (std::string)node["value"];
|
||||||
|
}
|
||||||
|
friend std::ostream& operator<<(std::ostream& out, const LabelInfo& info);
|
||||||
|
};
|
||||||
|
|
||||||
|
static void write(cv::FileStorage& fs, const std::string&, const LabelInfo& x)
|
||||||
|
{
|
||||||
|
x.write(fs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void read(const cv::FileNode& node, LabelInfo& x, const LabelInfo& default_value = LabelInfo())
|
||||||
|
{
|
||||||
|
if(node.empty())
|
||||||
|
x = default_value;
|
||||||
|
else
|
||||||
|
x.read(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& out, const LabelInfo& info)
|
||||||
|
{
|
||||||
|
out << "{ label = " << info.label << ", " << "value = " << info.value << "}";
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
namespace cv
|
namespace cv
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -98,7 +135,6 @@ inline vector<_Tp> remove_dups(const vector<_Tp>& src) {
|
|||||||
return elems;
|
return elems;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Turk, M., and Pentland, A. "Eigenfaces for recognition.". Journal of
|
// Turk, M., and Pentland, A. "Eigenfaces for recognition.". Journal of
|
||||||
// Cognitive Neuroscience 3 (1991), 71–86.
|
// Cognitive Neuroscience 3 (1991), 71–86.
|
||||||
class Eigenfaces : public FaceRecognizer
|
class Eigenfaces : public FaceRecognizer
|
||||||
@@ -111,6 +147,7 @@ private:
|
|||||||
Mat _eigenvectors;
|
Mat _eigenvectors;
|
||||||
Mat _eigenvalues;
|
Mat _eigenvalues;
|
||||||
Mat _mean;
|
Mat _mean;
|
||||||
|
std::map<int, string> _labelsInfo;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using FaceRecognizer::save;
|
using FaceRecognizer::save;
|
||||||
@@ -147,6 +184,15 @@ public:
|
|||||||
// See FaceRecognizer::save.
|
// See FaceRecognizer::save.
|
||||||
void save(FileStorage& fs) const;
|
void save(FileStorage& fs) const;
|
||||||
|
|
||||||
|
// Sets additions information as pairs label - info.
|
||||||
|
void setLabelsInfo(const std::map<int,string>& labelsInfo);
|
||||||
|
|
||||||
|
// Gets additional information by label
|
||||||
|
string getLabelInfo(const int label);
|
||||||
|
|
||||||
|
// Gets labels by string
|
||||||
|
std::vector<int> getLabelsByString(const string str);
|
||||||
|
|
||||||
AlgorithmInfo* info() const;
|
AlgorithmInfo* info() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -164,6 +210,7 @@ private:
|
|||||||
Mat _mean;
|
Mat _mean;
|
||||||
vector<Mat> _projections;
|
vector<Mat> _projections;
|
||||||
Mat _labels;
|
Mat _labels;
|
||||||
|
std::map<int, string> _labelsInfo;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using FaceRecognizer::save;
|
using FaceRecognizer::save;
|
||||||
@@ -202,6 +249,15 @@ public:
|
|||||||
// See FaceRecognizer::save.
|
// See FaceRecognizer::save.
|
||||||
void save(FileStorage& fs) const;
|
void save(FileStorage& fs) const;
|
||||||
|
|
||||||
|
// Sets additions information as pairs label - info.
|
||||||
|
void setLabelsInfo(const std::map<int,string>& labelsInfo);
|
||||||
|
|
||||||
|
// Gets additional information by label
|
||||||
|
string getLabelInfo(const int label);
|
||||||
|
|
||||||
|
// Gets labels by string
|
||||||
|
std::vector<int> getLabelsByString(const string str);
|
||||||
|
|
||||||
AlgorithmInfo* info() const;
|
AlgorithmInfo* info() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -222,6 +278,7 @@ private:
|
|||||||
|
|
||||||
vector<Mat> _histograms;
|
vector<Mat> _histograms;
|
||||||
Mat _labels;
|
Mat _labels;
|
||||||
|
std::map<int, string> _labelsInfo;
|
||||||
|
|
||||||
// Computes a LBPH model with images in src and
|
// Computes a LBPH model with images in src and
|
||||||
// corresponding labels in labels, possibly preserving
|
// corresponding labels in labels, possibly preserving
|
||||||
@@ -287,6 +344,15 @@ public:
|
|||||||
// See FaceRecognizer::save.
|
// See FaceRecognizer::save.
|
||||||
void save(FileStorage& fs) const;
|
void save(FileStorage& fs) const;
|
||||||
|
|
||||||
|
// Sets additions information as pairs label - info.
|
||||||
|
void setLabelsInfo(const std::map<int,string>& labelsInfo);
|
||||||
|
|
||||||
|
// Gets additional information by label
|
||||||
|
string getLabelInfo(const int label);
|
||||||
|
|
||||||
|
// Gets labels by string
|
||||||
|
std::vector<int> getLabelsByString(const string str);
|
||||||
|
|
||||||
// Getter functions.
|
// Getter functions.
|
||||||
int neighbors() const { return _neighbors; }
|
int neighbors() const { return _neighbors; }
|
||||||
int radius() const { return _radius; }
|
int radius() const { return _radius; }
|
||||||
@@ -423,6 +489,17 @@ void Eigenfaces::load(const FileStorage& fs) {
|
|||||||
// read sequences
|
// read sequences
|
||||||
readFileNodeList(fs["projections"], _projections);
|
readFileNodeList(fs["projections"], _projections);
|
||||||
fs["labels"] >> _labels;
|
fs["labels"] >> _labels;
|
||||||
|
const FileNode& fn = fs["info"];
|
||||||
|
if (fn.type() == FileNode::SEQ)
|
||||||
|
{
|
||||||
|
_labelsInfo.clear();
|
||||||
|
for (FileNodeIterator it = fn.begin(); it != fn.end();)
|
||||||
|
{
|
||||||
|
LabelInfo item;
|
||||||
|
it >> item;
|
||||||
|
_labelsInfo.insert(std::make_pair(item.label, item.value));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Eigenfaces::save(FileStorage& fs) const {
|
void Eigenfaces::save(FileStorage& fs) const {
|
||||||
@@ -434,6 +511,34 @@ void Eigenfaces::save(FileStorage& fs) const {
|
|||||||
// write sequences
|
// write sequences
|
||||||
writeFileNodeList(fs, "projections", _projections);
|
writeFileNodeList(fs, "projections", _projections);
|
||||||
fs << "labels" << _labels;
|
fs << "labels" << _labels;
|
||||||
|
fs << "info" << "[";
|
||||||
|
for (std::map<int, string>::const_iterator it = _labelsInfo.begin(); it != _labelsInfo.end(); it++)
|
||||||
|
fs << LabelInfo(it->first, it->second);
|
||||||
|
fs << "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
void Eigenfaces::setLabelsInfo(const std::map<int,string>& labelsInfo)
|
||||||
|
{
|
||||||
|
_labelsInfo = labelsInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
string Eigenfaces::getLabelInfo(const int label)
|
||||||
|
{
|
||||||
|
if(_labelsInfo.count(label) > 0)
|
||||||
|
return _labelsInfo[label];
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<int> Eigenfaces::getLabelsByString(const string str)
|
||||||
|
{
|
||||||
|
vector<int> labels;
|
||||||
|
for(std::map<int,string>::const_iterator it = _labelsInfo.begin(); it != _labelsInfo.end(); it++)
|
||||||
|
{
|
||||||
|
size_t found = (it->second).find(str);
|
||||||
|
if(found != string::npos)
|
||||||
|
labels.push_back(it->first);
|
||||||
|
}
|
||||||
|
return labels;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -544,6 +649,17 @@ void Fisherfaces::load(const FileStorage& fs) {
|
|||||||
// read sequences
|
// read sequences
|
||||||
readFileNodeList(fs["projections"], _projections);
|
readFileNodeList(fs["projections"], _projections);
|
||||||
fs["labels"] >> _labels;
|
fs["labels"] >> _labels;
|
||||||
|
const FileNode& fn = fs["info"];
|
||||||
|
if (fn.type() == FileNode::SEQ)
|
||||||
|
{
|
||||||
|
_labelsInfo.clear();
|
||||||
|
for (FileNodeIterator it = fn.begin(); it != fn.end();)
|
||||||
|
{
|
||||||
|
LabelInfo item;
|
||||||
|
it >> item;
|
||||||
|
_labelsInfo.insert(std::make_pair(item.label, item.value));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// See FaceRecognizer::save.
|
// See FaceRecognizer::save.
|
||||||
@@ -556,6 +672,34 @@ void Fisherfaces::save(FileStorage& fs) const {
|
|||||||
// write sequences
|
// write sequences
|
||||||
writeFileNodeList(fs, "projections", _projections);
|
writeFileNodeList(fs, "projections", _projections);
|
||||||
fs << "labels" << _labels;
|
fs << "labels" << _labels;
|
||||||
|
fs << "info" << "[";
|
||||||
|
for (std::map<int, string>::const_iterator it = _labelsInfo.begin(); it != _labelsInfo.end(); it++)
|
||||||
|
fs << LabelInfo(it->first, it->second);
|
||||||
|
fs << "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
void Fisherfaces::setLabelsInfo(const std::map<int,string>& labelsInfo)
|
||||||
|
{
|
||||||
|
_labelsInfo = labelsInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
string Fisherfaces::getLabelInfo(const int label)
|
||||||
|
{
|
||||||
|
if(_labelsInfo.count(label) > 0)
|
||||||
|
return _labelsInfo[label];
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<int> Fisherfaces::getLabelsByString(const string str)
|
||||||
|
{
|
||||||
|
vector<int> labels;
|
||||||
|
for(std::map<int,string>::const_iterator it = _labelsInfo.begin(); it != _labelsInfo.end(); it++)
|
||||||
|
{
|
||||||
|
size_t found = (it->second).find(str);
|
||||||
|
if(found != string::npos)
|
||||||
|
labels.push_back(it->first);
|
||||||
|
}
|
||||||
|
return labels;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -743,6 +887,17 @@ void LBPH::load(const FileStorage& fs) {
|
|||||||
//read matrices
|
//read matrices
|
||||||
readFileNodeList(fs["histograms"], _histograms);
|
readFileNodeList(fs["histograms"], _histograms);
|
||||||
fs["labels"] >> _labels;
|
fs["labels"] >> _labels;
|
||||||
|
const FileNode& fn = fs["info"];
|
||||||
|
if (fn.type() == FileNode::SEQ)
|
||||||
|
{
|
||||||
|
_labelsInfo.clear();
|
||||||
|
for (FileNodeIterator it = fn.begin(); it != fn.end();)
|
||||||
|
{
|
||||||
|
LabelInfo item;
|
||||||
|
it >> item;
|
||||||
|
_labelsInfo.insert(std::make_pair(item.label, item.value));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// See FaceRecognizer::save.
|
// See FaceRecognizer::save.
|
||||||
@@ -754,6 +909,34 @@ void LBPH::save(FileStorage& fs) const {
|
|||||||
// write matrices
|
// write matrices
|
||||||
writeFileNodeList(fs, "histograms", _histograms);
|
writeFileNodeList(fs, "histograms", _histograms);
|
||||||
fs << "labels" << _labels;
|
fs << "labels" << _labels;
|
||||||
|
fs << "info" << "[";
|
||||||
|
for (std::map<int, string>::const_iterator it = _labelsInfo.begin(); it != _labelsInfo.end(); it++)
|
||||||
|
fs << LabelInfo(it->first, it->second);
|
||||||
|
fs << "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
void LBPH::setLabelsInfo(const std::map<int,string>& labelsInfo)
|
||||||
|
{
|
||||||
|
_labelsInfo = labelsInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
string LBPH::getLabelInfo(const int label)
|
||||||
|
{
|
||||||
|
if(_labelsInfo.count(label) > 0)
|
||||||
|
return _labelsInfo[label];
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<int> LBPH::getLabelsByString(const string str)
|
||||||
|
{
|
||||||
|
vector<int> labels;
|
||||||
|
for(std::map<int,string>::const_iterator it = _labelsInfo.begin(); it != _labelsInfo.end(); it++)
|
||||||
|
{
|
||||||
|
size_t found = (it->second).find(str);
|
||||||
|
if(found != string::npos)
|
||||||
|
labels.push_back(it->first);
|
||||||
|
}
|
||||||
|
return labels;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LBPH::train(InputArrayOfArrays _in_src, InputArray _in_labels) {
|
void LBPH::train(InputArrayOfArrays _in_src, InputArray _in_labels) {
|
||||||
@@ -849,7 +1032,6 @@ int LBPH::predict(InputArray _src) const {
|
|||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Ptr<FaceRecognizer> createEigenFaceRecognizer(int num_components, double threshold)
|
Ptr<FaceRecognizer> createEigenFaceRecognizer(int num_components, double threshold)
|
||||||
{
|
{
|
||||||
return new Eigenfaces(num_components, threshold);
|
return new Eigenfaces(num_components, threshold);
|
||||||
|
@@ -39,20 +39,23 @@ static Mat toGrayscale(InputArray _src) {
|
|||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void read_csv(const string& filename, vector<Mat>& images, vector<int>& labels, char separator = ';') {
|
static void read_csv(const string& filename, vector<Mat>& images, vector<int>& labels, std::map<int, string>& labelsInfo, char separator = ';') {
|
||||||
std::ifstream file(filename.c_str(), ifstream::in);
|
std::ifstream file(filename.c_str(), ifstream::in);
|
||||||
if (!file) {
|
if (!file) {
|
||||||
string error_message = "No valid input file was given, please check the given filename.";
|
string error_message = "No valid input file was given, please check the given filename.";
|
||||||
CV_Error(CV_StsBadArg, error_message);
|
CV_Error(CV_StsBadArg, error_message);
|
||||||
}
|
}
|
||||||
string line, path, classlabel;
|
string line, path, classlabel, info;
|
||||||
while (getline(file, line)) {
|
while (getline(file, line)) {
|
||||||
stringstream liness(line);
|
stringstream liness(line);
|
||||||
getline(liness, path, separator);
|
getline(liness, path, separator);
|
||||||
getline(liness, classlabel);
|
getline(liness, classlabel, separator);
|
||||||
|
getline(liness, info, separator);
|
||||||
if(!path.empty() && !classlabel.empty()) {
|
if(!path.empty() && !classlabel.empty()) {
|
||||||
images.push_back(imread(path, 0));
|
images.push_back(imread(path, 0));
|
||||||
labels.push_back(atoi(classlabel.c_str()));
|
labels.push_back(atoi(classlabel.c_str()));
|
||||||
|
if(!info.empty())
|
||||||
|
labelsInfo.insert(std::make_pair(labels.back(), info));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -69,15 +72,17 @@ int main(int argc, const char *argv[]) {
|
|||||||
// These vectors hold the images and corresponding labels.
|
// These vectors hold the images and corresponding labels.
|
||||||
vector<Mat> images;
|
vector<Mat> images;
|
||||||
vector<int> labels;
|
vector<int> labels;
|
||||||
|
std::map<int, string> labelsInfo;
|
||||||
// Read in the data. This can fail if no valid
|
// Read in the data. This can fail if no valid
|
||||||
// input filename is given.
|
// input filename is given.
|
||||||
try {
|
try {
|
||||||
read_csv(fn_csv, images, labels);
|
read_csv(fn_csv, images, labels, labelsInfo);
|
||||||
} catch (cv::Exception& e) {
|
} catch (cv::Exception& e) {
|
||||||
cerr << "Error opening file \"" << fn_csv << "\". Reason: " << e.msg << endl;
|
cerr << "Error opening file \"" << fn_csv << "\". Reason: " << e.msg << endl;
|
||||||
// nothing more we can do
|
// nothing more we can do
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Quit if there are not enough images for this demo.
|
// Quit if there are not enough images for this demo.
|
||||||
if(images.size() <= 1) {
|
if(images.size() <= 1) {
|
||||||
string error_message = "This demo needs at least 2 images to work. Please add more images to your data set!";
|
string error_message = "This demo needs at least 2 images to work. Please add more images to your data set!";
|
||||||
@@ -111,6 +116,7 @@ int main(int argc, const char *argv[]) {
|
|||||||
// cv::createEigenFaceRecognizer(10, 123.0);
|
// cv::createEigenFaceRecognizer(10, 123.0);
|
||||||
//
|
//
|
||||||
Ptr<FaceRecognizer> model = createEigenFaceRecognizer();
|
Ptr<FaceRecognizer> model = createEigenFaceRecognizer();
|
||||||
|
model->setLabelsInfo(labelsInfo);
|
||||||
model->train(images, labels);
|
model->train(images, labels);
|
||||||
// The following line predicts the label of a given
|
// The following line predicts the label of a given
|
||||||
// test image:
|
// test image:
|
||||||
@@ -124,6 +130,8 @@ int main(int argc, const char *argv[]) {
|
|||||||
//
|
//
|
||||||
string result_message = format("Predicted class = %d / Actual class = %d.", predictedLabel, testLabel);
|
string result_message = format("Predicted class = %d / Actual class = %d.", predictedLabel, testLabel);
|
||||||
cout << result_message << endl;
|
cout << result_message << endl;
|
||||||
|
if( (predictedLabel == testLabel) && (model->getLabelInfo(predictedLabel) != "") )
|
||||||
|
cout << format("%d-th label's info: %s", predictedLabel, model->getLabelInfo(predictedLabel).c_str()) << endl;
|
||||||
// Sometimes you'll need to get/set internal model data,
|
// Sometimes you'll need to get/set internal model data,
|
||||||
// which isn't exposed by the public cv::FaceRecognizer.
|
// which isn't exposed by the public cv::FaceRecognizer.
|
||||||
// Since each cv::FaceRecognizer is derived from a
|
// Since each cv::FaceRecognizer is derived from a
|
||||||
|
Reference in New Issue
Block a user