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>
43 void estimatePlaneEquationSVD(
const std::vector<double> &point_cloud_face,
vpPlane &plane_equation_estimated,
46 const unsigned int max_iter = 10;
47 double prev_error = 1e3;
48 double error = 1e3 - 1;
49 const unsigned int size3DPt = 3;
50 unsigned int nPoints =
static_cast<unsigned int>(point_cloud_face.size() / size3DPt);
51 const unsigned int idX = 0;
52 const unsigned int idY = 1;
53 const unsigned int idZ = 2;
62 double fabs_error_m_prev_error = std::fabs(error - prev_error);
63 unsigned int iter = 0;
64 while ((iter < max_iter) && (fabs_error_m_prev_error > 1e-6)) {
70 double centroid_x = 0.0, centroid_y = 0.0, centroid_z = 0.0;
73 for (
unsigned int i = 0; i < nPoints; ++i) {
74 centroid_x += weights[i] * point_cloud_face[(size3DPt * i) + idX];
75 centroid_y += weights[i] * point_cloud_face[(size3DPt * i) + idY];
76 centroid_z += weights[i] * point_cloud_face[(size3DPt * i) + idZ];
77 total_w += weights[i];
80 centroid_x /= total_w;
81 centroid_y /= total_w;
82 centroid_z /= total_w;
85 for (
unsigned int i = 0; i < nPoints; ++i) {
86 M[
static_cast<unsigned int>(i)][idX] = weights[i] * (point_cloud_face[(size3DPt * i) + idX] - centroid_x);
87 M[
static_cast<unsigned int>(i)][idY] = weights[i] * (point_cloud_face[(size3DPt * i) + idY] - centroid_y);
88 M[
static_cast<unsigned int>(i)][idZ] = weights[i] * (point_cloud_face[(size3DPt * i) + idZ] - centroid_z);
96 double smallestSv = W[0];
97 unsigned int indexSmallestSv = 0;
98 unsigned int w_size = W.
size();
99 for (
unsigned int i = 1; i < w_size; ++i) {
100 if (W[i] < smallestSv) {
106 normal = V.
getCol(indexSmallestSv);
109 double A = normal[idX];
110 double B = normal[idY];
111 double C = normal[idZ];
112 double D = -((A * centroid_x) + (B * centroid_y) + (C * centroid_z));
117 for (
unsigned int i = 0; i < nPoints; ++i) {
118 residues[i] = std::fabs((A * point_cloud_face[size3DPt * i]) + (B * point_cloud_face[(size3DPt * i) + idY]) +
119 (C * point_cloud_face[(size3DPt * i) + idZ]) + D) /
120 sqrt((A * A) + (B * B) + (C * C));
121 error += weights[i] * residues[i];
125 fabs_error_m_prev_error = std::fabs(error - prev_error);
134 centroid.
resize(size3DPt,
false);
135 double total_w = 0.0;
137 for (
unsigned int i = 0; i < nPoints; ++i) {
138 centroid[idX] += weights[i] * point_cloud_face[size3DPt * i];
139 centroid[idY] += weights[i] * point_cloud_face[(size3DPt * i) + idY];
140 centroid[idZ] += weights[i] * point_cloud_face[(size3DPt * i) + idZ];
141 total_w += weights[i];
144 centroid[idX] /= total_w;
145 centroid[idY] /= total_w;
146 centroid[idZ] /= total_w;
149 double A = normal[0], B = normal[1], C = normal[idZ];
150 double D = -((A * centroid[0]) + (B * centroid[1]) + (C * centroid[idZ]));
153 plane_equation_estimated.
setABCD(A, B, C, D);
155 normalized_weights = total_w / nPoints;
161 double *confidence_index)
163 if (corners.size() != point3d.size()) {
165 "Cannot compute pose from RGBD, 3D (%d) and 2D (%d) data doesn't have the same size",
166 point3d.size(), corners.size()));
168 std::vector<vpPoint> pose_points;
169 if (confidence_index !=
nullptr) {
170 *confidence_index = 0.0;
173 size_t point3d_size = point3d.size();
174 for (
size_t i = 0; i < point3d_size; ++i) {
175 pose_points.push_back(point3d[i]);
180 unsigned int top =
static_cast<unsigned int>(std::max<int>(0,
static_cast<int>(bb.
getTop())));
181 unsigned int bottom =
182 static_cast<unsigned int>(std::min<int>(
static_cast<int>(depthMap.
getHeight()) - 1,
static_cast<int>(bb.
getBottom())));
183 unsigned int left =
static_cast<unsigned int>(std::max<int>(0,
static_cast<int>(bb.
getLeft())));
185 static_cast<unsigned int>(std::min<int>(
static_cast<int>(depthMap.
getWidth()) - 1,
static_cast<int>(bb.
getRight())));
187 std::vector<double> points_3d;
188 points_3d.reserve((bottom - top) * (right - left));
189 for (
unsigned int idx_i = top; idx_i < bottom; ++idx_i) {
190 for (
unsigned int idx_j = left; idx_j < right; ++idx_j) {
192 if ((depthMap[idx_i][idx_j] > 0) && (polygon.
isInside(imPt))) {
195 double Z = depthMap[idx_i][idx_j];
196 points_3d.push_back(x * Z);
197 points_3d.push_back(y * Z);
198 points_3d.push_back(Z);
203 unsigned int nb_points_3d =
static_cast<unsigned int>(points_3d.size() / 3);
205 const unsigned int minNbPoints = 4;
206 if (nb_points_3d > minNbPoints) {
207 std::vector<vpPoint> p, q;
212 double normalized_weights = 0;
213 estimatePlaneEquationSVD(points_3d, plane_equation, centroid, normalized_weights);
215 size_t corners_size = corners.size();
216 for (
size_t j = 0; j < corners_size; ++j) {
220 double Z = plane_equation.
computeZ(x, y);
224 p.push_back(
vpPoint(x * Z, y * Z, Z));
226 pose_points[j].set_x(x);
227 pose_points[j].set_y(y);
230 size_t point3d_size = point3d.size();
231 for (
size_t i = 0; i < point3d_size; ++i) {
232 q.push_back(point3d[i]);
241 if (confidence_index !=
nullptr) {
242 *confidence_index = std::min<double>(1.0, (normalized_weights *
static_cast<double>(nb_points_3d)) / polygon.
getArea());
253 const std::vector<std::vector<vpImagePoint> > &corners,
255 const std::vector<std::vector<vpPoint> > &point3d,
258 const size_t nb3dPoints = point3d.size();
259 const size_t nbCorners = corners.size();
260 if (nbCorners != nb3dPoints) {
262 "Cannot compute pose from RGBD, 3D (%d) and 2D (%d) data doesn't have the same size",
263 nb3dPoints, nbCorners));
265 std::vector<vpPoint> pose_points;
266 if (confidence_index !=
nullptr) {
267 *confidence_index = 0.0;
270 for (
size_t i = 0; i < nb3dPoints; ++i) {
271 std::vector<vpPoint> tagPoint3d = point3d[i];
272 size_t tagpoint3d_size = tagPoint3d.size();
273 for (
size_t j = 0; j < tagpoint3d_size; ++j) {
274 pose_points.push_back(tagPoint3d[j]);
279 double totalArea = 0.0;
282 std::vector<double> tag_points_3d;
285 std::vector<std::vector<double> > tag_points_3d_nonplanar;
286 size_t nb_points_3d_non_planar = 0;
289 size_t corners_size = corners.size();
290 for (
size_t i = 0; i < corners_size; ++i) {
291 std::vector<double> points_3d;
296 totalArea += polygon.
getArea();
298 unsigned int top =
static_cast<unsigned int>(std::max<int>(0,
static_cast<int>(bb.
getTop())));
299 unsigned int bottom =
static_cast<unsigned int>(
300 std::min<int>(
static_cast<int>(depthMap.
getHeight()) - 1,
static_cast<int>(bb.
getBottom())));
301 unsigned int left =
static_cast<unsigned int>(std::max<int>(0,
static_cast<int>(bb.
getLeft())));
303 static_cast<unsigned int>(std::min<int>(
static_cast<int>(depthMap.
getWidth()) - 1,
static_cast<int>(bb.
getRight())));
305 points_3d.reserve((bottom - top) * (right - left));
306 for (
unsigned int idx_i = top; idx_i < bottom; ++idx_i) {
307 for (
unsigned int idx_j = left; idx_j < right; ++idx_j) {
309 if ((depthMap[idx_i][idx_j] > 0) && (polygon.
isInside(imPt))) {
312 double Z = depthMap[idx_i][idx_j];
313 points_3d.push_back(x * Z);
314 points_3d.push_back(y * Z);
315 points_3d.push_back(Z);
322 if (coplanar_points) {
323 tag_points_3d.
insert(tag_points_3d.end(), points_3d.begin(), points_3d.end());
326 tag_points_3d_nonplanar.push_back(points_3d);
327 nb_points_3d_non_planar += points_3d.size();
331 size_t nb_points_3d = 0;
332 const size_t sizePt3D = 3;
334 if (coplanar_points) {
335 nb_points_3d = tag_points_3d.size() / sizePt3D;
338 nb_points_3d = nb_points_3d_non_planar / sizePt3D;
341 const size_t minNbPts = 4;
342 if (nb_points_3d > minNbPts) {
343 std::vector<vpPoint> p, q;
348 double normalized_weights = 0;
350 if (coplanar_points) {
352 estimatePlaneEquationSVD(tag_points_3d, plane_equation, centroid, normalized_weights);
354 for (
size_t j = 0; j < nbCorners; ++j) {
355 std::vector<vpImagePoint> tag_corner = corners[j];
356 size_t tag_corner_size = tag_corner.size();
357 for (
size_t i = 0; i < tag_corner_size; ++i) {
361 double Z = plane_equation.
computeZ(x, y);
366 p.push_back(
vpPoint(x * Z, y * Z, Z));
367 pose_points[count].set_x(x);
368 pose_points[count].set_y(y);
377 size_t tag_points_3d_nonplanar_size = tag_points_3d_nonplanar.size();
378 for (
size_t k = 0; k < tag_points_3d_nonplanar_size; ++k) {
379 std::vector<double> rec_points_3d = tag_points_3d_nonplanar[k];
380 double tag_normalized_weights = 0;
381 const size_t minNbPtsForPlaneSVD = 3;
382 const size_t minSizeForPlaneSVD = minNbPtsForPlaneSVD * sizePt3D;
383 if (rec_points_3d.size() >= minSizeForPlaneSVD) {
385 estimatePlaneEquationSVD(rec_points_3d, plane_equation, centroid, tag_normalized_weights);
386 normalized_weights += tag_normalized_weights;
389 std::vector<vpImagePoint> tag_corner = corners[k];
391 size_t tag_corner_size = tag_corner.size();
392 for (
size_t i = 0; i < tag_corner_size; ++i) {
396 double Z = plane_equation.
computeZ(x, y);
401 p.push_back(
vpPoint(x * Z, y * Z, Z));
402 pose_points[count].set_x(x);
403 pose_points[count].set_y(y);
411 count += corners[k].size();
414 normalized_weights = normalized_weights / tag_points_3d_nonplanar.size();
417 for (
size_t i = 0; i < nb3dPoints; ++i) {
418 std::vector<vpPoint> tagPoint3d = point3d[i];
423 if (coplanar_points) {
424 size_t tag_point3d_size = tagPoint3d.size();
425 for (
size_t j = 0; j < tag_point3d_size; ++j) {
426 q.push_back(tagPoint3d[j]);
430 if (tag_points_3d_nonplanar[i].size() > 0) {
431 size_t tag_point3d_size = tagPoint3d.size();
432 for (
size_t j = 0; j < tag_point3d_size; ++j) {
433 q.push_back(tagPoint3d[j]);
440 if (p.size() == q.size()) {
447 if (confidence_index !=
nullptr) {
448 *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 ...
unsigned int getWidth() const
void insert(const vpImage< Type > &src, const vpImagePoint &topLeft)
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
Class used for pose computation from N points (pose from point only). Some of the algorithms implemen...
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)