utils.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 RobotAPI::ArmarXObjects::armem_objects
17 * @author Rainer Kartmann ( rainer dot kartmann at kit dot edu )
18 * @date 2022
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
23#include "utils.h"
24
25#include <cstddef>
26#include <cstdint>
27#include <random>
28#include <string>
29#include <vector>
30
31#include <pcl/point_types.h>
32
33#include <SimoxUtility/shapes/AxisAlignedBoundingBox.h>
34#include <VirtualRobot/ManipulationObject.h> // IWYU pragma: keep
35#include <VirtualRobot/VirtualRobot.h>
36#include <VirtualRobot/Visualization/TriMeshModel.h>
37#include <VirtualRobot/Visualization/VisualizationNode.h>
38
41
46#include <RobotAPI/libraries/ArmarXObjects/aron_conversions.h> // IWYU pragma: keep
48#include <RobotAPI/libraries/armem_objects/aron/FamiliarObjectInstance.aron.generated.h>
50
51namespace armarx::armem
52{
53
54 // Samples points from the surface of a TriMeshModel. The sampling is non-uniform
55 // and approximates picking barycentric coordinates per face with random weights.
56 // Returns a point cloud in the same coordinate frame as the mesh vertices.
57 pcl::PointCloud<pcl::PointXYZRGBA>
58 samplePointCloudFromTriMesh(const VirtualRobot::TriMeshModel& mesh, int sampleCount)
59 {
60 pcl::PointCloud<pcl::PointXYZRGBA> cloud;
61 if (mesh.faces.empty())
62 return cloud;
63
64 std::mt19937 gen{std::random_device{}()};
65 std::uniform_int_distribution<std::size_t> d{0, mesh.faces.size() - 1};
66
67 cloud.points.reserve(static_cast<std::size_t>(sampleCount));
68
69 for (int i = 0; i < sampleCount; ++i)
70 {
71 const auto& f = mesh.faces.at(d(gen));
72 const float f0 = 1 + d(gen);
73 const float f1 = 1 + d(gen);
74 const float f2 = 1 + d(gen);
75 Eigen::Vector3f factors = Eigen::Vector3f{f0, f1, f2}.normalized();
76 factors /= factors.sum();
77 const Eigen::Vector3f pt = factors(0) * mesh.vertices.at(f.id1) +
78 factors(1) * mesh.vertices.at(f.id2) +
79 factors(2) * mesh.vertices.at(f.id3);
80
81 pcl::PointXYZRGBA point;
82 point.x = pt.x();
83 point.y = pt.y();
84 point.z = pt.z();
85
86 // use the color of the first vertex (approximation)
87 const auto color = mesh.colors.at(f.id1);
88
89 point.r = static_cast<std::uint8_t>(color.r * 255);
90 point.g = static_cast<std::uint8_t>(color.g * 255);
91 point.b = static_cast<std::uint8_t>(color.b * 255);
92
93 cloud.points.push_back(point);
94 }
95
96 cloud.is_dense = true;
97 cloud.width = cloud.points.size();
98 cloud.height = 1;
99
100 return cloud;
101 }
102
103 MemoryID
105 {
106 armem::MemoryID id =
107 armem::objects::instaceSegmentID.withProviderSegmentName(objectPose.providerName)
108 .withEntityName(objectPose.objectID.str())
109 .withTimestamp(objectPose.timestamp)
110 .withInstanceIndex(0);
111 return id;
112 }
113
114 armarx::armem::arondto::FamiliarObjectInstance
116 const VirtualRobot::ManipulationObject& manipulationObject,
117 const armarx::ObjectID& objectID)
118 {
119
120 const std::string agent = ""; // unused as it is the global frame
121
122 armarx::armem::arondto::FamiliarObjectInstance familiarObject;
123
124 familiarObject.timestamp = armarx::Clock::Now();
125
126 // Use the object's global pose as both sensor and global pose. Caller may override frames.
127 const Eigen::Matrix4f objPose = manipulationObject.getGlobalPose();
128
129 familiarObject.poseSensFrame.pose = objPose;
130 familiarObject.poseSensFrame.header.frame = armarx::GlobalFrame;
131 familiarObject.poseSensFrame.header.agent = agent;
132
133 familiarObject.poseGlobal.emplace();
134 familiarObject.poseGlobal->pose = objPose;
135 familiarObject.poseGlobal->header.frame = armarx::GlobalFrame;
136 familiarObject.poseGlobal->header.agent = agent;
137
138 toAron(familiarObject.objectID, objectID);
139 familiarObject.confidence = 1.0f;
140
141 // Try to obtain the visualization mesh and sample points similarly to the existing example.
142 ARMARX_CHECK_NOT_NULL(manipulationObject.getVisualization())
143 << "ManipulationObject has no visualization node.";
144 const auto mesh = manipulationObject.getVisualization()->getTriMeshModel();
145
146 if (mesh && !mesh->faces.empty())
147 {
148 std::mt19937 gen{std::random_device{}()};
149 std::uniform_int_distribution<std::size_t> d{0, mesh->faces.size() - 1};
150
151 ARMARX_CHECK_NOT_EMPTY(mesh->faces);
152
153 auto nonUniformSampleSurface = [mesh = *mesh, &gen, &d]() -> pcl::PointXYZRGBA
154 {
155 const auto& f = mesh.faces.at(d(gen));
156 const float f0 = 1 + d(gen);
157 const float f1 = 1 + d(gen);
158 const float f2 = 1 + d(gen);
159 Eigen::Vector3f factors = Eigen::Vector3f{f0, f1, f2}.normalized();
160 factors /= factors.sum();
161 const Eigen::Vector3f pt = factors(0) * mesh.vertices.at(f.id1) +
162 factors(1) * mesh.vertices.at(f.id2) +
163 factors(2) * mesh.vertices.at(f.id3);
164
165 pcl::PointXYZRGBA point;
166 point.x = pt.x();
167 point.y = pt.y();
168 point.z = pt.z();
169
170 // we use the color of the first vertex (approximation)
171 const auto color = mesh.colors.at(f.id1);
172
173 point.r = static_cast<std::uint8_t>(color.r * 255);
174 point.g = static_cast<std::uint8_t>(color.g * 255);
175 point.b = static_cast<std::uint8_t>(color.b * 255);
176
177 return point;
178 };
179
180 const int sampleCount = 1000;
181 for (int i = 0; i < sampleCount; ++i)
182 {
183 familiarObject.points.points.push_back(nonUniformSampleSurface());
184 }
185
186 familiarObject.points.header.frame_id = armarx::GlobalFrame;
187 familiarObject.points.is_dense = true;
188 familiarObject.points.width = familiarObject.points.points.size();
189 familiarObject.points.height = 1;
190
191 std::vector<Eigen::Vector3f> sampledPoints;
192 sampledPoints.reserve(familiarObject.points.points.size());
193 for (const auto& pt : familiarObject.points.points)
194 {
195 sampledPoints.emplace_back(pt.x, pt.y, pt.z);
196 }
197
198 auto aabb = simox::aabb::from_points(sampledPoints);
199 familiarObject.bounding_box.center = aabb.center();
200 familiarObject.bounding_box.extents = aabb.extents();
201 }
202
203 return familiarObject;
204 }
205} // namespace armarx::armem
#define ARMARX_CHECK_NOT_EMPTY(c)
static DateTime Now()
Current time on the virtual clock.
Definition Clock.cpp:93
A known object ID of the form "Dataset/ClassName" or "Dataset/ClassName/InstanceName".
Definition ObjectID.h:11
std::string str() const
Return "dataset/className" or "dataset/className/instanceName".
Definition ObjectID.cpp:60
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
std::string const GlobalFrame
Variable of the global coordinate system.
Definition FramedPose.h:65
armarx::armem::arondto::FamiliarObjectInstance createFamiliarObjectInstanceFromManipulationObject(const VirtualRobot::ManipulationObject &manipulationObject, const armarx::ObjectID &objectID)
createFamiliarObjectInstanceFromManipulationObject Create a FamiliarObjectInstance from a known Manip...
Definition utils.cpp:115
const MemoryID instaceSegmentID
armem::MemoryID reconstructObjectInstanceID(const objpose::ObjectPose &objectPose)
Definition utils.cpp:104
pcl::PointCloud< pcl::PointXYZRGBA > samplePointCloudFromTriMesh(const VirtualRobot::TriMeshModel &mesh, int sampleCount)
Definition utils.cpp:58
void toAron(arondto::MemoryID &dto, const MemoryID &bo)
An object pose as stored by the ObjectPoseStorage.
Definition ObjectPose.h:34
armarx::ObjectID objectID
The object ID, i.e. dataset, class name and instance name.
Definition ObjectPose.h:56
std::string providerName
Name of the providing component.
Definition ObjectPose.h:59
DateTime timestamp
Source timestamp.
Definition ObjectPose.h:98