IntelRealSenseProvider.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::ArmarXObjects::IntelRealSenseProvider
17  * @author Simon Thelen ( urday at student dot kit dot edu )
18  * @date 2018
19  * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20  * GNU General Public License
21  */
22 
23 #include "IntelRealSenseProvider.h"
24 
25 #include <stdio.h>
26 
27 #include <filesystem>
28 
32 
35 
36 #include <Image/ImageProcessor.h>
37 #include <librealsense2/h/rs_sensor.h>
38 #include <librealsense2/rs.hpp>
39 #include <librealsense2/rs_advanced_mode.hpp>
40 #include <librealsense2/rsutil.h>
41 
42 using namespace armarx;
43 using namespace visionx;
44 
45 void
46 IntelRealSenseProvider::onInitImageProvider()
47 {
48  Eigen::Vector2f fov = getProperty<Eigen::Vector2f>("FieldOfView");
49  depthUtils.setFieldOfView(fov(0), fov(1));
50  setNumberImages(2);
51  Eigen::Vector2i dimensions = getProperty<Eigen::Vector2i>("Resolution");
52  setImageFormat(visionx::ImageDimension(dimensions(0), dimensions(1)),
53  visionx::eRgb,
54  visionx::eBayerPatternGr);
55  depthImage.reset(visionx::tools::createByteImage(getImageFormat(), visionx::eRgb));
56  pointcloud.reset(new pcl::PointCloud<CloudPointType>());
57 
58  alignFilter.reset(new rs2::align(RS2_STREAM_COLOR));
59 }
60 
61 void
62 IntelRealSenseProvider::onInitCapturingPointCloudProvider()
63 {
64 }
65 
66 void
67 IntelRealSenseProvider::onExitCapturingPointCloudProvider()
68 {
69 }
70 
71 void
72 IntelRealSenseProvider::onStartCapture(float framesPerSecond)
73 {
74  ARMARX_VERBOSE << "starting pipe";
75 
76  //Create a configuration for configuring the pipeline with a non default profile
77  rs2::config cfg;
78 
79  Eigen::Vector2i dimensions = getProperty<Eigen::Vector2i>("Resolution").getValue();
80  //Add desired streams to configuration
81  cfg.enable_stream(
82  RS2_STREAM_COLOR, dimensions(0), dimensions(1), RS2_FORMAT_RGB8, framesPerSecond);
83  cfg.enable_stream(
84  RS2_STREAM_DEPTH, dimensions(0), dimensions(1), RS2_FORMAT_Z16, framesPerSecond);
85  rs2::pipeline_profile profile = pipe.start(cfg);
86 
87  rs2::device dev = profile.get_device();
88 
89  rs2::depth_sensor ds = dev.query_sensors().front().as<rs2::depth_sensor>();
90 
91  if (getProperty<std::string>("ConfigFile").isSet())
92  {
93  using namespace rs2;
94  context ctx;
95  auto devices = ctx.query_devices();
96  size_t device_count = devices.size();
97  if (!device_count)
98  {
99  throw armarx::LocalException("No device detected. Is it plugged in?\n");
100  }
101 
102  // Get the first connected device
103  auto dev = devices[0];
104 
105  // Enter advanced mode
106  if (dev.is<rs400::advanced_mode>())
107  {
108  // Get the advanced mode functionality
109  auto advanced_mode_dev = dev.as<rs400::advanced_mode>();
110 
111  // Load and configure .json file to device
112  std::string path = getProperty<std::string>("ConfigFile");
113  std::string absPath;
114  auto configFileFound = armarx::ArmarXDataPath::getAbsolutePath(path, absPath);
115  ARMARX_CHECK_EXPRESSION(configFileFound) << path;
116  ARMARX_INFO << "Loading realsense config from " << path;
117  std::ifstream t(path);
118  std::string str((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
119  advanced_mode_dev.load_json(str);
120  }
121  else
122  {
123  throw armarx::LocalException() << "Current device doesn't support advanced-mode!\n";
124  }
125  }
126  else
127  {
128  auto preset = getProperty<rs2_rs400_visual_preset>("Preset").getValue();
129  ARMARX_INFO << "Setting preset to: " << rs2_rs400_visual_preset_to_string(preset);
130  ds.set_option(RS2_OPTION_VISUAL_PRESET, preset);
131  }
132 
133  depthScale = ds.get_depth_scale();
134  ARMARX_VERBOSE << "pipe started";
135  ARMARX_VERBOSE << "depthScale: " << depthScale;
136  cloudFormat = getPointCloudFormat();
137  calibration = createStereoCalibration(profile);
138 
139  setMetaInfo(
140  "Baseline",
141  new Variant(std::to_string(calibration.calibrationRight.cameraParam.translation[0]) + ", " +
142  std::to_string(calibration.calibrationRight.cameraParam.translation[1]) + ", " +
143  std::to_string(calibration.calibrationRight.cameraParam.translation[2])));
144 }
145 
146 void
147 IntelRealSenseProvider::onStopCapture()
148 {
149  pipe.stop();
150 }
151 
152 bool
153 IntelRealSenseProvider::doCapture()
154 {
155  rs2::frameset data;
156  int timeout = 1000;
157  try
158  {
159  data = pipe.wait_for_frames(timeout);
160  }
161  catch (...)
162  {
163  ARMARX_INFO << deactivateSpam(30) << "Did not get frame until timeout of " << timeout
164  << " ms";
165  return false;
166  }
167 
168  auto rstimestamp = data.get_timestamp();
170  if (data.get_frame_timestamp_domain() == RS2_TIMESTAMP_DOMAIN_GLOBAL_TIME)
171  {
172  timestamp = IceUtil::Time::milliSeconds(rstimestamp);
173  }
174  else
175  {
177  ARMARX_WARNING << deactivateSpam(999999999)
178  << "Timestamp of realsense is not global - measuring time myself";
179  }
181  << deactivateSpam(1) << "frame age: "
182  << (IceUtil::Time::now() - IceUtil::Time::milliSeconds(rstimestamp)).toMilliSeconds()
183  << " ms";
184 
185 
186  if (getProperty<bool>("ApplyAlignmentFilter").getValue())
187  {
188  // TIMING_START(alignment);
189  data = alignFilter->process(data);
190  // TIMING_END(alignment);
191  }
192 
193  auto depthFrame = data.get_depth_frame();
194 
195  const bool applyDisparityFilter = getProperty<bool>("ApplyDisparityFilter").getValue();
196  if (applyDisparityFilter)
197  {
198  // TIMING_START(disparityFilter);
199  depthFrame = depth_to_disparity_filter.process(depthFrame);
200  // TIMING_END(disparityFilter);
201  }
202 
203 
204  if (getProperty<bool>("ApplySpatialFilter").getValue())
205  {
206  // TIMING_START(filter);
207  depthFrame = spat_filter.process(depthFrame);
208  // TIMING_END(filter);
209  }
210  if (getProperty<bool>("ApplyTemporalFilter").getValue())
211  {
212  // TIMING_START(tempFilter);
213  depthFrame = temporal_filter.process(depthFrame);
214  // TIMING_END(tempFilter);
215  }
216 
217  if (applyDisparityFilter)
218  {
219  // TIMING_START(disparityFilterBack);
220  depthFrame = disparity_to_depth_filter.process(depthFrame);
221  // TIMING_END(disparityFilterBack);
222  }
223 
224  rs2::frame color = data.get_color_frame();
225 
226 
227  if (!color)
228  {
229  color = data.get_infrared_frame();
230  }
231 
232 
233  const int cw = color.as<rs2::video_frame>().get_width();
234  const int ch = color.as<rs2::video_frame>().get_height();
235  auto colorBuffer = reinterpret_cast<const unsigned char*>(color.get_data());
236  CByteImage rgbImage(cw, ch, CByteImage::eRGB24, true);
237  rgbImage.pixels = const_cast<unsigned char*>(colorBuffer);
238 
239 
240  int index = 0;
241  int index2 = 0;
242  auto resultDepthBuffer = depthImage->pixels;
243  auto depthBuffer = reinterpret_cast<const unsigned short*>(depthFrame.get_data());
244  const int dw = depthFrame.as<rs2::video_frame>().get_width();
245  const int dh = depthFrame.as<rs2::video_frame>().get_height();
246 
247  for (int y = 0; y < dh; ++y)
248  {
249  for (int x = 0; x < dw; ++x)
250  {
251  int depthValue = 1000.f * depthBuffer[index2] * depthScale;
253  resultDepthBuffer[index],
254  resultDepthBuffer[index + 1],
255  resultDepthBuffer[index + 2]);
256  index += 3;
257  index2++;
258  }
259  }
260 
261  CByteImage* images[2] = {&rgbImage, depthImage.get()};
262  provideImages(images, timestamp);
263 
264 
265  // Tell pointcloud object to map to this color frame
266  pc.map_to(color);
267 
268  // Generate the pointcloud and texture mappings
269 
270  points = pc.calculate(depthFrame);
271 
272 
273  //convert to pcl cloud
274  {
275  ARMARX_CHECK_EXPRESSION(pointcloud);
276  pointcloud->width = dw;
277  pointcloud->height = dh;
278  pointcloud->is_dense = false;
279  pointcloud->points.resize(points.size());
280  auto ptr = points.get_vertices();
281  auto texPtr = points.get_texture_coordinates();
283  ARMARX_CHECK_EXPRESSION(texPtr);
284  float maxDepth = getProperty<float>("MaxDepth").getValue() / 1000.f; // in m
285  if (ptr && texPtr)
286  {
287  for (auto& p : pointcloud->points)
288  {
289  p.x = ptr->x * 1000.f; // m to mm
290  p.y = ptr->y * 1000.f;
291  p.z = ptr->z <= maxDepth ? ptr->z * 1000.f : std::nan("");
292  if (texPtr)
293  {
294  int x = texPtr->u * cw;
295  int y = texPtr->v * ch;
296  if (x >= 0 && x < cw && y >= 0 && y < ch)
297  {
298  auto colorIndex = int((x + y * cw) * 3);
299  p.r = colorBuffer[colorIndex];
300  p.g = colorBuffer[colorIndex + 1];
301  p.b = colorBuffer[colorIndex + 2];
302  }
303  else
304  {
305  p.r = p.g = p.b = 255;
306  }
307  }
308  ptr++;
309  texPtr++;
310  }
311  }
312  }
313 
314  pointcloud->header.stamp = timestamp.toMicroSeconds();
315  providePointCloud(pointcloud);
316  return true;
317 }
318 
319 std::string
320 IntelRealSenseProvider::getDefaultName() const
321 {
322  return "IntelRealSenseProvider";
323 }
324 
326 IntelRealSenseProvider::createPropertyDefinitions()
327 {
329  new IntelRealSenseProviderPropertyDefinitions(getConfigIdentifier()));
330 }
331 
332 void
333 IntelRealSenseProvider::onInitComponent()
334 {
335  ImageProvider::onInitComponent();
336  CapturingPointCloudProvider::onInitComponent();
337 }
338 
339 void
340 IntelRealSenseProvider::onConnectComponent()
341 {
342 
343  ImageProvider::onConnectComponent();
344  CapturingPointCloudProvider::onConnectComponent();
345 }
346 
347 void
348 IntelRealSenseProvider::onDisconnectComponent()
349 {
350  captureEnabled = false;
351 
352  ImageProvider::onDisconnectComponent();
353  CapturingPointCloudProvider::onDisconnectComponent();
354 }
355 
356 void
357 IntelRealSenseProvider::onExitComponent()
358 {
359  ImageProvider::onExitComponent();
360  CapturingPointCloudProvider::onExitComponent();
361 }
362 
363 visionx::StereoCalibration
364 IntelRealSenseProvider::getStereoCalibration(const Ice::Current&)
365 {
366  return calibration;
367 }
368 
369 bool
370 IntelRealSenseProvider::getImagesAreUndistorted(const Ice::Current& c)
371 {
372  return false;
373 }
374 
375 std::string
376 IntelRealSenseProvider::getReferenceFrame(const Ice::Current& c)
377 {
378  return getProperty<std::string>("frameName");
379 }
380 
381 StereoCalibration
382 IntelRealSenseProvider::createStereoCalibration(const rs2::pipeline_profile& selection) const
383 {
384 
385 
386  auto getIntrinsics =
387  [](visionx::CameraParameters& params, rs2::video_stream_profile& streamProfile)
388  {
389  // auto resolution = std::make_pair(streamProfile.width(), streamProfile.height());
390  auto i = streamProfile.get_intrinsics();
391  // auto principal_point = std::make_pair(i.ppx, i.ppy);
392  // auto focal_length = std::make_pair(i.fx, i.fy);
393  // rs2_distortion model = i.model;
394 
395 
396  params.focalLength.resize(2, 0.0f);
397  params.principalPoint.resize(2, 0.0f);
398  params.distortion.resize(4, 0.0f);
399 
400  //Eigen::Matrix3f id = Eigen::Matrix3f::Identity();
402  params.translation = visionx::tools::convertEigenVecToVisionX(Eigen::Vector3f::Zero());
403 
404  params.principalPoint[0] = i.ppx;
405  params.principalPoint[1] = i.ppy;
406  params.focalLength[0] = i.fx;
407  params.focalLength[1] = i.fy;
408  params.width = streamProfile.width();
409  params.height = streamProfile.height();
410  };
411  rs2::video_stream_profile rgb_stream =
412  selection.get_stream(RS2_STREAM_COLOR).as<rs2::video_stream_profile>();
413  rs2::video_stream_profile depth_stream =
414  selection.get_stream(RS2_STREAM_DEPTH).as<rs2::video_stream_profile>();
415 
416  visionx::CameraParameters rgbParams;
417  visionx::CameraParameters depthParams;
418 
419  getIntrinsics(rgbParams, rgb_stream);
420  getIntrinsics(depthParams, depth_stream);
421 
422  StereoCalibration calibration;
423  {
424  auto depth_stream = selection.get_stream(RS2_STREAM_DEPTH);
425  auto color_stream = selection.get_stream(RS2_STREAM_COLOR);
426  rs2_extrinsics e = depth_stream.get_extrinsics_to(color_stream);
427  // Apply extrinsics to the origin
428  float origin[3]{0.f, 0.f, 0.f};
429  float target[3];
430  rs2_transform_point_to_point(target, &e, origin);
431 
432 
433  calibration.calibrationLeft = visionx::tools::createDefaultMonocularCalibration();
434  calibration.calibrationRight = visionx::tools::createDefaultMonocularCalibration();
435  calibration.calibrationLeft.cameraParam = rgbParams;
436  calibration.calibrationRight.cameraParam = depthParams;
437  calibration.rectificationHomographyLeft =
438  visionx::tools::convertEigenMatToVisionX(Eigen::Matrix3f::Zero());
439  calibration.rectificationHomographyRight =
440  visionx::tools::convertEigenMatToVisionX(Eigen::Matrix3f::Zero());
441  calibration.calibrationRight.cameraParam.translation = {target[0], target[1], target[2]};
442  }
443  return calibration;
444 }
armarx::Variant
The Variant class is described here: Variants.
Definition: Variant.h:223
ARMARX_VERBOSE
#define ARMARX_VERBOSE
Definition: Logging.h:187
str
std::string str(const T &t)
Definition: UserAssistedSegmenterGuiWidgetController.cpp:43
visionx
ArmarX headers.
Definition: OpenPoseStressTest.h:38
index
uint8_t index
Definition: EtherCATFrame.h:59
IntelRealSenseProvider.h
boost::target
Vertex target(const detail::edge_base< Directed, Vertex > &e, const PCG &)
Definition: point_cloud_graph.h:668
c
constexpr T c
Definition: UnscentedKalmanFilterTest.cpp:46
visionx::IntelRealSenseProviderPropertyDefinitions
Definition: IntelRealSenseProvider.h:50
visionx::tools::createByteImage
CByteImage * createByteImage(const ImageFormatInfo &imageFormat, const ImageType imageType)
Creates a ByteImage for the destination type specified in the given imageProviderInfo.
std::align
void * align(size_t alignment, size_t bytes, void *&bufferPlace, size_t &bufferSpace) noexcept
Definition: HeterogenousContinuousContainer.h:37
deactivateSpam
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
Definition: Logging.cpp:75
GfxTL::Identity
void Identity(MatrixXX< N, N, T > *a)
Definition: MatrixXX.h:570
visionx::tools::convertEigenVecToVisionX
visionx::types::Vec convertEigenVecToVisionX(Eigen::VectorXf v)
Definition: TypeMapping.cpp:662
data
uint8_t data[1]
Definition: EtherCATFrame.h:68
ARMARX_DEBUG
#define ARMARX_DEBUG
Definition: Logging.h:184
visionx::tools::depthValueToRGB
void depthValueToRGB(unsigned int depthInMM, unsigned char &r, unsigned char &g, unsigned char &b, bool noiseResistant=false)
Definition: ImageUtil.h:183
timestamp
std::string timestamp()
Definition: CartographerAdapter.cpp:85
armarx::armem::Time
armarx::core::time::DateTime Time
Definition: forward_declarations.h:13
armarx::to_string
const std::string & to_string(const std::string &s)
Definition: StringHelpers.h:41
armarx::TimeUtil::GetTime
static IceUtil::Time GetTime(TimeMode timeMode=TimeMode::VirtualTime)
Get the current time.
Definition: TimeUtil.cpp:42
ARMARX_CHECK_EXPRESSION
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
Definition: ExpressionException.h:73
TimeUtil.h
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:181
IceUtil::Handle< class PropertyDefinitionContainer >
visionx::tools::convertEigenMatToVisionX
visionx::types::Mat convertEigenMatToVisionX(Eigen::MatrixXf m)
Definition: TypeMapping.cpp:686
ImageUtil.h
TypeMapping.h
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
pc
Introduction Thank you for taking interest in our work and downloading this software This library implements the algorithm described in the paper R R R Klein Efficient RANSAC for Point Cloud Shape in Computer Graphics Blackwell June If you use this software you should cite the aforementioned paper in any resulting publication Please send comments or bug reports to Ruwen Roland BUT NOT LIMITED THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY OR CONSEQUENTIAL WHETHER IN STRICT OR EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE Example usage This section shows how to use the library to detect the shapes in a point cloud PointCloud pc
Definition: ReadMe.txt:68
ARMARX_WARNING
#define ARMARX_WARNING
Definition: Logging.h:193
armarx::PropertyDefinitionsPtr
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
Definition: forward_declarations.h:35
ArmarXDataPath.h
Variant.h
visionx::tools::createDefaultMonocularCalibration
MonocularCalibration createDefaultMonocularCalibration()
Creates a MonocularCalibration with all parameters set to a neutral value.
Definition: ImageUtil.cpp:265
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27