camera_info_publisher.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019 Roboception GmbH
3  * All rights reserved
4  *
5  * Author: Heiko Hirschmueller
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice,
11  * this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright notice,
14  * this list of conditions and the following disclaimer in the documentation
15  * and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the copyright holder nor the names of its contributors
18  * may be used to endorse or promote products derived from this software without
19  * specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "camera_info_publisher.h"
35 
36 #include <string>
37 #include <map>
38 #include <stdexcept>
39 
40 #include <iostream>
41 #include <fstream>
42 #include <sstream>
43 
44 namespace rcgccam
45 {
46 namespace
47 {
48 
49 /*
50  Remove leading and trailing spaces from string.
51 */
52 
53 void trim(std::string& s)
54 {
55  size_t pos;
56 
57  pos = 0;
58 
59  while (pos < s.size() && isspace(s[pos]))
60  {
61  pos++;
62  }
63 
64  if (pos > 0)
65  {
66  s = s.substr(pos);
67  }
68 
69  pos = s.size();
70 
71  while (pos > 0 && isspace(s[pos - 1]))
72  {
73  pos--;
74  }
75 
76  if (pos < s.size())
77  {
78  s = s.substr(0, pos);
79  }
80 }
81 
82 /*
83  Load key/value pairs from an ascii file into a map.
84 */
85 
86 bool loadFile(std::map<std::string, std::string>& data, const char* name)
87 {
88  std::ifstream in;
89  std::string line;
90 
91  in.open(name);
92 
93  if (!in.good())
94  {
95  return false;
96  }
97 
98  while (in.good())
99  {
100  getline(in, line);
101 
102  trim(line);
103 
104  size_t pos = line.find('#');
105 
106  if (pos != line.npos)
107  {
108  line = line.substr(0, pos);
109  }
110 
111  if (line.size() > 0)
112  {
113  pos = line.find('=');
114 
115  if (pos != line.npos)
116  {
117  std::string key = line.substr(0, pos);
118  std::string value = line.substr(pos + 1);
119 
120  trim(key);
121  trim(value);
122 
123  data.insert(std::pair<std::string, std::string>(key, value));
124  }
125  else
126  {
127  return false;
128  }
129  }
130  }
131 
132  in.close();
133 
134  return true;
135 }
136 
137 /*
138  Create a key like camera[.<id>].<name>
139 */
140 
141 inline std::string createKey(const char *name, int id)
142 {
143  std::ostringstream out;
144 
145  out << "camera.";
146  if (id >= 0) out << id << '.';
147  out << name;
148 
149  return out.str();
150 }
151 
152 /*
153  Get the value with the given key from the map. Use the given default value if
154  the key does not exist in the map.
155 */
156 
157 template <class T>
158 void getValue(const std::map<std::string, std::string>& data, const std::string &key, T& value, const char* defvalue)
159 {
160  std::map<std::string, std::string>::const_iterator it = data.find(key.c_str());
161  std::string v;
162 
163  if (it != data.end())
164  {
165  v = it->second;
166  }
167  else
168  {
169  v = defvalue;
170  }
171 
172  std::istringstream in(v);
173  in >> value;
174 }
175 
176 /*
177  Get a 3x3 matrix from the given key of the map. An identity matrix is
178  returned if the key does not exist.
179 */
180 
181 bool getMatrix33(const std::map<std::string, std::string>& data, const std::string &key,
182  double M[3][3])
183 {
184  std::map<std::string, std::string>::const_iterator it = data.find(key.c_str());
185  std::string v;
186 
187  if (it != data.end())
188  {
189  v = it->second;
190  }
191  else
192  {
193  v = "[1 0 0; 0 1 0; 0 0 1]";
194  }
195 
196  std::istringstream in(v);
197 
198  char c;
199  in >> c;
200 
201  if (c == '[')
202  {
203  for (int k = 0; k < 3 && in; k++)
204  {
205  for (int i = 0; i < 3 && in; i++)
206  {
207  in >> M[k][i];
208  }
209 
210  in >> c;
211 
212  if (k + 1 < 3 && c != ';')
213  {
214  return false;
215  }
216  }
217 
218  if (c != ']')
219  {
220  return false;
221  }
222  }
223  else
224  {
225  return false;
226  }
227 
228  return true;
229 }
230 
231 /*
232  Get a vector of size 3 from the given key of the map. A null vector is
233  returned if the key does not exist.
234 */
235 
236 bool getVector3(const std::map<std::string, std::string>& data, const std::string &key,
237  double A[3])
238 {
239  std::map<std::string, std::string>::const_iterator it = data.find(key.c_str());
240  std::string v;
241 
242  if (it != data.end())
243  {
244  v = it->second;
245  }
246  else
247  {
248  v = "[0 0 0]";
249  }
250 
251  std::istringstream in(v);
252 
253  char c;
254  in >> c;
255 
256  if (c == '[')
257  {
258  for (int i = 0; i < 3 && in; i++)
259  {
260  in >> A[i];
261  }
262 
263  in >> c;
264 
265  if (c != ']')
266  {
267  return false;
268  }
269  }
270  else
271  {
272  return false;
273  }
274 
275  return true;
276 }
277 
278 inline void mulMatrix33Matrix33(double ret[3][3], double A[3][3], double B[3][3])
279 {
280  for (int k=0; k<3; k++)
281  {
282  for (int i=0; i<3; i++)
283  {
284  ret[k][i] = 0;
285 
286  for (int j=0; j<3; j++)
287  {
288  ret[k][i] += A[k][j] * B[j][i];
289  }
290  }
291  }
292 }
293 
294 inline void mulMatrix33Vector3(double ret[3], double M[3][3], double V[3])
295 {
296  for (int k=0; k<3; k++)
297  {
298  ret[k] = 0;
299  for (int i=0; i<3; i++)
300  {
301  ret[k] += M[k][i] * V[i];
302  }
303  }
304 }
305 
306 inline void transposeMatrix33(double M[3][3])
307 {
308  double v = M[0][1];
309  M[0][1] = M[1][0];
310  M[1][0] = v;
311 
312  v = M[0][2];
313  M[0][2] = M[2][0];
314  M[2][0] = v;
315 
316  v = M[1][2];
317  M[1][2] = M[2][1];
318  M[2][1] = v;
319 }
320 
321 /*
322  Store the given 3x3 matrix in a linear array.
323 */
324 
325 inline void storeMatrix(boost::array<double, 9>& values, double M[3][3])
326 {
327  int j = 0;
328  for (int k = 0; k < 3; k++)
329  {
330  for (int i = 0; i < 3; i++)
331  {
332  values[j++] = M[k][i];
333  }
334  }
335 }
336 
337 } // namespace
338 
340 {
341 }
342 
343 void CameraInfoPublisher::init(ros::NodeHandle& nh, const char* calib_file, int id)
344 {
345  // advertise topic
346 
347  pub_ = nh.advertise<sensor_msgs::CameraInfo>("camera_info", 1);
348 
349  // check id
350 
351  if (id > 1)
352  {
353  ROS_ERROR_STREAM("Invalid camera ID, only < 0, 0 and 1 allowed: " << id);
354  return;
355  }
356 
357  // prepare camera info message
358 
359  if (calib_file != 0 && calib_file[0] != '\0')
360  {
361  std::map<std::string, std::string> data;
362 
363  if (loadFile(data, calib_file))
364  {
365  // get width and height
366 
367  getValue(data, createKey("width", id), info_.width, "0");
368  getValue(data, createKey("height", id), info_.height, "0");
369 
370  // get camera matrix
371 
372  double A[3][3];
373  if (!getMatrix33(data, createKey("A", id), A))
374  {
375  ROS_ERROR("Getting camera.A from calibration file failed");
376  info_ = sensor_msgs::CameraInfo();
377  return;
378  }
379 
380  storeMatrix(info_.K, A);
381 
382  // get lens distortion
383 
384  double e1, e2, e3, e4;
385 
386  getValue(data, createKey("e1", id), e1, "0");
387  getValue(data, createKey("e2", id), e2, "0");
388  getValue(data, createKey("e3", id), e3, "0");
389  getValue(data, createKey("e4", id), e4, "0");
390 
391  if (e1 != 0 || e2 != 0 || e3 != 0 || e4 != 0)
392  {
393  info_.distortion_model = "equidistant";
394  info_.D.resize(4);
395 
396  info_.D[0] = e1;
397  info_.D[1] = e2;
398  info_.D[2] = e3;
399  info_.D[3] = e4;
400  }
401  else
402  {
403  double k1, k2, k3, p1, p2;
404 
405  getValue(data, createKey("k1", id), k1, "0");
406  getValue(data, createKey("k2", id), k2, "0");
407  getValue(data, createKey("k3", id), k3, "0");
408  getValue(data, createKey("p1", id), p1, "0");
409  getValue(data, createKey("p2", id), p2, "0");
410 
411  info_.distortion_model = "plumb_bob";
412  info_.D.resize(5);
413 
414  info_.D[0] = k1;
415  info_.D[1] = k2;
416  info_.D[2] = p1;
417  info_.D[3] = p2;
418  info_.D[4] = k3;
419  }
420 
421  // determine focal length after rectification
422 
423  double f = 0;
424 
425  getValue(data, "rect.f", f, "0");
426 
427  if (f == 0)
428  {
429  if (id >= 0)
430  {
431  double A0[3][3], A1[3][3];
432  if (getMatrix33(data, createKey("A", 0), A0) && getMatrix33(data, createKey("A", 1), A1))
433  {
434  f = (A0[0][0] + A0[1][1] + A1[0][0] + A1[1][1])/4;
435  }
436  else
437  {
438  ROS_ERROR("Getting camera.A0 and camera.A1 from calibration file failed");
439  info_ = sensor_msgs::CameraInfo();
440  return;
441  }
442  }
443  else
444  {
445  f = (A[0][0] + A[1][1])/2;
446  }
447  }
448 
449  // rectification rotation (only relevant for stereo)
450 
451  double t = 0;
452 
453  if (id >= 0)
454  {
455  // get transformations of left and right camera
456 
457  double R0[3][3], R1[3][3];
458  double T0[3], T1[3];
459 
460  getMatrix33(data, createKey("R", 0), R0);
461  getMatrix33(data, createKey("R", 1), R1);
462  getVector3(data, createKey("T", 0), T0);
463  getVector3(data, createKey("T", 1), T1);
464 
465  // compute relative orientation between cameras
466 
467  double R[3][3];
468  double T[3];
469 
470  transposeMatrix33(R1);
471  mulMatrix33Matrix33(R, R1, R0);
472 
473  T1[0] -= T0[0];
474  T1[1] -= T0[1];
475  T1[2] -= T0[2];
476 
477  transposeMatrix33(R0);
478  mulMatrix33Vector3(T, R0, T1);
479 
480  // get length of baseline
481 
482  t = std::sqrt(T[0] * T[0] + T[1] * T[1] + T[2] * T[2]);
483  double l = std::sqrt(T[0] * T[0] + T[1] * T[1]);
484 
485  // compute rectification matrix of left camera
486 
487  double Rrect[3][3];
488 
489  Rrect[0][0] = T[0]/t;
490  Rrect[1][0] = T[1]/t;
491  Rrect[2][0] = T[2]/t;
492 
493  Rrect[0][1] = -T[1]/l;
494  Rrect[1][1] = T[0]/l;
495  Rrect[2][1] = 0;
496 
497  Rrect[0][2] = Rrect[1][0] * Rrect[2][1] - Rrect[2][0] * Rrect[1][1];
498  Rrect[1][2] = Rrect[2][0] * Rrect[0][1] - Rrect[0][0] * Rrect[2][1];
499  Rrect[2][2] = Rrect[0][0] * Rrect[1][1] - Rrect[1][0] * Rrect[0][1];
500 
501  if (id == 0)
502  {
503  transposeMatrix33(Rrect);
504  storeMatrix(info_.R, Rrect);
505  }
506  else
507  {
508  double Rrect_right[3][3];
509  mulMatrix33Matrix33(Rrect_right, R, Rrect);
510 
511  transposeMatrix33(Rrect_right);
512  storeMatrix(info_.R, Rrect_right);
513  }
514  }
515  else
516  {
517  // identity for mono camera
518 
519  info_.R[1] = info_.R[2] = info_.R[3] = 0;
520  info_.R[0] = info_.R[4] = info_.R[8] = 1;
521  info_.R[5] = info_.R[6] = info_.R[7] = 0;
522  }
523 
524  // define projection matrix after rectification
525 
526  info_.P[0] = f;
527  info_.P[1] = 0;
528  info_.P[2] = info_.width/2.0;
529  info_.P[3] = 0;
530  info_.P[4] = 0;
531  info_.P[5] = f;
532  info_.P[6] = info_.height/2.0;
533  info_.P[7] = 0;
534  info_.P[8] = 0;
535  info_.P[9] = 0;
536  info_.P[10] = 1;
537  info_.P[11] = 0;
538 
539  if (id == 1)
540  {
541  info_.P[3] = -f * t;
542  }
543 
544  info_.binning_x = 1;
545  info_.binning_y = 1;
546  }
547  else
548  {
549  ROS_ERROR_STREAM("gc_genicam_camera: Cannot load camera calibration: " << calib_file);
550  }
551  }
552 }
553 
555 {
556  return pub_.getNumSubscribers() > 0;
557 }
558 
559 void CameraInfoPublisher::publish(const sensor_msgs::ImagePtr& image)
560 {
561  if (image && pub_.getNumSubscribers() > 0)
562  {
563  info_.header = image->header;
564 
565  if (info_.K[0] == 0)
566  {
567  info_.width = image->width;
568  info_.height = image->height;
569  }
570 
571  pub_.publish(info_);
572  }
573 }
574 
575 } // namespace rcgccam
camera_info_publisher.h
ROS_ERROR_STREAM
#define ROS_ERROR_STREAM(args)
s
XmlRpcServer s
rcgccam::CameraInfoPublisher::publish
void publish(const sensor_msgs::ImagePtr &image)
Definition: camera_info_publisher.cc:559
ros::Publisher::publish
void publish(const boost::shared_ptr< M > &message) const
ros::NodeHandle::advertise
Publisher advertise(AdvertiseOptions &ops)
data
data
f
f
rcgccam
Definition: camerainfolist.cc:40
getline
std::istream & getline(std::istream &is, GENICAM_NAMESPACE::gcstring &str)
rcgccam::CameraInfoPublisher::pub_
ros::Publisher pub_
Definition: camera_info_publisher.h:71
rcgccam::CameraInfoPublisher::info_
sensor_msgs::CameraInfo info_
Definition: camera_info_publisher.h:70
std::ostringstream::str
std::string str()
rcgccam::CameraInfoPublisher::init
void init(ros::NodeHandle &nh, const char *calib_file, int id)
Initialization of publisher.
Definition: camera_info_publisher.cc:343
std::ostringstream
ROS_ERROR
#define ROS_ERROR(...)
ros::Publisher::getNumSubscribers
uint32_t getNumSubscribers() const
rcgccam::CameraInfoPublisher::CameraInfoPublisher
CameraInfoPublisher()
Definition: camera_info_publisher.cc:339
rcgccam::CameraInfoPublisher::used
bool used()
Definition: camera_info_publisher.cc:554
ros::NodeHandle


rc_genicam_camera
Author(s): Heiko Hirschmueller
autogenerated on Wed Mar 2 2022 00:49:18