DeepFaceRecognition.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::DeepFaceRecognition
17  * @author Mirko Waechter (waechter at kit dot edu)
18  * @date 2017
19  * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20  * GNU General Public License
21  */
22 
23 #include "DeepFaceRecognition.h"
24 
25 #include <Eigen/Geometry>
26 
27 #include <SimoxUtility/algorithm/string/string_tools.h>
28 
32 
34 
36 
37 #include <Calibration/Calibration.h>
38 #include <Image/ImageProcessor.h>
39 #include <Image/IplImageAdaptor.h>
40 #include <Image/PrimitivesDrawer.h>
41 #include <Image/PrimitivesDrawerCV.h>
45 
46 using namespace armarx;
47 using namespace visionx;
48 
49 //void visionx::DeepFaceRecognition::onInitObjectLocalizerProcessor()
50 void
52 {
53  usingProxy("FaceRecognition");
54  usingProxy("LongtermMemory");
55  usingProxy(getProperty<std::string>("ImageProviderName").getValue());
56 
57 
58  offeringTopic("TextToSpeech");
59 }
60 
61 //void visionx::DeepFaceRecognition::onConnectObjectLocalizerProcessor()
62 void
64 {
65  getProxy(faceReg, "FaceRecognition");
66  getProxy(ltm, "LongtermMemory");
67  getProxy(imageProvider, getProperty<std::string>("ImageProviderName").getValue());
68  // auto calibration = imageProvider->getMonocularCalibration();
69 
70  // this->calibration.reset(visionx::tools::convert(imageProvider->getMonocularCalibration()));
71  this->calibration.reset(new CCalibration());
72  calibration->SetCameraParameters(
73  987.99, 956.82, 639.32, 415.64, 0, 0, 0, 0, Math3d::unit_mat, Math3d::zero_vec, 1280, 720);
74 
75  tts = getTopic<armarx::TextListenerInterfacePrx>("TextToSpeech");
76  if (!ltm->hasSegment(faceSegmentName))
77  {
78  faceSegmentPrx = memoryx::EntityMemorySegmentInterfacePrx::checkedCast(
79  ltm->addGenericSegment(faceSegmentName));
80  }
81  else
82  {
83  faceSegmentPrx =
84  memoryx::EntityMemorySegmentInterfacePrx::checkedCast(ltm->getSegment(faceSegmentName));
85  }
86 }
87 
89 DeepFaceRecognition::createPropertyDefinitions()
90 {
92  new DeepFaceRecognitionPropertyDefinitions(getConfigIdentifier()));
93 }
94 
95 memoryx::ObjectLocalizationResultList
96 visionx::DeepFaceRecognition::localizeObjectClasses(const memoryx::ObjectClassNameList& classes,
97  const Ice::Current&)
98 {
99  ARMARX_VERBOSE << deactivateSpam(10) << "Localizing: " << classes;
100  memoryx::ObjectLocalizationResultList result;
101  ARMARX_CHECK_EXPRESSION(faceReg);
102  ARMARX_CHECK_EXPRESSION(faceSegmentPrx);
103 
104  auto faceLocations = faceReg->calculateFaceLocations();
105  ARMARX_VERBOSE << deactivateSpam(10, std::to_string(faceLocations.size())) << "Found "
106  << faceLocations.size() << " faces";
107  auto agentName = getProperty<std::string>("AgentName").getValue();
108  auto cameraFrame = getProperty<std::string>("CameraFrameName").getValue();
109  for (visionx::FaceLocation faceLocation : faceLocations)
110  {
111  memoryx::EntityPtr oldFace =
112  memoryx::EntityPtr::dynamicCast(faceSegmentPrx->getEntityByName(faceLocation.label));
113  bool updateFaceMemory = true;
114  ARMARX_DEBUG << deactivateSpam(1) << "Rect: " << faceLocation.topLeft.e0 << ", "
115  << faceLocation.topLeft.e1 << ", " << faceLocation.bottomRight.e0 << ", "
116  << faceLocation.bottomRight.e1;
117  float centerX = (faceLocation.bottomRight.e0 + faceLocation.topLeft.e0) * 0.5f;
118  float centerY = (faceLocation.bottomRight.e1 + faceLocation.topLeft.e1) * 0.5f;
119  memoryx::ObjectLocalizationResult r;
120  r.objectClassName = "face";
121  r.instanceName = faceLocation.label;
123  r.orientation = new FramedOrientation(ori, cameraFrame, agentName);
124  Vec3d cameraCoords;
125  float faceHeightPixel = faceLocation.bottomRight.e1 - faceLocation.topLeft.e1;
126  float distance =
127  calibration->GetCameraParameters().focalLength.y * 160.f / (faceHeightPixel);
128  this->calibration->ImageToCameraCoordinates(
129  Vec2d{centerX, centerY}, cameraCoords, distance, false);
130  ARMARX_VERBOSE << deactivateSpam(1) << "Camera coordinates for " << faceLocation.label
131  << ": " << cameraCoords.x << ", " << cameraCoords.y
132  << " distance: " << distance << ", " << VAROUT(faceHeightPixel)
133  << VAROUT(centerX) << VAROUT(centerY);
134  r.position = new FramedPosition(
135  Eigen::Vector3f(cameraCoords.x, cameraCoords.y, distance), cameraFrame, agentName);
137  r.orientation = new FramedOrientation(id, cameraFrame, agentName);
138  r.recognitionCertainty = 0.7f;
139  Eigen::Vector3f cov(10, 10, 10000);
140  r.positionNoise =
141  new memoryx::MultivariateNormalDistribution(Eigen::Vector3f::Zero(), cov.asDiagonal());
142 
143  r.timeStamp = new armarx::TimestampVariant(faceLocation.timestamp);
144  result.push_back(r);
145  if (faceLocation.label == "Unknown")
146  {
147  continue;
148  }
149  if (oldFace && oldFace->hasAttribute("LastGreetingTime"))
150  {
151  VariantPtr updateTimeVariant =
152  VariantPtr::dynamicCast(oldFace->getAttribute("LastGreetingTime")->getValue());
153  ARMARX_CHECK_EXPRESSION(updateTimeVariant);
154  ARMARX_CHECK_EXPRESSION(updateTimeVariant->get<TimestampVariant>());
155  updateFaceMemory &=
156  updateTimeVariant->get<TimestampVariant>()->toTime() +
157  IceUtil::Time::secondsDouble(getProperty<float>("GreetAgainDelay").getValue()) <
159  }
160  auto face = oldFace ? oldFace : memoryx::Entity::CreateGenericEntity();
162  // int matchCounter = 0;
163  if (updateFaceMemory)
164  {
165  // if (oldFace && oldFace->hasAttribute("MatchCounter"))
166  // {
167  // bool lastLocalizationTooOld = false;
168  // if (oldFace->hasAttribute("UpdateTime"))
169  // {
170  // VariantPtr updateTimeVariant = VariantPtr::dynamicCast(oldFace->getAttribute("UpdateTime")->getValue());
171  // lastLocalizationTooOld &= updateTimeVariant->get<TimestampVariant>()->toTime() + IceUtil::Time::secondsDouble(10) > TimeUtil::GetTime();
172 
173  // }
174  // if (!lastLocalizationTooOld)
175  // {
176  // matchCounter = oldFace->getAttribute("MatchCounter")->getValue()->getInt();
177  // }
178  // }
179  // matchCounter++;
180  face->setName(faceLocation.label);
181 
182  face->putAttribute("ImagePosition", new armarx::Vector2(centerX, centerY));
183  face->putAttribute("UpdateTime", TimestampVariant::nowPtr());
184  // if (matchCounter >= getProperty<int>("FaceMatchCounter").getValue())
185  float prob = updateAndCheckFaceExistenceProbability(faceLocation);
186  ARMARX_INFO << deactivateSpam(1) << VAROUT(prob);
187  if (prob > getProperty<float>("GreetThreshold").getValue())
188 
189  {
190  auto tts_label = simox::alg::replace_all(faceLocation.label, "mirko", "mir ko");
191  face->putAttribute("LastGreetingTime", TimestampVariant::nowPtr());
192  tts->reportTextWithParams("Hello %1%.", {tts_label});
193  ARMARX_IMPORTANT << "Hello " << faceLocation.label;
194  // matchCounter = 0; // reset back to 0 so
195  }
196  }
197  // face->putAttribute("MatchCounter", matchCounter); //always update matchCounter, though matchCounter is only increased if LastGreetingTime is old (see GreetAgainDelay)
198  faceSegmentPrx->upsertEntityByName(faceLocation.label, face);
199  }
200  return result;
201 }
202 
203 float
204 visionx::DeepFaceRecognition::updateAndCheckFaceExistenceProbability(
205  const visionx::FaceLocation& faceLocation)
206 {
207  auto& timeConfList = faceConfidenceHistory[faceLocation.label];
208 
209  double filterRadius = getProperty<float>("FilterRadius").getValue(); // kind of seconds
210  double sigma = filterRadius / 2.5;
211  double sigmaSquare = sigma * sigma;
212  auto gaussianBellCurve = [&](double x) { return exp(-double((x) * (x)) / (sigmaSquare)); };
213 
214  auto now = IceUtil::Time::now();
215  // remove old entries
216  for (auto it = timeConfList.begin(); it != timeConfList.end();)
217  {
218  IceUtil::Time t = it->first;
219  // double confidence = it->second;
220  double tDiff = (t - now).toMilliSecondsDouble() * 0.001;
221  double weight = gaussianBellCurve(tDiff);
222  // ARMARX_INFO << VAROUT(tDiff) << VAROUT(weight) << t.toDateTime() + " " << now.toDateTime();
223  if (weight < 0.001)
224  {
225  it = timeConfList.erase(it);
226  }
227  else
228  {
229  it++;
230  }
231  }
232 
233  timeConfList.push_back(std::make_pair(now, faceLocation.confidence));
234  float sum = 0;
235  for (auto& timeConfPair : timeConfList)
236  {
237  IceUtil::Time t = timeConfPair.first;
238  double confidence = timeConfPair.second;
239  double tDiff = (t - now).toMilliSecondsDouble() * 0.001;
240  double weight = gaussianBellCurve(tDiff);
241  // ARMARX_INFO << VAROUT(confidence) << VAROUT(weight) << VAROUT(tDiff);
242  sum += confidence * weight;
243  }
244  ARMARX_INFO << VAROUT(sum);
245  return sum;
246 }
visionx::DeepFaceRecognition::localizeObjectClasses
memoryx::ObjectLocalizationResultList localizeObjectClasses(const memoryx::ObjectClassNameList &classes, const Ice::Current &) override
Definition: DeepFaceRecognition.cpp:96
ARMARX_VERBOSE
#define ARMARX_VERBOSE
Definition: Logging.h:187
GfxTL::Vec3d
VectorXD< 3, double > Vec3d
Definition: VectorXD.h:737
ARMARX_IMPORTANT
#define ARMARX_IMPORTANT
Definition: Logging.h:190
visionx
ArmarX headers.
Definition: OpenPoseStressTest.h:38
visionx::DeepFaceRecognition::onConnectComponent
void onConnectComponent() override
Pure virtual hook for the subclass.
Definition: DeepFaceRecognition.cpp:63
visionx::DeepFaceRecognition::onInitComponent
void onInitComponent() override
Pure virtual hook for the subclass.
Definition: DeepFaceRecognition.cpp:51
visionx::DeepFaceRecognitionPropertyDefinitions
Definition: DeepFaceRecognition.h:43
armarx::TimestampVariant
Definition: TimestampVariant.h:54
PersistentEntitySegment.h
memoryx::Entity::CreateGenericEntity
static EntityPtr CreateGenericEntity()
Creates an entity without any convenience getter/setter functions.
Definition: Entity.cpp:41
armarx::Vector2
The Vector2 class.
Definition: Pose.h:52
armarx::TimestampVariant::nowPtr
static TimestampVariantPtr nowPtr()
Definition: TimestampVariant.h:126
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
FramedPose.h
ARMARX_DEBUG
#define ARMARX_DEBUG
Definition: Logging.h:184
TimestampVariant.h
MemoryXCoreObjectFactories.h
DeepFaceRecognition.h
armarx::armem::Time
armarx::core::time::DateTime Time
Definition: forward_declarations.h:13
armarx::to_string
const std::string & to_string(const std::string &s)
Definition: StringHelpers.h:41
GfxTL::Vec2d
VectorXD< 2, double > Vec2d
Definition: VectorXD.h:736
armarx::TimeUtil::GetTime
static IceUtil::Time GetTime(TimeMode timeMode=TimeMode::VirtualTime)
Get the current time.
Definition: TimeUtil.cpp:42
CMakePackageFinder.h
ARMARX_CHECK_EXPRESSION
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
Definition: ExpressionException.h:73
armarx::VariantType::FramedOrientation
const VariantTypeId FramedOrientation
Definition: FramedPose.h:39
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:181
VAROUT
#define VAROUT(x)
Definition: StringHelpers.h:198
IceUtil::Handle< class PropertyDefinitionContainer >
MemoryXTypesObjectFactories.h
distance
double distance(const Point &a, const Point &b)
Definition: point.hpp:95
TypeMapping.h
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::VariantType::MultivariateNormalDistribution
const armarx::VariantTypeId MultivariateNormalDistribution
Definition: ProbabilityMeasures.h:40