Visual Servoing Platform  version 3.6.1 under development (2024-07-27)
testLineFitting.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  * Test line fitting.
32  */
33 
39 #include <visp3/core/vpConfig.h>
40 
41 #ifdef VISP_HAVE_CATCH2
42 
43 #include <visp3/core/vpGaussRand.h>
44 #include <visp3/core/vpMath.h>
45 
46 #define CATCH_CONFIG_RUNNER
47 #include <catch.hpp>
48 
49 #ifdef ENABLE_VISP_NAMESPACE
50 using namespace VISP_NAMESPACE_NAME;
51 #endif
52 
53 namespace
54 {
55 void convertLineEquation(double A, double B, double C, double &a, double &b)
56 {
57  a = -A / B;
58  b = C / B;
59 }
60 } // namespace
61 
62 TEST_CASE("Line fitting - Horizontal", "[line_fitting]")
63 {
64  std::cout << "\nLine fitting - Horizontal" << std::endl;
65  double a = 0, b = 10;
66  std::vector<vpImagePoint> imPts;
67  for (int i = 0; i < 3; i++) {
68  double x = i * 10;
69  imPts.push_back(vpImagePoint(a * x + b, x));
70  std::cout << "imPts: (" << imPts.back().get_u() << ", " << imPts.back().get_v() << ")" << std::endl;
71  }
72 
73  double A = 0, B = 0, C = 0;
74  double error = vpMath::lineFitting(imPts, A, B, C);
75  std::cout << "error: " << error << std::endl;
76  std::cout << "a: " << a << " ; b: " << b << std::endl;
77  std::cout << "A: " << A << " ; B: " << B << " ; C: " << C << std::endl;
78  double a_est = 0, b_est = 0;
79  convertLineEquation(A, B, C, a_est, b_est);
80  std::cout << "-A/B: " << a_est << " ; -C/B: " << b_est << std::endl;
81 
82  CHECK(a == Approx(a_est).margin(1e-6));
83  CHECK(b == Approx(b_est).epsilon(1e-6));
84 }
85 
86 TEST_CASE("Line fitting", "[line_fitting]")
87 {
88  std::cout << "\nLine fitting" << std::endl;
89  double a = -4.68, b = 21.456;
90  std::vector<vpImagePoint> imPts;
91  const int nbPoints = 10;
92  for (int i = 0; i < nbPoints; i++) {
93  double x = i * 10;
94  double y = a * x + b;
95  imPts.push_back(vpImagePoint(y, x));
96  std::cout << "imPts: (" << imPts.back().get_u() << ", " << imPts.back().get_v() << ")" << std::endl;
97  }
98 
99  double A = 0, B = 0, C = 0;
100  double error = vpMath::lineFitting(imPts, A, B, C);
101  std::cout << "error: " << error << std::endl;
102  std::cout << "a: " << a << " ; b: " << b << std::endl;
103  std::cout << "A: " << A << " ; B: " << B << " ; C: " << C << std::endl;
104  double a_est = 0, b_est = 0;
105  convertLineEquation(A, B, C, a_est, b_est);
106  std::cout << "-A/B: " << a_est << " ; -C/B: " << b_est << std::endl;
107 
108  CHECK(a == Approx(a_est).epsilon(1e-6));
109  CHECK(b == Approx(b_est).epsilon(1e-6));
110 }
111 
112 TEST_CASE("Line fitting - Gaussian noise", "[line_fitting]")
113 {
114  std::cout << "\nLine fitting - Gaussian noise" << std::endl;
115  const double sigma = 3, mean = 0;
116  vpGaussRand gauss(sigma, mean);
117 
118  double a = -4.68, b = 21.456;
119  std::vector<vpImagePoint> imPts;
120  const int nbPoints = 10;
121  for (int i = 0; i < nbPoints; i++) {
122  double x = i * 10;
123  double y = a * x + b;
124  imPts.push_back(vpImagePoint(y + gauss(), x + gauss()));
125  std::cout << "x: " << x << " ; y: " << y << " ; imPts: (" << imPts.back().get_u() << ", " << imPts.back().get_v()
126  << ")" << std::endl;
127  }
128 
129  double A = 0, B = 0, C = 0;
130  double error = vpMath::lineFitting(imPts, A, B, C);
131  std::cout << "error: " << error << std::endl;
132  std::cout << "a: " << a << " ; b: " << b << std::endl;
133  std::cout << "A: " << A << " ; B: " << B << " ; C: " << C << std::endl;
134  double a_est = 0, b_est = 0;
135  convertLineEquation(A, B, C, a_est, b_est);
136  std::cout << "-A/B: " << a_est << " ; -C/B: " << b_est << std::endl;
137 
138  REQUIRE(error < sigma);
139 }
140 
141 int main(int argc, char *argv[])
142 {
143  Catch::Session session; // There must be exactly one instance
144 
145  // Let Catch (using Clara) parse the command line
146  session.applyCommandLine(argc, argv);
147 
148  int numFailed = session.run();
149 
150  // numFailed is clamped to 255 as some unices only use the lower 8 bits.
151  // This clamping has already been applied, so just return it here
152  // You can also do any post run clean-up here
153  return numFailed;
154 }
155 #else
156 #include <iostream>
157 
158 int main() { return EXIT_SUCCESS; }
159 #endif
Class for generating random number with normal probability density.
Definition: vpGaussRand.h:117
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:82
static double lineFitting(const std::vector< vpImagePoint > &imPts, double &a, double &b, double &c)
Definition: vpMath.cpp:390