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 <SegmentableRecognition/SegmentableDatabase.h>
36 #include <Image/ImageProcessor.h>
37 
38 // MemoryX
42 
43 // 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)!
44 // GLContext.h indirectly includes X.h which does "#define None", colliding with IceUtil::None.
45 #include <gui/GLContext.h>
46 
47 using namespace armarx;
48 using namespace visionx;
49 using namespace memoryx::EntityWrappers;
50 
51 
52 SegmentableObjectRecognition::SegmentableObjectRecognition()
53 {
54 }
55 
56 SegmentableObjectRecognition::~SegmentableObjectRecognition()
57 {
58 
59 }
60 
61 void SegmentableObjectRecognition::onExitObjectLocalizerProcessor()
62 {
63 
64 }
65 
66 bool 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: " << colorParemeterFilename;
83  }
84 
85 
86  if (!segmentableRecognition)
87  {
88  colorParameters.reset(new CColorParameterSet());
89 
90  if (!colorParameters->LoadFromFile(colorParemeterFilename.c_str()))
91  {
92  throw armarx::LocalException("Could not read color parameter file.");
93  }
94 
95  ARMARX_VERBOSE << "Startup step 1";
96 
97  segmentableRecognition.reset(new CSegmentableRecognition());
98 
99  ARMARX_VERBOSE << "Startup step 2";
100 
101  // create context
102  ImageFormatInfo imageFormat = getImageFormat();
103  contextGL.reset(new CGLContext());
104 
105  ARMARX_VERBOSE << "Startup step 3";
106 
107  contextGL->CreateContext(imageFormat.dimension.width, imageFormat.dimension.height);
108 
109  ARMARX_VERBOSE << "Startup step 4";
110 
111  contextGL->MakeCurrent();
112 
113  m_pOpenGLVisualizer.reset(new COpenGLVisualizer());
114  m_pOpenGLVisualizer->InitByCalibration(getStereoCalibration()->GetRightCalibration());
115 
116  ARMARX_VERBOSE << "Startup step 5";
117 
118  // init segmentable recognition
119  bool success = segmentableRecognition->InitWithoutDatabase(colorParameters.get(), getStereoCalibration());
120 
121  if (!success)
122  {
123  throw armarx::LocalException("Could not initialize segmentable object database.");
124  }
125 
126  float sizeRatioThreshold = getProperty<float>("SizeRatioThreshold").getValue();
127  float correlationThreshold = getProperty<float>("CorrelationThreshold").getValue();
128  segmentableRecognition->GetObjectDatabase()->SetRecognitionThresholds(sizeRatioThreshold, correlationThreshold);
129 
130  ARMARX_VERBOSE << "SegmentableObjectRecognition is initialized";
131 
132  return success;
133  }
134 
135  ARMARX_VERBOSE << "SegmentableObjectRecognition is initialized";
136 
137  return true;
138 }
139 
140 bool SegmentableObjectRecognition::addObjectClass(const memoryx::EntityPtr& objectClassEntity, const memoryx::GridFileManagerPtr& fileManager)
141 {
142  ARMARX_VERBOSE << "Adding object class " << objectClassEntity->getName() << armarx::flush;
143 
144  SegmentableRecognitionWrapperPtr recognitionWrapper = objectClassEntity->addWrapper(new SegmentableRecognitionWrapper(fileManager));
145  std::string dataPath = recognitionWrapper->getDataFiles();
146  ObjectColor color = recognitionWrapper->getObjectColor();
147 
148  std::string colorString;
149  CColorParameterSet::Translate(color, colorString);
150  ARMARX_VERBOSE << "Color: " << (int)color << " (" << colorString << ")";
151 
152  if (dataPath != "")
153  {
154  if (!segmentableRecognition->GetObjectDatabase()->AddClass(dataPath, "", objectClassEntity->getName()))
155  {
156  ARMARX_INFO << "Skipped object class: " << objectClassEntity->getName();
157  return false;
158  }
159 
160  // remember colors
161  std::string className = objectClassEntity->getName();
162  objectColors.insert(std::make_pair(className, color));
163 
164  return true;
165  }
166  else
167  {
168  ARMARX_WARNING << "Datapath is empty for " << objectClassEntity->getName() << " object class - make sure you set the correct model file in PriorKnowledge!";
169  }
170 
171  return false;
172 }
173 
174 memoryx::ObjectLocalizationResultList SegmentableObjectRecognition::localizeObjectClasses(const std::vector<std::string>& objectClassNames, CByteImage** cameraImages, armarx::MetaInfoSizeBasePtr imageMetaInfo, CByteImage** resultImages)
175 {
176 
177  if (objectClassNames.size() < 1)
178  {
179  ARMARX_WARNING << "objectClassNames.size() = " << objectClassNames.size() << ", something is wrong here! ";
180 
181  memoryx::ObjectLocalizationResultList resultList;
182  return resultList;
183  }
184 
185  std::string allObjectNames;
186 
187  for (size_t i = 0; i < objectClassNames.size(); i++)
188  {
189  allObjectNames.append(" ");
190  allObjectNames.append(objectClassNames.at(i));
191  }
192 
193  ARMARX_VERBOSE << "Localizing" << allObjectNames;
194 
195  contextGL->MakeCurrent();
196 
197  Object3DList objectList;
198 
199  if (objectClassNames.size() < 10)
200  {
201  std::string color;
202 
203  for (size_t i = 0; i < objectClassNames.size(); i++)
204  {
205  CColorParameterSet::Translate(objectColors[objectClassNames.at(i)], color);
206  ARMARX_VERBOSE << "Localizing " << objectClassNames.at(i) << ", color: " << color << flush;
207 
208  segmentableRecognition->DoRecognitionSingleObject(cameraImages, resultImages, objectClassNames.at(i).c_str(), minPixelsPerRegion, maxEpipolarDistance, objectColors[objectClassNames.at(i)], false, getImagesAreUndistorted());
209 
210  Object3DList result = segmentableRecognition->GetObject3DList();
211 
212  for (size_t j = 0; j < result.size(); j++)
213  {
214  objectList.push_back(result.at(j));
215  }
216 
217  ARMARX_VERBOSE << "Found " << result.size() << " instances";
218  }
219  }
220  else
221  {
222  ARMARX_VERBOSE << "Localizing everything at once";
223 
224  segmentableRecognition->DoRecognition(cameraImages, resultImages, minPixelsPerRegion, false, maxEpipolarDistance, eNone, false, getImagesAreUndistorted());
225 
226  objectList = segmentableRecognition->GetObject3DList();
227  }
228 
229 
230 
231  ARMARX_INFO << "Found " << objectList.size() << " objects";
232 
233 
234 
235  // help for problem analysis
236  if (objectList.size() == 0)
237  {
238  ARMARX_INFO << "Looked unsuccessfully for:";
239  std::string color;
240 
241  for (size_t i = 0; i < objectClassNames.size(); i++)
242  {
243  CColorParameterSet::Translate(objectColors[objectClassNames.at(i)], color);
244  ARMARX_INFO << objectClassNames.at(i) << " color: " << color << flush;
245  }
246  }
247  else
248  {
249  visualizeResults(objectList, resultImages);
250  }
251 
252  const auto agentName = getProperty<std::string>("AgentName").getValue();
253 
254  memoryx::ObjectLocalizationResultList resultList;
255 
256  for (Object3DList::iterator iter = objectList.begin() ; iter != objectList.end() ; iter++)
257  {
258  // assure instance belongs to queried class
259  bool queriedClass = (std::find(objectClassNames.begin(), objectClassNames.end(), iter->sName) != objectClassNames.end());
260 
261  if (iter->localizationValid && queriedClass)
262  {
263  float x = iter->pose.translation.x;
264  float y = iter->pose.translation.y;
265  float z = iter->pose.translation.z;
266 
267  if (seq.count(iter->sName))
268  {
269  seq[iter->sName]++;
270  }
271  else
272  {
273  seq[iter->sName] = 0;
274  }
275 
276 
277 
278 
279  StringVariantBaseMap mapValues;
280  mapValues["x"] = new Variant(x);
281  mapValues["y"] = new Variant(y);
282  mapValues["z"] = new Variant(z);
283  mapValues["name"] = new Variant(iter->sName);
284  mapValues["sequence"] = new Variant(seq[iter->sName]);
285  mapValues["timestamp"] = new Variant(imageMetaInfo->timeProvided / 1000.0 / 1000.0);
286  debugObserver->setDebugChannel("ObjectRecognition", mapValues);
287 
288 
289 
290  // only accept realistic positions
291  if (x > validResultBoundingBoxMin.x && y > validResultBoundingBoxMin.y && z > validResultBoundingBoxMin.z &&
292  x < validResultBoundingBoxMax.x && y < validResultBoundingBoxMax.y && z < validResultBoundingBoxMax.z)
293  {
294  // assemble result
295  memoryx::ObjectLocalizationResult result;
296 
297  // position and orientation
298  Eigen::Vector3f position(iter->pose.translation.x, iter->pose.translation.y, iter->pose.translation.z);
299  Eigen::Matrix3f orientation;
300  orientation << iter->pose.rotation.r1, iter->pose.rotation.r2, iter->pose.rotation.r3,
301  iter->pose.rotation.r4, iter->pose.rotation.r5, iter->pose.rotation.r6,
302  iter->pose.rotation.r7, iter->pose.rotation.r8, iter->pose.rotation.r9;
303 
304  result.position = new armarx::FramedPosition(position, referenceFrameName, agentName);
305  result.orientation = new armarx::FramedOrientation(orientation, referenceFrameName, agentName);
306 
307  // calculate noise
308  result.positionNoise = calculateLocalizationUncertainty(iter->region_left.centroid, iter->region_right.centroid);
309 
310  // calculate recognition certainty
311  result.recognitionCertainty = 0.5f + 0.5f * calculateRecognitionCertainty(iter->sName, *iter);
312  result.objectClassName = iter->sName;
313  result.timeStamp = new TimestampVariant(imageMetaInfo->timeProvided);
314 
315  resultList.push_back(result);
316  }
317  else
318  {
319  ARMARX_VERBOSE_S << "Refused unrealistic localization at position: " << x << " " << y << " " << z;
320  }
321  }
322  }
323 
324  ARMARX_VERBOSE << "Finished localizing " << objectClassNames.at(0);
325 
326  return resultList;
327 }
328 
329 
330 
331 float SegmentableObjectRecognition::calculateRecognitionCertainty(const std::string& objectClassName, const Object3DEntry& entry)
332 {
333  float foundProb = entry.quality * entry.quality2;
334  float notFoundProb = (1 - entry.quality) * (1 - entry.quality2);
335 
336  if (foundProb <= 0)
337  {
338  return 0.0f;
339  }
340 
341  return foundProb / (foundProb + notFoundProb);
342 }
343 
344 
345 
346 void SegmentableObjectRecognition::visualizeResults(const Object3DList& objectList, CByteImage** resultImages)
347 {
348  m_pOpenGLVisualizer->ActivateShading(true);
349  glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
350 
351 
352  m_pOpenGLVisualizer->SetProjectionMatrix(getStereoCalibration()->GetRightCalibration());
353 
354  m_pOpenGLVisualizer->Clear();
355 
356 
357  for (int i = 0; i < (int) objectList.size(); i++)
358  {
359  const Object3DEntry& entry = objectList.at(i);
360  CSegmentableDatabase::DrawObjectFromFile(m_pOpenGLVisualizer.get(), entry.sOivFilePath.c_str(), entry.pose);
361  }
362 
363  const int nImageIndex = 1;
364 
365  if (resultImages && resultImages[nImageIndex])
366  {
367  CByteImage tempImage(resultImages[nImageIndex]);
368  m_pOpenGLVisualizer->GetImage(&tempImage);
369  ::ImageProcessor::FlipY(&tempImage, &tempImage);
370  const int nBytes = 3 * tempImage.width * tempImage.height;
371  const unsigned char* pixels = tempImage.pixels;
372  unsigned char* output = resultImages[nImageIndex]->pixels;
373 
374  for (int i = 0; i < nBytes; i += 3)
375  {
376  if (pixels[i])
377  {
378  const unsigned char g = pixels[i];
379  output[i] = g;
380  output[i + 1] = g;
381  output[i + 2] = g;
382  }
383  }
384  }
385 }
386 
armarx::Variant
The Variant class is described here: Variants.
Definition: Variant.h:224
ARMARX_VERBOSE
#define ARMARX_VERBOSE
Definition: Logging.h:180
armarx::StringVariantBaseMap
std::map< std::string, VariantBasePtr > StringVariantBaseMap
Definition: ManagedIceObject.h:111
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:89
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:189
GfxTL::Matrix3f
MatrixXX< 3, 3, float > Matrix3f
Definition: MatrixXX.h:600
memoryx::EntityWrappers
Definition: AbstractEntityWrapper.cpp:28
armarx::VariantType::FramedOrientation
const VariantTypeId FramedOrientation
Definition: FramedPose.h:40
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:174
memoryx::GridFileManagerPtr
std::shared_ptr< GridFileManager > GridFileManagerPtr
Definition: AbstractEntityWrapper.h:32
ARMARX_VERBOSE_S
#define ARMARX_VERBOSE_S
Definition: Logging.h:200
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:111
armarx::VariantType::FramedPosition
const VariantTypeId FramedPosition
Definition: FramedPose.h:39
ARMARX_WARNING
#define ARMARX_WARNING
Definition: Logging.h:186
ArmarXDataPath.h
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:28
armarx::status::success
@ success