40 float computeAzimuth(
const float a,
const float b)
42 return a >= 0 ?
static_cast<float>(M_PI) -
atan(b / (a + std::numeric_limits<float>::epsilon()))
43 :
atan(b / -(a + std::numeric_limits<float>::epsilon()));
46 float computeRange(
const float a,
const float b)
51 template <
typename T> T computeQuadraticSurface(T x, T z,
const T* params)
57 return params[0] *
pow(x, 2) + params[1] *
pow(z, 2) + params[2] * x * z +
58 params[3] * x + params[4] * z + params[5];
61 Eigen::Matrix<Eigen::Matrix<float, Eigen::Dynamic, 1>, Eigen::Dynamic, 1> generateBasisArray()
63 Eigen::Matrix<Eigen::Matrix<float, Eigen::Dynamic, 1>, Eigen::Dynamic, 1> ret(4);
66 Eigen::Matrix<float, Eigen::Dynamic, 1> basisCoefficients(4);
76 basisCoefficients(0) = 1.0 / 6.0;
77 basisCoefficients(1) = -0.5;
78 basisCoefficients(2) = 0.5;
79 basisCoefficients(3) = -1.0 / 6.0;
80 ret(0) = basisCoefficients;
84 basisCoefficients(0) = 2.0 / 3.0;
85 basisCoefficients(1) = 0.0;
86 basisCoefficients(2) = -1.0;
87 basisCoefficients(3) = 0.5;
88 ret(1) = basisCoefficients;
92 basisCoefficients(0) = 1.0 / 6.0;
93 basisCoefficients(1) = 0.5;
94 basisCoefficients(2) = 0.5;
95 basisCoefficients(3) = -0.5;
96 ret(2) = basisCoefficients;
100 basisCoefficients(0) = 0.0;
101 basisCoefficients(1) = 0.0;
102 basisCoefficients(2) = 0.0;
103 basisCoefficients(3) = 1.0 / 6.0;
104 ret(3) = basisCoefficients;
109 template <
class FloatT>
110 FloatT getSplineValue(
111 const FloatT* xzCellOrigin,
112 const FloatT* xzCellSize,
115 const Eigen::Matrix<FloatT, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> &controlGrid,
116 const Eigen::Matrix<Eigen::Matrix<FloatT, Eigen::Dynamic, 1>, Eigen::Dynamic, 1> &basisArray)
119 FloatT iTmp = (sValue - xzCellOrigin[0]) / xzCellSize[0];
120 FloatT jTmp = (tValue - xzCellOrigin[1]) / xzCellSize[1];
122 int iCoord =
static_cast<int>(floor(iTmp));
123 int jCoord =
static_cast<int>(floor(jTmp));
128 powersOfS[0] = FloatT(1.0);
129 powersOfS[1] = iTmp - FloatT(iCoord);
130 powersOfS[2] = powersOfS[1] * powersOfS[1];
131 powersOfS[3] = powersOfS[2] * powersOfS[1];
133 powersOfT[0] = FloatT(1.0);
134 powersOfT[1] = jTmp - FloatT(jCoord);
135 powersOfT[2] = powersOfT[1] * powersOfT[1];
136 powersOfT[3] = powersOfT[2] * powersOfT[1];
138 size_t iIndex =
static_cast<size_t>(iCoord);
139 size_t jIndex =
static_cast<size_t>(jCoord);
142 int index0 = iIndex - 1;
143 int index1 = jIndex - 1;
144 FloatT functionValue = 0.0;
145 for (
size_t kIndex = 0; kIndex < 4; ++kIndex)
147 size_t i0PlusK = index0 + kIndex;
149 FloatT B_k = std::inner_product(
150 powersOfS, powersOfS + 4, (basisArray)[kIndex].
data(), static_cast<FloatT>(0));
152 for (
size_t lIndex = 0; lIndex < 4; ++lIndex)
154 size_t i1PlusL = index1 + lIndex;
156 FloatT B_l = std::inner_product(
157 powersOfT, powersOfT + 4, (basisArray)[lIndex].
data(), static_cast<FloatT>(0));
159 functionValue += (B_k * B_l * controlGrid(i1PlusL, i0PlusK));
162 return functionValue;
170 return Eigen::Matrix<uint8_t, 3, 1>{ 114, 159, 207 };
172 return Eigen::Matrix<uint8_t, 3, 1>{ 255, 0, 0 };
174 return Eigen::Matrix<uint8_t, 3, 1>{ 0, 255, 0 };
177 return Eigen::Matrix<uint8_t, 3, 1>{ 0, 0, 0 };
181 const std::vector<Eigen::Vector3f, Eigen::aligned_allocator<Eigen::Vector3f>> &input,
182 const std::string &frame_id)
184 sensor_msgs::PointCloud2 ret =
185 multisense_ros::initialize_pointcloud<float>(
true, frame_id,
"intensity");
187 const double num_points = input.size();
188 ret.data.resize(num_points * ret.point_step);
190 for (
size_t i = 0; i < num_points; ++i)
192 float* cloudP =
reinterpret_cast<float*
>(&(ret.data[i * ret.point_step]));
193 cloudP[0] = input[i][0];
194 cloudP[1] = input[i][1];
195 cloudP[2] = input[i][2];
199 ret.row_step = num_points * ret.point_step;
200 ret.width = num_points;
201 ret.data.resize(num_points * ret.point_step);
207 const Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> &controlGrid,
209 const double pointcloudMaxRange,
210 const float* xzCellOrigin,
211 const float* xzCellSize,
212 const float* minMaxAzimuthAngle,
213 const float* extrinsics,
214 const float* quadraticParams,
215 const float baseline)
217 static const auto basisArray = generateBasisArray();
220 Eigen::Matrix<float, 4, 4> extrinsicsMat;
222 extrinsicsMat.setZero();
223 extrinsicsMat(0, 3) = extrinsics[0];
224 extrinsicsMat(1, 3) = extrinsics[1];
225 extrinsicsMat(2, 3) = extrinsics[2];
226 extrinsicsMat(3, 3) =
static_cast<float>(1.0);
227 Eigen::Matrix<float, 3, 3> rot =
228 (Eigen::AngleAxis<float>(extrinsics[5], Eigen::Matrix<float, 3, 1>(0, 0, 1))
229 * Eigen::AngleAxis<float>(extrinsics[4], Eigen::Matrix<float, 3, 1>(0, 1, 0))
230 * Eigen::AngleAxis<float>(extrinsics[3], Eigen::Matrix<float, 3, 1>(1, 0, 0))).matrix();
231 extrinsicsMat.block(0, 0, 3, 3) = rot;
235 const auto extrinsicsInverse = extrinsicsMat.inverse();
238 const size_t numPoints =
242 std::vector<Eigen::Vector3f, Eigen::aligned_allocator<Eigen::Vector3f>> points;
243 points.reserve(numPoints);
250 const auto y = getSplineValue(xzCellOrigin, xzCellSize, x, z, controlGrid, basisArray)
251 + computeQuadraticSurface(x, z, quadraticParams);
253 const Eigen::Vector3f splinePoint = Eigen::Vector3f(x, y, z);
254 const Eigen::Vector3f transformedSplinePoint = (extrinsicsInverse * splinePoint.homogeneous()).hnormalized();
257 const auto distance = computeRange(transformedSplinePoint(0), transformedSplinePoint(2));
258 if (distance > pointcloudMaxRange)
261 const auto leftCamAzimuthAngle = computeAzimuth(transformedSplinePoint(0), transformedSplinePoint(2));
262 if (leftCamAzimuthAngle < minMaxAzimuthAngle[0])
266 const auto rightCamAzimuthAngle = computeAzimuth(transformedSplinePoint(0) + baseline, transformedSplinePoint(2));
267 if (rightCamAzimuthAngle > minMaxAzimuthAngle[1])
270 points.emplace_back(splinePoint);
274 points.shrink_to_fit();
double max_z_m
The max range (along the z dimension / optical axis) to draw the B-spline model.
INLINE Rall1d< T, V, S > atan(const Rall1d< T, V, S > &x)
double max_x_m
The max width (along the x dimension) to draw the B-spline model.
Struct containing parameters for drawing a pointcloud representation of a B-Spline model...
INLINE Rall1d< T, V, S > sqrt(const Rall1d< T, V, S > &arg)
INLINE Rall1d< T, V, S > pow(const Rall1d< T, V, S > &arg, double m)
sensor_msgs::PointCloud2 eigenToPointcloud(const std::vector< Eigen::Vector3f, Eigen::aligned_allocator< Eigen::Vector3f >> &input, const std::string &frame_id)
Convert an eigen representation of a pointcloud to a ROS sensor_msgs::PointCloud2 format...
Eigen::Matrix< uint8_t, 3, 1 > groundSurfaceClassToPixelColor(const uint8_t value)
Look up table to convert a ground surface class value into into a color for visualization (out-of-bou...
double min_x_m
The min width (along the x dimension) to draw the B-spline model.
double resolution
The resolution to sample the B-Spline model for drawing.
double min_z_m
The min range (along the z dimension / optical axis) to draw the B-spline model.
std::vector< Eigen::Vector3f, Eigen::aligned_allocator< Eigen::Vector3f > > convertSplineToPointcloud(const Eigen::Matrix< float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > &controlGrid, const SplineDrawParameters &splineDrawParams, const double pointcloudMaxRange, const float *xzCellOrigin, const float *xzCellSize, const float *minMaxAzimuthAngle, const float *extrinsics, const float *quadraticParams, const float baseline)
Generate a pointcloud representation of a b-spline ground surface model for visualization.