fixed warnings and added paper to opencv.bib

This commit is contained in:
Sara Kuhnert 2025-06-03 14:31:33 +02:00
parent b07e7ab11d
commit c4202b70a5
4 changed files with 71 additions and 85 deletions

View File

@ -1553,3 +1553,12 @@
year = {2014},
url = {http://www.marcozuliani.com/docs/RANSAC4Dummies.pdf}
}
@article{Aggarwal1985,
author = {Aggarwal, A. and Chang, J. and Yap, Chee K.},
title = {Minimum area circumscribing Polygons},
year = {1985},
pages = {112--117},
journal = {The Visual Computer},
volume = {7},
url = {https://doi.org/10.1007/BF01898354}
}

View File

@ -3070,10 +3070,9 @@ Also, the special values #THRESH_OTSU or #THRESH_TRIANGLE may be combined with o
above values. In these cases, the function determines the optimal threshold value using the Otsu's
or Triangle algorithm and uses it instead of the specified thresh.
@note Currently, the Otsu's method is implemented only for CV_8UC1 and CV_16UC1 images,
and the Triangle's method is implemented only for CV_8UC1 images.
@note Currently, the Otsu's and Triangle methods are implemented only for 8-bit single-channel images.
@param src input array (multiple-channel, CV_8U, CV_16S, CV_16U, CV_32F or CV_64F).
@param src input array (multiple-channel, 8-bit or 32-bit floating point).
@param dst output array of the same size and type and the same number of channels as src.
@param thresh threshold value.
@param maxval maximum value to use with the #THRESH_BINARY and #THRESH_BINARY_INV thresholding
@ -3081,30 +3080,11 @@ types.
@param type thresholding type (see #ThresholdTypes).
@return the computed threshold value if Otsu's or Triangle methods used.
@sa thresholdWithMask, adaptiveThreshold, findContours, compare, min, max
@sa adaptiveThreshold, findContours, compare, min, max
*/
CV_EXPORTS_W double threshold( InputArray src, OutputArray dst,
double thresh, double maxval, int type );
/** @brief Same as #threshold, but with an optional mask
@note If the mask is empty, #thresholdWithMask is equivalent to #threshold.
If the mask is not empty, dst *must* be of the same size and type as src, so that
outliers pixels are left as-is
@param src input array (multiple-channel, 8-bit or 32-bit floating point).
@param dst output array of the same size and type and the same number of channels as src.
@param mask optional mask (same size as src, 8-bit).
@param thresh threshold value.
@param maxval maximum value to use with the #THRESH_BINARY and #THRESH_BINARY_INV thresholding
types.
@param type thresholding type (see #ThresholdTypes).
@return the computed threshold value if Otsu's or Triangle methods used.
@sa threshold, adaptiveThreshold, findContours, compare, min, max
*/
CV_EXPORTS_W double thresholdWithMask( InputArray src, InputOutputArray dst, InputArray mask,
double thresh, double maxval, int type );
/** @brief Applies an adaptive threshold to an array.
@ -4160,11 +4140,7 @@ CV_EXPORTS_W double contourArea( InputArray contour, bool oriented = false );
/** @brief Finds a rotated rectangle of the minimum area enclosing the input 2D point set.
The function calculates and returns the minimum-area bounding rectangle (possibly rotated) for a
specified point set. The angle of rotation represents the angle between the line connecting the starting
and ending points (based on the clockwise order with greatest index for the corner with greatest \f$y\f$)
and the horizontal axis. This angle always falls between \f$[-90, 0)\f$ because, if the object
rotates more than a rect angle, the next edge is used to measure the angle. The starting and ending points change
as the object rotates.Developer should keep in mind that the returned RotatedRect can contain negative
specified point set. Developer should keep in mind that the returned RotatedRect can contain negative
indices when data is close to the containing Mat element boundary.
@param points Input vector of 2D points, stored in std::vector\<\> or Mat
@ -4173,9 +4149,7 @@ CV_EXPORTS_W RotatedRect minAreaRect( InputArray points );
/** @brief Finds the four vertices of a rotated rect. Useful to draw the rotated rectangle.
The function finds the four vertices of a rotated rectangle. The four vertices are returned
in clockwise order starting from the point with greatest \f$y\f$. If two points have the
same \f$y\f$ coordinate the rightmost is the starting point. This function is useful to draw the
The function finds the four vertices of a rotated rectangle. This function is useful to draw the
rectangle. In C++, instead of using this function, you can directly use RotatedRect::points method. Please
visit the @ref tutorial_bounding_rotated_ellipses "tutorial on Creating Bounding rotated boxes and ellipses for contours" for more information.
@ -4219,6 +4193,7 @@ of the OutputArray must be CV_32F.
*/
CV_EXPORTS_W double minEnclosingTriangle( InputArray points, CV_OUT OutputArray triangle );
/**
@brief Finds a convex polygon of minimum area enclosing a 2D point set and returns its area.
@ -4226,7 +4201,7 @@ This function takes a given set of 2D points and finds the enclosing polygon wit
area. It takes the set of points and the parameter k as input and returns the area of the minimal
enclosing polygon.
The Implementation is based on a paper by Aggarwal, Chang and Yap @cite AggarwalChangYap85. They
The Implementation is based on a paper by Aggarwal, Chang and Yap @cite Aggarwal1985. They
provide a \f$\theta(n²log(n)log(k))\f$ algorighm for finding the minimal convex polygon with k
vertices enclosing a 2D convex polygon with n vertices (k < n). Since the #minEnclosingConvexPolygon
function takes a 2D point set as input, an additional preprocessing step of computing the convex hull
@ -4241,6 +4216,7 @@ is lower than \f$\theta(n²log(n)log(k))\f$. Thus the overall complexity of the
CV_EXPORTS_W double minEnclosingConvexPolygon ( InputArray points, OutputArray polygon, int k );
/** @brief Compares two shapes.
The function compares two shapes. All three implemented methods use the Hu invariants (see #HuMoments)

View File

@ -1,12 +1,3 @@
/*
All the functionality must be put into cv:: namespace, or nested namespace, e.g. cv::vslam::
*/
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// This file is part of OpenCV project.
@ -139,7 +130,7 @@ struct IntersectionPoint
struct FlushIntersect
{
IntersectionPoint intersection = {};
float extra_area = std::numeric_limits<float>::max();
double extra_area = std::numeric_limits<double>::max();
bool done = false;
};
@ -156,7 +147,7 @@ struct BalancedIntersect
{
cv::Point2f pi = {-1, -1};
cv::Point2f pj = {-1, -1};
float extra_area = std::numeric_limits<float>::max();
double extra_area = std::numeric_limits<double>::max();
int flush = -1;
bool position = false;
bool done = false;
@ -172,7 +163,7 @@ struct BalancedIntersect
*/
struct Segment
{
float extra_area = std::numeric_limits<float>::max();
double extra_area = std::numeric_limits<double>::max();
int side = -1;
bool flush = false;
bool exists = false;
@ -187,7 +178,7 @@ struct Segment
*/
struct Minimum
{
float area = std::numeric_limits<float>::max();
double area = std::numeric_limits<double>::max();
int i = -1;
int j = -1;
};
@ -217,7 +208,7 @@ struct Kgon
{
std::vector<Side> sides;
std::vector<cv::Point2f> vertices;
float extra_area = std::numeric_limits<float>::max();
double extra_area = std::numeric_limits<double>::max();
int i = -1;
int j = -1;
};
@ -253,8 +244,7 @@ private:
std::vector<std::vector<BalancedIntersect>> balanced_intersections;
std::vector<cv::Point2f> area_edges;
float extraArea(int first, int last, const cv::Point2f& extra1,
const cv::Point2f& extra2);
double extraArea ( int first, int last, const cv::Point2f& extra1, const cv::Point2f& extra2 );
BalancedIntersect flush(int i, int j, int e);
@ -415,7 +405,7 @@ const FlushIntersect& FlushIntersections::lineIntersect(int i, int j)
if(itr.done)
return itr;
const int n = ngon.size();
const size_t n = ngon.size();
if((i + 1) % n == j)
{
itr.intersection.point = ngon[j];
@ -438,7 +428,7 @@ const FlushIntersect& FlushIntersections::lineIntersect(int i, int j)
}
else
{
itr.extra_area = std::numeric_limits<float>::max();
itr.extra_area = std::numeric_limits<double>::max();
itr.intersection.position = false;
itr.done = true;
}
@ -452,7 +442,7 @@ const FlushIntersect& FlushIntersections::lineIntersect(int i, int j)
* @param extra1 Last point of the sequence
* @param extra2 Intersection point
*/
float BalancedIntersections::extraArea(int first, int last,
double BalancedIntersections::extraArea(int first, int last,
const cv::Point2f& extra1,
const cv::Point2f& extra2)
{
@ -480,7 +470,7 @@ BalancedIntersect BalancedIntersections::flush(int i, int j, int e)
if(j == e)
std::logic_error("");
const int n = ngon.size();
const size_t n = ngon.size();
const int before = (e - 1 + n) % n;
BalancedIntersect bi = balanced_intersections[i][j];
@ -541,7 +531,7 @@ BalancedIntersect BalancedIntersections::balancedIntersect(int i, int j, int e)
if(balanced_intersections[i][j].done)
return balanced_intersections[i][j];
const int n = ngon.size();
const size_t n = ngon.size();
if((i + 2) % n == j)
{
BalancedIntersect& bi = balanced_intersections[i][j];
@ -646,12 +636,12 @@ const std::vector<BalancedIntersect>& BalancedIntersections::operator[](
*/
void Chains::findSingleE(int i, int j, int l, int r)
{
const int n = ngon.size();
const size_t n = ngon.size();
Segment& one = single_sides[i][j];
if (one.done)
return;
float min_area = std::numeric_limits<float>::max();
double min_area = std::numeric_limits<double>::max();
for (int e = l; e != r + 1 && e != j; e = (e + 1) %n)
{
BalancedIntersect candidate = balanced_inters.balancedIntersect(i, j, e);
@ -676,7 +666,7 @@ void Chains::findSingleE(int i, int j, int l, int r)
*/
void Chains::singleSideImpl(int i, int j1, int j2)
{
const int n = ngon.size();
const size_t n = ngon.size();
if((j1 + 1) %n == j2)
{
return;
@ -702,12 +692,12 @@ void Chains::singleSideImpl(int i, int j1, int j2)
*/
void Chains::findMiddleE1(int i, int j, int l, int r)
{
const int n = ngon.size();
const size_t n = ngon.size();
Segment& one = middle_sides[1][i][j];
if (one.done)
return;
float min_area = std::numeric_limits<float>::max();
double min_area = std::numeric_limits<double>::max();
for (int e = l; e != r + 1 && e != j; e = (e + 1) %n)
{
const FlushIntersect& before = intersections.lineIntersect(i, e);
@ -717,7 +707,7 @@ void Chains::findMiddleE1(int i, int j, int l, int r)
if(!after.intersection.position)
continue;
float tmp_area = before.extra_area + after.extra_area;
double tmp_area = before.extra_area + after.extra_area;
if(tmp_area < min_area)
{
min_area = tmp_area;
@ -738,7 +728,7 @@ void Chains::findMiddleE1(int i, int j, int l, int r)
*/
void Chains::middleSideImpl1(int i, int j1, int j2)
{
const int n = ngon.size();
const size_t n = ngon.size();
if((j1 + 1) %n == j2)
{
return;
@ -765,7 +755,7 @@ void Chains::middleSideImpl1(int i, int j1, int j2)
*/
void Chains::findMiddleE(int h, int i, int j, int l, int r)
{
const int n = ngon.size();
const size_t n = ngon.size();
Segment& one = middle_sides[h][i][j];
if (one.done)
return;
@ -791,17 +781,17 @@ void Chains::findMiddleE(int h, int i, int j, int l, int r)
return;
}
float min_area = std::numeric_limits<float>::max();
double min_area = std::numeric_limits<double>::max();
for (int e = l; e != r + 1 && e != j; e = (e + 1) %n)
{
const Segment& before = middle_sides[h_floor][i][e];
if (before.extra_area == std::numeric_limits<float>::max())
if (before.extra_area == std::numeric_limits<double>::max())
continue;
const Segment& after = middle_sides[h_ceil][e][j];
if(after.extra_area == std::numeric_limits<float>::max())
if(after.extra_area == std::numeric_limits<double>::max())
continue;
float tmp_area = before.extra_area + after.extra_area;
double tmp_area = before.extra_area + after.extra_area;
if(tmp_area < min_area)
{
min_area = tmp_area;
@ -823,7 +813,7 @@ void Chains::findMiddleE(int h, int i, int j, int l, int r)
*/
void Chains::middleSideImpl(int h, int i, int j1, int j2)
{
const int n = ngon.size();
const size_t n = ngon.size();
if((j1 + 1) %n == j2)
{
return;
@ -869,8 +859,8 @@ std::set<int> Chains::relevantChainLengths(int h)
*/
void Chains::calcOneSidedChains()
{
const int n = ngon.size();
for(int i = 0; i < n; i++)
const size_t n = ngon.size();
for(size_t i = 0; i < n; i++)
{
int j1 = (i + 2) %n, j2 = (i - 2 + n) %n;
@ -886,12 +876,12 @@ void Chains::calcOneSidedChains()
*/
void Chains::calcMiddleChains(int h)
{
const int n = ngon.size();
const size_t n = ngon.size();
if (h == 0)
{
for (int i = 0; i < n; i++)
for (size_t i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
for (size_t j = 0; j < n; j++)
{
Segment& one = middle_sides[h][i][j];
const FlushIntersect itrs = intersections.lineIntersect(i, j);
@ -907,7 +897,7 @@ void Chains::calcMiddleChains(int h)
}
if (h == 1)
{
for (int i = 0; i < n; i++)
for (size_t i = 0; i < n; i++)
{
int j1 = (i + 2) %n, j2 = (i - 2 + n) %n;
@ -918,7 +908,7 @@ void Chains::calcMiddleChains(int h)
return;
}
for (int i = 0; i < n; i++)
for (size_t i = 0; i < n; i++)
{
int j1 = (i + 2) %n, j2 = (i - 2 + n) %n;
@ -943,7 +933,7 @@ Minimum Chains::minimumArea(int n, int k)
if(!single_sides[i][j].exists || !middle_sides[k - 3][j][i].exists)
continue;
float tmp_area =
double tmp_area =
single_sides[i][j].extra_area + middle_sides[k - 3][j][i].extra_area;
if(tmp_area < min.area)
{
@ -1096,22 +1086,22 @@ static void findMinEnclosingPolygon(const std::vector<cv::Point2f> &ngon,
{
throw std::invalid_argument( "k must be 3 or higher" );
}
const int n = ngon.size();
if (n == k)
const size_t n = ngon.size();
if ((const int)n == k)
{
throw std::runtime_error ("(n = k)");
}
if (n < k)
if ((const int)n < k)
{
throw std::runtime_error ("(n < k)");
}
}
catch (std::invalid_argument message)
catch (std::invalid_argument &message)
{
std::cout << "invalid argument: " << message.what() << std::endl;
return;
}
catch (std::runtime_error message)
catch (std::runtime_error &message)
{
std::cout << "Warning: no minimum area polygon calculated " << message.what() << std::endl;
cv::Mat(ngon).copyTo(minPolygon);
@ -1149,7 +1139,7 @@ static void findMinAreaPolygon(const std::vector<cv::Point2f> &ngon,
double &area,
int k) {
const int n = ngon.size();
const size_t n = ngon.size();
Chains chains(ngon, k);
chains.calcOneSidedChains();

View File

@ -1077,32 +1077,43 @@ TEST(minEnclosingPolygon, input_errors)
std::vector<cv::Point2f> kgon;
std::vector<cv::Point2f> ngon;
std::cout << "Four lines of \'invalid argument: ...\' expected:" << std::endl;
std::cout << "Four lines of \'invalid argument: ...\' are expected:" << std::endl;
ngon = {{0.0, 0.0}, {1.0, 1.0}};
EXPECT_NO_THROW(minEnclosingConvexPolygon(ngon, kgon, 3))
<< "unexpected exception: not enough points in input ngon (n < 3)";
ngon = {{0.0, 0.0}, {0.0, 0.0}, {1.0, 1.0}, {1.0, 1.0}};
EXPECT_NO_THROW(minEnclosingConvexPolygon(ngon, kgon, 3))
<< "unexpected exception: not enough different points in input ngon (double points)";
ngon = {{0.0, 0.0}, {1.0, 1.0}, {2.0, 2.0}, {3.0, 3.0}, {4.0, 4.0}};
EXPECT_NO_THROW(minEnclosingConvexPolygon(ngon, kgon, 3))
<< "unexpected exception: all points on line";
ngon = {{0.0, 0.0}, {0.0, 1.0}, {1.0, 0.0}, {1.0, 1.0}};
EXPECT_NO_THROW(minEnclosingConvexPolygon(ngon, kgon, 2)) << "unexpected exception: k < 3";
}
TEST(minEnclosingPolygon, input_warnings)
{
double area = -1.0;
std::vector<cv::Point2f> kgon;
std::vector<cv::Point2f> ngon;
std::cout << "Two lines of \'Warning: ...\' are expected:" << std::endl;
std::cout << "Two lines of \'Warning: ...\' expected:" << std::endl;
ngon = {{0.0, 0.0}, {0.0, 1.0}, {1.0, 0.0}, {1.0, 1.0}};
EXPECT_NO_THROW({
area = minEnclosingConvexPolygon(ngon, kgon, 4);
}) << "unexpected exception: n = k failed";
EXPECT_NEAR(area, 1, 1e-4) << "n = k: area not equal " << ngon;
EXPECT_NEAR(area, 1.0, 1e-4) << "n = k: area not equal " << ngon;
ngon = {{0.0, 0.0}, {0.0, 1.0}, {1.0, 0.0}, {1.0, 1.0}};
EXPECT_NO_THROW({
area = minEnclosingConvexPolygon(ngon, kgon, 5);
}) << "unexpected exception: n < k failed";
EXPECT_NEAR(area, 1, 1e-4) << "n < k: area not equal " << ngon;
EXPECT_NEAR(area, 1.0, 1e-4) << "n < k: area not equal " << ngon;
}
TEST(minEnclosingPolygon, unit_circle)
@ -1182,6 +1193,6 @@ TEST(minEnclosingPolygon, pentagon)
}
}
}} // namespace
/* End of file. */