34#include <visp3/core/vpPixelMeterConversion.h>
35#include <visp3/core/vpPlane.h>
36#include <visp3/core/vpPolygon.h>
37#include <visp3/core/vpRobust.h>
38#include <visp3/vision/vpPose.h>
42void estimatePlaneEquationSVD(
const std::vector<double> &point_cloud_face,
vpPlane &plane_equation_estimated,
46void estimatePlaneEquationSVD(
const std::vector<double> &point_cloud_face,
vpPlane &plane_equation_estimated,
49 const unsigned int max_iter = 10;
50 double prev_error = 1e3;
51 double error = 1e3 - 1;
52 const unsigned int size3DPt = 3;
53 unsigned int nPoints =
static_cast<unsigned int>(point_cloud_face.size() / size3DPt);
54 const unsigned int idX = 0;
55 const unsigned int idY = 1;
56 const unsigned int idZ = 2;
65 double fabs_error_m_prev_error = std::fabs(error - prev_error);
66 unsigned int iter = 0;
67 while ((iter < max_iter) && (fabs_error_m_prev_error > 1e-6)) {
73 double centroid_x = 0.0, centroid_y = 0.0, centroid_z = 0.0;
76 for (
unsigned int i = 0;
i < nPoints; ++
i) {
77 centroid_x += weights[
i] * point_cloud_face[(size3DPt *
i) + idX];
78 centroid_y += weights[
i] * point_cloud_face[(size3DPt *
i) + idY];
79 centroid_z += weights[
i] * point_cloud_face[(size3DPt *
i) + idZ];
80 total_w += weights[
i];
83 centroid_x /= total_w;
84 centroid_y /= total_w;
85 centroid_z /= total_w;
88 for (
unsigned int i = 0;
i < nPoints; ++
i) {
89 M[
static_cast<unsigned int>(
i)][idX] = weights[i] * (point_cloud_face[(size3DPt * i) + idX] - centroid_x);
90 M[
static_cast<unsigned int>(
i)][idY] = weights[i] * (point_cloud_face[(size3DPt * i) + idY] - centroid_y);
91 M[
static_cast<unsigned int>(
i)][idZ] = weights[i] * (point_cloud_face[(size3DPt * i) + idZ] - centroid_z);
99 double smallestSv = W[0];
100 unsigned int indexSmallestSv = 0;
101 unsigned int w_size = W.
size();
102 for (
unsigned int i = 1;
i < w_size; ++
i) {
103 if (W[i] < smallestSv) {
109 normal = V.
getCol(indexSmallestSv);
112 double A = normal[idX];
113 double B = normal[idY];
114 double C = normal[idZ];
115 double D = -((A * centroid_x) + (B * centroid_y) + (C * centroid_z));
120 for (
unsigned int i = 0;
i < nPoints; ++
i) {
121 residues[
i] = std::fabs((A * point_cloud_face[size3DPt * i]) + (B * point_cloud_face[(size3DPt * i) + idY]) +
122 (C * point_cloud_face[(size3DPt * i) + idZ]) + D) /
123 sqrt((A * A) + (B * B) + (C * C));
124 error += weights[
i] * residues[
i];
128 fabs_error_m_prev_error = std::fabs(error - prev_error);
137 centroid.
resize(size3DPt,
false);
138 double total_w = 0.0;
140 for (
unsigned int i = 0;
i < nPoints; ++
i) {
141 centroid[idX] += weights[
i] * point_cloud_face[size3DPt *
i];
142 centroid[idY] += weights[
i] * point_cloud_face[(size3DPt *
i) + idY];
143 centroid[idZ] += weights[
i] * point_cloud_face[(size3DPt *
i) + idZ];
144 total_w += weights[
i];
147 centroid[idX] /= total_w;
148 centroid[idY] /= total_w;
149 centroid[idZ] /= total_w;
152 double A = normal[0], B = normal[1], C = normal[idZ];
153 double D = -((A * centroid[0]) + (B * centroid[1]) + (C * centroid[idZ]));
156 plane_equation_estimated.
setABCD(A, B, C, D);
158 normalized_weights = total_w / nPoints;
164 double *confidence_index)
166 if (corners.size() != point3d.size()) {
168 "Cannot compute pose from RGBD, 3D (%d) and 2D (%d) data doesn't have the same size",
169 point3d.size(), corners.size()));
171 std::vector<vpPoint> pose_points;
172 if (confidence_index !=
nullptr) {
173 *confidence_index = 0.0;
176 size_t point3d_size = point3d.size();
177 for (
size_t i = 0; i < point3d_size; ++i) {
178 pose_points.push_back(point3d[i]);
183 unsigned int top =
static_cast<unsigned int>(std::max<int>(0,
static_cast<int>(bb.getTop())));
184 unsigned int bottom =
185 static_cast<unsigned int>(std::min<int>(
static_cast<int>(depthMap.
getHeight()) - 1,
static_cast<int>(bb.getBottom())));
186 unsigned int left =
static_cast<unsigned int>(std::max<int>(0,
static_cast<int>(bb.getLeft())));
188 static_cast<unsigned int>(std::min<int>(
static_cast<int>(depthMap.
getWidth()) - 1,
static_cast<int>(bb.getRight())));
190 std::vector<double> points_3d;
191 points_3d.reserve((bottom - top) * (right - left));
192 for (
unsigned int idx_i = top; idx_i < bottom; ++idx_i) {
193 for (
unsigned int idx_j = left; idx_j < right; ++idx_j) {
195 if ((depthMap[idx_i][idx_j] > 0) && (polygon.
isInside(imPt))) {
198 double Z = depthMap[idx_i][idx_j];
199 points_3d.push_back(x * Z);
200 points_3d.push_back(y * Z);
201 points_3d.push_back(Z);
206 unsigned int nb_points_3d =
static_cast<unsigned int>(points_3d.size() / 3);
208 const unsigned int minNbPoints = 4;
209 if (nb_points_3d > minNbPoints) {
210 std::vector<vpPoint> p, q;
215 double normalized_weights = 0;
216 estimatePlaneEquationSVD(points_3d, plane_equation, centroid, normalized_weights);
218 size_t corners_size = corners.size();
219 for (
size_t j = 0; j < corners_size; ++j) {
223 double Z = plane_equation.
computeZ(x, y);
227 p.push_back(
vpPoint(x * Z, y * Z, Z));
229 pose_points[j].set_x(x);
230 pose_points[j].set_y(y);
233 size_t point3d_size = point3d.size();
234 for (
size_t i = 0; i < point3d_size; ++i) {
235 q.push_back(point3d[i]);
244 if (confidence_index !=
nullptr) {
245 *confidence_index = std::min<double>(1.0, (normalized_weights *
static_cast<double>(nb_points_3d)) / polygon.
getArea());
256 const std::vector<std::vector<vpImagePoint> > &corners,
258 const std::vector<std::vector<vpPoint> > &point3d,
261 const size_t nb3dPoints = point3d.size();
262 const size_t nbCorners = corners.size();
263 if (nbCorners != nb3dPoints) {
265 "Cannot compute pose from RGBD, 3D (%d) and 2D (%d) data doesn't have the same size",
266 nb3dPoints, nbCorners));
268 std::vector<vpPoint> pose_points;
269 if (confidence_index !=
nullptr) {
270 *confidence_index = 0.0;
273 for (
size_t i = 0; i < nb3dPoints; ++i) {
274 std::vector<vpPoint> tagPoint3d = point3d[i];
275 size_t tagpoint3d_size = tagPoint3d.size();
276 for (
size_t j = 0; j < tagpoint3d_size; ++j) {
277 pose_points.push_back(tagPoint3d[j]);
282 double totalArea = 0.0;
285 std::vector<double> tag_points_3d;
288 std::vector<std::vector<double> > tag_points_3d_nonplanar;
289 size_t nb_points_3d_non_planar = 0;
292 size_t corners_size = corners.size();
293 for (
size_t i = 0; i < corners_size; ++i) {
294 std::vector<double> points_3d;
299 totalArea += polygon.
getArea();
301 unsigned int top =
static_cast<unsigned int>(std::max<int>(0,
static_cast<int>(bb.getTop())));
302 unsigned int bottom =
static_cast<unsigned int>(
303 std::min<int>(
static_cast<int>(depthMap.
getHeight()) - 1,
static_cast<int>(bb.getBottom())));
304 unsigned int left =
static_cast<unsigned int>(std::max<int>(0,
static_cast<int>(bb.getLeft())));
306 static_cast<unsigned int>(std::min<int>(
static_cast<int>(depthMap.
getWidth()) - 1,
static_cast<int>(bb.getRight())));
308 points_3d.reserve((bottom - top) * (right - left));
309 for (
unsigned int idx_i = top; idx_i < bottom; ++idx_i) {
310 for (
unsigned int idx_j = left; idx_j < right; ++idx_j) {
312 if ((depthMap[idx_i][idx_j] > 0) && (polygon.
isInside(imPt))) {
315 double Z = depthMap[idx_i][idx_j];
316 points_3d.push_back(x * Z);
317 points_3d.push_back(y * Z);
318 points_3d.push_back(Z);
325 if (coplanar_points) {
326 tag_points_3d.insert(tag_points_3d.end(), points_3d.begin(), points_3d.end());
329 tag_points_3d_nonplanar.push_back(points_3d);
330 nb_points_3d_non_planar += points_3d.size();
334 size_t nb_points_3d = 0;
335 const size_t sizePt3D = 3;
337 if (coplanar_points) {
338 nb_points_3d = tag_points_3d.size() / sizePt3D;
341 nb_points_3d = nb_points_3d_non_planar / sizePt3D;
344 const size_t minNbPts = 4;
345 if (nb_points_3d > minNbPts) {
346 std::vector<vpPoint> p, q;
351 double normalized_weights = 0;
353 if (coplanar_points) {
355 estimatePlaneEquationSVD(tag_points_3d, plane_equation, centroid, normalized_weights);
357 for (
size_t j = 0; j < nbCorners; ++j) {
358 std::vector<vpImagePoint> tag_corner = corners[j];
359 size_t tag_corner_size = tag_corner.size();
360 for (
size_t i = 0; i < tag_corner_size; ++i) {
364 double Z = plane_equation.
computeZ(x, y);
369 p.push_back(
vpPoint(x * Z, y * Z, Z));
370 pose_points[count].set_x(x);
371 pose_points[count].set_y(y);
380 size_t tag_points_3d_nonplanar_size = tag_points_3d_nonplanar.size();
381 for (
size_t k = 0; k < tag_points_3d_nonplanar_size; ++k) {
382 std::vector<double> rec_points_3d = tag_points_3d_nonplanar[k];
383 double tag_normalized_weights = 0;
384 const size_t minNbPtsForPlaneSVD = 3;
385 const size_t minSizeForPlaneSVD = minNbPtsForPlaneSVD * sizePt3D;
386 if (rec_points_3d.size() >= minSizeForPlaneSVD) {
388 estimatePlaneEquationSVD(rec_points_3d, plane_equation, centroid, tag_normalized_weights);
389 normalized_weights += tag_normalized_weights;
392 std::vector<vpImagePoint> tag_corner = corners[k];
394 size_t tag_corner_size = tag_corner.size();
395 for (
size_t i = 0; i < tag_corner_size; ++i) {
399 double Z = plane_equation.
computeZ(x, y);
404 p.push_back(
vpPoint(x * Z, y * Z, Z));
405 pose_points[count].set_x(x);
406 pose_points[count].set_y(y);
414 count += corners[k].size();
417 normalized_weights = normalized_weights / tag_points_3d_nonplanar.size();
420 for (
size_t i = 0; i < nb3dPoints; ++i) {
421 std::vector<vpPoint> tagPoint3d = point3d[i];
426 if (coplanar_points) {
427 size_t tag_point3d_size = tagPoint3d.size();
428 for (
size_t j = 0; j < tag_point3d_size; ++j) {
429 q.push_back(tagPoint3d[j]);
433 if (tag_points_3d_nonplanar[i].size() > 0) {
434 size_t tag_point3d_size = tagPoint3d.size();
435 for (
size_t j = 0; j < tag_point3d_size; ++j) {
436 q.push_back(tagPoint3d[j]);
443 if (p.size() == q.size()) {
450 if (confidence_index !=
nullptr) {
451 *confidence_index = std::min<double>(1.0, (normalized_weights *
static_cast<double>(nb_points_3d)) / totalArea);
unsigned int size() const
Return the number of elements of the 2D array.
Generic class defining intrinsic camera parameters.
Implementation of column vector and the associated operations.
void resize(unsigned int i, bool flagNullify=true)
error that can be emitted by ViSP classes.
Implementation of an homogeneous matrix and operations on such kind of matrices.
static vpHomogeneousMatrix compute3d3dTransformation(const std::vector< vpPoint > &p, const std::vector< vpPoint > &q)
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition of the vpImage class member functions.
unsigned int getWidth() const
unsigned int getHeight() const
Implementation of a matrix and operations on matrices.
void svd(vpColVector &w, vpMatrix &V)
vpColVector getCol(unsigned int j) const
static void convertPoint(const vpCameraParameters &cam, const double &u, const double &v, double &x, double &y)
This class defines the container for a plane geometrical structure.
double computeZ(double x, double y) const
void setABCD(double a, double b, double c, double d)
Class that defines a 3D point in the object frame and allows forward projection of a 3D point in the ...
Defines a generic 2D polygon.
vpRect getBoundingBox() const
bool isInside(const vpImagePoint &iP, const PointInPolygonMethod &method=PnPolyRayCasting) const
static bool computePlanarObjectPoseFromRGBD(const vpImage< float > &depthMap, const std::vector< vpImagePoint > &corners, const vpCameraParameters &colorIntrinsics, const std::vector< vpPoint > &point3d, vpHomogeneousMatrix &cMo, double *confidence_index=nullptr)
bool computePose(vpPoseMethodType method, vpHomogeneousMatrix &cMo, FuncCheckValidityPose func=nullptr)
void addPoints(const std::vector< vpPoint > &lP)
Defines a rectangle in the plane.
Contains an M-estimator and various influence function.
@ TUKEY
Tukey influence function.
void MEstimator(const vpRobustEstimatorType method, const vpColVector &residues, vpColVector &weights)
void setMinMedianAbsoluteDeviation(double mad_min)