pointcloud.cc
Go to the documentation of this file.
1 /*
2  * This file is part of the rc_genicam_api package.
3  *
4  * Copyright (c) 2019 Roboception GmbH
5  * All rights reserved
6  *
7  * Author: Heiko Hirschmueller
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  *
19  * 3. Neither the name of the copyright holder nor the names of its contributors
20  * may be used to endorse or promote products derived from this software without
21  * specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 #include "pointcloud.h"
37 
38 #include <iostream>
39 #include <fstream>
40 #include <sstream>
41 #include <iomanip>
42 #include <vector>
43 #include <cmath>
44 #include <algorithm>
45 
46 #ifdef _WIN32
47 #undef min
48 #undef max
49 #endif
50 
51 namespace rcg
52 {
53 
54 namespace
55 {
56 
57 /*
58  Get the i-th 16 bit value.
59 
60  @param p Pointer to first byte of array of 16 bit values.
61  @param bigendian True if values are given as big endian. Otherwise, litte
62  endian is assumed.
63  @param i Index of 16 bit inside the given array.
64 */
65 
66 inline uint16_t getUint16(const uint8_t *p, bool bigendian, size_t i)
67 {
68  uint16_t ret;
69 
70  if (bigendian)
71  {
72  size_t j=i<<1;
73  ret=static_cast<uint16_t>(((p[j]<<8)|p[j+1]));
74  }
75  else
76  {
77  size_t j=i<<1;
78  ret=static_cast<uint16_t>(((p[j+1]<<8)|p[j]));
79  }
80 
81  return ret;
82 }
83 
84 }
85 
86 void storePointCloud(std::string name, double f, double t, double scale,
87  std::shared_ptr<const Image> left,
88  std::shared_ptr<const Image> disp,
89  std::shared_ptr<const Image> conf,
90  std::shared_ptr<const Image> error)
91 {
92  // get size and scale factor between left image and disparity image
93 
94  size_t width=disp->getWidth();
95  size_t height=disp->getHeight();
96  bool bigendian=disp->isBigEndian();
97  size_t ds=(left->getWidth()+disp->getWidth()-1)/disp->getWidth();
98 
99  // convert focal length factor into focal length in (disparity) pixels
100 
101  f*=width;
102 
103  // get pointer to disparity data and size of row in bytes
104 
105  const uint8_t *dps=disp->getPixels();
106  size_t dstep=disp->getWidth()*sizeof(uint16_t)+disp->getXPadding();
107 
108  // count number of valid disparities and store vertice index in a temporary
109  // index image
110 
111  size_t vi=0;
112  const uint32_t vinvalid=0xffffffff;
113  std::vector<uint32_t> vindex(width*height);
114 
115  uint32_t n=0;
116  for (size_t k=0; k<height; k++)
117  {
118  int j=0;
119  for (size_t i=0; i<width; i++)
120  {
121  vindex[vi]=vinvalid;
122  if ((dps[j]|dps[j+1]) != 0) vindex[vi]=n++;
123 
124  j+=2;
125  vi++;
126  }
127 
128  dps+=dstep;
129  }
130 
131  dps=disp->getPixels();
132 
133  // count number of triangles
134 
135  const uint16_t vstep=static_cast<uint16_t>(std::ceil(2/scale));
136 
137  int tn=0;
138  for (size_t k=1; k<height; k++)
139  {
140  for (size_t i=1; i<width; i++)
141  {
142  uint16_t v[4];
143  v[0]=getUint16(dps, bigendian, i-1);
144  v[1]=getUint16(dps, bigendian, i);
145  v[2]=getUint16(dps+dstep, bigendian, i-1);
146  v[3]=getUint16(dps+dstep, bigendian, i);
147 
148  uint16_t vmin=65535;
149  uint16_t vmax=0;
150  int valid=0;
151 
152  for (int jj=0; jj<4; jj++)
153  {
154  if (v[jj])
155  {
156  vmin=std::min(vmin, v[jj]);
157  vmax=std::max(vmax, v[jj]);
158  valid++;
159  }
160  }
161 
162  if (valid >= 3 && vmax-vmin <= vstep)
163  {
164  tn+=valid-2;
165  }
166  }
167 
168  dps+=dstep;
169  }
170 
171  dps=disp->getPixels();
172 
173  // get pointer to optional confidence and error data and size of row in bytes
174 
175  const uint8_t *cps=0, *eps=0;
176  size_t cstep=0, estep=0;
177 
178  if (conf)
179  {
180  cps=conf->getPixels();
181  cstep=conf->getWidth()*sizeof(uint8_t)+conf->getXPadding();
182  }
183 
184  if (error)
185  {
186  eps=error->getPixels();
187  estep=error->getWidth()*sizeof(uint8_t)+error->getXPadding();
188  }
189 
190  // open output file and write ASCII PLY header
191 
192  if (name.size() == 0)
193  {
195  double timestamp=left->getTimestampNS()/1000000000.0;
196  os << "rc_visard_" << std::setprecision(16) << timestamp << ".ply";
197  name=os.str();
198  }
199 
200  std::ofstream out(name);
201 
202  out << "ply" << std::endl;
203  out << "format ascii 1.0" << std::endl;
204  out << "comment Created with gc_pointcloud from Roboception GmbH" << std::endl;
205  out << "comment Camera [1 0 0; 0 1 0; 0 0 1] [0 0 0]" << std::endl;
206  out << "element vertex " << n << std::endl;
207  out << "property float32 x" << std::endl;
208  out << "property float32 y" << std::endl;
209  out << "property float32 z" << std::endl;
210  out << "property float32 scan_size" << std::endl; // i.e. size of 3D point
211 
212  if (cps != 0)
213  {
214  out << "property float32 scan_conf" << std::endl; // optional confidence
215  }
216 
217  if (eps != 0)
218  {
219  out << "property float32 scan_error" << std::endl; // optional error in 3D along line of sight
220  }
221 
222  out << "property uint8 diffuse_red" << std::endl;
223  out << "property uint8 diffuse_green" << std::endl;
224  out << "property uint8 diffuse_blue" << std::endl;
225  out << "element face " << tn << std::endl;
226  out << "property list uint8 uint32 vertex_indices" << std::endl;
227  out << "end_header" << std::endl;
228 
229  // create colored point cloud
230 
231  for (size_t k=0; k<height; k++)
232  {
233  for (size_t i=0; i<width; i++)
234  {
235  // convert disparity from fixed comma 16 bit integer into float value
236 
237  double d=scale*getUint16(dps, bigendian, i);
238 
239  // if disparity is valid and color can be obtained
240 
241  if (d)
242  {
243  // reconstruct 3D point from disparity value
244 
245  double x=(i+0.5-0.5*width)*t/d;
246  double y=(k+0.5-0.5*height)*t/d;
247  double z=f*t/d;
248 
249  // compute size of reconstructed point
250 
251  double x2=(i-0.5*width)*t/d;
252  double size=2*1.4*std::abs(x2-x);
253 
254  // get corresponding color value
255 
256  uint8_t rgb[3];
257  getColor(rgb, left, static_cast<uint32_t>(ds), static_cast<uint32_t>(i),
258  static_cast<uint32_t>(k));
259 
260  // store colored point, optionally with confidence and error
261 
262  out << x << " " << y << " " << z << " " << size << " ";
263 
264  if (cps != 0)
265  {
266  out << cps[i]/255.0 << " ";
267  }
268 
269  if (eps != 0)
270  {
271  out << eps[i]*scale*f*t/(d*d) << " ";
272  }
273 
274  out << static_cast<int>(rgb[0]) << " ";
275  out << static_cast<int>(rgb[1]) << " ";
276  out << static_cast<int>(rgb[2]) << std::endl;
277  }
278  }
279 
280  dps+=dstep;
281  cps+=cstep;
282  eps+=estep;
283  }
284 
285  dps=disp->getPixels();
286 
287  // create triangles
288 
289  uint32_t *ips=vindex.data();
290  for (size_t k=1; k<height; k++)
291  {
292  for (size_t i=1; i<width; i++)
293  {
294  uint16_t v[4];
295  v[0]=getUint16(dps, bigendian, i-1);
296  v[1]=getUint16(dps, bigendian, i);
297  v[2]=getUint16(dps+dstep, bigendian, i-1);
298  v[3]=getUint16(dps+dstep, bigendian, i);
299 
300  uint16_t vmin=65535;
301  uint16_t vmax=0;
302  int valid=0;
303 
304  for (int jj=0; jj<4; jj++)
305  {
306  if (v[jj])
307  {
308  vmin=std::min(vmin, v[jj]);
309  vmax=std::max(vmax, v[jj]);
310  valid++;
311  }
312  }
313 
314  if (valid >= 3 && vmax-vmin <= vstep)
315  {
316  int j=0;
317  uint32_t fc[4];
318 
319  if (ips[i-1] != vinvalid)
320  {
321  fc[j++]=ips[i-1];
322  }
323 
324  if (ips[width+i-1] != vinvalid)
325  {
326  fc[j++]=ips[width+i-1];
327  }
328 
329  if (ips[width+i] != vinvalid)
330  {
331  fc[j++]=ips[width+i];
332  }
333 
334  if (ips[i] != vinvalid)
335  {
336  fc[j++]=ips[i];
337  }
338 
339  out << "3 " << fc[0] << ' ' << fc[1] << ' ' << fc[2] << std::endl;
340 
341  if (j == 4)
342  {
343  out << "3 " << fc[2] << ' ' << fc[3] << ' ' << fc[0] << std::endl;
344  }
345  }
346  }
347 
348  ips+=width;
349  dps+=dstep;
350  }
351 
352  out.close();
353 }
354 
355 }
void storePointCloud(std::string name, double f, double t, double scale, std::shared_ptr< const Image > left, std::shared_ptr< const Image > disp, std::shared_ptr< const Image > conf, std::shared_ptr< const Image > error)
Definition: pointcloud.cc:86
std::string str()
LOG4CPP_EXPORT CategoryStream & left(CategoryStream &os)
left manipulator
double abs(double x)
Definition: PolyReference.h:61
Definition: buffer.cc:47
void getColor(uint8_t rgb[3], const std::shared_ptr< const Image > &img, uint32_t ds, uint32_t i, uint32_t k)
Expects an image in Mono8 or YCbCr411_8 format and returns the color as RGB value at the given pixel ...
Definition: image.cc:132


rc_genicam_api
Author(s): Heiko Hirschmueller
autogenerated on Wed Mar 17 2021 02:48:41