From 476b489bac54ba544deeaed9a5dee5d23d52eb75 Mon Sep 17 00:00:00 2001 From: rlagneau Date: Mon, 25 Sep 2023 11:54:16 +0200 Subject: [PATCH 01/22] [WIP] Added a method to compute the arc length of a circle that is contained in a rectangular RoI. Missing cases where the circle is bigger than the RoI and where the circle is near a corner and thus crosses two borders --- .../core/include/visp3/core/vpImageCircle.h | 10 +- modules/core/src/image/vpImageCircle.cpp | 129 ++++++++ .../test/tools/geometry/testImageCircle.cpp | 296 ++++++++++++++++++ 3 files changed, 433 insertions(+), 2 deletions(-) create mode 100644 modules/core/test/tools/geometry/testImageCircle.cpp diff --git a/modules/core/include/visp3/core/vpImageCircle.h b/modules/core/include/visp3/core/vpImageCircle.h index 6f1150f0c2..9529fad86b 100644 --- a/modules/core/include/visp3/core/vpImageCircle.h +++ b/modules/core/include/visp3/core/vpImageCircle.h @@ -78,9 +78,15 @@ class VISP_EXPORT vpImageCircle virtual ~vpImageCircle(); /*! - * Get the center of the image (2D) circle - * \return The center of the image (2D) circle. + * Compute the arc length that is contained in the Region of Interest (RoI). + * \return The number of pixels of the circle that are contained in the RoI. */ + float computeArcLengthInRoI(const vpRect &roi) const; + + /*! + * Get the center of the image (2D) circle + * \return The center of the image (2D) circle. + */ vpImagePoint getCenter() const; /*! diff --git a/modules/core/src/image/vpImageCircle.cpp b/modules/core/src/image/vpImageCircle.cpp index 252c0d17eb..c8b022436f 100644 --- a/modules/core/src/image/vpImageCircle.cpp +++ b/modules/core/src/image/vpImageCircle.cpp @@ -63,6 +63,135 @@ vpImageCircle::~vpImageCircle() } +void computeIntersectionsLeftBorderOnly(const float &u_c, const float &radius, + float &delta_theta) +{ + float theta1 = std::acos(-1.f * u_c / radius); + if (theta1 > M_PI) { + theta1 -= 2.0 * M_PI; + } + else if (theta1 > M_PI) { + theta1 += 2.0 * M_PI; + } + float theta2 = -1.f * theta1; + float theta_min = std::min(theta1, theta2); + float theta_max = std::max(theta1, theta2); + delta_theta = theta_max - theta_min; +} + +void computeIntersectionsRightBorderOnly(const float &u_c, const float &width, const float &radius, + float &delta_theta) +{ + float theta1 = std::acos((width - u_c) / radius); + if (theta1 > M_PI) { + theta1 -= 2.0 * M_PI; + } + else if (theta1 > M_PI) { + theta1 += 2.0 * M_PI; + } + float theta2 = -1.f * theta1; + float theta_min = std::min(theta1, theta2); + float theta_max = std::max(theta1, theta2); + delta_theta = 2.f * M_PI - (theta_max - theta_min); +} + +void computeIntersectionsTopBorderOnly(const float &v_c, const float &radius, + float &delta_theta) +{ + float theta1 = std::asin(-1.f * v_c / radius); + if (theta1 > M_PI) { + theta1 -= 2.0 * M_PI; + } + else if (theta1 > M_PI) { + theta1 += 2.0 * M_PI; + } + + float theta2 = 0.f; + if (theta1 >= 0.f) { + theta2 = M_PI - theta1; + } + else { + theta2 = -theta1 - M_PI; + } + float theta_min = std::min(theta1, theta2); + float theta_max = std::max(theta1, theta2); + if (theta1 > 0.f) { + delta_theta = 2.f * M_PI - (theta_max - theta_min); + } + else { + delta_theta = theta_max - theta_min; + } +} + +void computeIntersectionsBottomBorderOnly(const float &v_c, const float &height, const float &radius, + float &delta_theta) +{ + float theta1 = std::asin((height - v_c) / radius); + if (theta1 > M_PI) { + theta1 -= 2.0 * M_PI; + } + else if (theta1 > M_PI) { + theta1 += 2.0 * M_PI; + } + + float theta2 = 0.f; + if (theta1 >= 0.f) { + theta2 = M_PI - theta1; + } + else { + theta2 = -theta1 - M_PI; + } + float theta_min = std::min(theta1, theta2); + float theta_max = std::max(theta1, theta2); + if (theta1 > 0.f) { + delta_theta = theta_max - theta_min; + } + else { + delta_theta = 2.f * M_PI - (theta_max - theta_min); + } +} + +float vpImageCircle::computeArcLengthInRoI(const vpRect &roi) const +{ + float deltaTheta = 0.f; + vpImagePoint center = m_center; + float center_u = center.get_u(); + float center_v = center.get_v(); + float radius = m_radius; + float img_w = roi.getWidth(); + float img_h = roi.getHeight(); + bool touchLeftBorder = (center_u - radius) < 0.; + bool touchRightBorder = (center_u + radius) >= img_w; + bool touchTopBorder = (center_v - radius) < 0.; + bool touchBottomBorder = (center_v + radius) >= img_h; + bool isHorizontallyOK = (!touchLeftBorder && !touchRightBorder); + bool isVerticallyOK = (!touchTopBorder && !touchBottomBorder); + if (isHorizontallyOK && isVerticallyOK) { + // Easy case + // The circle has its center in the image and its radius is not too great + // to make it partially occluded + deltaTheta = 2.f * M_PI; + } + else if (touchBottomBorder && !touchLeftBorder && !touchRightBorder && !touchTopBorder) { + // Touch only the bottom border of the RoI + computeIntersectionsBottomBorderOnly(center_v, img_h, radius, deltaTheta); + } + else if (!touchBottomBorder && touchLeftBorder && !touchRightBorder && !touchTopBorder) { + // Touch only the left border of the RoI + computeIntersectionsLeftBorderOnly(center_u, radius, deltaTheta); + } + else if (!touchBottomBorder && !touchLeftBorder && touchRightBorder && !touchTopBorder) { + // Touch only the right border of the RoI + computeIntersectionsRightBorderOnly(center_u, img_w, radius, deltaTheta); + } + else if (!touchBottomBorder && !touchLeftBorder && !touchRightBorder && touchTopBorder) { + // Touch only the top border of the RoI + computeIntersectionsTopBorderOnly(center_v, radius, deltaTheta); + } + float arcLength = deltaTheta * radius; + return arcLength; +} + vpImagePoint vpImageCircle::getCenter() const { return m_center; diff --git a/modules/core/test/tools/geometry/testImageCircle.cpp b/modules/core/test/tools/geometry/testImageCircle.cpp new file mode 100644 index 0000000000..1361abc620 --- /dev/null +++ b/modules/core/test/tools/geometry/testImageCircle.cpp @@ -0,0 +1,296 @@ +/**************************************************************************** + * + * ViSP, open source Visual Servoing Platform software. + * Copyright (C) 2005 - 2023 by Inria. All rights reserved. + * + * This software is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * See the file LICENSE.txt at the root directory of this source + * distribution for additional information about the GNU GPL. + * + * For using ViSP with software that can not be combined with the GNU + * GPL, please contact Inria about acquiring a ViSP Professional + * Edition License. + * + * See https://visp.inria.fr for more information. + * + * This software was developed at: + * Inria Rennes - Bretagne Atlantique + * Campus Universitaire de Beaulieu + * 35042 Rennes Cedex + * France + * + * If you have questions regarding the use of this file, please contact + * Inria at visp@inria.fr + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Description: + * Test vpRect. + * +*****************************************************************************/ + +#include +#include +#include +#include + +bool compareAngles(const float &actualVal, const float &theoreticalVal) +{ + // Allow up to 1 pixel of difference, due to rounding effects + return (std::abs(theoreticalVal - actualVal) < 1.f); +} + +int main() +{ + const float WIDTH = 640.f; + const float HEIGHT = 480.f; + const float RADIUS = std::min(WIDTH, HEIGHT) / 10.f; + vpRect roi(0, 0, WIDTH, HEIGHT); + + // Test with no intersections + { + vpImageCircle noIntersect(vpImagePoint(HEIGHT / 2.f, WIDTH / 2.f), RADIUS); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = 2.f * M_PI * RADIUS; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "OK"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test no intersection." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest OK = " << statusTest << std::endl; + + if (!isValueOK) { + std::cerr << "Problem with the computeArcLengthInRoI function!" << std::endl; + return EXIT_FAILURE; + } + } + + // Test with intersections with the left border, more than half a circle visible + { + // Formula: uc = - RADIUS * cos(theta) + float uc = 24.f; + float vc = 100.f; + vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = 4.f * M_PI * RADIUS /3.f; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "OK"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test intersection left border, more than half a circle visible." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest OK = " << statusTest << std::endl; + + if (!isValueOK) { + std::cerr << "Problem with the computeArcLengthInRoI function!" << std::endl; + return EXIT_FAILURE; + } + } + + // Test with intersections with the left border, less than half a circle visible + { + // Formula: uc = - RADIUS * cos(theta) + float uc = -24.f; + float vc = 100.f; + vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = 2.f * M_PI * RADIUS /3.f; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "OK"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test intersection left border, less than half a circle visible." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest OK = " << statusTest << std::endl; + + if (!isValueOK) { + std::cerr << "Problem with the computeArcLengthInRoI function!" << std::endl; + return EXIT_FAILURE; + } + } + + // Test with intersections with the right border, more than half a circle visible + { + // Formula: uc = WIDTH - RADIUS * cos(theta) + float uc = 616.f; + float vc = 100.f; + vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = 4.f * M_PI * RADIUS /3.f; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "OK"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test intersection right border, more than half a circle visible." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest OK = " << statusTest << std::endl; + + if (!isValueOK) { + std::cerr << "Problem with the computeArcLengthInRoI function!" << std::endl; + return EXIT_FAILURE; + } + } + + // Test with intersections with the right border, less than half a circle visible + { + // Formula: uc = WIDTH - RADIUS * cos(theta) + float uc = 664.f; + float vc = 100.f; + vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = 2.f * M_PI * RADIUS /3.f; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "OK"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test intersection right border, less than half a circle visible." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest OK = " << statusTest << std::endl; + + if (!isValueOK) { + std::cerr << "Problem with the computeArcLengthInRoI function!" << std::endl; + return EXIT_FAILURE; + } + } + + // Test with intersections with the top border, more than half a circle visible + { + // Formula: vc = - RADIUS * sin(theta) + float uc = 100.f; + float vc = -41.56921938f; + vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = 5.f * M_PI * RADIUS /3.f; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "OK"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test intersection top border, more than half a circle visible." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest OK = " << statusTest << std::endl; + + if (!isValueOK) { + std::cerr << "Problem with the computeArcLengthInRoI function!" << std::endl; + return EXIT_FAILURE; + } + } + + // Test with intersections with the top border, less than half a circle visible + { + // Formula: vc = - RADIUS * sin(theta) + float uc = 100.f; + float vc = 41.56921938f; + vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = M_PI * RADIUS /3.f; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "OK"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test intersection top border, less than half a circle visible." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest OK = " << statusTest << std::endl; + + if (!isValueOK) { + std::cerr << "Problem with the computeArcLengthInRoI function!" << std::endl; + return EXIT_FAILURE; + } + } + + // Test with intersections with the bottom border, more than half a circle visible + { + // Formula: vc = HEIGHT - RADIUS * sin(theta) + float uc = 100.f; + float vc = 521.569219381653f; + vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = 5.f * M_PI * RADIUS /3.f; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "OK"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test intersection bottom border, more than half a circle visible." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest OK = " << statusTest << std::endl; + + if (!isValueOK) { + std::cerr << "Problem with the computeArcLengthInRoI function!" << std::endl; + return EXIT_FAILURE; + } + } + + // Test with intersections with the bottom border, less than half a circle visible + { + // Formula: vc = HEIGHT - RADIUS * sin(theta) + float uc = 100.f; + float vc = 438.430780618347f; + vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = M_PI * RADIUS /3.f; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "OK"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test intersection bottom border, less than half a circle visible." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest OK = " << statusTest << std::endl; + + if (!isValueOK) { + std::cerr << "Problem with the computeArcLengthInRoI function!" << std::endl; + return EXIT_FAILURE; + } + } + + std::cout << "vpImageCircle is ok." << std::endl; + return EXIT_SUCCESS; +} From 8209a0d975697b7e5ed09263243d4c885c31a7d8 Mon Sep 17 00:00:00 2001 From: rlagneau Date: Mon, 25 Sep 2023 18:14:33 +0200 Subject: [PATCH 02/22] [WIP] Manage cases where a single axis is touched (additionally to cases where a single axis is crossed). WiP for two perpendicular axes crossing --- .../core/include/visp3/core/vpImageCircle.h | 3 +- modules/core/src/image/vpImageCircle.cpp | 188 ++++++++++++++--- .../test/tools/geometry/testImageCircle.cpp | 198 +++++++++++++----- 3 files changed, 306 insertions(+), 83 deletions(-) diff --git a/modules/core/include/visp3/core/vpImageCircle.h b/modules/core/include/visp3/core/vpImageCircle.h index 9529fad86b..c30467627d 100644 --- a/modules/core/include/visp3/core/vpImageCircle.h +++ b/modules/core/include/visp3/core/vpImageCircle.h @@ -78,7 +78,8 @@ class VISP_EXPORT vpImageCircle virtual ~vpImageCircle(); /*! - * Compute the arc length that is contained in the Region of Interest (RoI). + * Compute the arc length, in terms of number of pixels, that is contained in the Region of Interest (RoI). + * \param[in] roi The rectangular RoI in which we want to know the number of pixels of the circle that are contained. * \return The number of pixels of the circle that are contained in the RoI. */ float computeArcLengthInRoI(const vpRect &roi) const; diff --git a/modules/core/src/image/vpImageCircle.cpp b/modules/core/src/image/vpImageCircle.cpp index c8b022436f..071d8e1a60 100644 --- a/modules/core/src/image/vpImageCircle.cpp +++ b/modules/core/src/image/vpImageCircle.cpp @@ -63,48 +63,76 @@ vpImageCircle::~vpImageCircle() } -void computeIntersectionsLeftBorderOnly(const float &u_c, const float &radius, - float &delta_theta) +/*! + * \brief Express \b theta between - Pi and Pi . + * + * \param[in] theta The input angle we want to ensure it is in the interval [-Pi ; Pi] + * \return float The input angle in the interval [-Pi ; Pi] + */ +float getAngleBetweenMinPiAndPi(const float &theta) { - float theta1 = std::acos(-1.f * u_c / radius); + float theta1 = theta; if (theta1 > M_PI) { theta1 -= 2.0 * M_PI; } else if (theta1 > M_PI) { theta1 += 2.0 * M_PI; } + return theta1; +} + +/*! + * \brief Compute the length of the angular interval of the circle when it intersects + * only with the left border of the Region of Interest (RoI). + * + * \param[in] u_c The u-coordinate of the center of the circle. + * \param[in] radius The radius of the circle. + * \param[out] delta_theta The length of the angular interval that is in the RoI. + */ +void computeIntersectionsLeftBorderOnly(const float &u_c, const float &radius, + float &delta_theta) +{ + float theta1 = std::acos(-1.f * u_c / radius); + theta1 = getAngleBetweenMinPiAndPi(theta1); float theta2 = -1.f * theta1; float theta_min = std::min(theta1, theta2); float theta_max = std::max(theta1, theta2); delta_theta = theta_max - theta_min; } +/*! + * \brief Compute the length of the angular interval of the circle when it intersects + * only with the right border of the Region of Interest (RoI). + * + * \param[in] u_c The u-coordinate of the center of the circle. + * \param[in] width The width of the RoI. + * \param[in] radius The radius of the circle. + * \param[out] delta_theta The length of the angular interval that is in the RoI. + */ void computeIntersectionsRightBorderOnly(const float &u_c, const float &width, const float &radius, float &delta_theta) { float theta1 = std::acos((width - u_c) / radius); - if (theta1 > M_PI) { - theta1 -= 2.0 * M_PI; - } - else if (theta1 > M_PI) { - theta1 += 2.0 * M_PI; - } + theta1 = getAngleBetweenMinPiAndPi(theta1); float theta2 = -1.f * theta1; float theta_min = std::min(theta1, theta2); float theta_max = std::max(theta1, theta2); delta_theta = 2.f * M_PI - (theta_max - theta_min); } +/*! + * \brief Compute the length of the angular interval of the circle when it intersects + * only with the top border of the Region of Interest (RoI). + * + * \param[in] v_c The v-coordinate of the center of the circle. + * \param[in] radius The radius of the circle. + * \param[out] delta_theta The length of the angular interval that is in the RoI. + */ void computeIntersectionsTopBorderOnly(const float &v_c, const float &radius, float &delta_theta) { float theta1 = std::asin(-1.f * v_c / radius); - if (theta1 > M_PI) { - theta1 -= 2.0 * M_PI; - } - else if (theta1 > M_PI) { - theta1 += 2.0 * M_PI; - } + theta1 = getAngleBetweenMinPiAndPi(theta1); float theta2 = 0.f; if (theta1 >= 0.f) { @@ -115,7 +143,12 @@ void computeIntersectionsTopBorderOnly(const float &v_c, const float &radius, } float theta_min = std::min(theta1, theta2); float theta_max = std::max(theta1, theta2); - if (theta1 > 0.f) { + if (std::abs(theta_max - theta_min) * radius < 1.f) { + // Between the maximum and minimum theta there is less than 1 pixel of difference + // It meens that the full circle is visible + delta_theta = 2.f * M_PI; + } + else if (theta1 > 0.f) { delta_theta = 2.f * M_PI - (theta_max - theta_min); } else { @@ -123,16 +156,20 @@ void computeIntersectionsTopBorderOnly(const float &v_c, const float &radius, } } +/*! + * \brief Compute the length of the angular interval of the circle when it intersects + * only with the left border of the Region of Interest (RoI). + * + * \param[in] v_c The v-coordinate of the center of the circle. + * \param[in] height The height of the RoI. + * \param[in] radius The radius of the circle. + * \param[out] delta_theta The length of the angular interval that is in the RoI. + */ void computeIntersectionsBottomBorderOnly(const float &v_c, const float &height, const float &radius, float &delta_theta) { float theta1 = std::asin((height - v_c) / radius); - if (theta1 > M_PI) { - theta1 -= 2.0 * M_PI; - } - else if (theta1 > M_PI) { - theta1 += 2.0 * M_PI; - } + theta1 = getAngleBetweenMinPiAndPi(theta1); float theta2 = 0.f; if (theta1 >= 0.f) { @@ -143,7 +180,12 @@ void computeIntersectionsBottomBorderOnly(const float &v_c, const float &height, } float theta_min = std::min(theta1, theta2); float theta_max = std::max(theta1, theta2); - if (theta1 > 0.f) { + if (std::abs(theta_max - theta_min) * radius < 1.f) { + // Between the maximum and minimum theta there is less than 1 pixel of difference + // It meens that the full circle is visible + delta_theta = 2.f * M_PI; + } + else if (theta1 > 0.f) { delta_theta = theta_max - theta_min; } else { @@ -151,6 +193,44 @@ void computeIntersectionsBottomBorderOnly(const float &v_c, const float &height, } } +/*! + * \brief Compute the angles for which the circle crosses the horizontal u-axis and the + * vertical v-axis. + * + * \param[in] u_c The horizontal u-axis coordinate of the center. + * \param[in] v_c The vertical v-axis coordinate of the center. + * \param[in] radius The radius of the circle. + * \param[in] crossing_u The horizontal u-axis coordinate of the crossing point with the v-axis. + * \param[in] crossing_v The vertical v-axis coordinate of the crossing point with the u-axis. + * \param[out] theta_u_cross_min The smallest angle for which the circle intersects the u-axis, i.e. \b theta_u_cross_min < \b theta_u_cross_max . + * \param[out] theta_u_cross_max The highest angle for which the circle intersects the u-axis. + * \param[out] theta_v_cross_min The smallest angle for which the circle intersects the v-axis; i.e. \b theta_v_cross_min < \b theta_v_cross_max . + * \param[out] theta_v_cross_max The highest angle for which the circle intersects the v-axis. + */ +void computePerpendicularAxesIntersections(const float &u_c, const float &v_c, const float &radius, + const float &crossing_u, const float &crossing_v, + float &theta_u_cross_min, float &theta_u_cross_max, + float &theta_v_cross_min, float &theta_v_cross_max) +{ + float theta_u_cross = std::asin((crossing_u - v_c)/radius); + theta_u_cross = getAngleBetweenMinPiAndPi(theta_u_cross); + float theta_u_cross_2 = 0.f; + if (theta_u_cross > 0) { + theta_u_cross_2 = M_PI - theta_u_cross; + } + else { + theta_u_cross_2 = -M_PI - theta_u_cross; + } + theta_u_cross_min = std::min(theta_u_cross, theta_u_cross_2); + theta_u_cross_max = std::max(theta_u_cross, theta_u_cross_2); + + float theta_v_cross = std::acos((crossing_v - u_c)/radius); + theta_v_cross = getAngleBetweenMinPiAndPi(theta_v_cross); + float theta_v_cross_2 = -theta_v_cross; + theta_v_cross_min = std::min(theta_v_cross, theta_v_cross_2); + theta_v_cross_max = std::max(theta_v_cross, theta_v_cross_2); +} + float vpImageCircle::computeArcLengthInRoI(const vpRect &roi) const { float deltaTheta = 0.f; @@ -160,34 +240,80 @@ float vpImageCircle::computeArcLengthInRoI(const vpRect &roi) const float radius = m_radius; float img_w = roi.getWidth(); float img_h = roi.getHeight(); - bool touchLeftBorder = (center_u - radius) < 0.; + bool touchLeftBorder = (center_u - radius) <= 0.; bool touchRightBorder = (center_u + radius) >= img_w; - bool touchTopBorder = (center_v - radius) < 0.; + bool touchTopBorder = (center_v - radius) <= 0.; bool touchBottomBorder = (center_v + radius) >= img_h; bool isHorizontallyOK = (!touchLeftBorder && !touchRightBorder); bool isVerticallyOK = (!touchTopBorder && !touchBottomBorder); - if (isHorizontallyOK && isVerticallyOK) { + if (isHorizontallyOK && isVerticallyOK && roi.isInside(m_center)) { // Easy case // The circle has its center in the image and its radius is not too great - // to make it partially occluded + // to make it fully contained in the RoI deltaTheta = 2.f * M_PI; } else if (touchBottomBorder && !touchLeftBorder && !touchRightBorder && !touchTopBorder) { - // Touch only the bottom border of the RoI + // Touches/intersects only the bottom border of the RoI + std::cout << "Case bottom only" << std::endl; computeIntersectionsBottomBorderOnly(center_v, img_h, radius, deltaTheta); } else if (!touchBottomBorder && touchLeftBorder && !touchRightBorder && !touchTopBorder) { - // Touch only the left border of the RoI + // Touches/intersects only the left border of the RoI + std::cout << "Case left only" << std::endl; computeIntersectionsLeftBorderOnly(center_u, radius, deltaTheta); } else if (!touchBottomBorder && !touchLeftBorder && touchRightBorder && !touchTopBorder) { - // Touch only the right border of the RoI + // Touches/intersects only the right border of the RoI + std::cout << "Case right only" << std::endl; computeIntersectionsRightBorderOnly(center_u, img_w, radius, deltaTheta); } else if (!touchBottomBorder && !touchLeftBorder && !touchRightBorder && touchTopBorder) { - // Touch only the top border of the RoI + // Touches/intersects only the top border of the RoI + std::cout << "Case top only" << std::endl; computeIntersectionsTopBorderOnly(center_v, radius, deltaTheta); } + else if (touchBottomBorder && touchLeftBorder && !touchRightBorder && !touchTopBorder) { + // Touches/intersects the bottom and left borders of the RoI + std::cout << "Case bottom / left" << std::endl; + float crossing_theta_u_min = 0.f, crossing_theta_v_min = 0.f; + float crossing_theta_u_max = 0.f, crossing_theta_v_max = 0.f; + computePerpendicularAxesIntersections(center_u, center_v, radius, 0, img_h, crossing_theta_u_min, crossing_theta_u_max, crossing_theta_v_min, crossing_theta_v_max); + } + else if (touchBottomBorder && !touchLeftBorder && touchRightBorder && !touchTopBorder) { + // Touches/intersects the bottom and right borders of the RoI + std::cout << "Case bottom / right" << std::endl; + float crossing_theta_u_min = 0.f, crossing_theta_v_min = 0.f; + float crossing_theta_u_max = 0.f, crossing_theta_v_max = 0.f; + computePerpendicularAxesIntersections(center_u, center_v, radius, img_w, img_h, crossing_theta_u_min, crossing_theta_u_max, crossing_theta_v_min, crossing_theta_v_max); + } + else if (!touchBottomBorder && touchLeftBorder && !touchRightBorder && touchTopBorder) { + // Touches/intersects the top and left borders of the RoI + std::cout << "Case top / left" << std::endl; + float crossing_theta_u_min = 0.f, crossing_theta_v_min = 0.f; + float crossing_theta_u_max = 0.f, crossing_theta_v_max = 0.f; + computePerpendicularAxesIntersections(center_u, center_v, radius, 0, 0, crossing_theta_u_min, crossing_theta_u_max, crossing_theta_v_min, crossing_theta_v_max); + } + else if (!touchBottomBorder && !touchLeftBorder && touchRightBorder && touchTopBorder) { + // Touches/intersects the top and right borders of the RoI + std::cout << "Case top / right" << std::endl; + float crossing_theta_u_min = 0.f, crossing_theta_v_min = 0.f; + float crossing_theta_u_max = 0.f, crossing_theta_v_max = 0.f; + computePerpendicularAxesIntersections(center_u, center_v, radius, img_w, 0, crossing_theta_u_min, crossing_theta_u_max, crossing_theta_v_min, crossing_theta_v_max); + } + else if (touchBottomBorder && touchTopBorder && (touchLeftBorder ^ touchRightBorder)) { + // Touches/intersects the top and bottom borders of the RoI + std::cout << "Case bottom / top" << std::endl; + // computeOppositeAxesIntersections ? + } + else if (touchLeftBorder && touchRightBorder && (touchTopBorder ^ touchBottomBorder)) { + // Touches/intersects the left and right borders of the RoI + std::cout << "Case right / left" << std::endl; + // computeOppositeAxesIntersections ? + } + else if (touchBottomBorder && touchLeftBorder && touchRightBorder && touchTopBorder) { + // Touches/intersects each axis + std::cout << "Case all" << std::endl; + } float arcLength = deltaTheta * radius; return arcLength; } diff --git a/modules/core/test/tools/geometry/testImageCircle.cpp b/modules/core/test/tools/geometry/testImageCircle.cpp index 1361abc620..c3cbd81076 100644 --- a/modules/core/test/tools/geometry/testImageCircle.cpp +++ b/modules/core/test/tools/geometry/testImageCircle.cpp @@ -50,6 +50,7 @@ int main() const float HEIGHT = 480.f; const float RADIUS = std::min(WIDTH, HEIGHT) / 10.f; vpRect roi(0, 0, WIDTH, HEIGHT); + bool hasSucceeded = true; // Test with no intersections { @@ -59,7 +60,7 @@ int main() bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); std::string statusTest; if (isValueOK) { - statusTest = "OK"; + statusTest = "SUCCESS"; } else { statusTest = "FAILED"; @@ -67,12 +68,31 @@ int main() std::cout << "Test no intersection." << std::endl; std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; - std::cout << "\ttest OK = " << statusTest << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; - if (!isValueOK) { - std::cerr << "Problem with the computeArcLengthInRoI function!" << std::endl; - return EXIT_FAILURE; + hasSucceeded &= isValueOK; + } + + // Test circle touching borders of the RoI + { + vpRect roiSquare(0, 0, HEIGHT, HEIGHT); + vpImageCircle noIntersect(vpImagePoint(HEIGHT / 2.f, HEIGHT / 2.f), HEIGHT / 2.f); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = 2.f * M_PI * RADIUS; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; } + std::cout << "Test circle touching borders of the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; } // Test with intersections with the left border, more than half a circle visible @@ -86,7 +106,7 @@ int main() bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); std::string statusTest; if (isValueOK) { - statusTest = "OK"; + statusTest = "SUCCESS"; } else { statusTest = "FAILED"; @@ -94,12 +114,9 @@ int main() std::cout << "Test intersection left border, more than half a circle visible." << std::endl; std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; - std::cout << "\ttest OK = " << statusTest << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; - if (!isValueOK) { - std::cerr << "Problem with the computeArcLengthInRoI function!" << std::endl; - return EXIT_FAILURE; - } + hasSucceeded &= isValueOK; } // Test with intersections with the left border, less than half a circle visible @@ -113,7 +130,7 @@ int main() bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); std::string statusTest; if (isValueOK) { - statusTest = "OK"; + statusTest = "SUCCESS"; } else { statusTest = "FAILED"; @@ -121,12 +138,33 @@ int main() std::cout << "Test intersection left border, less than half a circle visible." << std::endl; std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; - std::cout << "\ttest OK = " << statusTest << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } - if (!isValueOK) { - std::cerr << "Problem with the computeArcLengthInRoI function!" << std::endl; - return EXIT_FAILURE; + // Test with circle touching the left border, all the circle is visible + { + // Formula: uc = - RADIUS * cos(theta) + float uc = RADIUS; + float vc = 100.f; + vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = 2.f * M_PI * RADIUS; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; } + else { + statusTest = "FAILED"; + } + std::cout << "Test with circle touching the left border, all the circle is visible." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; } // Test with intersections with the right border, more than half a circle visible @@ -140,7 +178,7 @@ int main() bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); std::string statusTest; if (isValueOK) { - statusTest = "OK"; + statusTest = "SUCCESS"; } else { statusTest = "FAILED"; @@ -148,12 +186,9 @@ int main() std::cout << "Test intersection right border, more than half a circle visible." << std::endl; std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; - std::cout << "\ttest OK = " << statusTest << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; - if (!isValueOK) { - std::cerr << "Problem with the computeArcLengthInRoI function!" << std::endl; - return EXIT_FAILURE; - } + hasSucceeded &= isValueOK; } // Test with intersections with the right border, less than half a circle visible @@ -167,7 +202,7 @@ int main() bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); std::string statusTest; if (isValueOK) { - statusTest = "OK"; + statusTest = "SUCCESS"; } else { statusTest = "FAILED"; @@ -175,12 +210,33 @@ int main() std::cout << "Test intersection right border, less than half a circle visible." << std::endl; std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; - std::cout << "\ttest OK = " << statusTest << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; - if (!isValueOK) { - std::cerr << "Problem with the computeArcLengthInRoI function!" << std::endl; - return EXIT_FAILURE; + hasSucceeded &= isValueOK; + } + + // Test with circle touching the right border, all the circle is visible + { + // Formula: uc = WIDTH - RADIUS * cos(theta) + float uc = WIDTH - RADIUS; + float vc = 100.f; + vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = 2.f * M_PI * RADIUS; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; } + else { + statusTest = "FAILED"; + } + std::cout << "Test with circle touching the right border, all the circle is visible." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; } // Test with intersections with the top border, more than half a circle visible @@ -194,7 +250,7 @@ int main() bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); std::string statusTest; if (isValueOK) { - statusTest = "OK"; + statusTest = "SUCCESS"; } else { statusTest = "FAILED"; @@ -202,12 +258,9 @@ int main() std::cout << "Test intersection top border, more than half a circle visible." << std::endl; std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; - std::cout << "\ttest OK = " << statusTest << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; - if (!isValueOK) { - std::cerr << "Problem with the computeArcLengthInRoI function!" << std::endl; - return EXIT_FAILURE; - } + hasSucceeded &= isValueOK; } // Test with intersections with the top border, less than half a circle visible @@ -221,7 +274,7 @@ int main() bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); std::string statusTest; if (isValueOK) { - statusTest = "OK"; + statusTest = "SUCCESS"; } else { statusTest = "FAILED"; @@ -229,12 +282,33 @@ int main() std::cout << "Test intersection top border, less than half a circle visible." << std::endl; std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; - std::cout << "\ttest OK = " << statusTest << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } - if (!isValueOK) { - std::cerr << "Problem with the computeArcLengthInRoI function!" << std::endl; - return EXIT_FAILURE; + // Test with circle touching the top border, all the circle is visible + { + // Formula: vc = - RADIUS * sin(theta) + float uc = 100.f; + float vc = RADIUS; + vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = 2.f * M_PI * RADIUS; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; } + else { + statusTest = "FAILED"; + } + std::cout << "Test with circle touching the top border, all the circle is visible." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; } // Test with intersections with the bottom border, more than half a circle visible @@ -248,7 +322,7 @@ int main() bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); std::string statusTest; if (isValueOK) { - statusTest = "OK"; + statusTest = "SUCCESS"; } else { statusTest = "FAILED"; @@ -256,12 +330,9 @@ int main() std::cout << "Test intersection bottom border, more than half a circle visible." << std::endl; std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; - std::cout << "\ttest OK = " << statusTest << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; - if (!isValueOK) { - std::cerr << "Problem with the computeArcLengthInRoI function!" << std::endl; - return EXIT_FAILURE; - } + hasSucceeded &= isValueOK; } // Test with intersections with the bottom border, less than half a circle visible @@ -275,7 +346,7 @@ int main() bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); std::string statusTest; if (isValueOK) { - statusTest = "OK"; + statusTest = "SUCCESS"; } else { statusTest = "FAILED"; @@ -283,14 +354,39 @@ int main() std::cout << "Test intersection bottom border, less than half a circle visible." << std::endl; std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; - std::cout << "\ttest OK = " << statusTest << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; - if (!isValueOK) { - std::cerr << "Problem with the computeArcLengthInRoI function!" << std::endl; - return EXIT_FAILURE; + hasSucceeded &= isValueOK; + } + + // Test with circle touching the top border, all the circle is visible + { + // Formula: vc = HEIGHT - RADIUS * sin(theta) + float uc = 100.f; + float vc = HEIGHT - RADIUS; + vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = 2.f * M_PI * RADIUS; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; } + std::cout << "Test with circle touching the top border, all the circle is visible." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; } - std::cout << "vpImageCircle is ok." << std::endl; - return EXIT_SUCCESS; + if (hasSucceeded) { + std::cout << "testImageCircle overall result: SUCCESS"; + return EXIT_SUCCESS; + } + std::cout << "testImageCircle overall result: FAILED"; + return EXIT_FAILURE; } From e6a2865be0da9b47d815dbdd5802e08f1ef3982b Mon Sep 17 00:00:00 2001 From: rlagneau Date: Wed, 27 Sep 2023 10:14:22 +0200 Subject: [PATCH 03/22] [WIP] Added cases of crossing top and left axes once, and crossing one of the two axes outside the RoI --- modules/core/src/image/vpImageCircle.cpp | 232 ++++++++++++++---- .../test/tools/geometry/testImageCircle.cpp | 186 ++++++++++---- 2 files changed, 334 insertions(+), 84 deletions(-) diff --git a/modules/core/src/image/vpImageCircle.cpp b/modules/core/src/image/vpImageCircle.cpp index 071d8e1a60..f1a6b9c069 100644 --- a/modules/core/src/image/vpImageCircle.cpp +++ b/modules/core/src/image/vpImageCircle.cpp @@ -86,13 +86,16 @@ float getAngleBetweenMinPiAndPi(const float &theta) * only with the left border of the Region of Interest (RoI). * * \param[in] u_c The u-coordinate of the center of the circle. + * \param[in] umin_roi The minimum u-coordinate, i.e. the left border, of the RoI. * \param[in] radius The radius of the circle. * \param[out] delta_theta The length of the angular interval that is in the RoI. */ -void computeIntersectionsLeftBorderOnly(const float &u_c, const float &radius, +void computeIntersectionsLeftBorderOnly(const float &u_c, const float &umin_roi, const float &radius, float &delta_theta) { - float theta1 = std::acos(-1.f * u_c / radius); + // umin_roi = u_c + r cos(theta) + // theta = acos((umin_roi - u_c) / r) + float theta1 = std::acos((umin_roi - u_c)/ radius); theta1 = getAngleBetweenMinPiAndPi(theta1); float theta2 = -1.f * theta1; float theta_min = std::min(theta1, theta2); @@ -105,14 +108,16 @@ void computeIntersectionsLeftBorderOnly(const float &u_c, const float &radius, * only with the right border of the Region of Interest (RoI). * * \param[in] u_c The u-coordinate of the center of the circle. - * \param[in] width The width of the RoI. + * \param[in] umax_roi The maximum u-coordinate, i.e. the right border, of the RoI. * \param[in] radius The radius of the circle. * \param[out] delta_theta The length of the angular interval that is in the RoI. */ -void computeIntersectionsRightBorderOnly(const float &u_c, const float &width, const float &radius, +void computeIntersectionsRightBorderOnly(const float &u_c, const float &umax_roi, const float &radius, float &delta_theta) { - float theta1 = std::acos((width - u_c) / radius); + // u = u_c + r cos(theta) + // theta = acos((u - u_c) / r) + float theta1 = std::acos((umax_roi - u_c) / radius); theta1 = getAngleBetweenMinPiAndPi(theta1); float theta2 = -1.f * theta1; float theta_min = std::min(theta1, theta2); @@ -125,13 +130,16 @@ void computeIntersectionsRightBorderOnly(const float &u_c, const float &width, c * only with the top border of the Region of Interest (RoI). * * \param[in] v_c The v-coordinate of the center of the circle. + * \param[in] vmin_roi The minimum v-coordinate, i.e. the left border, of the RoI. * \param[in] radius The radius of the circle. * \param[out] delta_theta The length of the angular interval that is in the RoI. */ -void computeIntersectionsTopBorderOnly(const float &v_c, const float &radius, +void computeIntersectionsTopBorderOnly(const float &v_c, const float &vmin_roi, const float &radius, float &delta_theta) { - float theta1 = std::asin(-1.f * v_c / radius); + // v = vc - r sin(theta) because the v-axis goes down + // theta = asin((vc - v)/r) + float theta1 = std::asin((v_c - vmin_roi) / radius); theta1 = getAngleBetweenMinPiAndPi(theta1); float theta2 = 0.f; @@ -161,14 +169,16 @@ void computeIntersectionsTopBorderOnly(const float &v_c, const float &radius, * only with the left border of the Region of Interest (RoI). * * \param[in] v_c The v-coordinate of the center of the circle. - * \param[in] height The height of the RoI. + * \param[in] vmax_roi The maximum v-coordinate, i.e. the bottom border, of the RoI. * \param[in] radius The radius of the circle. * \param[out] delta_theta The length of the angular interval that is in the RoI. */ -void computeIntersectionsBottomBorderOnly(const float &v_c, const float &height, const float &radius, +void computeIntersectionsBottomBorderOnly(const float &v_c, const float &vmax_roi, const float &radius, float &delta_theta) { - float theta1 = std::asin((height - v_c) / radius); + // v = vc - r sin(theta) because the v-axis goes down + // theta = asin((vc - v)/r) + float theta1 = std::asin((v_c - vmax_roi) / radius); theta1 = getAngleBetweenMinPiAndPi(theta1); float theta2 = 0.f; @@ -202,17 +212,20 @@ void computeIntersectionsBottomBorderOnly(const float &v_c, const float &height, * \param[in] radius The radius of the circle. * \param[in] crossing_u The horizontal u-axis coordinate of the crossing point with the v-axis. * \param[in] crossing_v The vertical v-axis coordinate of the crossing point with the u-axis. - * \param[out] theta_u_cross_min The smallest angle for which the circle intersects the u-axis, i.e. \b theta_u_cross_min < \b theta_u_cross_max . - * \param[out] theta_u_cross_max The highest angle for which the circle intersects the u-axis. - * \param[out] theta_v_cross_min The smallest angle for which the circle intersects the v-axis; i.e. \b theta_v_cross_min < \b theta_v_cross_max . - * \param[out] theta_v_cross_max The highest angle for which the circle intersects the v-axis. + * \param[out] theta_u_cross_min The pair angle /u-coordinate for which the circle intersects the u-axis with the lowest u-coordinate, i.e. \b theta_u_cross_min.second < \b theta_u_cross_max.second . + * \param[out] theta_u_cross_max The pair angle /u-coordinate for which the circle intersects the u-axis with the highest u-coordinate. + * \param[out] theta_v_cross_min The pair angle /v-coordinate for which the circle intersects the v-axis with the lowest v-coordinate; i.e. \b theta_v_cross_min.second < \b theta_v_cross_max.second . + * \param[out] theta_v_cross_max The pair angle /v-coordinate for which the circle intersects the v-axis with the highest v-coordinate. */ void computePerpendicularAxesIntersections(const float &u_c, const float &v_c, const float &radius, const float &crossing_u, const float &crossing_v, - float &theta_u_cross_min, float &theta_u_cross_max, - float &theta_v_cross_min, float &theta_v_cross_max) + std::pair &theta_u_cross_min, std::pair &theta_u_cross_max, + std::pair &theta_v_cross_min, std::pair &theta_v_cross_max) { - float theta_u_cross = std::asin((crossing_u - v_c)/radius); + // Computing the two angles for which the u-axis is crossed + // v = vc - r sin(theta) because the v-axis goes down + // theta = asin((vc - v)/r) + float theta_u_cross = std::asin((v_c - crossing_u)/radius); theta_u_cross = getAngleBetweenMinPiAndPi(theta_u_cross); float theta_u_cross_2 = 0.f; if (theta_u_cross > 0) { @@ -221,16 +234,154 @@ void computePerpendicularAxesIntersections(const float &u_c, const float &v_c, c else { theta_u_cross_2 = -M_PI - theta_u_cross; } - theta_u_cross_min = std::min(theta_u_cross, theta_u_cross_2); - theta_u_cross_max = std::max(theta_u_cross, theta_u_cross_2); + // Computing the corresponding u-coordinates at which the u-axis is crossed + float u_ucross = u_c + radius * std::cos(theta_u_cross); + float u_ucross2 = u_c + radius * std::cos(theta_u_cross_2); + // Sorting the outputs such as theta_X_cross_min.second < theta_X_cross_max.second + if (u_ucross < u_ucross2) { + theta_u_cross_min.first = theta_u_cross; + theta_u_cross_min.second = u_ucross; + theta_u_cross_max.first = theta_u_cross_2; + theta_u_cross_max.second = u_ucross2; + } + else { + theta_u_cross_min.first = theta_u_cross_2; + theta_u_cross_min.second = u_ucross2; + theta_u_cross_max.first = theta_u_cross; + theta_u_cross_max.second = u_ucross; + } + // Computing the two angles for which the v-axis is crossed + // u = u_c + r cos(theta) + // theta = acos((u - u_c) / r) float theta_v_cross = std::acos((crossing_v - u_c)/radius); theta_v_cross = getAngleBetweenMinPiAndPi(theta_v_cross); float theta_v_cross_2 = -theta_v_cross; - theta_v_cross_min = std::min(theta_v_cross, theta_v_cross_2); - theta_v_cross_max = std::max(theta_v_cross, theta_v_cross_2); + // Computing the corresponding v-coordinates at which the v-axis is crossed + // v = v_c - radius sin(theta) because the v-axis is oriented towards the bottom + float v_vcross = v_c - radius * std::sin(theta_v_cross); + float v_vcross2 = v_c - radius * std::sin(theta_v_cross_2); + // Sorting the outputs such as theta_X_cross_min.second < theta_X_cross_max.second + if (v_vcross < v_vcross2) { + theta_v_cross_min.first = theta_v_cross; + theta_v_cross_min.second = v_vcross; + theta_v_cross_max.first = theta_v_cross_2; + theta_v_cross_max.second = v_vcross2; + } + else { + theta_v_cross_min.first = theta_v_cross_2; + theta_v_cross_min.second = v_vcross2; + theta_v_cross_max.first = theta_v_cross; + theta_v_cross_max.second = v_vcross; + } } +/*! + * \brief Compute the length of the angular interval of the circle when it intersects + * only with the left and top borders of the Region of Interest (RoI). + * + * \param[in] u_c The horizontal u-axis coordinate of the center. + * \param[in] v_c The vertical v-axis coordinate of the center. + * \param[in] topLeft The top left corner of the RoI. + * \param[in] radius The radius of the circle. + * \param[out] delta_theta The length of the angular interval that is in the RoI. + */ +void computeTopLeftIntersections(const float &u_c, const float &v_c, const vpImagePoint &topLeft, const float &radius, + float &delta_theta) +{ + std::pair crossing_theta_u_min, crossing_theta_u_max; + std::pair crossing_theta_v_min, crossing_theta_v_max; + float crossing_u = topLeft.get_v(); // We cross the u-axis of the RoI at which v-coordinate + float vmin_roi = crossing_u; // The minimum v-coordinate of the RoI + float crossing_v = topLeft.get_u(); // We cross the v-axis of the RoI at which u-coordinate + float umin_roi = crossing_v; // The minimum u-coordinate of the RoI + computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u, crossing_v, + crossing_theta_u_min, crossing_theta_u_max, + crossing_theta_v_min, crossing_theta_v_max); + float theta_u_min = crossing_theta_u_min.first, theta_v_min = crossing_theta_v_min.first; + float theta_u_max = crossing_theta_u_max.first, theta_v_max = crossing_theta_v_max.first; + float u_umin = crossing_theta_u_min.second; + float u_umax = crossing_theta_u_max.second; + float v_vmin = crossing_theta_v_min.second; + float v_vmax = crossing_theta_v_max.second; + std::cout << "umin_roi = " << umin_roi << "\tvmin_roi = " << vmin_roi << std::endl; + std::cout << "u_umin = " << u_umin << " (" << theta_u_min << ")\tu_umax = " << u_umax << " (" << theta_u_max << ")" << std::endl; + std::cout << "v_vmin = " << v_vmin << " (" << theta_v_min << ")\tv_vmax = " << v_vmax << " (" << theta_v_max << ")" << std::endl; + if (u_umin < umin_roi && u_umax >= umin_roi && v_vmin < vmin_roi && v_vmax >= vmin_roi) { + // The circle crosses only once each axis + std::cout << "\t|->Case crossing once, center below top border" << std::endl; + delta_theta = theta_u_max - theta_v_max; + } + else if (u_umin >= umin_roi && u_umax >= umin_roi && v_vmin >= vmin_roi && v_vmax >= vmin_roi) { + // The circle crosses twice each axis + std::cout << "\t|->Case crossing twice" << std::endl; + delta_theta = (theta_v_min - theta_u_min) + (theta_u_max - theta_v_max); + } + else if (u_umin < umin_roi && u_umax < umin_roi && v_vmin >= vmin_roi && v_vmax >= vmin_roi) { + // The circle crosses the u-axis outside the roi + // so it is equivalent to the case of crossing only the left border + std::cout << "\t|->Case left only" << std::endl; + computeIntersectionsLeftBorderOnly(u_c, umin_roi, radius, delta_theta); + } + else if (u_umin >= umin_roi && u_umax >= umin_roi && v_vmin <= vmin_roi && v_vmax <= vmin_roi) { + // The circle crosses the v-axis outside the roi + // so it is equivalent to the case of crossing only the top border + std::cout << "\t|->Case top only" << std::endl; + computeIntersectionsTopBorderOnly(v_c, vmin_roi, radius, delta_theta); + // delta_theta = theta_u_max - theta_u_min; + } +} + +/*! + * \brief Compute the length of the angular interval of the circle when it intersects + * only with the right and top borders of the Region of Interest (RoI). + * + * \param[in] u_c The horizontal u-axis coordinate of the center. + * \param[in] v_c The vertical v-axis coordinate of the center. + * \param[in] vmin_roi The top v-coordinate of the RoI. + * \param[in] umax_roi The right u-coordinate of the RoI. + * \param[in] radius The radius of the circle. + * \param[out] delta_theta The length of the angular interval that is in the RoI. + */ +void computeTopRightIntersections(const float &u_c, const float &v_c, const float &vmin_roi, const float &umax_roi, const float &radius, + float &delta_theta) +{ + std::pair crossing_theta_u_min, crossing_theta_u_max; + std::pair crossing_theta_v_min, crossing_theta_v_max; + computePerpendicularAxesIntersections(u_c, v_c, radius, vmin_roi, umax_roi, + crossing_theta_u_min, crossing_theta_u_max, + crossing_theta_v_min, crossing_theta_v_max); + float theta_u_min = crossing_theta_u_min.first, theta_v_min = crossing_theta_v_min.first; + float theta_u_max = crossing_theta_u_max.first, theta_v_max = crossing_theta_v_max.first; + float u_umin = crossing_theta_u_min.second; + float u_umax = crossing_theta_u_max.second; + float v_vmin = crossing_theta_v_min.second; + float v_vmax = crossing_theta_v_max.second; + if (u_umin <= umax_roi && v_vmin < vmin_roi && u_umax > umax_roi && v_vmax >= vmin_roi) { + // The circle crosses only once each axis and the center is below the top border + delta_theta = theta_v_max - theta_u_min; + if (delta_theta < 0) { + // The arc cannot be negative + delta_theta += 2.f * M_PI; + } + } + else if (u_umin <= umax_roi && v_vmin >= vmin_roi && u_umax <= umax_roi && v_vmax >= vmin_roi) { + // The circle crosses twice each axis + delta_theta = (2 * M_PI + theta_v_max - theta_u_min) + (theta_v_min - theta_u_max); + } + else if (true) { + // The circle crosses the u-axis outside the roi + // so it is equivalent to the case of crossing only the right border + computeIntersectionsRightBorderOnly(u_c, umax_roi, radius, delta_theta); + } + else if (true) { + // The circle crosses the v-axis outside the roi + // so it is equivalent to the case of crossing only the left border + computeIntersectionsTopBorderOnly(v_c, vmin_roi, radius, delta_theta); + } +} + + float vpImageCircle::computeArcLengthInRoI(const vpRect &roi) const { float deltaTheta = 0.f; @@ -238,12 +389,17 @@ float vpImageCircle::computeArcLengthInRoI(const vpRect &roi) const float center_u = center.get_u(); float center_v = center.get_v(); float radius = m_radius; - float img_w = roi.getWidth(); - float img_h = roi.getHeight(); - bool touchLeftBorder = (center_u - radius) <= 0.; - bool touchRightBorder = (center_u + radius) >= img_w; - bool touchTopBorder = (center_v - radius) <= 0.; - bool touchBottomBorder = (center_v + radius) >= img_h; + float roi_w = roi.getWidth(); + float roi_h = roi.getHeight(); + vpImagePoint topLeft = roi.getTopLeft(); + float umin_roi = topLeft.get_u(); + float vmin_roi = topLeft.get_v(); + float umax_roi = topLeft.get_u() + roi_w; + float vmax_roi = topLeft.get_v() + roi_h; + bool touchLeftBorder = (center_u - radius) <= umin_roi; + bool touchRightBorder = (center_u + radius) >= umax_roi; + bool touchTopBorder = (center_v - radius) <= vmin_roi; + bool touchBottomBorder = (center_v + radius) >= vmax_roi; bool isHorizontallyOK = (!touchLeftBorder && !touchRightBorder); bool isVerticallyOK = (!touchTopBorder && !touchBottomBorder); if (isHorizontallyOK && isVerticallyOK && roi.isInside(m_center)) { @@ -255,50 +411,40 @@ float vpImageCircle::computeArcLengthInRoI(const vpRect &roi) const else if (touchBottomBorder && !touchLeftBorder && !touchRightBorder && !touchTopBorder) { // Touches/intersects only the bottom border of the RoI std::cout << "Case bottom only" << std::endl; - computeIntersectionsBottomBorderOnly(center_v, img_h, radius, deltaTheta); + computeIntersectionsBottomBorderOnly(center_v, vmax_roi, radius, deltaTheta); } else if (!touchBottomBorder && touchLeftBorder && !touchRightBorder && !touchTopBorder) { // Touches/intersects only the left border of the RoI std::cout << "Case left only" << std::endl; - computeIntersectionsLeftBorderOnly(center_u, radius, deltaTheta); + computeIntersectionsLeftBorderOnly(center_u, umin_roi, radius, deltaTheta); } else if (!touchBottomBorder && !touchLeftBorder && touchRightBorder && !touchTopBorder) { // Touches/intersects only the right border of the RoI std::cout << "Case right only" << std::endl; - computeIntersectionsRightBorderOnly(center_u, img_w, radius, deltaTheta); + computeIntersectionsRightBorderOnly(center_u, umax_roi, radius, deltaTheta); } else if (!touchBottomBorder && !touchLeftBorder && !touchRightBorder && touchTopBorder) { // Touches/intersects only the top border of the RoI std::cout << "Case top only" << std::endl; - computeIntersectionsTopBorderOnly(center_v, radius, deltaTheta); + computeIntersectionsTopBorderOnly(center_v, vmin_roi, radius, deltaTheta); } else if (touchBottomBorder && touchLeftBorder && !touchRightBorder && !touchTopBorder) { // Touches/intersects the bottom and left borders of the RoI std::cout << "Case bottom / left" << std::endl; - float crossing_theta_u_min = 0.f, crossing_theta_v_min = 0.f; - float crossing_theta_u_max = 0.f, crossing_theta_v_max = 0.f; - computePerpendicularAxesIntersections(center_u, center_v, radius, 0, img_h, crossing_theta_u_min, crossing_theta_u_max, crossing_theta_v_min, crossing_theta_v_max); } else if (touchBottomBorder && !touchLeftBorder && touchRightBorder && !touchTopBorder) { // Touches/intersects the bottom and right borders of the RoI std::cout << "Case bottom / right" << std::endl; - float crossing_theta_u_min = 0.f, crossing_theta_v_min = 0.f; - float crossing_theta_u_max = 0.f, crossing_theta_v_max = 0.f; - computePerpendicularAxesIntersections(center_u, center_v, radius, img_w, img_h, crossing_theta_u_min, crossing_theta_u_max, crossing_theta_v_min, crossing_theta_v_max); } else if (!touchBottomBorder && touchLeftBorder && !touchRightBorder && touchTopBorder) { // Touches/intersects the top and left borders of the RoI std::cout << "Case top / left" << std::endl; - float crossing_theta_u_min = 0.f, crossing_theta_v_min = 0.f; - float crossing_theta_u_max = 0.f, crossing_theta_v_max = 0.f; - computePerpendicularAxesIntersections(center_u, center_v, radius, 0, 0, crossing_theta_u_min, crossing_theta_u_max, crossing_theta_v_min, crossing_theta_v_max); + computeTopLeftIntersections(center_u, center_v, topLeft, radius, deltaTheta); } else if (!touchBottomBorder && !touchLeftBorder && touchRightBorder && touchTopBorder) { // Touches/intersects the top and right borders of the RoI std::cout << "Case top / right" << std::endl; - float crossing_theta_u_min = 0.f, crossing_theta_v_min = 0.f; - float crossing_theta_u_max = 0.f, crossing_theta_v_max = 0.f; - computePerpendicularAxesIntersections(center_u, center_v, radius, img_w, 0, crossing_theta_u_min, crossing_theta_u_max, crossing_theta_v_min, crossing_theta_v_max); + computeTopRightIntersections(center_u, center_v, vmin_roi, umax_roi, radius, deltaTheta); } else if (touchBottomBorder && touchTopBorder && (touchLeftBorder ^ touchRightBorder)) { // Touches/intersects the top and bottom borders of the RoI diff --git a/modules/core/test/tools/geometry/testImageCircle.cpp b/modules/core/test/tools/geometry/testImageCircle.cpp index c3cbd81076..f38b66469f 100644 --- a/modules/core/test/tools/geometry/testImageCircle.cpp +++ b/modules/core/test/tools/geometry/testImageCircle.cpp @@ -46,10 +46,11 @@ bool compareAngles(const float &actualVal, const float &theoreticalVal) int main() { + const float OFFSET = 5.f; const float WIDTH = 640.f; const float HEIGHT = 480.f; const float RADIUS = std::min(WIDTH, HEIGHT) / 10.f; - vpRect roi(0, 0, WIDTH, HEIGHT); + vpRect roi(OFFSET, OFFSET, WIDTH, HEIGHT); bool hasSucceeded = true; // Test with no intersections @@ -75,8 +76,8 @@ int main() // Test circle touching borders of the RoI { - vpRect roiSquare(0, 0, HEIGHT, HEIGHT); - vpImageCircle noIntersect(vpImagePoint(HEIGHT / 2.f, HEIGHT / 2.f), HEIGHT / 2.f); + vpRect roiSquare(OFFSET, OFFSET, HEIGHT, HEIGHT); + vpImageCircle noIntersect(vpImagePoint(OFFSET + HEIGHT / 2.f, OFFSET + HEIGHT / 2.f), HEIGHT / 2.f); float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); float theoreticalValue = 2.f * M_PI * RADIUS; bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); @@ -97,9 +98,9 @@ int main() // Test with intersections with the left border, more than half a circle visible { - // Formula: uc = - RADIUS * cos(theta) - float uc = 24.f; - float vc = 100.f; + // Formula: uc = OFFSET - RADIUS * cos(theta) + float uc = OFFSET + 24.f; + float vc = OFFSET + 100.f; vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); float theoreticalValue = 4.f * M_PI * RADIUS /3.f; @@ -121,9 +122,9 @@ int main() // Test with intersections with the left border, less than half a circle visible { - // Formula: uc = - RADIUS * cos(theta) - float uc = -24.f; - float vc = 100.f; + // Formula: uc = OFFSET - RADIUS * cos(theta) + float uc = OFFSET - 24.f; + float vc = OFFSET + 100.f; vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); float theoreticalValue = 2.f * M_PI * RADIUS /3.f; @@ -145,9 +146,9 @@ int main() // Test with circle touching the left border, all the circle is visible { - // Formula: uc = - RADIUS * cos(theta) - float uc = RADIUS; - float vc = 100.f; + // Formula: uc = OFFSET - RADIUS * cos(theta) + float uc = OFFSET + RADIUS; + float vc = OFFSET + 100.f; vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); float theoreticalValue = 2.f * M_PI * RADIUS; @@ -169,9 +170,9 @@ int main() // Test with intersections with the right border, more than half a circle visible { - // Formula: uc = WIDTH - RADIUS * cos(theta) - float uc = 616.f; - float vc = 100.f; + // Formula: uc = OFFSET + WIDTH - RADIUS * cos(theta) + float uc = OFFSET + 616.f; + float vc = OFFSET + 100.f; vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); float theoreticalValue = 4.f * M_PI * RADIUS /3.f; @@ -193,9 +194,9 @@ int main() // Test with intersections with the right border, less than half a circle visible { - // Formula: uc = WIDTH - RADIUS * cos(theta) - float uc = 664.f; - float vc = 100.f; + // Formula: uc = OFFSET + WIDTH - RADIUS * cos(theta) + float uc = OFFSET + 664.f; + float vc = OFFSET + 100.f; vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); float theoreticalValue = 2.f * M_PI * RADIUS /3.f; @@ -217,9 +218,9 @@ int main() // Test with circle touching the right border, all the circle is visible { - // Formula: uc = WIDTH - RADIUS * cos(theta) - float uc = WIDTH - RADIUS; - float vc = 100.f; + // Formula: uc = OFFSET + WIDTH - RADIUS * cos(theta) + float uc = OFFSET + WIDTH - RADIUS; + float vc = OFFSET + 100.f; vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); float theoreticalValue = 2.f * M_PI * RADIUS; @@ -241,9 +242,11 @@ int main() // Test with intersections with the top border, more than half a circle visible { - // Formula: vc = - RADIUS * sin(theta) - float uc = 100.f; - float vc = -41.56921938f; + // v = vc - r sin(theta) + // Formula: vc = OFFSET + RADIUS * sin(theta) + float theta = M_PI / 3.f; + float uc = OFFSET + 100.f; + float vc = OFFSET + RADIUS * sin(theta); vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); float theoreticalValue = 5.f * M_PI * RADIUS /3.f; @@ -265,9 +268,11 @@ int main() // Test with intersections with the top border, less than half a circle visible { - // Formula: vc = - RADIUS * sin(theta) - float uc = 100.f; - float vc = 41.56921938f; + // v = vc - r sin(theta) + // Formula: vc = OFFSET + RADIUS * sin(theta) + float theta = -2.f * M_PI/3.f; + float uc = OFFSET + 100.f; + float vc = OFFSET + RADIUS * std::sin(theta); vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); float theoreticalValue = M_PI * RADIUS /3.f; @@ -289,9 +294,11 @@ int main() // Test with circle touching the top border, all the circle is visible { - // Formula: vc = - RADIUS * sin(theta) - float uc = 100.f; - float vc = RADIUS; + // v = vc - r sin(theta) + // Formula: vc = OFFSET + RADIUS * sin(theta) + float theta = M_PI_2; + float uc = OFFSET + 100.f; + float vc = OFFSET + RADIUS * sin(theta); vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); float theoreticalValue = 2.f * M_PI * RADIUS; @@ -313,9 +320,11 @@ int main() // Test with intersections with the bottom border, more than half a circle visible { - // Formula: vc = HEIGHT - RADIUS * sin(theta) - float uc = 100.f; - float vc = 521.569219381653f; + // v = vc - r sin(theta) + // Formula: vc = OFFSET + HEIGHT + RADIUS * sin(theta) + float theta = -M_PI / 3.f; + float uc = OFFSET + 100.f; + float vc = OFFSET + HEIGHT + RADIUS * std::sin(theta); vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); float theoreticalValue = 5.f * M_PI * RADIUS /3.f; @@ -337,9 +346,11 @@ int main() // Test with intersections with the bottom border, less than half a circle visible { - // Formula: vc = HEIGHT - RADIUS * sin(theta) - float uc = 100.f; - float vc = 438.430780618347f; + // v = vc - r sin(theta) + // Formula: vc = OFFSET + HEIGHT + RADIUS * sin(theta) + float theta = M_PI / 3.f; + float uc = OFFSET + 100.f; + float vc = OFFSET + HEIGHT + RADIUS * std::sin(theta); vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); float theoreticalValue = M_PI * RADIUS /3.f; @@ -359,11 +370,11 @@ int main() hasSucceeded &= isValueOK; } - // Test with circle touching the top border, all the circle is visible + // Test with circle touching the bottom border, all the circle is visible { - // Formula: vc = HEIGHT - RADIUS * sin(theta) - float uc = 100.f; - float vc = HEIGHT - RADIUS; + // Formula: vc = OFFSET + HEIGHT - RADIUS * sin(theta) + float uc = OFFSET + 100.f; + float vc = OFFSET + HEIGHT - RADIUS; vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); float theoreticalValue = 2.f * M_PI * RADIUS; @@ -375,7 +386,100 @@ int main() else { statusTest = "FAILED"; } - std::cout << "Test with circle touching the top border, all the circle is visible." << std::endl; + std::cout << "Test with circle touching the bottom border, all the circle is visible." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + + // Test with intersections with the top and the left border, crossing each axis once in the RoI + { + // Formula: u1 = uc + r cos (theta1) ; vmin = vc + r sin(theta1) + // Formula: umin = uc + r cos(theta 2) ; v = vc + r sin(theta2) + // Choice: theta1 - theta2 = pi / 2 => for theta1 = 0 theta2 = -pi/2 + // => uc = umin - r cos(theta2) vc = vmin - r sin(theta1) + float uc = OFFSET; + float vc = OFFSET; + vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = M_PI_2 * RADIUS; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the top and the left border, crossing each axis once in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + + // Test with intersections with the top and the left border + // but crossing only the left axis in the RoI + { + // (1): u1 = uc + rcos(theta1) <= umin ; vmin = vc - r sin(theta1) + // (2): u2 = uc + rcos(theta2) <= umin ; vmin = vc - r sin(theta2) + // (3): umin = uc + r cos(theta3) ; v3 = vc - r sin(theta3) + // (4): umin = uc + r cos(theta4) ; v4 = vc - r sin(theta4) + // (3) & (4) => uc = umin - r cos(theta3) = umin - r cos(theta4) <=> theta3 = - theta4 + // (3) & (4) => vc >= vmin + r sin(theta3) && vc >= vmin + r sin (theta4) + float theta = M_PI / 4.f; + float uc = OFFSET - RADIUS * std::cos(theta); + float vc = OFFSET + RADIUS * std::sin(theta) + 1.f; + vc = std::max(vc, OFFSET + RADIUS * std::sin(-theta) + 1.f); + vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = M_PI_2 * RADIUS; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the top and the left border but crossing only the left axis in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + + // Test with intersections with the top and the left border + // but crossing only the top axis in the RoI + { + // (1): u1 = uc + rcos(theta1) >= umin ; vmin = vc - r sin(theta1) + // (2): u2 = uc + rcos(theta2) >= umin ; vmin = vc - r sin(theta2) + // (3): umin = uc + r cos(theta3) ; v3 = vc - r sin(theta3) <= vmin + // (4): umin = uc + r cos(theta4) ; v4 = vc - r sin(theta4) <= vmin + // (1) & (2) => vmin = vc - r sin (theta1) = vc - r sin(theta2) <=> theta1 = PI - theta2 + // (1) => uc + r cos(theta1) >= umin <=> uc >= umin - r cos(theta1) + // (2) => uc + r cos(theta2) >= umin <=> uc >= umin - r cos(theta2) + + float theta = -1.1f * M_PI_2; + float uc = OFFSET - RADIUS * std::cos(theta) + 1.f; + uc = std::max(uc, OFFSET - RADIUS * std::cos((float)M_PI - theta) + 1.f); + float vc = OFFSET + RADIUS * std::sin(theta); + vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = 0.2f * M_PI_2 * RADIUS; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the top and the left border but crossing only the top axis in the RoI." << std::endl; std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; From 6340a8958cd02384483149a3cbbb38a1b3b6b2d8 Mon Sep 17 00:00:00 2001 From: rlagneau Date: Wed, 27 Sep 2023 11:19:07 +0200 Subject: [PATCH 04/22] [CORPS] Validated last case of intersection with both left and top borders --- .../test/tools/geometry/testImageCircle.cpp | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/modules/core/test/tools/geometry/testImageCircle.cpp b/modules/core/test/tools/geometry/testImageCircle.cpp index f38b66469f..0e5c6689bb 100644 --- a/modules/core/test/tools/geometry/testImageCircle.cpp +++ b/modules/core/test/tools/geometry/testImageCircle.cpp @@ -487,6 +487,56 @@ int main() hasSucceeded &= isValueOK; } + // Test with intersections with the top and the left border + // crossing twice each axis + { + // (1): u1 = uc + r cos(theta1) >= umin ; vmin = vc - r sin(theta1) + // (2): u2 = uc + r cos(theta2) >= umin ; vmin = vc - r sin(theta2) + // (3): umin = uc + r cos(theta3) ; v3 = vc - r sin(theta3) >= vmin + // (4): umin = uc + r cos(theta4) ; v4 = vc - r sin(theta4) >= vmin + // (1) & (2) => vmin = vc - r sin(theta1) = vc - r sin(theta2) <=> theta1 = PI - theta2 + // (1) & (2) =>{ uc >= umin - r cos(theta1) & { uc >= umin - r cos(PI - theta1) + // (1) & (2) { vc = vmin + r sin(theta1) & { vc = vmin + r sin(PI - theta1) + // (3) & (4) =>{ uc = umin - r cos(theta3) & { uc = umin - r cos( - theta3) + // (3) & (4) { vc >= vmin - r sin(theta3) & { vc >= vmin - r cos( - theta3) + + float theta1 = 5.f * M_PI / 8.f; + float theta2 = M_PI - theta1; + float uc = OFFSET - RADIUS * std::cos(theta1) + 1.f; + uc = std::max(uc, OFFSET - RADIUS * std::cos((float)M_PI - theta1) + 1.f); + float vc = OFFSET + RADIUS * std::sin(theta1); + float theta3 = std::acos((OFFSET - uc)/RADIUS); + if (theta3 > M_PI) { + theta3 -= 2.0 * M_PI; + } + else if (theta3 > M_PI) { + theta3 += 2.0 * M_PI; + } + float theta4 = -theta3; + if (theta4 < 0) { + float temp = theta4; + theta4 = theta3; + theta3 = temp; + } + vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = ((theta4 - theta1) + (theta2 - theta3)) * RADIUS; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the top and the left border crossing twice each axis ." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length = " << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + if (hasSucceeded) { std::cout << "testImageCircle overall result: SUCCESS"; return EXIT_SUCCESS; From e980cb7cfe5c1a28445c42ed51ca564db979315b Mon Sep 17 00:00:00 2001 From: rlagneau Date: Thu, 28 Sep 2023 13:05:22 +0200 Subject: [PATCH 05/22] [WIP] Added top right cases --- modules/core/src/image/vpImageCircle.cpp | 16 +- .../test/tools/geometry/testImageCircle.cpp | 174 +++++++++++++++++- 2 files changed, 181 insertions(+), 9 deletions(-) diff --git a/modules/core/src/image/vpImageCircle.cpp b/modules/core/src/image/vpImageCircle.cpp index f1a6b9c069..8d5f376679 100644 --- a/modules/core/src/image/vpImageCircle.cpp +++ b/modules/core/src/image/vpImageCircle.cpp @@ -309,7 +309,7 @@ void computeTopLeftIntersections(const float &u_c, const float &v_c, const vpIma std::cout << "v_vmin = " << v_vmin << " (" << theta_v_min << ")\tv_vmax = " << v_vmax << " (" << theta_v_max << ")" << std::endl; if (u_umin < umin_roi && u_umax >= umin_roi && v_vmin < vmin_roi && v_vmax >= vmin_roi) { // The circle crosses only once each axis - std::cout << "\t|->Case crossing once, center below top border" << std::endl; + std::cout << "\t|->Case crossing once" << std::endl; delta_theta = theta_u_max - theta_v_max; } else if (u_umin >= umin_roi && u_umax >= umin_roi && v_vmin >= vmin_roi && v_vmax >= vmin_roi) { @@ -357,8 +357,9 @@ void computeTopRightIntersections(const float &u_c, const float &v_c, const floa float u_umax = crossing_theta_u_max.second; float v_vmin = crossing_theta_v_min.second; float v_vmax = crossing_theta_v_max.second; - if (u_umin <= umax_roi && v_vmin < vmin_roi && u_umax > umax_roi && v_vmax >= vmin_roi) { + if (u_umin <= umax_roi && v_vmin < vmin_roi && u_umax >= umax_roi && v_vmax >= vmin_roi) { // The circle crosses only once each axis and the center is below the top border + std::cout << "\t|->Case crossing once" << std::endl; delta_theta = theta_v_max - theta_u_min; if (delta_theta < 0) { // The arc cannot be negative @@ -367,16 +368,19 @@ void computeTopRightIntersections(const float &u_c, const float &v_c, const floa } else if (u_umin <= umax_roi && v_vmin >= vmin_roi && u_umax <= umax_roi && v_vmax >= vmin_roi) { // The circle crosses twice each axis - delta_theta = (2 * M_PI + theta_v_max - theta_u_min) + (theta_v_min - theta_u_max); + std::cout << "\t|->Case crossing twice" << std::endl; + delta_theta = 2 * M_PI - ((theta_u_min - theta_u_max)+(theta_v_min - theta_v_max)); } - else if (true) { + else if (u_umin >= umax_roi && v_vmin >= vmin_roi && u_umax >= umax_roi && v_vmax >= vmin_roi) { // The circle crosses the u-axis outside the roi // so it is equivalent to the case of crossing only the right border + std::cout << "\t|->Case crossing right only" << std::endl; computeIntersectionsRightBorderOnly(u_c, umax_roi, radius, delta_theta); } - else if (true) { + else if (u_umin <= umax_roi && v_vmin <= vmin_roi && u_umax <= umax_roi && v_vmax <= vmin_roi) { // The circle crosses the v-axis outside the roi - // so it is equivalent to the case of crossing only the left border + // so it is equivalent to the case of crossing only the top border + std::cout << "\t|->Case crossing top only" << std::endl; computeIntersectionsTopBorderOnly(v_c, vmin_roi, radius, delta_theta); } } diff --git a/modules/core/test/tools/geometry/testImageCircle.cpp b/modules/core/test/tools/geometry/testImageCircle.cpp index 0e5c6689bb..7a2c383b92 100644 --- a/modules/core/test/tools/geometry/testImageCircle.cpp +++ b/modules/core/test/tools/geometry/testImageCircle.cpp @@ -396,10 +396,10 @@ int main() // Test with intersections with the top and the left border, crossing each axis once in the RoI { - // Formula: u1 = uc + r cos (theta1) ; vmin = vc + r sin(theta1) - // Formula: umin = uc + r cos(theta 2) ; v = vc + r sin(theta2) + // Formula: u1 = uc + r cos (theta1) ; vmin = vc - r sin(theta1) + // Formula: umin = uc + r cos(theta 2) ; v = vc - r sin(theta2) // Choice: theta1 - theta2 = pi / 2 => for theta1 = 0 theta2 = -pi/2 - // => uc = umin - r cos(theta2) vc = vmin - r sin(theta1) + // => uc = umin - r cos(theta2) vc = vmin + r sin(theta1) float uc = OFFSET; float vc = OFFSET; vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); @@ -537,6 +537,174 @@ int main() hasSucceeded &= isValueOK; } + // Test with intersections with the top and the right border, crossing each axis once in the RoI + { + // (1): u1 = uc + r cos(theta1) ; vmin = vc - r sin(theta1) + // (2): umin + width = uc + r cos(theta2) ; v = vc - r sin(theta2) <= vmin + // (3): u3 = uc + r cos(theta3) >= umin + width ; vmin = vc - r sin(theta3) + // (4): umin + width = uc + r cos(theta4) ; v = vc - r sin(theta4) >= vmin + // Choice: for theta1 = 2PI/3 theta4 = -pi/2 + // (4) => uc = umin + width - r cos(theta4) + // (1) => vc = vmin + r sin(theta1) + // (1) & (3) theta1 = PI - theta3 + // (2) & (4) theta2 = - theta4 + float theta1 = 2.f * M_PI / 3.f; + float theta4 = -M_PI_2; + float uc = OFFSET + WIDTH - RADIUS * std::cos(theta4); + float vc = OFFSET + RADIUS * std::sin(theta1);; + vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = (M_PI_2 + M_PI / 3.f) * RADIUS; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the top and the right border, crossing each axis once in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + + // Test with intersections with the top and the right border, + // but crossing only the right border in the RoI + { + // (1): u1 = uc + r cos(theta1) >= umin + width ; vmin = vc - r sin(theta1) + // (2): umin + width = uc + r cos(theta2) ; v = vc - r sin(theta2) >= vmin + // (3): u3 = uc + r cos(theta3) >= umin + width ; vmin = vc - r sin(theta3) + // (4): umin + width = uc + r cos(theta4) ; v = vc - r sin(theta4) >= vmin + // (4) => uc = umin + width - r cos(theta4) + // (1) => theta1 = asin((vc - vmin)/r) & uc + r cos(theta1) >= umin + width <=> uc + r cos[asin((vc - vmin)/r)] >= umin + width + // (1) <=> asin((vc - vmin)/r) >= acos[(umin + width - uc)/r] <=> vc >= r sin(acos[(umin + width - uc)/r]) + vmin + // (1) & (3) theta1 = PI - theta3 + // (2) & (4) theta2 = - theta4 + float theta4 = -7.f * M_PI / 8.f; // -5.f * M_PI / 6.f; + float theta2 = -theta4; + float uc = OFFSET + WIDTH - RADIUS * std::cos(theta4); + float vc = RADIUS * std::sin(std::acos((OFFSET + WIDTH - uc)/RADIUS)) + OFFSET + 1.f; + float theta1 = std::asin((vc - OFFSET) / RADIUS); + float theta3 = M_PI - theta1; + if (theta3 > theta1) { + float temp = theta3; + theta3 = theta1; + theta1 = temp; + } + vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = (2.f * M_PI - (theta2 - theta4)) * RADIUS; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the top and the right border, but crossing only the right border in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + + // Test with intersections with the top and the right border, + // but crossing only the top border in the RoI + { + // (1): u1 = uc + r cos(theta1) <= umin + width ; vmin = vc - r sin(theta1) + // (2): umin + width = uc + r cos(theta2) ; v = vc - r sin(theta2) <= vmin + // (3): u3 = uc + r cos(theta3) <= umin + width ; vmin = vc - r sin(theta3) + // (4): umin + width = uc + r cos(theta4) ; v = vc - r sin(theta4) <= vmin + // (1) & (3) theta1 = PI - theta3 + // (2) & (4) theta2 = - theta4 + // Choice: theta1 = -0.9 * PI / 2 + // (1) => vc = vmin + r sin(theta1) + // (2) vc - r sin(theta2) <= vmin => asin((vc - vmin)/r) <= theta2 + float theta1 = -0.9f * M_PI_2; + float theta3 = M_PI - theta1; + if (theta3 > M_PI) { + theta3 -= 2.0 * M_PI; + } + else if (theta3 > M_PI) { + theta3 += 2.0 * M_PI; + } + float vc = OFFSET + RADIUS * std::sin(theta1); + float theta2 = std::asin((vc - OFFSET)/RADIUS) + 1.f; + float uc = OFFSET + WIDTH - RADIUS * std::cos(theta2); + vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = std::abs(theta1 - theta3) * RADIUS; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the top and the right border, but crossing only the top border in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + + // Test with intersections with the top and the left border + // crossing twice each axis + { + // (1): u1 = uc + r cos(theta1) < umin + width ; vmin = vc - r sin(theta1) + // (2): umin + width = uc + r cos(theta2) ; v2 = vc - r sin(theta2) >= vmin + // (3): u3 = uc + r cos(theta3) <= umin + width; vmin = vc - r sin(theta3) + // (4): umin + width = uc + r cos(theta4) ; v4 = vc - r sin(theta4) > vmin + // (1) & (3) => vmin = vc - r sin(theta1) = vc - r sin(theta3) <=> theta1 = PI - theta3 + // (1) & (3) =>{ uc < umin + width - r cos(theta1) & { uc <= umin + width - r cos(PI - theta1) + // (1) & (3) { vc = vmin + r sin(theta1) & { vc = vmin + r sin(PI - theta1) + // (2) & (4) =>{ uc = umin - r cos(theta2) & { uc = umin - r cos( - theta2) + // (2) & (4) { vc >= vmin - r sin(theta2) & { vc >= vmin - r cos( - theta2) + + float theta1 = 5.f * M_PI / 8.f; + float theta3 = M_PI - theta1; + float uc = OFFSET + WIDTH - RADIUS * std::cos(theta1) - 1.f; + uc = std::min(uc, OFFSET + WIDTH - RADIUS * std::cos((float)M_PI - theta1) - 1.f); + float vc = OFFSET + RADIUS * std::sin(theta1); + float theta2 = std::acos((OFFSET + WIDTH - uc)/RADIUS); + if (theta2 > M_PI) { + theta2 -= 2.0 * M_PI; + } + else if (theta2 > M_PI) { + theta2 += 2.0 * M_PI; + } + float theta4 = -theta2; + if (theta2 < 0) { + float temp = theta2; + theta2 = theta2; + theta4 = temp; + } + vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = (2.f * M_PI - ((theta1 - theta3) + (theta2 - theta4))) * RADIUS; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the top and the left border crossing twice each axis ." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length (2 PI - (" << theta1 << " - " << theta3 << ") + (" << theta2 << " - " << theta4 << ")) R = " << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + if (hasSucceeded) { std::cout << "testImageCircle overall result: SUCCESS"; return EXIT_SUCCESS; From 0b75cc8cf803d7b412bcfbb23d93fbfc742e8141 Mon Sep 17 00:00:00 2001 From: rlagneau Date: Thu, 28 Sep 2023 15:53:19 +0200 Subject: [PATCH 06/22] [WIP] Added cases of crossings with bottom and left axes --- modules/core/src/image/vpImageCircle.cpp | 58 +++++- .../test/tools/geometry/testImageCircle.cpp | 178 ++++++++++++++++-- 2 files changed, 217 insertions(+), 19 deletions(-) diff --git a/modules/core/src/image/vpImageCircle.cpp b/modules/core/src/image/vpImageCircle.cpp index 8d5f376679..9190045b77 100644 --- a/modules/core/src/image/vpImageCircle.cpp +++ b/modules/core/src/image/vpImageCircle.cpp @@ -75,7 +75,7 @@ float getAngleBetweenMinPiAndPi(const float &theta) if (theta1 > M_PI) { theta1 -= 2.0 * M_PI; } - else if (theta1 > M_PI) { + else if (theta1 < -M_PI) { theta1 += 2.0 * M_PI; } return theta1; @@ -385,6 +385,61 @@ void computeTopRightIntersections(const float &u_c, const float &v_c, const floa } } +/*! + * \brief Compute the length of the angular interval of the circle when it intersects + * only with the left and bottom borders of the Region of Interest (RoI). + * + * \param[in] u_c The horizontal u-axis coordinate of the center. + * \param[in] v_c The vertical v-axis coordinate of the center. + * \param[in] topLeft The top left corner of the RoI. + * \param[in] height The height of the RoI. + * \param[in] radius The radius of the circle. + * \param[out] delta_theta The length of the angular interval that is in the RoI. + */ +void computeBottomLeftIntersections(const float &u_c, const float &v_c, const vpImagePoint &topLeft, const float &height, const float &radius, + float &delta_theta) +{ + std::pair crossing_theta_u_min, crossing_theta_u_max; + std::pair crossing_theta_v_min, crossing_theta_v_max; + float crossing_u = topLeft.get_v() + height; // We cross the u-axis of the RoI at which v-coordinate + float vmax_roi = crossing_u; // The maximum v-coordinate of the RoI + float crossing_v = topLeft.get_u(); // We cross the v-axis of the RoI at which u-coordinate + float umin_roi = crossing_v; // The minimum u-coordinate of the RoI + computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u, crossing_v, + crossing_theta_u_min, crossing_theta_u_max, + crossing_theta_v_min, crossing_theta_v_max); + float theta_u_min = crossing_theta_u_min.first, theta_v_min = crossing_theta_v_min.first; + float theta_u_max = crossing_theta_u_max.first, theta_v_max = crossing_theta_v_max.first; + float u_umin = crossing_theta_u_min.second; + float u_umax = crossing_theta_u_max.second; + float v_vmin = crossing_theta_v_min.second; + float v_vmax = crossing_theta_v_max.second; + std::cout << "umin_roi = " << umin_roi << "\tvmax_roi = " << vmax_roi << std::endl; + std::cout << "u_umin = " << u_umin << " (" << theta_u_min << ")\tu_umax = " << u_umax << " (" << theta_u_max << ")" << std::endl; + std::cout << "v_vmin = " << v_vmin << " (" << theta_v_min << ")\tv_vmax = " << v_vmax << " (" << theta_v_max << ")" << std::endl; + if (u_umin < umin_roi && u_umax >= umin_roi && v_vmin <= vmax_roi && v_vmax > vmax_roi) { + // The circle crosses only once each axis + std::cout << "\t|->Case crossing once" << std::endl; + delta_theta = theta_v_min - theta_u_max; + } + else if (u_umin >= umin_roi && u_umax >= umin_roi && v_vmin <= vmax_roi && v_vmax <= vmax_roi) { + // The circle crosses twice each axis + std::cout << "\t|->Case crossing twice" << std::endl; + delta_theta = (theta_v_min - theta_u_max) + (theta_u_min - theta_v_max); + } + else if (u_umin < umin_roi && u_umax < umin_roi && v_vmin <= vmax_roi && v_vmax <= vmax_roi) { + // The circle crosses the u-axis outside the roi + // so it is equivalent to the case of crossing only the left border + std::cout << "\t|->Case left only" << std::endl; + computeIntersectionsLeftBorderOnly(u_c, umin_roi, radius, delta_theta); + } + else if (u_umin >= umin_roi && u_umax >= umin_roi && v_vmin >= vmax_roi && v_vmax >= vmax_roi) { + // The circle crosses the v-axis outside the roi + // so it is equivalent to the case of crossing only the top border + std::cout << "\t|->Case bottom only" << std::endl; + computeIntersectionsBottomBorderOnly(v_c, vmax_roi, radius, delta_theta); + } +} float vpImageCircle::computeArcLengthInRoI(const vpRect &roi) const { @@ -435,6 +490,7 @@ float vpImageCircle::computeArcLengthInRoI(const vpRect &roi) const else if (touchBottomBorder && touchLeftBorder && !touchRightBorder && !touchTopBorder) { // Touches/intersects the bottom and left borders of the RoI std::cout << "Case bottom / left" << std::endl; + computeBottomLeftIntersections(center_u, center_v, topLeft, roi_h, radius, deltaTheta); } else if (touchBottomBorder && !touchLeftBorder && touchRightBorder && !touchTopBorder) { // Touches/intersects the bottom and right borders of the RoI diff --git a/modules/core/test/tools/geometry/testImageCircle.cpp b/modules/core/test/tools/geometry/testImageCircle.cpp index 7a2c383b92..289df5b804 100644 --- a/modules/core/test/tools/geometry/testImageCircle.cpp +++ b/modules/core/test/tools/geometry/testImageCircle.cpp @@ -44,6 +44,18 @@ bool compareAngles(const float &actualVal, const float &theoreticalVal) return (std::abs(theoreticalVal - actualVal) < 1.f); } +float ensureIsBetweenMinPiAndPi(const float &theta) +{ + float theta1 = theta; + if (theta1 > M_PI) { + theta1 -= 2.0 * M_PI; + } + else if (theta1 < -M_PI) { + theta1 += 2.0 * M_PI; + } + return theta1; +} + int main() { const float OFFSET = 5.f; @@ -506,12 +518,7 @@ int main() uc = std::max(uc, OFFSET - RADIUS * std::cos((float)M_PI - theta1) + 1.f); float vc = OFFSET + RADIUS * std::sin(theta1); float theta3 = std::acos((OFFSET - uc)/RADIUS); - if (theta3 > M_PI) { - theta3 -= 2.0 * M_PI; - } - else if (theta3 > M_PI) { - theta3 += 2.0 * M_PI; - } + theta3 = ensureIsBetweenMinPiAndPi(theta3); float theta4 = -theta3; if (theta4 < 0) { float temp = theta4; @@ -627,12 +634,7 @@ int main() // (2) vc - r sin(theta2) <= vmin => asin((vc - vmin)/r) <= theta2 float theta1 = -0.9f * M_PI_2; float theta3 = M_PI - theta1; - if (theta3 > M_PI) { - theta3 -= 2.0 * M_PI; - } - else if (theta3 > M_PI) { - theta3 += 2.0 * M_PI; - } + theta3 = ensureIsBetweenMinPiAndPi(theta3); float vc = OFFSET + RADIUS * std::sin(theta1); float theta2 = std::asin((vc - OFFSET)/RADIUS) + 1.f; float uc = OFFSET + WIDTH - RADIUS * std::cos(theta2); @@ -674,12 +676,7 @@ int main() uc = std::min(uc, OFFSET + WIDTH - RADIUS * std::cos((float)M_PI - theta1) - 1.f); float vc = OFFSET + RADIUS * std::sin(theta1); float theta2 = std::acos((OFFSET + WIDTH - uc)/RADIUS); - if (theta2 > M_PI) { - theta2 -= 2.0 * M_PI; - } - else if (theta2 > M_PI) { - theta2 += 2.0 * M_PI; - } + theta2 = ensureIsBetweenMinPiAndPi(theta2); float theta4 = -theta2; if (theta2 < 0) { float temp = theta2; @@ -705,6 +702,151 @@ int main() hasSucceeded &= isValueOK; } + // Test with intersections with the bottom and the left border, crossing each axis once in the RoI + { + // (1): u1 = uc + r cos(theta1) <= umin ; vmin + height = vc - r sin(theta1) + // (2): umin = uc + r cos(theta2) ; v = vc - r sin(theta2) <= vmin + height + // (3): u3 = uc + r cos(theta3) >= umin ; vmin + height = vc - r sin(theta3) + // (4): umin = uc + r cos(theta4) ; v = vc - r sin(theta4) >= vmin + height + // Choice: for theta2 = PI/2 theta3 = -PI/3 + // (2) => uc = umin - r cos(theta2) + // (3) => vc = vmin + height + r sin(theta3) + // (1) & (3) theta1 = PI - theta3 + // (2) & (4) theta2 = - theta4 + float theta2 = M_PI_2; + float theta3 = -M_PI / 3.f; + float uc = OFFSET - RADIUS * std::cos(theta2); + float vc = OFFSET + HEIGHT + RADIUS * std::sin(theta3);; + vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = (M_PI_2 + M_PI / 3.f) * RADIUS; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the bottom and the left border, crossing each axis once in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + + // Test with intersections with the bottom and the left border + // but crossing only the left border in the RoI + { + // (1): u1 = uc + r cos(theta1) <= umin ; vmin + height = vc - r sin(theta1) + // (2): umin = uc + r cos(theta2) ; v = vc - r sin(theta2) <= vmin + height + // (3): u3 = uc + r cos(theta3) <= umin ; vmin + height = vc - r sin(theta3) + // (4): umin = uc + r cos(theta4) ; v = vc - r sin(theta4) <= vmin + height + // Choice: for theta2 = PI/8 + // (2) => uc = umin - r cos(theta2) + // (2) => vc <= vmin + height + r sin(theta2) + // (4) => vc <= vmin + height + r sin(theta4) + // (1) & (3) theta1 = PI - theta3 + // (2) & (4) theta2 = - theta4 + float theta2 = M_PI_4 / 2.f; + float theta4 = -theta2; + float uc = OFFSET - RADIUS * std::cos(theta2); + float vc = std::min(OFFSET + HEIGHT + RADIUS * std::sin(theta2) - 1.f, OFFSET + HEIGHT + RADIUS * std::sin(theta4) - 1.f); + vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = (2.f * theta2) * RADIUS; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the bottom and the left border, but crossing only the left border in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + + // Test with intersections with the bottom and the left border + // but crossing only the bottom border in the RoI + { + // (1): u1 = uc + r cos(theta1) >= umin ; vmin + height = vc - r sin(theta1) + // (2): umin = uc + r cos(theta2) ; v = vc - r sin(theta2) >= vmin + height + // (3): u3 = uc + r cos(theta3) >= umin ; vmin + height = vc - r sin(theta3) + // (4): umin = uc + r cos(theta4) ; v = vc - r sin(theta4) >= vmin + height + // Choice: for theta1 = 5 PI/8 + // (1) => vc = vmin + height + r sin(theta1) + // (1) => uc >= umin - r cos(theta1) + // (1) => uc >= umin - r cos(theta3) + // (1) & (3) theta1 = PI - theta3 + // (2) & (4) theta2 = - theta4 + float theta1 = 5.f * M_PI_4 / 2.f; + float theta3 = M_PI - theta1; + float vc = OFFSET + HEIGHT + RADIUS * std::sin(theta1); + float uc = std::max(OFFSET - RADIUS * std::cos(theta1) + 1.f, OFFSET - RADIUS * std::cos(theta3) + 1.f); + vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = (theta1 - theta3) * RADIUS; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the bottom and the left border, but crossing only the bottom border in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + + // Test with intersections with the bottom and the left border + // crossing each axis twice in the RoI + { + // (1): u1 = uc + r cos(theta1) >= umin ; vmin + height = vc - r sin(theta1) + // (2): umin = uc + r cos(theta2) ; v = vc - r sin(theta2) < vmin + height + // (3): u3 = uc + r cos(theta3) > umin ; vmin + height = vc - r sin(theta3) + // (4): umin = uc + r cos(theta4) ; v = vc - r sin(theta4) <= vmin + height + // (1) & (3) => uc >= umin - r cos(theta1) & uc > umin - r cos(theta3) + // (1) & (3) => vc = vmin + height + r sin(theta1) & vc = vmin + height + r sin(PI - theta1) + // (2) & (4) => uc = umin - r cos(theta2) & uc = umin - r cos(-theta2) + // (2) & (4) => vc < vmin + height + r sin(theta2) & vc < vmin + height + r sin(-theta2) + // (1) & (3) theta1 = PI - theta3 + // (2) & (4) theta2 = - theta4 + float theta1 = -5.f * M_PI / 8.f; + float theta3 = M_PI - theta1; + theta3 = ensureIsBetweenMinPiAndPi(theta3); + float theta2 = 7.f * M_PI / 8.f; + float theta4 = -theta2; + float vc = OFFSET + HEIGHT + RADIUS * std::sin(theta1); + float uc = OFFSET - RADIUS * std::cos(theta2); + vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = ((theta2 - theta3) + (theta1 - theta4)) * RADIUS; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the bottom and the left border, crossing each axis twice in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + if (hasSucceeded) { std::cout << "testImageCircle overall result: SUCCESS"; return EXIT_SUCCESS; From 8fa5445a216982c6efff67720ead1ea1ad91582e Mon Sep 17 00:00:00 2001 From: rlagneau Date: Thu, 28 Sep 2023 16:37:43 +0200 Subject: [PATCH 07/22] [WIP] Handle crossing bottom and right axes --- modules/core/src/image/vpImageCircle.cpp | 61 +++++++- .../test/tools/geometry/testImageCircle.cpp | 141 ++++++++++++++++++ 2 files changed, 201 insertions(+), 1 deletion(-) diff --git a/modules/core/src/image/vpImageCircle.cpp b/modules/core/src/image/vpImageCircle.cpp index 9190045b77..56dac6d11b 100644 --- a/modules/core/src/image/vpImageCircle.cpp +++ b/modules/core/src/image/vpImageCircle.cpp @@ -435,7 +435,65 @@ void computeBottomLeftIntersections(const float &u_c, const float &v_c, const vp } else if (u_umin >= umin_roi && u_umax >= umin_roi && v_vmin >= vmax_roi && v_vmax >= vmax_roi) { // The circle crosses the v-axis outside the roi - // so it is equivalent to the case of crossing only the top border + // so it is equivalent to the case of crossing only the bottom border + std::cout << "\t|->Case bottom only" << std::endl; + computeIntersectionsBottomBorderOnly(v_c, vmax_roi, radius, delta_theta); + } +} + +/*! + * \brief Compute the length of the angular interval of the circle when it intersects + * only with the right and bottom borders of the Region of Interest (RoI). + * + * \param[in] u_c The horizontal u-axis coordinate of the center. + * \param[in] v_c The vertical v-axis coordinate of the center. + * \param[in] vmax_roi The bottom v-coordinate of the RoI. + * \param[in] umax_roi The right u-coordinate of the RoI. + * \param[in] radius The radius of the circle. + * \param[out] delta_theta The length of the angular interval that is in the RoI. + */ +void computeBottomRightIntersections(const float &u_c, const float &v_c, const float &vmax_roi, const float &umax_roi, const float &radius, + float &delta_theta) +{ + std::pair crossing_theta_u_min, crossing_theta_u_max; + std::pair crossing_theta_v_min, crossing_theta_v_max; + float crossing_u = vmax_roi; // We cross the u-axis of the RoI at the maximum v-coordinate of the RoI + float crossing_v = umax_roi; // We cross the v-axis of the RoI at the maximum u-coordinate of the RoI + computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u, crossing_v, + crossing_theta_u_min, crossing_theta_u_max, + crossing_theta_v_min, crossing_theta_v_max); + float theta_u_min = crossing_theta_u_min.first, theta_v_min = crossing_theta_v_min.first; + float theta_u_max = crossing_theta_u_max.first, theta_v_max = crossing_theta_v_max.first; + float u_umin = crossing_theta_u_min.second; + float u_umax = crossing_theta_u_max.second; + float v_vmin = crossing_theta_v_min.second; + float v_vmax = crossing_theta_v_max.second; + std::cout << "umax_roi = " << umax_roi << "\tvmax_roi = " << vmax_roi << std::endl; + std::cout << "u_umin = " << u_umin << " (" << theta_u_min << ")\tu_umax = " << u_umax << " (" << theta_u_max << ")" << std::endl; + std::cout << "v_vmin = " << v_vmin << " (" << theta_v_min << ")\tv_vmax = " << v_vmax << " (" << theta_v_max << ")" << std::endl; + if (u_umin <= umax_roi && u_umax > umax_roi && v_vmin <= vmax_roi && v_vmax > vmax_roi) { + // The circle crosses only once each axis + std::cout << "\t|->Case crossing once" << std::endl; + delta_theta = theta_u_min - theta_v_min; + if (delta_theta < 0) { + // An arc length cannot be negative it means that theta_u_max was comprise in the bottom left quadrant of the circle + delta_theta += 2.f * M_PI; + } + } + else if (u_umin <= umax_roi && u_umax <= umax_roi && v_vmin <= vmax_roi && v_vmax <= vmax_roi) { + // The circle crosses twice each axis + std::cout << "\t|->Case crossing twice" << std::endl; + delta_theta = 2.f * M_PI - ((theta_v_min - theta_v_max) + (theta_u_max - theta_u_min)); + } + else if (u_umin > umax_roi && u_umax > umax_roi && v_vmin <= vmax_roi && v_vmax <= vmax_roi) { + // The circle crosses the u-axis outside the roi + // so it is equivalent to the case of crossing only the right border + std::cout << "\t|->Case left only" << std::endl; + computeIntersectionsRightBorderOnly(u_c, umax_roi, radius, delta_theta); + } + else if (u_umin <= umax_roi && u_umax <= umax_roi && v_vmin > vmax_roi && v_vmax > vmax_roi) { + // The circle crosses the v-axis outside the roi + // so it is equivalent to the case of crossing only the bottom border std::cout << "\t|->Case bottom only" << std::endl; computeIntersectionsBottomBorderOnly(v_c, vmax_roi, radius, delta_theta); } @@ -495,6 +553,7 @@ float vpImageCircle::computeArcLengthInRoI(const vpRect &roi) const else if (touchBottomBorder && !touchLeftBorder && touchRightBorder && !touchTopBorder) { // Touches/intersects the bottom and right borders of the RoI std::cout << "Case bottom / right" << std::endl; + computeBottomRightIntersections(center_u, center_v, vmax_roi, umax_roi, radius, deltaTheta); } else if (!touchBottomBorder && touchLeftBorder && !touchRightBorder && touchTopBorder) { // Touches/intersects the top and left borders of the RoI diff --git a/modules/core/test/tools/geometry/testImageCircle.cpp b/modules/core/test/tools/geometry/testImageCircle.cpp index 289df5b804..f614e99ce5 100644 --- a/modules/core/test/tools/geometry/testImageCircle.cpp +++ b/modules/core/test/tools/geometry/testImageCircle.cpp @@ -847,6 +847,147 @@ int main() hasSucceeded &= isValueOK; } + // Test with intersections with the bottom and the right border, crossing each axis once in the RoI + { + // (1): u1 = uc + r cos(theta1) <= umin + width ; vmin + height = vc - r sin(theta1) + // (2): umin + width = uc + r cos(theta2) ; v = vc - r sin(theta2) <= vmin + height + // (3): u3 = uc + r cos(theta3) >= umin + width ; vmin + height = vc - r sin(theta3) + // (4): umin + width = uc + r cos(theta4) ; v = vc - r sin(theta4) >= vmin + height + // Choice: for theta1 = -2PI/3 theta2 = PI/2 + // (2) => uc = umin + width - r cos(theta2) + // (1) => vc = vmin + height + r sin(theta1) + // (1) & (3) theta1 = PI - theta3 + // (2) & (4) theta2 = - theta4 + float theta1 = -2.f * M_PI / 3.f; + float theta2 = M_PI_2; + float uc = OFFSET + WIDTH - RADIUS * std::cos(theta2); + float vc = OFFSET + HEIGHT + RADIUS * std::sin(theta1);; + vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = (M_PI_2 + M_PI / 3.f) * RADIUS; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the bottom and the right border, crossing each axis once in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + + // Test with intersections with the bottom and the right border, + // crossing only the right axis in the RoI + { + // (1): u1 = uc + r cos(theta1) >= umin + width ; vmin + height = vc - r sin(theta1) + // (2): umin + width = uc + r cos(theta2) ; v = vc - r sin(theta2) <= vmin + height + // (3): u3 = uc + r cos(theta3) >= umin + width ; vmin + height = vc - r sin(theta3) + // (4): umin + width = uc + r cos(theta4) ; v = vc - r sin(theta4) <= vmin + height + // Choice: for theta2 = 5*PI/6 + // (2) => uc = umin + width - r cos(theta2) + // (2) & (4) => vc <= vmin + height + r sin(theta2) & vc <= vmin + height + r sin(-theta2) + // (1) & (3) theta1 = PI - theta3 + // (2) & (4) theta2 = - theta4 + float theta2 = 5.f * M_PI / 6.f; + float uc = OFFSET + WIDTH - RADIUS * std::cos(theta2); + float vc = std::min(OFFSET + HEIGHT + RADIUS * std::sin(theta2) - 1.f, OFFSET + HEIGHT + RADIUS * std::sin(-theta2) - 1.f); + vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = (M_PI / 3.f) * RADIUS; // <=> 2.f * M_PI / 6.f + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the bottom and the right border, crossing only the right axis in the RoI in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + + // Test with intersections with the bottom and the right border, + // crossing only the bottom axis in the RoI + { + // (1): u1 = uc + r cos(theta1) < umin + width ; vmin + height = vc - r sin(theta1) + // (2): umin + width = uc + r cos(theta2) ; v = vc - r sin(theta2) >= vmin + height + // (3): u3 = uc + r cos(theta3) <= umin + width ; vmin + height = vc - r sin(theta3) + // (4): umin + width = uc + r cos(theta4) ; v = vc - r sin(theta4) >= vmin + height + // Choice: for theta1 = 4*PI/6 + // (1) => vc = vmin + height + r cos(theta1) + // (1) & (3) => uc < umin + width - r cos(theta1) & uc <= umin + width - r cos(PI - theta1) + // (1) & (3) theta1 = PI - theta3 + // (2) & (4) theta2 = - theta4 + float theta1 = 4.f * M_PI / 6.f; + float vc = OFFSET + HEIGHT + RADIUS * std::sin(theta1); + float uc = std::min(OFFSET + WIDTH - RADIUS * std::cos(theta1) - 1.f, OFFSET + WIDTH - RADIUS * std::cos((float)M_PI -theta1) - 1.f); + vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = (M_PI / 3.f) * RADIUS; // <=> 2.f * M_PI / 6.f + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the bottom and the right border, crossing only the bottom axis in the RoI in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + + // Test with intersections with the bottom and the right border + // crossing each axis twice in the RoI + { + // (1): u1 = uc + r cos(theta1) < umin + width ; vmin + height = vc - r sin(theta1) + // (2): umin + width = uc + r cos(theta2) ; v = vc - r sin(theta2) < vmin + height + // (3): u3 = uc + r cos(theta3) <= umin + width ; vmin + height = vc - r sin(theta3) + // (4): umin + width = uc + r cos(theta4) ; v = vc - r sin(theta4) <= vmin + height + // (1) & (3) => uc < umin + width - r cos(theta1) & uc <= umin + width - r cos(PI - theta1) + // (1) & (3) => vc = vmin + height + r sin(theta1) & vc = vmin + height + r sin(PI - theta1) + // (2) & (4) => uc = umin + width - r cos(theta2) & uc = umin + width - r cos(-theta2) + // (2) & (4) => vc < vmin + height + r sin(theta2) & vc < vmin + height + r sin(-theta2) + // (1) & (3) theta1 = PI - theta3 + // (2) & (4) theta2 = - theta4 + float theta1 = -7.f * M_PI / 8.f; + float theta3 = M_PI - theta1; + theta3 = ensureIsBetweenMinPiAndPi(theta3); + float theta4 = -3.f * M_PI / 8.f; + float theta2 = -theta4; + float vc = OFFSET + HEIGHT + RADIUS * std::sin(theta1); + float uc = OFFSET - RADIUS * std::cos(theta2); + vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = (2.f * M_PI - ((theta2 - theta4) + (theta3 - theta1))) * RADIUS; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the bottom and the right border, crossing each axis twice in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + if (hasSucceeded) { std::cout << "testImageCircle overall result: SUCCESS"; return EXIT_SUCCESS; From 0ba057916aae529235cdc8532be831c1ba67efa4 Mon Sep 17 00:00:00 2001 From: rlagneau Date: Fri, 29 Sep 2023 08:18:49 +0200 Subject: [PATCH 08/22] [CORPS] vpCHT radius candidate validation policy is now based on a probability scheme, which is the ratio of the number of visible pixels divided by the theoretical number of visible pixels --- .../visp3/imgproc/vpCircleHoughTransform.h | 77 ++++++++++------ .../imgproc/src/vpCircleHoughTransform.cpp | 90 +++++++++++++------ .../hough-transform/config/detector_full.json | 2 +- .../hough-transform/config/detector_half.json | 2 +- .../hough-transform/config/detector_img.json | 2 +- .../config/detector_quarter.json | 2 +- .../hough-transform/tutorial-circle-hough.cpp | 48 ++++------ 7 files changed, 135 insertions(+), 88 deletions(-) diff --git a/modules/imgproc/include/visp3/imgproc/vpCircleHoughTransform.h b/modules/imgproc/include/visp3/imgproc/vpCircleHoughTransform.h index f02bddb803..9c503700c4 100644 --- a/modules/imgproc/include/visp3/imgproc/vpCircleHoughTransform.h +++ b/modules/imgproc/include/visp3/imgproc/vpCircleHoughTransform.h @@ -95,7 +95,7 @@ class VISP_EXPORT vpCircleHoughTransform float m_centerThresh; /*!< Minimum number of votes a point must exceed to be considered as center candidate.*/ // // Circle candidates computation attributes - float m_radiusRatioThresh; /*!< Minimum number of votes per radian a radius candidate RC_ij of a center candidate CeC_i must have in order that the circle of center CeC_i and radius RC_ij must be considered as circle candidate.*/ + float m_circleProbaThresh; /*!< Probability threshold in order to keep a circle candidate.*/ float m_circlePerfectness; /*!< The scalar product radius RC_ij . gradient(Ep_j) >= m_circlePerfectness * || RC_ij || * || gradient(Ep_j) || to add a vote for the radius RC_ij. */ // // Circle candidates merging attributes @@ -120,7 +120,7 @@ class VISP_EXPORT vpCircleHoughTransform , m_maxRadius(1000) , m_dilatationNbIter(1) , m_centerThresh(50.f) - , m_radiusRatioThresh(2.f) + , m_circleProbaThresh(0.9f) , m_circlePerfectness(0.9f) , m_centerMinDist(15.f) , m_mergingRadiusDiffThresh(1.5f * m_centerMinDist) @@ -145,7 +145,7 @@ class VISP_EXPORT vpCircleHoughTransform * \param[in] maxRadius Maximum radius of the circles we want to detect. * \param[in] dilatationNbIter Number of times dilatation is performed to detect the maximum number of votes for the center candidates * \param[in] centerThresh Minimum number of votes a point must exceed to be considered as center candidate. - * \param[in] radiusThreshRatio Minimum number of votes per radian a radius candidate RC_ij of a center candidate CeC_i must have in order that the circle of center CeC_i and radius RC_ij must be considered as circle candidate. + * \param[in] circleProbabilityThresh Probability threshold in order to keep a circle candidate. * \param[in] circlePerfectness The scalar product radius RC_ij . gradient(Ep_j) >= m_circlePerfectness * || RC_ij || * || gradient(Ep_j) || to add a vote for the radius RC_ij. * \param[in] centerMinDistThresh Two circle candidates whose centers are closer than this threshold are considered for merging. * \param[in] mergingRadiusDiffThresh Maximum radius difference between two circle candidates to consider merging them. @@ -163,7 +163,7 @@ class VISP_EXPORT vpCircleHoughTransform , const unsigned int &maxRadius , const int &dilatationNbIter , const float ¢erThresh - , const float &radiusThreshRatio + , const float &circleProbabilityThresh , const float &circlePerfectness , const float ¢erMinDistThresh , const float &mergingRadiusDiffThresh @@ -180,13 +180,11 @@ class VISP_EXPORT vpCircleHoughTransform , m_maxRadius(std::max(minRadius, maxRadius)) , m_dilatationNbIter(dilatationNbIter) , m_centerThresh(centerThresh) - , m_radiusRatioThresh(radiusThreshRatio) + , m_circleProbaThresh(circleProbabilityThresh) , m_circlePerfectness(circlePerfectness) , m_centerMinDist(centerMinDistThresh) , m_mergingRadiusDiffThresh(mergingRadiusDiffThresh) - { - - } + { } /** * Create a string with all the Hough transform parameters. @@ -204,7 +202,7 @@ class VISP_EXPORT vpCircleHoughTransform txt += "\tRadius limits: min = " + std::to_string(m_minRadius) + "\tmax = " + std::to_string(m_maxRadius) +"\n"; txt += "\tNumber of repetitions of the dilatation filter = " + std::to_string(m_dilatationNbIter) + "\n"; txt += "\tCenters votes threshold = " + std::to_string(m_centerThresh) + "\n"; - txt += "\tRadius votes per radian threshold = " + std::to_string(m_radiusRatioThresh) + "\n"; + txt += "\tCircle probability threshold = " + std::to_string(m_circleProbaThresh) + "\n"; txt += "\tCircle perfectness threshold = " + std::to_string(m_circlePerfectness) + "\n"; txt += "\tCenters minimum distance = " + std::to_string(m_centerMinDist) + "\n"; txt += "\tRadius difference merging threshold = " + std::to_string(m_mergingRadiusDiffThresh) + "\n"; @@ -300,7 +298,7 @@ class VISP_EXPORT vpCircleHoughTransform throw vpException(vpException::badValue, "Votes thresholds for center detection must be positive."); } - params.m_radiusRatioThresh = j.value("radiusThreshRatio", params.m_radiusRatioThresh); + params.m_circleProbaThresh = j.value("circleProbabilityThreshold", params.m_circleProbaThresh); params.m_circlePerfectness = j.value("circlePerfectnessThreshold", params.m_circlePerfectness); @@ -341,17 +339,17 @@ class VISP_EXPORT vpCircleHoughTransform {"radiusLimits", radiusLimits}, {"dilatationNbIter", params.m_dilatationNbIter}, {"centerThresh", params.m_centerThresh}, - {"radiusThreshRatio", params.m_radiusRatioThresh}, + {"circleProbabilityThreshold", params.m_circleProbaThresh}, {"circlePerfectnessThreshold", params.m_circlePerfectness}, {"centerMinDistance", params.m_centerMinDist}, {"mergingRadiusDiffThresh", params.m_mergingRadiusDiffThresh} }; - } + } #endif -}; + }; -/** - * \brief Construct a new vpCircleHoughTransform object with default parameters. - */ + /** + * \brief Construct a new vpCircleHoughTransform object with default parameters. + */ vpCircleHoughTransform(); /** @@ -596,9 +594,9 @@ class VISP_EXPORT vpCircleHoughTransform */ inline void setRadiusRatioThreshold(const float &radiusRatioThresh) { - m_algoParams.m_radiusRatioThresh = radiusRatioThresh; + m_algoParams.m_circleProbaThresh = radiusRatioThresh; - if (m_algoParams.m_radiusRatioThresh <= 0) { + if (m_algoParams.m_circleProbaThresh <= 0) { throw vpException(vpException::badValue, "Radius ratio threshold must be > 0."); } } @@ -652,13 +650,13 @@ class VISP_EXPORT vpCircleHoughTransform } /** - * \brief Get the votes accumulator of the Circle Candidates. + * \brief Get the probabilities of the Circle Candidates. * - * \return std::vector The votes accumulator. + * \return std::vector The votes accumulator. */ - inline std::vector getCircleCandidatesVotes() + inline std::vector getCircleCandidatesProbabilities() { - return m_circleCandidatesVotes; + return m_circleCandidatesProbabilities; } /** @@ -724,6 +722,22 @@ class VISP_EXPORT vpCircleHoughTransform return m_algoParams.m_maxRadius; } + /*! + * Get the probabilities of the detections that are outputed by vpCircleHoughTransform::detect() + */ + inline std::vector getDetectionsProbabilities() const + { + return m_finalCirclesProbabilities; + } + + /*! + * Get the number of votes for the detections that are outputed by vpCircleHoughTransform::detect() + */ + inline std::vector getDetectionsVotes() const + { + return m_finalCircleVotes; + } + /*! * Create a string with all Hough transform parameters. */ @@ -770,6 +784,18 @@ class VISP_EXPORT vpCircleHoughTransform */ void computeCenterCandidates(); + /** + * \brief Compute the probability of \b circle given the number of pixels voting for + * it \b nbVotes. + * The probability is defined as the ratio of \b nbVotes by the theoretical number of + * pixel that should be visible in the image. + * + * @param circle The circle for which we want to evaluate the probability. + * @param nbVotes The number of visible pixels of the given circle. + * @return float The probability of the circle. + */ + float computeCircleProbability(const vpImageCircle &circle, const unsigned int &nbVotes); + /** * \brief For each center candidate CeC_i, do: * - For each edge point EP_j, compute the distance d_ij = distance(CeC_i; EP_j) @@ -794,7 +820,6 @@ class VISP_EXPORT vpCircleHoughTransform // // Gaussian smoothing attributes vpArray2D m_fg; vpArray2D m_fgDg; - vpImage m_Ifilt; /*!< Filtered version of the input image, after having used a Gaussian filter.*/ // // Gradient computation attributes vpImage m_dIx; /*!< Gradient along the x-axis of the input image.*/ @@ -811,11 +836,13 @@ class VISP_EXPORT vpCircleHoughTransform // // Circle candidates computation attributes std::vector m_circleCandidates; /*!< List of the candidate circles.*/ - std::vector m_circleCandidatesVotes; /*!< Number of votes for the candidate circles.*/ + std::vector m_circleCandidatesProbabilities; /*!< Probabilities of each candidate circle that is kept.*/ + std::vector m_circleCandidatesVotes; /*!< Number of pixels voting for each candidate circle that is kept.*/ // // Circle candidates merging attributes std::vector m_finalCircles; /*!< List of the final circles, i.e. the ones resulting from the merge of the circle candidates.*/ - std::vector m_finalCircleVotes; /*!< Number of votes for the candidate circles.*/ + std::vector m_finalCirclesProbabilities; /*!< Probabilities of each final circle, i.e. resulting from the merge of the circle candidates.*/ + std::vector m_finalCircleVotes; /*!< Number of votes for the final circles.*/ }; #endif #endif diff --git a/modules/imgproc/src/vpCircleHoughTransform.cpp b/modules/imgproc/src/vpCircleHoughTransform.cpp index 223e36f8d5..f97bee2b8c 100644 --- a/modules/imgproc/src/vpCircleHoughTransform.cpp +++ b/modules/imgproc/src/vpCircleHoughTransform.cpp @@ -129,21 +129,23 @@ vpCircleHoughTransform::detect(const vpImage &I, const int &nbCir { std::vector detections = detect(I); size_t nbDetections = detections.size(); - std::vector bestCircles; - std::vector > detectionsWithVotes; + + // Prepare vector of tuple to sort by decreasing probabilities + std::vector > detectionsWithVotes; for (size_t i = 0; i < nbDetections; i++) { - std::pair detectionWithVote(detections[i], m_finalCircleVotes[i]); + std::tuple detectionWithVote(detections[i], m_finalCircleVotes[i], m_finalCirclesProbabilities[i]); detectionsWithVotes.push_back(detectionWithVote); } - bool (*hasMoreVotes)(std::pair, std::pair) - = [](std::pair a, std::pair b) { - // We divide the number of votes by the radius to avoid to favour big circles - return (a.second / a.first.getRadius() > b.second / b.first.getRadius()); + // Sorting by decreasing probabilities + bool (*hasBetterProba)(std::tuple, std::tuple) + = [](std::tuple a, std::tuple b) { + return (std::get<2>(a) > std::get<2>(b)); }; + std::sort(detectionsWithVotes.begin(), detectionsWithVotes.end(), hasBetterProba); - std::sort(detectionsWithVotes.begin(), detectionsWithVotes.end(), hasMoreVotes); - + // Clearing the storages containing the detection results + // to have it sorted by decreasing probabilities size_t limitMin; if (nbCircles < 0) { limitMin = nbDetections; @@ -151,11 +153,18 @@ vpCircleHoughTransform::detect(const vpImage &I, const int &nbCir else { limitMin = std::min(nbDetections, (size_t)nbCircles); } - for (size_t i = 0; i < limitMin; i++) { - bestCircles.push_back(detectionsWithVotes[i].first); + + std::vector bestCircles; + for (size_t i = 0; i < nbDetections; i++) { + m_finalCircles[i] = std::get<0>(detectionsWithVotes[i]); + m_finalCircleVotes[i] = std::get<1>(detectionsWithVotes[i]); + m_finalCirclesProbabilities[i] = std::get<2>(detectionsWithVotes[i]); + if (i < limitMin) { + bestCircles.push_back(std::get<0>(detectionsWithVotes[i])); + } } - return bestCircles; + return m_finalCircles; } std::vector @@ -166,7 +175,7 @@ vpCircleHoughTransform::detect(const vpImage &I) m_centerVotes.clear(); m_edgePointsList.clear(); m_circleCandidates.clear(); - m_circleCandidatesVotes.clear(); + m_circleCandidatesProbabilities.clear(); m_finalCircles.clear(); m_finalCircleVotes.clear(); @@ -486,24 +495,42 @@ vpCircleHoughTransform::computeCircleCandidates() for (unsigned int idBin = 0; idBin < nbBins; idBin++) { // If the circle of center CeC_i and radius RCB_k has enough votes, it is added to the list // of Circle Candidates - float r_effective = radiusActualValueList[idBin] / (float)radiusAccumList[idBin]; - if ((float)radiusAccumList[idBin] / r_effective > m_algoParams.m_radiusRatioThresh) { - m_circleCandidates.push_back(vpImageCircle(vpImagePoint(centerCandidate.first, centerCandidate.second) - , r_effective - ) - ); - m_circleCandidatesVotes.push_back(radiusAccumList[idBin]); + if (radiusAccumList[idBin] > m_algoParams.m_centerThresh) { + float r_effective = radiusActualValueList[idBin] / (float)radiusAccumList[idBin]; + vpImageCircle candidateCircle(vpImagePoint(centerCandidate.first, centerCandidate.second), r_effective); + float proba = computeCircleProbability(candidateCircle, radiusAccumList[idBin]); + if (proba > m_algoParams.m_circleProbaThresh) { + m_circleCandidates.push_back(candidateCircle); + m_circleCandidatesProbabilities.push_back(proba); + m_circleCandidatesVotes.push_back(radiusAccumList[idBin]); + } } } } } +float +vpCircleHoughTransform::computeCircleProbability(const vpImageCircle &circle, const unsigned int &nbVotes) +{ + float proba(0.f); + float visibleArc((float)nbVotes); + float theoreticalLenght = circle.computeArcLengthInRoI(vpRect(vpImagePoint(0, 0), m_edgeMap.getWidth(), m_edgeMap.getHeight())); + if (theoreticalLenght < std::numeric_limits::epsilon()) { + proba = 0.f; + } + else { + proba = std::min(visibleArc / theoreticalLenght, 1.f); + } + return proba; +} + void vpCircleHoughTransform::mergeCircleCandidates() { // For each circle candidate CiC_i do: std::vector circleCandidates = m_circleCandidates; std::vector circleCandidatesVotes = m_circleCandidatesVotes; + std::vector circleCandidatesProba = m_circleCandidatesProbabilities; size_t nbCandidates = m_circleCandidates.size(); for (size_t i = 0; i < nbCandidates; i++) { vpImageCircle cic_i = circleCandidates[i]; @@ -520,14 +547,19 @@ vpCircleHoughTransform::mergeCircleCandidates() if (areCirclesSimilar) { // // // If the similarity exceeds a threshold, merge the circle candidates CiC_i and CiC_j and remove CiC_j of the list unsigned int totalVotes = circleCandidatesVotes[i] + circleCandidatesVotes[j]; - float newRadius = (cic_i.getRadius() * circleCandidatesVotes[i] + cic_j.getRadius() * circleCandidatesVotes[j]) / totalVotes; - vpImagePoint newCenter = (cic_i.getCenter() * circleCandidatesVotes[i]+ cic_j.getCenter() * circleCandidatesVotes[j]) / totalVotes; + float totalProba = circleCandidatesProba[i] + circleCandidatesProba[j]; + float newProba = 0.5f * totalProba; + float newRadius = (cic_i.getRadius() * circleCandidatesProba[i] + cic_j.getRadius() * circleCandidatesProba[j]) / totalProba; + vpImagePoint newCenter = (cic_i.getCenter() * circleCandidatesProba[i]+ cic_j.getCenter() * circleCandidatesProba[j]) / totalProba; cic_i = vpImageCircle(newCenter, newRadius); circleCandidates[j] = circleCandidates[nbCandidates - 1]; - circleCandidatesVotes[i] = totalVotes; + circleCandidatesVotes[i] = totalVotes / 2; circleCandidatesVotes[j] = circleCandidatesVotes[nbCandidates - 1]; + circleCandidatesProba[i] = newProba; + circleCandidatesProba[j] = circleCandidatesProba[nbCandidates - 1]; circleCandidates.pop_back(); circleCandidatesVotes.pop_back(); + circleCandidatesProba.pop_back(); nbCandidates--; j--; } @@ -552,14 +584,19 @@ vpCircleHoughTransform::mergeCircleCandidates() if (areCirclesSimilar) { // // // If the similarity exceeds a threshold, merge the circle candidates CiC_i and CiC_j and remove CiC_j of the list unsigned int totalVotes = circleCandidatesVotes[i] + circleCandidatesVotes[j]; - vpImagePoint newCenter = (cic_i.getCenter() * circleCandidatesVotes[i]+ cic_j.getCenter() * circleCandidatesVotes[j]) / totalVotes; - float newRadius = (cic_i.getRadius() * circleCandidatesVotes[i] + cic_j.getRadius() * circleCandidatesVotes[j]) / totalVotes; + float totalProba = circleCandidatesProba[i] + circleCandidatesProba[j]; + float newProba = 0.5f * totalProba; + float newRadius = (cic_i.getRadius() * circleCandidatesProba[i] + cic_j.getRadius() * circleCandidatesProba[j]) / totalProba; + vpImagePoint newCenter = (cic_i.getCenter() * circleCandidatesProba[i]+ cic_j.getCenter() * circleCandidatesProba[j]) / totalProba; cic_i = vpImageCircle(newCenter, newRadius); m_finalCircles[j] = m_finalCircles[nbCandidates - 1]; - circleCandidatesVotes[i] = totalVotes; + circleCandidatesVotes[i] = totalVotes / 2; circleCandidatesVotes[j] = circleCandidatesVotes[nbCandidates - 1]; + circleCandidatesProba[i] = newProba; + circleCandidatesProba[j] = circleCandidatesProba[nbCandidates - 1]; m_finalCircles.pop_back(); circleCandidatesVotes.pop_back(); + circleCandidatesProba.pop_back(); nbCandidates--; j--; } @@ -568,6 +605,7 @@ vpCircleHoughTransform::mergeCircleCandidates() m_finalCircles[i] = cic_i; } m_finalCircleVotes = circleCandidatesVotes; + m_finalCirclesProbabilities = circleCandidatesProba; } std::string diff --git a/tutorial/imgproc/hough-transform/config/detector_full.json b/tutorial/imgproc/hough-transform/config/detector_full.json index 7ca91550e7..0ac9889943 100644 --- a/tutorial/imgproc/hough-transform/config/detector_full.json +++ b/tutorial/imgproc/hough-transform/config/detector_full.json @@ -20,6 +20,6 @@ 0, 1000 ], - "radiusThreshRatio": 5, + "circleProbabilityThreshold": 0.9, "sobelKernelSize": 3 } diff --git a/tutorial/imgproc/hough-transform/config/detector_half.json b/tutorial/imgproc/hough-transform/config/detector_half.json index 376798b6f3..78d08a7ac7 100644 --- a/tutorial/imgproc/hough-transform/config/detector_half.json +++ b/tutorial/imgproc/hough-transform/config/detector_half.json @@ -20,6 +20,6 @@ 0, 1000 ], - "radiusThreshRatio": 2, + "circleProbabilityThreshold": 0.9, "sobelKernelSize": 3 } diff --git a/tutorial/imgproc/hough-transform/config/detector_img.json b/tutorial/imgproc/hough-transform/config/detector_img.json index f736c97e38..fd86ccddf6 100644 --- a/tutorial/imgproc/hough-transform/config/detector_img.json +++ b/tutorial/imgproc/hough-transform/config/detector_img.json @@ -21,6 +21,6 @@ 34, 75 ], - "radiusThreshRatio": 4.0, + "circleProbabilityThreshold": 0.9, "sobelKernelSize": 7 } diff --git a/tutorial/imgproc/hough-transform/config/detector_quarter.json b/tutorial/imgproc/hough-transform/config/detector_quarter.json index 06b14c3ea8..961fe089f8 100644 --- a/tutorial/imgproc/hough-transform/config/detector_quarter.json +++ b/tutorial/imgproc/hough-transform/config/detector_quarter.json @@ -20,6 +20,6 @@ 0, 1000 ], - "radiusThreshRatio": 1, + "circleProbabilityThreshold": 0.9, "sobelKernelSize": 3 } diff --git a/tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp b/tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp index 398051a3e0..36e9a9cc67 100644 --- a/tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp +++ b/tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp @@ -163,6 +163,8 @@ bool test_detection(const vpImage &I_src, vpCircleHoughTransform double t0 = vpTime::measureTimeMicros(); //! [Run detection] std::vector detectedCircles = detector.detect(I_src, nbCirclesToDetect); + std::vector probas = detector.getDetectionsProbabilities(); + std::vector votes = detector.getDetectionsVotes(); //! [Run detection] double tF = vpTime::measureTimeMicros(); std::cout << "Process time = " << (tF - t0) * 0.001 << "ms" << std::endl << std::flush; @@ -178,6 +180,8 @@ bool test_detection(const vpImage &I_src, vpCircleHoughTransform std::cout << "Circle #" << id << ":" << std::endl; std::cout << "\tCenter: (" << circleCandidate.getCenter() << ")" << std::endl; std::cout << "\tRadius: (" << circleCandidate.getRadius() << ")" << std::endl; + std::cout << "\tProba: " << probas[id] << "\tVotes:" << votes[id] << std::endl; + std::cout << "\tTheoretical arc length: " << circleCandidate.computeArcLengthInRoI(vpRect(0, 0, I_src.getWidth(), I_src.getHeight())) << std::endl; id++; idColor = (idColor + 1) % v_colors.size(); } @@ -212,7 +216,7 @@ int main(int argc, char **argv) const unsigned int def_maxRadius = 1000; const int def_dilatationRepet = 1; const float def_centerThresh = -1.f; - const float def_radiusThreshRatio = -1.f; + const float def_circleProbaThresh = 0.9f; const float def_circlePerfectness = 0.85f; const float def_centerDistanceThresh = 15.f; const float def_radiusDifferenceThresh = 15.f; @@ -232,7 +236,7 @@ int main(int argc, char **argv) unsigned int opt_maxRadius = def_maxRadius; int opt_dilatationRepet = def_dilatationRepet; float opt_centerThresh = def_centerThresh; - float opt_radiusThreshRatio = def_radiusThreshRatio; + float opt_circleProbaThresh = def_circleProbaThresh; float opt_circlePerfectness = def_circlePerfectness; float opt_centerDistanceThresh = def_centerDistanceThresh; float opt_radiusDifferenceThresh = def_radiusDifferenceThresh; @@ -296,8 +300,8 @@ int main(int argc, char **argv) opt_centerYlimits = std::pair(atoi(argv[i + 1]), atoi(argv[i + 2])); i += 2; } - else if (argName == "--radius-thresh" && i + 1 < argc) { - opt_radiusThreshRatio = static_cast(atof(argv[i + 1])); + else if (argName == "--circle-probability-thresh" && i + 1 < argc) { + opt_circleProbaThresh = static_cast(atof(argv[i + 1])); i++; } else if (argName == "--circle-perfectness" && i + 1 < argc) { @@ -333,8 +337,8 @@ int main(int argc, char **argv) << "\t [--center-thresh ] (default: " << (def_centerThresh < 0 ? "auto" : std::to_string(def_centerThresh)) << ")" << std::endl << "\t [--center-xlim ] (default: " << def_centerXlimits.first << " , " << def_centerXlimits.second << ")" << std::endl << "\t [--center-ylim ] (default: " << def_centerYlimits.first << " , " << def_centerYlimits.second << ")" << std::endl - << "\t [--radius-thresh ] (default: " << (def_radiusThreshRatio < 0 ? "auto" : std::to_string(def_radiusThreshRatio)) << ")" << std::endl - << "\t [--circle-perfectness ] (default: " << def_radiusThreshRatio << ")" << std::endl + << "\t [--circle-probability-thresh ] (default: " << def_circleProbaThresh << ")" << std::endl + << "\t [--circle-perfectness ] (default: " << def_circlePerfectness << ")" << std::endl << "\t [--merging-thresh ] (default: centers distance threshold = " << def_centerDistanceThresh << ", radius difference threshold = " << def_radiusDifferenceThresh << ")" << std::endl << "\t [--display-edge-map]" << std::endl << "\t [--help, -h]" << std::endl @@ -369,7 +373,7 @@ int main(int argc, char **argv) << "\t--canny-thresh" << std::endl << "\t\tPermit to set the lower and upper thresholds of the Canny edge detector." << std::endl << "\t\tIf a value is negative, it will be automatically computed." << std::endl - << "\t\tDefault: " << def_upperCannyThresh << std::endl + << "\t\tDefault: " << def_lowerCannyThresh << " ; " << def_upperCannyThresh << std::endl << std::endl << "\t--edge-filter" << std::endl << "\t\tPermit to set the number of iteration of 8-neighbor filter iterations of the result of the Canny edge detector." << std::endl @@ -401,9 +405,9 @@ int main(int argc, char **argv) << "\t\tThe search area is limited to [-maxRadius; +image.height + maxRadius]." << std::endl << "\t\tDefault: " << def_centerYlimits.first << " , " << def_centerYlimits.second << std::endl << std::endl - << "\t--radius-thresh" << std::endl - << "\t\tPermit to to set the minimum number of votes per radian a radius must reach to be considered as a circle candidate a given pair (center candidate, radius candidate)." << std::endl - << "\t\tDefault: " << (def_radiusThreshRatio < 0 ? "auto" : std::to_string(def_radiusThreshRatio)) << std::endl + << "\t--circle-probability-thresh" << std::endl + << "\t\tPermit to to set the minimum probability a circle must reach to be kept." << std::endl + << "\t\tDefault: " << def_circleProbaThresh << std::endl << std::endl << "\t--circle-perfectness" << std::endl << "\t\tPermit to set the set the circle perfectness threshold." << std::endl @@ -455,28 +459,6 @@ int main(int argc, char **argv) } } - if (opt_radiusThreshRatio < 0 && opt_jsonFilePath.empty()) { - // The user asked to use the parameter value that has been fine-tuned - TypeInputImage inputType = typeInputImageFromString(opt_input); - switch (inputType) { - case TypeInputImage::FULL_DISKS: -#ifdef HAVE_OPENCV_IMGPROC - opt_radiusThreshRatio = 5.; -#else - opt_radiusThreshRatio = 1.; -#endif - break; - case TypeInputImage::HALF_DISKS: - opt_radiusThreshRatio = 2.; - break; - case TypeInputImage::QUARTER_DISKS: - opt_radiusThreshRatio = 1.; - break; - default: - throw(vpException(vpException::badValue, "Missing radius threshold value to use with actual pictures as input. See the help for more information.")); - } - } - //! [Algo params] vpCircleHoughTransform::vpCircleHoughTransformParameters algoParams(opt_gaussianKernelSize @@ -491,7 +473,7 @@ int main(int argc, char **argv) , opt_maxRadius , opt_dilatationRepet , opt_centerThresh - , opt_radiusThreshRatio + , opt_circleProbaThresh , opt_circlePerfectness , opt_centerDistanceThresh , opt_radiusDifferenceThresh From 22736588eff0fb6f664816cdbfc9837577356a1c Mon Sep 17 00:00:00 2001 From: rlagneau Date: Fri, 29 Sep 2023 11:51:58 +0200 Subject: [PATCH 09/22] [WIP] Added case top + bottom + X and tested case with two intersections on each axis for the left case --- modules/core/src/image/vpImageCircle.cpp | 253 +++++++++++++++++- .../test/tools/geometry/testImageCircle.cpp | 43 ++- 2 files changed, 282 insertions(+), 14 deletions(-) diff --git a/modules/core/src/image/vpImageCircle.cpp b/modules/core/src/image/vpImageCircle.cpp index 56dac6d11b..47bd78fa5a 100644 --- a/modules/core/src/image/vpImageCircle.cpp +++ b/modules/core/src/image/vpImageCircle.cpp @@ -286,7 +286,7 @@ void computePerpendicularAxesIntersections(const float &u_c, const float &v_c, c * \param[in] radius The radius of the circle. * \param[out] delta_theta The length of the angular interval that is in the RoI. */ -void computeTopLeftIntersections(const float &u_c, const float &v_c, const vpImagePoint &topLeft, const float &radius, +void computeIntersectionsTopLeft(const float &u_c, const float &v_c, const vpImagePoint &topLeft, const float &radius, float &delta_theta) { std::pair crossing_theta_u_min, crossing_theta_u_max; @@ -343,7 +343,7 @@ void computeTopLeftIntersections(const float &u_c, const float &v_c, const vpIma * \param[in] radius The radius of the circle. * \param[out] delta_theta The length of the angular interval that is in the RoI. */ -void computeTopRightIntersections(const float &u_c, const float &v_c, const float &vmin_roi, const float &umax_roi, const float &radius, +void computeIntersectionsTopRight(const float &u_c, const float &v_c, const float &vmin_roi, const float &umax_roi, const float &radius, float &delta_theta) { std::pair crossing_theta_u_min, crossing_theta_u_max; @@ -396,7 +396,7 @@ void computeTopRightIntersections(const float &u_c, const float &v_c, const floa * \param[in] radius The radius of the circle. * \param[out] delta_theta The length of the angular interval that is in the RoI. */ -void computeBottomLeftIntersections(const float &u_c, const float &v_c, const vpImagePoint &topLeft, const float &height, const float &radius, +void computeIntersectionsBottomLeft(const float &u_c, const float &v_c, const vpImagePoint &topLeft, const float &height, const float &radius, float &delta_theta) { std::pair crossing_theta_u_min, crossing_theta_u_max; @@ -452,7 +452,7 @@ void computeBottomLeftIntersections(const float &u_c, const float &v_c, const vp * \param[in] radius The radius of the circle. * \param[out] delta_theta The length of the angular interval that is in the RoI. */ -void computeBottomRightIntersections(const float &u_c, const float &v_c, const float &vmax_roi, const float &umax_roi, const float &radius, +void computeIntersectionsBottomRight(const float &u_c, const float &v_c, const float &vmax_roi, const float &umax_roi, const float &radius, float &delta_theta) { std::pair crossing_theta_u_min, crossing_theta_u_max; @@ -499,6 +499,213 @@ void computeBottomRightIntersections(const float &u_c, const float &v_c, const f } } +/*! + * \brief Compute the length of the angular interval of the circle when it intersects + * only with the top, left and bottom borders of the Region of Interest (RoI). + * + * \param[in] u_c The horizontal u-axis coordinate of the center. + * \param[in] v_c The vertical v-axis coordinate of the center. + * \param[in] topLeft The top left corner of the RoI. + * \param[in] height The height of the RoI. + * \param[in] radius The radius of the circle. + * \param[out] delta_theta The length of the angular interval that is in the RoI. + */ +void computeIntersectionsTopLeftBottom(const float &u_c, const float &v_c, const vpImagePoint &topLeft, const float &height, const float &radius, + float &delta_theta) +{ + // Computing the intersections with the top and left axes + std::pair crossing_theta_u_min, crossing_theta_u_max; + std::pair crossing_theta_v_min, crossing_theta_v_max; + float crossing_u_top = topLeft.get_v(); // We cross the u-axis of the RoI at the maximum v-coordinate of the RoI + float crossing_v = topLeft.get_u(); // We cross the v-axis of the RoI at the minimum u-coordinate of the RoI + float umin_roi = crossing_v; + float vmin_roi = crossing_u_top; + computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u_top, crossing_v, + crossing_theta_u_min, crossing_theta_u_max, + crossing_theta_v_min, crossing_theta_v_max); + float theta_u_min_top = crossing_theta_u_min.first, theta_v_min = crossing_theta_v_min.first; + float theta_u_max_top = crossing_theta_u_max.first, theta_v_max = crossing_theta_v_max.first; + float u_umin_top = crossing_theta_u_min.second; + float u_umax_top = crossing_theta_u_max.second; + float v_vmin = crossing_theta_v_min.second; + float v_vmax = crossing_theta_v_max.second; + + // Computing the intersections with the bottom and left axes + float vmax_roi = vmin_roi + height; + float crossing_u_bottom = vmax_roi; // We cross the u-axis of the RoI at the maximum v-coordinate of the RoI + computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u_bottom, crossing_v, + crossing_theta_u_min, crossing_theta_u_max, + crossing_theta_v_min, crossing_theta_v_max); + float theta_u_min_bottom = crossing_theta_u_min.first; + float theta_u_max_bottom = crossing_theta_u_max.first; + float u_umin_bottom = crossing_theta_u_min.second; + float u_umax_bottom = crossing_theta_u_max.second; + std::cout << "umin_roi = " << topLeft.get_u() << "\tvmin_roi = " << topLeft.get_v() << "\tvmax_roi = " << vmax_roi << std::endl; + std::cout << "u_umin_top = " << u_umin_top << " (" << theta_u_min_top << ")\tu_umax_top = " << u_umax_top << " (" << theta_u_max_top << ")" << std::endl; + std::cout << "u_umin_bottom = " << u_umin_bottom << " (" << theta_u_min_bottom << ")\tu_umax_bottom = " << u_umax_bottom << " (" << theta_u_max_bottom << ")" << std::endl; + std::cout << "v_vmin = " << v_vmin << " (" << theta_v_min << ")\tv_vmax = " << v_vmax << " (" << theta_v_max << ")" << std::endl; + if (u_umin_top >= umin_roi && u_umin_bottom >= umin_roi && v_vmin >= vmin_roi && v_vmax <= vmax_roi) { + std::cout << "\t|-> case intersection top + left + bottom twice" << std::endl; + delta_theta = (theta_v_min - theta_u_min_top) + (theta_u_max_top - theta_u_max_bottom) + (theta_u_min_bottom - theta_v_max); + } + else if (u_umin_top <= umin_roi && v_vmin <= vmin_roi && u_umin_bottom <= umin_roi && v_vmax >= vmax_roi) { + std::cout << "\t|-> case intersection top and bottom" << std::endl; + delta_theta = (theta_u_max_top - theta_u_max_bottom); + } + else if (u_umax_top <= umin_roi && u_umax_bottom <= umin_roi && v_vmin >= vmin_roi && v_vmax <= vmax_roi) { + std::cout << "\t|-> case left only" << std::endl; + computeIntersectionsLeftBorderOnly(u_c, umin_roi, radius, delta_theta); + } + else if (u_umax_bottom > umin_roi && v_vmin >= vmin_roi) { + std::cout << "\t|-> case bottom/left corner" << std::endl; + computeIntersectionsBottomLeft(u_c, v_c, topLeft, height, radius, delta_theta); + } + else if (u_umax_top > umin_roi && v_vmax <= vmax_roi) { + std::cout << "\t|-> case top/left corner" << std::endl; + computeIntersectionsTopLeft(u_c, v_c, topLeft, radius, delta_theta); + } +} + +/*! + * \brief Compute the length of the angular interval of the circle when it intersects + * only with the top, right and bottom borders of the Region of Interest (RoI). + * + * \param[in] u_c The horizontal u-axis coordinate of the center. + * \param[in] v_c The vertical v-axis coordinate of the center. + * \param[in] topLeft The top left corner of the RoI. + * \param[in] width The width of the RoI. + * \param[in] height The height of the RoI. + * \param[in] radius The radius of the circle. + * \param[out] delta_theta The length of the angular interval that is in the RoI. + */ +void computeIntersectionsTopRightBottom(const float &u_c, const float &v_c, const vpImagePoint &topLeft, const float &width, const float &height, const float &radius, + float &delta_theta) +{ + // Computing the intersections with the top and left axes + std::pair crossing_theta_u_min, crossing_theta_u_max; + std::pair crossing_theta_v_min, crossing_theta_v_max; + float crossing_u_top = topLeft.get_v(); // We cross the u-axis of the RoI at the maximum v-coordinate of the RoI + float umin_roi = topLeft.get_u(); + float umax_roi = umin_roi + width; + float crossing_v = umax_roi; // We cross the v-axis of the RoI at the maximum u-coordinate of the RoI + float vmin_roi = crossing_u_top; + computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u_top, crossing_v, + crossing_theta_u_min, crossing_theta_u_max, + crossing_theta_v_min, crossing_theta_v_max); + float theta_u_min_top = crossing_theta_u_min.first, theta_v_min = crossing_theta_v_min.first; + float theta_u_max_top = crossing_theta_u_max.first, theta_v_max = crossing_theta_v_max.first; + float u_umin_top = crossing_theta_u_min.second; + float u_umax_top = crossing_theta_u_max.second; + float v_vmin = crossing_theta_v_min.second; + float v_vmax = crossing_theta_v_max.second; + + // Computing the intersections with the bottom and left axes + float vmax_roi = vmin_roi + height; + float crossing_u_bottom = vmax_roi; // We cross the u-axis of the RoI at the maximum v-coordinate of the RoI + computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u_bottom, crossing_v, + crossing_theta_u_min, crossing_theta_u_max, + crossing_theta_v_min, crossing_theta_v_max); + float theta_u_min_bottom = crossing_theta_u_min.first; + float theta_u_max_bottom = crossing_theta_u_max.first; + float u_umin_bottom = crossing_theta_u_min.second; + float u_umax_bottom = crossing_theta_u_max.second; + std::cout << "umin_roi = " << topLeft.get_u() << "\tvmin_roi = " << topLeft.get_v() << "\tvmax_roi = " << vmax_roi << std::endl; + std::cout << "u_umin_top = " << u_umin_top << " (" << theta_u_min_top << ")\tu_umax_top = " << u_umax_top << " (" << theta_u_max_top << ")" << std::endl; + std::cout << "u_umin_bottom = " << u_umin_bottom << " (" << theta_u_min_bottom << ")\tu_umax_bottom = " << u_umax_bottom << " (" << theta_u_max_bottom << ")" << std::endl; + std::cout << "v_vmin = " << v_vmin << " (" << theta_v_min << ")\tv_vmax = " << v_vmax << " (" << theta_v_max << ")" << std::endl; + if (u_umax_top <= umax_roi && u_umax_bottom <= umin_roi && v_vmin >= vmin_roi && v_vmax <= vmax_roi) { + std::cout << "\t|-> case intersection top + right + bottom twice" << std::endl; + delta_theta = 2.f * M_PI - ((theta_u_min_top - theta_u_max_top) + (theta_v_min - theta_v_max) + (theta_u_max_bottom - theta_u_min_bottom)); + } + else if (u_umin_top <= umax_roi && u_umax_top > umax_roi && v_vmin <= vmin_roi && u_umin_bottom <= umax_roi && u_umax_bottom > umax_roi && v_vmax >= vmax_roi) { + std::cout << "\t|-> case intersection top and bottom" << std::endl; + delta_theta = (theta_u_max_top - theta_u_max_bottom); + } + else if (u_umin_top >= umax_roi && u_umin_bottom >= umax_roi && v_vmin >= vmin_roi && v_vmax <= vmax_roi) { + std::cout << "\t|-> case right only" << std::endl; + computeIntersectionsRightBorderOnly(u_c, umax_roi, radius, delta_theta); + } + else if (u_umin_bottom <= umax_roi && v_vmin >= vmin_roi) { + std::cout << "\t|-> case bottom/right corner" << std::endl; + computeIntersectionsBottomRight(u_c, v_c, vmax_roi, umax_roi, radius, delta_theta); + } + else if (u_umin_top <= umax_roi && v_vmax <= vmax_roi) { + std::cout << "\t|-> case top/right corner" << std::endl; + computeIntersectionsTopRight(u_c, v_c, vmin_roi, umax_roi, radius, delta_theta); + } +} + +/*! + * \brief Compute the length of the angular interval of the circle when it intersects + * only with the top and bottom borders of the Region of Interest (RoI). + * + * \param[in] u_c The horizontal u-axis coordinate of the center. + * \param[in] v_c The vertical v-axis coordinate of the center. + * \param[in] vmin_roi The minimum v-coordinate of the RoI. + * \param[in] vmax_roi The maximum v-coordinate of the RoI. + * \param[in] radius The radius of the circle. + * \param[out] delta_theta The length of the angular interval that is in the RoI. + */ +void computeIntersectionsTopBottomOnly(const float &u_c, const float &v_c, const float &vmin_roi, const float &vmax_roi, const float &radius, + float &delta_theta) +{ + // Computing the two angles for which the u-axis is crossed at the top of the RoI + // v = vc - r sin(theta) because the v-axis goes down + // theta = asin((vc - vmin_roi)/r) + float theta_u_cross_top = std::asin((v_c - vmin_roi)/radius); + theta_u_cross_top = getAngleBetweenMinPiAndPi(theta_u_cross_top); + float theta_u_cross_top_2 = 0.f; + if (theta_u_cross_top_2 > 0) { + theta_u_cross_top_2 = M_PI - theta_u_cross_top; + } + else { + theta_u_cross_top_2 = -M_PI - theta_u_cross_top; + } + // Computing the corresponding u-coordinates at which the u-axis is crossed + float u_ucross_top = u_c + radius * std::cos(theta_u_cross_top); + float u_ucross_top_2 = u_c + radius * std::cos(theta_u_cross_top_2); + // Sorting the outputs such as u(theta_u_cross_top_min) < u(theta_u_cross_top_max) + float theta_u_cross_top_min = 0.f, theta_u_cross_top_max = 0.f; + if (u_ucross_top < u_ucross_top_2) { + theta_u_cross_top_min = theta_u_cross_top; + theta_u_cross_top_max = theta_u_cross_top_2; + } + else { + theta_u_cross_top_min = theta_u_cross_top_2; + theta_u_cross_top_max = theta_u_cross_top; + } + + // Computing the two angles for which the u-axis is crossed at the bottom of the RoI + // v = vc - r sin(theta) because the v-axis goes down + // theta = asin((vc - vmax_roi)/r) + float theta_u_cross_bottom = std::asin((v_c - vmax_roi)/radius); + theta_u_cross_bottom = getAngleBetweenMinPiAndPi(theta_u_cross_bottom); + float theta_u_cross_bottom_2 = 0.f; + if (theta_u_cross_bottom_2 > 0) { + theta_u_cross_bottom_2 = M_PI - theta_u_cross_bottom; + } + else { + theta_u_cross_bottom_2 = -M_PI - theta_u_cross_bottom; + } + // Computing the corresponding u-coordinates at which the u-axis is crossed + float u_ucross_bottom = u_c + radius * std::cos(theta_u_cross_bottom); + float u_ucross_bottom_2 = u_c + radius * std::cos(theta_u_cross_bottom_2); + // Sorting the outputs such as u(theta_u_cross_bottom_min) < u(theta_u_cross_bottom_max) + float theta_u_cross_bottom_min = 0.f, theta_u_cross_bottom_max = 0.f; + if (u_ucross_bottom < u_ucross_bottom_2) { + theta_u_cross_bottom_min = theta_u_cross_bottom; + theta_u_cross_bottom_max = theta_u_cross_bottom_2; + } + else { + theta_u_cross_bottom_min = theta_u_cross_bottom_2; + theta_u_cross_bottom_max = theta_u_cross_bottom; + } + + // Computing the the length of the angular interval of the circle when it intersects + // only with the top and bottom borders of the Region of Interest (RoI) + delta_theta = 2.f * M_PI - ((theta_u_cross_top_min - theta_u_cross_top_max) + (theta_u_cross_bottom_max - theta_u_cross_bottom_min)); +} + float vpImageCircle::computeArcLengthInRoI(const vpRect &roi) const { float deltaTheta = 0.f; @@ -548,31 +755,51 @@ float vpImageCircle::computeArcLengthInRoI(const vpRect &roi) const else if (touchBottomBorder && touchLeftBorder && !touchRightBorder && !touchTopBorder) { // Touches/intersects the bottom and left borders of the RoI std::cout << "Case bottom / left" << std::endl; - computeBottomLeftIntersections(center_u, center_v, topLeft, roi_h, radius, deltaTheta); + computeIntersectionsBottomLeft(center_u, center_v, topLeft, roi_h, radius, deltaTheta); } else if (touchBottomBorder && !touchLeftBorder && touchRightBorder && !touchTopBorder) { // Touches/intersects the bottom and right borders of the RoI std::cout << "Case bottom / right" << std::endl; - computeBottomRightIntersections(center_u, center_v, vmax_roi, umax_roi, radius, deltaTheta); + computeIntersectionsBottomRight(center_u, center_v, vmax_roi, umax_roi, radius, deltaTheta); } else if (!touchBottomBorder && touchLeftBorder && !touchRightBorder && touchTopBorder) { // Touches/intersects the top and left borders of the RoI std::cout << "Case top / left" << std::endl; - computeTopLeftIntersections(center_u, center_v, topLeft, radius, deltaTheta); + computeIntersectionsTopLeft(center_u, center_v, topLeft, radius, deltaTheta); } else if (!touchBottomBorder && !touchLeftBorder && touchRightBorder && touchTopBorder) { // Touches/intersects the top and right borders of the RoI std::cout << "Case top / right" << std::endl; - computeTopRightIntersections(center_u, center_v, vmin_roi, umax_roi, radius, deltaTheta); + computeIntersectionsTopRight(center_u, center_v, vmin_roi, umax_roi, radius, deltaTheta); + } + else if (touchBottomBorder && touchTopBorder && touchLeftBorder && !touchRightBorder) { + // Touches/intersects the top, left and bottom borders of the RoI + std::cout << "Case bottom / top / left" << std::endl; + computeIntersectionsTopLeftBottom(center_u, center_v, topLeft, roi_h, radius, deltaTheta); + } + else if (touchBottomBorder && touchTopBorder && !touchLeftBorder && touchRightBorder) { + // Touches/intersects the top, right and bottom borders of the RoI + std::cout << "Case bottom / top / right" << std::endl; + computeIntersectionsTopRightBottom(center_u, center_v, topLeft, roi_w, roi_h, radius, deltaTheta); } - else if (touchBottomBorder && touchTopBorder && (touchLeftBorder ^ touchRightBorder)) { + else if (touchBottomBorder && touchTopBorder && !touchLeftBorder && touchRightBorder) { // Touches/intersects the top and bottom borders of the RoI - std::cout << "Case bottom / top" << std::endl; + std::cout << "Case bottom / top only" << std::endl; + computeIntersectionsTopBottomOnly(center_u, center_v, vmin_roi, vmax_roi, radius, deltaTheta); + } + else if (touchLeftBorder && touchRightBorder && touchTopBorder && !touchBottomBorder) { + // Touches/intersects the top, left and right borders of the RoI + std::cout << "Case top / right / left" << std::endl; + // computeOppositeAxesIntersections ? + } + else if (touchLeftBorder && touchRightBorder && !touchTopBorder && touchBottomBorder) { + // Touches/intersects the bottom, left and right borders of the RoI + std::cout << "Case bottom / right / left" << std::endl; // computeOppositeAxesIntersections ? } - else if (touchLeftBorder && touchRightBorder && (touchTopBorder ^ touchBottomBorder)) { - // Touches/intersects the left and right borders of the RoI - std::cout << "Case right / left" << std::endl; + else if (touchLeftBorder && touchRightBorder && !touchTopBorder && !touchBottomBorder) { + // Touches/intersects the bottom, left and right borders of the RoI + std::cout << "Case bottom / right / left" << std::endl; // computeOppositeAxesIntersections ? } else if (touchBottomBorder && touchLeftBorder && touchRightBorder && touchTopBorder) { diff --git a/modules/core/test/tools/geometry/testImageCircle.cpp b/modules/core/test/tools/geometry/testImageCircle.cpp index f614e99ce5..801d231cd1 100644 --- a/modules/core/test/tools/geometry/testImageCircle.cpp +++ b/modules/core/test/tools/geometry/testImageCircle.cpp @@ -91,7 +91,7 @@ int main() vpRect roiSquare(OFFSET, OFFSET, HEIGHT, HEIGHT); vpImageCircle noIntersect(vpImagePoint(OFFSET + HEIGHT / 2.f, OFFSET + HEIGHT / 2.f), HEIGHT / 2.f); float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); - float theoreticalValue = 2.f * M_PI * RADIUS; + float theoreticalValue = 2.f * M_PI * HEIGHT / 2.f; bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); std::string statusTest; if (isValueOK) { @@ -988,6 +988,47 @@ int main() hasSucceeded &= isValueOK; } + // Test with intersections with the top, bottom and the left border + // crossing each axis twice in the RoI + { + // (1): u_cross_top_min = uc + r cos(theta_u_top_min) >= umin_roi ; vmin_roi = vc - r sin(theta_u_top_min) + // (2): umin_roi = uc + r cos(theta_v_min); v_cross_min = vc - r sin(theta_v_min) >= vmin_roi + // (3): u_cross_top_max = uc + r cos(theta_u_top_max) > umin_roi ; vmin_roi = vc - r sin(theta_u_top_max) + // (4): umin_roi = uc + r cos(theta_v_max); v_cross_max = vc - r sin(theta_v_max) <= vmin_roi + height + // (5): u_cross_bot_min = uc + r cos(theta_u_bottom_min) >= umin_roi ; vmin_roi + height = vc - r sin(theta_u_bottom_min) + // (6): u_cross_bot_max = uc + r cos(theta_u_bottom_max) > umin_roi ; vmin_roi + height = vc - r sin(theta_u_bottom_max) + // (1) & (3) theta_u_top_min = PI - theta_u_top_max + // (2) & (4) theta_v_min = - theta_v_max + // (5) & (6) theta_u_bottom_min = PI - theta_u_bottom_max + float theta_u_top_min = 5.f * M_PI / 8.f; + float theta_u_top_max = 3.f * M_PI / 8.f; + float theta_v_min = 7.f * M_PI / 8.f; + float theta_v_max = -theta_v_min; + float theta_u_bottom_min = -5.f * M_PI / 8.f; + float theta_u_bottom_max = -3.f * M_PI / 8.f; + float vc = OFFSET + HEIGHT / 2.f; + float radius = -(OFFSET - vc)/ std::sin(theta_u_top_min); + float uc = OFFSET - radius * std::cos(theta_v_min); + vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = ((theta_v_min - theta_u_top_min) + (theta_u_top_max - theta_u_bottom_max) + (theta_u_bottom_min - theta_v_max)) * radius; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the top, bottom and the left border, crossing each axis twice in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + + if (hasSucceeded) { std::cout << "testImageCircle overall result: SUCCESS"; return EXIT_SUCCESS; From 0262a6dfbcc4417b2be871af71c5d06fb4d053b9 Mon Sep 17 00:00:00 2001 From: rlagneau Date: Fri, 29 Sep 2023 14:11:49 +0200 Subject: [PATCH 10/22] [WIP] Successful tests: top/right/bottom with two intersections on each axis + top / bottom only --- modules/core/src/image/vpImageCircle.cpp | 11 ++- .../test/tools/geometry/testImageCircle.cpp | 75 +++++++++++++++++++ 2 files changed, 82 insertions(+), 4 deletions(-) diff --git a/modules/core/src/image/vpImageCircle.cpp b/modules/core/src/image/vpImageCircle.cpp index 47bd78fa5a..d9b34282b7 100644 --- a/modules/core/src/image/vpImageCircle.cpp +++ b/modules/core/src/image/vpImageCircle.cpp @@ -613,7 +613,7 @@ void computeIntersectionsTopRightBottom(const float &u_c, const float &v_c, cons std::cout << "u_umin_top = " << u_umin_top << " (" << theta_u_min_top << ")\tu_umax_top = " << u_umax_top << " (" << theta_u_max_top << ")" << std::endl; std::cout << "u_umin_bottom = " << u_umin_bottom << " (" << theta_u_min_bottom << ")\tu_umax_bottom = " << u_umax_bottom << " (" << theta_u_max_bottom << ")" << std::endl; std::cout << "v_vmin = " << v_vmin << " (" << theta_v_min << ")\tv_vmax = " << v_vmax << " (" << theta_v_max << ")" << std::endl; - if (u_umax_top <= umax_roi && u_umax_bottom <= umin_roi && v_vmin >= vmin_roi && v_vmax <= vmax_roi) { + if (u_umax_top <= umax_roi && u_umax_bottom <= umax_roi && v_vmin >= vmin_roi && v_vmax <= vmax_roi) { std::cout << "\t|-> case intersection top + right + bottom twice" << std::endl; delta_theta = 2.f * M_PI - ((theta_u_min_top - theta_u_max_top) + (theta_v_min - theta_v_max) + (theta_u_max_bottom - theta_u_min_bottom)); } @@ -655,12 +655,13 @@ void computeIntersectionsTopBottomOnly(const float &u_c, const float &v_c, const float theta_u_cross_top = std::asin((v_c - vmin_roi)/radius); theta_u_cross_top = getAngleBetweenMinPiAndPi(theta_u_cross_top); float theta_u_cross_top_2 = 0.f; - if (theta_u_cross_top_2 > 0) { + if (theta_u_cross_top > 0) { theta_u_cross_top_2 = M_PI - theta_u_cross_top; } else { theta_u_cross_top_2 = -M_PI - theta_u_cross_top; } + // Computing the corresponding u-coordinates at which the u-axis is crossed float u_ucross_top = u_c + radius * std::cos(theta_u_cross_top); float u_ucross_top_2 = u_c + radius * std::cos(theta_u_cross_top_2); @@ -681,15 +682,17 @@ void computeIntersectionsTopBottomOnly(const float &u_c, const float &v_c, const float theta_u_cross_bottom = std::asin((v_c - vmax_roi)/radius); theta_u_cross_bottom = getAngleBetweenMinPiAndPi(theta_u_cross_bottom); float theta_u_cross_bottom_2 = 0.f; - if (theta_u_cross_bottom_2 > 0) { + if (theta_u_cross_bottom > 0) { theta_u_cross_bottom_2 = M_PI - theta_u_cross_bottom; } else { theta_u_cross_bottom_2 = -M_PI - theta_u_cross_bottom; } + // Computing the corresponding u-coordinates at which the u-axis is crossed float u_ucross_bottom = u_c + radius * std::cos(theta_u_cross_bottom); float u_ucross_bottom_2 = u_c + radius * std::cos(theta_u_cross_bottom_2); + // Sorting the outputs such as u(theta_u_cross_bottom_min) < u(theta_u_cross_bottom_max) float theta_u_cross_bottom_min = 0.f, theta_u_cross_bottom_max = 0.f; if (u_ucross_bottom < u_ucross_bottom_2) { @@ -782,7 +785,7 @@ float vpImageCircle::computeArcLengthInRoI(const vpRect &roi) const std::cout << "Case bottom / top / right" << std::endl; computeIntersectionsTopRightBottom(center_u, center_v, topLeft, roi_w, roi_h, radius, deltaTheta); } - else if (touchBottomBorder && touchTopBorder && !touchLeftBorder && touchRightBorder) { + else if (touchBottomBorder && touchTopBorder && !touchLeftBorder && !touchRightBorder) { // Touches/intersects the top and bottom borders of the RoI std::cout << "Case bottom / top only" << std::endl; computeIntersectionsTopBottomOnly(center_u, center_v, vmin_roi, vmax_roi, radius, deltaTheta); diff --git a/modules/core/test/tools/geometry/testImageCircle.cpp b/modules/core/test/tools/geometry/testImageCircle.cpp index 801d231cd1..400826d114 100644 --- a/modules/core/test/tools/geometry/testImageCircle.cpp +++ b/modules/core/test/tools/geometry/testImageCircle.cpp @@ -1028,6 +1028,81 @@ int main() hasSucceeded &= isValueOK; } + // Test with intersections with the top, bottom and the right border + // crossing each axis twice in the RoI + { + // (1): u_cross_top_min = uc + r cos(theta_u_top_min) < umin_roi + width ; vmin_roi = vc - r sin(theta_u_top_min) + // (2): umin_roi + width = uc + r cos(theta_v_min); v_cross_min = vc - r sin(theta_v_min) >= vmin_roi + // (3): u_cross_top_max = uc + r cos(theta_u_top_max) <= umin_roi + width ; vmin_roi = vc - r sin(theta_u_top_max) + // (4): umin_roi + width = uc + r cos(theta_v_max); v_cross_max = vc - r sin(theta_v_max) <= vmin_roi + height + // (5): u_cross_bot_min = uc + r cos(theta_u_bottom_min) < umin_roi + width ; vmin_roi + height = vc - r sin(theta_u_bottom_min) + // (6): u_cross_bot_max = uc + r cos(theta_u_bottom_max) <= umin_roi + width ; vmin_roi + height = vc - r sin(theta_u_bottom_max) + // (1) & (3) theta_u_top_min = PI - theta_u_top_max + // (2) & (4) theta_v_min = - theta_v_max + // (5) & (6) theta_u_bottom_min = PI - theta_u_bottom_max + float theta_u_top_min = 5.f * M_PI / 8.f; + float theta_u_top_max = 3.f * M_PI / 8.f; + float theta_v_min = 1.f * M_PI / 8.f; + float theta_v_max = -theta_v_min; + float theta_u_bottom_min = -5.f * M_PI / 8.f; + float theta_u_bottom_max = -3.f * M_PI / 8.f; + float vc = OFFSET + HEIGHT / 2.f; + float radius = -(OFFSET - vc)/ std::sin(theta_u_top_min); + float uc = OFFSET + WIDTH - radius * std::cos(theta_v_min); + vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = (2.f * M_PI - ((theta_u_top_min - theta_u_top_max) + (theta_v_min - theta_v_max) + (theta_u_bottom_max - theta_u_bottom_min))) * radius; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the top, bottom and the right border, crossing each axis twice in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + + // Test with intersections with the top and bottom only, + // crossing each axis twice in the RoI + { + // (1): u_cross_top_min = uc + r cos(theta_u_top_min) < umin_roi + width ; vmin_roi = vc - r sin(theta_u_top_min) + // (3): u_cross_top_max = uc + r cos(theta_u_top_max) <= umin_roi + width ; vmin_roi = vc - r sin(theta_u_top_max) + // (5): u_cross_bot_min = uc + r cos(theta_u_bottom_min) < umin_roi + width ; vmin_roi + height = vc - r sin(theta_u_bottom_min) + // (6): u_cross_bot_max = uc + r cos(theta_u_bottom_max) <= umin_roi + width ; vmin_roi + height = vc - r sin(theta_u_bottom_max) + // (1) & (3) theta_u_top_min = PI - theta_u_top_max + // (5) & (6) theta_u_bottom_min = PI - theta_u_bottom_max + float theta_u_top_min = 2.f * M_PI / 3.f; + float theta_u_top_max = M_PI / 3.f; + float theta_u_bottom_min = -2.f * M_PI / 3.f; + float theta_u_bottom_max = -M_PI / 3.f; + float uc = OFFSET + WIDTH / 2.f; + float vc = OFFSET + HEIGHT / 2.f; + float radius = -(OFFSET - vc)/ std::sin(theta_u_top_min); + + vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = (2.f * M_PI - ((theta_u_top_min - theta_u_top_max) + (theta_u_bottom_max - theta_u_bottom_min))) * radius; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the top and bottom borders only, crossing each axis twice in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } if (hasSucceeded) { std::cout << "testImageCircle overall result: SUCCESS"; From 52bec05ac62af82d49fe69422534d7ab621793fe Mon Sep 17 00:00:00 2001 From: rlagneau Date: Fri, 29 Sep 2023 14:40:34 +0200 Subject: [PATCH 11/22] [WIP] Added tests for top/bottom/left and top/bottom/right where only top and bottom are crossed in the RoI --- .../test/tools/geometry/testImageCircle.cpp | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/modules/core/test/tools/geometry/testImageCircle.cpp b/modules/core/test/tools/geometry/testImageCircle.cpp index 400826d114..22cdb28858 100644 --- a/modules/core/test/tools/geometry/testImageCircle.cpp +++ b/modules/core/test/tools/geometry/testImageCircle.cpp @@ -1028,6 +1028,46 @@ int main() hasSucceeded &= isValueOK; } + // Test with intersections with the top, bottom and the left border + // crossing top and bottom only in the RoI + { + // (1): u_cross_top_min = uc + r cos(theta_u_top_min) < umin_roi ; vmin_roi = vc - r sin(theta_u_top_min) + // (2): umin_roi = uc + r cos(theta_v_min); v_cross_min = vc - r sin(theta_v_min) <= vmin_roi + // (3): u_cross_top_max = uc + r cos(theta_u_top_max) >= umin_roi ; vmin_roi = vc - r sin(theta_u_top_max) + // (4): umin_roi = uc + r cos(theta_v_max); v_cross_max = vc - r sin(theta_v_max) >= vmin_roi + height + // (5): u_cross_bot_min = uc + r cos(theta_u_bottom_min) < umin_roi ; vmin_roi + height = vc - r sin(theta_u_bottom_min) + // (6): u_cross_bot_max = uc + r cos(theta_u_bottom_max) >= umin_roi ; vmin_roi + height = vc - r sin(theta_u_bottom_max) + // (1) & (3) theta_u_top_min = PI - theta_u_top_max + // (2) & (4) theta_v_min = - theta_v_max + // (5) & (6) theta_u_bottom_min = PI - theta_u_bottom_max + float theta_u_top_max = M_PI / 6.f; + float theta_u_top_min = M_PI - theta_u_top_max; + float theta_v_min = M_PI / 3.f; + float theta_v_max = -theta_v_min; + float theta_u_bottom_min = -theta_u_top_min; + float theta_u_bottom_max = -theta_u_top_max; + float radius = HEIGHT; + float vc = OFFSET + radius * std::sin(theta_u_top_min); + float uc = OFFSET - radius * std::cos(theta_v_min); + vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = (theta_u_top_max - theta_u_bottom_max) * radius; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the top, bottom and the left border, crossing top and bottom only in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + // Test with intersections with the top, bottom and the right border // crossing each axis twice in the RoI { @@ -1068,6 +1108,46 @@ int main() hasSucceeded &= isValueOK; } + // Test with intersections with the top, bottom and the right border + // crossing top and bottom only in the RoI + { + // (1): u_cross_top_min = uc + r cos(theta_u_top_min) <= umin_roi + width ; vmin_roi = vc - r sin(theta_u_top_min) + // (2): umin_roi + width = uc + r cos(theta_v_min); v_cross_min = vc - r sin(theta_v_min) <= vmin_roi + // (3): u_cross_top_max = uc + r cos(theta_u_top_max) > umin_roi + width ; vmin_roi = vc - r sin(theta_u_top_max) + // (4): umin_roi + width = uc + r cos(theta_v_max); v_cross_max = vc - r sin(theta_v_max) >= vmin_roi + height + // (5): u_cross_bot_min = uc + r cos(theta_u_bottom_min) <= umin_roi + width ; vmin_roi + height = vc - r sin(theta_u_bottom_min) + // (6): u_cross_bot_max = uc + r cos(theta_u_bottom_max) > umin_roi + width ; vmin_roi + height = vc - r sin(theta_u_bottom_max) + // (1) & (3) theta_u_top_min = PI - theta_u_top_max + // (2) & (4) theta_v_min = - theta_v_max + // (5) & (6) theta_u_bottom_min = PI - theta_u_bottom_max + float theta_u_top_min = 5.f * M_PI / 6.f; + float theta_u_top_max = M_PI - theta_u_top_min; + float theta_v_min = 2.f * M_PI / 3.f; + float theta_v_max = -theta_v_min; + float theta_u_bottom_min = -theta_u_top_min; + float theta_u_bottom_max = -theta_u_top_max; + float radius = HEIGHT; + float vc = OFFSET + radius * std::sin(theta_u_top_min); + float uc = OFFSET + WIDTH - radius * std::cos(theta_v_min); + vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = (2.f * M_PI - (theta_u_top_min - theta_u_bottom_min)) * radius; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the top, bottom and the right border, crossing top and bottom only in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + // Test with intersections with the top and bottom only, // crossing each axis twice in the RoI { From e595d5c2ef568bac7d8004a2da3c9d24dea2b8be Mon Sep 17 00:00:00 2001 From: rlagneau Date: Fri, 29 Sep 2023 14:58:13 +0200 Subject: [PATCH 12/22] [WIP] Added tests for top/bottom/left and top/bottom/right where only left (or right) axis is crossed --- .../test/tools/geometry/testImageCircle.cpp | 88 ++++++++++++++++++- 1 file changed, 84 insertions(+), 4 deletions(-) diff --git a/modules/core/test/tools/geometry/testImageCircle.cpp b/modules/core/test/tools/geometry/testImageCircle.cpp index 22cdb28858..e09df6207c 100644 --- a/modules/core/test/tools/geometry/testImageCircle.cpp +++ b/modules/core/test/tools/geometry/testImageCircle.cpp @@ -1029,7 +1029,7 @@ int main() } // Test with intersections with the top, bottom and the left border - // crossing top and bottom only in the RoI + // crossing only the top and bottom axes in the RoI { // (1): u_cross_top_min = uc + r cos(theta_u_top_min) < umin_roi ; vmin_roi = vc - r sin(theta_u_top_min) // (2): umin_roi = uc + r cos(theta_v_min); v_cross_min = vc - r sin(theta_v_min) <= vmin_roi @@ -1060,7 +1060,47 @@ int main() else { statusTest = "FAILED"; } - std::cout << "Test with intersections with the top, bottom and the left border, crossing top and bottom only in the RoI." << std::endl; + std::cout << "Test with intersections with the top, bottom and the left border, crossing only the top and bottom axes in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + + // Test with intersections with the top, bottom and the left border + // crossing only the left axis in the RoI + { + // (1): u_cross_top_min = uc + r cos(theta_u_top_min) < umin_roi ; vmin_roi = vc - r sin(theta_u_top_min) + // (2): umin_roi = uc + r cos(theta_v_min); v_cross_min = vc - r sin(theta_v_min) >= vmin_roi + // (3): u_cross_top_max = uc + r cos(theta_u_top_max) <= umin_roi ; vmin_roi = vc - r sin(theta_u_top_max) + // (4): umin_roi = uc + r cos(theta_v_max); v_cross_max = vc - r sin(theta_v_max) <= vmin_roi + height + // (5): u_cross_bot_min = uc + r cos(theta_u_bottom_min) < umin_roi ; vmin_roi + height = vc - r sin(theta_u_bottom_min) + // (6): u_cross_bot_max = uc + r cos(theta_u_bottom_max) <= umin_roi ; vmin_roi + height = vc - r sin(theta_u_bottom_max) + // (1) & (3) theta_u_top_min = PI - theta_u_top_max + // (2) & (4) theta_v_min = - theta_v_max + // (5) & (6) theta_u_bottom_min = PI - theta_u_bottom_max + float theta_u_top_min = M_PI_2; + float theta_u_top_max = M_PI - theta_u_top_min; + float theta_v_min = M_PI_4; + float theta_v_max = -theta_v_min; + float theta_u_bottom_min = -theta_u_top_min; + float theta_u_bottom_max = -theta_u_top_max; + float radius = HEIGHT / 2.f; + float vc = OFFSET + radius * std::sin(theta_u_top_min); + float uc = OFFSET - radius * std::cos(theta_v_min); + vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = (theta_v_min - theta_v_max) * radius; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the top, bottom and the left border, crossing only the left axis in the RoI." << std::endl; std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -1109,7 +1149,7 @@ int main() } // Test with intersections with the top, bottom and the right border - // crossing top and bottom only in the RoI + // crossing only the top and bottom axes in the RoI { // (1): u_cross_top_min = uc + r cos(theta_u_top_min) <= umin_roi + width ; vmin_roi = vc - r sin(theta_u_top_min) // (2): umin_roi + width = uc + r cos(theta_v_min); v_cross_min = vc - r sin(theta_v_min) <= vmin_roi @@ -1140,7 +1180,47 @@ int main() else { statusTest = "FAILED"; } - std::cout << "Test with intersections with the top, bottom and the right border, crossing top and bottom only in the RoI." << std::endl; + std::cout << "Test with intersections with the top, bottom and the right border, crossing only the top and bottom axes in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + + // Test with intersections with the top, bottom and the right border + // crossing only the right axis in the RoI + { + // (1): u_cross_top_min = uc + r cos(theta_u_top_min) >= umin_roi + width ; vmin_roi = vc - r sin(theta_u_top_min) + // (2): umin_roi + width = uc + r cos(theta_v_min); v_cross_min = vc - r sin(theta_v_min) >= vmin_roi + // (3): u_cross_top_max = uc + r cos(theta_u_top_max) > umin_roi + width ; vmin_roi = vc - r sin(theta_u_top_max) + // (4): umin_roi + width = uc + r cos(theta_v_max); v_cross_max = vc - r sin(theta_v_max) <= vmin_roi + height + // (5): u_cross_bot_min = uc + r cos(theta_u_bottom_min) >= umin_roi + width ; vmin_roi + height = vc - r sin(theta_u_bottom_min) + // (6): u_cross_bot_max = uc + r cos(theta_u_bottom_max) > umin_roi + width ; vmin_roi + height = vc - r sin(theta_u_bottom_max) + // (1) & (3) theta_u_top_min = PI - theta_u_top_max + // (2) & (4) theta_v_min = - theta_v_max + // (5) & (6) theta_u_bottom_min = PI - theta_u_bottom_max + float theta_u_top_min = M_PI_2; + float theta_u_top_max = M_PI - theta_u_top_min; + float theta_v_min = 3.f * M_PI_4; + float theta_v_max = -theta_v_min; + float theta_u_bottom_min = -theta_u_top_min; + float theta_u_bottom_max = -theta_u_top_max; + float radius = HEIGHT / 2.f; + float vc = OFFSET + radius * std::sin(theta_u_top_min); + float uc = OFFSET + WIDTH - radius * std::cos(theta_v_min); + vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = (2.f * M_PI - (theta_v_min - theta_v_max)) * radius; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the top, bottom and the right border, crossing only the right axis in the RoI." << std::endl; std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; From baf5b1657f5c9da7d36b1771905658369eacb3b2 Mon Sep 17 00:00:00 2001 From: rlagneau Date: Fri, 29 Sep 2023 15:51:07 +0200 Subject: [PATCH 13/22] [WIP] Added test for top/bottom/right and top/bottom/left where top and bottom are crossed and the third axis is touched --- .../test/tools/geometry/testImageCircle.cpp | 163 ++++++++++++++++-- 1 file changed, 152 insertions(+), 11 deletions(-) diff --git a/modules/core/test/tools/geometry/testImageCircle.cpp b/modules/core/test/tools/geometry/testImageCircle.cpp index e09df6207c..1f4a28447f 100644 --- a/modules/core/test/tools/geometry/testImageCircle.cpp +++ b/modules/core/test/tools/geometry/testImageCircle.cpp @@ -1043,8 +1043,6 @@ int main() float theta_u_top_max = M_PI / 6.f; float theta_u_top_min = M_PI - theta_u_top_max; float theta_v_min = M_PI / 3.f; - float theta_v_max = -theta_v_min; - float theta_u_bottom_min = -theta_u_top_min; float theta_u_bottom_max = -theta_u_top_max; float radius = HEIGHT; float vc = OFFSET + radius * std::sin(theta_u_top_min); @@ -1068,6 +1066,45 @@ int main() hasSucceeded &= isValueOK; } + // Test with intersections with the top, bottom and the left border + // crossing the top and bottom axes and touching the left axis in the RoI + { + // (1): u_cross_top_min = uc + r cos(theta_u_top_min) >= umin_roi ; vmin_roi = vc - r sin(theta_u_top_min) + // (2): umin_roi = uc + r cos(theta_v_min); v_cross_min = vc - r sin(theta_v_min) >= vmin_roi && v_cross_min <= vmin_roi + height + // (3): u_cross_top_max = uc + r cos(theta_u_top_max) >= umin_roi ; vmin_roi = vc - r sin(theta_u_top_max) + // (4): umin_roi = uc + r cos(theta_v_max); v_cross_max = v_cross_min + // (5): u_cross_bot_min = uc + r cos(theta_u_bottom_min) >= umin_roi ; vmin_roi + height = vc - r sin(theta_u_bottom_min) + // (6): u_cross_bot_max = uc + r cos(theta_u_bottom_max) >= umin_roi ; vmin_roi + height = vc - r sin(theta_u_bottom_max) + // (1) & (3) theta_u_top_min = PI - theta_u_top_max + // (2) & (4) theta_v_min = - theta_v_max + // (5) & (6) theta_u_bottom_min = PI - theta_u_bottom_max + float theta_u_top_min = 4.f * M_PI / 6.f; + float theta_u_top_max = M_PI - theta_u_top_min; + float theta_v_min = M_PI; + float theta_u_bottom_min = -theta_u_top_min; + float theta_u_bottom_max = -theta_u_top_max; + float radius = HEIGHT / (2.f * std::sin(theta_u_top_min)); // vmin + h - vmin = (vc - r sin(-theta_u_top_min)) - (vc - r sin(theta_top_min)) + float vc = OFFSET + radius * std::sin(theta_u_top_min); + float uc = OFFSET - radius * std::cos(theta_v_min); + vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = (2.f * M_PI - ((theta_u_top_min - theta_u_top_max) + (theta_u_bottom_max - theta_u_bottom_min))) * radius; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the top, bottom and the left border, crossing the top and bottom axes and touching the left axis in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + // Test with intersections with the top, bottom and the left border // crossing only the left axis in the RoI { @@ -1081,11 +1118,8 @@ int main() // (2) & (4) theta_v_min = - theta_v_max // (5) & (6) theta_u_bottom_min = PI - theta_u_bottom_max float theta_u_top_min = M_PI_2; - float theta_u_top_max = M_PI - theta_u_top_min; float theta_v_min = M_PI_4; float theta_v_max = -theta_v_min; - float theta_u_bottom_min = -theta_u_top_min; - float theta_u_bottom_max = -theta_u_top_max; float radius = HEIGHT / 2.f; float vc = OFFSET + radius * std::sin(theta_u_top_min); float uc = OFFSET - radius * std::cos(theta_v_min); @@ -1108,6 +1142,43 @@ int main() hasSucceeded &= isValueOK; } + // Test with intersections with the top, bottom and the left border + // crossing the left axis and touching the two others in the RoI + { + // (1): u_cross_top_min = uc + r cos(theta_u_top_min) >= umin_roi ; vmin_roi = vc - r sin(theta_u_top_min) + // (2): umin_roi = uc + r cos(theta_v_min); v_cross_min = vc - r sin(theta_v_min) >= vmin_roi + // (3): u_cross_top_max = uc + r cos(theta_u_top_max) >= umin_roi ; vmin_roi = vc - r sin(theta_u_top_max) + // (4): umin_roi = uc + r cos(theta_v_max); v_cross_max = vc - r sin(theta_v_max) <= vmin_roi + height + // (5): u_cross_bot_min = uc + r cos(theta_u_bottom_min) >= umin_roi ; vmin_roi + height = vc - r sin(theta_u_bottom_min) + // (6): u_cross_bot_max = uc + r cos(theta_u_bottom_max) >= umin_roi ; vmin_roi + height = vc - r sin(theta_u_bottom_max) + // (1) & (3) theta_u_top_min = PI - theta_u_top_max + // (2) & (4) theta_v_min = - theta_v_max + // (5) & (6) theta_u_bottom_min = PI - theta_u_bottom_max + float theta_u_top_min = M_PI_2; + float theta_v_min = 3.f * M_PI_4; + float theta_v_max = -theta_v_min; + float radius = HEIGHT / 2.f; + float vc = OFFSET + radius * std::sin(theta_u_top_min); + float uc = OFFSET - radius * std::cos(theta_v_min); + vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = (theta_v_min - theta_v_max) * radius; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the top, bottom and the left border, crossing the left axis and touching the two others in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + // Test with intersections with the top, bottom and the right border // crossing each axis twice in the RoI { @@ -1161,11 +1232,8 @@ int main() // (2) & (4) theta_v_min = - theta_v_max // (5) & (6) theta_u_bottom_min = PI - theta_u_bottom_max float theta_u_top_min = 5.f * M_PI / 6.f; - float theta_u_top_max = M_PI - theta_u_top_min; float theta_v_min = 2.f * M_PI / 3.f; - float theta_v_max = -theta_v_min; float theta_u_bottom_min = -theta_u_top_min; - float theta_u_bottom_max = -theta_u_top_max; float radius = HEIGHT; float vc = OFFSET + radius * std::sin(theta_u_top_min); float uc = OFFSET + WIDTH - radius * std::cos(theta_v_min); @@ -1188,6 +1256,45 @@ int main() hasSucceeded &= isValueOK; } + // Test with intersections with the top, bottom and the right border + // crossing the top and bottom axes and touching the right axis in the RoI + { + // (1): u_cross_top_min = uc + r cos(theta_u_top_min) < umin_roi + width ; vmin_roi = vc - r sin(theta_u_top_min) + // (2): umin_roi + width = uc + r cos(theta_v_min); v_cross_min = vc - r sin(theta_v_min) >= vmin_roi && <= vmin_roi + height + // (3): u_cross_top_max = uc + r cos(theta_u_top_max) <= umin_roi + width ; vmin_roi = vc - r sin(theta_u_top_max) + // (4): umin_roi + width = uc + r cos(theta_v_max); v_cross_max = v_cross_min + // (5): u_cross_bot_min = uc + r cos(theta_u_bottom_min) < umin_roi ; vmin_roi + height = vc - r sin(theta_u_bottom_min) + // (6): u_cross_bot_max = uc + r cos(theta_u_bottom_max) <= umin_roi ; vmin_roi + height = vc - r sin(theta_u_bottom_max) + // (1) & (3) theta_u_top_min = PI - theta_u_top_max + // (2) & (4) theta_v_min = - theta_v_max + // (5) & (6) theta_u_bottom_min = PI - theta_u_bottom_max + float theta_u_top_min = 4.f * M_PI / 6.f; + float theta_u_top_max = M_PI - theta_u_top_min; + float theta_v_min = 0; + float theta_u_bottom_min = -theta_u_top_min; + float theta_u_bottom_max = -theta_u_top_max; + float radius = HEIGHT / (2.f * std::sin(theta_u_top_min)); // vmin + h - vmin = (vc - r sin(-theta_u_top_min)) - (vc - r sin(theta_top_min)) + float vc = OFFSET + radius * std::sin(theta_u_top_min); + float uc = OFFSET + WIDTH - radius * std::cos(theta_v_min); + vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = (2.f * M_PI - ((theta_u_top_min - theta_u_top_max) + (theta_u_bottom_max - theta_u_bottom_min))) * radius; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the top, bottom and the right border, crossing the top and bottom axes and touching the right axis in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + // Test with intersections with the top, bottom and the right border // crossing only the right axis in the RoI { @@ -1201,11 +1308,8 @@ int main() // (2) & (4) theta_v_min = - theta_v_max // (5) & (6) theta_u_bottom_min = PI - theta_u_bottom_max float theta_u_top_min = M_PI_2; - float theta_u_top_max = M_PI - theta_u_top_min; float theta_v_min = 3.f * M_PI_4; float theta_v_max = -theta_v_min; - float theta_u_bottom_min = -theta_u_top_min; - float theta_u_bottom_max = -theta_u_top_max; float radius = HEIGHT / 2.f; float vc = OFFSET + radius * std::sin(theta_u_top_min); float uc = OFFSET + WIDTH - radius * std::cos(theta_v_min); @@ -1228,6 +1332,43 @@ int main() hasSucceeded &= isValueOK; } + // Test with intersections with the top, bottom and the right border + // crossing the right axis and touching the two others in the RoI + { + // (1): u_cross_top_min = uc + r cos(theta_u_top_min) <= umin_roi + width ; vmin_roi = vc - r sin(theta_u_top_min) + // (2): umin_roi + width = uc + r cos(theta_v_min); v_cross_min = vc - r sin(theta_v_min) >= vmin_roi + // (3): u_cross_top_max = uc + r cos(theta_u_top_max) <= umin_roi + width ; vmin_roi = vc - r sin(theta_u_top_max) + // (4): umin_roi + width = uc + r cos(theta_v_max); v_cross_max = vc - r sin(theta_v_max) <= vmin_roi + height + // (5): u_cross_bot_min = uc + r cos(theta_u_bottom_min) <= umin_roi + width ; vmin_roi + height = vc - r sin(theta_u_bottom_min) + // (6): u_cross_bot_max = uc + r cos(theta_u_bottom_max) <= umin_roi + width ; vmin_roi + height = vc - r sin(theta_u_bottom_max) + // (1) & (3) theta_u_top_min = PI - theta_u_top_max + // (2) & (4) theta_v_min = - theta_v_max + // (5) & (6) theta_u_bottom_min = PI - theta_u_bottom_max + float theta_u_top_min = M_PI_2; + float theta_v_min = M_PI_4; + float theta_v_max = -theta_v_min; + float radius = HEIGHT / 2.f; + float vc = OFFSET + radius * std::sin(theta_u_top_min); + float uc = OFFSET + WIDTH - radius * std::cos(theta_v_min); + vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = (2.f * M_PI - (theta_v_min - theta_v_max)) * radius; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the top, bottom and the right border, crossing the right axis and touching the two others in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + // Test with intersections with the top and bottom only, // crossing each axis twice in the RoI { From ecc391acca7a351fe09ab389e18144c404b6a2d2 Mon Sep 17 00:00:00 2001 From: rlagneau Date: Fri, 29 Sep 2023 16:54:27 +0200 Subject: [PATCH 14/22] [WIP] Added tests for top/bottom/left and top/bottom/right where the top + the lateral axes are crossed once and the bottom one is not crossed in the RoI --- .../test/tools/geometry/testImageCircle.cpp | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/modules/core/test/tools/geometry/testImageCircle.cpp b/modules/core/test/tools/geometry/testImageCircle.cpp index 1f4a28447f..4098998aa5 100644 --- a/modules/core/test/tools/geometry/testImageCircle.cpp +++ b/modules/core/test/tools/geometry/testImageCircle.cpp @@ -1179,6 +1179,43 @@ int main() hasSucceeded &= isValueOK; } + // Test with intersections with the top, bottom and the left border + // crossing only the top and left axes once in the RoI + { + // (1): u_cross_top_min = uc + r cos(theta_u_top_min) < umin_roi ; vmin_roi = vc - r sin(theta_u_top_min) + // (2): umin_roi = uc + r cos(theta_v_min); v_cross_min = vc - r sin(theta_v_min) < vmin_roi + // (3): u_cross_top_max = uc + r cos(theta_u_top_max) > umin_roi ; vmin_roi = vc - r sin(theta_u_top_max) + // (4): umin_roi = uc + r cos(theta_v_max); v_cross_max = vc - r sin(theta_v_max) > & && <= vmin_roi + height + // (5): u_cross_bot_min = uc + r cos(theta_u_bottom_min) < umin_roi ; vmin_roi + height = vc - r sin(theta_u_bottom_min) + // (6): u_cross_bot_max = uc + r cos(theta_u_bottom_max) < umin_roi ; vmin_roi + height = vc - r sin(theta_u_bottom_max) + // (1) & (3) theta_u_top_min = PI - theta_u_top_max + // (2) & (4) theta_v_min = - theta_v_max + // (5) & (6) theta_u_bottom_min = PI - theta_u_bottom_max + float theta_u_top_max = 0.f; + float theta_u_bot_max = -M_PI / 3.f; + float theta_v_max = -M_PI / 6.f; + float radius = HEIGHT / (std::sin(theta_u_top_max) - std::sin(theta_u_bot_max)); + float uc = OFFSET - radius * std::cos(theta_v_max); + float vc = OFFSET + radius * std::sin(theta_u_top_max); + vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = (theta_u_top_max - theta_v_max) * radius; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the top, bottom and the left border, crossing only the top and left axes once in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + // Test with intersections with the top, bottom and the right border // crossing each axis twice in the RoI { @@ -1369,6 +1406,43 @@ int main() hasSucceeded &= isValueOK; } + // Test with intersections with the top, bottom and the right border + // crossing the top and right axis once in the RoI + { + // (1): u_cross_top_min = uc + r cos(theta_u_top_min) <= umin_roi + width ; vmin_roi = vc - r sin(theta_u_top_min) + // (2): umin_roi + width = uc + r cos(theta_v_min); v_cross_min = vc - r sin(theta_v_min) >= vmin_roi + // (3): u_cross_top_max = uc + r cos(theta_u_top_max) <= umin_roi + width ; vmin_roi = vc - r sin(theta_u_top_max) + // (4): umin_roi + width = uc + r cos(theta_v_max); v_cross_max = vc - r sin(theta_v_max) <= vmin_roi + height + // (5): u_cross_bot_min = uc + r cos(theta_u_bottom_min) <= umin_roi + width ; vmin_roi + height = vc - r sin(theta_u_bottom_min) + // (6): u_cross_bot_max = uc + r cos(theta_u_bottom_max) <= umin_roi + width ; vmin_roi + height = vc - r sin(theta_u_bottom_max) + // (1) & (3) theta_u_top_min = PI - theta_u_top_max + // (2) & (4) theta_v_min = - theta_v_max + // (5) & (6) theta_u_bottom_min = PI - theta_u_bottom_max + float theta_u_top_min = M_PI; + float theta_u_bot_min = -2.f * M_PI / 3.f; + float theta_v_max = -5.f * M_PI / 6.f; + float radius = HEIGHT / (std::sin(theta_u_top_min) - std::sin(theta_u_bot_min)); + float uc = OFFSET + WIDTH - radius * std::cos(theta_v_max); + float vc = OFFSET + radius * std::sin(theta_u_top_min); + vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = (2.f * M_PI - (theta_u_top_min - theta_v_max)) * radius; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the top, bottom and the right border, crossing the top and right axis once in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + // Test with intersections with the top and bottom only, // crossing each axis twice in the RoI { From 201575c5f4e979b0cf06786d66921fe139f0c83a Mon Sep 17 00:00:00 2001 From: rlagneau Date: Mon, 2 Oct 2023 07:52:55 +0200 Subject: [PATCH 15/22] [TEST] Added tests for bottom/top/right and bottom/top/left for cases where the circle intersects the only the bottom and lateral side, once each --- .../test/tools/geometry/testImageCircle.cpp | 82 ++++++++++++++++++- 1 file changed, 78 insertions(+), 4 deletions(-) diff --git a/modules/core/test/tools/geometry/testImageCircle.cpp b/modules/core/test/tools/geometry/testImageCircle.cpp index 4098998aa5..8d4346a5fe 100644 --- a/modules/core/test/tools/geometry/testImageCircle.cpp +++ b/modules/core/test/tools/geometry/testImageCircle.cpp @@ -1216,6 +1216,43 @@ int main() hasSucceeded &= isValueOK; } + // Test with intersections with the top, bottom and the left border + // crossing the bottom and left axis once in the RoI + { + // (1): u_cross_top_min = uc + r cos(theta_u_top_min) <= umin_roi ; vmin_roi = vc - r sin(theta_u_top_min) + // (2): umin_roi = uc + r cos(theta_v_min); v_cross_min = vc - r sin(theta_v_min) >= vmin_roi + // (3): u_cross_top_max = uc + r cos(theta_u_top_max) >= umin_roi ; vmin_roi = vc - r sin(theta_u_top_max) + // (4): umin_roi = uc + r cos(theta_v_max); v_cross_max = vc - r sin(theta_v_max) >= vmin_roi + height + // (5): u_cross_bot_min = uc + r cos(theta_u_bottom_min) <= umin_roi ; vmin_roi + height = vc - r sin(theta_u_bottom_min) + // (6): u_cross_bot_max = uc + r cos(theta_u_bottom_max) >= umin_roi ; vmin_roi + height = vc - r sin(theta_u_bottom_max) + // (1) & (3) theta_u_top_min = PI - theta_u_top_max + // (2) & (4) theta_v_min = - theta_v_max + // (5) & (6) theta_u_bottom_min = PI - theta_u_bottom_max + float theta_u_top_max = M_PI / 3.f; + float theta_u_bot_max = 0.f; + float theta_v_min = M_PI / 6.f; + float radius = HEIGHT / (std::sin(theta_u_top_max) - std::sin(theta_u_bot_max)); + float uc = OFFSET - radius * std::cos(theta_v_min); + float vc = OFFSET + radius * std::sin(theta_u_top_max); + vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = (theta_v_min - theta_u_bot_max) * radius; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the top, bottom and the left border, crossing the bottom and left axis once in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + // Test with intersections with the top, bottom and the right border // crossing each axis twice in the RoI { @@ -1410,11 +1447,11 @@ int main() // crossing the top and right axis once in the RoI { // (1): u_cross_top_min = uc + r cos(theta_u_top_min) <= umin_roi + width ; vmin_roi = vc - r sin(theta_u_top_min) - // (2): umin_roi + width = uc + r cos(theta_v_min); v_cross_min = vc - r sin(theta_v_min) >= vmin_roi - // (3): u_cross_top_max = uc + r cos(theta_u_top_max) <= umin_roi + width ; vmin_roi = vc - r sin(theta_u_top_max) + // (2): umin_roi + width = uc + r cos(theta_v_min); v_cross_min = vc - r sin(theta_v_min) <= vmin_roi + // (3): u_cross_top_max = uc + r cos(theta_u_top_max) >= umin_roi + width ; vmin_roi = vc - r sin(theta_u_top_max) // (4): umin_roi + width = uc + r cos(theta_v_max); v_cross_max = vc - r sin(theta_v_max) <= vmin_roi + height - // (5): u_cross_bot_min = uc + r cos(theta_u_bottom_min) <= umin_roi + width ; vmin_roi + height = vc - r sin(theta_u_bottom_min) - // (6): u_cross_bot_max = uc + r cos(theta_u_bottom_max) <= umin_roi + width ; vmin_roi + height = vc - r sin(theta_u_bottom_max) + // (5): u_cross_bot_min = uc + r cos(theta_u_bottom_min) >= umin_roi + width ; vmin_roi + height = vc - r sin(theta_u_bottom_min) + // (6): u_cross_bot_max = uc + r cos(theta_u_bottom_max) > umin_roi + width ; vmin_roi + height = vc - r sin(theta_u_bottom_max) // (1) & (3) theta_u_top_min = PI - theta_u_top_max // (2) & (4) theta_v_min = - theta_v_max // (5) & (6) theta_u_bottom_min = PI - theta_u_bottom_max @@ -1443,6 +1480,43 @@ int main() hasSucceeded &= isValueOK; } + // Test with intersections with the top, bottom and the right border + // crossing the bottom and right axis once in the RoI + { + // (1): u_cross_top_min = uc + r cos(theta_u_top_min) >= umin_roi + width ; vmin_roi = vc - r sin(theta_u_top_min) + // (2): umin_roi + width = uc + r cos(theta_v_min); v_cross_min = vc - r sin(theta_v_min) >= vmin_roi + // (3): u_cross_top_max = uc + r cos(theta_u_top_max) >= umin_roi + width ; vmin_roi = vc - r sin(theta_u_top_max) + // (4): umin_roi + width = uc + r cos(theta_v_max); v_cross_max = vc - r sin(theta_v_max) >= vmin_roi + height + // (5): u_cross_bot_min = uc + r cos(theta_u_bottom_min) <= umin_roi + width ; vmin_roi + height = vc - r sin(theta_u_bottom_min) + // (6): u_cross_bot_max = uc + r cos(theta_u_bottom_max) >= umin_roi + width ; vmin_roi + height = vc - r sin(theta_u_bottom_max) + // (1) & (3) theta_u_top_min = PI - theta_u_top_max + // (2) & (4) theta_v_min = - theta_v_max + // (5) & (6) theta_u_bottom_min = PI - theta_u_bottom_max + float theta_u_top_min = 2.f * M_PI / 3.f; + float theta_u_bot_min = M_PI; + float theta_v_min = 5.f * M_PI / 6.f; + float radius = HEIGHT / (std::sin(theta_u_top_min) - std::sin(theta_u_bot_min)); + float uc = OFFSET + WIDTH - radius * std::cos(theta_v_min); + float vc = OFFSET + radius * std::sin(theta_u_top_min); + vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); + float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + float theoreticalValue = (theta_u_bot_min - theta_v_min) * radius; + bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the top, bottom and the right border, crossing the bottom and right axis once in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + // Test with intersections with the top and bottom only, // crossing each axis twice in the RoI { From 07ea84580f6aa3f8d98d9b7b49a77d6ff7d68d6e Mon Sep 17 00:00:00 2001 From: rlagneau Date: Mon, 2 Oct 2023 08:52:03 +0200 Subject: [PATCH 16/22] [TEST] Made homogeneity in the notation of the tests --- .../test/tools/geometry/testImageCircle.cpp | 473 +++++++++--------- 1 file changed, 236 insertions(+), 237 deletions(-) diff --git a/modules/core/test/tools/geometry/testImageCircle.cpp b/modules/core/test/tools/geometry/testImageCircle.cpp index 8d4346a5fe..2903d3741f 100644 --- a/modules/core/test/tools/geometry/testImageCircle.cpp +++ b/modules/core/test/tools/geometry/testImageCircle.cpp @@ -111,6 +111,7 @@ int main() // Test with intersections with the left border, more than half a circle visible { // Formula: uc = OFFSET - RADIUS * cos(theta) + // theta := 2 * PI / 3 float uc = OFFSET + 24.f; float vc = OFFSET + 100.f; vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); @@ -135,6 +136,7 @@ int main() // Test with intersections with the left border, less than half a circle visible { // Formula: uc = OFFSET - RADIUS * cos(theta) + // theta := PI / 3 float uc = OFFSET - 24.f; float vc = OFFSET + 100.f; vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); @@ -159,6 +161,7 @@ int main() // Test with circle touching the left border, all the circle is visible { // Formula: uc = OFFSET - RADIUS * cos(theta) + // theta := PI float uc = OFFSET + RADIUS; float vc = OFFSET + 100.f; vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); @@ -183,6 +186,7 @@ int main() // Test with intersections with the right border, more than half a circle visible { // Formula: uc = OFFSET + WIDTH - RADIUS * cos(theta) + // theta := PI / 3 float uc = OFFSET + 616.f; float vc = OFFSET + 100.f; vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); @@ -207,6 +211,7 @@ int main() // Test with intersections with the right border, less than half a circle visible { // Formula: uc = OFFSET + WIDTH - RADIUS * cos(theta) + // theta := 2 * PI / 3 float uc = OFFSET + 664.f; float vc = OFFSET + 100.f; vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); @@ -231,6 +236,7 @@ int main() // Test with circle touching the right border, all the circle is visible { // Formula: uc = OFFSET + WIDTH - RADIUS * cos(theta) + // theta := 0 float uc = OFFSET + WIDTH - RADIUS; float vc = OFFSET + 100.f; vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); @@ -408,10 +414,10 @@ int main() // Test with intersections with the top and the left border, crossing each axis once in the RoI { - // Formula: u1 = uc + r cos (theta1) ; vmin = vc - r sin(theta1) - // Formula: umin = uc + r cos(theta 2) ; v = vc - r sin(theta2) - // Choice: theta1 - theta2 = pi / 2 => for theta1 = 0 theta2 = -pi/2 - // => uc = umin - r cos(theta2) vc = vmin + r sin(theta1) + // Formula: u_cross_top_max = uc + r cos (theta_u_top_max) >= umin ; vmin = vc - r sin(theta_u_top_max) + // Formula: umin = uc + r cos(theta_v_max) ; v = vc - r sin(theta_v_max) >= vmin + // Choice: theta_u_top_max - theta_v_max = pi / 2 => for theta_u_top_max = 0 theta_v_max = -pi/2 + // => uc = umin - r cos(theta_v_max) vc = vmin + r sin(theta_u_top_max) float uc = OFFSET; float vc = OFFSET; vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); @@ -436,16 +442,16 @@ int main() // Test with intersections with the top and the left border // but crossing only the left axis in the RoI { - // (1): u1 = uc + rcos(theta1) <= umin ; vmin = vc - r sin(theta1) - // (2): u2 = uc + rcos(theta2) <= umin ; vmin = vc - r sin(theta2) - // (3): umin = uc + r cos(theta3) ; v3 = vc - r sin(theta3) - // (4): umin = uc + r cos(theta4) ; v4 = vc - r sin(theta4) - // (3) & (4) => uc = umin - r cos(theta3) = umin - r cos(theta4) <=> theta3 = - theta4 - // (3) & (4) => vc >= vmin + r sin(theta3) && vc >= vmin + r sin (theta4) - float theta = M_PI / 4.f; - float uc = OFFSET - RADIUS * std::cos(theta); - float vc = OFFSET + RADIUS * std::sin(theta) + 1.f; - vc = std::max(vc, OFFSET + RADIUS * std::sin(-theta) + 1.f); + // (1): u_cross_top_min = uc + rcos(theta_u_top_min) <= umin ; vmin = vc - r sin(theta_u_top_min) + // (2): u_cross_top_max = uc + rcos(theta_u_top_max) <= umin ; vmin = vc - r sin(theta_u_top_max) + // (3): umin = uc + r cos(theta_v_min) ; v_cross_min = vc - r sin(theta_v_min) >= vmin && <= vmin + height + // (4): umin = uc + r cos(theta_v_max) ; v_cross_max = vc - r sin(theta_v_max) >= vmin && <= vmin + height + // (3) & (4) => uc = umin - r cos(theta_v_min) = umin - r cos(theta_v_max) <=> theta_v_min = - theta_v_max + // (3) & (4) => vc >= vmin + r sin(theta_v_min) && vc >= vmin + r sin (theta_v_max) + float theta_v_min = M_PI / 4.f; + float uc = OFFSET - RADIUS * std::cos(theta_v_min); + float vc = OFFSET + RADIUS * std::sin(theta_v_min) + 1.f; + vc = std::max(vc, OFFSET + RADIUS * std::sin(-theta_v_min) + 1.f); vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); float theoreticalValue = M_PI_2 * RADIUS; @@ -468,18 +474,18 @@ int main() // Test with intersections with the top and the left border // but crossing only the top axis in the RoI { - // (1): u1 = uc + rcos(theta1) >= umin ; vmin = vc - r sin(theta1) - // (2): u2 = uc + rcos(theta2) >= umin ; vmin = vc - r sin(theta2) - // (3): umin = uc + r cos(theta3) ; v3 = vc - r sin(theta3) <= vmin - // (4): umin = uc + r cos(theta4) ; v4 = vc - r sin(theta4) <= vmin - // (1) & (2) => vmin = vc - r sin (theta1) = vc - r sin(theta2) <=> theta1 = PI - theta2 - // (1) => uc + r cos(theta1) >= umin <=> uc >= umin - r cos(theta1) - // (2) => uc + r cos(theta2) >= umin <=> uc >= umin - r cos(theta2) - - float theta = -1.1f * M_PI_2; - float uc = OFFSET - RADIUS * std::cos(theta) + 1.f; - uc = std::max(uc, OFFSET - RADIUS * std::cos((float)M_PI - theta) + 1.f); - float vc = OFFSET + RADIUS * std::sin(theta); + // (1): u_cross_top_min = uc + rcos(theta_u_top_min) >= umin ; vmin = vc - r sin(theta_u_top_min) + // (2): u_cross_top_max = uc + rcos(theta_u_top_max) >= umin ; vmin = vc - r sin(theta_u_top_max) + // (3): umin = uc + r cos(theta_v_min) ; v_cross_min = vc - r sin(theta_v_min) <= vmin + // (4): umin = uc + r cos(theta_v_max) ; v_cross_max = vc - r sin(theta_v_max) <= vmin + // (1) & (2) => vmin = vc - r sin (theta_u_top_min) = vc - r sin(theta_u_top_max) <=> theta_u_top_min = PI - theta_u_top_max + // (1) => uc + r cos(theta_u_top_min) >= umin <=> uc >= umin - r cos(theta_u_top_min) + // (2) => uc + r cos(theta_u_top_max) >= umin <=> uc >= umin - r cos(theta_u_top_max) + + float theta_u_top_min = -1.1f * M_PI_2; + float uc = OFFSET - RADIUS * std::cos(theta_u_top_min) + 1.f; + uc = std::max(uc, OFFSET - RADIUS * std::cos((float)M_PI - theta_u_top_min) + 1.f); + float vc = OFFSET + RADIUS * std::sin(theta_u_top_min); vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); float theoreticalValue = 0.2f * M_PI_2 * RADIUS; @@ -502,32 +508,32 @@ int main() // Test with intersections with the top and the left border // crossing twice each axis { - // (1): u1 = uc + r cos(theta1) >= umin ; vmin = vc - r sin(theta1) - // (2): u2 = uc + r cos(theta2) >= umin ; vmin = vc - r sin(theta2) - // (3): umin = uc + r cos(theta3) ; v3 = vc - r sin(theta3) >= vmin - // (4): umin = uc + r cos(theta4) ; v4 = vc - r sin(theta4) >= vmin - // (1) & (2) => vmin = vc - r sin(theta1) = vc - r sin(theta2) <=> theta1 = PI - theta2 - // (1) & (2) =>{ uc >= umin - r cos(theta1) & { uc >= umin - r cos(PI - theta1) - // (1) & (2) { vc = vmin + r sin(theta1) & { vc = vmin + r sin(PI - theta1) - // (3) & (4) =>{ uc = umin - r cos(theta3) & { uc = umin - r cos( - theta3) - // (3) & (4) { vc >= vmin - r sin(theta3) & { vc >= vmin - r cos( - theta3) - - float theta1 = 5.f * M_PI / 8.f; - float theta2 = M_PI - theta1; - float uc = OFFSET - RADIUS * std::cos(theta1) + 1.f; - uc = std::max(uc, OFFSET - RADIUS * std::cos((float)M_PI - theta1) + 1.f); - float vc = OFFSET + RADIUS * std::sin(theta1); - float theta3 = std::acos((OFFSET - uc)/RADIUS); - theta3 = ensureIsBetweenMinPiAndPi(theta3); - float theta4 = -theta3; - if (theta4 < 0) { - float temp = theta4; - theta4 = theta3; - theta3 = temp; + // (1): u_cross_top_min = uc + r cos(theta_u_top_min) >= umin ; vmin = vc - r sin(theta_u_top_min) + // (2): u_cross_top_max = uc + r cos(theta_u_top_max) >= umin ; vmin = vc - r sin(theta_u_top_max) + // (3): umin = uc + r cos(theta_v_min) ; v_cross_min = vc - r sin(theta_v_min) >= vmin + // (4): umin = uc + r cos(theta_v_max) ; v_cross_max = vc - r sin(theta_v_max) >= vmin + // (1) & (2) => vmin = vc - r sin(theta_u_top_min) = vc - r sin(theta_u_top_max) <=> theta_u_top_min = PI - theta_u_top_max + // (1) & (2) =>{ uc >= umin - r cos(theta_u_top_min) & { uc >= umin - r cos(PI - theta_u_top_min) + // (1) & (2) { vc = vmin + r sin(theta_u_top_min) & { vc = vmin + r sin(PI - theta_u_top_min) + // (3) & (4) =>{ uc = umin - r cos(theta_v_min) & { uc = umin - r cos(- theta_v_min) + // (3) & (4) { vc >= vmin - r sin(theta_v_min) & { vc >= vmin - r cos(- theta_v_min) + + float theta_u_top_min = 5.f * M_PI / 8.f; + float theta_u_top_max = M_PI - theta_u_top_min; + float uc = OFFSET - RADIUS * std::cos(theta_u_top_min) + 1.f; + uc = std::max(uc, OFFSET - RADIUS * std::cos((float)M_PI - theta_u_top_min) + 1.f); + float vc = OFFSET + RADIUS * std::sin(theta_u_top_min); + float theta_v_min = std::acos((OFFSET - uc)/RADIUS); + theta_v_min = ensureIsBetweenMinPiAndPi(theta_v_min); + float theta_v_max = -theta_v_min; + if (theta_v_max < 0) { + float temp = theta_v_max; + theta_v_max = theta_v_min; + theta_v_min = temp; } vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); - float theoreticalValue = ((theta4 - theta1) + (theta2 - theta3)) * RADIUS; + float theoreticalValue = ((theta_v_max - theta_u_top_min) + (theta_u_top_max - theta_v_min)) * RADIUS; bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); std::string statusTest; if (isValueOK) { @@ -546,19 +552,19 @@ int main() // Test with intersections with the top and the right border, crossing each axis once in the RoI { - // (1): u1 = uc + r cos(theta1) ; vmin = vc - r sin(theta1) - // (2): umin + width = uc + r cos(theta2) ; v = vc - r sin(theta2) <= vmin - // (3): u3 = uc + r cos(theta3) >= umin + width ; vmin = vc - r sin(theta3) - // (4): umin + width = uc + r cos(theta4) ; v = vc - r sin(theta4) >= vmin - // Choice: for theta1 = 2PI/3 theta4 = -pi/2 - // (4) => uc = umin + width - r cos(theta4) - // (1) => vc = vmin + r sin(theta1) - // (1) & (3) theta1 = PI - theta3 - // (2) & (4) theta2 = - theta4 - float theta1 = 2.f * M_PI / 3.f; - float theta4 = -M_PI_2; - float uc = OFFSET + WIDTH - RADIUS * std::cos(theta4); - float vc = OFFSET + RADIUS * std::sin(theta1);; + // (1): u_cross_top_min = uc + r cos(theta_u_top_min) <= umin + width ; vmin = vc - r sin(theta_u_top_min) + // (2): umin + width = uc + r cos(theta_v_min) ; v_cross_min = vc - r sin(theta_v_min) <= vmin + // (3): u_cross_top_max = uc + r cos(theta_u_top_max) >= umin + width ; vmin = vc - r sin(theta_u_top_max) + // (4): umin + width = uc + r cos(theta_v_max) ; v_cross_max = vc - r sin(theta_v_max) >= vmin + // Choice: for theta_u_top_min = 2PI/3 theta_v_max = -pi/2 + // (4) => uc = umin + width - r cos(theta_v_max) + // (1) => vc = vmin + r sin(theta_u_top_min) + // (1) & (3) theta_u_top_min = PI - theta_u_top_max + // (2) & (4) theta_v_min = - theta_v_max + float theta_u_top_min = 2.f * M_PI / 3.f; + float theta_v_max = -M_PI_2; + float uc = OFFSET + WIDTH - RADIUS * std::cos(theta_v_max); + float vc = OFFSET + RADIUS * std::sin(theta_u_top_min);; vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); float theoreticalValue = (M_PI_2 + M_PI / 3.f) * RADIUS; @@ -581,29 +587,22 @@ int main() // Test with intersections with the top and the right border, // but crossing only the right border in the RoI { - // (1): u1 = uc + r cos(theta1) >= umin + width ; vmin = vc - r sin(theta1) - // (2): umin + width = uc + r cos(theta2) ; v = vc - r sin(theta2) >= vmin - // (3): u3 = uc + r cos(theta3) >= umin + width ; vmin = vc - r sin(theta3) - // (4): umin + width = uc + r cos(theta4) ; v = vc - r sin(theta4) >= vmin - // (4) => uc = umin + width - r cos(theta4) - // (1) => theta1 = asin((vc - vmin)/r) & uc + r cos(theta1) >= umin + width <=> uc + r cos[asin((vc - vmin)/r)] >= umin + width + // (1): u_cross_top_min = uc + r cos(theta_u_top_min) >= umin + width ; vmin = vc - r sin(theta_u_top_min) + // (2): umin + width = uc + r cos(theta_v_min) ; v_cross_min = vc - r sin(theta_v_min) >= vmin + // (3): u_cross_top_max = uc + r cos(theta_u_top_max) >= umin + width ; vmin = vc - r sin(theta_u_top_max) + // (4): umin + width = uc + r cos(theta_v_max) ; v_cross_max = vc - r sin(theta_v_max) >= vmin + // (4) => uc = umin + width - r cos(theta_v_max) + // (1) => theta_u_top_min = asin((vc - vmin)/r) & uc + r cos(theta_u_top_min) >= umin + width <=> uc + r cos[asin((vc - vmin)/r)] >= umin + width // (1) <=> asin((vc - vmin)/r) >= acos[(umin + width - uc)/r] <=> vc >= r sin(acos[(umin + width - uc)/r]) + vmin - // (1) & (3) theta1 = PI - theta3 - // (2) & (4) theta2 = - theta4 - float theta4 = -7.f * M_PI / 8.f; // -5.f * M_PI / 6.f; - float theta2 = -theta4; - float uc = OFFSET + WIDTH - RADIUS * std::cos(theta4); + // (1) & (3) theta_u_top_min = PI - theta_u_top_max + // (2) & (4) theta_v_min = - theta_v_max + float theta_v_max = -7.f * M_PI / 8.f; + float theta_v_min = -theta_v_max; + float uc = OFFSET + WIDTH - RADIUS * std::cos(theta_v_max); float vc = RADIUS * std::sin(std::acos((OFFSET + WIDTH - uc)/RADIUS)) + OFFSET + 1.f; - float theta1 = std::asin((vc - OFFSET) / RADIUS); - float theta3 = M_PI - theta1; - if (theta3 > theta1) { - float temp = theta3; - theta3 = theta1; - theta1 = temp; - } vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); - float theoreticalValue = (2.f * M_PI - (theta2 - theta4)) * RADIUS; + float theoreticalValue = (2.f * M_PI - (theta_v_min - theta_v_max)) * RADIUS; bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); std::string statusTest; if (isValueOK) { @@ -623,24 +622,24 @@ int main() // Test with intersections with the top and the right border, // but crossing only the top border in the RoI { - // (1): u1 = uc + r cos(theta1) <= umin + width ; vmin = vc - r sin(theta1) - // (2): umin + width = uc + r cos(theta2) ; v = vc - r sin(theta2) <= vmin - // (3): u3 = uc + r cos(theta3) <= umin + width ; vmin = vc - r sin(theta3) - // (4): umin + width = uc + r cos(theta4) ; v = vc - r sin(theta4) <= vmin - // (1) & (3) theta1 = PI - theta3 - // (2) & (4) theta2 = - theta4 - // Choice: theta1 = -0.9 * PI / 2 - // (1) => vc = vmin + r sin(theta1) - // (2) vc - r sin(theta2) <= vmin => asin((vc - vmin)/r) <= theta2 - float theta1 = -0.9f * M_PI_2; - float theta3 = M_PI - theta1; - theta3 = ensureIsBetweenMinPiAndPi(theta3); - float vc = OFFSET + RADIUS * std::sin(theta1); - float theta2 = std::asin((vc - OFFSET)/RADIUS) + 1.f; - float uc = OFFSET + WIDTH - RADIUS * std::cos(theta2); + // (1): u_cross_top_min = uc + r cos(theta_u_top_min) <= umin + width ; vmin = vc - r sin(theta_u_top_min) + // (2): umin + width = uc + r cos(theta_v_min) ; v_cross_min = vc - r sin(theta_v_min) <= vmin + // (3): u_cross_top_max = uc + r cos(theta_u_top_max) <= umin + width ; vmin = vc - r sin(theta_u_top_max) + // (4): umin + width = uc + r cos(theta_v_max) ; v_cross_max = vc - r sin(theta_v_max) <= vmin + // (1) & (3) theta_u_top_min = PI - theta_u_top_max + // (2) & (4) theta_v_min = - theta_v_max + // Choice: theta_u_top_min = -0.9 * PI / 2 + // (1) => vc = vmin + r sin(theta_u_top_min) + // (2) vc - r sin(theta_v_min) <= vmin => asin((vc - vmin)/r) <= theta_v_min + float theta_u_top_min = -0.9f * M_PI_2; + float theta_u_top_max = M_PI - theta_u_top_min; + theta_u_top_max = ensureIsBetweenMinPiAndPi(theta_u_top_max); + float vc = OFFSET + RADIUS * std::sin(theta_u_top_min); + float theta_v_min = std::asin((vc - OFFSET)/RADIUS) + 1.f; + float uc = OFFSET + WIDTH - RADIUS * std::cos(theta_v_min); vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); - float theoreticalValue = std::abs(theta1 - theta3) * RADIUS; + float theoreticalValue = std::abs(theta_u_top_min - theta_u_top_max) * RADIUS; bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); std::string statusTest; if (isValueOK) { @@ -660,32 +659,32 @@ int main() // Test with intersections with the top and the left border // crossing twice each axis { - // (1): u1 = uc + r cos(theta1) < umin + width ; vmin = vc - r sin(theta1) - // (2): umin + width = uc + r cos(theta2) ; v2 = vc - r sin(theta2) >= vmin - // (3): u3 = uc + r cos(theta3) <= umin + width; vmin = vc - r sin(theta3) - // (4): umin + width = uc + r cos(theta4) ; v4 = vc - r sin(theta4) > vmin - // (1) & (3) => vmin = vc - r sin(theta1) = vc - r sin(theta3) <=> theta1 = PI - theta3 - // (1) & (3) =>{ uc < umin + width - r cos(theta1) & { uc <= umin + width - r cos(PI - theta1) - // (1) & (3) { vc = vmin + r sin(theta1) & { vc = vmin + r sin(PI - theta1) - // (2) & (4) =>{ uc = umin - r cos(theta2) & { uc = umin - r cos( - theta2) - // (2) & (4) { vc >= vmin - r sin(theta2) & { vc >= vmin - r cos( - theta2) - - float theta1 = 5.f * M_PI / 8.f; - float theta3 = M_PI - theta1; - float uc = OFFSET + WIDTH - RADIUS * std::cos(theta1) - 1.f; - uc = std::min(uc, OFFSET + WIDTH - RADIUS * std::cos((float)M_PI - theta1) - 1.f); - float vc = OFFSET + RADIUS * std::sin(theta1); - float theta2 = std::acos((OFFSET + WIDTH - uc)/RADIUS); - theta2 = ensureIsBetweenMinPiAndPi(theta2); - float theta4 = -theta2; - if (theta2 < 0) { - float temp = theta2; - theta2 = theta2; - theta4 = temp; + // (1): u_cross_top_min = uc + r cos(theta_u_top_min) < umin + width ; vmin = vc - r sin(theta_u_top_min) + // (2): umin + width = uc + r cos(theta_v_min) ; v_cross_min = vc - r sin(theta_v_min) >= vmin + // (3): u_cross_top_miax = uc + r cos(theta_u_top_max) <= umin + width; vmin = vc - r sin(theta_u_top_max) + // (4): umin + width = uc + r cos(theta_v_max) ; v_cross_max = vc - r sin(theta_v_max) > vmin + // (1) & (3) => vmin = vc - r sin(theta_u_top_min) = vc - r sin(theta_u_top_max) <=> theta_u_top_min = PI - theta_u_top_max + // (1) & (3) =>{ uc < umin + width - r cos(theta_u_top_min) & { uc <= umin + width - r cos(PI - theta_u_top_min) + // (1) & (3) { vc = vmin + r sin(theta_u_top_min) & { vc = vmin + r sin(PI - theta_u_top_min) + // (2) & (4) =>{ uc = umin - r cos(theta_v_min) & { uc = umin - r cos(- theta_v_min) + // (2) & (4) { vc >= vmin - r sin(theta_v_min) & { vc >= vmin - r cos(- theta_v_min) + + float theta_u_top_min = 5.f * M_PI / 8.f; + float theta_u_top_max = M_PI - theta_u_top_min; + float uc = OFFSET + WIDTH - RADIUS * std::cos(theta_u_top_min) - 1.f; + uc = std::min(uc, OFFSET + WIDTH - RADIUS * std::cos((float)M_PI - theta_u_top_min) - 1.f); + float vc = OFFSET + RADIUS * std::sin(theta_u_top_min); + float theta_v_min = std::acos((OFFSET + WIDTH - uc)/RADIUS); + theta_v_min = ensureIsBetweenMinPiAndPi(theta_v_min); + float theta_v_max = -theta_v_min; + if (theta_v_min < 0) { + float temp = theta_v_min; + theta_v_min = theta_v_max; + theta_v_max = temp; } vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); - float theoreticalValue = (2.f * M_PI - ((theta1 - theta3) + (theta2 - theta4))) * RADIUS; + float theoreticalValue = (2.f * M_PI - ((theta_u_top_min - theta_u_top_max) + (theta_v_min - theta_v_max))) * RADIUS; bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); std::string statusTest; if (isValueOK) { @@ -696,7 +695,7 @@ int main() } std::cout << "Test with intersections with the top and the left border crossing twice each axis ." << std::endl; std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; - std::cout << "\ttheoretical length (2 PI - (" << theta1 << " - " << theta3 << ") + (" << theta2 << " - " << theta4 << ")) R = " << theoreticalValue << std::endl; + std::cout << "\ttheoretical length = " << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; hasSucceeded &= isValueOK; @@ -704,19 +703,19 @@ int main() // Test with intersections with the bottom and the left border, crossing each axis once in the RoI { - // (1): u1 = uc + r cos(theta1) <= umin ; vmin + height = vc - r sin(theta1) - // (2): umin = uc + r cos(theta2) ; v = vc - r sin(theta2) <= vmin + height - // (3): u3 = uc + r cos(theta3) >= umin ; vmin + height = vc - r sin(theta3) - // (4): umin = uc + r cos(theta4) ; v = vc - r sin(theta4) >= vmin + height - // Choice: for theta2 = PI/2 theta3 = -PI/3 - // (2) => uc = umin - r cos(theta2) - // (3) => vc = vmin + height + r sin(theta3) - // (1) & (3) theta1 = PI - theta3 - // (2) & (4) theta2 = - theta4 - float theta2 = M_PI_2; - float theta3 = -M_PI / 3.f; - float uc = OFFSET - RADIUS * std::cos(theta2); - float vc = OFFSET + HEIGHT + RADIUS * std::sin(theta3);; + // (1): u_cross_bot_min = uc + r cos(theta_u_bot_min) <= umin ; vmin + height = vc - r sin(theta_u_bot_min) + // (2): umin = uc + r cos(theta_v_min) ; v_cross_min = vc - r sin(theta_v_min) <= vmin + height + // (3): u_cross_bot_max = uc + r cos(theta_u_bot_max) >= umin ; vmin + height = vc - r sin(theta_u_bot_max) + // (4): umin = uc + r cos(theta_v_max) ; v_cross_max = vc - r sin(theta_v_max) >= vmin + height + // Choice: for theta_v_min = PI/2 theta_u_bot_max = -PI/3 + // (2) => uc = umin - r cos(theta_v_min) + // (3) => vc = vmin + height + r sin(theta_u_bot_max) + // (1) & (3) theta_u_bot_min = PI - theta_u_bot_max + // (2) & (4) theta_v_min = - theta_v_max + float theta_v_min = M_PI_2; + float theta_u_bot_max = -M_PI / 3.f; + float uc = OFFSET - RADIUS * std::cos(theta_v_min); + float vc = OFFSET + HEIGHT + RADIUS * std::sin(theta_u_bot_max);; vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); float theoreticalValue = (M_PI_2 + M_PI / 3.f) * RADIUS; @@ -739,23 +738,23 @@ int main() // Test with intersections with the bottom and the left border // but crossing only the left border in the RoI { - // (1): u1 = uc + r cos(theta1) <= umin ; vmin + height = vc - r sin(theta1) - // (2): umin = uc + r cos(theta2) ; v = vc - r sin(theta2) <= vmin + height - // (3): u3 = uc + r cos(theta3) <= umin ; vmin + height = vc - r sin(theta3) - // (4): umin = uc + r cos(theta4) ; v = vc - r sin(theta4) <= vmin + height - // Choice: for theta2 = PI/8 - // (2) => uc = umin - r cos(theta2) - // (2) => vc <= vmin + height + r sin(theta2) - // (4) => vc <= vmin + height + r sin(theta4) - // (1) & (3) theta1 = PI - theta3 - // (2) & (4) theta2 = - theta4 - float theta2 = M_PI_4 / 2.f; - float theta4 = -theta2; - float uc = OFFSET - RADIUS * std::cos(theta2); - float vc = std::min(OFFSET + HEIGHT + RADIUS * std::sin(theta2) - 1.f, OFFSET + HEIGHT + RADIUS * std::sin(theta4) - 1.f); + // (1): u_cross_bot_min = uc + r cos(theta_u_bot_min) <= umin ; vmin + height = vc - r sin(theta_u_bot_min) + // (2): umin = uc + r cos(theta_v_min) ; v_cross_min = vc - r sin(theta_v_min) <= vmin + height + // (3): u_cross_bot_max = uc + r cos(theta_u_bot_max) <= umin ; vmin + height = vc - r sin(theta_u_bot_max) + // (4): umin = uc + r cos(theta_v_max) ; v_cross_max = vc - r sin(theta_v_max) <= vmin + height + // Choice: for theta_v_min = PI/8 + // (2) => uc = umin - r cos(theta_v_min) + // (2) => vc <= vmin + height + r sin(theta_v_min) + // (4) => vc <= vmin + height + r sin(theta_v_max) + // (1) & (3) theta_u_bot_min = PI - theta_u_bot_max + // (2) & (4) theta_v_min = - theta_v_max + float theta_v_min = M_PI_4 / 2.f; + float theta_v_max = -theta_v_min; + float uc = OFFSET - RADIUS * std::cos(theta_v_min); + float vc = std::min(OFFSET + HEIGHT + RADIUS * std::sin(theta_v_min) - 1.f, OFFSET + HEIGHT + RADIUS * std::sin(theta_v_max) - 1.f); vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); - float theoreticalValue = (2.f * theta2) * RADIUS; + float theoreticalValue = (2.f * theta_v_min) * RADIUS; bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); std::string statusTest; if (isValueOK) { @@ -775,23 +774,23 @@ int main() // Test with intersections with the bottom and the left border // but crossing only the bottom border in the RoI { - // (1): u1 = uc + r cos(theta1) >= umin ; vmin + height = vc - r sin(theta1) - // (2): umin = uc + r cos(theta2) ; v = vc - r sin(theta2) >= vmin + height - // (3): u3 = uc + r cos(theta3) >= umin ; vmin + height = vc - r sin(theta3) - // (4): umin = uc + r cos(theta4) ; v = vc - r sin(theta4) >= vmin + height - // Choice: for theta1 = 5 PI/8 - // (1) => vc = vmin + height + r sin(theta1) - // (1) => uc >= umin - r cos(theta1) - // (1) => uc >= umin - r cos(theta3) - // (1) & (3) theta1 = PI - theta3 - // (2) & (4) theta2 = - theta4 - float theta1 = 5.f * M_PI_4 / 2.f; - float theta3 = M_PI - theta1; - float vc = OFFSET + HEIGHT + RADIUS * std::sin(theta1); - float uc = std::max(OFFSET - RADIUS * std::cos(theta1) + 1.f, OFFSET - RADIUS * std::cos(theta3) + 1.f); + // (1): u_cross_bot_min = uc + r cos(theta_u_bot_min) >= umin ; vmin + height = vc - r sin(theta_u_bot_min) + // (2): umin = uc + r cos(theta_v_min) ; v_cross_min = vc - r sin(theta_v_min) >= vmin + height + // (3): u_cross_bot_max = uc + r cos(theta_u_bot_max) >= umin ; vmin + height = vc - r sin(theta_u_bot_max) + // (4): umin = uc + r cos(theta_v_max) ; v_cross_max = vc - r sin(theta_v_max) >= vmin + height + // Choice: for theta_u_bot_min = 5 PI/8 + // (1) => vc = vmin + height + r sin(theta_u_bot_min) + // (1) => uc >= umin - r cos(theta_u_bot_min) + // (1) => uc >= umin - r cos(theta_u_bot_max) + // (1) & (3) theta_u_bot_min = PI - theta_u_bot_max + // (2) & (4) theta_v_min = - theta_v_max + float theta_u_bot_min = 5.f * M_PI_4 / 2.f; + float theta_u_bot_max = M_PI - theta_u_bot_min; + float vc = OFFSET + HEIGHT + RADIUS * std::sin(theta_u_bot_min); + float uc = std::max(OFFSET - RADIUS * std::cos(theta_u_bot_min) + 1.f, OFFSET - RADIUS * std::cos(theta_u_bot_max) + 1.f); vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); - float theoreticalValue = (theta1 - theta3) * RADIUS; + float theoreticalValue = (theta_u_bot_min - theta_u_bot_max) * RADIUS; bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); std::string statusTest; if (isValueOK) { @@ -811,26 +810,26 @@ int main() // Test with intersections with the bottom and the left border // crossing each axis twice in the RoI { - // (1): u1 = uc + r cos(theta1) >= umin ; vmin + height = vc - r sin(theta1) - // (2): umin = uc + r cos(theta2) ; v = vc - r sin(theta2) < vmin + height - // (3): u3 = uc + r cos(theta3) > umin ; vmin + height = vc - r sin(theta3) - // (4): umin = uc + r cos(theta4) ; v = vc - r sin(theta4) <= vmin + height - // (1) & (3) => uc >= umin - r cos(theta1) & uc > umin - r cos(theta3) - // (1) & (3) => vc = vmin + height + r sin(theta1) & vc = vmin + height + r sin(PI - theta1) - // (2) & (4) => uc = umin - r cos(theta2) & uc = umin - r cos(-theta2) - // (2) & (4) => vc < vmin + height + r sin(theta2) & vc < vmin + height + r sin(-theta2) - // (1) & (3) theta1 = PI - theta3 - // (2) & (4) theta2 = - theta4 - float theta1 = -5.f * M_PI / 8.f; - float theta3 = M_PI - theta1; - theta3 = ensureIsBetweenMinPiAndPi(theta3); - float theta2 = 7.f * M_PI / 8.f; - float theta4 = -theta2; - float vc = OFFSET + HEIGHT + RADIUS * std::sin(theta1); - float uc = OFFSET - RADIUS * std::cos(theta2); + // (1): u_cross_bot_min = uc + r cos(theta_u_bot_min) >= umin ; vmin + height = vc - r sin(theta_u_bot_min) + // (2): umin = uc + r cos(theta_v_min) ; v_cross_min = vc - r sin(theta_v_min) < vmin + height + // (3): u_cross_bot_max = uc + r cos(theta_u_bot_max) > umin ; vmin + height = vc - r sin(theta_u_bot_max) + // (4): umin = uc + r cos(theta_v_max) ; v_cross_max = vc - r sin(theta_v_max) <= vmin + height + // (1) & (3) => uc >= umin - r cos(theta_u_bot_min) & uc > umin - r cos(theta_u_bot_max) + // (1) & (3) => vc = vmin + height + r sin(theta_u_bot_min) & vc = vmin + height + r sin(PI - theta_u_bot_min) + // (2) & (4) => uc = umin - r cos(theta_v_min) & uc = umin - r cos(-theta_v_min) + // (2) & (4) => vc < vmin + height + r sin(theta_v_min) & vc < vmin + height + r sin(-theta_v_min) + // (1) & (3) theta_u_bot_min = PI - theta_u_bot_max + // (2) & (4) theta_v_min = - theta_v_max + float theta_u_bot_min = -5.f * M_PI / 8.f; + float theta_u_bot_max = M_PI - theta_u_bot_min; + theta_u_bot_max = ensureIsBetweenMinPiAndPi(theta_u_bot_max); + float theta_v_min = 7.f * M_PI / 8.f; + float theta_v_max = -theta_v_min; + float vc = OFFSET + HEIGHT + RADIUS * std::sin(theta_u_bot_min); + float uc = OFFSET - RADIUS * std::cos(theta_v_min); vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); - float theoreticalValue = ((theta2 - theta3) + (theta1 - theta4)) * RADIUS; + float theoreticalValue = ((theta_v_min - theta_u_bot_max) + (theta_u_bot_min - theta_v_max)) * RADIUS; bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); std::string statusTest; if (isValueOK) { @@ -849,19 +848,19 @@ int main() // Test with intersections with the bottom and the right border, crossing each axis once in the RoI { - // (1): u1 = uc + r cos(theta1) <= umin + width ; vmin + height = vc - r sin(theta1) - // (2): umin + width = uc + r cos(theta2) ; v = vc - r sin(theta2) <= vmin + height - // (3): u3 = uc + r cos(theta3) >= umin + width ; vmin + height = vc - r sin(theta3) - // (4): umin + width = uc + r cos(theta4) ; v = vc - r sin(theta4) >= vmin + height - // Choice: for theta1 = -2PI/3 theta2 = PI/2 - // (2) => uc = umin + width - r cos(theta2) - // (1) => vc = vmin + height + r sin(theta1) - // (1) & (3) theta1 = PI - theta3 - // (2) & (4) theta2 = - theta4 - float theta1 = -2.f * M_PI / 3.f; - float theta2 = M_PI_2; - float uc = OFFSET + WIDTH - RADIUS * std::cos(theta2); - float vc = OFFSET + HEIGHT + RADIUS * std::sin(theta1);; + // (1): u_cross_bot_min = uc + r cos(theta_u_bot_min) <= umin + width ; vmin + height = vc - r sin(theta_u_bot_min) + // (2): umin + width = uc + r cos(theta_v_min) ; v_cross_min = vc - r sin(theta_v_min) <= vmin + height + // (3): u_cross_bot_max = uc + r cos(theta_u_bot_max) >= umin + width ; vmin + height = vc - r sin(theta_u_bot_max) + // (4): umin + width = uc + r cos(theta_v_max) ; v_cross_max = vc - r sin(theta_v_max) >= vmin + height + // Choice: for theta_u_bot_min = -2PI/3 theta_v_min = PI/2 + // (2) => uc = umin + width - r cos(theta_v_min) + // (1) => vc = vmin + height + r sin(theta_u_bot_min) + // (1) & (3) theta_u_bot_min = PI - theta_u_bot_max + // (2) & (4) theta_v_min = - theta_v_max + float theta_u_bot_min = -2.f * M_PI / 3.f; + float theta_v_min = M_PI_2; + float uc = OFFSET + WIDTH - RADIUS * std::cos(theta_v_min); + float vc = OFFSET + HEIGHT + RADIUS * std::sin(theta_u_bot_min);; vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); float theoreticalValue = (M_PI_2 + M_PI / 3.f) * RADIUS; @@ -884,18 +883,18 @@ int main() // Test with intersections with the bottom and the right border, // crossing only the right axis in the RoI { - // (1): u1 = uc + r cos(theta1) >= umin + width ; vmin + height = vc - r sin(theta1) - // (2): umin + width = uc + r cos(theta2) ; v = vc - r sin(theta2) <= vmin + height - // (3): u3 = uc + r cos(theta3) >= umin + width ; vmin + height = vc - r sin(theta3) - // (4): umin + width = uc + r cos(theta4) ; v = vc - r sin(theta4) <= vmin + height - // Choice: for theta2 = 5*PI/6 - // (2) => uc = umin + width - r cos(theta2) - // (2) & (4) => vc <= vmin + height + r sin(theta2) & vc <= vmin + height + r sin(-theta2) - // (1) & (3) theta1 = PI - theta3 - // (2) & (4) theta2 = - theta4 - float theta2 = 5.f * M_PI / 6.f; - float uc = OFFSET + WIDTH - RADIUS * std::cos(theta2); - float vc = std::min(OFFSET + HEIGHT + RADIUS * std::sin(theta2) - 1.f, OFFSET + HEIGHT + RADIUS * std::sin(-theta2) - 1.f); + // (1): u_cross_bot_min = uc + r cos(theta_u_bot_min) <= umin + width ; vmin + height = vc - r sin(theta_u_bot_min) + // (2): umin + width = uc + r cos(theta_v_min) ; v_cross_min = vc - r sin(theta_v_min) <= vmin + height + // (3): u_cross_bot_max = uc + r cos(theta_u_bot_max) >= umin + width ; vmin + height = vc - r sin(theta_u_bot_max) + // (4): umin + width = uc + r cos(theta_v_max) ; v_cross_max = vc - r sin(theta_v_max) >= vmin + height + // Choice: for theta_v_min = 5*PI/6 + // (2) => uc = umin + width - r cos(theta_v_min) + // (2) & (4) => vc <= vmin + height + r sin(theta_v_min) & vc <= vmin + height + r sin(-theta_v_min) + // (1) & (3) theta_u_bot_min = PI - theta_u_bot_max + // (2) & (4) theta_v_min = - theta_v_max + float theta_v_min = 5.f * M_PI / 6.f; + float uc = OFFSET + WIDTH - RADIUS * std::cos(theta_v_min); + float vc = std::min(OFFSET + HEIGHT + RADIUS * std::sin(theta_v_min) - 1.f, OFFSET + HEIGHT + RADIUS * std::sin(-theta_v_min) - 1.f); vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); float theoreticalValue = (M_PI / 3.f) * RADIUS; // <=> 2.f * M_PI / 6.f @@ -918,18 +917,18 @@ int main() // Test with intersections with the bottom and the right border, // crossing only the bottom axis in the RoI { - // (1): u1 = uc + r cos(theta1) < umin + width ; vmin + height = vc - r sin(theta1) - // (2): umin + width = uc + r cos(theta2) ; v = vc - r sin(theta2) >= vmin + height - // (3): u3 = uc + r cos(theta3) <= umin + width ; vmin + height = vc - r sin(theta3) - // (4): umin + width = uc + r cos(theta4) ; v = vc - r sin(theta4) >= vmin + height - // Choice: for theta1 = 4*PI/6 - // (1) => vc = vmin + height + r cos(theta1) - // (1) & (3) => uc < umin + width - r cos(theta1) & uc <= umin + width - r cos(PI - theta1) - // (1) & (3) theta1 = PI - theta3 - // (2) & (4) theta2 = - theta4 - float theta1 = 4.f * M_PI / 6.f; - float vc = OFFSET + HEIGHT + RADIUS * std::sin(theta1); - float uc = std::min(OFFSET + WIDTH - RADIUS * std::cos(theta1) - 1.f, OFFSET + WIDTH - RADIUS * std::cos((float)M_PI -theta1) - 1.f); + // (1): u_cross_bot_min = uc + r cos(theta_u_bot_min) < umin + width ; vmin + height = vc - r sin(theta_u_bot_min) + // (2): umin + width = uc + r cos(theta_v_min) ; v_cross_min = vc - r sin(theta_v_min) >= vmin + height + // (3): u_cross_bot_max = uc + r cos(theta_u_bot_max) <= umin + width ; vmin + height = vc - r sin(theta_u_bot_max) + // (4): umin + width = uc + r cos(theta_v_max) ; v_cross_max = vc - r sin(theta_v_max) >= vmin + height + // Choice: for theta_u_bot_min = 4*PI/6 + // (1) => vc = vmin + height + r cos(theta_u_bot_min) + // (1) & (3) => uc < umin + width - r cos(theta_u_bot_min) & uc <= umin + width - r cos(PI - theta_u_bot_min) + // (1) & (3) theta_u_bot_min = PI - theta_u_bot_max + // (2) & (4) theta_v_min = - theta_v_max + float theta_u_bot_min = 4.f * M_PI / 6.f; + float vc = OFFSET + HEIGHT + RADIUS * std::sin(theta_u_bot_min); + float uc = std::min(OFFSET + WIDTH - RADIUS * std::cos(theta_u_bot_min) - 1.f, OFFSET + WIDTH - RADIUS * std::cos((float)M_PI -theta_u_bot_min) - 1.f); vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); float theoreticalValue = (M_PI / 3.f) * RADIUS; // <=> 2.f * M_PI / 6.f @@ -952,26 +951,26 @@ int main() // Test with intersections with the bottom and the right border // crossing each axis twice in the RoI { - // (1): u1 = uc + r cos(theta1) < umin + width ; vmin + height = vc - r sin(theta1) - // (2): umin + width = uc + r cos(theta2) ; v = vc - r sin(theta2) < vmin + height - // (3): u3 = uc + r cos(theta3) <= umin + width ; vmin + height = vc - r sin(theta3) - // (4): umin + width = uc + r cos(theta4) ; v = vc - r sin(theta4) <= vmin + height - // (1) & (3) => uc < umin + width - r cos(theta1) & uc <= umin + width - r cos(PI - theta1) - // (1) & (3) => vc = vmin + height + r sin(theta1) & vc = vmin + height + r sin(PI - theta1) - // (2) & (4) => uc = umin + width - r cos(theta2) & uc = umin + width - r cos(-theta2) - // (2) & (4) => vc < vmin + height + r sin(theta2) & vc < vmin + height + r sin(-theta2) - // (1) & (3) theta1 = PI - theta3 - // (2) & (4) theta2 = - theta4 - float theta1 = -7.f * M_PI / 8.f; - float theta3 = M_PI - theta1; - theta3 = ensureIsBetweenMinPiAndPi(theta3); - float theta4 = -3.f * M_PI / 8.f; - float theta2 = -theta4; - float vc = OFFSET + HEIGHT + RADIUS * std::sin(theta1); - float uc = OFFSET - RADIUS * std::cos(theta2); + // (1): u_cross_bot_min = uc + r cos(theta_u_bot_min) < umin + width ; vmin + height = vc - r sin(theta_u_bot_min) + // (2): umin + width = uc + r cos(theta_v_min) ; v_cross_min = vc - r sin(theta_v_min) < vmin + height + // (3): u_cross_bot_max = uc + r cos(theta_u_bot_max) <= umin + width ; vmin + height = vc - r sin(theta_u_bot_max) + // (4): umin + width = uc + r cos(theta_v_max) ; v_cross_max = vc - r sin(theta_v_max) <= vmin + height + // (1) & (3) => uc < umin + width - r cos(theta_u_bot_min) & uc <= umin + width - r cos(PI - theta_u_bot_min) + // (1) & (3) => vc = vmin + height + r sin(theta_u_bot_min) & vc = vmin + height + r sin(PI - theta_u_bot_min) + // (2) & (4) => uc = umin + width - r cos(theta_v_min) & uc = umin + width - r cos(-theta_v_min) + // (2) & (4) => vc < vmin + height + r sin(theta_v_min) & vc < vmin + height + r sin(-theta_v_min) + // (1) & (3) theta_u_bot_min = PI - theta_u_bot_max + // (2) & (4) theta_v_min = - theta_v_max + float theta_u_bot_min = -7.f * M_PI / 8.f; + float theta_u_bot_max = M_PI - theta_u_bot_min; + theta_u_bot_max = ensureIsBetweenMinPiAndPi(theta_u_bot_max); + float theta_v_max = -3.f * M_PI / 8.f; + float theta_v_min = -theta_v_max; + float vc = OFFSET + HEIGHT + RADIUS * std::sin(theta_u_bot_min); + float uc = OFFSET - RADIUS * std::cos(theta_v_min); vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); - float theoreticalValue = (2.f * M_PI - ((theta2 - theta4) + (theta3 - theta1))) * RADIUS; + float theoreticalValue = (2.f * M_PI - ((theta_v_min - theta_v_max) + (theta_u_bot_max - theta_u_bot_min))) * RADIUS; bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); std::string statusTest; if (isValueOK) { From 149a41eb0aafc8e7c69d438cc990974abb9d83e6 Mon Sep 17 00:00:00 2001 From: rlagneau Date: Mon, 2 Oct 2023 10:59:03 +0200 Subject: [PATCH 17/22] Added case where all the axes are crossed --- modules/core/src/image/vpImageCircle.cpp | 378 +++++++++++++---- .../test/tools/geometry/testImageCircle.cpp | 391 ++++++++++-------- 2 files changed, 509 insertions(+), 260 deletions(-) diff --git a/modules/core/src/image/vpImageCircle.cpp b/modules/core/src/image/vpImageCircle.cpp index d9b34282b7..2b974e8ef1 100644 --- a/modules/core/src/image/vpImageCircle.cpp +++ b/modules/core/src/image/vpImageCircle.cpp @@ -282,19 +282,18 @@ void computePerpendicularAxesIntersections(const float &u_c, const float &v_c, c * * \param[in] u_c The horizontal u-axis coordinate of the center. * \param[in] v_c The vertical v-axis coordinate of the center. - * \param[in] topLeft The top left corner of the RoI. + * \param[in] umin_roi The u-coordinate of the left v-axis of the RoI. + * \param[in] vmin_roi The v-coordinate of the top u-axis of the RoI. * \param[in] radius The radius of the circle. * \param[out] delta_theta The length of the angular interval that is in the RoI. */ -void computeIntersectionsTopLeft(const float &u_c, const float &v_c, const vpImagePoint &topLeft, const float &radius, +void computeIntersectionsTopLeft(const float &u_c, const float &v_c, const float &umin_roi, const float &vmin_roi, const float &radius, float &delta_theta) { std::pair crossing_theta_u_min, crossing_theta_u_max; std::pair crossing_theta_v_min, crossing_theta_v_max; - float crossing_u = topLeft.get_v(); // We cross the u-axis of the RoI at which v-coordinate - float vmin_roi = crossing_u; // The minimum v-coordinate of the RoI - float crossing_v = topLeft.get_u(); // We cross the v-axis of the RoI at which u-coordinate - float umin_roi = crossing_v; // The minimum u-coordinate of the RoI + float crossing_u = vmin_roi; // We cross the u-axis of the RoI at which v-coordinate + float crossing_v = umin_roi; // We cross the v-axis of the RoI at which u-coordinate computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u, crossing_v, crossing_theta_u_min, crossing_theta_u_max, crossing_theta_v_min, crossing_theta_v_max); @@ -304,9 +303,6 @@ void computeIntersectionsTopLeft(const float &u_c, const float &v_c, const vpIma float u_umax = crossing_theta_u_max.second; float v_vmin = crossing_theta_v_min.second; float v_vmax = crossing_theta_v_max.second; - std::cout << "umin_roi = " << umin_roi << "\tvmin_roi = " << vmin_roi << std::endl; - std::cout << "u_umin = " << u_umin << " (" << theta_u_min << ")\tu_umax = " << u_umax << " (" << theta_u_max << ")" << std::endl; - std::cout << "v_vmin = " << v_vmin << " (" << theta_v_min << ")\tv_vmax = " << v_vmax << " (" << theta_v_max << ")" << std::endl; if (u_umin < umin_roi && u_umax >= umin_roi && v_vmin < vmin_roi && v_vmax >= vmin_roi) { // The circle crosses only once each axis std::cout << "\t|->Case crossing once" << std::endl; @@ -328,7 +324,6 @@ void computeIntersectionsTopLeft(const float &u_c, const float &v_c, const vpIma // so it is equivalent to the case of crossing only the top border std::cout << "\t|->Case top only" << std::endl; computeIntersectionsTopBorderOnly(v_c, vmin_roi, radius, delta_theta); - // delta_theta = theta_u_max - theta_u_min; } } @@ -391,20 +386,18 @@ void computeIntersectionsTopRight(const float &u_c, const float &v_c, const floa * * \param[in] u_c The horizontal u-axis coordinate of the center. * \param[in] v_c The vertical v-axis coordinate of the center. - * \param[in] topLeft The top left corner of the RoI. - * \param[in] height The height of the RoI. + * \param[in] umin_roi The left u-coordinate of the RoI. + * \param[in] vmax_roi The bottom v-coordinate of the RoI. * \param[in] radius The radius of the circle. * \param[out] delta_theta The length of the angular interval that is in the RoI. */ -void computeIntersectionsBottomLeft(const float &u_c, const float &v_c, const vpImagePoint &topLeft, const float &height, const float &radius, +void computeIntersectionsBottomLeft(const float &u_c, const float &v_c, const float &umin_roi, const float &vmax_roi, const float &radius, float &delta_theta) { std::pair crossing_theta_u_min, crossing_theta_u_max; std::pair crossing_theta_v_min, crossing_theta_v_max; - float crossing_u = topLeft.get_v() + height; // We cross the u-axis of the RoI at which v-coordinate - float vmax_roi = crossing_u; // The maximum v-coordinate of the RoI - float crossing_v = topLeft.get_u(); // We cross the v-axis of the RoI at which u-coordinate - float umin_roi = crossing_v; // The minimum u-coordinate of the RoI + float crossing_u = vmax_roi; // We cross the u-axis of the RoI at which v-coordinate + float crossing_v = umin_roi; // We cross the v-axis of the RoI at which u-coordinate computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u, crossing_v, crossing_theta_u_min, crossing_theta_u_max, crossing_theta_v_min, crossing_theta_v_max); @@ -414,9 +407,6 @@ void computeIntersectionsBottomLeft(const float &u_c, const float &v_c, const vp float u_umax = crossing_theta_u_max.second; float v_vmin = crossing_theta_v_min.second; float v_vmax = crossing_theta_v_max.second; - std::cout << "umin_roi = " << umin_roi << "\tvmax_roi = " << vmax_roi << std::endl; - std::cout << "u_umin = " << u_umin << " (" << theta_u_min << ")\tu_umax = " << u_umax << " (" << theta_u_max << ")" << std::endl; - std::cout << "v_vmin = " << v_vmin << " (" << theta_v_min << ")\tv_vmax = " << v_vmax << " (" << theta_v_max << ")" << std::endl; if (u_umin < umin_roi && u_umax >= umin_roi && v_vmin <= vmax_roi && v_vmax > vmax_roi) { // The circle crosses only once each axis std::cout << "\t|->Case crossing once" << std::endl; @@ -468,9 +458,6 @@ void computeIntersectionsBottomRight(const float &u_c, const float &v_c, const f float u_umax = crossing_theta_u_max.second; float v_vmin = crossing_theta_v_min.second; float v_vmax = crossing_theta_v_max.second; - std::cout << "umax_roi = " << umax_roi << "\tvmax_roi = " << vmax_roi << std::endl; - std::cout << "u_umin = " << u_umin << " (" << theta_u_min << ")\tu_umax = " << u_umax << " (" << theta_u_max << ")" << std::endl; - std::cout << "v_vmin = " << v_vmin << " (" << theta_v_min << ")\tv_vmax = " << v_vmax << " (" << theta_v_max << ")" << std::endl; if (u_umin <= umax_roi && u_umax > umax_roi && v_vmin <= vmax_roi && v_vmax > vmax_roi) { // The circle crosses only once each axis std::cout << "\t|->Case crossing once" << std::endl; @@ -505,21 +492,20 @@ void computeIntersectionsBottomRight(const float &u_c, const float &v_c, const f * * \param[in] u_c The horizontal u-axis coordinate of the center. * \param[in] v_c The vertical v-axis coordinate of the center. - * \param[in] topLeft The top left corner of the RoI. - * \param[in] height The height of the RoI. + * \param[in] umin_roi The u-coordinate of the left axis of the RoI. + * \param[in] vmin_roi The v-coordinate of the top axis of the RoI. + * \param[in] vmax_roi The v-coordinate of the bottom axis of the RoI. * \param[in] radius The radius of the circle. * \param[out] delta_theta The length of the angular interval that is in the RoI. */ -void computeIntersectionsTopLeftBottom(const float &u_c, const float &v_c, const vpImagePoint &topLeft, const float &height, const float &radius, - float &delta_theta) +void computeIntersectionsTopLeftBottom(const float &u_c, const float &v_c, const float &umin_roi, const float &vmin_roi, + const float &vmax_roi, const float &radius, float &delta_theta) { // Computing the intersections with the top and left axes std::pair crossing_theta_u_min, crossing_theta_u_max; std::pair crossing_theta_v_min, crossing_theta_v_max; - float crossing_u_top = topLeft.get_v(); // We cross the u-axis of the RoI at the maximum v-coordinate of the RoI - float crossing_v = topLeft.get_u(); // We cross the v-axis of the RoI at the minimum u-coordinate of the RoI - float umin_roi = crossing_v; - float vmin_roi = crossing_u_top; + float crossing_u_top = vmin_roi; // We cross the u-axis of the top axis of the RoI at the minimum v-coordinate of the RoI + float crossing_v = vmin_roi; // We cross the v-axis of the RoI at the minimum u-coordinate of the RoI computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u_top, crossing_v, crossing_theta_u_min, crossing_theta_u_max, crossing_theta_v_min, crossing_theta_v_max); @@ -531,7 +517,6 @@ void computeIntersectionsTopLeftBottom(const float &u_c, const float &v_c, const float v_vmax = crossing_theta_v_max.second; // Computing the intersections with the bottom and left axes - float vmax_roi = vmin_roi + height; float crossing_u_bottom = vmax_roi; // We cross the u-axis of the RoI at the maximum v-coordinate of the RoI computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u_bottom, crossing_v, crossing_theta_u_min, crossing_theta_u_max, @@ -540,10 +525,6 @@ void computeIntersectionsTopLeftBottom(const float &u_c, const float &v_c, const float theta_u_max_bottom = crossing_theta_u_max.first; float u_umin_bottom = crossing_theta_u_min.second; float u_umax_bottom = crossing_theta_u_max.second; - std::cout << "umin_roi = " << topLeft.get_u() << "\tvmin_roi = " << topLeft.get_v() << "\tvmax_roi = " << vmax_roi << std::endl; - std::cout << "u_umin_top = " << u_umin_top << " (" << theta_u_min_top << ")\tu_umax_top = " << u_umax_top << " (" << theta_u_max_top << ")" << std::endl; - std::cout << "u_umin_bottom = " << u_umin_bottom << " (" << theta_u_min_bottom << ")\tu_umax_bottom = " << u_umax_bottom << " (" << theta_u_max_bottom << ")" << std::endl; - std::cout << "v_vmin = " << v_vmin << " (" << theta_v_min << ")\tv_vmax = " << v_vmax << " (" << theta_v_max << ")" << std::endl; if (u_umin_top >= umin_roi && u_umin_bottom >= umin_roi && v_vmin >= vmin_roi && v_vmax <= vmax_roi) { std::cout << "\t|-> case intersection top + left + bottom twice" << std::endl; delta_theta = (theta_v_min - theta_u_min_top) + (theta_u_max_top - theta_u_max_bottom) + (theta_u_min_bottom - theta_v_max); @@ -558,11 +539,11 @@ void computeIntersectionsTopLeftBottom(const float &u_c, const float &v_c, const } else if (u_umax_bottom > umin_roi && v_vmin >= vmin_roi) { std::cout << "\t|-> case bottom/left corner" << std::endl; - computeIntersectionsBottomLeft(u_c, v_c, topLeft, height, radius, delta_theta); + computeIntersectionsBottomLeft(u_c, v_c, umin_roi, vmax_roi, radius, delta_theta); } else if (u_umax_top > umin_roi && v_vmax <= vmax_roi) { std::cout << "\t|-> case top/left corner" << std::endl; - computeIntersectionsTopLeft(u_c, v_c, topLeft, radius, delta_theta); + computeIntersectionsTopLeft(u_c, v_c, umin_roi, vmin_roi, radius, delta_theta); } } @@ -572,23 +553,20 @@ void computeIntersectionsTopLeftBottom(const float &u_c, const float &v_c, const * * \param[in] u_c The horizontal u-axis coordinate of the center. * \param[in] v_c The vertical v-axis coordinate of the center. - * \param[in] topLeft The top left corner of the RoI. - * \param[in] width The width of the RoI. - * \param[in] height The height of the RoI. + * \param[in] umax_roi The u-coordinate of the right axis of the RoI. + * \param[in] vmin_roi The v-coordinate of the top axis of the RoI. + * \param[in] vmax_roi The v-coordinate of the bottom axis of the RoI. * \param[in] radius The radius of the circle. * \param[out] delta_theta The length of the angular interval that is in the RoI. */ -void computeIntersectionsTopRightBottom(const float &u_c, const float &v_c, const vpImagePoint &topLeft, const float &width, const float &height, const float &radius, - float &delta_theta) +void computeIntersectionsTopRightBottom(const float &u_c, const float &v_c, const float &umax_roi, const float &vmin_roi, const float &vmax_roi, + const float &radius, float &delta_theta) { - // Computing the intersections with the top and left axes + // Computing the intersections with the top and right axes std::pair crossing_theta_u_min, crossing_theta_u_max; std::pair crossing_theta_v_min, crossing_theta_v_max; - float crossing_u_top = topLeft.get_v(); // We cross the u-axis of the RoI at the maximum v-coordinate of the RoI - float umin_roi = topLeft.get_u(); - float umax_roi = umin_roi + width; - float crossing_v = umax_roi; // We cross the v-axis of the RoI at the maximum u-coordinate of the RoI - float vmin_roi = crossing_u_top; + float crossing_u_top = vmin_roi; // We cross the u-axis of the top axis of the RoI at the minimum v-coordinate of the RoI + float crossing_v = umax_roi; // We cross the v-axis of the right axis of the RoI at the maximum u-coordinate of the RoI computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u_top, crossing_v, crossing_theta_u_min, crossing_theta_u_max, crossing_theta_v_min, crossing_theta_v_max); @@ -599,8 +577,7 @@ void computeIntersectionsTopRightBottom(const float &u_c, const float &v_c, cons float v_vmin = crossing_theta_v_min.second; float v_vmax = crossing_theta_v_max.second; - // Computing the intersections with the bottom and left axes - float vmax_roi = vmin_roi + height; + // Computing the intersections with the bottom and right axes float crossing_u_bottom = vmax_roi; // We cross the u-axis of the RoI at the maximum v-coordinate of the RoI computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u_bottom, crossing_v, crossing_theta_u_min, crossing_theta_u_max, @@ -609,10 +586,6 @@ void computeIntersectionsTopRightBottom(const float &u_c, const float &v_c, cons float theta_u_max_bottom = crossing_theta_u_max.first; float u_umin_bottom = crossing_theta_u_min.second; float u_umax_bottom = crossing_theta_u_max.second; - std::cout << "umin_roi = " << topLeft.get_u() << "\tvmin_roi = " << topLeft.get_v() << "\tvmax_roi = " << vmax_roi << std::endl; - std::cout << "u_umin_top = " << u_umin_top << " (" << theta_u_min_top << ")\tu_umax_top = " << u_umax_top << " (" << theta_u_max_top << ")" << std::endl; - std::cout << "u_umin_bottom = " << u_umin_bottom << " (" << theta_u_min_bottom << ")\tu_umax_bottom = " << u_umax_bottom << " (" << theta_u_max_bottom << ")" << std::endl; - std::cout << "v_vmin = " << v_vmin << " (" << theta_v_min << ")\tv_vmax = " << v_vmax << " (" << theta_v_max << ")" << std::endl; if (u_umax_top <= umax_roi && u_umax_bottom <= umax_roi && v_vmin >= vmin_roi && v_vmax <= vmax_roi) { std::cout << "\t|-> case intersection top + right + bottom twice" << std::endl; delta_theta = 2.f * M_PI - ((theta_u_min_top - theta_u_max_top) + (theta_v_min - theta_v_max) + (theta_u_max_bottom - theta_u_min_bottom)); @@ -709,12 +682,256 @@ void computeIntersectionsTopBottomOnly(const float &u_c, const float &v_c, const delta_theta = 2.f * M_PI - ((theta_u_cross_top_min - theta_u_cross_top_max) + (theta_u_cross_bottom_max - theta_u_cross_bottom_min)); } +/*! + * \brief Compute the length of the angular interval of the circle when it intersects + * only with the left, right and top borders of the Region of Interest (RoI). + * + * \param[in] u_c The horizontal u-axis coordinate of the center. + * \param[in] v_c The vertical v-axis coordinate of the center. + * \param[in] umin_roi The u-coordinate of the left axis of the RoI. + * \param[in] umax_roi The u-coordinate of the right axis of the RoI. + * \param[in] vmin_roi The v-coordinate of the top axis of the RoI. + * \param[in] radius The radius of the circle. + * \param[out] delta_theta The length of the angular interval that is in the RoI. + */ +void computeIntersectionsLeftRightTop(const float &u_c, const float &v_c, const float &umin_roi, const float &umax_roi, + const float &vmin_roi, const float &radius, float &delta_theta) +{ + // Computing the intersections with the top and left axes + std::pair crossing_theta_u_min, crossing_theta_u_max; + std::pair crossing_theta_v_min, crossing_theta_v_max; + float crossing_u = vmin_roi; // We cross the u-axis of the RoI at the minimum v-coordinate of the RoI + float crossing_v_left = umin_roi; // We cross the v-axis of the left of the RoI at the minimum u-coordinate of the RoI + computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u, crossing_v_left, + crossing_theta_u_min, crossing_theta_u_max, + crossing_theta_v_min, crossing_theta_v_max); + float theta_u_min = crossing_theta_u_min.first; + float theta_u_max = crossing_theta_u_max.first; + float u_umin = crossing_theta_u_min.second; + float u_umax = crossing_theta_u_max.second; + float theta_v_min_left = crossing_theta_v_min.first; + float theta_v_max_left = crossing_theta_v_max.first; + float v_vmin_left = crossing_theta_v_min.second; + float v_vmax_left = crossing_theta_v_max.second; + + // Computing the intersections with the rigt and top axes + float crossing_v_right = umax_roi; // We cross the v-axis of the right of the RoI at the maximum u-coordinate of the RoI + computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u, crossing_v_right, + crossing_theta_u_min, crossing_theta_u_max, + crossing_theta_v_min, crossing_theta_v_max); + float theta_v_min_right = crossing_theta_v_min.first; + float theta_v_max_right = crossing_theta_v_max.first; + float v_vmin_right = crossing_theta_v_min.second; + float v_vmax_right = crossing_theta_v_max.second; + + if (u_umin >= umin_roi && u_umax <= umax_roi && v_vmin_left >= vmin_roi && v_vmin_right >= vmin_roi) { + std::cout << "\t|-> case intersection left + right + top twice" << std::endl; + delta_theta = (theta_v_min_left - theta_u_min) + (theta_u_max - theta_v_min_right) + (theta_v_max_right - theta_v_max_left); + } + else if (u_umin <= umin_roi && u_umax >= umax_roi && v_vmax_left >= vmin_roi && v_vmax_right >= vmin_roi) { + std::cout << "\t|-> case intersection left + right" << std::endl; + delta_theta = (theta_v_max_right - theta_v_max_left); + } + else if (v_vmax_left <= vmin_roi && v_vmax_right <= vmin_roi && u_umin >= umin_roi && u_umax <= umax_roi) { + std::cout << "\t|-> case top only" << std::endl; + computeIntersectionsTopBorderOnly(v_c, vmin_roi, radius, delta_theta); + } + else if (u_umax >= umin_roi && v_vmax_right >= vmin_roi) { + std::cout << "\t|-> case top/left corner" << std::endl; + computeIntersectionsTopLeft(u_c, v_c, umin_roi, vmin_roi, radius, delta_theta); + } + else if (u_umin <= umax_roi && v_vmax_right >= vmin_roi) { + std::cout << "\t|-> case top/right corner" << std::endl; + computeIntersectionsTopRight(u_c, v_c, vmin_roi, umax_roi, radius, delta_theta); + } +} + +/*! + * \brief Compute the length of the angular interval of the circle when it intersects + * only with the left, right and top borders of the Region of Interest (RoI). + * + * \param[in] u_c The horizontal u-axis coordinate of the center. + * \param[in] v_c The vertical v-axis coordinate of the center. + * \param[in] umin_roi The u-coordinate of the left axis of the RoI. + * \param[in] umax_roi The u-coordinate of the right axis of the RoI. + * \param[in] vmax_roi The v-coordinate of the bottom axis of the RoI. + * \param[in] radius The radius of the circle. + * \param[out] delta_theta The length of the angular interval that is in the RoI. + */ +void computeIntersectionsLeftRightBottom(const float &u_c, const float &v_c, const float &umin_roi, const float &umax_roi, + const float &vmax_roi, const float &radius, float &delta_theta) +{ + // Computing the intersections with the bottom and left axes + std::pair crossing_theta_u_min, crossing_theta_u_max; + std::pair crossing_theta_v_min, crossing_theta_v_max; + float crossing_u = vmax_roi; // We cross the u-axis of the bottom axis of the RoI at the maximum v-coordinate of the RoI + float crossing_v_left = umin_roi; // We cross the v-axis of the left of the RoI at the minimum u-coordinate of the RoI + computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u, crossing_v_left, + crossing_theta_u_min, crossing_theta_u_max, + crossing_theta_v_min, crossing_theta_v_max); + float theta_u_min = crossing_theta_u_min.first; + float theta_u_max = crossing_theta_u_max.first; + float u_umin = crossing_theta_u_min.second; + float u_umax = crossing_theta_u_max.second; + float theta_v_min_left = crossing_theta_v_min.first; + float theta_v_max_left = crossing_theta_v_max.first; + float v_vmin_left = crossing_theta_v_min.second; + // float v_vmax_left = crossing_theta_v_max.second; + + // Computing the intersections with the bottom and right axes + float crossing_v_right = umax_roi; // We cross the v-axis of the right of the RoI at the maximum u-coordinate of the RoI + computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u, crossing_v_right, + crossing_theta_u_min, crossing_theta_u_max, + crossing_theta_v_min, crossing_theta_v_max); + float theta_v_min_right = crossing_theta_v_min.first; + float theta_v_max_right = crossing_theta_v_max.first; + float v_vmin_right = crossing_theta_v_min.second; + // float v_vmax_right = crossing_theta_v_max.second; + + if (u_umin >= umin_roi && u_umax <= umax_roi && v_vmin_left <= vmax_roi && v_vmin_right <= vmax_roi) { + std::cout << "\t|-> case intersection left + right + bottom twice" << std::endl; + delta_theta = (theta_v_min_left - theta_v_min_right) + (theta_v_max_right - theta_u_max) + (theta_u_min - theta_v_max_left); + } + else if (u_umin <= umin_roi && u_umax >= umax_roi && v_vmin_left <= vmax_roi && v_vmin_right <= vmax_roi) { + std::cout << "\t|-> case intersection left + right" << std::endl; + delta_theta = (theta_v_min_left - theta_v_min_right); + } + else if (v_vmin_left >= vmax_roi && v_vmin_right >= vmax_roi && u_umin >= umin_roi && u_umax <= umax_roi) { + std::cout << "\t|-> case bottom only" << std::endl; + computeIntersectionsBottomBorderOnly(v_c, vmax_roi, radius, delta_theta); + } + else if (u_umax >= umin_roi && v_vmin_right <= vmax_roi) { + std::cout << "\t|-> case bottom/left corner" << std::endl; + computeIntersectionsBottomLeft(u_c, v_c, umin_roi, vmax_roi, radius, delta_theta); + } + else if (u_umin <= umax_roi && v_vmin_right <= vmax_roi) { + std::cout << "\t|-> case bottom/right corner" << std::endl; + computeIntersectionsBottomRight(u_c, v_c, vmax_roi, umax_roi, radius, delta_theta); + } +} + +/*! + * \brief Compute the length of the angular interval of the circle when it intersects + * only with the left and right borders of the Region of Interest (RoI). + * + * \param[in] u_c The horizontal u-axis coordinate of the center. + * \param[in] v_c The vertical v-axis coordinate of the center. + * \param[in] umin_roi The minimum u-coordinate of the left axis of the RoI. + * \param[in] umax_roi The maximum u-coordinate of the right axis of the RoI. + * \param[in] radius The radius of the circle. + * \param[out] delta_theta The length of the angular interval that is in the RoI. + */ +void computeIntersectionsLeftRightOnly(const float &u_c, const float &v_c, const float &umin_roi, const float &umax_roi, const float &radius, + float &delta_theta) +{ + // Computing the two angles for which the v-axis is crossed at the left of the RoI + // umin_roi = u_c + r cos(theta) + // theta = acos((umin_roi - u_c)/r) + // theta_min = -theta_max + float theta_v_cross_left = std::acos((umin_roi - u_c)/radius); + theta_v_cross_left = getAngleBetweenMinPiAndPi(theta_v_cross_left); + float theta_v_cross_left_2 = -theta_v_cross_left; + + // Computing the corresponding v-coordinates at which the v-axis is crossed + float v_vcross_left = v_c - radius * std::sin(theta_v_cross_left); + float v_vcross_left_2 = v_c + radius * std::sin(theta_v_cross_left_2); + // Sorting the outputs such as v(theta_v_cross_left_min) < v(theta_v_cross_left_max) + float theta_v_cross_left_min = 0.f, theta_v_cross_left_max = 0.f; + if (v_vcross_left < v_vcross_left_2) { + theta_v_cross_left_min = theta_v_cross_left; + theta_v_cross_left_max = theta_v_cross_left_2; + } + else { + theta_v_cross_left_min = theta_v_cross_left_2; + theta_v_cross_left_max = theta_v_cross_left; + } + + // Computing the two angles for which the v-axis is crossed at the right of the RoI + // umax_roi = u_c + r cos(theta) + // theta = acos((umin_roi - u_c)/r) + // theta_min = -theta_max + float theta_v_cross_right = std::acos((umax_roi - u_c)/radius); + theta_v_cross_right = getAngleBetweenMinPiAndPi(theta_v_cross_right); + float theta_v_cross_right_2 = -theta_v_cross_right; + + // Computing the corresponding v-coordinates at which the v-axis is crossed + float v_vcross_right = v_c - radius * std::sin(theta_v_cross_right); + float v_vcross_right_2 = v_c + radius * std::sin(theta_v_cross_right_2); + + // Sorting the outputs such as v(theta_v_cross_right_min) < v(theta_v_cross_right_max) + float theta_v_cross_right_min = 0.f, theta_v_cross_right_max = 0.f; + if (v_vcross_right < v_vcross_right_2) { + theta_v_cross_right_min = theta_v_cross_right; + theta_v_cross_right_max = theta_v_cross_right_2; + } + else { + theta_v_cross_right_min = theta_v_cross_right_2; + theta_v_cross_right_max = theta_v_cross_right; + } + + // Computing the the length of the angular interval of the circle when it intersects + // only with the top and bottom borders of the Region of Interest (RoI) + delta_theta = (theta_v_cross_left_min - theta_v_cross_right_min) + (theta_v_cross_right_max - theta_v_cross_left_max); +} + + +/*! + * \brief Compute the length of the angular interval of the circle when it intersects + * only with the left, right and top borders of the Region of Interest (RoI). + * + * \param[in] u_c The horizontal u-axis coordinate of the center. + * \param[in] v_c The vertical v-axis coordinate of the center. + * \param[in] umin_roi The u-coordinate of the left axis of the RoI. + * \param[in] umax_roi The u-coordinate of the right axis of the RoI. + * \param[in] vmin_roi The v-coordinate of the top axis of the RoI. + * \param[in] vmax_roi The v-coordinate of the bottom axis of the RoI. + * \param[in] radius The radius of the circle. + * \param[out] delta_theta The length of the angular interval that is in the RoI. + */ +void computeIntersectionsAllAxes(const float &u_c, const float &v_c, const float &umin_roi, const float &umax_roi, + const float &vmin_roi, const float &vmax_roi, const float &radius, float &delta_theta) +{ + // Computing the intersections with the top and left axes + std::pair crossing_theta_u_min, crossing_theta_u_max; + std::pair crossing_theta_v_min, crossing_theta_v_max; + float crossing_u_top = vmin_roi; // We cross the u-axis of the top axis of the RoI at the minimum v-coordinate of the RoI + float crossing_v_left = umin_roi; // We cross the v-axis of the left of the RoI at the minimum u-coordinate of the RoI + computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u_top, crossing_v_left, + crossing_theta_u_min, crossing_theta_u_max, + crossing_theta_v_min, crossing_theta_v_max); + float theta_u_min_top = crossing_theta_u_min.first; + float theta_u_max_top = crossing_theta_u_max.first; + // float u_umin_top = crossing_theta_u_min.second; + // float u_umax_top = crossing_theta_u_max.second; + float theta_v_min_left = crossing_theta_v_min.first; + float theta_v_max_left = crossing_theta_v_max.first; + // float v_vmin_left = crossing_theta_v_min.second; + // float v_vmax_left = crossing_theta_v_max.second; + + // Computing the intersections with the bottom and right axes + float crossing_u_bottom = vmax_roi; // We cross the u-axis of the RoI at the maximum v-coordinate of the RoI + float crossing_v_right = umax_roi; // We cross the v-axis of the right of the RoI at the maximum u-coordinate of the RoI + computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u_bottom, crossing_v_right, + crossing_theta_u_min, crossing_theta_u_max, + crossing_theta_v_min, crossing_theta_v_max); + float theta_u_min_bottom = crossing_theta_u_min.first; + float theta_u_max_bottom = crossing_theta_u_max.first; + // float u_umin_bottom = crossing_theta_u_min.second; + // float u_umax_bottom = crossing_theta_u_max.second; + float theta_v_min_right = crossing_theta_v_min.first; + float theta_v_max_right = crossing_theta_v_max.first; + // float v_vmin_right = crossing_theta_v_min.second; + // float v_vmax_right = crossing_theta_v_max.second; + delta_theta = (theta_v_min_left - theta_u_min_top) + (theta_u_max_top -theta_v_min_right); + delta_theta += (theta_v_max_right - theta_u_max_bottom) + (theta_u_min_bottom - theta_v_max_left); +} + float vpImageCircle::computeArcLengthInRoI(const vpRect &roi) const { - float deltaTheta = 0.f; + float delta_theta = 0.f; vpImagePoint center = m_center; - float center_u = center.get_u(); - float center_v = center.get_v(); + float u_c = center.get_u(); + float v_c = center.get_v(); float radius = m_radius; float roi_w = roi.getWidth(); float roi_h = roi.getHeight(); @@ -723,93 +940,94 @@ float vpImageCircle::computeArcLengthInRoI(const vpRect &roi) const float vmin_roi = topLeft.get_v(); float umax_roi = topLeft.get_u() + roi_w; float vmax_roi = topLeft.get_v() + roi_h; - bool touchLeftBorder = (center_u - radius) <= umin_roi; - bool touchRightBorder = (center_u + radius) >= umax_roi; - bool touchTopBorder = (center_v - radius) <= vmin_roi; - bool touchBottomBorder = (center_v + radius) >= vmax_roi; + bool touchLeftBorder = (u_c - radius) <= umin_roi; + bool touchRightBorder = (u_c + radius) >= umax_roi; + bool touchTopBorder = (v_c - radius) <= vmin_roi; + bool touchBottomBorder = (v_c + radius) >= vmax_roi; bool isHorizontallyOK = (!touchLeftBorder && !touchRightBorder); bool isVerticallyOK = (!touchTopBorder && !touchBottomBorder); if (isHorizontallyOK && isVerticallyOK && roi.isInside(m_center)) { // Easy case // The circle has its center in the image and its radius is not too great // to make it fully contained in the RoI - deltaTheta = 2.f * M_PI; + delta_theta = 2.f * M_PI; } else if (touchBottomBorder && !touchLeftBorder && !touchRightBorder && !touchTopBorder) { // Touches/intersects only the bottom border of the RoI std::cout << "Case bottom only" << std::endl; - computeIntersectionsBottomBorderOnly(center_v, vmax_roi, radius, deltaTheta); + computeIntersectionsBottomBorderOnly(v_c, vmax_roi, radius, delta_theta); } else if (!touchBottomBorder && touchLeftBorder && !touchRightBorder && !touchTopBorder) { // Touches/intersects only the left border of the RoI std::cout << "Case left only" << std::endl; - computeIntersectionsLeftBorderOnly(center_u, umin_roi, radius, deltaTheta); + computeIntersectionsLeftBorderOnly(u_c, umin_roi, radius, delta_theta); } else if (!touchBottomBorder && !touchLeftBorder && touchRightBorder && !touchTopBorder) { // Touches/intersects only the right border of the RoI std::cout << "Case right only" << std::endl; - computeIntersectionsRightBorderOnly(center_u, umax_roi, radius, deltaTheta); + computeIntersectionsRightBorderOnly(u_c, umax_roi, radius, delta_theta); } else if (!touchBottomBorder && !touchLeftBorder && !touchRightBorder && touchTopBorder) { // Touches/intersects only the top border of the RoI std::cout << "Case top only" << std::endl; - computeIntersectionsTopBorderOnly(center_v, vmin_roi, radius, deltaTheta); + computeIntersectionsTopBorderOnly(v_c, vmin_roi, radius, delta_theta); } else if (touchBottomBorder && touchLeftBorder && !touchRightBorder && !touchTopBorder) { // Touches/intersects the bottom and left borders of the RoI std::cout << "Case bottom / left" << std::endl; - computeIntersectionsBottomLeft(center_u, center_v, topLeft, roi_h, radius, deltaTheta); + computeIntersectionsBottomLeft(u_c, v_c, umin_roi, vmax_roi, radius, delta_theta); } else if (touchBottomBorder && !touchLeftBorder && touchRightBorder && !touchTopBorder) { // Touches/intersects the bottom and right borders of the RoI std::cout << "Case bottom / right" << std::endl; - computeIntersectionsBottomRight(center_u, center_v, vmax_roi, umax_roi, radius, deltaTheta); + computeIntersectionsBottomRight(u_c, v_c, vmax_roi, umax_roi, radius, delta_theta); } else if (!touchBottomBorder && touchLeftBorder && !touchRightBorder && touchTopBorder) { // Touches/intersects the top and left borders of the RoI std::cout << "Case top / left" << std::endl; - computeIntersectionsTopLeft(center_u, center_v, topLeft, radius, deltaTheta); + computeIntersectionsTopLeft(u_c, v_c, umin_roi, vmin_roi, radius, delta_theta); } else if (!touchBottomBorder && !touchLeftBorder && touchRightBorder && touchTopBorder) { // Touches/intersects the top and right borders of the RoI std::cout << "Case top / right" << std::endl; - computeIntersectionsTopRight(center_u, center_v, vmin_roi, umax_roi, radius, deltaTheta); + computeIntersectionsTopRight(u_c, v_c, vmin_roi, umax_roi, radius, delta_theta); } else if (touchBottomBorder && touchTopBorder && touchLeftBorder && !touchRightBorder) { // Touches/intersects the top, left and bottom borders of the RoI std::cout << "Case bottom / top / left" << std::endl; - computeIntersectionsTopLeftBottom(center_u, center_v, topLeft, roi_h, radius, deltaTheta); + computeIntersectionsTopLeftBottom(u_c, v_c, umin_roi, vmin_roi, vmax_roi, radius, delta_theta); } else if (touchBottomBorder && touchTopBorder && !touchLeftBorder && touchRightBorder) { // Touches/intersects the top, right and bottom borders of the RoI std::cout << "Case bottom / top / right" << std::endl; - computeIntersectionsTopRightBottom(center_u, center_v, topLeft, roi_w, roi_h, radius, deltaTheta); + computeIntersectionsTopRightBottom(u_c, v_c, umax_roi, vmin_roi, vmax_roi, radius, delta_theta); } else if (touchBottomBorder && touchTopBorder && !touchLeftBorder && !touchRightBorder) { // Touches/intersects the top and bottom borders of the RoI std::cout << "Case bottom / top only" << std::endl; - computeIntersectionsTopBottomOnly(center_u, center_v, vmin_roi, vmax_roi, radius, deltaTheta); + computeIntersectionsTopBottomOnly(u_c, v_c, vmin_roi, vmax_roi, radius, delta_theta); } else if (touchLeftBorder && touchRightBorder && touchTopBorder && !touchBottomBorder) { // Touches/intersects the top, left and right borders of the RoI std::cout << "Case top / right / left" << std::endl; - // computeOppositeAxesIntersections ? + computeIntersectionsLeftRightTop(u_c, v_c, umin_roi, umax_roi, vmin_roi, radius, delta_theta); } else if (touchLeftBorder && touchRightBorder && !touchTopBorder && touchBottomBorder) { // Touches/intersects the bottom, left and right borders of the RoI std::cout << "Case bottom / right / left" << std::endl; - // computeOppositeAxesIntersections ? + computeIntersectionsLeftRightBottom(u_c, v_c, umin_roi, umax_roi, vmax_roi, radius, delta_theta); } else if (touchLeftBorder && touchRightBorder && !touchTopBorder && !touchBottomBorder) { // Touches/intersects the bottom, left and right borders of the RoI - std::cout << "Case bottom / right / left" << std::endl; - // computeOppositeAxesIntersections ? + std::cout << "Case right / left only" << std::endl; + computeIntersectionsLeftRightOnly(u_c, v_c, umin_roi, vmin_roi, radius, delta_theta); } - else if (touchBottomBorder && touchLeftBorder && touchRightBorder && touchTopBorder) { + else { // Touches/intersects each axis std::cout << "Case all" << std::endl; + computeIntersectionsAllAxes(u_c, v_c, umin_roi, umax_roi, vmin_roi, vmax_roi, radius, delta_theta); } - float arcLength = deltaTheta * radius; + float arcLength = delta_theta * radius; return arcLength; } diff --git a/modules/core/test/tools/geometry/testImageCircle.cpp b/modules/core/test/tools/geometry/testImageCircle.cpp index 2903d3741f..31786fcb8e 100644 --- a/modules/core/test/tools/geometry/testImageCircle.cpp +++ b/modules/core/test/tools/geometry/testImageCircle.cpp @@ -67,10 +67,10 @@ int main() // Test with no intersections { - vpImageCircle noIntersect(vpImagePoint(HEIGHT / 2.f, WIDTH / 2.f), RADIUS); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(HEIGHT / 2.f, WIDTH / 2.f), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = 2.f * M_PI * RADIUS; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -79,7 +79,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test no intersection." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -89,10 +89,10 @@ int main() // Test circle touching borders of the RoI { vpRect roiSquare(OFFSET, OFFSET, HEIGHT, HEIGHT); - vpImageCircle noIntersect(vpImagePoint(OFFSET + HEIGHT / 2.f, OFFSET + HEIGHT / 2.f), HEIGHT / 2.f); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(OFFSET + HEIGHT / 2.f, OFFSET + HEIGHT / 2.f), HEIGHT / 2.f); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = 2.f * M_PI * HEIGHT / 2.f; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -101,7 +101,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test circle touching borders of the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -114,10 +114,10 @@ int main() // theta := 2 * PI / 3 float uc = OFFSET + 24.f; float vc = OFFSET + 100.f; - vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = 4.f * M_PI * RADIUS /3.f; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -126,7 +126,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test intersection left border, more than half a circle visible." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -139,10 +139,10 @@ int main() // theta := PI / 3 float uc = OFFSET - 24.f; float vc = OFFSET + 100.f; - vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = 2.f * M_PI * RADIUS /3.f; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -151,7 +151,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test intersection left border, less than half a circle visible." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -164,10 +164,10 @@ int main() // theta := PI float uc = OFFSET + RADIUS; float vc = OFFSET + 100.f; - vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = 2.f * M_PI * RADIUS; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -176,7 +176,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with circle touching the left border, all the circle is visible." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -189,10 +189,10 @@ int main() // theta := PI / 3 float uc = OFFSET + 616.f; float vc = OFFSET + 100.f; - vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = 4.f * M_PI * RADIUS /3.f; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -201,7 +201,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test intersection right border, more than half a circle visible." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -214,10 +214,10 @@ int main() // theta := 2 * PI / 3 float uc = OFFSET + 664.f; float vc = OFFSET + 100.f; - vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = 2.f * M_PI * RADIUS /3.f; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -226,7 +226,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test intersection right border, less than half a circle visible." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -239,10 +239,10 @@ int main() // theta := 0 float uc = OFFSET + WIDTH - RADIUS; float vc = OFFSET + 100.f; - vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = 2.f * M_PI * RADIUS; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -251,7 +251,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with circle touching the right border, all the circle is visible." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -265,10 +265,10 @@ int main() float theta = M_PI / 3.f; float uc = OFFSET + 100.f; float vc = OFFSET + RADIUS * sin(theta); - vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = 5.f * M_PI * RADIUS /3.f; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -277,7 +277,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test intersection top border, more than half a circle visible." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -291,10 +291,10 @@ int main() float theta = -2.f * M_PI/3.f; float uc = OFFSET + 100.f; float vc = OFFSET + RADIUS * std::sin(theta); - vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = M_PI * RADIUS /3.f; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -303,7 +303,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test intersection top border, less than half a circle visible." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -317,10 +317,10 @@ int main() float theta = M_PI_2; float uc = OFFSET + 100.f; float vc = OFFSET + RADIUS * sin(theta); - vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = 2.f * M_PI * RADIUS; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -329,7 +329,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with circle touching the top border, all the circle is visible." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -343,10 +343,10 @@ int main() float theta = -M_PI / 3.f; float uc = OFFSET + 100.f; float vc = OFFSET + HEIGHT + RADIUS * std::sin(theta); - vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = 5.f * M_PI * RADIUS /3.f; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -355,7 +355,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test intersection bottom border, more than half a circle visible." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -369,10 +369,10 @@ int main() float theta = M_PI / 3.f; float uc = OFFSET + 100.f; float vc = OFFSET + HEIGHT + RADIUS * std::sin(theta); - vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = M_PI * RADIUS /3.f; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -381,7 +381,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test intersection bottom border, less than half a circle visible." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -393,10 +393,10 @@ int main() // Formula: vc = OFFSET + HEIGHT - RADIUS * sin(theta) float uc = OFFSET + 100.f; float vc = OFFSET + HEIGHT - RADIUS; - vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = 2.f * M_PI * RADIUS; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -405,7 +405,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with circle touching the bottom border, all the circle is visible." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -420,10 +420,10 @@ int main() // => uc = umin - r cos(theta_v_max) vc = vmin + r sin(theta_u_top_max) float uc = OFFSET; float vc = OFFSET; - vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = M_PI_2 * RADIUS; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -432,7 +432,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the top and the left border, crossing each axis once in the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -452,10 +452,10 @@ int main() float uc = OFFSET - RADIUS * std::cos(theta_v_min); float vc = OFFSET + RADIUS * std::sin(theta_v_min) + 1.f; vc = std::max(vc, OFFSET + RADIUS * std::sin(-theta_v_min) + 1.f); - vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = M_PI_2 * RADIUS; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -464,7 +464,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the top and the left border but crossing only the left axis in the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -486,10 +486,10 @@ int main() float uc = OFFSET - RADIUS * std::cos(theta_u_top_min) + 1.f; uc = std::max(uc, OFFSET - RADIUS * std::cos((float)M_PI - theta_u_top_min) + 1.f); float vc = OFFSET + RADIUS * std::sin(theta_u_top_min); - vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = 0.2f * M_PI_2 * RADIUS; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -498,7 +498,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the top and the left border but crossing only the top axis in the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -531,10 +531,10 @@ int main() theta_v_max = theta_v_min; theta_v_min = temp; } - vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = ((theta_v_max - theta_u_top_min) + (theta_u_top_max - theta_v_min)) * RADIUS; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -543,7 +543,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the top and the left border crossing twice each axis ." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length = " << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -565,10 +565,10 @@ int main() float theta_v_max = -M_PI_2; float uc = OFFSET + WIDTH - RADIUS * std::cos(theta_v_max); float vc = OFFSET + RADIUS * std::sin(theta_u_top_min);; - vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = (M_PI_2 + M_PI / 3.f) * RADIUS; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -577,7 +577,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the top and the right border, crossing each axis once in the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -600,10 +600,10 @@ int main() float theta_v_min = -theta_v_max; float uc = OFFSET + WIDTH - RADIUS * std::cos(theta_v_max); float vc = RADIUS * std::sin(std::acos((OFFSET + WIDTH - uc)/RADIUS)) + OFFSET + 1.f; - vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = (2.f * M_PI - (theta_v_min - theta_v_max)) * RADIUS; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -612,7 +612,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the top and the right border, but crossing only the right border in the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -637,10 +637,10 @@ int main() float vc = OFFSET + RADIUS * std::sin(theta_u_top_min); float theta_v_min = std::asin((vc - OFFSET)/RADIUS) + 1.f; float uc = OFFSET + WIDTH - RADIUS * std::cos(theta_v_min); - vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = std::abs(theta_u_top_min - theta_u_top_max) * RADIUS; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -649,7 +649,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the top and the right border, but crossing only the top border in the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -682,10 +682,10 @@ int main() theta_v_min = theta_v_max; theta_v_max = temp; } - vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = (2.f * M_PI - ((theta_u_top_min - theta_u_top_max) + (theta_v_min - theta_v_max))) * RADIUS; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -694,7 +694,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the top and the left border crossing twice each axis ." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length = " << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -716,10 +716,10 @@ int main() float theta_u_bot_max = -M_PI / 3.f; float uc = OFFSET - RADIUS * std::cos(theta_v_min); float vc = OFFSET + HEIGHT + RADIUS * std::sin(theta_u_bot_max);; - vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = (M_PI_2 + M_PI / 3.f) * RADIUS; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -728,7 +728,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the bottom and the left border, crossing each axis once in the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -752,10 +752,10 @@ int main() float theta_v_max = -theta_v_min; float uc = OFFSET - RADIUS * std::cos(theta_v_min); float vc = std::min(OFFSET + HEIGHT + RADIUS * std::sin(theta_v_min) - 1.f, OFFSET + HEIGHT + RADIUS * std::sin(theta_v_max) - 1.f); - vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = (2.f * theta_v_min) * RADIUS; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -764,7 +764,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the bottom and the left border, but crossing only the left border in the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -788,10 +788,10 @@ int main() float theta_u_bot_max = M_PI - theta_u_bot_min; float vc = OFFSET + HEIGHT + RADIUS * std::sin(theta_u_bot_min); float uc = std::max(OFFSET - RADIUS * std::cos(theta_u_bot_min) + 1.f, OFFSET - RADIUS * std::cos(theta_u_bot_max) + 1.f); - vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = (theta_u_bot_min - theta_u_bot_max) * RADIUS; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -800,7 +800,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the bottom and the left border, but crossing only the bottom border in the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -827,10 +827,10 @@ int main() float theta_v_max = -theta_v_min; float vc = OFFSET + HEIGHT + RADIUS * std::sin(theta_u_bot_min); float uc = OFFSET - RADIUS * std::cos(theta_v_min); - vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = ((theta_v_min - theta_u_bot_max) + (theta_u_bot_min - theta_v_max)) * RADIUS; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -839,7 +839,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the bottom and the left border, crossing each axis twice in the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -861,10 +861,10 @@ int main() float theta_v_min = M_PI_2; float uc = OFFSET + WIDTH - RADIUS * std::cos(theta_v_min); float vc = OFFSET + HEIGHT + RADIUS * std::sin(theta_u_bot_min);; - vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = (M_PI_2 + M_PI / 3.f) * RADIUS; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -873,7 +873,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the bottom and the right border, crossing each axis once in the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -895,10 +895,10 @@ int main() float theta_v_min = 5.f * M_PI / 6.f; float uc = OFFSET + WIDTH - RADIUS * std::cos(theta_v_min); float vc = std::min(OFFSET + HEIGHT + RADIUS * std::sin(theta_v_min) - 1.f, OFFSET + HEIGHT + RADIUS * std::sin(-theta_v_min) - 1.f); - vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = (M_PI / 3.f) * RADIUS; // <=> 2.f * M_PI / 6.f - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -907,7 +907,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the bottom and the right border, crossing only the right axis in the RoI in the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -929,10 +929,10 @@ int main() float theta_u_bot_min = 4.f * M_PI / 6.f; float vc = OFFSET + HEIGHT + RADIUS * std::sin(theta_u_bot_min); float uc = std::min(OFFSET + WIDTH - RADIUS * std::cos(theta_u_bot_min) - 1.f, OFFSET + WIDTH - RADIUS * std::cos((float)M_PI -theta_u_bot_min) - 1.f); - vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = (M_PI / 3.f) * RADIUS; // <=> 2.f * M_PI / 6.f - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -941,7 +941,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the bottom and the right border, crossing only the bottom axis in the RoI in the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -968,10 +968,10 @@ int main() float theta_v_min = -theta_v_max; float vc = OFFSET + HEIGHT + RADIUS * std::sin(theta_u_bot_min); float uc = OFFSET - RADIUS * std::cos(theta_v_min); - vpImageCircle noIntersect(vpImagePoint(vc, uc), RADIUS); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = (2.f * M_PI - ((theta_v_min - theta_v_max) + (theta_u_bot_max - theta_u_bot_min))) * RADIUS; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -980,7 +980,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the bottom and the right border, crossing each axis twice in the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -1008,10 +1008,10 @@ int main() float vc = OFFSET + HEIGHT / 2.f; float radius = -(OFFSET - vc)/ std::sin(theta_u_top_min); float uc = OFFSET - radius * std::cos(theta_v_min); - vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = ((theta_v_min - theta_u_top_min) + (theta_u_top_max - theta_u_bottom_max) + (theta_u_bottom_min - theta_v_max)) * radius; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -1020,7 +1020,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the top, bottom and the left border, crossing each axis twice in the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -1046,10 +1046,10 @@ int main() float radius = HEIGHT; float vc = OFFSET + radius * std::sin(theta_u_top_min); float uc = OFFSET - radius * std::cos(theta_v_min); - vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = (theta_u_top_max - theta_u_bottom_max) * radius; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -1058,7 +1058,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the top, bottom and the left border, crossing only the top and bottom axes in the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -1085,10 +1085,10 @@ int main() float radius = HEIGHT / (2.f * std::sin(theta_u_top_min)); // vmin + h - vmin = (vc - r sin(-theta_u_top_min)) - (vc - r sin(theta_top_min)) float vc = OFFSET + radius * std::sin(theta_u_top_min); float uc = OFFSET - radius * std::cos(theta_v_min); - vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = (2.f * M_PI - ((theta_u_top_min - theta_u_top_max) + (theta_u_bottom_max - theta_u_bottom_min))) * radius; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -1097,7 +1097,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the top, bottom and the left border, crossing the top and bottom axes and touching the left axis in the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -1122,10 +1122,10 @@ int main() float radius = HEIGHT / 2.f; float vc = OFFSET + radius * std::sin(theta_u_top_min); float uc = OFFSET - radius * std::cos(theta_v_min); - vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = (theta_v_min - theta_v_max) * radius; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -1134,7 +1134,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the top, bottom and the left border, crossing only the left axis in the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -1159,10 +1159,10 @@ int main() float radius = HEIGHT / 2.f; float vc = OFFSET + radius * std::sin(theta_u_top_min); float uc = OFFSET - radius * std::cos(theta_v_min); - vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = (theta_v_min - theta_v_max) * radius; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -1171,7 +1171,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the top, bottom and the left border, crossing the left axis and touching the two others in the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -1196,10 +1196,10 @@ int main() float radius = HEIGHT / (std::sin(theta_u_top_max) - std::sin(theta_u_bot_max)); float uc = OFFSET - radius * std::cos(theta_v_max); float vc = OFFSET + radius * std::sin(theta_u_top_max); - vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = (theta_u_top_max - theta_v_max) * radius; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -1208,7 +1208,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the top, bottom and the left border, crossing only the top and left axes once in the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -1233,10 +1233,10 @@ int main() float radius = HEIGHT / (std::sin(theta_u_top_max) - std::sin(theta_u_bot_max)); float uc = OFFSET - radius * std::cos(theta_v_min); float vc = OFFSET + radius * std::sin(theta_u_top_max); - vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = (theta_v_min - theta_u_bot_max) * radius; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -1245,7 +1245,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the top, bottom and the left border, crossing the bottom and left axis once in the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -1273,10 +1273,10 @@ int main() float vc = OFFSET + HEIGHT / 2.f; float radius = -(OFFSET - vc)/ std::sin(theta_u_top_min); float uc = OFFSET + WIDTH - radius * std::cos(theta_v_min); - vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = (2.f * M_PI - ((theta_u_top_min - theta_u_top_max) + (theta_v_min - theta_v_max) + (theta_u_bottom_max - theta_u_bottom_min))) * radius; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -1285,7 +1285,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the top, bottom and the right border, crossing each axis twice in the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -1310,10 +1310,10 @@ int main() float radius = HEIGHT; float vc = OFFSET + radius * std::sin(theta_u_top_min); float uc = OFFSET + WIDTH - radius * std::cos(theta_v_min); - vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = (2.f * M_PI - (theta_u_top_min - theta_u_bottom_min)) * radius; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -1322,7 +1322,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the top, bottom and the right border, crossing only the top and bottom axes in the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -1349,10 +1349,10 @@ int main() float radius = HEIGHT / (2.f * std::sin(theta_u_top_min)); // vmin + h - vmin = (vc - r sin(-theta_u_top_min)) - (vc - r sin(theta_top_min)) float vc = OFFSET + radius * std::sin(theta_u_top_min); float uc = OFFSET + WIDTH - radius * std::cos(theta_v_min); - vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = (2.f * M_PI - ((theta_u_top_min - theta_u_top_max) + (theta_u_bottom_max - theta_u_bottom_min))) * radius; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -1361,7 +1361,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the top, bottom and the right border, crossing the top and bottom axes and touching the right axis in the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -1386,10 +1386,10 @@ int main() float radius = HEIGHT / 2.f; float vc = OFFSET + radius * std::sin(theta_u_top_min); float uc = OFFSET + WIDTH - radius * std::cos(theta_v_min); - vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = (2.f * M_PI - (theta_v_min - theta_v_max)) * radius; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -1398,7 +1398,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the top, bottom and the right border, crossing only the right axis in the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -1423,10 +1423,10 @@ int main() float radius = HEIGHT / 2.f; float vc = OFFSET + radius * std::sin(theta_u_top_min); float uc = OFFSET + WIDTH - radius * std::cos(theta_v_min); - vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = (2.f * M_PI - (theta_v_min - theta_v_max)) * radius; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -1435,7 +1435,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the top, bottom and the right border, crossing the right axis and touching the two others in the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -1460,10 +1460,10 @@ int main() float radius = HEIGHT / (std::sin(theta_u_top_min) - std::sin(theta_u_bot_min)); float uc = OFFSET + WIDTH - radius * std::cos(theta_v_max); float vc = OFFSET + radius * std::sin(theta_u_top_min); - vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = (2.f * M_PI - (theta_u_top_min - theta_v_max)) * radius; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -1472,7 +1472,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the top, bottom and the right border, crossing the top and right axis once in the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -1497,10 +1497,10 @@ int main() float radius = HEIGHT / (std::sin(theta_u_top_min) - std::sin(theta_u_bot_min)); float uc = OFFSET + WIDTH - radius * std::cos(theta_v_min); float vc = OFFSET + radius * std::sin(theta_u_top_min); - vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = (theta_u_bot_min - theta_v_min) * radius; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -1509,7 +1509,7 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the top, bottom and the right border, crossing the bottom and right axis once in the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; @@ -1533,10 +1533,10 @@ int main() float vc = OFFSET + HEIGHT / 2.f; float radius = -(OFFSET - vc)/ std::sin(theta_u_top_min); - vpImageCircle noIntersect(vpImagePoint(vc, uc), radius); - float arcLengthNoIntersect = noIntersect.computeArcLengthInRoI(roi); + vpImageCircle circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); float theoreticalValue = (2.f * M_PI - ((theta_u_top_min - theta_u_top_max) + (theta_u_bottom_max - theta_u_bottom_min))) * radius; - bool isValueOK = compareAngles(arcLengthNoIntersect, theoreticalValue); + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; if (isValueOK) { statusTest = "SUCCESS"; @@ -1545,7 +1545,38 @@ int main() statusTest = "FAILED"; } std::cout << "Test with intersections with the top and bottom borders only, crossing each axis twice in the RoI." << std::endl; - std::cout << "\tarc length =" << arcLengthNoIntersect << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + + // Test intersections with all the axis + { + // Choosing theta_v_left_min = 7 PI / 8 and circle at the center of the RoI + // umin = uc + r cos(theta_v_left_min) => r = (umin - uc) / cos(theta_v_left_min) + vpRect squareRoI(OFFSET, OFFSET, HEIGHT, HEIGHT); + float theta_v_left_min = 7.f * M_PI / 8.f; + float uc = OFFSET + HEIGHT / 2.f; + float vc = OFFSET + HEIGHT / 2.f; + float radius = (OFFSET - uc) / std::cos(theta_v_left_min); + std::cout << "uc = " << uc << "\tvc = " << vc << "\tr = " << radius << std::endl; + std::cout << "roi = " << squareRoI << std::endl; + + vpImageCircle circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(squareRoI); + float theoreticalValue = M_PI * radius; + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the top and bottom borders only, crossing each axis twice in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; std::cout << "\ttest status = " << statusTest << std::endl; From fc7500a32bebe60bc325e899bfdcb6c39de513d0 Mon Sep 17 00:00:00 2001 From: rlagneau Date: Mon, 2 Oct 2023 11:40:24 +0200 Subject: [PATCH 18/22] [FIX] Fixed typos when the left and right axes are the only axes that are crossed --- modules/core/src/image/vpImageCircle.cpp | 20 ++++------ .../test/tools/geometry/testImageCircle.cpp | 39 ++++++++++++++++++- 2 files changed, 45 insertions(+), 14 deletions(-) diff --git a/modules/core/src/image/vpImageCircle.cpp b/modules/core/src/image/vpImageCircle.cpp index 2b974e8ef1..b6788b4540 100644 --- a/modules/core/src/image/vpImageCircle.cpp +++ b/modules/core/src/image/vpImageCircle.cpp @@ -834,7 +834,7 @@ void computeIntersectionsLeftRightOnly(const float &u_c, const float &v_c, const // Computing the corresponding v-coordinates at which the v-axis is crossed float v_vcross_left = v_c - radius * std::sin(theta_v_cross_left); - float v_vcross_left_2 = v_c + radius * std::sin(theta_v_cross_left_2); + float v_vcross_left_2 = v_c - radius * std::sin(theta_v_cross_left_2); // Sorting the outputs such as v(theta_v_cross_left_min) < v(theta_v_cross_left_max) float theta_v_cross_left_min = 0.f, theta_v_cross_left_max = 0.f; if (v_vcross_left < v_vcross_left_2) { @@ -856,7 +856,7 @@ void computeIntersectionsLeftRightOnly(const float &u_c, const float &v_c, const // Computing the corresponding v-coordinates at which the v-axis is crossed float v_vcross_right = v_c - radius * std::sin(theta_v_cross_right); - float v_vcross_right_2 = v_c + radius * std::sin(theta_v_cross_right_2); + float v_vcross_right_2 = v_c - radius * std::sin(theta_v_cross_right_2); // Sorting the outputs such as v(theta_v_cross_right_min) < v(theta_v_cross_right_max) float theta_v_cross_right_min = 0.f, theta_v_cross_right_max = 0.f; @@ -901,12 +901,8 @@ void computeIntersectionsAllAxes(const float &u_c, const float &v_c, const float crossing_theta_v_min, crossing_theta_v_max); float theta_u_min_top = crossing_theta_u_min.first; float theta_u_max_top = crossing_theta_u_max.first; - // float u_umin_top = crossing_theta_u_min.second; - // float u_umax_top = crossing_theta_u_max.second; float theta_v_min_left = crossing_theta_v_min.first; float theta_v_max_left = crossing_theta_v_max.first; - // float v_vmin_left = crossing_theta_v_min.second; - // float v_vmax_left = crossing_theta_v_max.second; // Computing the intersections with the bottom and right axes float crossing_u_bottom = vmax_roi; // We cross the u-axis of the RoI at the maximum v-coordinate of the RoI @@ -916,12 +912,8 @@ void computeIntersectionsAllAxes(const float &u_c, const float &v_c, const float crossing_theta_v_min, crossing_theta_v_max); float theta_u_min_bottom = crossing_theta_u_min.first; float theta_u_max_bottom = crossing_theta_u_max.first; - // float u_umin_bottom = crossing_theta_u_min.second; - // float u_umax_bottom = crossing_theta_u_max.second; float theta_v_min_right = crossing_theta_v_min.first; float theta_v_max_right = crossing_theta_v_max.first; - // float v_vmin_right = crossing_theta_v_min.second; - // float v_vmax_right = crossing_theta_v_max.second; delta_theta = (theta_v_min_left - theta_u_min_top) + (theta_u_max_top -theta_v_min_right); delta_theta += (theta_v_max_right - theta_u_max_bottom) + (theta_u_min_bottom - theta_v_max_left); } @@ -950,6 +942,7 @@ float vpImageCircle::computeArcLengthInRoI(const vpRect &roi) const // Easy case // The circle has its center in the image and its radius is not too great // to make it fully contained in the RoI + std::cout << "Case fully OK" << std::endl; delta_theta = 2.f * M_PI; } else if (touchBottomBorder && !touchLeftBorder && !touchRightBorder && !touchTopBorder) { @@ -1020,13 +1013,16 @@ float vpImageCircle::computeArcLengthInRoI(const vpRect &roi) const else if (touchLeftBorder && touchRightBorder && !touchTopBorder && !touchBottomBorder) { // Touches/intersects the bottom, left and right borders of the RoI std::cout << "Case right / left only" << std::endl; - computeIntersectionsLeftRightOnly(u_c, v_c, umin_roi, vmin_roi, radius, delta_theta); + computeIntersectionsLeftRightOnly(u_c, v_c, umin_roi, umax_roi, radius, delta_theta); } - else { + else if (touchLeftBorder && touchRightBorder && touchTopBorder && touchBottomBorder) { // Touches/intersects each axis std::cout << "Case all" << std::endl; computeIntersectionsAllAxes(u_c, v_c, umin_roi, umax_roi, vmin_roi, vmax_roi, radius, delta_theta); } + else { + throw(vpException(vpException::fatalError, "This case should never happen. Please contact Inria to make fix the problem")); + } float arcLength = delta_theta * radius; return arcLength; } diff --git a/modules/core/test/tools/geometry/testImageCircle.cpp b/modules/core/test/tools/geometry/testImageCircle.cpp index 31786fcb8e..1f3f1c2119 100644 --- a/modules/core/test/tools/geometry/testImageCircle.cpp +++ b/modules/core/test/tools/geometry/testImageCircle.cpp @@ -1552,6 +1552,43 @@ int main() hasSucceeded &= isValueOK; } + // Test with intersections with the right and left only, + // crossing each axis twice in the RoI + { + // (2): u_min = uc + r cos(theta_v_left_min) ; v_cross_left_min = vc - r sin(theta_v_left_min) > vmin_roi + // (4): u_min = uc + r cos(theta_v_left_max) ; v_cross_left_max = vc - r sin(theta_v_left_max) < vmax_roi + // (5): u_min + width = uc + r cos(theta_v_right_min); v_cross_right_min = vc - r sin(theta_v_right_min) + // (6): u_min + width = uc + r cos(theta_v_right_max); v_cross_right_max = vc - r sin(theta_v_right_max) + // (2) & (4) theta_v_left_min = - theta_v_left_max + // (5) & (6) theta_v_right_min = - theta_v_right_max + vpRect invertedRoI(OFFSET, OFFSET, HEIGHT, WIDTH); + float theta_v_left_min = 5.f * M_PI / 6.f; + float theta_v_left_max = -theta_v_left_min; + float theta_v_right_min = M_PI / 6.f; + float theta_v_right_max = -theta_v_right_min; + float uc = OFFSET + HEIGHT / 2.f; + float vc = OFFSET + WIDTH / 2.f; + float radius = (OFFSET - uc)/ std::cos(theta_v_left_min); + + vpImageCircle circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(invertedRoI); + float theoreticalValue = ((theta_v_left_min - theta_v_right_min) + (theta_v_right_max - theta_v_left_max)) * radius; + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the right and left borders only, crossing each axis twice in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + // Test intersections with all the axis { // Choosing theta_v_left_min = 7 PI / 8 and circle at the center of the RoI @@ -1561,8 +1598,6 @@ int main() float uc = OFFSET + HEIGHT / 2.f; float vc = OFFSET + HEIGHT / 2.f; float radius = (OFFSET - uc) / std::cos(theta_v_left_min); - std::cout << "uc = " << uc << "\tvc = " << vc << "\tr = " << radius << std::endl; - std::cout << "roi = " << squareRoI << std::endl; vpImageCircle circle(vpImagePoint(vc, uc), radius); float arcLengthCircle = circle.computeArcLengthInRoI(squareRoI); From 19f36b7bf50f0d52aeb62b25b1679fdb73364839 Mon Sep 17 00:00:00 2001 From: rlagneau Date: Mon, 2 Oct 2023 16:20:22 +0200 Subject: [PATCH 19/22] [FIX] Fixed some typos in the left/right/top case + tested all the cases corresponding to this case --- modules/core/src/image/vpImageCircle.cpp | 11 +- .../test/tools/geometry/testImageCircle.cpp | 200 +++++++++++++++++- 2 files changed, 206 insertions(+), 5 deletions(-) diff --git a/modules/core/src/image/vpImageCircle.cpp b/modules/core/src/image/vpImageCircle.cpp index b6788b4540..60321ffeea 100644 --- a/modules/core/src/image/vpImageCircle.cpp +++ b/modules/core/src/image/vpImageCircle.cpp @@ -736,7 +736,7 @@ void computeIntersectionsLeftRightTop(const float &u_c, const float &v_c, const std::cout << "\t|-> case top only" << std::endl; computeIntersectionsTopBorderOnly(v_c, vmin_roi, radius, delta_theta); } - else if (u_umax >= umin_roi && v_vmax_right >= vmin_roi) { + else if (u_umax >= umin_roi && v_vmax_left >= vmin_roi) { std::cout << "\t|-> case top/left corner" << std::endl; computeIntersectionsTopLeft(u_c, v_c, umin_roi, vmin_roi, radius, delta_theta); } @@ -1000,12 +1000,12 @@ float vpImageCircle::computeArcLengthInRoI(const vpRect &roi) const std::cout << "Case bottom / top only" << std::endl; computeIntersectionsTopBottomOnly(u_c, v_c, vmin_roi, vmax_roi, radius, delta_theta); } - else if (touchLeftBorder && touchRightBorder && touchTopBorder && !touchBottomBorder) { + else if (!touchBottomBorder && touchTopBorder && touchLeftBorder && touchRightBorder) { // Touches/intersects the top, left and right borders of the RoI std::cout << "Case top / right / left" << std::endl; computeIntersectionsLeftRightTop(u_c, v_c, umin_roi, umax_roi, vmin_roi, radius, delta_theta); } - else if (touchLeftBorder && touchRightBorder && !touchTopBorder && touchBottomBorder) { + else if (touchBottomBorder && !touchTopBorder && touchLeftBorder && touchRightBorder) { // Touches/intersects the bottom, left and right borders of the RoI std::cout << "Case bottom / right / left" << std::endl; computeIntersectionsLeftRightBottom(u_c, v_c, umin_roi, umax_roi, vmax_roi, radius, delta_theta); @@ -1021,6 +1021,11 @@ float vpImageCircle::computeArcLengthInRoI(const vpRect &roi) const computeIntersectionsAllAxes(u_c, v_c, umin_roi, umax_roi, vmin_roi, vmax_roi, radius, delta_theta); } else { + std::cerr << "touchLeft = " << (touchLeftBorder ? "true" : "false") << "\ttouchRight = " << (touchRightBorder ? "true" : "false") << std::endl; + std::cerr << "touchTop = " << (touchTopBorder ? "true" : "false") << "\ttouchBottom = " << (touchBottomBorder ? "true" : "false") << std::endl; + std::cerr << "u_c = " << u_c << "\tv_c = " << v_c << "\tradius = " << radius << std::endl; + std::cerr << "umin_roi = " << umin_roi << "\tumax_roi = " << umax_roi << std::endl; + std::cerr << "vmin_roi = " << vmin_roi << "\tvmax_roi = " << vmax_roi << std::endl << std::flush; throw(vpException(vpException::fatalError, "This case should never happen. Please contact Inria to make fix the problem")); } float arcLength = delta_theta * radius; diff --git a/modules/core/test/tools/geometry/testImageCircle.cpp b/modules/core/test/tools/geometry/testImageCircle.cpp index 1f3f1c2119..249e5f3f7f 100644 --- a/modules/core/test/tools/geometry/testImageCircle.cpp +++ b/modules/core/test/tools/geometry/testImageCircle.cpp @@ -63,6 +63,9 @@ int main() const float HEIGHT = 480.f; const float RADIUS = std::min(WIDTH, HEIGHT) / 10.f; vpRect roi(OFFSET, OFFSET, WIDTH, HEIGHT); + const float WIDTH_SWITCHED = HEIGHT; // The RoI must be inverted in order to cross left and right axes while crossing only the top axis + const float HEIGHT_SWITCHED = WIDTH; // The RoI must be inverted in order to cross left and right axes while crossing only the top axis + vpRect switchedRoI(OFFSET, OFFSET, WIDTH_SWITCHED, HEIGHT_SWITCHED); bool hasSucceeded = true; // Test with no intersections @@ -1516,6 +1519,200 @@ int main() hasSucceeded &= isValueOK; } + // Test with intersections with the top, left and the right border + // crossing each axis twice + { + // (1): u_cross_top_min = uc + r cos(theta_u_top_min) >= umin_roi ; vmin_roi = vc - r sin(theta_u_top_min) + // (2): umin_roi = uc + r cos(theta_v_left_min); v_cross_left_min = vc - r sin(theta_v_left_min) >= vmin_roi + // (3): u_cross_top_max = uc + r cos(theta_u_top_max) <= umin_roi + width ; vmin_roi = vc - r sin(theta_u_top_max) + // (4): umin_roi = uc + r cos(theta_v_left_max); v_cross_left_max = vc - r sin(theta_v_left_max) <= vmin_roi + height + // (5): umin_roi + width = uc + r cos(theta_v_right_min) ; v_cross_right_min = vc - r sin(theta_v_right_min) + // (6): umin_roi + width = uc + r cos(theta_v_right_max) ; v_cross_right_max = vc - r sin(theta_v_right_max) + // (5) - (2) width = r (cos(theta_v_right_min) - cos(theta_v_left_min)) + // (1) & (3) theta_u_top_min = PI - theta_u_top_max + // (2) & (4) theta_v_left_min = - theta_v_left_max + // (5) & (6) theta_v_right_min = - theta_v_right_max + + float theta_v_left_min = 7.f * M_PI / 8.f; + float theta_v_left_max = -theta_v_left_min; + float theta_v_right_min = M_PI / 8.f; + float theta_v_right_max = -theta_v_right_min; + float theta_u_top_min = 5.f * M_PI / 8.f; + float theta_u_top_max = M_PI - theta_u_top_min; + float radius = WIDTH_SWITCHED / (std::cos(theta_v_right_min) - std::cos(theta_v_left_min)); + float uc = OFFSET + WIDTH_SWITCHED - radius * std::cos(theta_v_right_min); + float vc = OFFSET + radius * std::sin(theta_u_top_min); + vpImageCircle circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(switchedRoI); + float theoreticalValue = ((theta_v_left_min - theta_u_top_min) + (theta_u_top_max - theta_v_right_min) + (theta_v_right_max - theta_v_left_max)) * radius; + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the top, left and the right border, crossing each axis twice in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + + // Test with intersections with the top, left and the right border + // crossing only the top axis + { + // (1): u_cross_top_min = uc + r cos(theta_u_top_min) >= umin_roi ; vmin_roi = vc - r sin(theta_u_top_min) + // (2): umin_roi = uc + r cos(theta_v_left_min); v_cross_left_min = vc - r sin(theta_v_left_min) < vmin_roi + // (3): u_cross_top_max = uc + r cos(theta_u_top_max) <= umin_roi + width ; vmin_roi = vc - r sin(theta_u_top_max) + // (4): umin_roi = uc + r cos(theta_v_left_max); v_cross_left_max = vc - r sin(theta_v_left_max) <= vmin_roi + // (5): umin_roi + width = uc + r cos(theta_v_right_min) ; v_cross_right_min = vc - r sin(theta_v_right_min) < vmin_roi + // (6): umin_roi + width = uc + r cos(theta_v_right_max) ; v_cross_right_max = vc - r sin(theta_v_right_max) <= vmin_roi + // (1) & (3) theta_u_top_min = PI - theta_u_top_max + // (2) & (4) theta_v_left_min = - theta_v_left_max + // (5) & (6) theta_v_right_min = - theta_v_right_max + + float theta_u_top_min = -2.f * M_PI / 3.f; + float uc = OFFSET + WIDTH_SWITCHED/2.f; + float vc = OFFSET + RADIUS * std::sin(theta_u_top_min); + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(switchedRoI); + float theoreticalValue = (M_PI/3.f) * RADIUS; + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the top, left and the right border, crossing only the top axis." << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + + // Test with intersections with the top, left and the right border + // crossing left right only + { + // (1): u_cross_top_min = uc + r cos(theta_u_top_min) <= umin_roi ; vmin_roi = vc - r sin(theta_u_top_min) + // (2): umin_roi = uc + r cos(theta_v_left_min); v_cross_left_min = vc - r sin(theta_v_left_min) < vmin_roi + // (3): u_cross_top_max = uc + r cos(theta_u_top_max) >= umin_roi + width ; vmin_roi = vc - r sin(theta_u_top_max) + // (4): umin_roi = uc + r cos(theta_v_left_max); v_cross_left_max = vc - r sin(theta_v_left_max) <= vmin_roi + height + // (5): umin_roi + width = uc + r cos(theta_v_right_min) ; v_cross_right_min = vc - r sin(theta_v_right_min) < vmin_roi + // (6): umin_roi + width = uc + r cos(theta_v_right_max) ; v_cross_right_max = vc - r sin(theta_v_right_max) <= vmin_roi + height + // (6) - (3) width = r (cos(theta_v_right_max) - cos(theta_v_left_max)) + // (1) & (3) theta_u_top_min = PI - theta_u_top_max + // (2) & (4) theta_v_left_min = - theta_v_left_max + // (5) & (6) theta_v_right_min = - theta_v_right_max + + float theta_v_left_max = -5.f * M_PI / 8.f; + float theta_v_right_max = -3.f *M_PI / 8.f; + float theta_u_top_min = -7.f * M_PI / 8.f; + float radius = WIDTH_SWITCHED / (std::cos(theta_v_right_max) - std::cos(theta_v_left_max)); + float uc = OFFSET - radius * std::cos(theta_v_left_max); + float vc = OFFSET + radius * std::sin(theta_u_top_min); + vpImageCircle circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(switchedRoI); + float theoreticalValue = (theta_v_right_max - theta_v_left_max) * radius; + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the top, left and the right border, crossing only left right in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + + // Test with intersections with the top, left and the right border + // crossing only the top and left axes + { + // (1): u_cross_top_min = uc + r cos(theta_u_top_min) < umin_roi ; vmin_roi = vc - r sin(theta_u_top_min) + // (2): umin_roi = uc + r cos(theta_v_left_min); v_cross_left_min = vc - r sin(theta_v_left_min) < vmin_roi + // (3): u_cross_top_max = uc + r cos(theta_u_top_max) >= umin_roi ; vmin_roi = vc - r sin(theta_u_top_max) + // (4): umin_roi = uc + r cos(theta_v_left_max); v_cross_left_max = vc - r sin(theta_v_left_max) >= vmin_roi + // (5): umin_roi + width = uc + r cos(theta_v_right_min) ; v_cross_right_min = vc - r sin(theta_v_right_min) < vmin_roi + // (6): umin_roi + width = uc + r cos(theta_v_right_max) ; v_cross_right_max = vc - r sin(theta_v_right_max) <= vmin_roi + // (6) - (4) => width = r (cos(theta_v_right_max) - cos(theta_v_left_max)) + // (1) & (3) theta_u_top_min = PI - theta_u_top_max + // (2) & (4) theta_v_left_min = - theta_v_left_max + // (5) & (6) theta_v_right_min = - theta_v_right_max + + float theta_u_top_max = -M_PI / 3.f; + float theta_v_right_max = 0; + float theta_v_left_max = -M_PI_2; + float radius = WIDTH_SWITCHED / (std::cos(theta_v_right_max) - std::cos(theta_v_left_max)); + float uc = OFFSET; + float vc = OFFSET + radius * std::sin(theta_u_top_max); + vpImageCircle circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(switchedRoI); + float theoreticalValue = (theta_u_top_max - theta_v_left_max) * radius; + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the top, left and the right border, crossing only the top and left axes." << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + + // Test with intersections with the top, left and the right border + // crossing only the top and right axes + { + // (1): u_cross_top_min = uc + r cos(theta_u_top_min) < umin_roi + width ; vmin_roi = vc - r sin(theta_u_top_min) + // (2): umin_roi = uc + r cos(theta_v_left_min); v_cross_left_min = vc - r sin(theta_v_left_min) < vmin_roi + // (3): u_cross_top_max = uc + r cos(theta_u_top_max) >= umin_roi + width ; vmin_roi = vc - r sin(theta_u_top_max) + // (4): umin_roi = uc + r cos(theta_v_left_max); v_cross_left_max = vc - r sin(theta_v_left_max) < vmin_roi + // (5): umin_roi + width = uc + r cos(theta_v_right_min) ; v_cross_right_min = vc - r sin(theta_v_right_min) < vmin_roi + // (6): umin_roi + width = uc + r cos(theta_v_right_max) ; v_cross_right_max = vc - r sin(theta_v_right_max) >= vmin_roi + // (6) - (4) => width = r (cos(theta_v_right_max) - cos(theta_v_left_max)) + // (1) & (3) theta_u_top_min = PI - theta_u_top_max + // (2) & (4) theta_v_left_min = - theta_v_left_max + // (5) & (6) theta_v_right_min = - theta_v_right_max + + float theta_u_top_min = -2.f * M_PI / 3.f; + float theta_v_left_max = M_PI; + float theta_v_right_max = -M_PI_2; + float radius = WIDTH_SWITCHED / (std::cos(theta_v_right_max) - std::cos(theta_v_left_max)); + float uc = OFFSET + WIDTH_SWITCHED; + float vc = OFFSET + radius * std::sin(theta_u_top_min); + vpImageCircle circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(switchedRoI); + float theoreticalValue = (theta_v_right_max - theta_u_top_min) * radius; + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the top, left and the right border, crossing only the top and right axes." << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + // Test with intersections with the top and bottom only, // crossing each axis twice in the RoI { @@ -1561,7 +1758,6 @@ int main() // (6): u_min + width = uc + r cos(theta_v_right_max); v_cross_right_max = vc - r sin(theta_v_right_max) // (2) & (4) theta_v_left_min = - theta_v_left_max // (5) & (6) theta_v_right_min = - theta_v_right_max - vpRect invertedRoI(OFFSET, OFFSET, HEIGHT, WIDTH); float theta_v_left_min = 5.f * M_PI / 6.f; float theta_v_left_max = -theta_v_left_min; float theta_v_right_min = M_PI / 6.f; @@ -1571,7 +1767,7 @@ int main() float radius = (OFFSET - uc)/ std::cos(theta_v_left_min); vpImageCircle circle(vpImagePoint(vc, uc), radius); - float arcLengthCircle = circle.computeArcLengthInRoI(invertedRoI); + float arcLengthCircle = circle.computeArcLengthInRoI(switchedRoI); float theoreticalValue = ((theta_v_left_min - theta_v_right_min) + (theta_v_right_max - theta_v_left_max)) * radius; bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); std::string statusTest; From 2bbd72f40ca9ddcdef060d8492770d6680e8806b Mon Sep 17 00:00:00 2001 From: rlagneau Date: Tue, 3 Oct 2023 08:51:11 +0200 Subject: [PATCH 20/22] [CORPS] The method vpImageCircle::computeArcLengthInRoI has been successfully tested =) --- .../core/include/visp3/core/vpImageCircle.h | 9 + modules/core/src/image/vpImageCircle.cpp | 100 ++++----- .../test/tools/geometry/testImageCircle.cpp | 197 +++++++++++++++++- 3 files changed, 250 insertions(+), 56 deletions(-) diff --git a/modules/core/include/visp3/core/vpImageCircle.h b/modules/core/include/visp3/core/vpImageCircle.h index c30467627d..33343e1f75 100644 --- a/modules/core/include/visp3/core/vpImageCircle.h +++ b/modules/core/include/visp3/core/vpImageCircle.h @@ -77,8 +77,17 @@ class VISP_EXPORT vpImageCircle */ virtual ~vpImageCircle(); + /*! + * Compute the angular coverage, in terms of radians, that is contained in the Region of Interest (RoI). + * \sa \ref vpImageCircle::computeArcLengthInRoI() "vpImageCircle::computeArcLengthInRoI(const vpRect &roi)" + * \param[in] roi The rectangular RoI in which we want to know the number of pixels of the circle that are contained. + * \return Returns 2.f * M_PI for a circle that is fully visible in the RoI, or the sum of the angles of the arc(s) that is(are) visible in the RoI. + */ + float computeAngularCoverageInRoI(const vpRect &roi) const; + /*! * Compute the arc length, in terms of number of pixels, that is contained in the Region of Interest (RoI). + * \sa \ref vpImageCircle::computeAngularCoverageInRoI() "vpImageCircle::computeAngularCoverageInRoI(const vpRect &roi)" * \param[in] roi The rectangular RoI in which we want to know the number of pixels of the circle that are contained. * \return The number of pixels of the circle that are contained in the RoI. */ diff --git a/modules/core/src/image/vpImageCircle.cpp b/modules/core/src/image/vpImageCircle.cpp index 60321ffeea..b8e49af9bd 100644 --- a/modules/core/src/image/vpImageCircle.cpp +++ b/modules/core/src/image/vpImageCircle.cpp @@ -305,24 +305,24 @@ void computeIntersectionsTopLeft(const float &u_c, const float &v_c, const float float v_vmax = crossing_theta_v_max.second; if (u_umin < umin_roi && u_umax >= umin_roi && v_vmin < vmin_roi && v_vmax >= vmin_roi) { // The circle crosses only once each axis - std::cout << "\t|->Case crossing once" << std::endl; + //Case crossing once delta_theta = theta_u_max - theta_v_max; } else if (u_umin >= umin_roi && u_umax >= umin_roi && v_vmin >= vmin_roi && v_vmax >= vmin_roi) { // The circle crosses twice each axis - std::cout << "\t|->Case crossing twice" << std::endl; + //Case crossing twice delta_theta = (theta_v_min - theta_u_min) + (theta_u_max - theta_v_max); } else if (u_umin < umin_roi && u_umax < umin_roi && v_vmin >= vmin_roi && v_vmax >= vmin_roi) { // The circle crosses the u-axis outside the roi // so it is equivalent to the case of crossing only the left border - std::cout << "\t|->Case left only" << std::endl; + //Case left only computeIntersectionsLeftBorderOnly(u_c, umin_roi, radius, delta_theta); } else if (u_umin >= umin_roi && u_umax >= umin_roi && v_vmin <= vmin_roi && v_vmax <= vmin_roi) { // The circle crosses the v-axis outside the roi // so it is equivalent to the case of crossing only the top border - std::cout << "\t|->Case top only" << std::endl; + //Case top only computeIntersectionsTopBorderOnly(v_c, vmin_roi, radius, delta_theta); } } @@ -354,7 +354,7 @@ void computeIntersectionsTopRight(const float &u_c, const float &v_c, const floa float v_vmax = crossing_theta_v_max.second; if (u_umin <= umax_roi && v_vmin < vmin_roi && u_umax >= umax_roi && v_vmax >= vmin_roi) { // The circle crosses only once each axis and the center is below the top border - std::cout << "\t|->Case crossing once" << std::endl; + //Case crossing once delta_theta = theta_v_max - theta_u_min; if (delta_theta < 0) { // The arc cannot be negative @@ -363,19 +363,19 @@ void computeIntersectionsTopRight(const float &u_c, const float &v_c, const floa } else if (u_umin <= umax_roi && v_vmin >= vmin_roi && u_umax <= umax_roi && v_vmax >= vmin_roi) { // The circle crosses twice each axis - std::cout << "\t|->Case crossing twice" << std::endl; + //Case crossing twice delta_theta = 2 * M_PI - ((theta_u_min - theta_u_max)+(theta_v_min - theta_v_max)); } else if (u_umin >= umax_roi && v_vmin >= vmin_roi && u_umax >= umax_roi && v_vmax >= vmin_roi) { // The circle crosses the u-axis outside the roi // so it is equivalent to the case of crossing only the right border - std::cout << "\t|->Case crossing right only" << std::endl; + //Case crossing right only computeIntersectionsRightBorderOnly(u_c, umax_roi, radius, delta_theta); } else if (u_umin <= umax_roi && v_vmin <= vmin_roi && u_umax <= umax_roi && v_vmax <= vmin_roi) { // The circle crosses the v-axis outside the roi // so it is equivalent to the case of crossing only the top border - std::cout << "\t|->Case crossing top only" << std::endl; + //Case crossing top only computeIntersectionsTopBorderOnly(v_c, vmin_roi, radius, delta_theta); } } @@ -409,24 +409,24 @@ void computeIntersectionsBottomLeft(const float &u_c, const float &v_c, const fl float v_vmax = crossing_theta_v_max.second; if (u_umin < umin_roi && u_umax >= umin_roi && v_vmin <= vmax_roi && v_vmax > vmax_roi) { // The circle crosses only once each axis - std::cout << "\t|->Case crossing once" << std::endl; + //Case crossing once delta_theta = theta_v_min - theta_u_max; } else if (u_umin >= umin_roi && u_umax >= umin_roi && v_vmin <= vmax_roi && v_vmax <= vmax_roi) { // The circle crosses twice each axis - std::cout << "\t|->Case crossing twice" << std::endl; + //Case crossing twice delta_theta = (theta_v_min - theta_u_max) + (theta_u_min - theta_v_max); } else if (u_umin < umin_roi && u_umax < umin_roi && v_vmin <= vmax_roi && v_vmax <= vmax_roi) { // The circle crosses the u-axis outside the roi // so it is equivalent to the case of crossing only the left border - std::cout << "\t|->Case left only" << std::endl; + //Case left only computeIntersectionsLeftBorderOnly(u_c, umin_roi, radius, delta_theta); } else if (u_umin >= umin_roi && u_umax >= umin_roi && v_vmin >= vmax_roi && v_vmax >= vmax_roi) { // The circle crosses the v-axis outside the roi // so it is equivalent to the case of crossing only the bottom border - std::cout << "\t|->Case bottom only" << std::endl; + //Case bottom only computeIntersectionsBottomBorderOnly(v_c, vmax_roi, radius, delta_theta); } } @@ -460,7 +460,7 @@ void computeIntersectionsBottomRight(const float &u_c, const float &v_c, const f float v_vmax = crossing_theta_v_max.second; if (u_umin <= umax_roi && u_umax > umax_roi && v_vmin <= vmax_roi && v_vmax > vmax_roi) { // The circle crosses only once each axis - std::cout << "\t|->Case crossing once" << std::endl; + //Case crossing once delta_theta = theta_u_min - theta_v_min; if (delta_theta < 0) { // An arc length cannot be negative it means that theta_u_max was comprise in the bottom left quadrant of the circle @@ -469,19 +469,19 @@ void computeIntersectionsBottomRight(const float &u_c, const float &v_c, const f } else if (u_umin <= umax_roi && u_umax <= umax_roi && v_vmin <= vmax_roi && v_vmax <= vmax_roi) { // The circle crosses twice each axis - std::cout << "\t|->Case crossing twice" << std::endl; + //Case crossing twice delta_theta = 2.f * M_PI - ((theta_v_min - theta_v_max) + (theta_u_max - theta_u_min)); } else if (u_umin > umax_roi && u_umax > umax_roi && v_vmin <= vmax_roi && v_vmax <= vmax_roi) { // The circle crosses the u-axis outside the roi // so it is equivalent to the case of crossing only the right border - std::cout << "\t|->Case left only" << std::endl; + //Case left only computeIntersectionsRightBorderOnly(u_c, umax_roi, radius, delta_theta); } else if (u_umin <= umax_roi && u_umax <= umax_roi && v_vmin > vmax_roi && v_vmax > vmax_roi) { // The circle crosses the v-axis outside the roi // so it is equivalent to the case of crossing only the bottom border - std::cout << "\t|->Case bottom only" << std::endl; + //Case bottom only computeIntersectionsBottomBorderOnly(v_c, vmax_roi, radius, delta_theta); } } @@ -526,23 +526,23 @@ void computeIntersectionsTopLeftBottom(const float &u_c, const float &v_c, const float u_umin_bottom = crossing_theta_u_min.second; float u_umax_bottom = crossing_theta_u_max.second; if (u_umin_top >= umin_roi && u_umin_bottom >= umin_roi && v_vmin >= vmin_roi && v_vmax <= vmax_roi) { - std::cout << "\t|-> case intersection top + left + bottom twice" << std::endl; + // case intersection top + left + bottom twice delta_theta = (theta_v_min - theta_u_min_top) + (theta_u_max_top - theta_u_max_bottom) + (theta_u_min_bottom - theta_v_max); } else if (u_umin_top <= umin_roi && v_vmin <= vmin_roi && u_umin_bottom <= umin_roi && v_vmax >= vmax_roi) { - std::cout << "\t|-> case intersection top and bottom" << std::endl; + // case intersection top and bottom delta_theta = (theta_u_max_top - theta_u_max_bottom); } else if (u_umax_top <= umin_roi && u_umax_bottom <= umin_roi && v_vmin >= vmin_roi && v_vmax <= vmax_roi) { - std::cout << "\t|-> case left only" << std::endl; + // case left only computeIntersectionsLeftBorderOnly(u_c, umin_roi, radius, delta_theta); } else if (u_umax_bottom > umin_roi && v_vmin >= vmin_roi) { - std::cout << "\t|-> case bottom/left corner" << std::endl; + // case bottom/left corner computeIntersectionsBottomLeft(u_c, v_c, umin_roi, vmax_roi, radius, delta_theta); } else if (u_umax_top > umin_roi && v_vmax <= vmax_roi) { - std::cout << "\t|-> case top/left corner" << std::endl; + // case top/left corner computeIntersectionsTopLeft(u_c, v_c, umin_roi, vmin_roi, radius, delta_theta); } } @@ -587,23 +587,23 @@ void computeIntersectionsTopRightBottom(const float &u_c, const float &v_c, cons float u_umin_bottom = crossing_theta_u_min.second; float u_umax_bottom = crossing_theta_u_max.second; if (u_umax_top <= umax_roi && u_umax_bottom <= umax_roi && v_vmin >= vmin_roi && v_vmax <= vmax_roi) { - std::cout << "\t|-> case intersection top + right + bottom twice" << std::endl; + // case intersection top + right + bottom twice delta_theta = 2.f * M_PI - ((theta_u_min_top - theta_u_max_top) + (theta_v_min - theta_v_max) + (theta_u_max_bottom - theta_u_min_bottom)); } else if (u_umin_top <= umax_roi && u_umax_top > umax_roi && v_vmin <= vmin_roi && u_umin_bottom <= umax_roi && u_umax_bottom > umax_roi && v_vmax >= vmax_roi) { - std::cout << "\t|-> case intersection top and bottom" << std::endl; + // case intersection top and bottom delta_theta = (theta_u_max_top - theta_u_max_bottom); } else if (u_umin_top >= umax_roi && u_umin_bottom >= umax_roi && v_vmin >= vmin_roi && v_vmax <= vmax_roi) { - std::cout << "\t|-> case right only" << std::endl; + // case right only computeIntersectionsRightBorderOnly(u_c, umax_roi, radius, delta_theta); } else if (u_umin_bottom <= umax_roi && v_vmin >= vmin_roi) { - std::cout << "\t|-> case bottom/right corner" << std::endl; + // case bottom/right corner computeIntersectionsBottomRight(u_c, v_c, vmax_roi, umax_roi, radius, delta_theta); } else if (u_umin_top <= umax_roi && v_vmax <= vmax_roi) { - std::cout << "\t|-> case top/right corner" << std::endl; + // case top/right corner computeIntersectionsTopRight(u_c, v_c, vmin_roi, umax_roi, radius, delta_theta); } } @@ -725,23 +725,23 @@ void computeIntersectionsLeftRightTop(const float &u_c, const float &v_c, const float v_vmax_right = crossing_theta_v_max.second; if (u_umin >= umin_roi && u_umax <= umax_roi && v_vmin_left >= vmin_roi && v_vmin_right >= vmin_roi) { - std::cout << "\t|-> case intersection left + right + top twice" << std::endl; + // case intersection left + right + top twice delta_theta = (theta_v_min_left - theta_u_min) + (theta_u_max - theta_v_min_right) + (theta_v_max_right - theta_v_max_left); } else if (u_umin <= umin_roi && u_umax >= umax_roi && v_vmax_left >= vmin_roi && v_vmax_right >= vmin_roi) { - std::cout << "\t|-> case intersection left + right" << std::endl; + // case intersection left + right delta_theta = (theta_v_max_right - theta_v_max_left); } else if (v_vmax_left <= vmin_roi && v_vmax_right <= vmin_roi && u_umin >= umin_roi && u_umax <= umax_roi) { - std::cout << "\t|-> case top only" << std::endl; + // case top only computeIntersectionsTopBorderOnly(v_c, vmin_roi, radius, delta_theta); } else if (u_umax >= umin_roi && v_vmax_left >= vmin_roi) { - std::cout << "\t|-> case top/left corner" << std::endl; + // case top/left corner computeIntersectionsTopLeft(u_c, v_c, umin_roi, vmin_roi, radius, delta_theta); } else if (u_umin <= umax_roi && v_vmax_right >= vmin_roi) { - std::cout << "\t|-> case top/right corner" << std::endl; + // case top/right corner computeIntersectionsTopRight(u_c, v_c, vmin_roi, umax_roi, radius, delta_theta); } } @@ -789,23 +789,23 @@ void computeIntersectionsLeftRightBottom(const float &u_c, const float &v_c, con // float v_vmax_right = crossing_theta_v_max.second; if (u_umin >= umin_roi && u_umax <= umax_roi && v_vmin_left <= vmax_roi && v_vmin_right <= vmax_roi) { - std::cout << "\t|-> case intersection left + right + bottom twice" << std::endl; + // case intersection left + right + bottom twice delta_theta = (theta_v_min_left - theta_v_min_right) + (theta_v_max_right - theta_u_max) + (theta_u_min - theta_v_max_left); } else if (u_umin <= umin_roi && u_umax >= umax_roi && v_vmin_left <= vmax_roi && v_vmin_right <= vmax_roi) { - std::cout << "\t|-> case intersection left + right" << std::endl; + // case intersection left + right delta_theta = (theta_v_min_left - theta_v_min_right); } else if (v_vmin_left >= vmax_roi && v_vmin_right >= vmax_roi && u_umin >= umin_roi && u_umax <= umax_roi) { - std::cout << "\t|-> case bottom only" << std::endl; + // case bottom only computeIntersectionsBottomBorderOnly(v_c, vmax_roi, radius, delta_theta); } - else if (u_umax >= umin_roi && v_vmin_right <= vmax_roi) { - std::cout << "\t|-> case bottom/left corner" << std::endl; + else if (u_umax >= umin_roi && v_vmin_right >= vmax_roi) { + // case bottom/left corner computeIntersectionsBottomLeft(u_c, v_c, umin_roi, vmax_roi, radius, delta_theta); } else if (u_umin <= umax_roi && v_vmin_right <= vmax_roi) { - std::cout << "\t|-> case bottom/right corner" << std::endl; + // case bottom/right corner computeIntersectionsBottomRight(u_c, v_c, vmax_roi, umax_roi, radius, delta_theta); } } @@ -918,7 +918,7 @@ void computeIntersectionsAllAxes(const float &u_c, const float &v_c, const float delta_theta += (theta_v_max_right - theta_u_max_bottom) + (theta_u_min_bottom - theta_v_max_left); } -float vpImageCircle::computeArcLengthInRoI(const vpRect &roi) const +float vpImageCircle::computeAngularCoverageInRoI(const vpRect &roi) const { float delta_theta = 0.f; vpImagePoint center = m_center; @@ -942,82 +942,66 @@ float vpImageCircle::computeArcLengthInRoI(const vpRect &roi) const // Easy case // The circle has its center in the image and its radius is not too great // to make it fully contained in the RoI - std::cout << "Case fully OK" << std::endl; delta_theta = 2.f * M_PI; } else if (touchBottomBorder && !touchLeftBorder && !touchRightBorder && !touchTopBorder) { // Touches/intersects only the bottom border of the RoI - std::cout << "Case bottom only" << std::endl; computeIntersectionsBottomBorderOnly(v_c, vmax_roi, radius, delta_theta); } else if (!touchBottomBorder && touchLeftBorder && !touchRightBorder && !touchTopBorder) { // Touches/intersects only the left border of the RoI - std::cout << "Case left only" << std::endl; computeIntersectionsLeftBorderOnly(u_c, umin_roi, radius, delta_theta); } else if (!touchBottomBorder && !touchLeftBorder && touchRightBorder && !touchTopBorder) { // Touches/intersects only the right border of the RoI - std::cout << "Case right only" << std::endl; computeIntersectionsRightBorderOnly(u_c, umax_roi, radius, delta_theta); } else if (!touchBottomBorder && !touchLeftBorder && !touchRightBorder && touchTopBorder) { // Touches/intersects only the top border of the RoI - std::cout << "Case top only" << std::endl; computeIntersectionsTopBorderOnly(v_c, vmin_roi, radius, delta_theta); } else if (touchBottomBorder && touchLeftBorder && !touchRightBorder && !touchTopBorder) { // Touches/intersects the bottom and left borders of the RoI - std::cout << "Case bottom / left" << std::endl; computeIntersectionsBottomLeft(u_c, v_c, umin_roi, vmax_roi, radius, delta_theta); } else if (touchBottomBorder && !touchLeftBorder && touchRightBorder && !touchTopBorder) { // Touches/intersects the bottom and right borders of the RoI - std::cout << "Case bottom / right" << std::endl; computeIntersectionsBottomRight(u_c, v_c, vmax_roi, umax_roi, radius, delta_theta); } else if (!touchBottomBorder && touchLeftBorder && !touchRightBorder && touchTopBorder) { // Touches/intersects the top and left borders of the RoI - std::cout << "Case top / left" << std::endl; computeIntersectionsTopLeft(u_c, v_c, umin_roi, vmin_roi, radius, delta_theta); } else if (!touchBottomBorder && !touchLeftBorder && touchRightBorder && touchTopBorder) { // Touches/intersects the top and right borders of the RoI - std::cout << "Case top / right" << std::endl; computeIntersectionsTopRight(u_c, v_c, vmin_roi, umax_roi, radius, delta_theta); } else if (touchBottomBorder && touchTopBorder && touchLeftBorder && !touchRightBorder) { // Touches/intersects the top, left and bottom borders of the RoI - std::cout << "Case bottom / top / left" << std::endl; computeIntersectionsTopLeftBottom(u_c, v_c, umin_roi, vmin_roi, vmax_roi, radius, delta_theta); } else if (touchBottomBorder && touchTopBorder && !touchLeftBorder && touchRightBorder) { // Touches/intersects the top, right and bottom borders of the RoI - std::cout << "Case bottom / top / right" << std::endl; computeIntersectionsTopRightBottom(u_c, v_c, umax_roi, vmin_roi, vmax_roi, radius, delta_theta); } else if (touchBottomBorder && touchTopBorder && !touchLeftBorder && !touchRightBorder) { // Touches/intersects the top and bottom borders of the RoI - std::cout << "Case bottom / top only" << std::endl; computeIntersectionsTopBottomOnly(u_c, v_c, vmin_roi, vmax_roi, radius, delta_theta); } else if (!touchBottomBorder && touchTopBorder && touchLeftBorder && touchRightBorder) { // Touches/intersects the top, left and right borders of the RoI - std::cout << "Case top / right / left" << std::endl; computeIntersectionsLeftRightTop(u_c, v_c, umin_roi, umax_roi, vmin_roi, radius, delta_theta); } else if (touchBottomBorder && !touchTopBorder && touchLeftBorder && touchRightBorder) { // Touches/intersects the bottom, left and right borders of the RoI - std::cout << "Case bottom / right / left" << std::endl; computeIntersectionsLeftRightBottom(u_c, v_c, umin_roi, umax_roi, vmax_roi, radius, delta_theta); } else if (touchLeftBorder && touchRightBorder && !touchTopBorder && !touchBottomBorder) { // Touches/intersects the bottom, left and right borders of the RoI - std::cout << "Case right / left only" << std::endl; computeIntersectionsLeftRightOnly(u_c, v_c, umin_roi, umax_roi, radius, delta_theta); } else if (touchLeftBorder && touchRightBorder && touchTopBorder && touchBottomBorder) { // Touches/intersects each axis - std::cout << "Case all" << std::endl; computeIntersectionsAllAxes(u_c, v_c, umin_roi, umax_roi, vmin_roi, vmax_roi, radius, delta_theta); } else { @@ -1028,7 +1012,13 @@ float vpImageCircle::computeArcLengthInRoI(const vpRect &roi) const std::cerr << "vmin_roi = " << vmin_roi << "\tvmax_roi = " << vmax_roi << std::endl << std::flush; throw(vpException(vpException::fatalError, "This case should never happen. Please contact Inria to make fix the problem")); } - float arcLength = delta_theta * radius; + return delta_theta; +} + +float vpImageCircle::computeArcLengthInRoI(const vpRect &roi) const +{ + float delta_theta = computeAngularCoverageInRoI(roi); + float arcLength = delta_theta * m_radius; return arcLength; } diff --git a/modules/core/test/tools/geometry/testImageCircle.cpp b/modules/core/test/tools/geometry/testImageCircle.cpp index 249e5f3f7f..b029a3a212 100644 --- a/modules/core/test/tools/geometry/testImageCircle.cpp +++ b/modules/core/test/tools/geometry/testImageCircle.cpp @@ -1650,7 +1650,7 @@ int main() // (5) & (6) theta_v_right_min = - theta_v_right_max float theta_u_top_max = -M_PI / 3.f; - float theta_v_right_max = 0; + float theta_v_right_max = 0.f; float theta_v_left_max = -M_PI_2; float radius = WIDTH_SWITCHED / (std::cos(theta_v_right_max) - std::cos(theta_v_left_max)); float uc = OFFSET; @@ -1713,6 +1713,201 @@ int main() hasSucceeded &= isValueOK; } + // Test with intersections with the bottom, left and the right border + // crossing each axis twice + { + // (1): u_cross_bot_min = uc + r cos(theta_u_top_min) >= umin_roi ; vmin_roi + height = vc - r sin(theta_u_top_min) + // (2): umin_roi = uc + r cos(theta_v_left_min); v_cross_left_min = vc - r sin(theta_v_left_min) >= vmin_roi + // (3): u_cross_bot_max = uc + r cos(theta_u_top_max) <= umin_roi + width ; vmin_roi + height = vc - r sin(theta_u_top_max) + // (4): umin_roi = uc + r cos(theta_v_left_max); v_cross_left_max = vc - r sin(theta_v_left_max) <= vmin_roi + height + // (5): umin_roi + width = uc + r cos(theta_v_right_min) ; v_cross_right_min = vc - r sin(theta_v_right_min) + // (6): umin_roi + width = uc + r cos(theta_v_right_max) ; v_cross_right_max = vc - r sin(theta_v_right_max) + // (5) - (2) width = r (cos(theta_v_right_min) - cos(theta_v_left_min)) + // (1) & (3) theta_u_top_min = PI - theta_u_top_max + // (2) & (4) theta_v_left_min = - theta_v_left_max + // (5) & (6) theta_v_right_min = - theta_v_right_max + + float theta_v_left_min = 7.f * M_PI / 8.f; + float theta_v_left_max = -theta_v_left_min; + float theta_v_right_min = M_PI / 8.f; + float theta_v_right_max = -theta_v_right_min; + float theta_u_bot_min = -5.f * M_PI / 8.f; + float theta_u_bot_max = -M_PI - theta_u_bot_min; + float radius = WIDTH_SWITCHED / (std::cos(theta_v_right_min) - std::cos(theta_v_left_min)); + float uc = OFFSET + WIDTH_SWITCHED - radius * std::cos(theta_v_right_min); + float vc = OFFSET + HEIGHT_SWITCHED + radius * std::sin(theta_u_bot_min); + vpImageCircle circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(switchedRoI); + float theoreticalValue = ((theta_v_left_min - theta_v_right_min) + (theta_v_right_max - theta_u_bot_max) + (theta_u_bot_min - theta_v_left_max)) * radius; + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the bottom, left and the right border, crossing each axis twice in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + + // Test with intersections with the bottom, left and the right border + // crossing only the bottom one in the RoI + { + // (1): u_cross_bot_min = uc + r cos(theta_u_top_min) >= umin_roi ; vmin_roi + height = vc - r sin(theta_u_top_min) + // (2): umin_roi = uc + r cos(theta_v_left_min); v_cross_left_min = vc - r sin(theta_v_left_min) >= vmin_roi + height + // (3): u_cross_bot_max = uc + r cos(theta_u_top_max) <= umin_roi + width ; vmin_roi + height = vc - r sin(theta_u_top_max) + // (4): umin_roi = uc + r cos(theta_v_left_max); v_cross_left_max = vc - r sin(theta_v_left_max) >= vmin_roi + height + // (5): umin_roi + width = uc + r cos(theta_v_right_min) ; v_cross_right_min = vc - r sin(theta_v_right_min) >= vmin_roi + height + // (6): umin_roi + width = uc + r cos(theta_v_right_max) ; v_cross_right_max = vc - r sin(theta_v_right_max) >= vmin_roi + height + // (5) - (2) width = r (cos(theta_v_right_min) - cos(theta_v_left_min)) + // (1) & (3) theta_u_top_min = PI - theta_u_top_max + // (2) & (4) theta_v_left_min = - theta_v_left_max + // (5) & (6) theta_v_right_min = - theta_v_right_max + float theta_u_bot_min = 2.f * M_PI / 3.f; + float theta_u_bot_max = M_PI - theta_u_bot_min; + float theta_v_left_min = 5.f * M_PI / 6.f; + float theta_v_right_min = M_PI / 6.f; + float radius = WIDTH_SWITCHED / (std::cos(theta_v_right_min) - std::cos(theta_v_left_min)); + float uc = OFFSET + WIDTH_SWITCHED - radius * std::cos(theta_v_right_min); + float vc = OFFSET + HEIGHT_SWITCHED + radius * std::sin(theta_u_bot_min); + vpImageCircle circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(switchedRoI); + float theoreticalValue = ((theta_u_bot_min - theta_u_bot_max)) * radius; + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the bottom, left and the right border, crossing only the bottom one in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + + // Test with intersections with the bottom, left and the right border + // crossing only the left and right in the RoI + { + // (1): u_cross_bot_min = uc + r cos(theta_u_top_min) <= umin_roi ; vmin_roi + height = vc - r sin(theta_u_top_min) + // (2): umin_roi = uc + r cos(theta_v_left_min); v_cross_left_min = vc - r sin(theta_v_left_min) <= vmin_roi + height + // (3): u_cross_bot_max = uc + r cos(theta_u_top_max) >= umin_roi + width ; vmin_roi + height = vc - r sin(theta_u_top_max) + // (4): umin_roi = uc + r cos(theta_v_left_max); v_cross_left_max = vc - r sin(theta_v_left_max) <= vmin_roi + height + // (5): umin_roi + width = uc + r cos(theta_v_right_min) ; v_cross_right_min = vc - r sin(theta_v_right_min) >= vmin_roi + height + // (6): umin_roi + width = uc + r cos(theta_v_right_max) ; v_cross_right_max = vc - r sin(theta_v_right_max) >= vmin_roi + height + // (5) - (2) width = r (cos(theta_v_right_min) - cos(theta_v_left_min)) + // (1) & (3) theta_u_top_min = PI - theta_u_top_max + // (2) & (4) theta_v_left_min = - theta_v_left_max + // (5) & (6) theta_v_right_min = - theta_v_right_max + float theta_u_bot_min = 7.f * M_PI / 8.f; + float theta_v_left_min = 5.f * M_PI / 8.f; + float theta_v_right_min = 3.f * M_PI / 8.f; + float radius = WIDTH_SWITCHED / (std::cos(theta_v_right_min) - std::cos(theta_v_left_min)); + float uc = OFFSET + WIDTH_SWITCHED - radius * std::cos(theta_v_right_min); + float vc = OFFSET + HEIGHT_SWITCHED + radius * std::sin(theta_u_bot_min); + vpImageCircle circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(switchedRoI); + float theoreticalValue = ((theta_v_left_min - theta_v_right_min)) * radius; + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the bottom, left and the right border, crossing only the left and right in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + + // Test with intersections with the bottom, left and the right border + // crossing only the left and bottom in the RoI + { + // (1): u_cross_bot_min = uc + r cos(theta_u_top_min) <= umin_roi ; vmin_roi + height = vc - r sin(theta_u_top_min) + // (2): umin_roi = uc + r cos(theta_v_left_min); v_cross_left_min = vc - r sin(theta_v_left_min) <= vmin_roi + height + // (3): u_cross_bot_max = uc + r cos(theta_u_top_max) <= umin_roi + width ; vmin_roi + height = vc - r sin(theta_u_top_max) + // (4): umin_roi = uc + r cos(theta_v_left_max); v_cross_left_max = vc - r sin(theta_v_left_max) >= vmin_roi + height + // (5): umin_roi + width = uc + r cos(theta_v_right_min) ; v_cross_right_min = vc - r sin(theta_v_right_min) >= vmin_roi + height + // (6): umin_roi + width = uc + r cos(theta_v_right_max) ; v_cross_right_max = vc - r sin(theta_v_right_max) >= vmin_roi + height + // (5) - (2) width = r (cos(theta_v_right_min) - cos(theta_v_left_min)) + // (1) & (3) theta_u_top_min = PI - theta_u_top_max + // (2) & (4) theta_v_left_min = - theta_v_left_max + // (5) & (6) theta_v_right_min = - theta_v_right_max + float theta_u_bot_max = M_PI / 3.f; + float theta_v_left_min = M_PI_2; + float theta_v_right_min = 0.f; + float radius = WIDTH_SWITCHED / (std::cos(theta_v_right_min) - std::cos(theta_v_left_min)); + float uc = OFFSET; + float vc = OFFSET + HEIGHT_SWITCHED + radius * std::sin(theta_u_bot_max); + vpImageCircle circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(switchedRoI); + float theoreticalValue = ((theta_v_left_min - theta_u_bot_max)) * radius; + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the bottom, left and the right border, crossing only the left and bottom in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + + // Test with intersections with the bottom, left and the right border + // crossing only the right and bottom in the RoI + { + // (1): u_cross_bot_min = uc + r cos(theta_u_top_min) <= umin_roi + width ; vmin_roi + height = vc - r sin(theta_u_top_min) + // (2): umin_roi = uc + r cos(theta_v_left_min); v_cross_left_min = vc - r sin(theta_v_left_min) >= vmin_roi + height + // (3): u_cross_bot_max = uc + r cos(theta_u_top_max) >= umin_roi + width ; vmin_roi + height = vc - r sin(theta_u_top_max) + // (4): umin_roi = uc + r cos(theta_v_left_max); v_cross_left_max = vc - r sin(theta_v_left_max) >= vmin_roi + height + // (5): umin_roi + width = uc + r cos(theta_v_right_min) ; v_cross_right_min = vc - r sin(theta_v_right_min) <= vmin_roi + height + // (6): umin_roi + width = uc + r cos(theta_v_right_max) ; v_cross_right_max = vc - r sin(theta_v_right_max) >= vmin_roi + height + // (5) - (2) width = r (cos(theta_v_right_min) - cos(theta_v_left_min)) + // (1) & (3) theta_u_top_min = PI - theta_u_top_max + // (2) & (4) theta_v_left_min = - theta_v_left_max + // (5) & (6) theta_v_right_min = - theta_v_right_max + float theta_u_bot_min = 2.f * M_PI / 3.f; + float theta_v_right_min = M_PI_2; + float theta_v_left_min = M_PI; + float radius = WIDTH_SWITCHED / (std::cos(theta_v_right_min) - std::cos(theta_v_left_min)); + float uc = OFFSET + WIDTH_SWITCHED; + float vc = OFFSET + HEIGHT_SWITCHED + radius * std::sin(theta_u_bot_min); + vpImageCircle circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(switchedRoI); + float theoreticalValue = ((theta_u_bot_min - theta_v_right_min)) * radius; + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with intersections with the bottom, left and the right border, crossing only the right and bottom in the RoI." << std::endl; + std::cout << "\tarc length =" << arcLengthCircle << std::endl; + std::cout << "\ttheoretical length =" << theoreticalValue << std::endl; + std::cout << "\ttest status = " << statusTest << std::endl; + + hasSucceeded &= isValueOK; + } + // Test with intersections with the top and bottom only, // crossing each axis twice in the RoI { From db37b1fa37f06116d24c5ca2b46c147e65a4cca3 Mon Sep 17 00:00:00 2001 From: rlagneau Date: Tue, 3 Oct 2023 08:52:20 +0200 Subject: [PATCH 21/22] [TUTO] Updated the vpCircleHoughTransform tutorial based on the recent changes on the circle candidate validation policy --- doc/tutorial/imgproc/tutorial-imgproc-cht.dox | 9 +++------ .../imgproc/hough-transform/config/detector_img.json | 6 +++--- .../imgproc/hough-transform/tutorial-circle-hough.cpp | 3 +-- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/doc/tutorial/imgproc/tutorial-imgproc-cht.dox b/doc/tutorial/imgproc/tutorial-imgproc-cht.dox index 08a200332c..852fdf6fe2 100644 --- a/doc/tutorial/imgproc/tutorial-imgproc-cht.dox +++ b/doc/tutorial/imgproc/tutorial-imgproc-cht.dox @@ -27,11 +27,6 @@ parameter. \image html img-tutorial-cht-radius-votes.png -\section imgproc_cht_requirements Requirements - -With the current implementation, the `vpCircleHoughTransform` requires ViSP to be compiled with OpenCV. -If you do not know how to do it, please refer to the installation guidelines of \ref soft_vision_opencv. - \section imgproc_cht_howto How to use the tutorial It is possible to configure the `vpCircleHoughTransform` class using a JSON file. @@ -74,7 +69,7 @@ If the detections seem a bit off, you might need to change the parameters in `co To run the software on an actual image using command line arguments instead, please run: ``` -$ ./tutorial-circle-hough --input /path/to/my/image --gaussian-kernel 5 --gaussian-sigma 1 --canny-thresh -1. --dilatation-repet 1 --center-thresh 200 --radius-bin 2 --radius-thresh 2 --radius-limits 80 90 --merging-thresh 15 2 --circle-perfectness 0.9 +$ ./tutorial-circle-hough --input /path/to/my/image --gaussian-kernel 5 --gaussian-sigma 1 --canny-thresh 100. 200. --dilatation-repet 1 --center-thresh 200 --radius-bin 2 --circle-probability-thresh 0.75 --radius-limits 80 90 --merging-thresh 15 2 --circle-perfectness 0.9 ``` If the detections seem a bit off, you might need to change the parameters @@ -139,6 +134,8 @@ to the command line arguments: To run the circle detection, you must call the following method: \snippet tutorial-circle-hough.cpp Run detection +The call to vpCircleHoughTransform::getDetectionsProbabilities permits to know the confidence in each detection. +It is sorted in the same way that are sorted the detections. You could have also used the following method to get only the `num_best` best detections: diff --git a/tutorial/imgproc/hough-transform/config/detector_img.json b/tutorial/imgproc/hough-transform/config/detector_img.json index fd86ccddf6..febadcdcbe 100644 --- a/tutorial/imgproc/hough-transform/config/detector_img.json +++ b/tutorial/imgproc/hough-transform/config/detector_img.json @@ -1,6 +1,6 @@ { - "lowerCannyThresh": -1.0, - "upperCannyThresh": -1.0, + "lowerCannyThresh": 100.0, + "upperCannyThresh": 200.0, "centerMinDistance": 5.0, "centerThresh": 100.0, "centerXlimits": [ @@ -21,6 +21,6 @@ 34, 75 ], - "circleProbabilityThreshold": 0.9, + "circleProbabilityThreshold": 0.75, "sobelKernelSize": 7 } diff --git a/tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp b/tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp index 36e9a9cc67..0e0940b354 100644 --- a/tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp +++ b/tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp @@ -164,7 +164,6 @@ bool test_detection(const vpImage &I_src, vpCircleHoughTransform //! [Run detection] std::vector detectedCircles = detector.detect(I_src, nbCirclesToDetect); std::vector probas = detector.getDetectionsProbabilities(); - std::vector votes = detector.getDetectionsVotes(); //! [Run detection] double tF = vpTime::measureTimeMicros(); std::cout << "Process time = " << (tF - t0) * 0.001 << "ms" << std::endl << std::flush; @@ -180,7 +179,7 @@ bool test_detection(const vpImage &I_src, vpCircleHoughTransform std::cout << "Circle #" << id << ":" << std::endl; std::cout << "\tCenter: (" << circleCandidate.getCenter() << ")" << std::endl; std::cout << "\tRadius: (" << circleCandidate.getRadius() << ")" << std::endl; - std::cout << "\tProba: " << probas[id] << "\tVotes:" << votes[id] << std::endl; + std::cout << "\tProba: " << probas[id] << std::endl; std::cout << "\tTheoretical arc length: " << circleCandidate.computeArcLengthInRoI(vpRect(0, 0, I_src.getWidth(), I_src.getHeight())) << std::endl; id++; idColor = (idColor + 1) % v_colors.size(); From e5cce9c048738a904f7fc4fb042dd24ce60901ec Mon Sep 17 00:00:00 2001 From: rlagneau Date: Tue, 3 Oct 2023 09:36:18 +0200 Subject: [PATCH 22/22] [FIX] Forgot to clean the votes vector --- modules/imgproc/src/vpCircleHoughTransform.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/imgproc/src/vpCircleHoughTransform.cpp b/modules/imgproc/src/vpCircleHoughTransform.cpp index f97bee2b8c..a5e3d5b198 100644 --- a/modules/imgproc/src/vpCircleHoughTransform.cpp +++ b/modules/imgproc/src/vpCircleHoughTransform.cpp @@ -175,6 +175,7 @@ vpCircleHoughTransform::detect(const vpImage &I) m_centerVotes.clear(); m_edgePointsList.clear(); m_circleCandidates.clear(); + m_circleCandidatesVotes.clear(); m_circleCandidatesProbabilities.clear(); m_finalCircles.clear(); m_finalCircleVotes.clear();