ObjectLocalizationSaliency.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 RobotComponents::ArmarXObjects::ObjectLocalizationSaliency
17 * @author David Schiebener (schiebener at kit dot edu)
18 * @author Markus Grotz ( markus dot grotz at kit dot edu )
19 * @date 2016
20 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
21 * GNU General Public License
22 */
23
25
28
30
31using namespace armarx;
32
33void
35{
36 usingProxy(getProperty<std::string>("ViewSelectionName").getValue());
37 usingTopic(getProperty<std::string>("ViewSelectionName").getValue() + "Observer");
38 usingProxy(getProperty<std::string>("RobotStateComponentName").getValue());
39 usingProxy(getProperty<std::string>("HeadIKUnitName").getValue());
40 usingProxy(getProperty<std::string>("WorkingMemoryName").getValue());
41 usingProxy(getProperty<std::string>("PriorKnowledgeName").getValue());
42
43 randomNoiseLevel = getProperty<float>("RandomNoiseLevel").getValue();
44
45 cameraFrameName = getProperty<std::string>("CameraFrameName").getValue();
46 headFrameName = getProperty<std::string>("HeadFrameName").getValue();
47 centralHeadTiltAngle = getProperty<float>("CentralHeadTiltAngle").getValue();
48
49 halfCameraOpeningAngle = getProperty<float>("HalfCameraOpeningAngle").getValue();
50 deviationFromCameraCenterFactor = 0.5f;
51
52 std::string graphFileName = "RobotAPI/ViewSelection/graph40k.gra";
53
54 armarx::CMakePackageFinder finder("RobotAPI");
56
57 if (ArmarXDataPath::getAbsolutePath(graphFileName, graphFileName))
58 {
59 saliencyEgosphereGraph = new CIntensityGraph(graphFileName);
60 ARMARX_VERBOSE << "Created egosphere graph with "
61 << saliencyEgosphereGraph->getNodes()->size() << "nodes";
62 graphLookupTable = new CGraphPyramidLookupTable(9, 18);
63 graphLookupTable->buildLookupTable(saliencyEgosphereGraph);
64 nodeVisitedForObject.resize(saliencyEgosphereGraph->getNodes()->size());
65
66 randomNoiseGraph = new CIntensityGraph(*saliencyEgosphereGraph);
67 randomNoiseGraph->set(0);
68 }
69 else
70 {
71 ARMARX_ERROR << "Could not find required graph file";
73 }
74
75 // this is robot model specific: offset from the used head coordinate system to the actual
76 // head center where the eyes are assumed to be located. Here it is correct for ARMAR-III
77 offsetToHeadCenter << 0, 0, 150;
79 this,
80 &ObjectLocalizationSaliency::process,
81 1000.f / getProperty<float>("UpdateFrequency").getValue(),
82 false,
83 "ViewSelectionCalculation",
84 false);
85 processorTask->setDelayWarningTolerance(2600);
86}
87
88void
90{
92 getProperty<std::string>("ViewSelectionName").getValue());
93 viewSelection = viewSelection->ice_compress(true);
95 getProperty<std::string>("RobotStateComponentName").getValue());
96
98 getProperty<std::string>("WorkingMemoryName").getValue());
100 getProperty<std::string>("PriorKnowledgeName").getValue());
101 objectInstancesProxy = memoryx::ObjectInstanceMemorySegmentBasePrx::uncheckedCast(
102 memoryProxy->getSegment("objectInstances"));
103 objectClassesProxy = memoryx::ObjectClassMemorySegmentBasePrx::uncheckedCast(
104 memoryProxy->getSegment("objectClasses"));
105
106 robot = RemoteRobot::createLocalClone(robotStateComponent);
107
108 auto objClassSegment = priorKnowledge->getObjectClassesSegment();
109 std::vector<std::string> ids = objClassSegment->getAllEntityIds();
110
111
112 for (std::string& id : ids)
113 {
114 memoryx::ObjectClassPtr objClass =
115 memoryx::ObjectClassPtr::dynamicCast(objClassSegment->getEntityById(id));
116
117 if (objClass)
118 {
120 objClass->addWrapper(new memoryx::EntityWrappers::ObjectRecognitionWrapper());
121
122 if (!wrapper->getRecognitionMethod().empty() &&
123 wrapper->getRecognitionMethod() != "<none>")
124 {
125 recognizableObjClasses[objClass->getName()] = objClass;
126 ARMARX_INFO << objClass->getName() << " has " << wrapper->getRecognitionMethod();
127 }
128 }
129 }
130
131 if (viewSelection->isEnabledAutomaticViewSelection())
132 {
134 }
135}
136
137void
143
144void
146{
147 delete graphLookupTable;
148 delete saliencyEgosphereGraph;
149 delete randomNoiseGraph;
150}
151
152void
153ObjectLocalizationSaliency::process()
154{
155 std::unique_lock<std::mutex> lock(mutex);
156
157 IceUtil::Time delta = next - armarx::TimeUtil::GetTime();
158 delta -= lastDiff;
159 delta -= IceUtil::Time::milliSeconds(50);
160
161 lock.unlock();
162
163 if (delta > IceUtil::Time::seconds(0))
164 {
165 TimeUtil::Sleep(delta);
166 }
167
168
169 IceUtil::Time startTime = TimeUtil::GetTime();
170
171 generateObjectLocalizationSaliency();
172
173 SaliencyMapBasePtr objectLocalizationSaliencyMap = new SaliencyMapBase();
174 objectLocalizationSaliencyMap->name = "objectLocalizationSaliency";
175 saliencyEgosphereGraph->graphToVec(objectLocalizationSaliencyMap->map);
176 viewSelection->updateSaliencyMap(objectLocalizationSaliencyMap);
177
178 SaliencyMapBasePtr randomNoise = new SaliencyMapBase();
179 randomNoise->name = "randomNoise";
180 randomNoiseGraph->graphToVec(randomNoise->map);
181 viewSelection->updateSaliencyMap(randomNoise);
182
183 IceUtil::Time stopTime = TimeUtil::GetTime();
184
185 std::lock_guard<std::mutex> lock2(mutex);
186
187 lastDiff = (stopTime - startTime);
188}
189
190void
191ObjectLocalizationSaliency::generateObjectLocalizationSaliency()
192{
193
194 // reset saliency and visited nodes
195 saliencyEgosphereGraph->set(0);
196
197 for (size_t i = 0; i < saliencyEgosphereGraph->getNodes()->size(); i++)
198 {
199 nodeVisitedForObject.at(i) = -1;
200 }
201
202
203 // collect localizable objects
204 std::vector<memoryx::ObjectInstancePtr> localizableObjects;
205 std::vector<FramedPositionPtr> localizableObjectPositions;
206 float maxObjectDistance = getProperty<float>("MaxObjectDistance").getValue();
207
208 RemoteRobot::synchronizeLocalClone(robot, robotStateComponent);
209
210 int numberOfLostObjects = 0;
211
212 memoryx::EntityBaseList objectInstances = objectInstancesProxy->getAllEntities();
213
214 for (size_t i = 0; i < objectInstances.size(); i++)
215 {
216 const memoryx::ObjectInstancePtr object =
217 memoryx::ObjectInstancePtr::dynamicCast(objectInstances.at(i));
218
219 if (object)
220 {
221 if (recognizableObjClasses.count(object->getMostProbableClass()) > 0 &&
222 !object->getPosition()->getFrame().empty())
223 {
224 if (objectClassesProxy->hasEntityByName(
225 object
226 ->getMostProbableClass())) // should be true if and only if object has been requested
227 {
228 FramedPositionPtr position = object->getPosition();
229 position->changeFrame(robot, headFrameName);
230 float objDist = position->toEigen().norm();
231
232 if (objDist <= maxObjectDistance)
233 {
234 localizableObjects.push_back(object);
235 localizableObjectPositions.push_back(position);
236
237 if (object->getExistenceCertainty() < 0.5)
238 {
239 numberOfLostObjects++;
240 }
241 }
242 else
243 {
244 ARMARX_DEBUG << "Discarding " << object->getName() << " which is at "
245 << position->output() << " ObjectDistance " << objDist;
246 }
247 }
248 }
249 }
250 }
251
252
253 // generate new random noise
254 if (randomNoiseLevel > 0)
255 {
256 generateRandomNoise(localizableObjects, objectInstances);
257 }
258
259
260 const float probabilityToAddALostObject =
261 (numberOfLostObjects > 0)
262 ? getProperty<float>("ProbabilityToLookForALostObject").getValue() / numberOfLostObjects
263 : 0;
264
265 // add localization necessities to sphere of possible view directions
266 for (size_t i = 0; i < localizableObjects.size(); i++)
267 {
268 const memoryx::ObjectInstancePtr object = localizableObjects.at(i);
269
270 if ((object->getExistenceCertainty() >= 0.5) ||
271 (rand() % 100000 < 100000 * probabilityToAddALostObject))
272 {
273 const FramedPositionPtr position = localizableObjectPositions.at(i);
274
276 memoryx::MultivariateNormalDistributionPtr::dynamicCast(
277 object->getPositionUncertainty());
278
279 if (!uncertaintyGaussian)
280 {
281 uncertaintyGaussian =
283 }
284
285 float priority = object->getLocalizationPriority() / 100.0;
286 float saliency = priority * log(1.0 + uncertaintyGaussian->getVarianceScalar());
287
288 if (saliency > 0)
289 {
290 // close objects get a smaller visibility angle to avoid problems due to the head being positioned unfortunately
291 float modifiedHalfCameraOpeningAngle = halfCameraOpeningAngle;
292 float objDist = position->toEigen().norm();
293 float shortDistance = 0.5f * maxObjectDistance;
294 if (objDist < shortDistance)
295 {
296 modifiedHalfCameraOpeningAngle = (objDist - 0.1f * shortDistance) /
297 (0.9f * shortDistance) *
298 halfCameraOpeningAngle;
299 modifiedHalfCameraOpeningAngle = std::max(0.0f, modifiedHalfCameraOpeningAngle);
300 }
301
302 TSphereCoord positionInSphereCoordinates;
303 Eigen::Vector3f vec = position->toEigen() - offsetToHeadCenter;
304 MathTools::convert(vec, positionInSphereCoordinates);
305 int closestNodeIndex =
306 graphLookupTable->getClosestNode(positionInSphereCoordinates);
307 addSaliencyRecursive(closestNodeIndex,
308 saliency,
309 positionInSphereCoordinates,
310 i,
311 modifiedHalfCameraOpeningAngle);
312 }
313 }
314 }
315}
316
317void
318ObjectLocalizationSaliency::addSaliencyRecursive(const int currentNodeIndex,
319 const float saliency,
320 const TSphereCoord objectSphereCoord,
321 const int objectIndex,
322 const float maxDistanceOnArc)
323{
324
325 // distance on arc between object projection center and node,
326 // normalized by the maximal viewing angle of the camera (=> in [0,1])
327 float normalizedDistance =
329 objectSphereCoord,
330 saliencyEgosphereGraph->getNodes()->at(currentNodeIndex)->getPosition()) /
331 maxDistanceOnArc;
332
333 // increase value of node
334 float newValue =
335 ((CIntensityNode*)saliencyEgosphereGraph->getNodes()->at(currentNodeIndex))
336 ->getIntensity() +
337 (1.0f - deviationFromCameraCenterFactor * normalizedDistance * normalizedDistance) *
338 saliency;
339 ((CIntensityNode*)saliencyEgosphereGraph->getNodes()->at(currentNodeIndex))
340 ->setIntensity(newValue);
341
342 // mark node as visited for this object
343 nodeVisitedForObject.at(currentNodeIndex) = objectIndex;
344
345 // recurse on neighbours if they were not yet visited and close enough to the object projection center
346 int neighbourIndex;
347
348 for (size_t i = 0; i < saliencyEgosphereGraph->getNodeAdjacency(currentNodeIndex)->size(); i++)
349 {
350 neighbourIndex = saliencyEgosphereGraph->getNodeAdjacency(currentNodeIndex)->at(i);
351
352 if (nodeVisitedForObject.at(neighbourIndex) != objectIndex)
353 {
355 objectSphereCoord,
356 saliencyEgosphereGraph->getNodes()->at(neighbourIndex)->getPosition()) <=
357 maxDistanceOnArc)
358 {
359 addSaliencyRecursive(
360 neighbourIndex, saliency, objectSphereCoord, objectIndex, maxDistanceOnArc);
361 }
362 else
363 {
364 nodeVisitedForObject.at(neighbourIndex) = objectIndex;
365 }
366 }
367 }
368}
369
370void
371ObjectLocalizationSaliency::generateRandomNoise(
372 std::vector<memoryx::ObjectInstancePtr>& localizableObjects,
373 memoryx::EntityBaseList& objectInstances)
374{
375
376 // if there are requested objects that were not localized yet, the random noise component will be bigger
377 memoryx::EntityBaseList requestedObjectClasses = objectClassesProxy->getAllEntities();
378
379 bool unlocalizedObjectExists = false;
380 for (size_t i = 0; i < requestedObjectClasses.size(); i++)
381 {
382 bool isInInstancesList = false;
383 for (size_t j = 0; j < objectInstances.size(); j++)
384 {
385 if (requestedObjectClasses.at(i)->getName() ==
386 memoryx::ObjectInstanceBasePtr::dynamicCast(objectInstances.at(j))
387 ->getMostProbableClass())
388 {
389 isInInstancesList = true;
390 break;
391 }
392 }
393 if (!isInInstancesList)
394 {
395 unlocalizedObjectExists = true;
396 break;
397 }
398 }
399
400 if (unlocalizedObjectExists)
401 {
402 if (localizableObjects.size() == 0)
403 {
404 ARMARX_DEBUG << "There are objects requested, and none of them has been localized yet";
405 setRandomNoise(centralHeadTiltAngle + 30, 3.0f);
406 }
407 else
408 {
409 ARMARX_DEBUG << "There are objects requested, and some but not all of them have been "
410 "localized already";
411 setRandomNoise(centralHeadTiltAngle + 20, 2.0f);
412 }
413 }
414 else
415 {
416 ARMARX_DEBUG << "There are no requested objects that were not localized yet. "
417 "requestedObjectClasses.size() = "
418 << requestedObjectClasses.size() << ", objectInstances.size() = "
419 << objectInstances.size(); // << ", difference.size() = " << difference.size();
420 setRandomNoise(centralHeadTiltAngle, 1.0f);
421 }
422}
423
424void
426{
427 std::lock_guard<std::mutex> lock(mutex);
428
429 next = IceUtil::Time::milliSeconds(timestamp);
430}
431
432void
433ObjectLocalizationSaliency::setRandomNoise(const float centralAngleForVerticalDirection,
434 const float directionVariabilityFactor)
435{
436
437 Eigen::Vector3f currentViewTargetEigen(
438 1000, 0, 0); // virtual central gaze goes into x direction
439 FramedPosition currentViewTarget(currentViewTargetEigen, cameraFrameName, robot->getName());
440 currentViewTarget.changeFrame(robot, headFrameName);
441 currentViewTargetEigen = currentViewTarget.toEigen() - offsetToHeadCenter;
442 TSphereCoord currentViewDirection;
443 MathTools::convert(currentViewTargetEigen, currentViewDirection);
444
445 TNodeList* nodes = randomNoiseGraph->getNodes();
446 const int randomFactor = 100000;
447 const float noiseFactor = randomNoiseLevel / randomFactor;
448 const float distanceWeight = std::min(0.6f / directionVariabilityFactor, 1.0f);
449 const float centralityWeight = std::min(0.1f / directionVariabilityFactor, 0.2f);
450
451 for (size_t i = 0; i < nodes->size(); i++)
452 {
453 CIntensityNode* node = (CIntensityNode*)nodes->at(i);
454 TSphereCoord nodeCoord = node->getPosition();
455 float distanceOnSphere = MathTools::getDistanceOnArc(currentViewDirection, nodeCoord);
456 float distanceFactor = 1.0f - distanceWeight * distanceOnSphere /
457 M_PI; // prefer directions close to current direction
458 float verticalCenterFactor =
459 1.0f - centralityWeight * fabs(nodeCoord.fPhi - centralAngleForVerticalDirection) /
460 90.0f; // prefer directions that look to the center
461 float horizontalCenterFactor = 1.0f - centralityWeight * fabs(nodeCoord.fTheta) / 120.0f;
462 node->setIntensity(verticalCenterFactor * horizontalCenterFactor * distanceFactor *
463 noiseFactor * (rand() % randomFactor));
464 }
465}
466
std::string timestamp()
#define M_PI
Definition MathTools.h:17
std::vector< CSGNode * > TNodeList
constexpr T c
void graphToVec(std::vector< float > &vec)
void setIntensity(float fIntensity)
TSphereCoord getPosition()
TNodeList * getNodes()
static float getDistanceOnArc(TSphereCoord p1, TSphereCoord p2)
static void convert(TSphereCoord in, Eigen::Vector3d &out)
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)
The FramedPosition class.
Definition FramedPose.h:158
bool usingProxy(const std::string &name, const std::string &endpoints="")
Registers a proxy for retrieval after initialization and adds it to the dependency list.
void usingTopic(const std::string &name, bool orderedPublishing=false)
Registers a proxy for subscription after initialization.
Ice::ObjectPrx getProxy(long timeoutMs=0, bool waitForScheduler=true) const
Returns the proxy of this object (optionally it waits for the proxy)
void onDeactivateAutomaticViewSelection(const Ice::Current &c=Ice::emptyCurrent) override
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
void onActivateAutomaticViewSelection(const Ice::Current &c=Ice::emptyCurrent) override
void nextViewTarget(Ice::Long timestamp, const Ice::Current &c=Ice::emptyCurrent) override
The periodic task executes one thread method repeatedly using the time period specified in the constr...
Property< PropertyType > getProperty(const std::string &name)
Property creation and retrieval.
VirtualRobot::RobotPtr createLocalClone()
Clones the structure of this remote robot to a local instance.
static bool synchronizeLocalClone(VirtualRobot::RobotPtr robot, RobotStateComponentInterfacePrx robotStatePrx)
static IceUtil::Time GetTime(TimeMode timeMode=TimeMode::VirtualTime)
Get the current time.
Definition TimeUtil.cpp:42
static void Sleep(IceUtil::Time duration)
lock the calling thread for a given duration (like usleep(...) but using Timeserver time)
Definition TimeUtil.cpp:80
static MultivariateNormalDistributionPtr CreateDefaultDistribution(float variance=10000)
Create a distribution with uncertainty of variance in all directions (default: variance = 10000,...
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:196
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
Definition Logging.h:184
#define ARMARX_VERBOSE
The logging level for verbose information.
Definition Logging.h:187
This file offers overloads of toIce() and fromIce() functions for STL container types.
void handleExceptions()
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
IceInternal::Handle< FramedPosition > FramedPositionPtr
Definition FramedPose.h:149
IceInternal::Handle< ObjectRecognitionWrapper > ObjectRecognitionWrapperPtr
IceInternal::Handle< ObjectInstance > ObjectInstancePtr
IceInternal::Handle< ObjectClass > ObjectClassPtr
Definition ObjectClass.h:35
IceInternal::Handle< MultivariateNormalDistribution > MultivariateNormalDistributionPtr
float fTheta
Definition Structs.h:27
float fPhi
Definition Structs.h:26