Visual Servoing Platform  version 3.6.1 under development (2025-02-06)
vpPixelMeterConversion.cpp
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2024 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 
38 #include <visp3/core/vpCameraParameters.h>
39 #include <visp3/core/vpException.h>
40 #include <visp3/core/vpMath.h>
41 #include <visp3/core/vpPixelMeterConversion.h>
42 
43 #if defined(HAVE_OPENCV_IMGPROC) && \
44  (((VISP_HAVE_OPENCV_VERSION < 0x050000) && defined(HAVE_OPENCV_CALIB3D)) || ((VISP_HAVE_OPENCV_VERSION >= 0x050000) && defined(HAVE_OPENCV_CALIB) && defined(HAVE_OPENCV_3D)))
45 
46 #if (VISP_HAVE_OPENCV_VERSION < 0x050000)
47 #include <opencv2/calib3d/calib3d.hpp>
48 #endif
49 
50 #if (VISP_HAVE_OPENCV_VERSION >= 0x050000)
51 #include <opencv2/calib.hpp>
52 #include <opencv2/3d.hpp>
53 #endif
54 
55 #include <opencv2/imgproc/imgproc.hpp>
56 #endif
57 
58 BEGIN_VISP_NAMESPACE
69  void vpPixelMeterConversion::convertEllipse(const vpCameraParameters &cam, const vpImagePoint &center_p, double n20_p,
70  double n11_p, double n02_p, double &xc_m, double &yc_m, double &n20_m,
71  double &n11_m, double &n02_m)
72 {
73  vpPixelMeterConversion::convertPoint(cam, center_p, xc_m, yc_m);
74  double px = cam.get_px();
75  double py = cam.get_py();
76 
77  n20_m = n20_p / (px * px);
78  n11_m = n11_p / (px * py);
79  n02_m = n02_p / (py * py);
80 }
81 
91 void vpPixelMeterConversion::convertLine(const vpCameraParameters &cam, const double &rho_p, const double &theta_p,
92  double &rho_m, double &theta_m)
93 {
94  double co = cos(theta_p);
95  double si = sin(theta_p);
96  double d = vpMath::sqr(cam.m_px * co) + vpMath::sqr(cam.m_py * si);
97 
98  if (fabs(d) < 1e-6) {
99  throw(vpException(vpException::divideByZeroError, "division by zero"));
100  }
101  theta_m = atan2(si * cam.m_py, co * cam.m_px);
102  rho_m = (rho_p - (cam.m_u0 * co) - (cam.m_v0 * si)) / sqrt(d);
103 }
104 
142 void vpPixelMeterConversion::convertMoment(const vpCameraParameters &cam, unsigned int order,
143  const vpMatrix &moment_pixel, vpMatrix &moment_meter)
144 {
145  vpMatrix m(order, order);
146  double yc = -cam.m_v0;
147  double xc = -cam.m_u0;
148 
149  for (unsigned int k = 0; k < order; ++k) { // iteration corresponding to moment order
150  for (unsigned int p = 0; p < order; ++p) { // iteration en X
151  for (unsigned int q = 0; q < order; ++q) { // iteration en Y
152  if ((p + q) == k) { // on est bien dans la matrice triangulaire superieure
153  m[p][q] = 0; // initialisation e 0
154  for (unsigned int r = 0; r <= p; ++r) { // somme externe
155  for (unsigned int t = 0; t <= q; ++t) { // somme interne
156  m[p][q] += static_cast<double>(vpMath::comb(p, r)) * static_cast<double>(vpMath::comb(q, t)) *
157  pow(xc, static_cast<int>(p - r)) * pow(yc, static_cast<int>(q - t)) * moment_pixel[r][t];
158  }
159  }
160  }
161  }
162  }
163  }
164 
165  for (unsigned int k = 0; k < order; ++k) { // iteration corresponding to moment order
166  for (unsigned int p = 0; p < order; ++p) {
167  for (unsigned int q = 0; q < order; ++q) {
168  if ((p + q) == k) {
169  m[p][q] *= pow(cam.m_inv_px, static_cast<int>(1 + p)) * pow(cam.m_inv_py, static_cast<int>(1 + q));
170  }
171  }
172  }
173  }
174 
175  for (unsigned int k = 0; k < order; ++k) { // iteration corresponding to moment order
176  for (unsigned int p = 0; p < order; ++p) {
177  for (unsigned int q = 0; q < order; ++q) {
178  if ((p + q) == k) {
179  moment_meter[p][q] = m[p][q];
180  }
181  }
182  }
183  }
184 }
185 
186 #if defined(HAVE_OPENCV_IMGPROC) && \
187  (((VISP_HAVE_OPENCV_VERSION < 0x050000) && defined(HAVE_OPENCV_CALIB3D)) || ((VISP_HAVE_OPENCV_VERSION >= 0x050000) && defined(HAVE_OPENCV_CALIB) && defined(HAVE_OPENCV_3D)))
201 void vpPixelMeterConversion::convertEllipse(const cv::Mat &cameraMatrix, const cv::Mat &distCoeffs,
202  const vpImagePoint &center_p, double n20_p, double n11_p, double n02_p,
203  double &xc_m, double &yc_m, double &n20_m, double &n11_m, double &n02_m)
204 {
205  vpPixelMeterConversion::convertPoint(cameraMatrix, distCoeffs, center_p, xc_m, yc_m);
206  double px = cameraMatrix.at<double>(0, 0);
207  double py = cameraMatrix.at<double>(1, 1);
208 
209  n20_m = n20_p / (px * px);
210  n11_m = n11_p / (px * py);
211  n02_m = n02_p / (py * py);
212 }
213 
223 void vpPixelMeterConversion::convertLine(const cv::Mat &cameraMatrix, const double &rho_p, const double &theta_p,
224  double &rho_m, double &theta_m)
225 {
226  double co = cos(theta_p);
227  double si = sin(theta_p);
228  double px = cameraMatrix.at<double>(0, 0);
229  double py = cameraMatrix.at<double>(1, 1);
230  double u0 = cameraMatrix.at<double>(0, 2);
231  double v0 = cameraMatrix.at<double>(1, 2);
232 
233  double d = vpMath::sqr(px * co) + vpMath::sqr(py * si);
234 
235  if (fabs(d) < 1e-6) {
236  throw(vpException(vpException::divideByZeroError, "division by zero"));
237  }
238  theta_m = atan2(si * py, co * px);
239  rho_m = (rho_p - u0 * co - v0 * si) / sqrt(d);
240 }
241 
252 void vpPixelMeterConversion::convertMoment(const cv::Mat &cameraMatrix, unsigned int order,
253  const vpMatrix &moment_pixel, vpMatrix &moment_meter)
254 {
255  double inv_px = 1. / cameraMatrix.at<double>(0, 0);
256  double inv_py = 1. / cameraMatrix.at<double>(1, 1);
257  double u0 = cameraMatrix.at<double>(0, 2);
258  double v0 = cameraMatrix.at<double>(1, 2);
259 
260  vpMatrix m(order, order);
261  double yc = -v0;
262  double xc = -u0;
263 
264  for (unsigned int k = 0; k < order; ++k) { // iteration corresponding to moment order
265  for (unsigned int p = 0; p < order; ++p) { // iteration en X
266  for (unsigned int q = 0; q < order; ++q) { // iteration en Y
267  if (p + q == k) { // on est bien dans la matrice triangulaire superieure
268  m[p][q] = 0; // initialisation e 0
269  for (unsigned int r = 0; r <= p; ++r) { // somme externe
270  for (unsigned int t = 0; t <= q; ++t) { // somme interne
271  m[p][q] += static_cast<double>(vpMath::comb(p, r)) * static_cast<double>(vpMath::comb(q, t)) *
272  pow(xc, static_cast<int>(p - r)) * pow(yc, static_cast<int>(q - t)) * moment_pixel[r][t];
273  }
274  }
275  }
276  }
277  }
278  }
279 
280  for (unsigned int k = 0; k < order; ++k) { // iteration corresponding to moment order
281  for (unsigned int p = 0; p < order; ++p) {
282  for (unsigned int q = 0; q < order; ++q) {
283  if (p + q == k) {
284  m[p][q] *= pow(inv_px, static_cast<int>(1 + p)) * pow(inv_py, static_cast<int>(1 + q));
285  }
286  }
287  }
288  }
289 
290  for (unsigned int k = 0; k < order; ++k) { // iteration corresponding to moment order
291  for (unsigned int p = 0; p < order; ++p) {
292  for (unsigned int q = 0; q < order; ++q) {
293  if (p + q == k) {
294  moment_meter[p][q] = m[p][q];
295  }
296  }
297  }
298  }
299 }
300 
315 void vpPixelMeterConversion::convertPoint(const cv::Mat &cameraMatrix, const cv::Mat &distCoeffs, const double &u,
316  const double &v, double &x, double &y)
317 {
318  std::vector<cv::Point2d> imagePoints_vec;
319  imagePoints_vec.push_back(cv::Point2d(u, v));
320  std::vector<cv::Point2d> objectPoints_vec;
321  cv::undistortPoints(imagePoints_vec, objectPoints_vec, cameraMatrix, distCoeffs);
322  x = objectPoints_vec[0].x;
323  y = objectPoints_vec[0].y;
324 }
325 
339 void vpPixelMeterConversion::convertPoint(const cv::Mat &cameraMatrix, const cv::Mat &distCoeffs,
340  const vpImagePoint &iP, double &x, double &y)
341 {
342  std::vector<cv::Point2d> imagePoints_vec;
343  imagePoints_vec.push_back(cv::Point2d(iP.get_u(), iP.get_v()));
344  std::vector<cv::Point2d> objectPoints_vec;
345  cv::undistortPoints(imagePoints_vec, objectPoints_vec, cameraMatrix, distCoeffs);
346  x = objectPoints_vec[0].x;
347  y = objectPoints_vec[0].y;
348 }
349 
350 #endif
351 END_VISP_NAMESPACE
Generic class defining intrinsic camera parameters.
error that can be emitted by ViSP classes.
Definition: vpException.h:60
@ divideByZeroError
Division by zero.
Definition: vpException.h:70
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:203
static long double comb(unsigned int n, unsigned int p)
Definition: vpMath.h:395
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:169
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 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 convertPoint(const vpCameraParameters &cam, const double &u, const double &v, double &x, double &y)