Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpMeNurbs.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2025 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 * Description:
31 * Moving edges.
32 */
33
38
39#include <cmath> // std::fabs
40#include <limits> // numeric_limits
41#include <stdlib.h>
42#include <visp3/core/vpImageConvert.h>
43#include <visp3/core/vpImageFilter.h>
44#include <visp3/core/vpImagePoint.h>
45#include <visp3/core/vpImageTools.h>
46#include <visp3/core/vpMath.h>
47#include <visp3/core/vpRect.h>
48#include <visp3/core/vpRobust.h>
49#include <visp3/core/vpTrackingException.h>
50#include <visp3/me/vpMe.h>
51#include <visp3/me/vpMeNurbs.h>
52#include <visp3/me/vpMeSite.h>
53#include <visp3/me/vpMeTracker.h>
54#if defined(HAVE_OPENCV_IMGPROC)
55#include <opencv2/imgproc/imgproc.hpp>
56#if (VISP_HAVE_OPENCV_VERSION < 0x050000)
57#include <opencv2/imgproc/imgproc_c.h>
58#endif
59#endif
60
62double computeDelta(double deltai, double deltaj);
63void findAngle(const vpImage<unsigned char> &I, const vpImagePoint &iP, vpMe *me, double &angle, double &convlt);
64vpImagePoint findFirstBorder(const vpImage<unsigned char> &Isub, const vpImagePoint &iP);
65bool findCenterPoint(std::list<vpImagePoint> *ip_edges_list);
66
67// Compute the angle delta = arctan(deltai/deltaj)
68// and normalize it between 0 and pi
69double computeDelta(double deltai, double deltaj)
70{
71 double delta;
72 delta = atan2(deltai, deltaj);
73 delta -= M_PI / 2.0;
74 while (delta > M_PI) {
75 delta -= M_PI;
76 }
77 while (delta < 0) {
78 delta += M_PI;
79 }
80 return (delta);
81}
82
83// Check if the image point is in the image and not to close to
84// its edge to enable the computation of a convolution with a mask.
85static bool outOfImage(const vpImagePoint &iP, int half, int rows, int cols)
86{
87 return ((iP.get_i() < half + 1) || (iP.get_i() > (rows - half - 3)) || (iP.get_j() < half + 1) ||
88 (iP.get_j() > (cols - half - 3)));
89}
90
91// if iP is a edge point, it computes the angle corresponding to the
92// highest convolution result. the angle is between 0 an 179.
93// The result gives the angle in RADIAN + pi/2 (to deal with the moving edeg
94// alpha angle) and the corresponding convolution result.
95void findAngle(const vpImage<unsigned char> &I, const vpImagePoint &iP, vpMe *me, double &angle, double &convlt)
96{
97 int Iheight = static_cast<int>(I.getHeight());
98 int Iwidth = static_cast<int>(I.getWidth());
99 angle = 0.0;
100 convlt = 0.0;
101 for (int i = 0; i < 180; i++) {
102 double conv = 0.0;
103 unsigned int half;
104 half = (me->getMaskSize() - 1) >> 1;
105
106 if (outOfImage(iP, static_cast<int>(half) + me->getStrip(), Iheight, Iwidth)) {
107 conv = 0.0;
108 }
109 else {
110 int index_mask;
111
112 if (me->getAngleStep() != 0)
113 index_mask = static_cast<int>(i / static_cast<double>(me->getAngleStep()));
114 else
115 throw(vpException(vpException::divideByZeroError, "angle step = 0"));
116
117 unsigned int ihalf = static_cast<unsigned int>(iP.get_i() - half);
118 unsigned int jhalf = static_cast<unsigned int>(iP.get_j() - half);
119 unsigned int a;
120 unsigned int b;
121 for (a = 0; a < me->getMaskSize(); a++) {
122 unsigned int ihalfa = ihalf + a;
123 for (b = 0; b < me->getMaskSize(); b++) {
124 conv += me->getMask()[index_mask][a][b] * I(ihalfa, jhalf + b);
125 }
126 }
127 }
128 conv = fabs(conv);
129 if (conv > convlt) {
130 convlt = conv;
131 angle = vpMath::rad(i);
132 angle += M_PI / 2;
133 while (angle > M_PI) {
134 angle -= M_PI;
135 }
136 while (angle < 0) {
137 angle += M_PI;
138 }
139 }
140 }
141}
142
143// Find the point belonging to the edge of the sub image which respects the
144// following hypotheses:
145//- the value of the pixel is upper than zero.
146//- the distantce between the point and iP is less than 4 pixels.
147// The function returns the nearest point of iP which respect the hypotheses
148// If no point is found the returned point is (-1,-1)
149vpImagePoint findFirstBorder(const vpImage<unsigned char> &Isub, const vpImagePoint &iP)
150{
151 double dist = 1e6;
152 double dist_1 = 1e6;
153 vpImagePoint index(-1, -1);
154 for (unsigned int i = 0; i <= Isub.getHeight(); i++) {
155 for (unsigned int j = 0; j <= Isub.getWidth(); j++) {
156 if (i == 0 || i == Isub.getHeight() - 1 || j == 0 || j == Isub.getWidth() - 1) {
157 if (Isub(i, j) > 0) {
159 if (dist <= 16 && dist < dist_1) {
160 dist_1 = dist;
161 index.set_ij(i, j);
162 }
163 }
164 }
165 }
166 }
167 return index;
168}
169
170// Check if the list of vpImagePoint contains a distant point of less tha 4
171// pixels from the center of the sub image (ie the point (15,15).
172bool findCenterPoint(std::list<vpImagePoint> *ip_edges_list)
173{
174 for (std::list<vpImagePoint>::const_iterator it = ip_edges_list->begin(); it != ip_edges_list->end(); ++it) {
175 vpImagePoint iP = *it;
176 double dist = vpImagePoint::sqrDistance(iP, vpImagePoint(15, 15));
177 if (dist <= 16) {
178 return true;
179 }
180 }
181 return false;
182}
183
184/***************************************/
185
187 : nurbs(), dist(0.), nbControlPoints(20), beginPtFound(0), endPtFound(0), enableCannyDetection(false), cannyTh1(100.),
188 cannyTh2(200.)
189{ }
190
192 : vpMeTracker(menurbs), nurbs(menurbs.nurbs), dist(0.), nbControlPoints(20), beginPtFound(0), endPtFound(0),
193 enableCannyDetection(false), cannyTh1(100.f), cannyTh2(200.f)
194{
195 dist = menurbs.dist;
196 nbControlPoints = menurbs.nbControlPoints;
197 beginPtFound = menurbs.beginPtFound;
198 endPtFound = menurbs.endPtFound;
199 enableCannyDetection = menurbs.enableCannyDetection;
200 cannyTh1 = menurbs.cannyTh1;
201 cannyTh2 = menurbs.cannyTh2;
202}
203
205{
206 std::list<vpImagePoint> ptList;
207 vpImagePoint pt;
209
210 while (vpDisplay::getClick(I, pt, b)) {
211 if (b == vpMouseButton::button1) {
212 // std::cout<<pt<<std::endl;
213 ptList.push_back(pt);
216 }
217 if (b == vpMouseButton::button3)
218 break;
219 }
220 if (ptList.size() > 3)
221 initTracking(I, ptList);
222 else
223 throw(vpException(vpException::notInitialized, "Not enough points to initialize the Nurbs"));
224}
225
226void vpMeNurbs::initTracking(const vpImage<unsigned char> &I, const std::list<vpImagePoint> &ptList)
227{
228 nurbs.globalCurveInterp(ptList);
229
230 sample(I);
231
233 track(I);
234}
235
236void vpMeNurbs::sample(const vpImage<unsigned char> &I, bool doNotTrack)
237{
238 (void)doNotTrack;
239 int rows = static_cast<int>(I.getHeight());
240 int cols = static_cast<int>(I.getWidth());
241 double step = 1.0 / static_cast<double>(m_me->getPointsToTrack());
242
243 // Delete old list
244 m_meList.clear();
245
246 double u = 0.0;
247 vpImagePoint *pt = nullptr;
248 vpImagePoint pt_1(-rows, -cols);
249 while (u <= 1.0) {
250 if (pt != nullptr)
251 delete[] pt;
252 pt = nurbs.computeCurveDersPoint(u, 1);
253 double delta = computeDelta(pt[1].get_i(), pt[1].get_j());
254
255 // If point is in the image, add to the sample list
256 if (!outOfImage(pt[0], 0, rows, cols) &&
257 vpImagePoint::sqrDistance(pt[0], pt_1) >= vpMath::sqr(m_me->getSampleStep())) {
258 vpMeSite pix;
259 pix.init(pt[0].get_i(), pt[0].get_j(), delta);
261
262 m_meList.push_back(pix);
263 pt_1 = pt[0];
264 }
265 u = u + step;
266 }
267 if (pt != nullptr)
268 delete[] pt;
269}
270
272{
273 for (std::list<vpMeSite>::iterator it = m_meList.begin(); it != m_meList.end();) {
274 vpMeSite s = *it; // current reference pixel
275
276 if (s.getState() != vpMeSite::NO_SUPPRESSION) {
277 it = m_meList.erase(it);
278 }
279 else
280 ++it;
281 }
282}
283
285{
286 double u = 0.0;
287 double d = 1e6;
288 double d_1 = 1e6;
289 std::list<vpMeSite>::iterator it = m_meList.begin();
290
291 vpImagePoint Cu;
292 vpImagePoint *der = nullptr;
293 double step = 0.01;
294 while (u < 1 && it != m_meList.end()) {
295 vpMeSite s = *it;
296 vpImagePoint pt(s.get_i(), s.get_j());
297 while (d <= d_1 && u < 1) {
298 Cu = nurbs.computeCurvePoint(u);
299 d_1 = d;
300 d = vpImagePoint::distance(pt, Cu);
301 u += step;
302 }
303
304 u -= step;
305 if (der != nullptr)
306 delete[] der;
307 der = nurbs.computeCurveDersPoint(u, 1);
308 // vpImagePoint toto(der[0].get_i(),der[0].get_j());
309 // vpDisplay::displayCross(I,toto,4,vpColor::red);
310
311 s.setAlpha(computeDelta(der[1].get_i(), der[1].get_j()));
312 *it = s;
313 ++it;
314 d = 1e6;
315 d_1 = 1.5e6;
316 }
317 if (der != nullptr)
318 delete[] der;
319}
320
322{
323 int rows = static_cast<int>(I.getHeight());
324 int cols = static_cast<int>(I.getWidth());
325
326 vpImagePoint *begin = nullptr;
327 vpImagePoint *end = nullptr;
328
329 begin = nurbs.computeCurveDersPoint(0.0, 1);
330 end = nurbs.computeCurveDersPoint(1.0, 1);
331
332 // Check if the two extremities are not to close to eachother.
333 double d = vpImagePoint::distance(begin[0], end[0]);
334 double threshold = 3 * m_me->getSampleStep();
335 double sample_step = m_me->getSampleStep();
336 vpImagePoint pt;
337 if (d > threshold /*|| (m_meList.firstValue()).m_mask_sign != (m_meList.lastValue()).m_mask_sign*/) {
338 vpMeSite P;
339
340 // Init vpMeSite
341 P.init(begin[0].get_i(), begin[0].get_j(), (m_meList.front()).getAlpha(), 0, (m_meList.front()).m_mask_sign);
343
344 // Set the range
345 unsigned int memory_range = m_me->getRange();
346 m_me->setRange(2);
347
348 // Point at the beginning of the list
349 bool beginPtAdded = false;
350 vpImagePoint pt_max = begin[0];
351 double angle = atan2(begin[1].get_i(), begin[1].get_j());
352 double co = vpMath::abs(cos(angle));
353 co = co * vpMath::sign(begin[1].get_j());
354 double si = vpMath::abs(sin(angle));
355 si = si * vpMath::sign(begin[1].get_i());
356 for (int i = 0; i < 3; i++) {
357 P.m_ifloat = P.m_ifloat - si * sample_step;
358 P.m_i = static_cast<int>(P.m_ifloat);
359 P.m_jfloat = P.m_jfloat - co * sample_step;
360 P.m_j = static_cast<int>(P.m_jfloat);
361 pt.set_ij(P.m_ifloat, P.m_jfloat);
362 if (vpImagePoint::distance(end[0], pt) < threshold)
363 break;
364 if (!outOfImage(P.get_i(), P.get_j(), 5, rows, cols)) {
365 P.track(I, m_me, false);
366
368 m_meList.push_front(P);
369 beginPtAdded = true;
370 pt_max = pt;
371 if (vpDEBUG_ENABLE(3)) {
373 }
374 }
375 else {
376 if (vpDEBUG_ENABLE(3)) {
378 }
379 }
380 }
381 }
382
383 if (!beginPtAdded)
384 beginPtFound++;
385
386 P.init(end[0].get_i(), end[0].get_j(), (m_meList.back()).getAlpha(), 0, (m_meList.back()).m_mask_sign);
388
389 bool endPtAdded = false;
390 angle = atan2(end[1].get_i(), end[1].get_j());
391 co = vpMath::abs(cos(angle));
392 co = co * vpMath::sign(end[1].get_j());
393 si = vpMath::abs(sin(angle));
394 si = si * vpMath::sign(end[1].get_i());
395 for (int i = 0; i < 3; i++) {
396 P.m_ifloat = P.m_ifloat + si * sample_step;
397 P.m_i = static_cast<int>(P.m_ifloat);
398 P.m_jfloat = P.m_jfloat + co * sample_step;
399 P.m_j = static_cast<int>(P.m_jfloat);
400 pt.set_ij(P.m_ifloat, P.m_jfloat);
401 if (vpImagePoint::distance(begin[0], pt) < threshold)
402 break;
403 if (!outOfImage(P.get_i(), P.get_j(), 5, rows, cols)) {
404 P.track(I, m_me, false);
405
407 m_meList.push_back(P);
408 endPtAdded = true;
409 if (vpDEBUG_ENABLE(3)) {
411 }
412 }
413 else {
414 if (vpDEBUG_ENABLE(3)) {
416 }
417 }
418 }
419 }
420 if (!endPtAdded)
421 endPtFound++;
422 m_me->setRange(memory_range);
423 }
424 else {
425 m_meList.pop_front();
426 }
427 /*if(begin != nullptr)*/ delete[] begin;
428 /*if(end != nullptr) */ delete[] end;
429}
430
432{
433 vpMeSite pt = m_meList.front();
434 vpImagePoint firstPoint(pt.m_ifloat, pt.m_jfloat);
435 pt = m_meList.back();
436 vpImagePoint lastPoint(pt.m_ifloat, pt.m_jfloat);
437 if (beginPtFound >= 3 && farFromImageEdge(I, firstPoint)) {
438 vpImagePoint *begin = nullptr;
439 begin = nurbs.computeCurveDersPoint(0.0, 1);
440 vpImage<unsigned char> Isub(32, 32); // Sub image.
441 vpImagePoint topLeft(begin[0].get_i() - 15, begin[0].get_j() - 15);
442 vpRect rect(topLeft, 32, 32);
443
445
446 vpImageTools::crop(I, rect, Isub);
447
448 vpImagePoint lastPtInSubIm(begin[0]);
449 double u = 0.0;
450 double step = 0.0001;
451 // Find the point of the nurbs closest from the edge of the subImage and
452 // in the subImage.
453 while (inRectangle(lastPtInSubIm, rect) && u < 1) {
454 u += step;
455 lastPtInSubIm = nurbs.computeCurvePoint(u);
456 }
457
458 u -= step;
459 if (u > 0)
460 lastPtInSubIm = nurbs.computeCurvePoint(u);
461
462 vpImageFilter::canny(Isub, Isub, 3, cannyTh1, 3);
463
464 vpImagePoint firstBorder(-1, -1);
465
466 firstBorder = findFirstBorder(Isub, lastPtInSubIm - topLeft);
467
468 std::list<vpImagePoint> ip_edges_list;
469 if (firstBorder != vpImagePoint(-1, -1)) {
470 unsigned int dir;
471 double fi = static_cast<double>(firstBorder.get_i());
472 double fj = static_cast<double>(firstBorder.get_j());
473 double w = Isub.getWidth() - 1;
474 double h = Isub.getHeight() - 1;
475 // if (firstBorder.get_i() == 0) dir = 4;
476 if (std::fabs(fi) <= std::numeric_limits<double>::epsilon())
477 dir = 4;
478 // else if (firstBorder.get_i() == Isub.getHeight()-1) dir = 0;
479 else if (std::fabs(fi - h) <= std::fabs(vpMath::maximum(fi, h)) * std::numeric_limits<double>::epsilon())
480 dir = 0;
481 // else if (firstBorder.get_j() == 0) dir = 2;
482 else if (std::fabs(fj) <= std::numeric_limits<double>::epsilon())
483 dir = 2;
484 // else if (firstBorder.get_j() == Isub.getWidth()-1) dir = 6;
485 else if (std::fabs(fj - w) <= std::fabs(vpMath::maximum(fj, w)) * std::numeric_limits<double>::epsilon())
486 dir = 6;
487 computeFreemanChainElement(Isub, firstBorder, dir);
488 unsigned int firstDir = dir;
489 ip_edges_list.push_back(firstBorder);
490 vpImagePoint border(firstBorder);
491 vpImagePoint dBorder;
492 do {
493 computeFreemanParameters(dir, dBorder);
494 border = border + dBorder;
495 vpDisplay::displayPoint(I, border + topLeft, vpColor::orange);
496
497 ip_edges_list.push_back(border);
498
499 computeFreemanChainElement(Isub, border, dir);
500 } while ((border != firstBorder || dir != firstDir) && isInImage(Isub, border));
501 }
502
503 if (findCenterPoint(&ip_edges_list)) {
504 for (std::list<vpMeSite>::iterator it = m_meList.begin(); it != m_meList.end();
505 /*++it*/) {
506 vpMeSite s = *it;
507 vpImagePoint iP(s.m_ifloat, s.m_jfloat);
508 if (inRectangle(iP, rect))
509 it = m_meList.erase(it);
510 else
511 break;
512 }
513
514 std::list<vpMeSite>::iterator itList = m_meList.begin();
515 double convlt;
516 double delta = 0;
517 unsigned int nbr = 0;
518 std::list<vpMeSite> addedPt;
519 for (std::list<vpImagePoint>::const_iterator itEdges = ip_edges_list.begin(); itEdges != ip_edges_list.end();
520 ++itEdges) {
521 vpMeSite s = *itList;
522 vpImagePoint iPtemp = *itEdges + topLeft;
523 vpMeSite pix;
524 pix.init(iPtemp.get_i(), iPtemp.get_j(), delta);
525 dist = vpMeSite::sqrDistance(s, pix);
526 if (dist >= vpMath::sqr(m_me->getSampleStep()) /*25*/) {
527 bool exist = false;
528 for (std::list<vpMeSite>::const_iterator itAdd = addedPt.begin(); itAdd != addedPt.end(); ++itAdd) {
529 dist = vpMeSite::sqrDistance(pix, *itAdd);
530 if (dist < vpMath::sqr(m_me->getSampleStep()) /*25*/)
531 exist = true;
532 }
533 if (!exist) {
534 findAngle(I, iPtemp, m_me, delta, convlt);
535 pix.init(iPtemp.get_i(), iPtemp.get_j(), delta, convlt);
537 --itList;
538 m_meList.insert(itList, pix);
539 ++itList;
540 addedPt.push_front(pix);
541 nbr++;
542 }
543 }
544 }
545
546 unsigned int memory_range = m_me->getRange();
547 m_me->setRange(3);
548 std::list<vpMeSite>::iterator itList2 = m_meList.begin();
549 for (unsigned int j = 0; j < nbr; j++) {
550 vpMeSite s = *itList2;
551 s.track(I, m_me, false);
552 *itList2 = s;
553 ++itList2;
554 }
555 m_me->setRange(memory_range);
556 }
557
558 /* if (begin != nullptr) */ delete[] begin;
559 beginPtFound = 0;
560 }
561
562 if (endPtFound >= 3 && farFromImageEdge(I, lastPoint)) {
563 vpImagePoint *end = nullptr;
564 end = nurbs.computeCurveDersPoint(1.0, 1);
565
566 vpImage<unsigned char> Isub(32, 32); // Sub image.
567 vpImagePoint topLeft(end[0].get_i() - 15, end[0].get_j() - 15);
568 vpRect rect(topLeft, 32, 32);
569
571
572 vpImageTools::crop(I, rect, Isub);
573
574 vpImagePoint lastPtInSubIm(end[0]);
575 double u = 1.0;
576 double step = 0.0001;
577 // Find the point of the nurbs closest from the edge of the subImage and
578 // in the subImage.
579 while (inRectangle(lastPtInSubIm, rect) && u > 0) {
580 u -= step;
581 lastPtInSubIm = nurbs.computeCurvePoint(u);
582 }
583
584 u += step;
585 if (u < 1.0)
586 lastPtInSubIm = nurbs.computeCurvePoint(u);
587
588 vpImageFilter::canny(Isub, Isub, 3, cannyTh1, 3);
589
590 vpImagePoint firstBorder(-1, -1);
591
592 firstBorder = findFirstBorder(Isub, lastPtInSubIm - topLeft);
593
594 std::list<vpImagePoint> ip_edges_list;
595 if (firstBorder != vpImagePoint(-1, -1)) {
596 unsigned int dir;
597 double fi = firstBorder.get_i();
598 double fj = firstBorder.get_j();
599 double w = Isub.getWidth() - 1;
600 double h = Isub.getHeight() - 1;
601 // if (firstBorder.get_i() == 0) dir = 4;
602 if (std::fabs(fi) <= std::numeric_limits<double>::epsilon())
603 dir = 4;
604 // else if (firstBorder.get_i() == Isub.getHeight()-1) dir = 0;
605 else if (std::fabs(fi - h) <= std::fabs(vpMath::maximum(fi, h)) * std::numeric_limits<double>::epsilon())
606 dir = 0;
607 // else if (firstBorder.get_j() == 0) dir = 2;
608 else if (std::fabs(fj) <= std::numeric_limits<double>::epsilon())
609 dir = 2;
610 // else if (firstBorder.get_j() == Isub.getWidth()-1) dir = 6;
611 else if (std::fabs(fj - w) <= std::fabs(vpMath::maximum(fj, w)) * std::numeric_limits<double>::epsilon())
612 dir = 6;
613
614 computeFreemanChainElement(Isub, firstBorder, dir);
615 unsigned int firstDir = dir;
616 ip_edges_list.push_back(firstBorder);
617 vpImagePoint border(firstBorder);
618 vpImagePoint dBorder;
619 do {
620 computeFreemanParameters(dir, dBorder);
621 border = border + dBorder;
622 vpDisplay::displayPoint(I, border + topLeft, vpColor::orange);
623
624 ip_edges_list.push_back(border);
625
626 computeFreemanChainElement(Isub, border, dir);
627 } while ((border != firstBorder || dir != firstDir) && isInImage(Isub, border));
628 }
629
630 if (findCenterPoint(&ip_edges_list)) {
631 vpMeSite s;
632
633 for (std::list<vpMeSite>::iterator it = m_meList.begin(); it!=m_meList.end(); ++it) {
634 s = *it;
635 vpImagePoint iP(s.m_ifloat, s.m_jfloat);
636 if (inRectangle(iP, rect)) {
637 m_meList.erase(it);
638 }
639 else
640 break;
641 }
642
643 std::list<vpMeSite>::iterator itList = m_meList.end();
644 --itList; // Move on the last element
645 double convlt;
646 double delta;
647 unsigned int nbr = 0;
648 std::list<vpMeSite> addedPt;
649 for (std::list<vpImagePoint>::const_iterator itEdges = ip_edges_list.begin(); itEdges != ip_edges_list.end();
650 ++itEdges) {
651 s = *itList;
652 vpImagePoint iPtemp = *itEdges + topLeft;
653 vpMeSite pix;
654 pix.init(iPtemp.get_i(), iPtemp.get_j(), 0);
655 dist = vpMeSite::sqrDistance(s, pix);
656 if (dist >= vpMath::sqr(m_me->getSampleStep())) {
657 bool exist = false;
658 for (std::list<vpMeSite>::const_iterator itAdd = addedPt.begin(); itAdd != addedPt.end(); ++itAdd) {
659 dist = vpMeSite::sqrDistance(pix, *itAdd);
660 if (dist < vpMath::sqr(m_me->getSampleStep()))
661 exist = true;
662 }
663 if (!exist) {
664 findAngle(I, iPtemp, m_me, delta, convlt);
665 pix.init(iPtemp.get_i(), iPtemp.get_j(), delta, convlt);
667 m_meList.push_back(pix);
668 addedPt.push_back(pix);
669 nbr++;
670 }
671 }
672 }
673
674 unsigned int memory_range = m_me->getRange();
675 m_me->setRange(3);
676 std::list<vpMeSite>::iterator itList2 = m_meList.end();
677 --itList2; // Move to the last element
678 for (unsigned int j = 0; j < nbr; j++) {
679 vpMeSite me_s = *itList2;
680 me_s.track(I, m_me, false);
681 *itList2 = me_s;
682 --itList2;
683 }
684 m_me->setRange(memory_range);
685 }
686
687 /* if (end != nullptr) */ delete[] end;
688 endPtFound = 0;
689 }
690}
691
693{
694 unsigned int n = numberOfSignal();
695 double nbPt = floor(dist / m_me->getSampleStep());
696
697 if (static_cast<double>(n) < 0.7 * nbPt) {
698 sample(I);
700 }
701}
702
704{
705 int rows = static_cast<int>(I.getHeight());
706 int cols = static_cast<int>(I.getWidth());
707 vpImagePoint *iP = nullptr;
708
709 int n = static_cast<int>(numberOfSignal());
710
711 std::list<vpMeSite>::iterator it = m_meList.begin();
712 std::list<vpMeSite>::iterator itNext = m_meList.begin();
713 ++itNext;
714
715 unsigned int range_tmp = m_me->getRange();
716 m_me->setRange(2);
717
718 while (itNext != m_meList.end() && n <= m_me->getPointsToTrack()) {
719 vpMeSite s = *it; // current reference pixel
720 vpMeSite s_next = *itNext; // current reference pixel
721
722 double d = vpMeSite::sqrDistance(s, s_next);
723 if (d > 4 * vpMath::sqr(m_me->getSampleStep()) && d < 1600) {
724 vpImagePoint iP0(s.m_ifloat, s.m_jfloat);
725 vpImagePoint iPend(s_next.m_ifloat, s_next.m_jfloat);
726 vpImagePoint iP_1(s.m_ifloat, s.m_jfloat);
727
728 double u = 0.0;
729 double ubegin = 0.0;
730 double uend = 0.0;
731 double dmin1_1 = 1e6;
732 double dmin2_1 = 1e6;
733 while (u < 1) {
734 u += 0.01;
735 double dmin1 = vpImagePoint::sqrDistance(nurbs.computeCurvePoint(u), iP0);
736 double dmin2 = vpImagePoint::sqrDistance(nurbs.computeCurvePoint(u), iPend);
737
738 if (dmin1 < dmin1_1) {
739 dmin1_1 = dmin1;
740 ubegin = u;
741 }
742
743 if (dmin2 < dmin2_1) {
744 dmin2_1 = dmin2;
745 uend = u;
746 }
747 }
748 u = ubegin;
749
750 // if(( u != 1.0 || uend != 1.0)
751 if ((std::fabs(u - 1.0) > std::fabs(vpMath::maximum(u, 1.0)) * std::numeric_limits<double>::epsilon()) ||
752 (std::fabs(uend - 1.0) > std::fabs(vpMath::maximum(uend, 1.0)) * std::numeric_limits<double>::epsilon())) {
753 iP = nurbs.computeCurveDersPoint(u, 1);
754
755 while (vpImagePoint::sqrDistance(iP[0], iPend) > vpMath::sqr(m_me->getSampleStep()) && u < uend) {
756 u += 0.01;
757 /*if (iP!=nullptr)*/ {
758 delete[] iP;
759 iP = nullptr;
760 }
761 iP = nurbs.computeCurveDersPoint(u, 1);
762 if (vpImagePoint::sqrDistance(iP[0], iP_1) > vpMath::sqr(m_me->getSampleStep()) &&
763 !outOfImage(iP[0], 0, rows, cols)) {
764 double delta = computeDelta(iP[1].get_i(), iP[1].get_j());
765 vpMeSite pix;
766 pix.init(iP[0].get_i(), iP[0].get_j(), delta);
768 pix.track(I, m_me, false);
769 if (pix.getState() == vpMeSite::NO_SUPPRESSION) {
770 m_meList.insert(it, pix);
771 iP_1 = iP[0];
772 }
773 }
774 }
775 /*if (iP!=nullptr)*/ {
776 delete[] iP;
777 iP = nullptr;
778 }
779 }
780 }
781 ++it;
782 ++itNext;
783 }
784 m_me->setRange(range_tmp);
785}
786
788{
789 std::list<vpMeSite>::const_iterator it = m_meList.begin();
790 std::list<vpMeSite>::iterator itNext = m_meList.begin();
791 ++itNext;
792 for (; itNext != m_meList.end();) {
793 vpMeSite s = *it; // current reference pixel
794 vpMeSite s_next = *itNext; // current reference pixel
795
796 if (vpMeSite::sqrDistance(s, s_next) < vpMath::sqr(m_me->getSampleStep())) {
798
799 *itNext = s_next;
800 ++it;
801 ++itNext;
802 if (itNext != m_meList.end()) {
803 ++it;
804 ++itNext;
805 }
806 }
807 else {
808 ++it;
809 ++itNext;
810 }
811 }
812}
813
815{
816 // Tracking des vpMeSites
818
819 // Suppress points which are too close to each other
821
822 // Suppressions des points ejectes par le tracking
824
825 if (m_meList.size() == 1)
826 throw(vpTrackingException(vpTrackingException::notEnoughPointError, "Not enough valid me to track"));
827
828 // Recalcule les parametres
829 // nurbs.globalCurveInterp(m_meList);
830 nurbs.globalCurveApprox(m_meList, nbControlPoints);
831
832 // On resample localement
833 localReSample(I);
834
836 if (enableCannyDetection)
838
839 // nurbs.globalCurveInterp(m_meList);
840 nurbs.globalCurveApprox(m_meList, nbControlPoints);
841
842 double u = 0.0;
843 vpImagePoint pt;
844 vpImagePoint pt_1;
845 dist = 0;
846 while (u <= 1.0) {
847 pt = nurbs.computeCurvePoint(u);
848 // if(u!=0)
849 if (std::fabs(u) > std::numeric_limits<double>::epsilon())
850 dist = dist + vpImagePoint::distance(pt, pt_1);
851 pt_1 = pt;
852 u = u + 0.01;
853 }
854
855 updateDelta();
856
857 reSample(I);
858}
859
860void vpMeNurbs::display(const vpImage<unsigned char> &I, const vpColor &color, unsigned int thickness)
861{
862 vpMeNurbs::display(I, nurbs, color, thickness);
863}
864
881bool vpMeNurbs::computeFreemanChainElement(const vpImage<unsigned char> &I, vpImagePoint &iP, unsigned int &element)
882{
883 vpImagePoint diP;
884 vpImagePoint iPtemp;
885 if (hasGoodLevel(I, iP)) {
886 // get the point on the right of the point passed in
887 computeFreemanParameters((element + 2) % 8, diP);
888 iPtemp = iP + diP;
889 if (hasGoodLevel(I, iPtemp)) {
890 element = (element + 2) % 8; // turn right
891 }
892 else {
893 computeFreemanParameters((element + 1) % 8, diP);
894 iPtemp = iP + diP;
895
896 if (hasGoodLevel(I, iPtemp)) {
897 element = (element + 1) % 8; // turn diag right
898 }
899 else {
900 computeFreemanParameters(element, diP);
901 iPtemp = iP + diP;
902
903 if (hasGoodLevel(I, iPtemp)) {
904 // element = element; // keep same dir
905 }
906 else {
907 computeFreemanParameters((element + 7) % 8, diP);
908 iPtemp = iP + diP;
909
910 if (hasGoodLevel(I, iPtemp)) {
911 element = (element + 7) % 8; // turn diag left
912 }
913 else {
914 computeFreemanParameters((element + 6) % 8, diP);
915 iPtemp = iP + diP;
916
917 if (hasGoodLevel(I, iPtemp)) {
918 element = (element + 6) % 8; // turn left
919 }
920 else {
921 computeFreemanParameters((element + 5) % 8, diP);
922 iPtemp = iP + diP;
923
924 if (hasGoodLevel(I, iPtemp)) {
925 element = (element + 5) % 8; // turn diag down
926 }
927 else {
928 computeFreemanParameters((element + 4) % 8, diP);
929 iPtemp = iP + diP;
930
931 if (hasGoodLevel(I, iPtemp)) {
932 element = (element + 4) % 8; // turn down
933 }
934 else {
935 computeFreemanParameters((element + 3) % 8, diP);
936 iPtemp = iP + diP;
937
938 if (hasGoodLevel(I, iPtemp)) {
939 element = (element + 3) % 8; // turn diag right down
940 }
941 else {
942 // No neighbor with a good level
943 //
944 return false;
945 }
946 }
947 }
948 }
949 }
950 }
951 }
952 }
953 }
954 else {
955 return false;
956 }
957 return true;
958}
959
972bool vpMeNurbs::hasGoodLevel(const vpImage<unsigned char> &I, const vpImagePoint &iP) const
973{
974 if (!isInImage(I, iP))
975 return false;
976
977 if (I(static_cast<unsigned int>(vpMath::round(iP.get_i())), static_cast<unsigned int>(vpMath::round(iP.get_j()))) > 0) {
978 return true;
979 }
980 else {
981 return false;
982 }
983}
984
995bool vpMeNurbs::isInImage(const vpImage<unsigned char> &I, const vpImagePoint &iP) const
996{
997 return (iP.get_i() >= 0 && iP.get_j() >= 0 && iP.get_i() < I.getHeight() && iP.get_j() < I.getWidth());
998}
999
1017void vpMeNurbs::computeFreemanParameters(unsigned int element, vpImagePoint &diP)
1018{
1019 /*
1020 5 6 7
1021 \ | /
1022 \|/
1023 4 ------- 0
1024 /|\
1025 / | \
1026 3 2 1
1027 */
1028 switch (element) {
1029 case 0: // go right
1030 diP.set_ij(0, 1);
1031 break;
1032
1033 case 1: // go right top
1034 diP.set_ij(1, 1);
1035 break;
1036
1037 case 2: // go top
1038 diP.set_ij(1, 0);
1039 break;
1040
1041 case 3:
1042 diP.set_ij(1, -1);
1043 break;
1044
1045 case 4:
1046 diP.set_ij(0, -1);
1047 break;
1048
1049 case 5:
1050 diP.set_ij(-1, -1);
1051 break;
1052
1053 case 6:
1054 diP.set_ij(-1, 0);
1055 break;
1056
1057 case 7:
1058 diP.set_ij(-1, 1);
1059 break;
1060 }
1061}
1062
1072bool vpMeNurbs::farFromImageEdge(const vpImage<unsigned char> &I, const vpImagePoint &iP)
1073{
1074 unsigned int height = I.getHeight();
1075 unsigned int width = I.getWidth();
1076 return (iP.get_i() < height - 20 && iP.get_j() < width - 20 && iP.get_i() > 20 && iP.get_j() > 20);
1077}
1078
1079void vpMeNurbs::display(const vpImage<unsigned char> &I, vpNurbs &n, const vpColor &color, unsigned int thickness)
1080{
1081 double u = 0.0;
1082 vpImagePoint pt;
1083 while (u <= 1) {
1084 pt = n.computeCurvePoint(u);
1085 vpDisplay::displayCross(I, pt, 4, color, thickness);
1086 u += 0.01;
1087 }
1088}
1089
1090void vpMeNurbs::display(const vpImage<vpRGBa> &I, vpNurbs &n, const vpColor &color, unsigned int thickness)
1091{
1092 double u = 0.0;
1093 vpImagePoint pt;
1094 while (u <= 1) {
1095 pt = n.computeCurvePoint(u);
1096 vpDisplay::displayCross(I, pt, 4, color, thickness);
1097 u += 0.01;
1098 }
1099}
1100END_VISP_NAMESPACE
Class to define RGB colors available for display functionalities.
Definition vpColor.h:157
static const vpColor orange
Definition vpColor.h:208
static const vpColor blue
Definition vpColor.h:204
static const vpColor green
Definition vpColor.h:201
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
static void displayCross(const vpImage< unsigned char > &I, const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)
static void flush(const vpImage< unsigned char > &I)
static void displayPoint(const vpImage< unsigned char > &I, const vpImagePoint &ip, const vpColor &color, unsigned int thickness=1)
static void displayRectangle(const vpImage< unsigned char > &I, const vpImagePoint &topLeft, unsigned int width, unsigned int height, const vpColor &color, bool fill=false, unsigned int thickness=1)
error that can be emitted by ViSP classes.
Definition vpException.h:60
@ notInitialized
Used to indicate that a parameter is not initialized.
Definition vpException.h:74
@ divideByZeroError
Division by zero.
Definition vpException.h:70
static void canny(const vpImage< unsigned char > &I, vpImage< unsigned char > &Ic, const unsigned int &gaussianFilterSize, const float &thresholdCanny, const unsigned int &apertureSobel)
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
double get_j() const
static double distance(const vpImagePoint &iP1, const vpImagePoint &iP2)
void set_ij(double ii, double jj)
static double sqrDistance(const vpImagePoint &iP1, const vpImagePoint &iP2)
double get_i() const
static void crop(const vpImage< Type > &I, double roi_top, double roi_left, unsigned int roi_height, unsigned int roi_width, vpImage< Type > &crop, unsigned int v_scale=1, unsigned int h_scale=1)
Definition of the vpImage class member functions.
Definition vpImage.h:131
unsigned int getWidth() const
Definition vpImage.h:242
unsigned int getHeight() const
Definition vpImage.h:181
static double rad(double deg)
Definition vpMath.h:129
static Type maximum(const Type &a, const Type &b)
Definition vpMath.h:257
static double sqr(double x)
Definition vpMath.h:203
static Type abs(const Type &x)
Definition vpMath.h:272
static int round(double x)
Definition vpMath.h:413
static int sign(double x)
Definition vpMath.h:432
void track(const vpImage< unsigned char > &I)
void reSample(const vpImage< unsigned char > &I)
void seekExtremities(const vpImage< unsigned char > &I)
vpNurbs nurbs
The Nurbs which represents the tracked edge.
Definition vpMeNurbs.h:147
virtual void sample(const vpImage< unsigned char > &I, bool doNotTrack=false)
void initTracking(const vpImage< unsigned char > &I)
void updateDelta()
void localReSample(const vpImage< unsigned char > &I)
void display(const vpImage< unsigned char > &I, const vpColor &color, unsigned int thickness=1)
void seekExtremitiesCanny(const vpImage< unsigned char > &I)
void suppressPoints()
void supressNearPoints()
Performs search in a given direction(normal) for a given distance(pixels) for a given 'site'....
Definition vpMeSite.h:75
@ TOO_NEAR
Point not tracked anymore, since too near from its neighbor.
Definition vpMeSite.h:100
@ NO_SUPPRESSION
Point successfully tracked.
Definition vpMeSite.h:93
void setDisplay(vpMeSiteDisplayType select)
Definition vpMeSite.h:287
double m_ifloat
Subpixel coordinates along i of a site.
Definition vpMeSite.h:110
void init()
Definition vpMeSite.cpp:70
vpMeSiteState getState() const
Definition vpMeSite.h:306
int m_j
Integer coordinates along j of a site.
Definition vpMeSite.h:108
int get_j() const
Definition vpMeSite.h:206
int m_i
Integer coordinate along i of a site.
Definition vpMeSite.h:106
double m_jfloat
Subpixel coordinates along j of a site.
Definition vpMeSite.h:112
int get_i() const
Definition vpMeSite.h:200
static double sqrDistance(const vpMeSite &S1, const vpMeSite &S2)
Definition vpMeSite.h:407
void track(const vpImage< unsigned char > &I, const vpMe *me, const bool &test_contrast=true)
Definition vpMeSite.cpp:330
void setState(const vpMeSiteState &flag)
Definition vpMeSite.h:296
void initTracking(const vpImage< unsigned char > &I)
unsigned int numberOfSignal()
vpMeSite::vpMeSiteDisplayType m_selectDisplay
Moving-edges display type.
void track(const vpImage< unsigned char > &I)
vpMe * m_me
Moving edges initialisation parameters.
bool outOfImage(int i, int j, int border, int nrows, int ncols)
std::list< vpMeSite > m_meList
Definition vpMe.h:143
unsigned int getAngleStep() const
Definition vpMe.h:202
vpMatrix * getMask() const
Definition vpMe.h:215
int getStrip() const
Definition vpMe.h:297
unsigned int getMaskSize() const
Definition vpMe.h:240
Class that provides tools to compute and manipulate a Non Uniform Rational B-Spline curve.
Definition vpNurbs.h:93
static vpImagePoint computeCurvePoint(double l_u, unsigned int l_i, unsigned int l_p, std::vector< double > &l_knots, std::vector< vpImagePoint > &l_controlPoints, std::vector< double > &l_weights)
Definition vpNurbs.cpp:56
Defines a rectangle in the plane.
Definition vpRect.h:79
Error that can be emitted by the vpTracker class and its derivatives.
@ notEnoughPointError
Not enough point to track.
#define vpDEBUG_ENABLE(level)
Definition vpDebug.h:585