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 
48 using namespace armarx;
49 using namespace visionx;
50 using namespace memoryx::EntityWrappers;
51 
52 SegmentableObjectRecognition::SegmentableObjectRecognition()
53 {
54 }
55 
56 SegmentableObjectRecognition::~SegmentableObjectRecognition()
57 {
58 }
59 
60 void
61 SegmentableObjectRecognition::onExitObjectLocalizerProcessor()
62 {
63 }
64 
65 bool
66 SegmentableObjectRecognition::initRecognizer()
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(),
121  getStereoCalibration());
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 
143 bool
144 SegmentableObjectRecognition::addObjectClass(const memoryx::EntityPtr& objectClassEntity,
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 
183 memoryx::ObjectLocalizationResultList
184 SegmentableObjectRecognition::localizeObjectClasses(
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,
225  resultImages,
226  objectClassNames.at(i).c_str(),
227  minPixelsPerRegion,
228  maxEpipolarDistance,
229  objectColors[objectClassNames.at(i)],
230  false,
231  getImagesAreUndistorted());
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,
248  resultImages,
249  minPixelsPerRegion,
250  false,
251  maxEpipolarDistance,
252  eNone,
253  false,
254  getImagesAreUndistorted());
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 
364 float
365 SegmentableObjectRecognition::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 
379 void
380 SegmentableObjectRecognition::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 }
armarx::Variant
The Variant class is described here: Variants.
Definition: Variant.h:223
ARMARX_VERBOSE
#define ARMARX_VERBOSE
Definition: Logging.h:187
armarx::StringVariantBaseMap
std::map< std::string, VariantBasePtr > StringVariantBaseMap
Definition: ManagedIceObject.h:110
visionx
ArmarX headers.
Definition: OpenPoseStressTest.h:38
Pose.h
armarx::TimestampVariant
Definition: TimestampVariant.h:54
SegmentableObjectRecognition.h
ObjectRecognitionWrapper.h
memoryx::EntityWrappers::SegmentableRecognitionWrapper
SegmentableRecognitionWrapper offers a simplified access to the data of an object class or instance r...
Definition: ObjectRecognitionWrapper.h:85
IceInternal::Handle
Definition: forward_declarations.h:8
FramedPose.h
armarx::flush
const LogSender::manipulator flush
Definition: LogSender.h:251
TimestampVariant.h
MemoryXCoreObjectFactories.h
ARMARX_ERROR
#define ARMARX_ERROR
Definition: Logging.h:196
memoryx::EntityWrappers
Definition: AbstractEntityWrapper.cpp:30
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
magic_enum::detail::find
constexpr std::size_t find(string_view str, char_type c) noexcept
Definition: magic_enum.hpp:309
ARMARX_VERBOSE_S
#define ARMARX_VERBOSE_S
Definition: Logging.h:207
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_WARNING
#define ARMARX_WARNING
Definition: Logging.h:193
ArmarXDataPath.h
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27
armarx::status::success
@ success