Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpMomentObject.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 * Object input structure used by moments.
32 */
33
34#include <stdexcept>
35#include <visp3/core/vpCameraParameters.h>
36#include <visp3/core/vpConfig.h>
37#include <visp3/core/vpMomentBasic.h>
38#include <visp3/core/vpMomentObject.h>
39#include <visp3/core/vpPixelMeterConversion.h>
40
41#include <cmath>
42#include <limits>
43
44#ifdef VISP_HAVE_OPENMP
45#include <omp.h>
46#endif
47#include <cassert>
48
59double vpMomentObject::calc_mom_polygon(unsigned int p, unsigned int q, const std::vector<vpPoint> &points)
60{
61 unsigned int i, k, l;
62 double den, mom;
63 double x_p_k;
64 double y_l;
65 double y_q_l;
66
67 den = static_cast<double>((p + q + 2) * (p + q + 1) * vpMath::comb(p + q, p));
68
69 mom = 0.0;
70 for (i = 1; i <= points.size() - 1; i++) {
71 double s = 0.0;
72 double x_k = 1;
73 for (k = 0; k <= p; k++) {
74 y_l = 1;
75 x_p_k = pow(points[i - 1].get_x(), static_cast<int>(p - k));
76 for (l = 0; l <= q; l++) {
77 y_q_l = pow(points[i - 1].get_y(), static_cast<int>(q - l));
78
79 s += static_cast<double>(vpMath::comb(k + l, l) * vpMath::comb(p + q - k - l, q - l) * x_k * x_p_k * y_l *
80 y_q_l);
81
82 y_l *= points[i].get_y();
83 }
84 x_k *= points[i].get_x();
85 }
86
87 s *= ((points[i - 1].get_x()) * (points[i].get_y()) - (points[i].get_x()) * (points[i - 1].get_y()));
88 mom += s;
89 }
90 mom /= den;
91 return (mom);
92}
93
108void vpMomentObject::cacheValues(std::vector<double> &cache, double x, double y)
109{
110 cache[0] = 1;
111
112 for (unsigned int i = 1; i < order; i++)
113 cache[i] = cache[i - 1] * x;
114
115 for (unsigned int j = order; j < order * order; j += order)
116 cache[j] = cache[j - order] * y;
117
118 for (unsigned int j = 1; j < order; j++) {
119 for (unsigned int i = 1; i < order - j; i++) {
120 cache[j * order + i] = cache[j * order] * cache[i];
121 }
122 }
123}
124
129void vpMomentObject::cacheValues(std::vector<double> &cache, double x, double y, double IntensityNormalized)
130{
131
132 cache[0] = IntensityNormalized;
133
134 double invIntensityNormalized = 0.;
135 if (std::fabs(IntensityNormalized) >= std::numeric_limits<double>::epsilon())
136 invIntensityNormalized = 1.0 / IntensityNormalized;
137
138 for (unsigned int i = 1; i < order; i++)
139 cache[i] = cache[i - 1] * x;
140
141 for (unsigned int j = order; j < order * order; j += order)
142 cache[j] = cache[j - order] * y;
143
144 for (unsigned int j = 1; j < order; j++) {
145 for (unsigned int i = 1; i < order - j; i++) {
146 cache[j * order + i] = cache[j * order] * cache[i] * invIntensityNormalized;
147 }
148 }
149}
150
232void vpMomentObject::fromVector(std::vector<vpPoint> &points)
233{
235 if (std::fabs(points.rbegin()->get_x() - points.begin()->get_x()) > std::numeric_limits<double>::epsilon() ||
236 std::fabs(points.rbegin()->get_y() - points.begin()->get_y()) > std::numeric_limits<double>::epsilon()) {
237 points.resize(points.size() + 1);
238 points[points.size() - 1] = points[0];
239 }
240 for (unsigned int j = 0; j < order * order; j++) {
241 values[j] = calc_mom_polygon(j % order, j / order, points);
242 }
243 }
244 else {
245 std::vector<double> cache(order * order, 0.);
246 values.assign(order * order, 0);
247 for (unsigned int i = 0; i < points.size(); i++) {
248 cacheValues(cache, points[i].get_x(), points[i].get_y());
249 for (unsigned int j = 0; j < order; j++) {
250 for (unsigned int k = 0; k < order - j; k++) {
251 values[j * order + k] += cache[j * order + k];
252 }
253 }
254 }
255 }
256}
257
295
296void vpMomentObject::fromImage(const vpImage<unsigned char> &image, unsigned char threshold,
297 const vpCameraParameters &cam)
298{
299#ifdef VISP_HAVE_OPENMP
300#pragma omp parallel shared(threshold)
301 {
302 std::vector<double> curvals(order * order);
303 curvals.assign(order * order, 0.);
304
305#pragma omp for nowait // automatically organize loop counter between threads
306 for (int i = 0; i < static_cast<int>(image.getCols()); i++) {
307 for (int j = 0; j < static_cast<int>(image.getRows()); j++) {
308 unsigned int i_ = static_cast<unsigned int>(i);
309 unsigned int j_ = static_cast<unsigned int>(j);
310 if (image[j_][i_] > threshold) {
311 double x = 0;
312 double y = 0;
313 vpPixelMeterConversion::convertPoint(cam, i_, j_, x, y);
314
315 double yval = 1.;
316 for (unsigned int k = 0; k < order; k++) {
317 double xval = 1.;
318 for (unsigned int l = 0; l < order - k; l++) {
319 curvals[(k * order + l)] += (xval * yval);
320 xval *= x;
321 }
322 yval *= y;
323 }
324 }
325 }
326 }
327
328#pragma omp master // only set this variable in master thread
329 {
330 values.assign(order * order, 0.);
331 }
332
333#pragma omp barrier
334 for (unsigned int k = 0; k < order; k++) {
335 for (unsigned int l = 0; l < order - k; l++) {
336#pragma omp atomic
337 values[k * order + l] += curvals[k * order + l];
338 }
339 }
340 }
341#else
342 std::vector<double> cache(order * order, 0.);
343 values.assign(order * order, 0);
344 for (unsigned int i = 0; i < image.getCols(); i++) {
345 for (unsigned int j = 0; j < image.getRows(); j++) {
346 if (image[j][i] > threshold) {
347 double x = 0;
348 double y = 0;
350 cacheValues(cache, x, y);
351 for (unsigned int k = 0; k < order; k++) {
352 for (unsigned int l = 0; l < order - k; l++) {
353 values[k * order + l] += cache[k * order + l];
354 }
355 }
356 }
357 }
358 }
359#endif
360
361 // Normalization equivalent to sampling interval/pixel size delX x delY
362 double norm_factor = 1. / (cam.get_px() * cam.get_py());
363 for (std::vector<double>::iterator it = values.begin(); it != values.end(); ++it) {
364 *it = (*it) * norm_factor;
365 }
366}
367
380 vpCameraImgBckGrndType bg_type, bool normalize_with_pix_size)
381{
382 std::vector<double> cache(order * order, 0.);
383 values.assign(order * order, 0);
384
385 // (x,y) - Pixel co-ordinates in metres
386 double x = 0;
387 double y = 0;
388 // for indexing into cache[] and values[]
389 unsigned int idx = 0;
390 unsigned int kidx = 0;
391
392 double intensity = 0;
393
394 // double Imax = static_cast<double>(image.getMaxValue());
395
396 double iscale = 1.0;
397 if (flg_normalize_intensity) { // This makes the image a probability density
398 // function
399 double Imax = 255.; // To check the effect of gray level change. ISR Coimbra
400 iscale = 1.0 / Imax;
401 }
402
403 if (bg_type == vpMomentObject::WHITE) {
405 for (unsigned int j = 0; j < image.getRows(); j++) {
406 for (unsigned int i = 0; i < image.getCols(); i++) {
407 x = 0;
408 y = 0;
409 intensity = static_cast<double>(image[j][i]) * iscale;
410 double intensity_white = 1. - intensity;
411
413 cacheValues(cache, x, y, intensity_white); // Modify 'cache' which has
414 // x^p*y^q to x^p*y^q*(1 -
415 // I(x,y))
416
417 // Copy to "values"
418 for (unsigned int k = 0; k < order; k++) {
419 kidx = k * order;
420 for (unsigned int l = 0; l < order - k; l++) {
421 idx = kidx + l;
422 values[idx] += cache[idx];
423 }
424 }
425 }
426 }
427 }
428 else {
430 for (unsigned int j = 0; j < image.getRows(); j++) {
431 for (unsigned int i = 0; i < image.getCols(); i++) {
432 x = 0;
433 y = 0;
434 intensity = static_cast<double>(image[j][i]) * iscale;
436
437 // Cache values for fast moment calculation
438 cacheValues(cache, x, y,
439 intensity); // Modify 'cache' which has x^p*y^q to x^p*y^q*I(x,y)
440
441 // Copy to moments array 'values'
442 for (unsigned int k = 0; k < order; k++) {
443 kidx = k * order;
444 for (unsigned int l = 0; l < order - k; l++) {
445 idx = kidx + l;
446 values[idx] += cache[idx];
447 }
448 }
449 }
450 }
451 }
452
453 if (normalize_with_pix_size) {
454 // Normalization equivalent to sampling interval/pixel size delX x delY
455 double norm_factor = 1. / (cam.get_px() * cam.get_py());
456 for (std::vector<double>::iterator it = values.begin(); it != values.end(); ++it) {
457 *it = (*it) * norm_factor;
458 }
459 }
460}
461
466void vpMomentObject::init(unsigned int orderinp)
467{
468 order = orderinp + 1;
470 flg_normalize_intensity = true; // By default, the intensity values are normalized
471 values.resize((order + 1) * (order + 1));
472 values.assign((order + 1) * (order + 1), 0);
473}
474
479{
480 order = objin.getOrder() + 1;
481 type = objin.getType();
483 values.resize(objin.values.size());
484 values = objin.values;
485}
486
502vpMomentObject::vpMomentObject(unsigned int max_order)
504{
505 init(max_order);
506}
507
516
538const std::vector<double> &vpMomentObject::get() const { return values; }
539
546double vpMomentObject::get(unsigned int i, unsigned int j) const
547{
548 assert(i + j <= getOrder());
549 if (i + j >= order)
550 throw vpException(vpException::badValue, "The requested value has not "
551 "been computed, you should "
552 "specify a higher order.");
553
554 return values[j * order + i];
555}
556
563void vpMomentObject::set(unsigned int i, unsigned int j, const double &value_ij)
564{
565 assert(i + j <= getOrder());
566 if (i + j >= order)
567 throw vpException(vpException::badValue, "The requested value cannot be set, you should specify "
568 "a higher order for the moment object.");
569 values[j * order + i] = value_ij;
570}
571
577void vpMomentObject::printWithIndices(const vpMomentObject &momobj, std::ostream &os)
578{
579 std::vector<double> moment = momobj.get();
580 os << std::endl << "Order of vpMomentObject: " << momobj.getOrder() << std::endl;
581 // Print out values. This is same as printing using operator <<
582 for (unsigned int k = 0; k <= momobj.getOrder(); k++) {
583 for (unsigned int l = 0; l < (momobj.getOrder() + 1) - k; l++) {
584 os << "m[" << l << "," << k << "] = " << moment[k * (momobj.getOrder() + 1) + l] << "\t";
585 }
586 os << std::endl;
587 }
588 os << std::endl;
589}
590
618{
619 std::vector<double> moment = momobj.get();
620 unsigned int order = momobj.getOrder();
621 vpMatrix M(order + 1, order + 1);
622 for (unsigned int k = 0; k <= order; k++) {
623 for (unsigned int l = 0; l < (order + 1) - k; l++) {
624 M[l][k] = moment[k * (order + 1) + l];
625 }
626 }
627 return M;
628}
629
639{
640 // deliberate empty
641}
642
658VISP_EXPORT std::ostream &operator<<(std::ostream &os, const vpMomentObject &m)
659{
660 for (unsigned int i = 0; i < m.values.size(); ++i) {
661
662 if (i % (m.order) == 0)
663 os << std::endl;
664
665 if ((i % (m.order) + i / (m.order)) < m.order) {
666 os << m.values[i];
667 }
668 else {
669 os << "x";
670 }
671
672 os << "\t";
673 }
674
675 return os;
676}
677END_VISP_NAMESPACE
Generic class defining intrinsic camera parameters.
error that can be emitted by ViSP classes.
Definition vpException.h:60
@ badValue
Used to indicate that a value is not in the allowed range.
Definition vpException.h:73
Definition of the vpImage class member functions.
Definition vpImage.h:131
unsigned int getCols() const
Definition vpImage.h:171
unsigned int getRows() const
Definition vpImage.h:212
static long double comb(unsigned int n, unsigned int p)
Definition vpMath.h:398
Implementation of a matrix and operations on matrices.
Definition vpMatrix.h:175
static void printWithIndices(const vpMomentObject &momobj, std::ostream &os)
unsigned int getOrder() const
VP_EXPLICIT vpMomentObject(unsigned int order)
unsigned int order
virtual ~vpMomentObject()
void cacheValues(std::vector< double > &cache, double x, double y)
vpObjectType type
void set(unsigned int i, unsigned int j, const double &value_ij)
@ WHITE
Not functional right now.
const std::vector< double > & get() const
static vpMatrix convertTovpMatrix(const vpMomentObject &momobj)
std::vector< double > values
vpObjectType getType() const
void fromImage(const vpImage< unsigned char > &image, unsigned char threshold, const vpCameraParameters &cam)
void fromVector(std::vector< vpPoint > &points)
friend VISP_EXPORT std::ostream & operator<<(std::ostream &os, const vpMomentObject &v)
void init(unsigned int orderinp)
static void convertPoint(const vpCameraParameters &cam, const double &u, const double &v, double &x, double &y)