34 #include <visp3/core/vpConfig.h>
35 #ifndef DOXYGEN_SHOULD_SKIP_THIS
45 #include <visp3/core/vpDebug.h>
46 #include <visp3/core/vpRobust.h>
47 #include <visp3/core/vpTrackingException.h>
48 #include <visp3/mbt/vpMbtMeLine.h>
52 static void normalizeAngle(
double &delta)
54 while (delta > M_PI) {
57 while (delta < -M_PI) {
65 vpMbtMeLine::vpMbtMeLine()
66 : m_rho(0.), m_theta(0.), m_theta_1(M_PI / 2), m_delta(0.), m_delta_1(0), m_sign(1), m_a(0.), m_b(0.), m_c(0.),
67 imin(0), imax(0), jmin(0), jmax(0), expecteddensity(0.)
73 vpMbtMeLine::~vpMbtMeLine()
94 double rho,
double theta,
bool doNoTrack)
96 vpCDEBUG(1) <<
" begin vpMeLine::initTracking()" << std::endl;
101 m_PExt[0].m_ifloat = (float)ip1.
get_i();
102 m_PExt[0].m_jfloat = (float)ip1.
get_j();
103 m_PExt[1].m_ifloat = (float)ip2.
get_i();
104 m_PExt[1].m_jfloat = (float)ip2.
get_j();
114 m_delta = -m_theta + M_PI / 2.0;
115 normalizeAngle(m_delta);
118 sample(I, doNoTrack);
119 expecteddensity = (double)m_meList.size();
127 vpCDEBUG(1) <<
" end vpMeLine::initTracking()" << std::endl;
139 int nbrows =
static_cast<int>(I.
getHeight());
140 int nbcols =
static_cast<int>(I.
getWidth());
143 if (std::fabs(m_me->getSampleStep()) <= std::numeric_limits<double>::epsilon()) {
145 "moving-edges sample step = 0"));
149 double diffsi = m_PExt[0].m_ifloat - m_PExt[1].m_ifloat;
150 double diffsj = m_PExt[0].m_jfloat - m_PExt[1].m_jfloat;
155 n_sample = length_p / (double)m_me->getSampleStep();
157 double stepi = diffsi / (double)n_sample;
158 double stepj = diffsj / (double)n_sample;
161 double is = m_PExt[1].m_ifloat;
162 double js = m_PExt[1].m_jfloat;
175 if (!outOfImage(iP, (
int)(m_me->getRange() + m_me->getMaskSize() + 1), nbrows, nbcols)) {
176 unsigned int is_uint =
static_cast<unsigned int>(is);
177 unsigned int js_uint =
static_cast<unsigned int>(js);
178 if (inRoiMask(m_mask, is_uint, js_uint) && inMeMaskCandidates(m_maskCandidates, is_uint, js_uint)) {
183 const double marginRatio = m_me->getThresholdMarginRatio();
185 double contrastThreshold = fabs(convolution) * marginRatio;
189 pix.
track(I, m_me,
false);
192 if (vpDEBUG_ENABLE(3)) {
196 m_meList.push_back(pix);
203 vpCDEBUG(1) <<
"end vpMeLine::sample() : ";
204 vpCDEBUG(1) << m_meList.size() <<
" point inserted in the list " << std::endl;
214 for (std::list<vpMeSite>::iterator it = m_meList.begin(); it != m_meList.end();) {
217 if (fabs(sin(m_theta)) > 0.9)
219 if ((s.
m_i < imin) || (s.
m_i > imax)) {
224 else if (fabs(cos(m_theta)) > 0.9)
226 if ((s.
m_j < jmin) || (s.
m_j > jmax)) {
232 if ((s.
m_i < imin) || (s.
m_i > imax) || (s.
m_j < jmin) || (s.
m_j > jmax)) {
237 if (outOfImage(s.
m_i, s.
m_j, (
int)(m_me->getRange() + m_me->getMaskSize() + 1), (
int)I.
getHeight(), (
int)I.
getWidth())) {
242 it = m_meList.erase(it);
256 vpCDEBUG(1) <<
"begin vpMeLine::sample() : " << std::endl;
263 if (std::fabs(m_me->getSampleStep()) <= std::numeric_limits<double>::epsilon()) {
268 double diffsi = m_PExt[0].m_ifloat - m_PExt[1].m_ifloat;
269 double diffsj = m_PExt[0].m_jfloat - m_PExt[1].m_jfloat;
273 double di = diffsi / sqrt(s);
274 double dj = diffsj / sqrt(s);
276 double length_p = sqrt(s);
279 n_sample = length_p / (double)m_me->getSampleStep();
280 double sample_step = (double)m_me->getSampleStep();
283 P.
init((
int)m_PExt[0].m_ifloat, (int)m_PExt[0].m_jfloat, m_delta_1, 0, m_sign);
286 unsigned int memory_range = m_me->getRange();
289 for (
int i = 0; i < 3; i++) {
295 if ((P.
m_i < imin) || (P.
m_i > imax) || (P.
m_j < jmin) || (P.
m_j > jmax)) {
296 if (vpDEBUG_ENABLE(3))
299 else if (!outOfImage(P.
m_i, P.
m_j, (
int)(m_me->getRange() + m_me->getMaskSize() + 1), (
int)rows, (int)cols)) {
300 P.
track(I, m_me,
false);
303 m_meList.push_back(P);
304 if (vpDEBUG_ENABLE(3))
307 else if (vpDEBUG_ENABLE(3))
312 P.
init((
int)m_PExt[1].m_ifloat, (int)m_PExt[1].m_jfloat, m_delta_1, 0, m_sign);
314 for (
int i = 0; i < 3; i++) {
320 if ((P.
m_i < imin) || (P.
m_i > imax) || (P.
m_j < jmin) || (P.
m_j > jmax)) {
321 if (vpDEBUG_ENABLE(3))
325 else if (!outOfImage(P.
m_i, P.
m_j, (
int)(m_me->getRange() + m_me->getMaskSize() + 1), (
int)rows, (int)cols)) {
326 P.
track(I, m_me,
false);
329 m_meList.push_back(P);
330 if (vpDEBUG_ENABLE(3))
333 else if (vpDEBUG_ENABLE(3))
338 m_me->setRange(memory_range);
340 vpCDEBUG(1) <<
"end vpMeLine::sample() : ";
341 vpCDEBUG(1) << n_sample <<
" point inserted in the list " << std::endl;
360 bool display,
unsigned int length,
unsigned int thickness)
364 double deltaNormalized = m_theta;
365 unsigned int iter = 0;
367 while (deltaNormalized < 0) {
368 deltaNormalized += M_PI;
370 while (deltaNormalized > M_PI) {
371 deltaNormalized -= M_PI;
375 vecLine[0] = cos(deltaNormalized);
376 vecLine[1] = sin(deltaNormalized);
379 double offset = std::floor(SobelX.
getRows() / 2.0f);
381 for (std::list<vpMeSite>::const_iterator it = m_meList.begin(); it != m_meList.end(); ++it) {
382 if (iter != 0 && iter + 1 != m_meList.size()) {
383 double gradientX = 0;
384 double gradientY = 0;
386 double iSite = it->m_ifloat;
387 double jSite = it->m_jfloat;
389 for (
unsigned int i = 0; i < SobelX.
getRows(); i++) {
390 double iImg = iSite + (i - offset);
391 for (
unsigned int j = 0; j < SobelX.
getCols(); j++) {
392 double jImg = jSite + (j - offset);
404 gradientX += SobelX[i][j] * _I((
unsigned int)iImg, (
unsigned int)jImg);
408 for (
unsigned int i = 0; i < SobelY.
getRows(); i++) {
409 double iImg = iSite + (i - offset);
410 for (
unsigned int j = 0; j < SobelY.
getCols(); j++) {
411 double jImg = jSite + (j - offset);
423 gradientY += SobelY[i][j] * _I((
unsigned int)iImg, (
unsigned int)jImg);
427 double angle = atan2(gradientX, gradientY);
434 vecGrad[0] = cos(angle);
435 vecGrad[1] = sin(angle);
438 double angle1 = acos(vecLine * vecGrad);
439 double angle2 = acos(vecLine * (-vecGrad));
443 (
int)(it->get_j() + length * sin(deltaNormalized)),
vpColor::blue,
444 length >= 20 ? length / 5 : 4, length >= 20 ? length / 10 : 2, thickness);
445 if (angle1 < angle2) {
447 (
int)(it->get_j() + length * sin(angle)),
vpColor::red, length >= 20 ? length / 5 : 4,
448 length >= 20 ? length / 10 : 2, thickness);
452 (
int)(it->get_j() + length * sin(angle + M_PI)),
vpColor::red,
453 length >= 20 ? length / 5 : 4, length >= 20 ? length / 10 : 2, thickness);
457 _sumErrorRad += std::min<double>(angle1, angle2);
477 unsigned int n = numberOfSignal();
479 if ((
double)n < 0.5 * expecteddensity && n > 0) {
480 double delta_new = m_delta;
483 expecteddensity = (double)m_meList.size();
504 size_t n = m_meList.size();
506 if ((
double)n < 0.5 * expecteddensity /*&& n > 0*/)
508 double delta_new = m_delta;
510 m_PExt[0].m_ifloat = (float)ip1.
get_i();
511 m_PExt[0].m_jfloat = (float)ip1.
get_j();
512 m_PExt[1].m_ifloat = (float)ip2.
get_i();
513 m_PExt[1].m_jfloat = (float)ip2.
get_j();
515 expecteddensity = (double)m_meList.size();
524 void vpMbtMeLine::updateDelta()
531 if (std::fabs(std::fabs(m_theta) - M_PI) <=
532 vpMath::maximum(std::fabs(m_theta), (
double)M_PI) * std::numeric_limits<double>::epsilon()) {
536 diff = fabs(m_theta - m_theta_1);
537 if (diff > M_PI / 2.0) {
543 m_delta = -m_theta + M_PI / 2.0;
544 normalizeAngle(m_delta);
546 for (std::list<vpMeSite>::iterator it = m_meList.begin(); it != m_meList.end(); ++it) {
564 if (m_mask !=
nullptr) {
566 expecteddensity = (double)m_meList.size();
613 double rho,
double theta)
627 reSample(I, ip1, ip2);
636 void vpMbtMeLine::setExtremities()
644 for (std::list<vpMeSite>::const_iterator it = m_meList.begin(); it != m_meList.end(); ++it) {
657 if (!m_meList.empty()) {
658 m_PExt[0].m_ifloat = i_min;
659 m_PExt[0].m_jfloat = j_min;
660 m_PExt[1].m_ifloat = i_max;
661 m_PExt[1].m_jfloat = j_max;
664 if (fabs(i_min - i_max) < 25) {
665 for (std::list<vpMeSite>::const_iterator it = m_meList.begin(); it != m_meList.end(); ++it) {
678 if (!m_meList.empty()) {
679 m_PExt[0].m_ifloat = i_min;
680 m_PExt[0].m_jfloat = j_min;
681 m_PExt[1].m_ifloat = i_max;
682 m_PExt[1].m_jfloat = j_max;
693 void vpMbtMeLine::bubbleSortI()
696 unsigned int nbElmt = m_meList.size();
697 for (
unsigned int pass = 1; pass < nbElmt; pass++) {
699 for (
unsigned int i = 0; i < nbElmt-pass; i++) {
703 m_meList.swapRight();
709 m_meList.sort(sortByI);
714 void vpMbtMeLine::bubbleSortJ()
717 unsigned int nbElmt = m_meList.size();
718 for (
unsigned int pass = 1; pass < nbElmt; pass++) {
720 for (
unsigned int i = 0; i < nbElmt-pass; i++) {
724 m_meList.swapRight();
730 m_meList.sort(sortByJ);
unsigned int getCols() const
unsigned int getRows() const
Implementation of column vector and the associated operations.
static const vpColor cyan
static const vpColor blue
static const vpColor green
static void displayCross(const vpImage< unsigned char > &I, const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)
static void displayArrow(const vpImage< unsigned char > &I, const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color=vpColor::white, unsigned int w=4, unsigned int h=2, unsigned int thickness=1)
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
unsigned int getWidth() const
unsigned int getHeight() const
static Type maximum(const Type &a, const Type &b)
static double sqr(double x)
static int round(double x)
Implementation of a matrix and operations on matrices.
Performs search in a given direction(normal) for a given distance(pixels) for a given 'site'....
int m_mask_sign
Mask sign.
@ TOO_NEAR
Point not tracked anymore, since too near from its neighbor.
@ CONTRAST
Point not tracked due to a contrast problem, but retained in the ME list.
@ NO_SUPPRESSION
Point successfully tracked.
void setDisplay(vpMeSiteDisplayType select)
double m_ifloat
Subpixel coordinates along i of a site.
double convolution(const vpImage< unsigned char > &ima, const vpMe *me)
double m_alpha
Angle of tangent at site.
vpMeSiteState getState() const
int m_j
Integer coordinates along j of a site.
int m_i
Integer coordinate along i of a site.
double m_jfloat
Subpixel coordinates along j of a site.
void setContrastThreshold(const double &thresh, const vpMe &me)
void track(const vpImage< unsigned char > &I, const vpMe *me, const bool &test_contrast=true)
void setState(const vpMeSiteState &flag)
void initTracking(const vpImage< unsigned char > &I)
void track(const vpImage< unsigned char > &I)
Error that can be emitted by the vpTracker class and its derivatives.
@ fatalError
Tracker fatal error.