SegmentableObjectRecognition.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::Component
17* @author Kai Welke <welke at kit dot edu>
18* @copyright 2013 Humanoids Group, HIS, KIT
19* @license http://www.gnu.org/licenses/gpl-2.0.txt
20* GNU General Public License
21*/
22
24
25// Core
27
28// RobotState
31
32// IVT
33
34#include <Image/ByteImage.h>
35#include <Image/ImageProcessor.h>
36#include <SegmentableRecognition/SegmentableDatabase.h>
37
38// MemoryX
40
43
44// This file must be included after all Ice-related headers when Ice 3.5.x is used (e.g. with Ubuntu 14.04 or Debian 7.0)!
45// GLContext.h indirectly includes X.h which does "#define None", colliding with IceUtil::None.
46#include <gui/GLContext.h>
47
48using namespace armarx;
49using namespace visionx;
50using namespace memoryx::EntityWrappers;
51
55
59
60void
64
65bool
67{
68 ARMARX_VERBOSE << "Initializing SegmentableObjectRecognition";
69
70 Eigen::Vector3f minPoint = getProperty<Eigen::Vector3f>("MinPoint").getValue();
71 Eigen::Vector3f maxPoint = getProperty<Eigen::Vector3f>("MaxPoint").getValue();
72
73 Math3d::SetVec(validResultBoundingBoxMin, minPoint(0), minPoint(1), minPoint(2));
74 Math3d::SetVec(validResultBoundingBoxMax, maxPoint(0), maxPoint(1), maxPoint(2));
75
76 minPixelsPerRegion = getProperty<float>("MinPixelsPerRegion").getValue();
77 maxEpipolarDistance = getProperty<float>("MaxEpipolarDistance").getValue();
78 std::string colorParemeterFilename = getProperty<std::string>("ColorParameterFile").getValue();
79
80 if (!ArmarXDataPath::getAbsolutePath(colorParemeterFilename, colorParemeterFilename))
81 {
82 ARMARX_ERROR << "Could not find color parameter file in ArmarXDataPath: "
83 << colorParemeterFilename;
84 }
85
86
87 if (!segmentableRecognition)
88 {
89 colorParameters.reset(new CColorParameterSet());
90
91 if (!colorParameters->LoadFromFile(colorParemeterFilename.c_str()))
92 {
93 throw armarx::LocalException("Could not read color parameter file.");
94 }
95
96 ARMARX_VERBOSE << "Startup step 1";
97
98 segmentableRecognition.reset(new CSegmentableRecognition());
99
100 ARMARX_VERBOSE << "Startup step 2";
101
102 // create context
103 ImageFormatInfo imageFormat = getImageFormat();
104 contextGL.reset(new CGLContext());
105
106 ARMARX_VERBOSE << "Startup step 3";
107
108 contextGL->CreateContext(imageFormat.dimension.width, imageFormat.dimension.height);
109
110 ARMARX_VERBOSE << "Startup step 4";
111
112 contextGL->MakeCurrent();
113
114 m_pOpenGLVisualizer.reset(new COpenGLVisualizer());
115 m_pOpenGLVisualizer->InitByCalibration(getStereoCalibration()->GetRightCalibration());
116
117 ARMARX_VERBOSE << "Startup step 5";
118
119 // init segmentable recognition
120 bool success = segmentableRecognition->InitWithoutDatabase(colorParameters.get(),
122
123 if (!success)
124 {
125 throw armarx::LocalException("Could not initialize segmentable object database.");
126 }
127
128 float sizeRatioThreshold = getProperty<float>("SizeRatioThreshold").getValue();
129 float correlationThreshold = getProperty<float>("CorrelationThreshold").getValue();
130 segmentableRecognition->GetObjectDatabase()->SetRecognitionThresholds(sizeRatioThreshold,
131 correlationThreshold);
132
133 ARMARX_VERBOSE << "SegmentableObjectRecognition is initialized";
134
135 return success;
136 }
137
138 ARMARX_VERBOSE << "SegmentableObjectRecognition is initialized";
139
140 return true;
141}
142
143bool
145 const memoryx::GridFileManagerPtr& fileManager)
146{
147 ARMARX_VERBOSE << "Adding object class " << objectClassEntity->getName() << armarx::flush;
148
149 SegmentableRecognitionWrapperPtr recognitionWrapper =
150 objectClassEntity->addWrapper(new SegmentableRecognitionWrapper(fileManager));
151 std::string dataPath = recognitionWrapper->getDataFiles();
152 ObjectColor color = recognitionWrapper->getObjectColor();
153
154 std::string colorString;
155 CColorParameterSet::Translate(color, colorString);
156 ARMARX_VERBOSE << "Color: " << (int)color << " (" << colorString << ")";
157
158 if (dataPath != "")
159 {
160 if (!segmentableRecognition->GetObjectDatabase()->AddClass(
161 dataPath, "", objectClassEntity->getName()))
162 {
163 ARMARX_INFO << "Skipped object class: " << objectClassEntity->getName();
164 return false;
165 }
166
167 // remember colors
168 std::string className = objectClassEntity->getName();
169 objectColors.insert(std::make_pair(className, color));
170
171 return true;
172 }
173 else
174 {
176 << "Datapath is empty for " << objectClassEntity->getName()
177 << " object class - make sure you set the correct model file in PriorKnowledge!";
178 }
179
180 return false;
181}
182
183memoryx::ObjectLocalizationResultList
185 const std::vector<std::string>& objectClassNames,
186 CByteImage** cameraImages,
187 armarx::MetaInfoSizeBasePtr imageMetaInfo,
188 CByteImage** resultImages)
189{
190
191 if (objectClassNames.size() < 1)
192 {
193 ARMARX_WARNING << "objectClassNames.size() = " << objectClassNames.size()
194 << ", something is wrong here! ";
195
196 memoryx::ObjectLocalizationResultList resultList;
197 return resultList;
198 }
199
200 std::string allObjectNames;
201
202 for (size_t i = 0; i < objectClassNames.size(); i++)
203 {
204 allObjectNames.append(" ");
205 allObjectNames.append(objectClassNames.at(i));
206 }
207
208 ARMARX_VERBOSE << "Localizing" << allObjectNames;
209
210 contextGL->MakeCurrent();
211
212 Object3DList objectList;
213
214 if (objectClassNames.size() < 10)
215 {
216 std::string color;
217
218 for (size_t i = 0; i < objectClassNames.size(); i++)
219 {
220 CColorParameterSet::Translate(objectColors[objectClassNames.at(i)], color);
221 ARMARX_VERBOSE << "Localizing " << objectClassNames.at(i) << ", color: " << color
222 << flush;
223
224 segmentableRecognition->DoRecognitionSingleObject(cameraImages,
226 objectClassNames.at(i).c_str(),
227 minPixelsPerRegion,
228 maxEpipolarDistance,
229 objectColors[objectClassNames.at(i)],
230 false,
232
233 Object3DList result = segmentableRecognition->GetObject3DList();
234
235 for (size_t j = 0; j < result.size(); j++)
236 {
237 objectList.push_back(result.at(j));
238 }
239
240 ARMARX_VERBOSE << "Found " << result.size() << " instances";
241 }
242 }
243 else
244 {
245 ARMARX_VERBOSE << "Localizing everything at once";
246
247 segmentableRecognition->DoRecognition(cameraImages,
249 minPixelsPerRegion,
250 false,
251 maxEpipolarDistance,
252 eNone,
253 false,
255
256 objectList = segmentableRecognition->GetObject3DList();
257 }
258
259
260 ARMARX_INFO << "Found " << objectList.size() << " objects";
261
262
263 // help for problem analysis
264 if (objectList.size() == 0)
265 {
266 ARMARX_INFO << "Looked unsuccessfully for:";
267 std::string color;
268
269 for (size_t i = 0; i < objectClassNames.size(); i++)
270 {
271 CColorParameterSet::Translate(objectColors[objectClassNames.at(i)], color);
272 ARMARX_INFO << objectClassNames.at(i) << " color: " << color << flush;
273 }
274 }
275 else
276 {
277 visualizeResults(objectList, resultImages);
278 }
279
280 const auto agentName = getProperty<std::string>("AgentName").getValue();
281
282 memoryx::ObjectLocalizationResultList resultList;
283
284 for (Object3DList::iterator iter = objectList.begin(); iter != objectList.end(); iter++)
285 {
286 // assure instance belongs to queried class
287 bool queriedClass =
288 (std::find(objectClassNames.begin(), objectClassNames.end(), iter->sName) !=
289 objectClassNames.end());
290
291 if (iter->localizationValid && queriedClass)
292 {
293 float x = iter->pose.translation.x;
294 float y = iter->pose.translation.y;
295 float z = iter->pose.translation.z;
296
297 if (seq.count(iter->sName))
298 {
299 seq[iter->sName]++;
300 }
301 else
302 {
303 seq[iter->sName] = 0;
304 }
305
306
307 StringVariantBaseMap mapValues;
308 mapValues["x"] = new Variant(x);
309 mapValues["y"] = new Variant(y);
310 mapValues["z"] = new Variant(z);
311 mapValues["name"] = new Variant(iter->sName);
312 mapValues["sequence"] = new Variant(seq[iter->sName]);
313 mapValues["timestamp"] = new Variant(imageMetaInfo->timeProvided / 1000.0 / 1000.0);
314 debugObserver->setDebugChannel("ObjectRecognition", mapValues);
315
316
317 // only accept realistic positions
318 if (x > validResultBoundingBoxMin.x && y > validResultBoundingBoxMin.y &&
319 z > validResultBoundingBoxMin.z && x < validResultBoundingBoxMax.x &&
320 y < validResultBoundingBoxMax.y && z < validResultBoundingBoxMax.z)
321 {
322 // assemble result
323 memoryx::ObjectLocalizationResult result;
324
325 // position and orientation
326 Eigen::Vector3f position(
327 iter->pose.translation.x, iter->pose.translation.y, iter->pose.translation.z);
328 Eigen::Matrix3f orientation;
329 orientation << iter->pose.rotation.r1, iter->pose.rotation.r2,
330 iter->pose.rotation.r3, iter->pose.rotation.r4, iter->pose.rotation.r5,
331 iter->pose.rotation.r6, iter->pose.rotation.r7, iter->pose.rotation.r8,
332 iter->pose.rotation.r9;
333
334 result.position =
335 new armarx::FramedPosition(position, referenceFrameName, agentName);
336 result.orientation =
337 new armarx::FramedOrientation(orientation, referenceFrameName, agentName);
338
339 // calculate noise
340 result.positionNoise = calculateLocalizationUncertainty(
341 iter->region_left.centroid, iter->region_right.centroid);
342
343 // calculate recognition certainty
344 result.recognitionCertainty =
345 0.5f + 0.5f * calculateRecognitionCertainty(iter->sName, *iter);
346 result.objectClassName = iter->sName;
347 result.timeStamp = new TimestampVariant(imageMetaInfo->timeProvided);
348
349 resultList.push_back(result);
350 }
351 else
352 {
353 ARMARX_VERBOSE_S << "Refused unrealistic localization at position: " << x << " "
354 << y << " " << z;
355 }
356 }
357 }
358
359 ARMARX_VERBOSE << "Finished localizing " << objectClassNames.at(0);
360
361 return resultList;
362}
363
364float
365SegmentableObjectRecognition::calculateRecognitionCertainty(const std::string& objectClassName,
366 const Object3DEntry& entry)
367{
368 float foundProb = entry.quality * entry.quality2;
369 float notFoundProb = (1 - entry.quality) * (1 - entry.quality2);
370
371 if (foundProb <= 0)
372 {
373 return 0.0f;
374 }
375
376 return foundProb / (foundProb + notFoundProb);
377}
378
379void
380SegmentableObjectRecognition::visualizeResults(const Object3DList& objectList,
381 CByteImage** resultImages)
382{
383 m_pOpenGLVisualizer->ActivateShading(true);
384 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
385
386
387 m_pOpenGLVisualizer->SetProjectionMatrix(getStereoCalibration()->GetRightCalibration());
388
389 m_pOpenGLVisualizer->Clear();
390
391
392 for (int i = 0; i < (int)objectList.size(); i++)
393 {
394 const Object3DEntry& entry = objectList.at(i);
395 CSegmentableDatabase::DrawObjectFromFile(
396 m_pOpenGLVisualizer.get(), entry.sOivFilePath.c_str(), entry.pose);
397 }
398
399 const int nImageIndex = 1;
400
401 if (resultImages && resultImages[nImageIndex])
402 {
403 CByteImage tempImage(resultImages[nImageIndex]);
404 m_pOpenGLVisualizer->GetImage(&tempImage);
405 ::ImageProcessor::FlipY(&tempImage, &tempImage);
406 const int nBytes = 3 * tempImage.width * tempImage.height;
407 const unsigned char* pixels = tempImage.pixels;
408 unsigned char* output = resultImages[nImageIndex]->pixels;
409
410 for (int i = 0; i < nBytes; i += 3)
411 {
412 if (pixels[i])
413 {
414 const unsigned char g = pixels[i];
415 output[i] = g;
416 output[i + 1] = g;
417 output[i + 2] = g;
418 }
419 }
420 }
421}
static bool getAbsolutePath(const std::string &relativeFilename, std::string &storeAbsoluteFilename, const std::vector< std::string > &additionalSearchPaths={}, bool verbose=true)
Property< PropertyType > getProperty(const std::string &name)
The FramedOrientation class.
Definition FramedPose.h:216
The FramedPosition class.
Definition FramedPose.h:158
Implements a Variant type for timestamps.
The Variant class is described here: Variants.
Definition Variant.h:224
SegmentableRecognitionWrapper offers a simplified access to the data of an object class or instance r...
ImageFormatInfo getImageFormat() const
Retrieve format of input images.
bool getImagesAreUndistorted() const
Retrieve whether images are undistorted.
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.
bool initRecognizer() override
Initializes segmentable recognition.
memoryx::ObjectLocalizationResultList localizeObjectClasses(const std::vector< std::string > &objectClassNames, CByteImage **cameraImages, armarx::MetaInfoSizeBasePtr imageMetaInfo, CByteImage **resultImages) override
localizes segmentable object instances
bool addObjectClass(const memoryx::EntityPtr &objectClassEntity, const memoryx::GridFileManagerPtr &fileManager) override
Add object class to segmentable object recognition.
#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_VERBOSE_S
Definition Logging.h:207
#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.
std::map< std::string, VariantBasePtr > StringVariantBaseMap
const LogSender::manipulator flush
Definition LogSender.h:251
IceInternal::Handle< SegmentableRecognitionWrapper > SegmentableRecognitionWrapperPtr
IceInternal::Handle< Entity > EntityPtr
Typedef of EntityPtr as IceInternal::Handle<Entity> for convenience.
Definition Entity.h:45
std::shared_ptr< GridFileManager > GridFileManagerPtr
ArmarX headers.