ISAAC  0.2.11
Flight software for the ISAAC project, adding functionality to the Astrobee robot, operating inside the International Space Station.
All Classes Functions Variables Pages
dense_map_utils.h
1 /* Copyright (c) 2021, United States Government, as represented by the
2  * Administrator of the National Aeronautics and Space Administration.
3  *
4  * All rights reserved.
5  *
6  * The "ISAAC - Integrated System for Autonomous and Adaptive Caretaking
7  * platform" software is licensed under the Apache License, Version 2.0
8  * (the "License"); you may not use this file except in compliance with the
9  * License. You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16  * License for the specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 #ifndef DENSE_MAP_UTILS_H_
21 #define DENSE_MAP_UTILS_H_
22 
23 #include <opencv2/calib3d/calib3d.hpp>
24 #include <opencv2/imgproc.hpp>
25 #include <opencv2/imgcodecs.hpp>
26 #include <opencv2/highgui.hpp>
27 #include <opencv2/core/utility.hpp>
28 
29 #include <Eigen/Core>
30 #include <Eigen/Geometry>
31 
32 #include <config_reader/config_reader.h>
33 #include <camera/camera_params.h>
34 
35 #include <boost/shared_ptr.hpp>
36 
37 #include <map>
38 #include <set>
39 #include <string>
40 #include <vector>
41 
42 namespace dense_map {
43 
44 const int NUM_SCALAR_PARAMS = 1; // Used to float single-value params // NOLINT
45 const int NUM_OPT_CTR_PARAMS = 2; // optical center in x and y // NOLINT
46 const int NUM_PIX_PARAMS = 2; // NOLINT
47 const int NUM_XYZ_PARAMS = 3; // NOLINT
48 const int NUM_RIGID_PARAMS = 7; // quaternion (4) + translation (3) // NOLINT
49 const int NUM_AFFINE_PARAMS = 12; // 3x3 matrix (9) + translation (3) // NOLINT
50 
51 // A function to split a string like 'optical_center focal_length' into
52 // its two constituents.
53 void parse_intrinsics_to_float(std::string const& intrinsics_to_float,
54  std::set<std::string>& intrinsics_to_float_set);
55 
56 // A function to split a string like 'haz_cam sci_cam' into
57 // its two constituents and validate against the list of known cameras.
58 void parse_extrinsics_to_float(std::vector<std::string> const& cam_names,
59  std::string const& ref_cam_name,
60  std::string const& depth_to_image_name,
61  std::string const& extrinsics_to_float,
62  std::set<std::string>& extrinsics_to_float_set);
63 
64 // Extract a rigid transform to an array of length NUM_RIGID_PARAMS
65 void rigid_transform_to_array(Eigen::Affine3d const& aff, double* arr);
66 
67 // Convert an array of length NUM_RIGID_PARAMS to a rigid
68 // transform. Normalize the quaternion to make it into a rotation.
69 void array_to_rigid_transform(Eigen::Affine3d& aff, const double* arr);
70 
71 void affine_transform_to_array(Eigen::Affine3d const& aff, double* arr);
72 void array_to_affine_transform(Eigen::Affine3d& aff, const double* arr);
73 
74 // Convert a string of values separated by spaces to a vector of doubles.
75 std::vector<double> string_to_vector(std::string const& str);
76 
77 // Read a 4x4 pose matrix of doubles from disk
78 void readPoseMatrix(cv::Mat& pose, std::string const& filename);
79 
80 // Read an affine matrix with double values
81 bool readAffine(Eigen::Affine3d& T, std::string const& filename);
82 
83 // Write a matrix with double values
84 void writeMatrix(Eigen::MatrixXd const& M, std::string const& filename);
85 
86 void writeCloud(std::vector<float> const& points, size_t point_size, std::string const& filename);
87 
88 // Return the type of an opencv matrix
89 std::string matType(cv::Mat const& mat);
90 
91 // Read the transform from depth to given camera
92 void readCameraTransform(config_reader::ConfigReader& config, std::string const transform_str,
93  Eigen::Affine3d& transform);
94 
95 // Read some transforms from the robot calibration file
96 void readConfigFile // NOLINT
97 (// Inputs // NOLINT
98  std::vector<std::string> const& cam_names, // NOLINT
99  std::string const& nav_cam_to_body_trans_str, // NOLINT
100  std::string const& haz_cam_depth_to_image_trans_str, // NOLINT
101  // Outputs // NOLINT
102  std::vector<camera::CameraParameters> & cam_params, // NOLINT
103  std::vector<Eigen::Affine3d> & nav_to_cam_trans, // NOLINT
104  std::vector<double> & nav_to_cam_timestamp_offset, // NOLINT
105  Eigen::Affine3d & nav_cam_to_body_trans, // NOLINT
106  Eigen::Affine3d & haz_cam_depth_to_image_trans); // NOLINT
107 
108 // Save some transforms from the robot calibration file. This has some very fragile
109 // logic and cannot handle comments in the config file.
110 void updateConfigFile // NOLINT
111 (std::vector<std::string> const& cam_names, // NOLINT
112  std::string const& haz_cam_depth_to_image_trans_str, // NOLINT
113  std::vector<camera::CameraParameters> const& cam_params, // NOLINT
114  std::vector<Eigen::Affine3d> const& nav_to_cam_trans, // NOLINT
115  std::vector<double> const& nav_to_cam_timestamp_offset, // NOLINT
116  Eigen::Affine3d const& haz_cam_depth_to_image_trans); // NOLINT
117 
118 // Given two poses aff0 and aff1, and 0 <= alpha <= 1, do linear interpolation.
119 Eigen::Affine3d linearInterp(double alpha, Eigen::Affine3d const& aff0,
120  Eigen::Affine3d const& aff1);
121 
122 // Given a set of poses indexed by timestamp in an std::map, find the
123 // interpolated pose at desired timestamp. This is efficient
124 // only for very small maps. Else use the StampedPoseStorage class.
125 bool findInterpPose(double desired_time, std::map<double, Eigen::Affine3d> const& poses,
126  Eigen::Affine3d& interp_pose);
127 
128 // Implement some heuristic to find the maximum rotation angle that can result
129 // from applying the given transform. It is assumed that the transform is not
130 // too different from the identity.
131 double maxRotationAngle(Eigen::Affine3d const& T);
132 
133 // A class to store timestamped poses, implementing O(log(n)) linear
134 // interpolation at a desired timestamp. For fast access, keep the
135 // poses in bins obtained by flooring the timestamp, which is measured
136 // in seconds. It is assumed that there are a handful of poses
137 // measured every second, so in each bin. When bins get large, or too
138 // many bins are empty, the efficiency of this algorithm goes down.
140  public:
141  void addPose(Eigen::Affine3d const& pose, double timestamp);
142 
143  // Find the interpolated pose by looking up the two poses with
144  // closest timestamps that are below and above input_timestamp. If
145  // the gap between those timestamps is more than max_gap, return
146  // failure, as then likely the interpolation result is not accurate.
147  bool interpPose(double input_timestamp, double max_gap, Eigen::Affine3d& out_pose) const;
148 
149  void clear();
150 
151  bool empty() const;
152 
153  private:
154  std::map<int, std::map<double, Eigen::Affine3d> > m_poses;
155 };
156 
157 // Compute the azimuth and elevation for a (normal) vector
158 void normalToAzimuthAndElevation(Eigen::Vector3d const& normal, double& azimuth, double& elevation);
159 
160 // Compute a normal vector based on the azimuth and elevation angles
161 void azimuthAndElevationToNormal(Eigen::Vector3d& normal, double azimuth, double elevation);
162 
163 // Snap the normal to the plane (and the plane itself) to make
164 // all angles multiple of 45 degrees with the coordinate axes.
165 void snapPlaneNormal(Eigen::Vector3d& plane_normal);
166 
167 // Find the best fitting plane to a set of points
168 void bestFitPlane(const std::vector<Eigen::Vector3d>& points, Eigen::Vector3d& centroid, Eigen::Vector3d& plane_normal);
169 
170 // Extract from a string of the form someDir/1234.5678.jpg the number 123.456.
171 double fileNameToTimestamp(std::string const& file_name);
172 
173 // Create a directory unless it exists already
174 void createDir(std::string const& dir);
175 
176 // A little holding structure for nav, sci, and haz poses
177 struct CameraPoses {
178  std::map<double, double> haz_depth_to_image_timestamps;
179  std::map<std::string, std::map<double, Eigen::Affine3d> > world_to_cam_poses;
180 };
181 
182 // Some small utilities for writing a file having poses for nav, sci, and haz cam,
183 // and also the depth timestamp corresponding to given haz intensity timestamp
184 void writeCameraPoses(std::string const& filename, std::map<double, double> const& haz_depth_to_image_timestamps,
185  std::map<std::string, std::map<double, Eigen::Affine3d> > const& world_to_cam_poses);
186 
187 void readCameraPoses(std::string const& filename, std::map<double, double>& haz_depth_to_image_timestamps,
188  std::map<std::string, std::map<double, Eigen::Affine3d> >& world_to_cam_poses);
189 
190 // Gamma and inverse gamma functions
191 // https://en.wikipedia.org/wiki/SRGB#Specification_of_the_transformation
192 double gamma(double x);
193 double inv_gamma(double x);
194 
195 // Apply the inverse gamma transform to images, multiply them by
196 // max_iso_times_exposure/ISO/exposure_time to adjust for
197 // lightning differences, then apply the gamma transform back.
198 void exposureCorrection(double max_iso_times_exposure, double iso, double exposure, cv::Mat const& input_image,
199  cv::Mat& output_image);
200 
201 // Scale an image to correct for lightning variations by taking into
202 // account that JPEG images have gamma correction applied to them.
203 // See https://en.wikipedia.org/wiki/Gamma_correction.
204 void scaleImage(double max_iso_times_exposure, double iso, double exposure, cv::Mat const& input_image,
205  cv::Mat& output_image);
206 
207 // Given two bounds, pick two timestamps within these bounds, the one
208 // closest to the left bound and the one to the right bound. Take into
209 // account that the timestamps may need to have an offset added to
210 // them. Assume that the input timestamps are sorted in increasing order.
211 // TODO(oalexan1): May have to add a constraint to only pick
212 // a timestamp if not further from the bound than a given value.
213 void pickTimestampsInBounds(std::vector<double> const& timestamps, double left_bound, double right_bound, double offset,
214  std::vector<double>& out_timestamps);
215 
216 // Must always have NUM_EXIF the last.
217 enum ExifData { TIMESTAMP = 0, EXPOSURE_TIME, ISO, APERTURE, FOCAL_LENGTH, NUM_EXIF };
218 
219 // A utility for saving a camera in a format ASP understands.
220 // TODO(oalexan1): Expose the sci cam intrinsics rather than having
221 // them hard-coded.
222 void save_tsai_camera(Eigen::MatrixXd const& desired_cam_to_world_trans,
223  std::string const& output_dir,
224  double curr_time, std::string const& suffix);
225 
226 } // namespace dense_map
227 
228 #endif // DENSE_MAP_UTILS_H_
dense_map::CameraPoses
Definition: dense_map_utils.h:177
dense_map::StampedPoseStorage
Definition: dense_map_utils.h:139