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 
42 using namespace armarx;
43 
44 void
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 
114 void
116 {
117  stereoMatcher->InitCameraParameters(getStereoCalibration(), false);
118 }
119 
120 void
122 {
123 
124  delete stereoMatcher;
125 }
126 
127 bool
129 {
130  return true;
131 }
132 
133 bool
135  const memoryx::GridFileManagerPtr& fileManager)
136 {
137  ///@TODO
138  throw std::logic_error{"bool armarx::FaceRecognition::addObjectClass not implemented yet"};
139 }
140 
141 memoryx::ObjectLocalizationResultList
142 armarx::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 =
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 
261 {
264 }
armarx::FaceRecognition::onExitObjectLocalizerProcessor
void onExitObjectLocalizerProcessor() override
Definition: FaceRecognition.cpp:121
GfxTL::Vec3d
VectorXD< 3, double > Vec3d
Definition: VectorXD.h:737
armarx::FaceRecognition::createPropertyDefinitions
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
Definition: FaceRecognition.cpp:260
armarx::FaceRecognition::addObjectClass
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.
Definition: FaceRecognition.cpp:134
index
uint8_t index
Definition: EtherCATFrame.h:59
armarx::CMakePackageFinder
The CMakePackageFinder class provides an interface to the CMake Package finder capabilities.
Definition: CMakePackageFinder.h:52
armarx::FaceRecognition::localizeObjectClasses
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.
Definition: FaceRecognition.cpp:142
ARMARX_FATAL
#define ARMARX_FATAL
Definition: Logging.h:199
IceInternal::Handle
Definition: forward_declarations.h:8
deactivateSpam
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
Definition: Logging.cpp:75
GfxTL::Identity
void Identity(MatrixXX< N, N, T > *a)
Definition: MatrixXX.h:570
armarx::FaceRecognition::onConnectObjectLocalizerProcessor
void onConnectObjectLocalizerProcessor() override
Definition: FaceRecognition.cpp:115
armarx::FaceRecognitionPropertyDefinitions
Definition: FaceRecognition.h:42
FaceRecognition.h
M_PI
#define M_PI
Definition: MathTools.h:17
FramedPose.h
armarx::FaceRecognition::onInitObjectLocalizerProcessor
void onInitObjectLocalizerProcessor() override
Definition: FaceRecognition.cpp:45
armarx::CMakePackageFinder::getDataDir
std::string getDataDir() const
Definition: CMakePackageFinder.h:194
MemoryXCoreObjectFactories.h
visionx::Point
Eigen::Vector3f Point
Definition: ObjectShapeClassification.h:70
max
T max(T t1, T t2)
Definition: gdiam.h:51
ARMARX_ERROR
#define ARMARX_ERROR
Definition: Logging.h:196
armarx::to_string
const std::string & to_string(const std::string &s)
Definition: StringHelpers.h:41
ARMARX_LOG
#define ARMARX_LOG
Definition: Logging.h:165
GfxTL::Vec2d
VectorXD< 2, double > Vec2d
Definition: VectorXD.h:736
armarx::FaceRecognition::initRecognizer
bool initRecognizer() override
Initializes segmentable recognition.
Definition: FaceRecognition.cpp:128
armarx::Component::getConfigIdentifier
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition: Component.cpp:79
CMakePackageFinder.h
armarx::VariantType::FramedOrientation
const VariantTypeId FramedOrientation
Definition: FramedPose.h:39
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:181
memoryx::GridFileManagerPtr
std::shared_ptr< GridFileManager > GridFileManagerPtr
Definition: AbstractEntityWrapper.h:33
armarx::ArmarXDataPath::addDataPaths
static void addDataPaths(const std::string &dataPathList)
Definition: ArmarXDataPath.cpp:554
IceUtil::Handle< class PropertyDefinitionContainer >
TypeMapping.h
armarx::ArmarXDataPath::getAbsolutePath
static bool getAbsolutePath(const std::string &relativeFilename, std::string &storeAbsoluteFilename, const std::vector< std::string > &additionalSearchPaths={}, bool verbose=true)
Definition: ArmarXDataPath.cpp:109
GfxTL::Matrix3f
MatrixXX< 3, 3, float > Matrix3f
Definition: MatrixXX.h:649
armarx::VariantType::FramedPosition
const VariantTypeId FramedPosition
Definition: FramedPose.h:38
armarx::PropertyDefinitionsPtr
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
Definition: forward_declarations.h:35
ArmarXDataPath.h
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27
armarx::split
std::vector< std::string > split(const std::string &source, const std::string &splitBy, bool trimElements=false, bool removeEmptyElements=false)
Definition: StringHelpers.cpp:38