Visual Servoing Platform  version 3.6.1 under development (2024-04-26)
vpPixelMeterConversion.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  * Pixel to meter conversion.
33  *
34 *****************************************************************************/
35 
40 #include <visp3/core/vpCameraParameters.h>
41 #include <visp3/core/vpDebug.h>
42 #include <visp3/core/vpException.h>
43 #include <visp3/core/vpMath.h>
44 #include <visp3/core/vpPixelMeterConversion.h>
45 
56 void vpPixelMeterConversion::convertEllipse(const vpCameraParameters &cam, const vpImagePoint &center_p, double n20_p,
57  double n11_p, double n02_p, double &xc_m, double &yc_m, double &n20_m,
58  double &n11_m, double &n02_m)
59 {
60  vpPixelMeterConversion::convertPoint(cam, center_p, xc_m, yc_m);
61  double px = cam.get_px();
62  double py = cam.get_py();
63 
64  n20_m = n20_p / (px * px);
65  n11_m = n11_p / (px * py);
66  n02_m = n02_p / (py * py);
67 }
68 
78 void vpPixelMeterConversion::convertLine(const vpCameraParameters &cam, const double &rho_p, const double &theta_p,
79  double &rho_m, double &theta_m)
80 {
81  double co = cos(theta_p);
82  double si = sin(theta_p);
83  double d = vpMath::sqr(cam.m_px * co) + vpMath::sqr(cam.m_py * si);
84 
85  if (fabs(d) < 1e-6) {
86  vpERROR_TRACE("division by zero");
87  throw(vpException(vpException::divideByZeroError, "division by zero"));
88  }
89  theta_m = atan2(si * cam.m_py, co * cam.m_px);
90  rho_m = (rho_p - (cam.m_u0 * co) - (cam.m_v0 * si)) / sqrt(d);
91 }
92 
130 void vpPixelMeterConversion::convertMoment(const vpCameraParameters &cam, unsigned int order,
131  const vpMatrix &moment_pixel, vpMatrix &moment_meter)
132 {
133  vpMatrix m(order, order);
134  double yc = -cam.m_v0;
135  double xc = -cam.m_u0;
136 
137  for (unsigned int k = 0; k < order; ++k) { // iteration correspondant e l'ordre du moment
138  for (unsigned int p = 0; p < order; ++p) { // iteration en X
139  for (unsigned int q = 0; q < order; ++q) { // iteration en Y
140  if ((p + q) == k) { // on est bien dans la matrice triangulaire superieure
141  m[p][q] = 0; // initialisation e 0
142  for (unsigned int r = 0; r <= p; ++r) { // somme externe
143  for (unsigned int t = 0; t <= q; ++t) { // somme interne
144  m[p][q] += static_cast<double>(vpMath::comb(p, r)) * static_cast<double>(vpMath::comb(q, t)) *
145  pow(xc, static_cast<int>(p - r)) * pow(yc, static_cast<int>(q - t)) * moment_pixel[r][t];
146  }
147  }
148  }
149  }
150  }
151  }
152 
153  for (unsigned int k = 0; k < order; ++k) { // iteration correspondant e l'ordre du moment
154  for (unsigned int p = 0; p < order; ++p) {
155  for (unsigned int q = 0; q < order; ++q) {
156  if ((p + q) == k) {
157  m[p][q] *= pow(cam.m_inv_px, static_cast<int>(1 + p)) * pow(cam.m_inv_py, static_cast<int>(1 + q));
158  }
159  }
160  }
161  }
162 
163  for (unsigned int k = 0; k < order; ++k) { // iteration correspondant e l'ordre du moment
164  for (unsigned int p = 0; p < order; ++p) {
165  for (unsigned int q = 0; q < order; ++q) {
166  if ((p + q) == k) {
167  moment_meter[p][q] = m[p][q];
168  }
169  }
170  }
171  }
172 }
173 
174 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_CALIB3D) && defined(HAVE_OPENCV_IMGPROC)
188 void vpPixelMeterConversion::convertEllipse(const cv::Mat &cameraMatrix, const cv::Mat &distCoeffs,
189  const vpImagePoint &center_p, double n20_p, double n11_p, double n02_p,
190  double &xc_m, double &yc_m, double &n20_m, double &n11_m, double &n02_m)
191 {
192  vpPixelMeterConversion::convertPoint(cameraMatrix, distCoeffs, center_p, xc_m, yc_m);
193  double px = cameraMatrix.at<double>(0, 0);
194  double py = cameraMatrix.at<double>(1, 1);
195 
196  n20_m = n20_p / (px * px);
197  n11_m = n11_p / (px * py);
198  n02_m = n02_p / (py * py);
199 }
200 
210 void vpPixelMeterConversion::convertLine(const cv::Mat &cameraMatrix, const double &rho_p, const double &theta_p,
211  double &rho_m, double &theta_m)
212 {
213  double co = cos(theta_p);
214  double si = sin(theta_p);
215  double px = cameraMatrix.at<double>(0, 0);
216  double py = cameraMatrix.at<double>(1, 1);
217  double u0 = cameraMatrix.at<double>(0, 2);
218  double v0 = cameraMatrix.at<double>(1, 2);
219 
220  double d = vpMath::sqr(px * co) + vpMath::sqr(py * si);
221 
222  if (fabs(d) < 1e-6) {
223  vpERROR_TRACE("division by zero");
224  throw(vpException(vpException::divideByZeroError, "division by zero"));
225  }
226  theta_m = atan2(si * py, co * px);
227  rho_m = (rho_p - u0 * co - v0 * si) / sqrt(d);
228 }
229 
240 void vpPixelMeterConversion::convertMoment(const cv::Mat &cameraMatrix, unsigned int order,
241  const vpMatrix &moment_pixel, vpMatrix &moment_meter)
242 {
243  double inv_px = 1. / cameraMatrix.at<double>(0, 0);
244  double inv_py = 1. / cameraMatrix.at<double>(1, 1);
245  double u0 = cameraMatrix.at<double>(0, 2);
246  double v0 = cameraMatrix.at<double>(1, 2);
247 
248  vpMatrix m(order, order);
249  double yc = -v0;
250  double xc = -u0;
251 
252  for (unsigned int k = 0; k < order; ++k) { // iteration correspondant e l'ordre du moment
253  for (unsigned int p = 0; p < order; ++p) { // iteration en X
254  for (unsigned int q = 0; q < order; ++q) { // iteration en Y
255  if (p + q == k) { // on est bien dans la matrice triangulaire superieure
256  m[p][q] = 0; // initialisation e 0
257  for (unsigned int r = 0; r <= p; ++r) { // somme externe
258  for (unsigned int t = 0; t <= q; ++t) { // somme interne
259  m[p][q] += static_cast<double>(vpMath::comb(p, r)) * static_cast<double>(vpMath::comb(q, t)) *
260  pow(xc, static_cast<int>(p - r)) * pow(yc, static_cast<int>(q - t)) * moment_pixel[r][t];
261  }
262  }
263  }
264  }
265  }
266  }
267 
268  for (unsigned int k = 0; k < order; ++k) { // iteration correspondant e l'ordre du moment
269  for (unsigned int p = 0; p < order; ++p) {
270  for (unsigned int q = 0; q < order; ++q) {
271  if (p + q == k) {
272  m[p][q] *= pow(inv_px, static_cast<int>(1 + p)) * pow(inv_py, static_cast<int>(1 + q));
273  }
274  }
275  }
276  }
277 
278  for (unsigned int k = 0; k < order; ++k) { // iteration correspondant e l'ordre du moment
279  for (unsigned int p = 0; p < order; ++p) {
280  for (unsigned int q = 0; q < order; ++q) {
281  if (p + q == k) {
282  moment_meter[p][q] = m[p][q];
283  }
284  }
285  }
286  }
287 }
288 
303 void vpPixelMeterConversion::convertPoint(const cv::Mat &cameraMatrix, const cv::Mat &distCoeffs, const double &u,
304  const double &v, double &x, double &y)
305 {
306  std::vector<cv::Point2d> imagePoints_vec;
307  imagePoints_vec.push_back(cv::Point2d(u, v));
308  std::vector<cv::Point2d> objectPoints_vec;
309  cv::undistortPoints(imagePoints_vec, objectPoints_vec, cameraMatrix, distCoeffs);
310  x = objectPoints_vec[0].x;
311  y = objectPoints_vec[0].y;
312 }
313 
327 void vpPixelMeterConversion::convertPoint(const cv::Mat &cameraMatrix, const cv::Mat &distCoeffs,
328  const vpImagePoint &iP, double &x, double &y)
329 {
330  std::vector<cv::Point2d> imagePoints_vec;
331  imagePoints_vec.push_back(cv::Point2d(iP.get_u(), iP.get_v()));
332  std::vector<cv::Point2d> objectPoints_vec;
333  cv::undistortPoints(imagePoints_vec, objectPoints_vec, cameraMatrix, distCoeffs);
334  x = objectPoints_vec[0].x;
335  y = objectPoints_vec[0].y;
336 }
337 
338 #endif
Generic class defining intrinsic camera parameters.
error that can be emitted by ViSP classes.
Definition: vpException.h:59
@ divideByZeroError
Division by zero.
Definition: vpException.h:82
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
static long double comb(unsigned int n, unsigned int p)
Definition: vpMath.h:389
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:146
static void convertEllipse(const vpCameraParameters &cam, const vpImagePoint &center_p, double n20_p, double n11_p, double n02_p, double &xc_m, double &yc_m, double &n20_m, double &n11_m, double &n02_m)
static void convertMoment(const vpCameraParameters &cam, unsigned int order, const vpMatrix &moment_pixel, vpMatrix &moment_meter)
static void convertLine(const vpCameraParameters &cam, const double &rho_p, const double &theta_p, double &rho_m, double &theta_m)
static void convertPoint(const vpCameraParameters &cam, const double &u, const double &v, double &x, double &y)
#define vpERROR_TRACE
Definition: vpDebug.h:382