ImageToPointCloud.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 ActiveVision::ArmarXObjects::ImageToPointCloud
17  * @author Markus Grotz ( markus dot grotz at kit dot edu )
18  * @author Mirko Waechter ( waechter at kit dot edu )
19  * @date 2019
20  * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
21  * GNU General Public License
22  */
23 
24 #include "ImageToPointCloud.h"
25 
26 #include <Eigen/Core>
27 #include <Eigen/Geometry>
28 
29 #include <pcl/common/transforms.h>
30 
32 
34 #include <VisionX/interface/components/Calibration.h>
36 
37 
38 using namespace armarx;
39 
40 void
42 {
43  offeringTopicFromProperty("DebugObserverName");
44 
45  providerName = getProperty<std::string>("ProviderName").getValue();
46  usingImageProvider(providerName);
47 
48  fovH = getProperty<float>("HorizontalViewAngle").getValue();
49  fovV = getProperty<float>("VerticalViewAngle").getValue();
50  if (!getProperty<std::string>("CalibrationProviderName").getValue().empty())
51  {
52  usingProxy(getProperty<std::string>("CalibrationProviderName").getValue());
53  }
54  nanValue = getProperty<float>("NaNValue").getValue();
55  maxDist = getProperty<float>("MaxDist").getValue();
56  minDist = getProperty<float>("MinDist").getValue();
57 }
58 
59 void
61 {
62  ARMARX_VERBOSE << "onConnectImageProcessor()";
63  imageProviderInfo = getImageProvider(providerName);
64  ARMARX_VERBOSE << "after getImageProvider('" << providerName << "')";
65 
66  ARMARX_CHECK_GREATER_EQUAL(imageProviderInfo.numberImages, 2);
67  numImages = std::min(imageProviderInfo.numberImages, 3);
68 
69  images = new CByteImage*[numImages];
70  for (size_t i = 0; i < numImages; i++)
71  {
72  images[i] = visionx::tools::createByteImage(imageProviderInfo);
73  }
74 
75  getTopicFromProperty(debugObserver, "DebugObserverName");
76 
77 
78  auto applyCalibration = [&](visionx::StereoCalibrationInterfacePrx prx)
79  {
80  if (getProperty<bool>("ComputeViewAngleFromCalibration").getValue())
81  {
82  visionx::StereoCalibration stereoCalibration = prx->getStereoCalibration();
83  float fx = stereoCalibration.calibrationRight.cameraParam.focalLength[0];
84  float fy = stereoCalibration.calibrationRight.cameraParam.focalLength[1];
85  fovV = 180.0 / M_PI * 2.0 * std::atan(images[0]->height / (2.0 * fy));
86  fovH = 180.0 / M_PI * 2.0 * std::atan(images[0]->width / (2.0 * fx));
87  ARMARX_INFO << " Using provided HorizontalViewAngle/VerticalViewAngle parameters from "
88  "calibration";
89  }
90  };
91  if (!getProperty<std::string>("CalibrationProviderName").getValue().empty())
92  {
93  calibrationPrx = getProxy<visionx::StereoCalibrationInterfacePrx>(
94  getProperty<std::string>("CalibrationProviderName").getValue());
95 
96  if (calibrationPrx)
97  {
98  applyCalibration(calibrationPrx);
99  }
100  else
101  {
102  ARMARX_WARNING << "Property CalibrationProviderName was given, but the proxy is not a "
103  "StereoCalibrationInterfacePrx. Calibration not available!";
104  }
105  }
106  else
107  {
108  visionx::StereoCalibrationInterfacePrx calibrationInterface =
109  visionx::StereoCalibrationInterfacePrx::checkedCast(imageProviderInfo.proxy);
110  if (calibrationInterface)
111  {
112  applyCalibration(calibrationInterface);
113  }
114  }
115 
116  ARMARX_INFO << "HorizontalViewAngle: " << fovH << " VerticalViewAngle: " << fovV;
117  cloud.reset(new pcl::PointCloud<PointL>());
118  transformedCloud.reset(new pcl::PointCloud<PointL>());
119 
120  debugObserver->setDebugDatafield(getName(), "processCount", new Variant(processCounter));
121 }
122 
123 void
125 {
128  for (size_t i = 0; i < numImages; i++)
129  {
130  delete images[i];
131  }
132  delete[] images;
133 }
134 
135 void
137 {
138 }
139 
140 void
142 {
143  std::unique_lock lock(mutex);
144 
145  if (!waitForImages(1000))
146  {
147  ARMARX_INFO << deactivateSpam(300) << "Timeout or error while waiting for image data";
148  return;
149  }
150 
151  if (getImages(providerName, images, imageMetaInfo) != static_cast<int>(numImages))
152  {
153  ARMARX_WARNING << "Unable to transfer or read images";
154  return;
155  }
156 
157 
158  cloud->width = images[0]->width;
159  cloud->height = images[0]->height;
160  cloud->header.stamp = imageMetaInfo->timeProvided;
161  ARMARX_CHECK_EQUAL(getProperty<int>("PointCloudWidth").getValue(), images[0]->width);
162  ARMARX_CHECK_EQUAL(getProperty<int>("PointCloudHeight").getValue(), images[0]->height);
163  cloud->points.resize(images[0]->width * images[0]->height);
164  cloud->is_dense = true;
165 
166 
167  const float scaleX = std::tan(fovH * M_PI / 180.0 / 2.0) * 2.0;
168  const float scaleY = std::tan(fovV * M_PI / 180.0 / 2.0) * 2.0;
169 
170  const size_t width = static_cast<size_t>(images[0]->width);
171  const size_t height = static_cast<size_t>(images[0]->height);
172  const float halfWidth = (width / 2.0);
173  const float halfHeight = (height / 2.0);
174  const auto& image0Data = images[0]->pixels;
175  const auto& image1Data = images[1]->pixels;
176 
177  for (size_t j = 0; j < height; j++)
178  {
179  for (size_t i = 0; i < width; i++)
180  {
181  auto coord = j * width + i;
182  // unsigned short value = images[1]->pixels[3 * coord + 0]
183  // + (images[1]->pixels[3 * coord + 1] << 8);
185  image1Data[3 * coord + 0], image1Data[3 * coord + 1], image1Data[3 * coord + 2]);
186 
187  if (maxDist > 0 && value > maxDist)
188  {
189  value = -1.0f;
190  }
191  else if (value < minDist)
192  {
193  value = -1.0f;
194  }
195 
196 
197  PointL& p = cloud->points.at(coord);
198  auto index = 3 * (coord);
199  p.r = image0Data[index + 0];
200  p.g = image0Data[index + 1];
201  p.b = image0Data[index + 2];
202 
203  if (value < 0)
204  {
205  if (nanValue >= 0)
206  {
207  p.z = static_cast<float>(nanValue);
208  //p.z /= 1000.0;
209  p.x = -1.0 * (i - halfWidth) / width * p.z * scaleX;
210  p.y = (halfHeight - j) / height * p.z * scaleY;
211  }
212  else
213  {
214  p.x = p.y = p.z = std::numeric_limits<float>::quiet_NaN();
215  }
216  }
217  else
218  {
219  p.z = static_cast<float>(value);
220  p.x = -1.0 * (i - halfWidth) / width * p.z * scaleX;
221  p.y = (halfHeight - j) / height * p.z * scaleY;
222  }
223 
224  if (numImages > 2)
225  {
226  auto& image2Data = images[2]->pixels;
227 
228  if (images[2]->bytesPerPixel == 3)
229  {
230  p.label = static_cast<unsigned int>(image2Data[index + 0] +
231  (image2Data[index + 1] << 8) +
232  (image2Data[index + 2] << 16));
233  }
234  else
235  {
236  p.label = static_cast<unsigned int>(image2Data[coord]);
237  }
238  }
239  else
240  {
241  p.label = 0;
242  }
243  }
244  }
245 
246  processCounter++;
247  debugObserver->setDebugDatafield(getName(), "processCount", new Variant(processCounter));
248 
249  float angle = getProperty<float>("PointCloudRotationZ").getValue() / 180.f * M_PI;
250  if (angle != 0.0f)
251  {
253  Eigen::Matrix3f m;
254  m = Eigen::AngleAxisf(angle, Eigen::Vector3f::UnitZ());
255  transform2.block<3, 3>(0, 0) *= m;
256  pcl::transformPointCloud(*cloud, *transformedCloud, transform2);
257  transformedCloud->header.stamp = imageMetaInfo->timeProvided;
258  providePointCloud(transformedCloud);
259  }
260  else
261  {
262  providePointCloud(cloud);
263  }
264  // pcl::PointCloud<PointL>::Ptr temp(new pcl::PointCloud<PointL>());
265 }
266 
267 visionx::MetaPointCloudFormatPtr
269 {
270  visionx::MetaPointCloudFormatPtr info = new visionx::MetaPointCloudFormat();
271  info->size = getProperty<int>("PointCloudWidth").getValue() *
272  getProperty<int>("PointCloudHeight").getValue() * sizeof(PointL);
273  info->capacity = info->size;
274  info->type = visionx::PointContentType::eColoredLabeledPoints;
275  return info;
276 }
277 
280 {
283 }
armarx::Variant
The Variant class is described here: Variants.
Definition: Variant.h:223
ARMARX_VERBOSE
#define ARMARX_VERBOSE
Definition: Logging.h:187
visionx::ImageProviderInfo::numberImages
int numberImages
Number of images.
Definition: ImageProcessor.h:519
index
uint8_t index
Definition: EtherCATFrame.h:59
GfxTL::Matrix4f
MatrixXX< 4, 4, float > Matrix4f
Definition: MatrixXX.h:650
visionx::ImageProcessor::getImageProvider
ImageProviderInfo getImageProvider(std::string name, ImageType destinationImageType=eRgb, bool waitForProxy=false)
Select an ImageProvider.
Definition: ImageProcessor.cpp:167
armarx::Component::offeringTopicFromProperty
void offeringTopicFromProperty(const std::string &propertyName)
Offer a topic whose name is specified by the given property.
Definition: Component.cpp:159
armarx::ImageToPointCloud::createPropertyDefinitions
virtual armarx::PropertyDefinitionsPtr createPropertyDefinitions()
Definition: ImageToPointCloud.cpp:279
visionx::tools::createByteImage
CByteImage * createByteImage(const ImageFormatInfo &imageFormat, const ImageType imageType)
Creates a ByteImage for the destination type specified in the given imageProviderInfo.
visionx::PointCloudProvider::onDisconnectComponent
void onDisconnectComponent() override
Hook for subclass.
Definition: PointCloudProvider.cpp:101
cxxopts::empty
bool empty(const std::string &s)
Definition: cxxopts.hpp:234
armarx::Component::getTopicFromProperty
TopicProxyType getTopicFromProperty(const std::string &propertyName)
Get a topic proxy whose name is specified by the given property.
Definition: Component.h:221
armarx::ImageToPointCloud::onDisconnectComponent
void onDisconnectComponent() override
Hook for subclass.
Definition: ImageToPointCloud.cpp:124
GfxTL::Identity
void Identity(MatrixXX< N, N, T > *a)
Definition: MatrixXX.h:570
armarx::ImageToPointCloud::process
void process() override
Process the vision component.
Definition: ImageToPointCloud.cpp:141
cxxopts::value
std::shared_ptr< Value > value()
Definition: cxxopts.hpp:855
M_PI
#define M_PI
Definition: MathTools.h:17
armarx::ImageToPointCloudPropertyDefinitions
Definition: ImageToPointCloud.h:53
PCLUtilities.h
visionx::ImageProcessor::usingImageProvider
void usingImageProvider(std::string name)
Registers a delayed topic subscription and a delayed provider proxy retrieval which all will be avail...
Definition: ImageProcessor.cpp:128
visionx::ImageProcessor::getImages
int getImages(CByteImage **ppImages)
Poll images from provider.
Definition: ImageProcessor.cpp:395
ARMARX_CHECK_GREATER_EQUAL
#define ARMARX_CHECK_GREATER_EQUAL(lhs, rhs)
This macro evaluates whether lhs is greater or equal (>=) rhs and if it turns out to be false it will...
Definition: ExpressionException.h:123
armarx::ImageToPointCloud::onConnectImageProcessor
void onConnectImageProcessor() override
Implement this method in the ImageProcessor in order execute parts when the component is fully initia...
Definition: ImageToPointCloud.cpp:60
armarx::ImageToPointCloud::onInitImageProcessor
void onInitImageProcessor() override
Setup the vision component.
Definition: ImageToPointCloud.cpp:41
armarx::Component::getConfigIdentifier
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition: Component.cpp:79
visionx::ImageProviderInfo::proxy
ImageProviderInterfacePrx proxy
proxy to image provider
Definition: ImageProcessor.h:485
visionx::PointCloudProvider::providePointCloud
void providePointCloud(PointCloudPtrT pointCloudPtr)
offer the new point cloud.
Definition: PointCloudProvider.h:122
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:181
IceUtil::Handle< class PropertyDefinitionContainer >
ImageToPointCloud.h
ImageUtil.h
visionx::tools::rgbToDepthValue
float rgbToDepthValue(unsigned char r, unsigned char g, unsigned char b, bool noiseResistant=false)
Definition: ImageUtil.h:148
angle
double angle(const Point &a, const Point &b, const Point &c)
Definition: point.hpp:109
armarx::Logging::deactivateSpam
SpamFilterDataPtr deactivateSpam(float deactivationDurationSec=10.0f, const std::string &identifier="", bool deactivate=true) const
disables the logging for the current line for the given amount of seconds.
Definition: Logging.cpp:99
armarx::ManagedIceObject::getName
std::string getName() const
Retrieve name of object.
Definition: ManagedIceObject.cpp:108
GfxTL::Matrix3f
MatrixXX< 3, 3, float > Matrix3f
Definition: MatrixXX.h:649
min
T min(T t1, T t2)
Definition: gdiam.h:44
ARMARX_CHECK_EQUAL
#define ARMARX_CHECK_EQUAL(lhs, rhs)
This macro evaluates whether lhs is equal (==) rhs and if it turns out to be false it will throw an E...
Definition: ExpressionException.h:130
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
Variant.h
armarx::PointL
pcl::PointXYZRGBL PointL
Definition: TabletopSegmentation.h:73
armarx::ManagedIceObject::usingProxy
bool usingProxy(const std::string &name, const std::string &endpoints="")
Registers a proxy for retrieval after initialization and adds it to the dependency list.
Definition: ManagedIceObject.cpp:154
visionx::ImageProcessor::onDisconnectComponent
void onDisconnectComponent() override
Definition: ImageProcessor.cpp:90
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27
armarx::ImageToPointCloud::getDefaultPointCloudFormat
virtual visionx::MetaPointCloudFormatPtr getDefaultPointCloudFormat()
default point cloud format used to initialize shared memory
Definition: ImageToPointCloud.cpp:268
armarx::ImageToPointCloud::onExitImageProcessor
void onExitImageProcessor() override
Exit the ImapeProcessor component.
Definition: ImageToPointCloud.cpp:136
visionx::ImageProcessor::waitForImages
bool waitForImages(int milliseconds=1000)
Wait for new images.
Definition: ImageProcessor.cpp:309