FaceRecognition.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * @package VisionX::ArmarXObjects::FaceRecognition
17 * @author Markus Grotz ( markus dot grotz at kit dot edu )
18 * @date 2016
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
23#include "FaceRecognition.h"
24
25#include <Eigen/Geometry>
26
27#include <SimoxUtility/algorithm/string/string_tools.h>
28
31
33
35
36#include <Image/ImageProcessor.h>
37#include <Image/IplImageAdaptor.h>
38#include <Image/PrimitivesDrawer.h>
39#include <Image/PrimitivesDrawerCV.h>
41
42using namespace armarx;
43
44void
46{
47
48 stereoMatcher = new CStereoMatcher();
49
50 model = cv::face::FisherFaceRecognizer(0, 1000.0);
51
52 armarx::CMakePackageFinder finder("VisionX");
54
55 std::string trainingDataPath = getProperty<std::string>("trainingDataPath").getValue();
56
57 if (!ArmarXDataPath::getAbsolutePath(trainingDataPath, trainingDataPath))
58 {
59 ARMARX_ERROR << "Could not find data file in ArmarXDataPath: " << trainingDataPath;
60 }
61
62 std::string classifierFileName = getProperty<std::string>("classifierFileName").getValue();
63
64 if (!ArmarXDataPath::getAbsolutePath(classifierFileName, classifierFileName))
65 {
66 ARMARX_ERROR << "Could not find data file in ArmarXDataPath: " << classifierFileName;
67 }
68
69 if (!std::filesystem::is_directory(trainingDataPath))
70 {
71 ARMARX_FATAL << "unable to load training model";
72 }
73
74 std::vector<std::string> fileNames;
75
76 for (auto iter = std::filesystem::directory_iterator(trainingDataPath);
77 iter != std::filesystem::directory_iterator();
78 ++iter)
79 {
80 fileNames.push_back(iter->path().string());
81 }
82
83 std::sort(fileNames.begin(), fileNames.end());
84
85 std::string currentLabel;
86
87 std::vector<cv::Mat> images;
88 std::vector<int> index;
89
90 for (std::string& fileName : fileNames)
91 {
92 const auto stem = std::filesystem::path(fileName).stem().string();
93 std::vector<std::string> strs = simox::alg::split(stem, "_");
94 std::string label = strs[0];
95
96 if (currentLabel != label)
97 {
98 labels[labels.size()] = label;
99 currentLabel = label;
100 }
101 images.push_back(cv::imread(fileName, CV_LOAD_IMAGE_GRAYSCALE));
102 index.push_back(labels.size() - 1);
103 }
104
105 ARMARX_LOG << "total number of classes: " << labels.size();
106
107 model->train(images, index);
108
109 faceImageSize = images[0].size();
110
111 classifier.load(classifierFileName);
112}
113
114void
116{
117 stereoMatcher->InitCameraParameters(getStereoCalibration(), false);
118}
119
120void
122{
123
124 delete stereoMatcher;
125}
126
127bool
129{
130 return true;
131}
132
133bool
135 const memoryx::GridFileManagerPtr& fileManager)
136{
137 ///@TODO
138 throw std::logic_error{"bool armarx::FaceRecognition::addObjectClass not implemented yet"};
139}
140
141memoryx::ObjectLocalizationResultList
142armarx::FaceRecognition::localizeObjectClasses(const std::vector<std::string>& objectClassNames,
143 CByteImage** cameraImages,
144 armarx::MetaInfoSizeBasePtr imageMetaInfo,
145 CByteImage** resultImages)
146{
147
148 memoryx::ObjectLocalizationResultList resultList;
149 cv::Mat result = cv::cvarrToMat(IplImageAdaptor::Adapt(resultImages[0]));
150
151
152 const cv::Mat tempRGBImage = cv::cvarrToMat(IplImageAdaptor::Adapt(cameraImages[0]));
153 cv::Mat original;
154 cv::cvtColor(tempRGBImage, original, CV_RGB2BGR);
155
156 cv::Mat gray;
157 cv::cvtColor(original, gray, CV_BGR2GRAY);
158
159 std::vector<cv::Rect_<int>> faces;
160 classifier.detectMultiScale(gray, faces, 1.05, 2);
161
162 const std::string refFrame = getProperty<std::string>("ReferenceFrameName").getValue();
163 const std::string agentName = getProperty<std::string>("AgentName").getValue();
164
165 ARMARX_INFO << deactivateSpam(5, std::to_string(faces.size())) << "found " << faces.size()
166 << " possible faces";
167 for (cv::Rect rect : faces)
168 {
169 cv::Mat face = gray(rect);
170
171 cv::Mat faceResized;
172 cv::resize(face, faceResized, faceImageSize, 1.0, 1.0, cv::INTER_CUBIC);
173
174 int predictedLabel = -1;
175 double predictedConfidence = 0.0;
176 model->predict(faceResized, predictedLabel, predictedConfidence);
177
178 std::string temp = labels[predictedLabel] + "=%0.1f";
179 std::string label = cv::format(temp.c_str(), predictedConfidence);
180
181
182 if (predictedLabel < 0)
183 {
184 cv::rectangle(result, rect, CV_RGB(0, 0, 255), 1);
185 }
186 else
187 {
188 cv::rectangle(result, rect, CV_RGB(0, 255, 0), 1);
189
190 int posX = std::max(rect.tl().x - 10, 0);
191 int posY = std::max(rect.tl().y - 10, 0);
192 putText(result,
193 label,
194 cv::Point(posX, posY),
195 cv::FONT_HERSHEY_PLAIN,
196 1.0,
197 CV_RGB(0, 255, 0),
198 2.0);
199
200 if (std::find(objectClassNames.begin(), objectClassNames.end(), label) !=
201 objectClassNames.end())
202 {
203 // todo see ObjectLearningByPushing/FeatureCalculation.cpp
204 CByteImage* imgRightGray = new CByteImage(
205 cameraImages[1]->width, cameraImages[1]->height, CByteImage::eGrayScale);
206 CByteImage* imgLeftGray = new CByteImage(
207 cameraImages[1]->width, cameraImages[1]->height, CByteImage::eGrayScale);
208 ::ImageProcessor::ConvertImage(cameraImages[0], imgLeftGray);
209 ::ImageProcessor::ConvertImage(cameraImages[1], imgRightGray);
210
211 Vec2d vCorrespondingPointRight;
212 Vec3d vPoint3D;
213 const int nDispMin = stereoMatcher->GetDisparityEstimate(10000);
214 const int nDispMax = stereoMatcher->GetDisparityEstimate(500);
215
216 // img l, img r, px, py, size of correlation window, min disparity, max disparity,
217 // corresponding point 2d, 3d point, correlation threshold, images are undistorted
218 int nMatchingResult = stereoMatcher->Match(imgLeftGray,
219 imgRightGray,
220 (int)rect.x + rect.width / 2.0,
221 (int)rect.y + rect.height / 2.0,
222 std::max(rect.width, rect.height),
223 nDispMin,
224 nDispMax,
225 vCorrespondingPointRight,
226 vPoint3D,
227 0.7f,
228 true);
229
230
231 delete imgRightGray;
232 delete imgLeftGray;
233
234 if (nMatchingResult >= 0)
235 {
236 Eigen::Vector3f position(vPoint3D.x, vPoint3D.y, vPoint3D.z);
237 Eigen::Matrix3f orientation =
238 Eigen::Matrix3f::Identity() *
239 Eigen::AngleAxisf(-M_PI, Eigen::Vector3f::UnitZ());
240
241 memoryx::ObjectLocalizationResult result;
242
243 result.position = new armarx::FramedPosition(position, refFrame, agentName);
244 result.orientation =
245 new armarx::FramedOrientation(orientation, refFrame, agentName);
246 result.recognitionCertainty = 1.0 / predictedConfidence;
247 result.positionNoise = calculateLocalizationUncertainty(position);
248 result.objectClassName = label;
249
250 resultList.push_back(result);
251 }
252 }
253 }
254 }
255
256 return resultList;
257}
258
uint8_t index
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
Definition Logging.cpp:75
#define M_PI
Definition MathTools.h:17
static bool getAbsolutePath(const std::string &relativeFilename, std::string &storeAbsoluteFilename, const std::vector< std::string > &additionalSearchPaths={}, bool verbose=true)
static void addDataPaths(const std::string &dataPathList)
The CMakePackageFinder class provides an interface to the CMake Package finder capabilities.
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition Component.cpp:90
Property< PropertyType > getProperty(const std::string &name)
bool initRecognizer() override
Initializes segmentable recognition.
void onExitObjectLocalizerProcessor() override
void onInitObjectLocalizerProcessor() override
memoryx::ObjectLocalizationResultList localizeObjectClasses(const std::vector< std::string > &objectClassNames, CByteImage **cameraImages, armarx::MetaInfoSizeBasePtr imageMetaInfo, CByteImage **resultImages) override
Add a memory entity representing the hand marker in order to set its properties.
void onConnectObjectLocalizerProcessor() override
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
bool addObjectClass(const memoryx::EntityPtr &objectClassEntity, const memoryx::GridFileManagerPtr &fileManager) override
Add a memory entity representing the hand marker in order to set its properties.
The FramedOrientation class.
Definition FramedPose.h:216
The FramedPosition class.
Definition FramedPose.h:158
memoryx::MultivariateNormalDistributionPtr calculateLocalizationUncertainty(Vec2d left_point, Vec2d right_point)
Calculate 3D uncertainty from two 2d points in left and right camera.
armarx::MetaInfoSizeBasePtr imageMetaInfo
CStereoCalibration * getStereoCalibration() const
Retrieve stereo calibration corresponding to image provider.
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_FATAL
The logging level for unexpected behaviour, that will lead to a seriously malfunctioning program and ...
Definition Logging.h:199
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:196
#define ARMARX_LOG
Definition Logging.h:165
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
IceInternal::Handle< Entity > EntityPtr
Typedef of EntityPtr as IceInternal::Handle<Entity> for convenience.
Definition Entity.h:45
std::shared_ptr< GridFileManager > GridFileManagerPtr