Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpRBSilhouetteControlPoint.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 * See the file LICENSE.txt at the root directory of this source
10 * distribution for additional information about the GNU GPL.
11 *
12 * For using ViSP with software that can not be combined with the GNU
13 * GPL, please contact Inria about acquiring a ViSP Professional
14 * Edition License.
15 *
16 * See https://visp.inria.fr for more information.
17 *
18 * This software was developed at:
19 * Inria Rennes - Bretagne Atlantique
20 * Campus Universitaire de Beaulieu
21 * 35042 Rennes Cedex
22 * France
23 *
24 * If you have questions regarding the use of this file, please contact
25 * Inria at visp@inria.fr
26 *
27 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 */
30
31#include <visp3/rbt/vpRBSilhouetteControlPoint.h>
32#include <visp3/core/vpTrackingException.h>
33#include <visp3/visual_features/vpFeatureBuilder.h>
34#include <visp3/core/vpRobust.h>
35
36#define VISP_DEBUG_RB_CONTROL_POINT 0
37#define DEGENERATE_LINE_THRESHOLD 1e-7
38
40
42{
43 m_valid = false;
44}
45
47{
48 init();
49 m_me = nullptr;
50 m_numCandidates = 1;
51 m_candidates.resize(1);
52 m_meMaskSign = 1;
53 m_normal.resize(3);
54 theta = 0;
55 m_isSilhouette = false;
56 m_valid = true;
57}
58
64
66{
67 m_me = other.m_me;
68 m_site = other.m_site;
69 m_numCandidates = other.m_numCandidates;
70 m_cam = other.m_cam;
71 icpoint = other.icpoint;
72 cpoint = other.cpoint;
73 cpointo = other.cpointo;
74 m_normal = other.m_normal;
75 m_normalO = other.m_normalO;
76 xs = other.xs;
77 ys = other.ys;
78 nxs = other.nxs;
79 nys = other.nys;
80 Zs = other.Zs;
81 m_isSilhouette = other.m_isSilhouette;
82 rho = other.rho;
83 theta = other.theta;
84 thetaInit = other.thetaInit;
85 m_meMaskSign = other.m_meMaskSign;
86 m_lineFeature = other.m_lineFeature;
87 m_line = other.m_line;
88 m_valid = other.m_valid;
89 return *this;
90}
91
96
98{
99 m_me = std::move(other.m_me);
100 m_site = std::move(other.m_site);
101 thetaInit = std::move(other.thetaInit);
102 m_numCandidates = std::move(other.m_numCandidates);
103 m_cam = std::move(other.m_cam);
104 icpoint = std::move(other.icpoint);
105 cpoint = std::move(other.cpoint);
106 cpointo = std::move(other.cpointo);
107 m_normal = std::move(other.m_normal);
108 m_normalO = std::move(other.m_normalO);
109 xs = std::move(other.xs);
110 ys = std::move(other.ys);
111 nxs = std::move(other.nxs);
112 nys = std::move(other.nys);
113 Zs = std::move(other.Zs);
114 m_isSilhouette = std::move(other.m_isSilhouette);
115 rho = std::move(other.rho);
116 theta = std::move(other.theta);
117 m_meMaskSign = std::move(other.m_meMaskSign);
118 m_lineFeature = std::move(other.m_lineFeature);
119 m_line = std::move(other.m_line);
120 m_valid = std::move(other.m_valid);
121 m_candidates = std::move(other.m_candidates);
122 return *this;
123}
124
126{
127
128 if (m_site.getState() == vpMeSite::NO_SUPPRESSION) {
129 try {
130 if (m_site.m_convlt == 0) {
131 m_site.track(I, m_me, false);
132 }
133 else {
134 m_site.track(I, m_me, false);
135 }
136 }
137 catch (vpTrackingException &) {
138 vpERROR_TRACE("caught a tracking exception, ignoring me point...");
139 m_site.setState(vpMeSite::THRESHOLD);
140 }
141 }
142}
143
145{
146 // If element hasn't been suppressed
147 try {
148 if (m_site.getState() == vpMeSite::NO_SUPPRESSION) {
149 //const bool testContrast = s.m_convlt != 0.0;
150 m_site.trackMultipleHypotheses(I, *m_me, false, m_candidates, m_numCandidates);
151 m_site = m_candidates[0];
152 }
153 }
154 catch (vpTrackingException &) {
155 vpERROR_TRACE("caught a tracking exception, ignoring me point...");
156 m_site.setState(vpMeSite::THRESHOLD);
157 }
158}
159
167void
168vpRBSilhouetteControlPoint::buildPlane(const vpPoint &pointn, const vpColVector &normal, vpPlane &plane)
169{
170 plane.init(pointn, normal, vpPlane::object_frame);
171}
172
173void
174vpRBSilhouetteControlPoint::buildPLine(const vpHomogeneousMatrix &oMc)
175{
176 vpPlane plane;
177 vpPlane plane1;
178 vpPlane plane2;
179 buildPlane(cpoint, m_normal, plane);
180 vpRotationMatrix R;
181 oMc.extract(R);
182
183 vpColVector V(3);
184 vpColVector Vo(3);
185 if (abs(theta) > 1e-2) {
186 V[0] = ((cpoint.get_oX()/cpoint.get_oZ())+1)*cpoint.get_oZ()-cpoint.get_oX();
187 V[1] = ((cpoint.get_oY()/cpoint.get_oZ())-cos(theta)/sin(theta))*cpoint.get_oZ()-cpoint.get_oY();
188 V[2] = (-plane.getD()-V[0]*plane.getA()-V[1]*plane.getB())/plane.getC()-cpoint.get_oZ();
189 }
190 else {
191 V[0] = ((cpoint.get_oX()/cpoint.get_oZ())+1)*cpoint.get_oZ()-cpoint.get_oX();
192 V[1] = ((cpoint.get_oY()/cpoint.get_oZ()))*cpoint.get_oZ()-cpoint.get_oY();
193 V[2] = (-plane.getD()-V[0]*plane.getA()-V[1]*plane.getB())/plane.getC()-cpoint.get_oZ();
194 }
195
196 Vo = R*V;
197 vpColVector norm2 = vpColVector::cross(Vo, m_normalO);
198 buildPlane(cpointo, norm2, plane2);
199 buildPlane(cpointo, m_normalO, plane1);
200
201 m_line.setWorldCoordinates(plane1.getA(), plane1.getB(), plane1.getC(), plane1.getD(),
202 plane2.getA(), plane2.getB(), plane2.getC(), plane2.getD());
203}
204
205void
206vpRBSilhouetteControlPoint::buildPoint(int n, int m, const double &Z, double orient, const vpColVector &normo,
207 const vpHomogeneousMatrix &cMo, const vpHomogeneousMatrix &oMc,
208 const vpCameraParameters &cam, const vpMe &me, bool isSilhouette)
209{
210 m_cam = &cam;
211 m_me = &me;
212 m_isSilhouette = isSilhouette;
214 cMo.extract(R);
215 theta = orient;
216 thetaInit = theta;
217 double px = m_cam->get_px();
218 double py = m_cam->get_py();
219 int jc = static_cast<int>(m_cam->get_u0());
220 int ic = static_cast<int>(m_cam->get_v0());
221 icpoint.set_i(n);
222 icpoint.set_j(m);
223 double x, y;
224 x = (m-jc)/px;
225 y = (n-ic)/py;
226 rho = x*cos(theta)+y*sin(theta);
227 cpoint.setWorldCoordinates(x*Z, y*Z, Z);
228 cpoint.changeFrame(oMc);
229 cpointo.setWorldCoordinates(cpoint.get_X(), cpoint.get_Y(), cpoint.get_Z());
230 m_normalO = normo;
231 m_normal = R * normo;
232 nxs = cos(theta);
233 nys = sin(theta);
234 buildPLine(oMc);
235 m_valid = !isLineDegenerate();
236}
237
238void
239vpRBSilhouetteControlPoint::buildSilhouettePoint(int n, int m, const double &Z, double orient, const vpColVector &normo,
240 const vpHomogeneousMatrix &cMo, const vpHomogeneousMatrix &oMc,
241 const vpCameraParameters &cam)
242{
243 m_isSilhouette = true;
244 m_cam = &cam;
246 cMo.extract(R);
247 theta = orient;
248 thetaInit = theta;
249 double px = m_cam->get_px();
250 double py = m_cam->get_py();
251 int jc = static_cast<int>(m_cam->get_u0());
252 int ic = static_cast<int>(m_cam->get_v0());
253 icpoint.set_i(n);
254 icpoint.set_j(m);
255 xs = (m-jc)/px;
256 ys = (n-ic)/py;
257 Zs = Z;
258
259 nxs = cos(theta);
260 nys = sin(theta);
261 double x, y;
262 x = (m-jc)/px;
263 y = (n-ic)/py;
264 cpoint.setWorldCoordinates(x * Z, y * Z, Z);
265 cpoint.changeFrame(oMc);
266 cpointo.setWorldCoordinates(cpoint.get_X(), cpoint.get_Y(), cpoint.get_Z());
267 m_normalO = normo;
268 m_normal = R * normo;
269 buildPLine(oMc);
270#if VISP_DEBUG_RB_CONTROL_POINT
271 if (std::isnan(m_line.getTheta())) {
272 std::cerr << "Line in camera frame = " << m_line.cP << std::endl;
273 throw vpException(vpException::fatalError, "Incorrect line definition");
274
275 }
276#endif
277 m_valid = isLineDegenerate();
278}
279
280void
282{
283 cpointo.changeFrame(_cMo);
284 cpointo.projection();
285 double px = m_cam->get_px();
286 double py = m_cam->get_py();
287 double uc = m_cam->get_u0();
288 double vc = m_cam->get_v0();
289 double u, v;
290 v = py*cpointo.get_y()+vc;
291 u = px*cpointo.get_x()+uc;
292 icpoint.set_uv(u, v);
293}
294
295void
297{
298 cpointo.changeFrame(cMo);
299 cpointo.projection();
300 const double px = m_cam->get_px();
301 const double py = m_cam->get_py();
302 const double uc = m_cam->get_u0();
303 const double vc = m_cam->get_v0();
304 const double v = py * cpointo.get_y() + vc;
305 const double u = px * cpointo.get_x() + uc;
306 icpoint.set_uv(u, v);
307 xs = cpointo.get_x();
308 ys = cpointo.get_y();
309 Zs = cpointo.get_Z();
310 m_normal = cRo * m_normalO;
311 vpColVector cameraRayObject({ cpointo.get_X(), cpointo.get_Y(), cpointo.get_Z() });
312 cameraRayObject.normalize();
313 if (acos(cameraRayObject * m_normal) < vpMath::rad(75.0)) {
314 m_valid = false;
315 }
316
317 if (m_valid) {
318 try {
319 m_line.changeFrame(cMo);
320 m_line.projection();
321 }
322 catch (vpException &) {
323 m_valid = false;
324 }
325 m_valid = !isLineDegenerate() && !std::isnan(m_line.getTheta());
326 if (m_valid) {
327 vpFeatureBuilder::create(m_lineFeature, m_line);
328 theta = m_lineFeature.getTheta();
329#if VISP_DEBUG_RB_CONTROL_POINT
330 if (std::isnan(theta)) {
331 throw vpException(vpException::fatalError, "Got nan theta in updateSilhouettePoint");
332 }
333#endif
334 if (fabs(theta - thetaInit) < M_PI / 2.0) {
335 nxs = cos(theta);
336 nys = sin(theta);
337 }
338 else {
339 nxs = -cos(theta);
340 nys = -sin(theta);
341 }
342 }
343 }
344}
345
347{
348 m_site.init(static_cast<double>(icpoint.get_i()), static_cast<double>(icpoint.get_j()), theta, cvlt, m_meMaskSign);
349 if (m_me != nullptr) {
350 const double marginRatio = m_me->getThresholdMarginRatio();
351 const double convolution = m_site.convolution(I, m_me);
352 m_site.init(static_cast<double>(icpoint.get_i()), static_cast<double>(icpoint.get_j()), theta, convolution, m_meMaskSign);
353 const double contrastThreshold = fabs(convolution) * marginRatio;
354 m_site.setContrastThreshold(contrastThreshold, *m_me);
355 }
356}
357
358
362void
364 vpColVector &e)
365{
366 m_line.changeFrame(cMo);
367
368 m_valid = false;
369 if (!isLineDegenerate()) {
370 m_line.projection();
371 vpFeatureBuilder::create(m_lineFeature, m_line);
372
373 double rho0 = m_lineFeature.getRho();
374 double theta0 = m_lineFeature.getTheta();
375#if VISP_DEBUG_RB_CONTROL_POINT
376 if (std::isnan(theta0)) {
377 std::cerr << "Line in camera frame = " << m_line.cP.t() << std::endl;
378 std::cerr << "Line in object frame = " << m_line.oP.t() << std::endl;
379 m_lineFeature.print();
380 throw vpException(vpException::fatalError, "Got nan theta in computeInteractionMatrixError");
381 }
382#endif
383 double co = cos(theta0);
384 double si = sin(theta0);
385
386 double mx = 1.0 / m_cam->get_px();
387 double my = 1.0 / m_cam->get_py();
388 double xc = m_cam->get_u0();
389 double yc = m_cam->get_v0();
390
391 vpMatrix H;
392 H = m_lineFeature.interaction();
393 double x = static_cast<double>(m_site.m_j), y = static_cast<double>(m_site.m_i);
394
395 x = (x-xc)*mx;
396 y = (y-yc)*my;
397
398 const double alpha = x*si - y*co;
399
400 double *Lrho = H[0];
401 double *Ltheta = H[1];
402 // Calculate interaction matrix for a distance
403 for (unsigned int k = 0; k < 6; k++) {
404 L[i][k] = (Lrho[k] + alpha*Ltheta[k]);
405 }
406 e[i] = rho0 - (x*co + y*si);
407 m_valid = true;
408 }
409 else {
410 m_valid = false;
411 e[i] = 0;
412 for (unsigned int k = 0; k < 6; k++) {
413 L[i][k] = 0.0;
414 }
415 }
416}
417
418void
420 vpMatrix &L, vpColVector &e)
421{
422 m_line.changeFrame(cMo);
423
424 m_valid = false;
425 if (!isLineDegenerate()) {
426 m_line.projection();
427
428 vpFeatureBuilder::create(m_lineFeature, m_line);
429 const double rho0 = m_lineFeature.getRho();
430 const double theta0 = m_lineFeature.getTheta();
431#if VISP_DEBUG_RB_CONTROL_POINT
432 if (std::isnan(theta0)) {
433 throw vpException(vpException::fatalError, "Got nan theta in computeInteractionMatrixMH");
434 }
435#endif
436
437 const double co = cos(theta0);
438 const double si = sin(theta0);
439
440 const double mx = 1.0 / m_cam->get_px();
441 const double my = 1.0 / m_cam->get_py();
442 const double xc = m_cam->get_u0();
443 const double yc = m_cam->get_v0();
444 const vpMatrix &H = m_lineFeature.interaction();
445 double xmin, ymin;
446 double errormin = std::numeric_limits<double>::max();
447
448 const std::vector<vpMeSite> &cs = m_candidates;
449 xmin = (m_site.m_j - xc) * mx;
450 ymin = (m_site.m_i - yc) * my;
451 for (unsigned int l = 0; l < m_numCandidates; l++) //for each candidate of P
452 {
453 const vpMeSite &Pk = cs[l];
454
455 if ((Pk.getState() == vpMeSite::NO_SUPPRESSION)) {
456 const double x = (Pk.m_j - xc) * mx;
457 const double y = (Pk.m_i - yc) * my;
458 const double err = fabs(rho0 - (x * co + y * si));
459 if (err <= errormin) {
460 errormin = err;
461 xmin = x;
462 ymin = y;
463 m_valid = true;
464 }
465 }
466 }
467 if (m_valid) {
468 e[i] = rho0 - (xmin * co + ymin * si);
469 const double alpha = xmin * si - ymin * co;
470
471 const double *Lrho = H[0];
472 const double *Ltheta = H[1];
473 // Calculate interaction matrix for a distance
474 for (unsigned int k = 0; k < 6; k++) {
475 L[i][k] = (Lrho[k] + alpha * Ltheta[k]);
476 }
477 }
478 else {
479 e[i] = 0;
480 for (unsigned int k = 0; k < 6; k++) {
481 L[i][k] = 0.0;
482 }
483 }
484 }
485}
486
487
489{
490 std::vector<float> maskValues(searchSize * 2 + 1);
491 double c = cos(theta);
492 double s = sin(theta);
493 int index = 0;
494 for (int n = -searchSize + 1; n < searchSize; ++n) {
495 unsigned int ii = static_cast<unsigned int>(round(icpoint.get_i() + s * n));
496 unsigned int jj = static_cast<unsigned int>(round(icpoint.get_j() + c * n));
497
498 maskValues[index] = mask[ii][jj];
499 ++index;
500 }
501
502 double maxGrad = 0.0;
503
504 for (unsigned i = 1; i < maskValues.size() - 1; ++i) {
505 double grad = abs(maskValues[i + 1] - maskValues[i - 1]);
506 if (grad > maxGrad) {
507 maxGrad = grad;
508 }
509 }
510 return maxGrad;
511}
512
513bool vpRBSilhouetteControlPoint::tooCloseToBorder(unsigned int h, unsigned int w, int searchSize) const
514{
515 double cs = cos(theta) * static_cast<double>(searchSize);
516 double ss = sin(theta) * static_cast<double>(searchSize);
517
518 std::array<std::pair<int, int>, 2> extremities = {
519 std::make_pair(static_cast<int>(round(icpoint.get_i() + ss)), static_cast<int>(round(icpoint.get_j() + cs))),
520 std::make_pair(static_cast<int>(round(icpoint.get_i() - ss)), static_cast<int>(round(icpoint.get_j() - cs)))
521 };
522
523 int width = static_cast<int>(w);
524 int height = static_cast<int>(h);
525 for (unsigned int e = 0; e < 2; ++e) {
526 int i = extremities[e].first;
527 int j = extremities[e].second;
528 if (i < 0 || i >= height || j < 0 || j >= width) {
529 return true;
530 }
531 }
532
533 return false;
534}
535
536bool vpRBSilhouetteControlPoint::isLineDegenerate() const
537{
538 double a, b, d;
539 a = m_line.cP[4] * m_line.cP[3] - m_line.cP[0] * m_line.cP[7];
540 b = m_line.cP[5] * m_line.cP[3] - m_line.cP[1] * m_line.cP[7];
541 d = a*a + b*b;
542 return d <= DEGENERATE_LINE_THRESHOLD;
543}
544
545END_VISP_NAMESPACE
Generic class defining intrinsic camera parameters.
Implementation of column vector and the associated operations.
vpColVector & normalize()
void init(const vpColVector &v, unsigned int r, unsigned int nrows)
static vpColVector cross(const vpColVector &a, const vpColVector &b)
error that can be emitted by ViSP classes.
Definition vpException.h:60
@ fatalError
Fatal error.
Definition vpException.h:72
static void create(vpFeaturePoint &s, const vpCameraParameters &cam, const vpDot &d)
Implementation of an homogeneous matrix and operations on such kind of matrices.
void extract(vpRotationMatrix &R) const
Definition of the vpImage class member functions.
Definition vpImage.h:131
static double rad(double deg)
Definition vpMath.h:129
Implementation of a matrix and operations on matrices.
Definition vpMatrix.h:175
Performs search in a given direction(normal) for a given distance(pixels) for a given 'site'....
Definition vpMeSite.h:75
@ THRESHOLD
Point not tracked due to the likelihood that is below the threshold, but retained in the ME list.
Definition vpMeSite.h:98
@ NO_SUPPRESSION
Point successfully tracked.
Definition vpMeSite.h:93
vpMeSiteState getState() const
Definition vpMeSite.h:306
int m_j
Integer coordinates along j of a site.
Definition vpMeSite.h:108
int m_i
Integer coordinate along i of a site.
Definition vpMeSite.h:106
Definition vpMe.h:143
This class defines the container for a plane geometrical structure.
Definition vpPlane.h:56
vpPlane & init(const vpPoint &P, const vpColVector &normal, const vpPlaneFrame &frame=camera_frame)
Definition vpPlane.cpp:159
@ object_frame
Definition vpPlane.h:64
double getD() const
Definition vpPlane.h:106
double getA() const
Definition vpPlane.h:100
double getC() const
Definition vpPlane.h:104
double getB() const
Definition vpPlane.h:102
Class that defines a 3D point in the object frame and allows forward projection of a 3D point in the ...
Definition vpPoint.h:79
void buildSilhouettePoint(int n, int m, const double &Z, double orient, const vpColVector &normo, const vpHomogeneousMatrix &cMo, const vpHomogeneousMatrix &oMc, const vpCameraParameters &cam)
double getMaxMaskGradientAlongLine(const vpImage< float > &mask, int searchSize) const
vpRBSilhouetteControlPoint & operator=(const vpRBSilhouetteControlPoint &meTracker)
void trackMultipleHypotheses(const vpImage< unsigned char > &I)
Track the moving edge and retain the best numCandidates hypotheses.
void computeMeInteractionMatrixError(const vpHomogeneousMatrix &cMo, unsigned int i, vpMatrix &L, vpColVector &e)
void track(const vpImage< unsigned char > &I)
Track the moving edge at this point retaining only the hypothesis with the highest likelihood.
bool tooCloseToBorder(unsigned int h, unsigned int w, int searchSize) const
void initControlPoint(const vpImage< unsigned char > &I, double cvlt)
void update(const vpHomogeneousMatrix &_cMo)
void updateSilhouettePoint(const vpHomogeneousMatrix &_cMo, const vpRotationMatrix &cRo)
void buildPoint(int n, int m, const double &Z, double orient, const vpColVector &normo, const vpHomogeneousMatrix &cMo, const vpHomogeneousMatrix &oMc, const vpCameraParameters &cam, const vpMe &me, bool isSilhouette)
void computeMeInteractionMatrixErrorMH(const vpHomogeneousMatrix &cMo, unsigned int i, vpMatrix &L, vpColVector &e)
Implementation of a rotation matrix and operations on such kind of matrices.
vpColVector cP
Definition vpTracker.h:73
Error that can be emitted by the vpTracker class and its derivatives.
#define vpERROR_TRACE
Definition vpDebug.h:423