Visual Servoing Platform  version 3.6.1 under development (2024-05-21)
vpPixelMeterConversion.h
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2023 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  * Pixel to meter conversion.
32  */
33 
34 #ifndef _vpPixelMeterConversion_h_
35 #define _vpPixelMeterConversion_h_
36 
42 #include <visp3/core/vpCameraParameters.h>
43 #include <visp3/core/vpDebug.h>
44 #include <visp3/core/vpException.h>
45 #include <visp3/core/vpImagePoint.h>
46 #include <visp3/core/vpMath.h>
47 
48 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_CALIB3D) && defined(HAVE_OPENCV_IMGPROC)
49 #include <opencv2/calib3d/calib3d.hpp>
50 #include <opencv2/imgproc/imgproc.hpp>
51 #endif
52 
65 class VISP_EXPORT vpPixelMeterConversion
66 {
67 public:
70  static void convertEllipse(const vpCameraParameters &cam, const vpImagePoint &center_p, double n20_p, double n11_p,
71  double n02_p, double &xc_m, double &yc_m, double &n20_m, double &n11_m, double &n02_m);
72  static void convertLine(const vpCameraParameters &cam, const double &rho_p, const double &theta_p, double &rho_m,
73  double &theta_m);
74 
75  static void convertMoment(const vpCameraParameters &cam, unsigned int order, const vpMatrix &moment_pixel,
76  vpMatrix &moment_meter);
102  inline static void convertPoint(const vpCameraParameters &cam, const double &u, const double &v, double &x, double &y)
103  {
104  switch (cam.m_projModel) {
106  convertPointWithoutDistortion(cam, u, v, x, y);
107  break;
109  convertPointWithDistortion(cam, u, v, x, y);
110  break;
112  convertPointWithKannalaBrandtDistortion(cam, u, v, x, y);
113  break;
114  default:
115  std::cerr << "projection model not identified" << std::endl;
116  }
117  }
118 
146  inline static void convertPoint(const vpCameraParameters &cam, const vpImagePoint &iP, double &x, double &y)
147  {
148  switch (cam.m_projModel) {
150  convertPointWithoutDistortion(cam, iP, x, y);
151  break;
153  convertPointWithDistortion(cam, iP, x, y);
154  break;
156  convertPointWithKannalaBrandtDistortion(cam, iP, x, y);
157  break;
158  default:
159  std::cerr << "projection model not identified" << std::endl;
160  }
161  }
162 
163 #ifndef DOXYGEN_SHOULD_SKIP_THIS
176  inline static void convertPointWithoutDistortion(const vpCameraParameters &cam, const double &u, const double &v,
177  double &x, double &y)
178  {
179  x = (u - cam.m_u0) * cam.m_inv_px;
180  y = (v - cam.m_v0) * cam.m_inv_py;
181  }
182 
198  inline static void convertPointWithoutDistortion(const vpCameraParameters &cam, const vpImagePoint &iP, double &x,
199  double &y)
200  {
201  x = (iP.get_u() - cam.m_u0) * cam.m_inv_px;
202  y = (iP.get_v() - cam.m_v0) * cam.m_inv_py;
203  }
204 
219  inline static void convertPointWithDistortion(const vpCameraParameters &cam, const double &u, const double &v,
220  double &x, double &y)
221  {
222  double r2 = 1. + (cam.m_kdu * (vpMath::sqr((u - cam.m_u0) * cam.m_inv_px) + vpMath::sqr((v - cam.m_v0) * cam.m_inv_py)));
223  x = (u - cam.m_u0) * r2 * cam.m_inv_px;
224  y = (v - cam.m_v0) * r2 * cam.m_inv_py;
225  }
226 
243  inline static void convertPointWithDistortion(const vpCameraParameters &cam, const vpImagePoint &iP, double &x,
244  double &y)
245  {
246  double r2 = 1. + (cam.m_kdu * (vpMath::sqr((iP.get_u() - cam.m_u0) * cam.m_inv_px) +
247  vpMath::sqr((iP.get_v() - cam.m_v0) * cam.m_inv_py)));
248  x = (iP.get_u() - cam.m_u0) * r2 * cam.m_inv_px;
249  y = (iP.get_v() - cam.m_v0) * r2 * cam.m_inv_py;
250  }
251 
272  inline static void convertPointWithKannalaBrandtDistortion(const vpCameraParameters &cam, const double &u,
273  const double &v, double &x, double &y)
274  {
275  double x_d = (u - cam.m_u0) / cam.m_px, y_d = (v - cam.m_v0) / cam.m_py;
276  double scale = 1.0;
277  double r_d = sqrt(vpMath::sqr(x_d) + vpMath::sqr(y_d));
278 
279  r_d = std::min<double>(std::max<double>(-M_PI, r_d), M_PI); // FOV restricted to 180degrees.
280 
281  std::vector<double> k = cam.getKannalaBrandtDistortionCoefficients();
282 
283  const double EPS = 1e-8;
284  // Use Newton-Raphson method to solve for the angle theta
285  if (r_d > EPS) {
286  // compensate distortion iteratively
287  double theta = r_d;
288 
289  for (int j = 0; j < 10; ++j) {
290  double theta2 = theta * theta, theta4 = theta2 * theta2, theta6 = theta4 * theta2, theta8 = theta6 * theta2;
291  double k0_theta2 = k[0] * theta2, k1_theta4 = k[1] * theta4, k2_theta6 = k[2] * theta6,
292  k3_theta8 = k[3] * theta8;
293  /*
294  // new_theta = theta - theta_fix, theta_fix = f0(theta) / f0'(theta)
295  */
296  double theta_fix = (theta * (1 + k0_theta2 + k1_theta4 + k2_theta6 + k3_theta8) - r_d) /
297  (1 + 3 * k0_theta2 + 5 * k1_theta4 + 7 * k2_theta6 + 9 * k3_theta8);
298  theta = theta - theta_fix;
299  if (fabs(theta_fix) < EPS) {
300  break;
301  }
302  }
303 
304  scale = std::tan(theta) / r_d; // Scale of norm of (x,y) and (x_d, y_d)
305  }
306 
307  x = x_d * scale;
308  y = y_d * scale;
309  }
310 
330  inline static void convertPointWithKannalaBrandtDistortion(const vpCameraParameters &cam, const vpImagePoint &iP,
331  double &x, double &y)
332  {
333  double x_d = (iP.get_u() - cam.m_u0) / cam.m_px, y_d = (iP.get_v() - cam.m_v0) / cam.m_py;
334  double scale = 1.0;
335  double r_d = sqrt(vpMath::sqr(x_d) + vpMath::sqr(y_d));
336 
337  r_d = std::min<double>(std::max<double>(-M_PI, r_d), M_PI); // FOV restricted to 180degrees.
338 
339  std::vector<double> k = cam.getKannalaBrandtDistortionCoefficients();
340 
341  const double EPS = 1e-8;
342  // Use Newton-Raphson method to solve for the angle theta
343  if (r_d > EPS) {
344  // compensate distortion iteratively
345  double theta = r_d;
346 
347  for (int j = 0; j < 10; ++j) {
348  double theta2 = theta * theta, theta4 = theta2 * theta2, theta6 = theta4 * theta2, theta8 = theta6 * theta2;
349  double k0_theta2 = k[0] * theta2, k1_theta4 = k[1] * theta4, k2_theta6 = k[2] * theta6,
350  k3_theta8 = k[3] * theta8;
351  /*
352  // new_theta = theta - theta_fix, theta_fix = f0(theta) / f0'(theta)
353  */
354  double theta_fix = ((theta * (1 + k0_theta2 + k1_theta4 + k2_theta6 + k3_theta8)) - r_d) /
355  (1 + (3 * k0_theta2) + (5 * k1_theta4) + (7 * k2_theta6) + (9 * k3_theta8));
356  theta = theta - theta_fix;
357  if (fabs(theta_fix) < EPS)
358  break;
359  }
360 
361  scale = std::tan(theta) / r_d; // Scale of norm of (x,y) and (x_d, y_d)
362  }
363 
364  x = x_d * scale;
365  y = y_d * scale;
366  }
367 #endif // #ifndef DOXYGEN_SHOULD_SKIP_THIS
369 
370 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_CALIB3D) && defined(HAVE_OPENCV_IMGPROC)
373  static void convertEllipse(const cv::Mat &cameraMatrix, const cv::Mat &distCoeffs, const vpImagePoint &center_p,
374  double n20_p, double n11_p, double n02_p, double &xc_m, double &yc_m, double &n20_m,
375  double &n11_m, double &n02_m);
376  static void convertLine(const cv::Mat &cameraMatrix, const double &rho_p, const double &theta_p, double &rho_m,
377  double &theta_m);
378  static void convertMoment(const cv::Mat &cameraMatrix, unsigned int order, const vpMatrix &moment_pixel,
379  vpMatrix &moment_meter);
380  static void convertPoint(const cv::Mat &cameraMatrix, const cv::Mat &distCoeffs, const double &u, const double &v,
381  double &x, double &y);
382  static void convertPoint(const cv::Mat &cameraMatrix, const cv::Mat &distCoeffs, const vpImagePoint &iP, double &x,
383  double &y);
385 #endif
386 };
387 
388 #endif
Generic class defining intrinsic camera parameters.
std::vector< double > getKannalaBrandtDistortionCoefficients() const
@ perspectiveProjWithDistortion
Perspective projection with distortion model.
@ ProjWithKannalaBrandtDistortion
Projection with Kannala-Brandt distortion model.
@ perspectiveProjWithoutDistortion
Perspective projection without distortion model.
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_u() const
Definition: vpImagePoint.h:136
double get_v() const
Definition: vpImagePoint.h:147
static double sqr(double x)
Definition: vpMath.h:201
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:146
static void convertPoint(const vpCameraParameters &cam, const vpImagePoint &iP, double &x, double &y)
static void convertPoint(const vpCameraParameters &cam, const double &u, const double &v, double &x, double &y)