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