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/modules/core/include/visp3/core/vpImageCircle.h b/modules/core/include/visp3/core/vpImageCircle.h index 6f1150f0c2..33343e1f75 100644 --- a/modules/core/include/visp3/core/vpImageCircle.h +++ b/modules/core/include/visp3/core/vpImageCircle.h @@ -78,9 +78,25 @@ class VISP_EXPORT vpImageCircle virtual ~vpImageCircle(); /*! - * Get the center of the image (2D) circle - * \return The center of the image (2D) circle. + * 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. + */ + 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..b8e49af9bd 100644 --- a/modules/core/src/image/vpImageCircle.cpp +++ b/modules/core/src/image/vpImageCircle.cpp @@ -63,6 +63,965 @@ vpImageCircle::~vpImageCircle() } +/*! + * \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 = 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] 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 &umin_roi, const float &radius, + float &delta_theta) +{ + // 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); + 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] 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 &umax_roi, const float &radius, + float &delta_theta) +{ + // 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); + 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] 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 &vmin_roi, const float &radius, + float &delta_theta) +{ + // 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; + 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 (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 { + delta_theta = theta_max - theta_min; + } +} + +/*! + * \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] 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 &vmax_roi, const float &radius, + float &delta_theta) +{ + // 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; + 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 (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 { + delta_theta = 2.f * M_PI - (theta_max - theta_min); + } +} + +/*! + * \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 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, + std::pair &theta_u_cross_min, std::pair &theta_u_cross_max, + std::pair &theta_v_cross_min, std::pair &theta_v_cross_max) +{ + // 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) { + theta_u_cross_2 = M_PI - theta_u_cross; + } + else { + theta_u_cross_2 = -M_PI - theta_u_cross; + } + // 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; + // 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] 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 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 = 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); + 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 < umin_roi && u_umax >= umin_roi && v_vmin < vmin_roi && v_vmax >= vmin_roi) { + // The circle crosses only once each axis + //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 + //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 + //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 + //Case top only + computeIntersectionsTopBorderOnly(v_c, vmin_roi, radius, delta_theta); + } +} + +/*! + * \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 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; + 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 + //Case crossing once + 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 + //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 + //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 + //Case crossing top only + computeIntersectionsTopBorderOnly(v_c, vmin_roi, radius, delta_theta); + } +} + +/*! + * \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] 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 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 = 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); + 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 < umin_roi && u_umax >= umin_roi && v_vmin <= vmax_roi && v_vmax > vmax_roi) { + // The circle crosses only once each axis + //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 + //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 + //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 + //Case bottom only + 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 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; + 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; + if (u_umin <= umax_roi && u_umax > umax_roi && v_vmin <= vmax_roi && v_vmax > vmax_roi) { + // The circle crosses only once each axis + //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 + 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 + //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 + //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 + //Case bottom only + 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 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] 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 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 = 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); + 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 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; + if (u_umin_top >= umin_roi && u_umin_bottom >= umin_roi && v_vmin >= vmin_roi && v_vmax <= vmax_roi) { + // 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) { + // 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) { + // case left only + computeIntersectionsLeftBorderOnly(u_c, umin_roi, radius, delta_theta); + } + else if (u_umax_bottom > umin_roi && v_vmin >= vmin_roi) { + // 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) { + // case top/left corner + computeIntersectionsTopLeft(u_c, v_c, umin_roi, vmin_roi, 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] 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 float &umax_roi, const float &vmin_roi, const float &vmax_roi, + const float &radius, float &delta_theta) +{ + // 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 = 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); + 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 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, + 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; + if (u_umax_top <= umax_roi && u_umax_bottom <= umax_roi && v_vmin >= vmin_roi && v_vmax <= vmax_roi) { + // 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) { + // 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) { + // case right only + computeIntersectionsRightBorderOnly(u_c, umax_roi, radius, delta_theta); + } + else if (u_umin_bottom <= umax_roi && v_vmin >= vmin_roi) { + // 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) { + // case top/right corner + 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 > 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 > 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)); +} + +/*! + * \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) { + // 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) { + // 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) { + // case top only + computeIntersectionsTopBorderOnly(v_c, vmin_roi, radius, delta_theta); + } + else if (u_umax >= umin_roi && v_vmax_left >= vmin_roi) { + // 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) { + // case top/right corner + 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) { + // 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) { + // 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) { + // case bottom only + computeIntersectionsBottomBorderOnly(v_c, vmax_roi, radius, delta_theta); + } + 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) { + // case bottom/right corner + 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 theta_v_min_left = crossing_theta_v_min.first; + float theta_v_max_left = crossing_theta_v_max.first; + + // 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 theta_v_min_right = crossing_theta_v_min.first; + float theta_v_max_right = crossing_theta_v_max.first; + 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::computeAngularCoverageInRoI(const vpRect &roi) const +{ + float delta_theta = 0.f; + vpImagePoint center = m_center; + 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(); + 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 = (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 + delta_theta = 2.f * M_PI; + } + else if (touchBottomBorder && !touchLeftBorder && !touchRightBorder && !touchTopBorder) { + // Touches/intersects only the bottom border of the RoI + computeIntersectionsBottomBorderOnly(v_c, vmax_roi, radius, delta_theta); + } + else if (!touchBottomBorder && touchLeftBorder && !touchRightBorder && !touchTopBorder) { + // Touches/intersects only the left border of the RoI + computeIntersectionsLeftBorderOnly(u_c, umin_roi, radius, delta_theta); + } + else if (!touchBottomBorder && !touchLeftBorder && touchRightBorder && !touchTopBorder) { + // Touches/intersects only the right border of the RoI + computeIntersectionsRightBorderOnly(u_c, umax_roi, radius, delta_theta); + } + else if (!touchBottomBorder && !touchLeftBorder && !touchRightBorder && touchTopBorder) { + // Touches/intersects only the top border of the RoI + computeIntersectionsTopBorderOnly(v_c, vmin_roi, radius, delta_theta); + } + else if (touchBottomBorder && touchLeftBorder && !touchRightBorder && !touchTopBorder) { + // Touches/intersects the bottom and left borders of the RoI + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + computeIntersectionsLeftRightOnly(u_c, v_c, umin_roi, umax_roi, radius, delta_theta); + } + else if (touchLeftBorder && touchRightBorder && touchTopBorder && touchBottomBorder) { + // Touches/intersects each axis + 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")); + } + return delta_theta; +} + +float vpImageCircle::computeArcLengthInRoI(const vpRect &roi) const +{ + float delta_theta = computeAngularCoverageInRoI(roi); + float arcLength = delta_theta * m_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..b029a3a212 --- /dev/null +++ b/modules/core/test/tools/geometry/testImageCircle.cpp @@ -0,0 +1,2018 @@ +/**************************************************************************** + * + * 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); +} + +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; + const float WIDTH = 640.f; + 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 + { + 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(arcLengthCircle, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test no intersection." << 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 circle touching borders of the RoI + { + vpRect roiSquare(OFFSET, OFFSET, HEIGHT, HEIGHT); + 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(arcLengthCircle, 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 =" << arcLengthCircle << 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 + { + // Formula: uc = OFFSET - RADIUS * cos(theta) + // theta := 2 * PI / 3 + float uc = OFFSET + 24.f; + float vc = OFFSET + 100.f; + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); + float theoreticalValue = 4.f * M_PI * RADIUS /3.f; + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test intersection left border, more than half a circle visible." << 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 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 circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); + float theoreticalValue = 2.f * M_PI * RADIUS /3.f; + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test intersection left border, less than half a circle visible." << 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 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 circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); + float theoreticalValue = 2.f * M_PI * RADIUS; + bool isValueOK = compareAngles(arcLengthCircle, 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 =" << arcLengthCircle << 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 + { + // Formula: uc = OFFSET + WIDTH - RADIUS * cos(theta) + // theta := PI / 3 + float uc = OFFSET + 616.f; + float vc = OFFSET + 100.f; + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); + float theoreticalValue = 4.f * M_PI * RADIUS /3.f; + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test intersection right border, more than half a circle visible." << 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 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 circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); + float theoreticalValue = 2.f * M_PI * RADIUS /3.f; + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test intersection right border, less than half a circle visible." << 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 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 circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); + float theoreticalValue = 2.f * M_PI * RADIUS; + bool isValueOK = compareAngles(arcLengthCircle, 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 =" << 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 border, more than half a circle visible + { + // 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 circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); + float theoreticalValue = 5.f * M_PI * RADIUS /3.f; + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test intersection top border, more than half a circle visible." << 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 border, less than half a circle visible + { + // 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 circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); + float theoreticalValue = M_PI * RADIUS /3.f; + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test intersection top border, less than half a circle visible." << 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 circle touching the top border, all the circle is visible + { + // 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 circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); + float theoreticalValue = 2.f * M_PI * RADIUS; + bool isValueOK = compareAngles(arcLengthCircle, 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 =" << 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 border, more than half a circle visible + { + // 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 circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); + float theoreticalValue = 5.f * M_PI * RADIUS /3.f; + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test intersection bottom border, more than half a circle visible." << 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 border, less than half a circle visible + { + // 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 circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); + float theoreticalValue = M_PI * RADIUS /3.f; + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test intersection bottom border, less than half a circle visible." << 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 circle touching the bottom border, all the circle is visible + { + // Formula: vc = OFFSET + HEIGHT - RADIUS * sin(theta) + float uc = OFFSET + 100.f; + float vc = OFFSET + HEIGHT - RADIUS; + vpImageCircle circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); + float theoreticalValue = 2.f * M_PI * RADIUS; + bool isValueOK = compareAngles(arcLengthCircle, theoreticalValue); + std::string statusTest; + if (isValueOK) { + statusTest = "SUCCESS"; + } + else { + statusTest = "FAILED"; + } + std::cout << "Test with circle touching the bottom border, all the circle is visible." << 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 the left border, crossing each axis once in the RoI + { + // 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 circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); + float theoreticalValue = M_PI_2 * 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 the left border, crossing each axis once 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 the left border + // but crossing only the left axis in the RoI + { + // (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 circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); + float theoreticalValue = M_PI_2 * 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 the left border but crossing only the left axis 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 the left border + // but crossing only the top axis in the RoI + { + // (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 circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); + float theoreticalValue = 0.2f * M_PI_2 * 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 the left border but crossing only the top axis 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 the left border + // crossing twice each axis + { + // (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 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(arcLengthCircle, 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 =" << 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 the right border, crossing each axis once in the RoI + { + // (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 circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); + float theoreticalValue = (M_PI_2 + 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 and the right border, crossing each axis once 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 the right border, + // but crossing only the right border in the RoI + { + // (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) 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; + 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(arcLengthCircle, 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 =" << 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 the right border, + // but crossing only the top border in the RoI + { + // (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 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(arcLengthCircle, 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 =" << 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 the left border + // crossing twice each axis + { + // (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 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(arcLengthCircle, 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 =" << 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 and the left border, crossing each axis once in the RoI + { + // (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 circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); + float theoreticalValue = (M_PI_2 + 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 bottom and the left border, crossing each axis once 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 and the left border + // but crossing only the left border in the RoI + { + // (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 circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); + float theoreticalValue = (2.f * theta_v_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 and the left border, but crossing only the left border 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 and the left border + // but crossing only the bottom border in the RoI + { + // (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 circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); + 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 and the left border, but crossing only the bottom border 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 and the left border + // crossing each axis twice in the RoI + { + // (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 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(arcLengthCircle, 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 =" << 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 and the right border, crossing each axis once in the RoI + { + // (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 circle(vpImagePoint(vc, uc), RADIUS); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); + float theoreticalValue = (M_PI_2 + 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 bottom and the right border, crossing each axis once 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 and the right border, + // crossing only the right axis in the RoI + { + // (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 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(arcLengthCircle, 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 =" << 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 and the right border, + // crossing only the bottom axis in the RoI + { + // (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 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(arcLengthCircle, 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 =" << 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 and the right border + // crossing each axis twice in the RoI + { + // (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 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(arcLengthCircle, 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 =" << 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, 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 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(arcLengthCircle, 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 =" << 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, bottom and the left border + // 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 + // (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_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 circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); + float theoreticalValue = (theta_u_top_max - theta_u_bottom_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, bottom and the left border, crossing only the top and bottom axes 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, 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 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(arcLengthCircle, 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 =" << 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, 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_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 - radius * std::cos(theta_v_min); + vpImageCircle circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); + float theoreticalValue = (theta_v_min - theta_v_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, bottom and the left border, crossing only the left axis 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, 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 circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); + float theoreticalValue = (theta_v_min - theta_v_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, bottom and the left border, crossing the left axis and touching the two others 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, 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 circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); + float theoreticalValue = (theta_u_top_max - theta_v_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, bottom and the left border, crossing only the top and left axes once 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, 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 circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); + float theoreticalValue = (theta_v_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 top, bottom and the left border, crossing the bottom and left axis once 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, 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 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(arcLengthCircle, 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 =" << 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, bottom and the right border + // 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 + // (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_v_min = 2.f * M_PI / 3.f; + float theta_u_bottom_min = -theta_u_top_min; + float radius = HEIGHT; + float vc = OFFSET + radius * std::sin(theta_u_top_min); + float uc = OFFSET + WIDTH - radius * std::cos(theta_v_min); + 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(arcLengthCircle, 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 top and bottom axes 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, 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 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(arcLengthCircle, 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 =" << 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, 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_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 + WIDTH - radius * std::cos(theta_v_min); + 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(arcLengthCircle, 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 =" << 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, 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 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(arcLengthCircle, 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 =" << 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, 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 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(arcLengthCircle, 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 =" << 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, 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 circle(vpImagePoint(vc, uc), radius); + float arcLengthCircle = circle.computeArcLengthInRoI(roi); + float theoreticalValue = (theta_u_bot_min - theta_v_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, bottom and the right border, crossing the bottom and right axis once 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 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.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; + 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 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 + { + // (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 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(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; + + 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 + 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(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; + 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 + // 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); + + 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; + + hasSucceeded &= isValueOK; + } + + if (hasSucceeded) { + std::cout << "testImageCircle overall result: SUCCESS"; + return EXIT_SUCCESS; + } + std::cout << "testImageCircle overall result: FAILED"; + return EXIT_FAILURE; +} 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..a5e3d5b198 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 @@ -167,6 +176,7 @@ vpCircleHoughTransform::detect(const vpImage &I) m_edgePointsList.clear(); m_circleCandidates.clear(); m_circleCandidatesVotes.clear(); + m_circleCandidatesProbabilities.clear(); m_finalCircles.clear(); m_finalCircleVotes.clear(); @@ -486,24 +496,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 +548,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 +585,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 +606,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..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 ], - "radiusThreshRatio": 4.0, + "circleProbabilityThreshold": 0.75, "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..0e0940b354 100644 --- a/tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp +++ b/tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp @@ -163,6 +163,7 @@ 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(); //! [Run detection] double tF = vpTime::measureTimeMicros(); std::cout << "Process time = " << (tF - t0) * 0.001 << "ms" << std::endl << std::flush; @@ -178,6 +179,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] << 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 +215,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 +235,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 +299,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 +336,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 +372,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 +404,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 +458,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 +472,7 @@ int main(int argc, char **argv) , opt_maxRadius , opt_dilatationRepet , opt_centerThresh - , opt_radiusThreshRatio + , opt_circleProbaThresh , opt_circlePerfectness , opt_centerDistanceThresh , opt_radiusDifferenceThresh