Visual Servoing Platform  version 3.3.0 under development (2020-02-17)
vpCircle.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 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 http://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  * Visual feature circle.
33  *
34  * Authors:
35  * Eric Marchand
36  *
37  *****************************************************************************/
38 
39 #include <visp3/core/vpCircle.h>
40 
41 #include <visp3/core/vpFeatureDisplay.h>
42 
44 {
45 
46  oP.resize(7);
47  cP.resize(7);
48 
49  p.resize(5);
50 }
51 
61 void vpCircle::setWorldCoordinates(const vpColVector &oP_) { this->oP = oP_; }
62 
75 void vpCircle::setWorldCoordinates(double A, double B, double C, double X0, double Y0, double Z0, double R)
76 {
77  oP[0] = A;
78  oP[1] = B;
79  oP[2] = C;
80  oP[3] = X0;
81  oP[4] = Y0;
82  oP[5] = Z0;
83  oP[6] = R;
84 }
85 
87 
99 {
100  init();
101  setWorldCoordinates(oP_);
102 }
103 
117 vpCircle::vpCircle(double A, double B, double C, double X0, double Y0, double Z0, double R)
118 {
119  init();
120  setWorldCoordinates(A, B, C, X0, Y0, Z0, R);
121 }
122 
124 
137 
155 {
156  vpColVector K(6);
157  {
158  double A = cP_[0];
159  double B = cP_[1];
160  double C = cP_[2];
161 
162  double X0 = cP_[3];
163  double Y0 = cP_[4];
164  double Z0 = cP_[5];
165 
166  double r = cP_[6];
167 
168  // projection
169  double s = X0 * X0 + Y0 * Y0 + Z0 * Z0 - r * r;
170  double det = A * X0 + B * Y0 + C * Z0;
171  A = A / det;
172  B = B / det;
173  C = C / det;
174 
175  K[0] = 1 - 2 * A * X0 + A * A * s;
176  K[1] = 1 - 2 * B * Y0 + B * B * s;
177  K[2] = -A * Y0 - B * X0 + A * B * s;
178  K[3] = -C * X0 - A * Z0 + A * C * s;
179  K[4] = -C * Y0 - B * Z0 + B * C * s;
180  K[5] = 1 - 2 * C * Z0 + C * C * s;
181  }
182 
183  // {
184  // std::cout << "K dans vpCircle::projection(): " << std::endl;
185  // for (unsigned int i=1; i<6; i++)
186  // std::cout << K[i]/K[0] << std::endl;
187  // }
188  double det = K[2] * K[2] - K[0] * K[1];
189  if (fabs(det) < 1e-8) {
190  vpERROR_TRACE("division par 0");
191  throw(vpException(vpException::divideByZeroError, "division par 0"));
192  }
193 
194  double xc = (K[1] * K[3] - K[2] * K[4]) / det;
195  double yc = (K[0] * K[4] - K[2] * K[3]) / det;
196 
197  double c = sqrt((K[0] - K[1]) * (K[0] - K[1]) + 4 * K[2] * K[2]);
198  double s = 2 * (K[0] * xc * xc + 2 * K[2] * xc * yc + K[1] * yc * yc - K[5]);
199 
200  double A, B, E;
201 
202  // if (fabs(K[2])<1e-6)
203  if (fabs(K[2]) < std::numeric_limits<double>::epsilon()) {
204  E = 0.0;
205  if (K[0] > K[1]) {
206  A = sqrt(s / (K[0] + K[1] + c));
207  B = sqrt(s / (K[0] + K[1] - c));
208  } else {
209  A = sqrt(s / (K[0] + K[1] - c));
210  B = sqrt(s / (K[0] + K[1] + c));
211  }
212  } else {
213  E = (K[1] - K[0] + c) / (2 * K[2]);
214  if (fabs(E) > 1.0) {
215  A = sqrt(s / (K[0] + K[1] + c));
216  B = sqrt(s / (K[0] + K[1] - c));
217  } else {
218  A = sqrt(s / (K[0] + K[1] - c));
219  B = sqrt(s / (K[0] + K[1] + c));
220  E = -1.0 / E;
221  }
222  }
223 
224  det = (1.0 + vpMath::sqr(E));
225  double mu20 = (vpMath::sqr(A) + vpMath::sqr(B * E)) / det;
226  double mu11 = (vpMath::sqr(A) - vpMath::sqr(B)) * E / det;
227  double mu02 = (vpMath::sqr(B) + vpMath::sqr(A * E)) / det;
228 
229  p_[0] = xc;
230  p_[1] = yc;
231  p_[2] = mu20;
232  p_[3] = mu11;
233  p_[4] = mu02;
234 }
235 
238 {
239 
240  double A, B, C;
241  A = cMo[0][0] * oP[0] + cMo[0][1] * oP[1] + cMo[0][2] * oP[2];
242  B = cMo[1][0] * oP[0] + cMo[1][1] * oP[1] + cMo[1][2] * oP[2];
243  C = cMo[2][0] * oP[0] + cMo[2][1] * oP[1] + cMo[2][2] * oP[2];
244 
245  double X0, Y0, Z0;
246  X0 = cMo[0][3] + cMo[0][0] * oP[3] + cMo[0][1] * oP[4] + cMo[0][2] * oP[5];
247  Y0 = cMo[1][3] + cMo[1][0] * oP[3] + cMo[1][1] * oP[4] + cMo[1][2] * oP[5];
248  Z0 = cMo[2][3] + cMo[2][0] * oP[3] + cMo[2][1] * oP[4] + cMo[2][2] * oP[5];
249  double R = oP[6];
250 
251  cP_[0] = A;
252  cP_[1] = B;
253  cP_[2] = C;
254 
255  cP_[3] = X0;
256  cP_[4] = Y0;
257  cP_[5] = Z0;
258 
259  cP_[6] = R;
260 
261  // vpTRACE("_cP :") ; std::cout << _cP.t() ;
262 }
263 
266 {
267 
268  double A, B, C;
269  A = cMo[0][0] * oP[0] + cMo[0][1] * oP[1] + cMo[0][2] * oP[2];
270  B = cMo[1][0] * oP[0] + cMo[1][1] * oP[1] + cMo[1][2] * oP[2];
271  C = cMo[2][0] * oP[0] + cMo[2][1] * oP[1] + cMo[2][2] * oP[2];
272 
273  double X0, Y0, Z0;
274  X0 = cMo[0][3] + cMo[0][0] * oP[3] + cMo[0][1] * oP[4] + cMo[0][2] * oP[5];
275  Y0 = cMo[1][3] + cMo[1][0] * oP[3] + cMo[1][1] * oP[4] + cMo[1][2] * oP[5];
276  Z0 = cMo[2][3] + cMo[2][0] * oP[3] + cMo[2][1] * oP[4] + cMo[2][2] * oP[5];
277  double R = oP[6];
278 
279  cP[0] = A;
280  cP[1] = B;
281  cP[2] = C;
282 
283  cP[3] = X0;
284  cP[4] = Y0;
285  cP[5] = Z0;
286 
287  cP[6] = R;
288 
289  // vpTRACE("_cP :") ; std::cout << _cP.t() ;
290 }
291 
292 void vpCircle::display(const vpImage<unsigned char> &I, const vpCameraParameters &cam, const vpColor &color,
293  unsigned int thickness)
294 {
295  vpFeatureDisplay::displayEllipse(p[0], p[1], p[2], p[3], p[4], cam, I, color, thickness);
296 }
297 
298 // non destructive wrt. cP and p
300  const vpColor &color, unsigned int thickness)
301 {
302  vpColVector _cP, _p;
303  changeFrame(cMo, _cP);
304  projection(_cP, _p);
305  vpFeatureDisplay::displayEllipse(_p[0], _p[1], _p[2], _p[3], _p[4], cam, I, color, thickness);
306 }
309 {
310  vpCircle *feature = new vpCircle(*this);
311  return feature;
312 }
313 
330 void vpCircle::computeIntersectionPoint(const vpCircle &circle, const vpCameraParameters &cam, const double &rho,
331  const double &theta, double &i, double &j)
332 {
333  // This was taken from the code of art-v1. (from the artCylinder class)
334  double px = cam.get_px();
335  double py = cam.get_py();
336  double u0 = cam.get_u0();
337  double v0 = cam.get_v0();
338 
339  double mu11 = circle.p[3];
340  double mu02 = circle.p[4];
341  double mu20 = circle.p[2];
342  double Xg = u0 + circle.p[0] * px;
343  double Yg = v0 + circle.p[1] * py;
344 
345  // Find Intersection between line and ellipse in the image.
346 
347  // Optimised calculation for X
348  double stheta = sin(theta);
349  double ctheta = cos(theta);
350  double sctheta = stheta * ctheta;
351  double m11yg = mu11 * Yg;
352  double ctheta2 = vpMath::sqr(ctheta);
353  double m02xg = mu02 * Xg;
354  double m11stheta = mu11 * stheta;
355  j = ((mu11 * Xg * sctheta - mu20 * Yg * sctheta + mu20 * rho * ctheta - m11yg + m11yg * ctheta2 + m02xg -
356  m02xg * ctheta2 + m11stheta * rho) /
357  (mu20 * ctheta2 + 2.0 * m11stheta * ctheta + mu02 - mu02 * ctheta2));
358  // Optimised calculation for Y
359  double rhom02 = rho * mu02;
360  double sctheta2 = stheta * ctheta2;
361  double ctheta3 = ctheta2 * ctheta;
362  i = (-(-rho * mu11 * stheta * ctheta - rhom02 + rhom02 * ctheta2 + mu11 * Xg * sctheta2 - mu20 * Yg * sctheta2 -
363  ctheta * mu11 * Yg + ctheta3 * mu11 * Yg + ctheta * mu02 * Xg - ctheta3 * mu02 * Xg) /
364  (mu20 * ctheta2 + 2.0 * mu11 * stheta * ctheta + mu02 - mu02 * ctheta2) / stheta);
365 }
void init()
Definition: vpCircle.cpp:43
void display(const vpImage< unsigned char > &I, const vpCameraParameters &cam, const vpColor &color=vpColor::green, unsigned int thickness=1)
Definition: vpCircle.cpp:292
static void displayEllipse(double x, double y, double mu20, double mu11, double m02, const vpCameraParameters &cam, const vpImage< unsigned char > &I, const vpColor &color=vpColor::green, unsigned int thickness=1)
void changeFrame(const vpHomogeneousMatrix &cMo, vpColVector &cP)
perspective projection of the circle
Definition: vpCircle.cpp:237
Implementation of an homogeneous matrix and operations on such kind of matrices.
#define vpERROR_TRACE
Definition: vpDebug.h:393
Class to define colors available for display functionnalities.
Definition: vpColor.h:119
error that can be emited by ViSP classes.
Definition: vpException.h:71
virtual ~vpCircle()
Definition: vpCircle.cpp:123
vpColVector cP
Definition: vpTracker.h:75
void projection()
Definition: vpCircle.cpp:136
vpCircle()
Definition: vpCircle.cpp:86
static double sqr(double x)
Definition: vpMath.h:114
static void computeIntersectionPoint(const vpCircle &circle, const vpCameraParameters &cam, const double &rho, const double &theta, double &i, double &j)
Definition: vpCircle.cpp:330
Generic class defining intrinsic camera parameters.
void resize(unsigned int i, bool flagNullify=true)
Definition: vpColVector.h:310
vpCircle * duplicate() const
for memory issue (used by the vpServo class only)
Definition: vpCircle.cpp:308
Implementation of column vector and the associated operations.
Definition: vpColVector.h:130
Class that defines what is a circle.
Definition: vpCircle.h:58
vpColVector p
Definition: vpTracker.h:71
void setWorldCoordinates(const vpColVector &oP)
Definition: vpCircle.cpp:61