Visual Servoing Platform  version 3.6.1 under development (2024-11-15)
vpMomentCInvariant.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2023 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See https://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Descriptor for various invariants used to drive space rotations around X and
33  *Y axis.
34  *
35  * Authors:
36  * Filip Novotny
37  *
38 *****************************************************************************/
39 
40 #include <visp3/core/vpMomentCInvariant.h>
41 #include <visp3/core/vpMomentCentered.h>
42 #include <visp3/core/vpMomentObject.h>
43 
44 BEGIN_VISP_NAMESPACE
49 vpMomentCInvariant::vpMomentCInvariant(bool flg_sxsynormalization)
50  : I(16), II(4), c(4), s(4), K(0.0), cn(4), sn(4), In1(0.0), flg_sxsynormalization_(flg_sxsynormalization)
51 {
52  values.resize(14);
53 }
54 
60 void vpMomentCInvariant::computeI(const vpMomentCentered &momentCentered, std::vector<double> &I_val)
61 {
62 
63  double mu30 = momentCentered.get(3, 0);
64  double mu30_2 = mu30 * mu30;
65  double mu30_3 = mu30_2 * mu30;
66 
67  double mu03 = momentCentered.get(0, 3);
68  double mu03_2 = mu03 * mu03;
69  double mu03_3 = mu03 * mu03_2;
70 
71  double mu20 = momentCentered.get(2, 0);
72  double mu02 = momentCentered.get(0, 2);
73  double mu50 = momentCentered.get(5, 0);
74  double mu32 = momentCentered.get(3, 2);
75  double mu14 = momentCentered.get(1, 4);
76  double mu05 = momentCentered.get(0, 5);
77  double mu23 = momentCentered.get(2, 3);
78  double mu41 = momentCentered.get(4, 1);
79  double mu40 = momentCentered.get(4, 0);
80  double mu04 = momentCentered.get(0, 4);
81  double mu31 = momentCentered.get(3, 1);
82  double mu13 = momentCentered.get(1, 3);
83  double mu22 = momentCentered.get(2, 2);
84  double mu21 = momentCentered.get(2, 1);
85  double mu12 = momentCentered.get(1, 2);
86  double mu11 = momentCentered.get(1, 1);
87 
88  double mu11_2 = mu11 * mu11;
89  double mu12_2 = mu12 * mu12;
90  double mu21_2 = mu21 * mu21;
91  double mu22_2 = mu22 * mu22;
92  double mu13_2 = mu13 * mu13;
93  double mu31_2 = mu31 * mu31;
94  double mu04_2 = mu04 * mu04;
95  double mu40_2 = mu40 * mu40;
96  double mu21_3 = mu21 * mu21_2;
97  double mu12_3 = mu12_2 * mu12;
98  double mu12_4 = mu12_3 * mu12;
99  double mu21_4 = mu21_2 * mu21_2;
100 
101  // double kappa = mu30_2+mu03_2-3*mu21_2+6*mu21*mu03; //Used in I8
102  // calculation but simplified with MAPLE and found it to be wrong
103  double zeta = mu20 - mu02;
104  double zeta_2 = zeta * zeta;
105  double omicron = (mu03_2 + 3 * mu03 * mu21 + mu30 * (mu30 + 3 * mu12));
106  double omega = mu50 + 2 * mu32 + mu14;
107  double nu = mu05 + 2 * mu23 + mu41;
108  double ro = mu50 - 2 * mu32 - 3 * mu14;
109  double gamma = mu05 - 2 * mu23 - 3 * mu41;
110 
111  double delta = mu50 - 10 * mu32 + 5 * mu14;
112  double phi = mu05 - 10 * mu23 + 5 * mu41;
113  double omega_2 = omega * omega;
114  double nu_2 = nu * nu;
115  double ro_2 = ro * ro;
116  double gamma_2 = gamma * gamma;
117  double delta_2 = delta * delta;
118  double phi_2 = phi * phi;
119 
120  I_val[1] = -mu20 * mu02 + mu11_2;
121  I_val[2] = zeta_2 + 4 * mu11_2;
122  I_val[3] = (mu30 - 3 * mu12) * (mu30 - 3 * mu12) + (mu03 - 3 * mu21) * (mu03 - 3 * mu21);
123  I_val[4] = (mu30 + mu12) * (mu30 + mu12) + (mu21 + mu03) * (mu21 + mu03);
124  I_val[5] = -mu30_2 * mu03_2 + (-4 * mu12_3 + 6 * mu21 * mu12 * mu03) * mu30 - 4 * mu21_3 * mu03 + 3 * mu21_2 * mu12_2;
125  I_val[6] = 3 * mu12_4 + 2 * mu30 * mu12_3 + (3 * mu30_2 - 6 * mu03 * mu21) * mu12_2 -
126  6 * mu30 * mu21 * (mu21 + mu03) * mu12 + 2 * mu30_2 * mu03_2 + 2 * mu21_3 * mu03 + 3 * mu21_2 * mu03_2 +
127  3 * mu21_4;
128  I_val[7] = (3 * mu21 + 2 * mu03) * mu12_3 + 3 * mu30 * (mu03 + 2 * mu21) * mu12_2 -
129  3 * mu21 * (mu30 + mu03 + mu21) * (-mu30 + mu03 + mu21) * mu12 +
130  mu30 * (-mu30_2 * mu03 - 2 * mu21_3 - 3 * mu03 * mu21_2 + mu03_3);
131 // I_val[8]=3*mu21_4-3*mu21_3*mu03+(3*mu03_2+kappa-6*mu12_2)*mu21_2-mu03*(-15*mu12_2+kappa)*mu21-(-3*mu12_2*mu30+(2*kappa-3*mu03_2)*mu12+kappa*mu30)*mu12;
132  I_val[8] = 3 * mu03 * mu21_3 - 2 * mu03_2 * mu21_2 + mu21_2 * mu30_2 + 3 * mu12_2 * mu03 * mu21 -
133  mu03 * mu21 * mu30_2 - mu03_3 * mu21 + 3 * mu12_3 * mu30 - 2 * mu12_2 * mu30_2 + mu12_2 * mu03_2 -
134  mu12 * mu30_3 - mu12 * mu30 * mu03_2 + 3 * mu12 * mu30 * mu21_2 - 6 * mu12 * mu30 * mu03 * mu21;
135  I_val[9] = omicron * omicron;
136 
137  I_val[10] = mu40 * mu04 - 4 * mu31 * mu13 + 3 * mu22_2;
138  I_val[11] = 3 * mu13_2 + 2 * mu31 * mu13 + (-3 * mu40 - 3 * mu04) * mu22 - 2 * mu40 * mu04 + 3 * mu31_2;
139  I_val[12] = 3 * mu04_2 + (2 * mu40 + 12 * mu22) * mu04 + 3 * mu40_2 + 12 * mu40 * mu22 + 16 * mu31 * mu13;
140  I_val[13] = omega_2 + nu_2;
141  I_val[14] = ro_2 + gamma_2;
142  I_val[15] = delta_2 + phi_2;
143 
144  double a;
146  a = momentCentered.get(2, 0) + momentCentered.get(0, 2);
147  else
148  a = getObject().get(0, 0);
149 
150  c[1] = momentCentered.get(2, 0) - momentCentered.get(0, 2);
151  s[1] = 2 * momentCentered.get(1, 1);
152  c[2] = momentCentered.get(0, 3) - 3 * momentCentered.get(2, 1);
153  s[2] = momentCentered.get(3, 0) - 3 * momentCentered.get(1, 2);
154  c[3] = c[1] * c[1] - s[1] * s[1];
155  s[3] = 2 * s[1] * c[1];
156 
157  II[1] = c[1] * c[1] + s[1] * s[1];
158  II[2] = c[2] * c[2] + s[2] * s[2];
159  II[3] = momentCentered.get(2, 0) + momentCentered.get(0, 2);
160 
161  K = (II[1] * (II[3] * sqrt(std::fabs(II[3])))) / sqrt(std::fabs(a));
162 
163  /*
164  * Intermediate quantities required for calculation of normalized version of
165  * Sx and Sy The pij doubles below are the respective centered moment values
166  * mu_ij scaled by mu20 + mu02
167  */
168  double p20 = momentCentered.get(2, 0) / II[3]; // II[3] is the normalization factor for the 2nd order moments
169  double p11 = momentCentered.get(1, 1) / II[3];
170  double p02 = momentCentered.get(0, 2) / II[3];
171 
172  double d =
173  sqrt(std::fabs(a)) / (II[3] * sqrt(std::fabs(II[3]))); // d is the normalization factor for 3rd order moments
174  double p30 = momentCentered.get(3, 0) * d;
175  double p21 = momentCentered.get(2, 1) * d;
176  double p12 = momentCentered.get(1, 2) * d;
177  double p03 = momentCentered.get(0, 3) * d;
178 
179  cn[1] = p20 - p02;
180  sn[1] = 2.0 * p11;
181  sn[2] = p30 - 3.0 * p12;
182  cn[2] = p03 - 3.0 * p21;
183 
184  cn[3] = cn[1] * cn[1] - sn[1] * sn[1];
185  sn[3] = 2.0 * sn[1] * cn[1];
186 
187  In1 = cn[1] * cn[1] + sn[1] * sn[1];
188 }
189 
197 {
198  if (getObject().getOrder() < 5)
199  throw vpException(vpException::notInitialized, "Order is not high enough for vpMomentCInvariant. "
200  "Specify at least order 5.");
201  bool found_moment_centered;
202  const vpMomentCentered &momentCentered =
203  (static_cast<const vpMomentCentered &>(getMoments().get("vpMomentCentered", found_moment_centered)));
204 
205  if (!found_moment_centered)
206  throw vpException(vpException::notInitialized, "vpMomentCentered not found");
207 
208  computeI(momentCentered, I);
209  double II3_2 = II[3] * II[3];
210  double II3_3 = II3_2 * II[3];
211 
212  double a;
213  if (getObject().getType() == vpMomentObject::DISCRETE)
214  a = momentCentered.get(2, 0) + momentCentered.get(0, 2);
215  else
216  a = getObject().get(0, 0);
217 
218  values[0] = I[1] / I[2];
219  values[1] = I[3] / I[4];
220 
221  values[2] = I[5] / I[6];
222 
223  values[3] = I[7] / I[6];
224 
225  values[4] = I[8] / I[6];
226 
227  values[5] = I[9] / I[6];
228 
229  values[6] = I[11] / I[10];
230 
231  values[7] = I[12] / I[10];
232 
233  values[8] = I[13] / I[15];
234 
235  values[9] = I[14] / I[15];
236 
237  if (flg_sxsynormalization_)
238  calcSxSyNormalized(values[10], values[11]);
239  else
240  calcSxSy(values[10], values[11]);
241 
242  values[12] = II[1] / (II3_2); // Px
243  values[13] = a * II[2] / (II3_3); // Py
244 }
245 
249 void vpMomentCInvariant::calcSxSy(double &sx, double &sy) const
250 {
251  sx = (c[2] * c[3] + s[2] * s[3]) / K;
252  sy = (s[2] * c[3] - c[2] * s[3]) / K;
253 }
254 
260 void vpMomentCInvariant::calcSxSyNormalized(double &sx, double &sy) const
261 {
262  sx = (cn[2] * cn[3] + sn[2] * sn[3]) / In1;
263  sy = (sn[2] * cn[3] - cn[2] * sn[3]) / In1;
264 }
265 
270 void vpMomentCInvariant::printI(unsigned int index) { std::cout << "I(" << index << ")=" << I[index] << std::endl; }
271 
277 void vpMomentCInvariant::printInvariants(std::ostream &os) const
278 {
279  for (unsigned int i = 1; i < I.size(); ++i) { // i = 1 since vector I has been indexed from 1 in
280  // vpMomentCinvariant
281  os << "I[" << i << "]=" << I[i] << std::endl;
282  }
283  os << std::endl;
284 }
285 
289 VISP_EXPORT std::ostream &operator<<(std::ostream &os, const vpMomentCInvariant &c)
290 {
291  for (unsigned int i = 0; i < c.values.size(); i++) {
292  os << c.values[i] << "," << std::endl;
293  }
294  return os;
295 }
296 END_VISP_NAMESPACE
friend std::ostream & operator<<(std::ostream &s, const vpArray2D< Type > &A)
Definition: vpArray2D.h:614
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
VP_EXPLICIT vpMomentCInvariant(bool flg_sxsynormalization=false)
void printI(unsigned int index)
void printInvariants(std::ostream &os) const
This class defines the double-indexed centered moment descriptor .
double get(unsigned int i, unsigned int j) const
const vpMoment & get(const std::string &moment_name, bool &found) const
const std::vector< double > & get() const
vpObjectType getType() const
std::vector< double > values
Definition: vpMoment.h:113
const vpMomentObject & getObject() const
Definition: vpMoment.h:145
vpMomentDatabase & getMoments() const
Definition: vpMoment.h:118