ValveAttention.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::ValveAttention
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 "ValveAttention.h"
24
25#include <pcl/common/point_tests.h>
26
29
31
32#include <Image/ImageProcessor.h>
33
34namespace armarx
35{
36
37
44
45 void
47 {
48 usingProxy(getProperty<std::string>("ViewSelectionName").getValue());
49 usingProxy(getProperty<std::string>("RobotStateComponentName").getValue());
50
51 providerName = getProperty<std::string>("providerName").getValue();
52 usingImageProvider(providerName);
53 usingPointCloudProvider(providerName);
54
55 std::string graphFileName = "RobotAPI/ViewSelection/graph40k.gra";
56
57 armarx::CMakePackageFinder finder("RobotAPI");
59
60 if (ArmarXDataPath::getAbsolutePath(graphFileName, graphFileName))
61 {
62 saliencyEgosphereGraph = new CIntensityGraph(graphFileName);
63 ARMARX_VERBOSE << "Created egosphere graph with "
64 << saliencyEgosphereGraph->getNodes()->size() << "nodes";
65 graphLookupTable = new CGraphPyramidLookupTable(9, 18);
66 graphLookupTable->buildLookupTable(saliencyEgosphereGraph);
67 }
68 else
69 {
70 ARMARX_ERROR << "Could not find required graph file";
72 }
73
74 headFrameName = getProperty<std::string>("HeadFrameName").getValue();
75 hog = new HoG();
76 hog->loadTrainingData(getProperty<std::string>("TrainingData").getValue());
77 hog->setParameters(true, true);
78 }
79
80 void
82 {
83
84 visionx::ImageType imageDisplayType = visionx::tools::typeNameToImageType("rgb");
85
86 visionx::ImageProviderInfo imageProviderInfo =
87 getImageProvider(providerName, imageDisplayType);
88
89 numImages = imageProviderInfo.numberImages;
90
91 images = new CByteImage*[numImages];
92 for (int i = 0; i < numImages; i++)
93 {
94 images[i] = visionx::tools::createByteImage(imageProviderInfo);
95 }
96
97 numResultImages = 3;
98 result = new CByteImage*[numResultImages];
99 result[0] = images[0];
100 result[1] = visionx::tools::createByteImage(imageProviderInfo);
101 result[2] = visionx::tools::createByteImage(imageProviderInfo);
102
103
104 visionx::ImageDimension dimension(images[0]->width, images[0]->height);
105 enableResultImages(numResultImages, dimension, visionx::tools::typeNameToImageType("rgb"));
106
107 robotStateComponent = getProxy<RobotStateComponentInterfacePrx>(
108 getProperty<std::string>("RobotStateComponentName").getValue());
109
111 robotStateComponent, VirtualRobot::RobotIO::RobotDescription::eFull);
112
114 getProperty<std::string>("ViewSelectionName").getValue());
115 }
116
117 void
121
122 void
124 {
125 for (int i = 0; i < numImages; i++)
126 {
127 delete images[i];
128 }
129 delete[] images;
130
131 for (int i = 0; i < numResultImages; i++)
132 {
133 delete result[i];
134 }
135 delete[] result;
136
137 delete graphLookupTable;
138 delete saliencyEgosphereGraph;
139 delete hog;
140 }
141
142 void
144 {
145 ARMARX_IMPORTANT << "process";
146
147 std::lock_guard<std::mutex> lock(mutex);
148
149 pcl::PointCloud<pcl::PointXYZRGBA>::Ptr currentPointCloud(
150 new pcl::PointCloud<pcl::PointXYZRGBA>());
151
152
153 ARMARX_VERBOSE << "waiting for images";
154 if (!waitForImages(providerName))
155 {
156 ARMARX_WARNING << "Timeout while waiting for images";
157 return;
158 }
159
160 ARMARX_VERBOSE << "waiting for pointcloud";
161 if (!waitForPointClouds(providerName))
162 {
163 ARMARX_WARNING << "Timeout while waiting for pointcloud";
164 return;
165 }
166
167 ARMARX_VERBOSE << "getting images";
168 if (getImages(images) != numImages)
169 {
170 ARMARX_WARNING << "Unable to transfer or read images";
171 return;
172 }
173
174 ARMARX_VERBOSE << "getting pointcloud";
175 if (!getPointClouds(currentPointCloud))
176 {
177 ARMARX_WARNING << "Unable to transfer or read point cloud";
178 return;
179 }
180
181
182 RemoteRobot::synchronizeLocalClone(robot, robotStateComponent);
183
184 saliencyEgosphereGraph->set(0.0);
185
186 const int scaleFactor = 4; //images[0]->width / 255;
187
188 int width = images[0]->width / scaleFactor;
189 int height = images[0]->height / scaleFactor;
190 CByteImage* image = new CByteImage(width, height, CByteImage::eRGB24);
191 ::ImageProcessor::Resize(images[0], image);
192
193 ARMARX_VERBOSE << "downscaling image to: " << width << "x" << height;
194
195 //CByteImage* saliencyImage = result[0]; //new CByteImage(width, height, CByteImage::eRGB24);
196 CFloatImage* saliencyImage = new CFloatImage(width, height, 1);
197
198
199 ARMARX_VERBOSE << "computing saliency map";
200 IceUtil::Time startTime = TimeUtil::GetTime();
201
202 hog->findSalientRegions(image, saliencyImage);
203 //*************************test for Cluster**************************/
204 std::vector<cv::Point2f> points;
205 cv::Mat outputLable;
206 cv::Mat centers;
207 std::map<int, int> saliencyHist;
208 float priorityProcent = 0.9;
209 int clusterNum = 3;
210 int intensityThreshold = 255;
211 int saliencySum = 0;
212 int saliencyImageWidth = saliencyImage->width;
213
214 for (int i = 0; i < saliencyImage->height; i++)
215 {
216 for (int j = 0; j < saliencyImageWidth; j++)
217 {
218 saliencyHist[(int)(saliencyImage->pixels[i * saliencyImageWidth + j] * 255.0)]++;
219 }
220 }
221
222 // determine 90% number of non-zero salient values
223 int usefulSampleAmount =
224 priorityProcent * (saliencyImage->width * saliencyImage->height - saliencyHist[0]);
225 for (int i = 1; i <= 255; i++)
226 {
227 if (!saliencyHist.count(i))
228 {
229 continue;
230 }
231 saliencySum += saliencyHist[i];
232 if (saliencySum > usefulSampleAmount)
233 {
234 intensityThreshold = i;
235 break;
236 }
237 }
238
239 for (int i = 0; i < saliencyImage->height; i++)
240 {
241 for (int j = 0; j < saliencyImageWidth; j++)
242 {
243 if (saliencyImage->pixels[i * saliencyImageWidth + j] * 255.0 > intensityThreshold)
244 {
245 points.push_back(cv::Point2f(j, i));
246 }
247 }
248 }
249
250 cv::Mat samples(points.size(), 2, CV_32F);
251 for (size_t i = 0; i < points.size(); i++)
252 {
253 samples.at<float>(i, 0) = points[i].x;
254 samples.at<float>(i, 1) = points[i].y;
255 }
256
257 if (points.size())
258 {
259 cv::kmeans(samples,
260 clusterNum,
261 outputLable,
262 cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 20, 0.1),
263 10,
264 cv::KMEANS_PP_CENTERS,
265 centers);
266 }
267
268 // calculate the number of elements in each cluster and get first two biggest cluster
269 std::map<int, int> numberOfEachCluster;
270 for (int i = 0; i < samples.rows; i++)
271 {
272 numberOfEachCluster[outputLable.at<int>(i, 0)]++;
273 }
274 size_t maxCluster = 0;
275 int secondCluster;
276 for (size_t i = 0; i < numberOfEachCluster.size(); i++)
277 {
278 if (numberOfEachCluster[i] > numberOfEachCluster[maxCluster])
279 {
280 maxCluster = i;
281 }
282 }
283 if (maxCluster != 0)
284 {
285 secondCluster = 0;
286 }
287 else
288 {
289 secondCluster = 1;
290 }
291 for (size_t i = 0; i < numberOfEachCluster.size(); i++)
292 {
293 if ((i != maxCluster) && numberOfEachCluster[i] > numberOfEachCluster[secondCluster])
294 {
295 secondCluster = i;
296 }
297 }
298
299 //*************************test for Cluster END**************************/
300
301 ARMARX_VERBOSE << "done computing saliency map. took "
302 << (TimeUtil::GetTime() - startTime).toMilliSeconds() << "ms";
303
304 delete image;
305
306#pragma omp parallel for
307 for (int i = 0; i < images[0]->height; i++)
308 {
309 for (int j = 0; j < images[0]->width; j++)
310 {
311 int idx = i * images[0]->width + j;
312
313 float saliency =
314 saliencyImage->pixels[(i / scaleFactor * width) + (j / scaleFactor)];
315
316 result[1]->pixels[3 * idx + 0] = 255 * saliency;
317 result[1]->pixels[3 * idx + 1] = 255 * saliency;
318 result[1]->pixels[3 * idx + 2] = 255 * saliency;
319
320 result[2]->pixels[3 * idx + 0] =
321 (0.2 + 0.8 * saliency) * result[0]->pixels[3 * idx + 0];
322 result[2]->pixels[3 * idx + 1] =
323 (0.2 + 0.8 * saliency) * result[0]->pixels[3 * idx + 1];
324 result[2]->pixels[3 * idx + 2] =
325 (0.2 + 0.8 * saliency) * result[0]->pixels[3 * idx + 2];
326 }
327 }
328
329
330 /*********transform cluster daten (the points near cluster centers) from pointcloud to sphere **********/
331 /*
332 for (int i = 0; i < samples.rows; i++)
333 {
334 int downScaleIdx = ((int)samples.at<float>(i, 1) * width) + ((int)samples.at<float>(i, 0));
335 int idx = (int)samples.at<float>(i, 1) * scaleFactor * images[0]->width + (int)samples.at<float>(i, 0) * scaleFactor;
336 float saliency = saliencyImage->pixels[downScaleIdx];
337 int clusterLabel = outputLable.at<int>(i, 0);
338 float distanceToClusterCenter = sqrt(pow((centers.at<float>(clusterLabel, 0) - samples.at<float>(i, 0)), 2) + pow((centers.at<float>(clusterLabel, 1) - samples.at<float>(i, 1)), 2));
339
340 if (saliency > 0 && (distanceToClusterCenter < (width / 5)))
341 {
342 if (idx >= (int)currentPointCloud->points.size())
343 {
344 continue;
345 }
346
347 Eigen::Vector3f vec = currentPointCloud->points[idx].getVector3fMap();
348
349 if (!pcl::isFinite(currentPointCloud->points[idx]))
350 {
351 continue;
352 }
353 TSphereCoord positionInSphereCoordinates;
354 //armarx::GlobalFrame
355 FramedPositionPtr currentViewTarget = new FramedPosition(vec, "DepthCamera", robotStateComponent->getSynchronizedRobot()->getName());
356 currentViewTarget->changeFrame(robot, headFrameName);
357
358 MathTools::convert(currentViewTarget->toEigen(), positionInSphereCoordinates);
359 int closestNodeIndex = graphLookupTable->getClosestNode(positionInSphereCoordinates);
360 CIntensityNode* currentNode = ((CIntensityNode*)saliencyEgosphereGraph->getNodes()->at(closestNodeIndex));
361
362 float currentSaliency = currentNode->getIntensity();
363
364 // give priority to the cluster which has the most elements, because this cluster always near valve
365 if (clusterLabel == maxCluster)
366 {
367 //consider about history? & predict --> consider about observation & predict
368 currentSaliency = std::min(1.0f, currentSaliency + saliency * (float)1.3);
369
370 //consider only about predict
371 //currentSaliency = std::min(1.0f, saliency * (float)1.3);
372 //std::cout << "currentSaliency!! " << currentSaliency << std::endl;
373 }
374 else
375 {
376 if (outputLable.at<int>(i, 0) == secondCluster)
377 {
378 currentSaliency = std::min(1.0f, currentSaliency + saliency * (float)1.02);
379 //currentSaliency = std::min(1.0f, saliency * (float)1.02);
380 }
381 }
382 currentNode->setIntensity(currentSaliency);
383 }
384 }
385
386 */
387 /*********transform cluster daten from pointcloud to sphere ***** END*****/
388
389 /*********transform cluster centers from pointcloud to sphere ***** *****/
390 for (int i = 0; i < centers.rows; i++)
391 {
392 int downScaleIdx =
393 ((int)centers.at<float>(i, 1) * width) + ((int)centers.at<float>(i, 0));
394 int idx = (int)centers.at<float>(i, 1) * scaleFactor * images[0]->width +
395 (int)centers.at<float>(i, 0) * scaleFactor;
396 //attention: center's saliency may shouldn't directly get from saliency map, because it's saliency can be low
397 float saliency = saliencyImage->pixels[downScaleIdx];
398
399 if (idx >= (int)currentPointCloud->points.size())
400 {
401 continue;
402 }
403
404 Eigen::Vector3f vec = currentPointCloud->points[idx].getVector3fMap();
405
406 if (!pcl::isFinite(currentPointCloud->points[idx]))
407 {
408 continue;
409 }
410 TSphereCoord positionInSphereCoordinates;
411 //armarx::GlobalFrame
412 FramedPositionPtr currentViewTarget = new FramedPosition(
413 vec, "DepthCamera", robotStateComponent->getSynchronizedRobot()->getName());
414 currentViewTarget->changeFrame(robot, headFrameName);
415
416 MathTools::convert(currentViewTarget->toEigen(), positionInSphereCoordinates);
417 int closestNodeIndex = graphLookupTable->getClosestNode(positionInSphereCoordinates);
418
419 float halfCameraOpeningAngle = 12.0 * M_PI / 180.0;
420 float modifiedHalfCameraOpeningAngle = halfCameraOpeningAngle;
421 float distance = currentViewTarget->toEigen().norm();
422
423
424 if (distance > 6000)
425 {
426 ARMARX_WARNING << "position is too far away." << distance;
427 return;
428 }
429
430 const float distanceThreshold = 1500;
431 if (distance < distanceThreshold)
432 {
433 modifiedHalfCameraOpeningAngle = (distance - 0.1f * distanceThreshold) /
434 (0.9f * distanceThreshold) *
435 halfCameraOpeningAngle;
436 modifiedHalfCameraOpeningAngle = std::max(0.0f, modifiedHalfCameraOpeningAngle);
437 }
438
439
440 std::vector<bool> visitedNodes(saliencyEgosphereGraph->getNodes()->size(), false);
441 addSaliencyRecursive(closestNodeIndex,
442 visitedNodes,
443 saliency,
444 positionInSphereCoordinates,
445 modifiedHalfCameraOpeningAngle);
446 }
447 /*********transform cluster centers from pointcloud to sphere ***** END*****/
448
449 //*************************test for Cluster**************************/
450 int index;
451 for (std::size_t row = 0; centers.rows > 0 && row < static_cast<std::size_t>(centers.rows);
452 row++)
453 {
454 for (std::size_t i = 0; i < 8; i++)
455 {
456 for (std::size_t j = 0; j < 8; j++)
457 {
458 index =
459 3 * (((int)centers.at<float>(row, 1) * scaleFactor + i) * images[0]->width +
460 ((int)centers.at<float>(row, 0) * scaleFactor + j));
461 result[2]->pixels[index] = 255;
462 result[2]->pixels[index + 1] = 255 * (row == maxCluster);
463 result[2]->pixels[index + 2] =
464 255 * (row == static_cast<std::size_t>(secondCluster));
465 }
466 }
467 }
468
469 //*************************test for Cluster END**************************/
470
471 ARMARX_VERBOSE << "mapping took !!!!! "
472 << (TimeUtil::GetTime() - startTime).toMilliSeconds() << "ms";
473
474 provideResultImages(result);
475
476 SaliencyMapBasePtr primitiveSaliency = new SaliencyMapBase();
477 primitiveSaliency->name = "ValveAttention";
478 saliencyEgosphereGraph->graphToVec(primitiveSaliency->map);
479 viewSelection->updateSaliencyMap(primitiveSaliency);
480
481 ARMARX_IMPORTANT << "process finished";
482 }
483
484 void
485 ValveAttention::addSaliencyRecursive(const int currentNodeIndex,
486 std::vector<bool>& visitedNodes,
487 const float saliency,
488 const TSphereCoord objectSphereCoord,
489 const float maxDistanceOnArc)
490 {
491
492 // distance on arc between object projection center and node,
493 // normalized by the maximal viewing angle of the camera (=> in [0,1])
494 float normalizedDistance =
496 objectSphereCoord,
497 saliencyEgosphereGraph->getNodes()->at(currentNodeIndex)->getPosition()) /
498 maxDistanceOnArc;
499
500 // increase value of node
501 float newValue = ((CIntensityNode*)saliencyEgosphereGraph->getNodes()->at(currentNodeIndex))
502 ->getIntensity() +
503 (1.0f - 0.5f * normalizedDistance * normalizedDistance) * saliency;
504
505 if (newValue > 1.0)
506 {
507 ARMARX_INFO << "saliency is greater than 1.0: " << newValue;
508 newValue = std::min(1.0f, newValue);
509 }
510
511 ((CIntensityNode*)saliencyEgosphereGraph->getNodes()->at(currentNodeIndex))
512 ->setIntensity(newValue);
513
514 // mark node as visited for this object
515 visitedNodes.at(currentNodeIndex) = true;
516
517 // recurse on neighbours if they were not yet visited and close enough to the object projection center
518 int neighbourIndex;
519
520 for (size_t i = 0; i < saliencyEgosphereGraph->getNodeAdjacency(currentNodeIndex)->size();
521 i++)
522 {
523 neighbourIndex = saliencyEgosphereGraph->getNodeAdjacency(currentNodeIndex)->at(i);
524
525 if (!visitedNodes.at(neighbourIndex))
526 {
528 objectSphereCoord,
529 saliencyEgosphereGraph->getNodes()->at(neighbourIndex)->getPosition()) <=
530 maxDistanceOnArc)
531 {
532 addSaliencyRecursive(neighbourIndex,
533 visitedNodes,
534 saliency,
535 objectSphereCoord,
536 maxDistanceOnArc);
537 }
538 else
539 {
540 visitedNodes.at(neighbourIndex) = true;
541 }
542 }
543 }
544 }
545} // namespace armarx
uint8_t index
#define M_PI
Definition MathTools.h:17
TNodeList * getNodes()
std::vector< int > * getNodeAdjacency(int nIndex)
Definition hog.h:48
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.
Ice::ObjectPrx getProxy(long timeoutMs=0, bool waitForScheduler=true) const
Returns the proxy of this object (optionally it waits for the proxy)
static VirtualRobot::RobotPtr createLocalCloneFromFile(RobotStateComponentInterfacePrx robotStatePrx, VirtualRobot::RobotIO::RobotDescription loadMode=VirtualRobot::RobotIO::eFull)
This is a convenience function for createLocalClone, which automatically gets the filename from the R...
static bool synchronizeLocalClone(VirtualRobot::RobotPtr robot, RobotStateComponentInterfacePrx robotStatePrx)
static IceUtil::Time GetTime(TimeMode timeMode=TimeMode::VirtualTime)
Get the current time.
Definition TimeUtil.cpp:42
void onDisconnectPointCloudAndImageProcessor() override
Implement this method in the PointCloudAndImageProcessor in order to execute parts when the component...
void onConnectPointCloudAndImageProcessor() override
Implement this method in your PointCloudAndImageProcessor in order execute parts when the component i...
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
void process() override
Process the vision component.
void onInitPointCloudAndImageProcessor() override
Setup the vision component.
void onExitPointCloudAndImageProcessor() override
Exit the ImapeProcessor component.
void enableResultImages(int numberImages, ImageDimension imageDimension, ImageType imageType, const std::string &name="")
Enables visualization.
void usingImageProvider(std::string name)
Registers a delayed topic subscription and a delayed provider proxy retrieval which all will be avail...
bool waitForImages(int milliseconds=1000)
Wait for new images.
ImageProviderInfo getImageProvider(std::string name, ImageType destinationImageType=eRgb, bool waitForProxy=false)
Select an ImageProvider.
int getImages(CByteImage **ppImages)
Poll images from provider.
void provideResultImages(CByteImage **images, armarx::MetaInfoSizeBasePtr info=nullptr)
sends result images for visualization
int numberImages
Number of images.
int getPointClouds(const PointCloudPtrT &pointCloudPtr)
Poll PointClouds from provider.
void usingPointCloudProvider(std::string providerName)
Registers a delayed topic subscription and a delayed provider proxy retrieval which will be available...
bool waitForPointClouds(int milliseconds=1000)
Wait for new PointClouds.
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
Definition Logging.h:190
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:196
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
#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
ImageType typeNameToImageType(const std::string &imageTypeName)
Converts an image type name as string into an ImageType integer.
CByteImage * createByteImage(const ImageFormatInfo &imageFormat, const ImageType imageType)
Creates a ByteImage for the destination type specified in the given imageProviderInfo.
double distance(const Point &a, const Point &b)
Definition point.hpp:95