Visual Servoing Platform  version 3.6.1 under development (2024-07-27)
vpMeTracker.cpp
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2019 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 
39 #include <visp3/core/vpColor.h>
40 #include <visp3/core/vpDisplay.h>
41 #include <visp3/me/vpMeTracker.h>
42 
43 #include <algorithm>
44 #include <visp3/core/vpTrackingException.h>
45 
47 
49 {
51  const unsigned int val_2 = 2;
52  p.resize(val_2);
54 }
55 
57  : m_meList(), m_me(nullptr), m_init_range(1), m_nGoodElement(0), m_mask(nullptr), m_maskCandidates(nullptr), m_selectDisplay(vpMeSite::NONE)
58 {
59  init();
60 }
61 
63  : vpTracker(meTracker), m_meList(), m_me(nullptr), m_init_range(1), m_nGoodElement(0), m_mask(nullptr), m_maskCandidates(nullptr), m_selectDisplay(vpMeSite::NONE)
64 {
65  init();
66 
67  m_me = meTracker.m_me;
68  m_meList = meTracker.m_meList;
69  m_nGoodElement = meTracker.m_nGoodElement;
70  m_init_range = meTracker.m_init_range;
71  m_selectDisplay = meTracker.m_selectDisplay;
72 }
73 
75 {
76  m_nGoodElement = 0;
77  m_meList.clear();
78 }
79 
81 
83 {
84  m_meList = meTracker.m_meList;
85  m_me = meTracker.m_me;
86  m_selectDisplay = meTracker.m_selectDisplay;
87  m_init_range = meTracker.m_init_range;
88  m_nGoodElement = meTracker.m_nGoodElement;
89  return *this;
90 }
91 
92 static bool isSuppressZero(const vpMeSite &P) { return (P.getState() == vpMeSite::NO_SUPPRESSION); }
93 
95 {
96  unsigned int number_signal = 0;
97 
98  // Loop through all the points tracked from the contour
99  number_signal = static_cast<unsigned int>(std::count_if(m_meList.begin(), m_meList.end(), isSuppressZero));
100  return number_signal;
101 }
102 
103 unsigned int vpMeTracker::totalNumberOfSignal() { return static_cast<unsigned int>(m_meList.size()); }
104 
105 bool vpMeTracker::inRoiMask(const vpImage<bool> *mask, unsigned int i, unsigned int j)
106 {
107  try {
108  return ((mask == nullptr) || (mask->getValue(i, j)));
109  }
110  catch (vpException &) {
111  return false;
112  }
113 }
114 
115 bool vpMeTracker::inMeMaskCandidates(const vpImage<bool> *meMaskCandidates, unsigned int i, unsigned int j)
116 {
117  if (meMaskCandidates == nullptr) {
118  return true;
119  }
120  else {
121  const unsigned int kernelSize = 3;
122  const unsigned int halfKernelSize = (kernelSize - 1) / 2;
123  const unsigned int nbRows = meMaskCandidates->getRows();
124  const unsigned int nbCols = meMaskCandidates->getCols();
125 
126  if ((i >= nbRows) || (j >= nbCols)) {
127  // The asked point is outside the mask
128  return false;
129  }
130  if ((*meMaskCandidates)[i][j]) {
131  // The asked point is a candidate
132  return true;
133  }
134  unsigned int iStart = 0, jStart = 0;
135  unsigned int iStop = nbRows - 1, jStop = nbCols - 1;
136  // Ensuring we won't go outside the limits of the mask
137  if (i >= halfKernelSize) {
138  iStart = i - halfKernelSize;
139  }
140  if (j >= halfKernelSize) {
141  jStart = j - halfKernelSize;
142  }
143  if ((i + halfKernelSize) < nbRows) {
144  iStop = i + halfKernelSize;
145  }
146  if ((j + halfKernelSize) < nbCols) {
147  jStop = j + halfKernelSize;
148  }
149  // Looking in its neighborhood
150  bool isACandidate = false;
151  unsigned int iter_i = iStart, iter_j = jStart;
152 
153  while ((!isACandidate) && (iter_i <= iStop)) {
154  iter_j = jStart;
155  while ((!isACandidate) && (iter_j <= jStop)) {
156  isACandidate = (*meMaskCandidates)[iter_i][iter_j];
157  ++iter_j;
158  }
159  ++iter_i;
160  }
161 
162  return isACandidate;
163  }
164 }
165 
166 bool vpMeTracker::outOfImage(int i, int j, int border, int nrows, int ncols)
167 {
168  int borderWith2SparedPixels = border + 2;
169  return (!((i > borderWith2SparedPixels) && (i < (nrows - borderWith2SparedPixels))
170  && (j > borderWith2SparedPixels) && (j < (ncols - borderWith2SparedPixels))
171  ));
172 }
173 
174 bool vpMeTracker::outOfImage(const vpImagePoint &iP, int border, int nrows, int ncols)
175 {
176  const int borderPlus2 = border + 2;
177  int i = vpMath::round(iP.get_i());
178  int j = vpMath::round(iP.get_j());
179  return (!((i > borderPlus2) && (i < (nrows - borderPlus2)) && (j > borderPlus2) && (j < (ncols - borderPlus2))));
180 }
181 
183 {
184  if (!m_me) {
185  throw(vpTrackingException(vpTrackingException::initializationError, "Moving edges not initialized"));
186  }
187 
188  // Must set range to 0
189  unsigned int range_tmp = m_me->getRange();
191 
192  m_nGoodElement = 0;
193 
194  // Loop through list of sites to track
195  std::list<vpMeSite>::iterator end = m_meList.end();
196  for (std::list<vpMeSite>::iterator it = m_meList.begin(); it != end; ++it) {
197  vpMeSite refp = *it; // current reference pixel
198 
199  // If element hasn't been suppressed
200  if (refp.getState() == vpMeSite::NO_SUPPRESSION) {
201 
202  refp.track(I, m_me, false);
203 
204  if (refp.getState() == vpMeSite::NO_SUPPRESSION) {
205  ++m_nGoodElement;
206  }
207  }
208 
209  *it = refp;
210  }
211 
212  m_me->setRange(range_tmp);
213 }
214 
216 {
217  if (!m_me) {
218  throw(vpTrackingException(vpTrackingException::initializationError, "Moving edges not initialized"));
219  }
220 
221  if (m_meList.empty()) {
222  throw(vpTrackingException(vpTrackingException::notEnoughPointError, "Too few pixel to track"));
223  }
224 
225  m_nGoodElement = 0;
226 
227  // Loop through list of sites to track
228  std::list<vpMeSite>::iterator it = m_meList.begin();
229  std::list<vpMeSite>::iterator end = m_meList.end();
230  while (it != end) {
231  vpMeSite s = *it; // current reference pixel
232 
233  // If element hasn't been suppressed
234  if (s.getState() == vpMeSite::NO_SUPPRESSION) {
235  s.track(I, m_me, true);
236 
237 
238  if (vpMeTracker::inRoiMask(m_mask, s.get_i(), s.get_j())) {
239  if (s.getState() == vpMeSite::NO_SUPPRESSION) {
240  ++m_nGoodElement;
241  }
242  }
243  else {
244  // Site outside mask
246  }
247  }
248 
249  *it = s;
250  ++it;
251  }
252 }
253 
255 {
256  std::list<vpMeSite>::const_iterator end = m_meList.end();
257  for (std::list<vpMeSite>::const_iterator it = m_meList.begin(); it != end; ++it) {
258  vpMeSite p_me = *it;
259  p_me.display(I);
260  }
261 }
262 
264 {
265  std::list<vpMeSite>::const_iterator end = m_meList.end();
266  for (std::list<vpMeSite>::const_iterator it = m_meList.begin(); it != end; ++it) {
267  vpMeSite p_me = *it;
268  p_me.display(I);
269  }
270 }
271 
272 void vpMeTracker::display(const vpImage<unsigned char> &I, vpColVector &w, unsigned int &index_w)
273 {
274  std::list<vpMeSite>::iterator end = m_meList.end();
275  for (std::list<vpMeSite>::iterator it = m_meList.begin(); it != end; ++it) {
276  vpMeSite P = *it;
277 
278  if (P.getState() == vpMeSite::NO_SUPPRESSION) {
279  P.setWeight(w[index_w]);
280  ++index_w;
281  }
282 
283  *it = P;
284  }
285  display(I);
286 }
287 
288 END_VISP_NAMESPACE
Implementation of column vector and the associated operations.
Definition: vpColVector.h:191
void resize(unsigned int i, bool flagNullify=true)
Definition: vpColVector.h:1143
error that can be emitted by ViSP classes.
Definition: vpException.h:60
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:82
double get_j() const
Definition: vpImagePoint.h:125
double get_i() const
Definition: vpImagePoint.h:114
Type getValue(unsigned int i, unsigned int j) const
unsigned int getCols() const
Definition: vpImage.h:171
unsigned int getRows() const
Definition: vpImage.h:212
static int round(double x)
Definition: vpMath.h:409
Performs search in a given direction(normal) for a given distance(pixels) for a given 'site'....
Definition: vpMeSite.h:68
@ OUTSIDE_ROI_MASK
Point is outside the region of interest mask, but retained in the ME list.
Definition: vpMeSite.h:95
@ NO_SUPPRESSION
Point successfully tracked.
Definition: vpMeSite.h:86
void display(const vpImage< unsigned char > &I)
Definition: vpMeSite.cpp:383
void setWeight(const double &weight)
Definition: vpMeSite.h:276
@ NONE
Not displayed.
Definition: vpMeSite.h:75
vpMeSiteState getState() const
Definition: vpMeSite.h:269
int get_j() const
Definition: vpMeSite.h:189
int get_i() const
Definition: vpMeSite.h:183
void track(const vpImage< unsigned char > &I, const vpMe *me, const bool &test_contrast=true)
Definition: vpMeSite.cpp:269
void setState(const vpMeSiteState &flag)
Definition: vpMeSite.h:259
Contains abstract elements for a Distance to Feature type feature.
Definition: vpMeTracker.h:62
void initTracking(const vpImage< unsigned char > &I)
const vpImage< bool > * m_mask
Mask used to disable tracking on a part of image.
Definition: vpMeTracker.h:319
unsigned int numberOfSignal()
Definition: vpMeTracker.cpp:94
vpMeSite::vpMeSiteDisplayType m_selectDisplay
Moving-edges display type.
Definition: vpMeTracker.h:323
void track(const vpImage< unsigned char > &I)
unsigned int m_init_range
Initial range.
Definition: vpMeTracker.h:315
unsigned int totalNumberOfSignal()
vpMe * m_me
Moving edges initialisation parameters.
Definition: vpMeTracker.h:313
vpMeTracker & operator=(vpMeTracker &meTracker)
Definition: vpMeTracker.cpp:82
static bool inRoiMask(const vpImage< bool > *mask, unsigned int i, unsigned int j)
void display(const vpImage< unsigned char > &I)
int m_nGoodElement
Number of good moving-edges that are tracked.
Definition: vpMeTracker.h:317
bool outOfImage(int i, int j, int border, int nrows, int ncols)
virtual ~vpMeTracker() VP_OVERRIDE
Definition: vpMeTracker.cpp:80
std::list< vpMeSite > m_meList
Definition: vpMeTracker.h:311
static bool inMeMaskCandidates(const vpImage< bool > *meMaskCandidates, unsigned int i, unsigned int j)
void reset()
Definition: vpMeTracker.cpp:74
void setRange(const unsigned int &range)
Definition: vpMe.h:415
unsigned int getRange() const
Definition: vpMe.h:268
Class that defines what is a feature generic tracker.
Definition: vpTracker.h:61
void init()
Default initialization.
Definition: vpTracker.cpp:44
vpColVector p
Definition: vpTracker.h:69
Error that can be emitted by the vpTracker class and its derivatives.
@ notEnoughPointError
Not enough point to track.
@ initializationError
Tracker initialization error.