Visual Servoing Platform  version 3.6.1 under development (2024-10-18)
vpDot2_freeman.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  * Description:
31  * Freeman chain dedicated functions.
32  */
33 
34 #include <visp3/core/vpConfig.h>
35 #include <visp3/blob/vpDot2.h>
36 
37 BEGIN_VISP_NAMESPACE
38 
39 #ifndef DOXYGEN_SHOULD_SKIP_THIS
40 namespace
41 {
54 void computeTopRightWithMoment(const int &u_p, const int &v_p, float &dMuv, float &dMu2, float &dMv2)
55 {
56  float half_u_p = static_cast<float>(0.5 * u_p);
57  dMuv = static_cast<float>((v_p * v_p * (0.25 + half_u_p)) + (v_p * ((1. / 3.) + half_u_p)) + ((1. / 6.) * u_p) + 0.125);
58  dMu2 = static_cast<float>(((-1. / 3.) * u_p * ((u_p * u_p) + (1.5 * u_p) + 1.)) - (1. / 12.0));
59  dMv2 = static_cast<float>(((1. / 3.) * v_p * ((v_p * v_p) + (1.5 * v_p) + 1.)) + (1. / 12.0));
60 }
61 
74 void computeTopLeftWithMoment(const int &u_p, const int &v_p, float &dMuv, float &dMu2, float &dMv2)
75 {
76  float half_u_p = static_cast<float>(0.5 * u_p);
77  dMuv = static_cast<float>((((v_p * v_p * (0.25 - half_u_p)) + (v_p * ((1. / 3.) - half_u_p))) - ((1. / 6.) * u_p)) + 0.125);
78  dMu2 = static_cast<float>(((-1. / 3.) * u_p * (((u_p * u_p) - (1.5 * u_p)) + 1.)) - (1. / 12.0));
79  dMv2 = static_cast<float>(((-1. / 3.) * v_p * ((v_p * v_p) + (1.5 * v_p) + 1.)) - (1. / 12.0));
80 }
81 
94 void computeDownRightWithMoment(const int &u_p, const int &v_p, float &dMuv, float &dMu2, float &dMv2)
95 {
96  float half_u_p = static_cast<float>(0.5 * u_p);
97  dMuv = static_cast<float>(((v_p * v_p * (0.25 + half_u_p)) - (v_p * ((1. / 3.) + half_u_p))) + ((1. / 6.) * u_p) + 0.125);
98  dMu2 = static_cast<float>(((1. / 3.) * u_p * ((u_p * u_p) + (1.5 * u_p) + 1.)) + (1. / 12.0));
99  dMv2 = static_cast<float>(((1. / 3.) * v_p * (((v_p * v_p) - (1.5 * v_p)) + 1.)) - (1. / 12.0));
100 }
101 
114 void computeDownLeftWithMoment(const int &u_p, const int &v_p, float &dMuv, float &dMu2, float &dMv2)
115 {
116  float half_u_p = static_cast<float>(0.5 * u_p);
117  dMuv = static_cast<float>((((v_p * v_p * (0.25 - half_u_p)) - (v_p * ((1. / 3.) - half_u_p))) - ((1. / 6.) * u_p)) + 0.125);
118  dMu2 = static_cast<float>(((1. / 3.) * u_p * (((u_p * u_p) - (1.5 * u_p)) + 1.)) - (1. / 12.0));
119  dMv2 = static_cast<float>(((-1. / 3.) * v_p * (((v_p * v_p) - (1.5 * v_p)) + 1.)) - (1. / 12.0));
120 }
121 }
122 
123 #endif // DOXYGEN_SHOULD_SKIP_THIS
139 void vpDot2::getFreemanChain(std::list<unsigned int> &freeman_chain) const { freeman_chain = m_direction_list; }
140 
159 bool vpDot2::computeFreemanChainElement(const vpImage<unsigned char> &I, const unsigned int &u, const unsigned int &v,
160  unsigned int &element)
161 {
162  if (hasGoodLevel(I, u, v)) {
163  unsigned int v_u = u;
164  unsigned int v_v = v;
165  const unsigned int val_1 = 1;
166  const unsigned int val_2 = 2;
167  const unsigned int val_3 = 3;
168  const unsigned int val_4 = 4;
169  const unsigned int val_5 = 5;
170  const unsigned int val_6 = 6;
171  const unsigned int val_7 = 7;
172  const unsigned int val_8 = 8;
173  // get the point on the right of the point passed in
174  updateFreemanPosition(v_u, v_v, (element + val_2) % val_8);
175  if (hasGoodLevel(I, v_u, v_v)) {
176  element = (element + val_2) % val_8; // turn right
177  }
178  else {
179  unsigned int v_u1 = u;
180  unsigned int v_v1 = v;
181  updateFreemanPosition(v_u1, v_v1, (element + val_1) % val_8);
182 
183  if (hasGoodLevel(I, v_u1, v_v1)) {
184  element = (element + val_1) % val_8; // turn diag right
185  }
186  else {
187  unsigned int v_u2 = u;
188  unsigned int v_v2 = v;
189  updateFreemanPosition(v_u2, v_v2, element); // same direction
190 
191  if (hasGoodLevel(I, v_u2, v_v2)) {
192  // element = element; // keep same dir
193  }
194  else {
195  unsigned int v_u3 = u;
196  unsigned int v_v3 = v;
197  updateFreemanPosition(v_u3, v_v3, (element + val_7) % val_8); // diag left
198 
199  if (hasGoodLevel(I, v_u3, v_v3)) {
200  element = (element + val_7) % val_8; // turn diag left
201  }
202  else {
203  unsigned int v_u4 = u;
204  unsigned int v_v4 = v;
205  updateFreemanPosition(v_u4, v_v4, (element + val_6) % val_8); // left
206 
207  if (hasGoodLevel(I, v_u4, v_v4)) {
208  element = (element + val_6) % val_8; // turn left
209  }
210  else {
211  unsigned int v_u5 = u;
212  unsigned int v_v5 = v;
213  updateFreemanPosition(v_u5, v_v5, (element + val_5) % val_8); // left
214 
215  if (hasGoodLevel(I, v_u5, v_v5)) {
216  element = (element + val_5) % val_8; // turn diag down
217  }
218  else {
219  unsigned int v_u6 = u;
220  unsigned int v_v6 = v;
221  updateFreemanPosition(v_u6, v_v6, (element + val_4) % val_8); // left
222 
223  if (hasGoodLevel(I, v_u6, v_v6)) {
224  element = (element + val_4) % val_8; // turn down
225  }
226  else {
227  unsigned int v_u7 = u;
228  unsigned int v_v7 = v;
229  updateFreemanPosition(v_u7, v_v7, (element + val_3) % val_8); // diag
230 
231  if (hasGoodLevel(I, v_u7, v_v7)) {
232  element = (element + val_3) % val_8; // turn diag right down
233  }
234  else {
235  // No neighbor with a good level
236  //
237  return false;
238  }
239  }
240  }
241  }
242  }
243  }
244  }
245  }
246  }
247 
248  else {
249  return false;
250  }
251 
252  return true;
253 }
254 
284 void vpDot2::computeFreemanParameters(const int &u_p, const int &v_p, unsigned int &element, int &du, int &dv,
285  float &dS, float &dMu, float &dMv, float &dMuv, float &dMu2, float &dMv2)
286 {
287  /*
288  3 2 1
289  \ | /
290  \|/
291  4 ------- 0
292  /|\
293  / | \
294  5 6 7
295  */
296  const unsigned int go_right = 0;
297  const unsigned int go_right_top = 1;
298  const unsigned int go_top = 2;
299  const unsigned int go_top_left = 3;
300  const unsigned int go_left = 4;
301  const unsigned int go_left_down = 5;
302  const unsigned int go_down = 6;
303  const unsigned int go_down_right = 7;
304  du = 0;
305  dv = 0;
306  dMuv = 0;
307  dMu2 = 0;
308  dMv2 = 0;
309  const unsigned int val_2 = 2;
310  switch (element) {
311  case go_right: // go right
312  du = 1;
313  dS = static_cast<float>(v_p);
314  dMu = 0.0;
315  dMv = static_cast<float>(0.5 * v_p * v_p);
316  if (m_compute_moment) {
317  dMuv = static_cast<float>(0.25 * v_p * v_p * ((val_2 * u_p) + 1));
318  dMu2 = 0;
319  dMv2 = static_cast<float>((1.0 / 3.) * v_p * v_p * v_p);
320  }
321  break;
322 
323  case go_right_top: // go right top
324  du = 1;
325  dv = 1;
326  dS = static_cast<float>(v_p + 0.5);
327  dMu = -static_cast<float>((0.5 * u_p * (u_p + 1)) + (1.0 / 6.0));
328  dMv = static_cast<float>((0.5 * v_p * (v_p + 1)) + (1.0 / 6.0));
329  if (m_compute_moment) {
330  computeTopRightWithMoment(u_p, v_p, dMuv, dMu2, dMv2);
331  }
332  break;
333 
334  case go_top: // go top
335  dv = 1;
336  dS = 0.0;
337  dMu = static_cast<float>(-0.5 * u_p * u_p);
338  dMv = 0.0;
339  if (m_compute_moment) {
340  dMuv = 0;
341  dMu2 = static_cast<float>((-1.0 / 3.) * u_p * u_p * u_p);
342  dMv2 = 0;
343  }
344  break;
345 
346  case go_top_left:
347  du = -1;
348  dv = 1;
349  dS = static_cast<float>(-v_p - 0.5);
350  dMu = -static_cast<float>((0.5 * u_p * (u_p - 1)) + (1.0 / 6.0));
351  dMv = -static_cast<float>((0.5 * v_p * (v_p + 1)) + (1.0 / 6.0));
352  if (m_compute_moment) {
353  computeTopLeftWithMoment(u_p, v_p, dMuv, dMu2, dMv2);
354  }
355  break;
356 
357  case go_left:
358  du = -1;
359  dS = static_cast<float>(-v_p);
360  dMv = static_cast<float>(-0.5 * v_p * v_p);
361  dMu = 0.0;
362  if (m_compute_moment) {
363  dMuv = static_cast<float>(-0.25 * v_p * v_p * ((val_2 * u_p) - 1));
364  dMu2 = 0;
365  dMv2 = static_cast<float>((-1.0 / 3.) * v_p * v_p * v_p);
366  }
367  break;
368 
369  case go_left_down:
370  du = -1;
371  dv = -1;
372  dS = static_cast<float>(-v_p + 0.5);
373  dMu = static_cast<float>((0.5 * u_p * (u_p - 1)) + (1.0 / 6.0));
374  dMv = static_cast<float>(-((0.5 * v_p * (v_p - 1)) + (1.0 / 6.0)));
375  if (m_compute_moment) {
376  computeDownLeftWithMoment(u_p, v_p, dMuv, dMu2, dMv2);
377  }
378  break;
379 
380  case go_down:
381  dv = -1;
382  dS = 0.0;
383  dMu = static_cast<float>(0.5 * u_p * u_p);
384  dMv = 0.0;
385  if (m_compute_moment) {
386  dMuv = 0;
387  dMu2 = static_cast<float>((1.0 / 3.) * u_p * u_p * u_p);
388  dMv2 = 0;
389  }
390  break;
391 
392  case go_down_right:
393  du = 1;
394  dv = -1;
395  dS = static_cast<float>(v_p - 0.5);
396  dMu = static_cast<float>((0.5 * u_p * (u_p + 1)) + (1.0 / 6.0));
397  dMv = static_cast<float>((0.5 * v_p * (v_p - 1)) + (1.0 / 6.0));
398  if (m_compute_moment) {
399  computeDownRightWithMoment(u_p, v_p, dMuv, dMu2, dMv2);
400  }
401  break;
402 
403  default:
404  std::cout << "to complete the default" << std::endl;
405  }
406 }
407 
421 void vpDot2::updateFreemanPosition(unsigned int &u, unsigned int &v, const unsigned int &dir)
422 {
423  /*
424  3 2 1
425  \ | /
426  \|/
427  4 ------- 0
428  /|\
429  / | \
430  5 6 7
431  */
432  const unsigned int go_right = 0;
433  const unsigned int go_right_top = 1;
434  const unsigned int go_top = 2;
435  const unsigned int go_top_left = 3;
436  const unsigned int go_left = 4;
437  const unsigned int go_left_down = 5;
438  const unsigned int go_down = 6;
439  const unsigned int go_down_right = 7;
440  switch (dir) {
441  case go_right:
442  u += 1;
443  break;
444  case go_right_top:
445  u += 1;
446  v += 1;
447  break;
448  case go_top:
449  v += 1;
450  break;
451  case go_top_left:
452  u -= 1;
453  v += 1;
454  break;
455  case go_left:
456  u -= 1;
457  break;
458  case go_left_down:
459  u -= 1;
460  v -= 1;
461  break;
462  case go_down:
463  v -= 1;
464  break;
465  case go_down_right:
466  u += 1;
467  v -= 1;
468  break;
469  default:
470  std::cout << "In vpDot2::updateFreemanPosition dir not identified" << std::endl;
471  }
472 }
473 
474 END_VISP_NAMESPACE