ObjectShapeClassification.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5 *
6 * ArmarX is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ArmarX is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * @package
19 * @author
20 * @date
21 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22 * GNU General Public License
23 */
24
26
27#include <stdio.h>
28
29#include <iostream>
30#include <iterator> //Needed for vector-to-string. CPP is ugly
31#include <sstream>
32
33#include <boost/filesystem.hpp>
34
36
38#include "Features/Features.h"
39#include "ICP.h"
40#include "IVPointParser.hpp"
41#include "convexHull.hpp"
42#include <Math/Math3d.h>
45
46
47using std::cout;
48using std::endl;
49
50const std::string ATTR_FEATURES = "RecognitionFeatures";
51const std::string ATTR_IV_FILE = "IvFile";
52
53using namespace visionx;
54using namespace memoryx;
55
56void
58{
59 settings_priorMemory = getProperty<std::string>("PriorKnowledgeMemoryProxyName").getValue();
60 usingProxy(settings_priorMemory);
61
62 featureCalculator.addFeature<CHArea>();
63 featureCalculator.addFeature<CHVolume>();
64
65 featureCalculator.addFeature<BBVolume>();
66 featureCalculator.addFeature<BBArea>();
67 featureCalculator.addFeature<BBLongSide>();
68 featureCalculator.addFeature<BBShortSide>();
69 featureCalculator.addFeature<BBMediumSide>();
70 featureCalculator.addFeature<BBLongShortRatio>();
71 featureCalculator.addFeature<BBMediumShortRatio>();
72
73 featureCalculator.addFeature<D2Histogram>();
74 featureCalculator.addFeature<A3Histogram>();
75}
76
77void
79{
80 memoryPrx = getProxy<PriorKnowledgeInterfacePrx>(settings_priorMemory);
81 classesSegmentPrx = memoryPrx->getObjectClassesSegment();
82 databasePrx = memoryPrx->getCommonStorage();
83
84 fileManager.reset(new GridFileManager(databasePrx));
85
86 connected = databasePrx->isConnected();
87}
88
89void
90ObjectShapeClassification::refetchObjects()
91{
92 ARMARX_VERBOSE << "Refetching objects from DB" << armarx::flush;
93 boost::recursive_mutex::scoped_lock lock(mutexEntities);
94 EntityIdList ids = classesSegmentPrx->getAllEntityIds();
95 dbObjects.clear();
96
97 for (EntityIdList::const_iterator it = ids.begin(); it != ids.end(); ++it)
98 {
99 const EntityBasePtr entity = classesSegmentPrx->getEntityById(*it);
100 const ObjectClassPtr objClass = ObjectClassPtr::dynamicCast(entity);
101
102 if (objClass)
103 {
104 ARMARX_VERBOSE << *objClass << armarx::flush;
105 dbObjects.push_back(objClass);
106 }
107 }
108}
109
110void
111ObjectShapeClassification::checkFeatures()
112{
113 for (auto optr : dbObjects)
114 {
115 //Check if the object has the feature attribute
116 if (!optr->hasAttribute(ATTR_FEATURES))
117 {
118 //Calculate the attributes for this object
119 }
120
121 //Compare to the attributes of the current object
122 }
123}
124
125Points
126ObjectShapeClassification::getPointsFromIV(ObjectClassPtr obj)
127{
128 //Cache the file
129 std::string ivFile = "";
130 Points ps;
131
132 if (obj->hasAttribute(ATTR_IV_FILE))
133 {
134 fileManager->ensureFileInCache(obj->getAttribute(ATTR_IV_FILE), ivFile, false);
135 ps = IVPointParser::fromFile(ivFile);
136 }
137 else
138 {
139 ARMARX_WARNING << "No IV file found for object" << obj->getName();
140 }
141
142 return ps;
143}
144
146{
147 template <typename Pair>
148 bool
149 operator()(const Pair& a, const Pair& b)
150 {
151 return a.second < b.second;
152 }
153};
154
156ObjectShapeClassification::compareToDB(Points& points)
157{
158 std::vector<std::pair<std::string, Points>> objectsPoints;
159
160 //Get the points from every object
161 for (auto& obj : dbObjects)
162 {
163 auto points = getPointsFromIV(obj);
164
165 if (points.size() != 0)
166 {
167 objectsPoints.push_back(TaggedPoints(obj->getName(), points));
168 }
169 }
170
171 ARMARX_VERBOSE << "Calculating features of new points...";
172 //Calculuate the features of the new object
173 auto newObjectFeatures = featureCalculator.getFeatures(points);
174 ARMARX_VERBOSE << "Calculated new features";
175
176 //Print the points and features (for parsing and learning) ======================
177 //Points pointsTransposed = Points(points.size());
178 //std::transform(points.begin(), points.end(), pointsTransposed.end(), [&](Point& p) {return p.transpose();}); //Transpose the points, so they are printed horizontally
179 //std::ostringstream oss;
180 //Put the vector into a string, so that we can give it to ARMARX_* in a single line....
181 //if (!pointsTransposed.empty()) {
182 // // Convert all but the last element to avoid a trailing ","
183 // std::copy(pointsTransposed.begin(), pointsTransposed.end()-1,
184 // std::ostream_iterator<Point>(oss, ","));
185 // // Now add the last element with no delimiter
186 // oss << pointsTransposed.back();
187 //}
188 //ARMARX_VERBOSE << "-- Points: [" << oss.str() << "]";
189 //Finished printing points =======================================================
190
191 //Now also print the features of the new object
192 for (const auto& feat : newObjectFeatures)
193 {
194 ARMARX_VERBOSE << "-- " << feat.first << ": " << *(feat.second);
195 }
196
197
198 //Now actually go on doing useful work....
199 std::map<std::string, std::map<std::string, double>> objectDiffs;
200 std::map<std::string, double> maxDiffs;
201
202 ARMARX_VERBOSE << "Now iterating over the db objects...";
203
204 //For every object, get the features, or calculate them
205 for (const auto& obj : objectsPoints)
206 {
207 ARMARX_VERBOSE << " Getting features for: " << obj.first;
208 auto features = featureCalculator.getFeatures(obj.second);
209 std::map<std::string, double> diffs;
210
211 //Compare to the new object, iterating over every feature
212 for (const auto& p : newObjectFeatures)
213 {
214 auto& feature = p.second;
215 double diff = feature->compare(*features[feature->name()]);
216 diffs[feature->name()] = diff;
217
218 //Store the maximum value of each feature, to normalize later.
219 double oldValue = maxDiffs[feature->name()];
220 maxDiffs[feature->name()] = (diff > oldValue) ? diff : oldValue;
221 }
222
223 objectDiffs[obj.first] = diffs;
224 }
225
226 std::map<std::string, double> objectDiffsTotal;
227
228 //For each object get the total diff
229 for (const auto& obj : objectDiffs)
230 {
231 //Get the sum of the differences of each feature, normalized.
232 ARMARX_VERBOSE << "--\n-- " << obj.first << ": ";
233 double totalDiff = std::accumulate(obj.second.begin(),
234 obj.second.end(),
235 0.0,
236 [&](double prev, const std::pair<std::string, double> p)
237 {
238 double diff = (p.second / maxDiffs[p.first]);
239 ARMARX_VERBOSE_S << "-- " << p.first << ": " << diff;
240 return prev + (p.second / maxDiffs[p.first]);
241 });
242 objectDiffsTotal[obj.first] = totalDiff;
243 ARMARX_VERBOSE << "--+ Total score(" << obj.first << "): " << totalDiff << "\n";
244 }
245
246
247 auto bestMatch =
248 *std::min_element(objectDiffsTotal.begin(), objectDiffsTotal.end(), by_second());
249
250 ARMARX_INFO << "Best match found: " << bestMatch.first << " with score of " << bestMatch.second;
251
252 return bestMatch;
253}
254
255void
256ObjectShapeClassification::matchToFoundPointCloud(const Points& newPoints,
257 const Points& foundPointCloud)
258{
259 ARMARX_VERBOSE << "Running ICP...";
260 ICP icp;
261 icp.SetScenePointcloud(foundPointCloud);
262 icp.SetObjectPointcloud(newPoints);
263
264 Mat3d rotation;
265 Vec3d translation;
266 double msd = icp.SearchObject(rotation, translation);
267 ARMARX_IMPORTANT << "Mean square difference to found point cloud: " << msd;
268}
269
270std::string
271ObjectShapeClassification::FindSimilarKnownObject(const types::PointList& segmentedObjectPoints,
272 const Ice::Current&)
273{
274 Points points;
275
276 for (size_t i = 0; i < segmentedObjectPoints.size(); i++)
277 {
278 points.push_back(armarx::Vector3Ptr::dynamicCast(segmentedObjectPoints.at(i))->toEigen());
279 }
280
281 ARMARX_VERBOSE << "Loaded " << points.size() << " data points.";
282
283 if (connected)
284 {
285 ARMARX_INFO << "Connected to DB, starting classification";
286
287 //Make sure we have all the objects
288 refetchObjects();
289
290 //Compare to the database and return the name of the best matched object
291 TaggedPoints foundPointCloud = compareToDB(points);
292 matchToFoundPointCloud(points, foundPointCloud.second);
293
294 ARMARX_IMPORTANT << "The hypothesis had " << points.size() << " points";
295
296 return foundPointCloud.first;
297 }
298 else
299 {
300 ARMARX_WARNING << "No connection to DB. Unable to start classification";
301 }
302
303 return "ERROR: No similar object found";
304}
const std::string ATTR_IV_FILE
const std::string ATTR_FEATURES
static std::vector< Eigen::Vector3f > fromFile(const std::string &fileName)
Property< PropertyType > getProperty(const std::string &name)
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)
GridFileManager provides utility functions for working with files in Mongo GridFS and links to them s...
void SetScenePointcloud(const std::vector< Eigen::Vector3f > &aScenePoints)
Definition ICP.cpp:58
void SetObjectPointcloud(const std::vector< Eigen::Vector3f > &aObjectPoints)
Definition ICP.cpp:96
float SearchObject(Mat3d &mRotation, Vec3d &vTranslation, const float fBestDistanceUntilNow=FLT_MAX)
Definition ICP.cpp:107
std::string FindSimilarKnownObject(const ::visionx::types::PointList &segmentedObjectPoints, const ::Ice::Current &)
void onInitComponent()
Pure virtual hook for the subclass.
void onConnectComponent()
Pure virtual hook for the subclass.
#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_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
VectorXD< 3, double > Vec3d
Definition VectorXD.h:737
const LogSender::manipulator flush
Definition LogSender.h:251
VirtualRobot headers.
IceInternal::Handle< ObjectClass > ObjectClassPtr
Definition ObjectClass.h:35
ArmarX headers.
std::vector< Point > Points
std::pair< std::string, Points > TaggedPoints
bool operator()(const Pair &a, const Pair &b)