mirror of
https://github.com/opencv/opencv.git
synced 2026-07-31 08:13:04 +04:00
Merge pull request #18857 from OrestChura:oc/kmeans
[G-API]: kmeans() Standard Kernel Implementation
* cv::gapi::kmeans kernel implementation
- 4 overloads:
- standard GMat - for any dimensionality
- GMat without bestLabels initialization
- GArray<Point2f> - for 2D
- GArray<Point3f> - for 3D
- Accuracy tests:
- for every input - 2 tests
1) without initializing. In this case, no comparison with cv::kmeans is done as kmeans uses random auto-initialization
2) with initialization
- in both cases, only 1 attempt is done as after first attempt kmeans initializes bestLabels randomly
* Addressing comments
- bestLabels is returned to its original place among parameters
- checkVector and isPointsVector functions are merged into one, shared between core.hpp & imgproc.hpp by placing it into gmat.hpp (and implementation - to gmat.cpp)
- typos corrected
* addressing comments
- unified names in tests
- const added
- typos
* Addressing comments
- fixed the doc note
- ddepth -> expectedDepth, `< 0 ` -> `== -1`
* Fix unsupported cases of input Mat
- supported: multiple channels, reversed width
- added test cases for those
- added notes in docs
- refactored checkVector to return dimentionality along with quantity
* Addressing comments
- makes chackVector smaller and (maybe) clearer
* Addressing comments
* Addressing comments
- cv::checkVector -> cv::gapi::detail
* Addressing comments
- Changed checkVector: returns bool, quantity & dimensionality as references
* Addressing comments
- Polishing checkVector
- FIXME added
* Addressing discussion
- checkVector: added overload, separate two different functionalities
- depth assert - out of the function
* Addressing comments
- quantity -> amount, dimensionality -> dim
- Fix typos
* Addressing comments
- fix docs
- use 2 variable's definitions instead of one (for all non-trivial variables)
This commit is contained in:
@@ -151,6 +151,16 @@ GAPI_TEST_FIXTURE(WarpPerspectiveTest, initMatrixRandU,
|
||||
GAPI_TEST_FIXTURE(WarpAffineTest, initMatrixRandU,
|
||||
FIXTURE_API(CompareMats, double , double, int, int, cv::Scalar),
|
||||
6, cmpF, angle, scale, flags, border_mode, border_value)
|
||||
GAPI_TEST_FIXTURE(KMeansNDNoInitTest, initMatrixRandU, FIXTURE_API(int, cv::KmeansFlags),
|
||||
2, K, flags)
|
||||
GAPI_TEST_FIXTURE(KMeansNDInitTest, initMatrixRandU,
|
||||
FIXTURE_API(CompareMats, int, cv::KmeansFlags), 3, cmpF, K, flags)
|
||||
GAPI_TEST_FIXTURE(KMeans2DNoInitTest, initNothing, FIXTURE_API(int, cv::KmeansFlags),
|
||||
2, K, flags)
|
||||
GAPI_TEST_FIXTURE(KMeans2DInitTest, initNothing, FIXTURE_API(int, cv::KmeansFlags), 2, K, flags)
|
||||
GAPI_TEST_FIXTURE(KMeans3DNoInitTest, initNothing, FIXTURE_API(int, cv::KmeansFlags),
|
||||
2, K, flags)
|
||||
GAPI_TEST_FIXTURE(KMeans3DInitTest, initNothing, FIXTURE_API(int, cv::KmeansFlags), 2, K, flags)
|
||||
|
||||
GAPI_TEST_EXT_BASE_FIXTURE(ParseSSDBLTest, ParserSSDTest, initNothing,
|
||||
FIXTURE_API(float, int), 2, confidence_threshold, filter_label)
|
||||
|
||||
@@ -15,6 +15,16 @@
|
||||
namespace opencv_test
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
template <typename Elem>
|
||||
inline bool compareVectorsAbsExact(const std::vector<Elem>& outOCV,
|
||||
const std::vector<Elem>& outGAPI)
|
||||
{
|
||||
return AbsExactVector<Elem>().to_compare_f()(outOCV, outGAPI);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(MathOpTest, MatricesAccuracyTest)
|
||||
{
|
||||
// G-API code & corresponding OpenCV code ////////////////////////////////
|
||||
@@ -1377,6 +1387,187 @@ TEST_P(NormalizeTest, Test)
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(KMeansNDNoInitTest, AccuracyTest)
|
||||
{
|
||||
const int amount = sz.height != 1 ? sz.height : sz.width,
|
||||
dim = sz.height != 1 ? sz.width : (type >> CV_CN_SHIFT) + 1;
|
||||
// amount of channels
|
||||
const cv::TermCriteria criteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 30, 0);
|
||||
const int attempts = 1;
|
||||
double compact_gapi = -1.;
|
||||
cv::Mat labels_gapi, centers_gapi;
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
cv::GMat in;
|
||||
cv::GOpaque<double> compactness;
|
||||
cv::GMat outLabels, centers;
|
||||
std::tie(compactness, outLabels, centers) = cv::gapi::kmeans(in, K, criteria, attempts, flags);
|
||||
cv::GComputation c(cv::GIn(in), cv::GOut(compactness, outLabels, centers));
|
||||
c.apply(cv::gin(in_mat1), cv::gout(compact_gapi, labels_gapi, centers_gapi), getCompileArgs());
|
||||
// Validation //////////////////////////////////////////////////////////////
|
||||
{
|
||||
EXPECT_GE(compact_gapi, 0.);
|
||||
EXPECT_EQ(labels_gapi.cols, 1);
|
||||
EXPECT_EQ(labels_gapi.rows, amount);
|
||||
EXPECT_FALSE(labels_gapi.empty());
|
||||
EXPECT_EQ(centers_gapi.cols, dim);
|
||||
EXPECT_EQ(centers_gapi.rows, K);
|
||||
EXPECT_FALSE(centers_gapi.empty());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(KMeansNDInitTest, AccuracyTest)
|
||||
{
|
||||
const int amount = sz.height != 1 ? sz.height : sz.width;
|
||||
const cv::TermCriteria criteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 30, 0);
|
||||
const int attempts = 1;
|
||||
cv::Mat bestLabels(cv::Size{1, amount}, CV_32SC1);
|
||||
double compact_ocv = -1., compact_gapi = -1.;
|
||||
cv::Mat labels_ocv, labels_gapi, centers_ocv, centers_gapi;
|
||||
cv::randu(bestLabels, 0, K);
|
||||
bestLabels.copyTo(labels_ocv);
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
cv::GMat in, inLabels;
|
||||
cv::GOpaque<double> compactness;
|
||||
cv::GMat outLabels, centers;
|
||||
std::tie(compactness, outLabels, centers) =
|
||||
cv::gapi::kmeans(in, K, inLabels, criteria, attempts, flags);
|
||||
cv::GComputation c(cv::GIn(in, inLabels), cv::GOut(compactness, outLabels, centers));
|
||||
c.apply(cv::gin(in_mat1, bestLabels), cv::gout(compact_gapi, labels_gapi, centers_gapi),
|
||||
getCompileArgs());
|
||||
// OpenCV code /////////////////////////////////////////////////////////////
|
||||
compact_ocv = cv::kmeans(in_mat1, K, labels_ocv, criteria, attempts, flags, centers_ocv);
|
||||
// Comparison //////////////////////////////////////////////////////////////
|
||||
{
|
||||
EXPECT_TRUE(compact_gapi == compact_ocv);
|
||||
EXPECT_TRUE(cmpF(labels_gapi, labels_ocv));
|
||||
EXPECT_TRUE(cmpF(centers_gapi, centers_ocv));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(KMeans2DNoInitTest, AccuracyTest)
|
||||
{
|
||||
const int amount = sz.height;
|
||||
const cv::TermCriteria criteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 30, 0);
|
||||
const int attempts = 1;
|
||||
std::vector<cv::Point2f> in_vector{};
|
||||
double compact_gapi = -1.;
|
||||
std::vector<int> labels_gapi{};
|
||||
std::vector<cv::Point2f> centers_gapi{};
|
||||
initPointsVectorRandU(amount, in_vector);
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
cv::GArray<cv::Point2f> in;
|
||||
cv::GArray<int> inLabels(std::vector<int>{});
|
||||
cv::GOpaque<double> compactness;
|
||||
cv::GArray<int> outLabels;
|
||||
cv::GArray<cv::Point2f> centers;
|
||||
std::tie(compactness, outLabels, centers) =
|
||||
cv::gapi::kmeans(in, K, inLabels, criteria, attempts, flags);
|
||||
cv::GComputation c(cv::GIn(in), cv::GOut(compactness, outLabels, centers));
|
||||
c.apply(cv::gin(in_vector), cv::gout(compact_gapi, labels_gapi, centers_gapi), getCompileArgs());
|
||||
// Validation //////////////////////////////////////////////////////////////
|
||||
{
|
||||
EXPECT_GE(compact_gapi, 0.);
|
||||
EXPECT_EQ(labels_gapi.size(), static_cast<size_t>(amount));
|
||||
EXPECT_EQ(centers_gapi.size(), static_cast<size_t>(K));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(KMeans2DInitTest, AccuracyTest)
|
||||
{
|
||||
const int amount = sz.height;
|
||||
const cv::TermCriteria criteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 30, 0);
|
||||
const int attempts = 1;
|
||||
std::vector<cv::Point2f> in_vector{};
|
||||
std::vector<int> bestLabels(amount);
|
||||
double compact_ocv = -1., compact_gapi = -1.;
|
||||
std::vector<int> labels_ocv{}, labels_gapi{};
|
||||
std::vector<cv::Point2f> centers_ocv{}, centers_gapi{};
|
||||
initPointsVectorRandU(amount, in_vector);
|
||||
cv::randu(bestLabels, 0, K);
|
||||
labels_ocv = bestLabels;
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
cv::GArray<cv::Point2f> in;
|
||||
cv::GArray<int> inLabels;
|
||||
cv::GOpaque<double> compactness;
|
||||
cv::GArray<int> outLabels;
|
||||
cv::GArray<cv::Point2f> centers;
|
||||
std::tie(compactness, outLabels, centers) =
|
||||
cv::gapi::kmeans(in, K, inLabels, criteria, attempts, flags);
|
||||
cv::GComputation c(cv::GIn(in, inLabels), cv::GOut(compactness, outLabels, centers));
|
||||
c.apply(cv::gin(in_vector, bestLabels), cv::gout(compact_gapi, labels_gapi, centers_gapi),
|
||||
getCompileArgs());
|
||||
// OpenCV code /////////////////////////////////////////////////////////////
|
||||
compact_ocv = cv::kmeans(in_vector, K, labels_ocv, criteria, attempts, flags, centers_ocv);
|
||||
// Comparison //////////////////////////////////////////////////////////////
|
||||
{
|
||||
EXPECT_TRUE(compact_gapi == compact_ocv);
|
||||
EXPECT_TRUE(compareVectorsAbsExact(labels_gapi, labels_ocv));
|
||||
EXPECT_TRUE(compareVectorsAbsExact(centers_gapi, centers_ocv));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(KMeans3DNoInitTest, AccuracyTest)
|
||||
{
|
||||
const int amount = sz.height;
|
||||
const cv::TermCriteria criteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 30, 0);
|
||||
const int attempts = 1;
|
||||
std::vector<cv::Point3f> in_vector{};
|
||||
double compact_gapi = -1.;
|
||||
std::vector<int> labels_gapi{};
|
||||
std::vector<cv::Point3f> centers_gapi{};
|
||||
initPointsVectorRandU(amount, in_vector);
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
cv::GArray<cv::Point3f> in;
|
||||
cv::GArray<int> inLabels(std::vector<int>{});
|
||||
cv::GOpaque<double> compactness;
|
||||
cv::GArray<int> outLabels;
|
||||
cv::GArray<cv::Point3f> centers;
|
||||
std::tie(compactness, outLabels, centers) =
|
||||
cv::gapi::kmeans(in, K, inLabels, criteria, attempts, flags);
|
||||
cv::GComputation c(cv::GIn(in), cv::GOut(compactness, outLabels, centers));
|
||||
c.apply(cv::gin(in_vector), cv::gout(compact_gapi, labels_gapi, centers_gapi), getCompileArgs());
|
||||
// Validation //////////////////////////////////////////////////////////////
|
||||
{
|
||||
EXPECT_GE(compact_gapi, 0.);
|
||||
EXPECT_EQ(labels_gapi.size(), static_cast<size_t>(amount));
|
||||
EXPECT_EQ(centers_gapi.size(), static_cast<size_t>(K));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(KMeans3DInitTest, AccuracyTest)
|
||||
{
|
||||
const int amount = sz.height;
|
||||
const cv::TermCriteria criteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 30, 0);
|
||||
const int attempts = 1;
|
||||
std::vector<cv::Point3f> in_vector{};
|
||||
std::vector<int> bestLabels(amount);
|
||||
double compact_ocv = -1., compact_gapi = -1.;
|
||||
std::vector<int> labels_ocv{}, labels_gapi{};
|
||||
std::vector<cv::Point3f> centers_ocv{}, centers_gapi{};
|
||||
initPointsVectorRandU(amount, in_vector);
|
||||
cv::randu(bestLabels, 0, K);
|
||||
labels_ocv = bestLabels;
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
cv::GArray<cv::Point3f> in;
|
||||
cv::GArray<int> inLabels;
|
||||
cv::GOpaque<double> compactness;
|
||||
cv::GArray<int> outLabels;
|
||||
cv::GArray<cv::Point3f> centers;
|
||||
std::tie(compactness, outLabels, centers) =
|
||||
cv::gapi::kmeans(in, K, inLabels, criteria, attempts, flags);
|
||||
cv::GComputation c(cv::GIn(in, inLabels), cv::GOut(compactness, outLabels, centers));
|
||||
c.apply(cv::gin(in_vector, bestLabels), cv::gout(compact_gapi, labels_gapi, centers_gapi),
|
||||
getCompileArgs());
|
||||
// OpenCV code /////////////////////////////////////////////////////////////
|
||||
compact_ocv = cv::kmeans(in_vector, K, labels_ocv, criteria, attempts, flags, centers_ocv);
|
||||
// Comparison //////////////////////////////////////////////////////////////
|
||||
{
|
||||
EXPECT_TRUE(compact_gapi == compact_ocv);
|
||||
EXPECT_TRUE(compareVectorsAbsExact(labels_gapi, labels_ocv));
|
||||
EXPECT_TRUE(compareVectorsAbsExact(centers_gapi, centers_ocv));
|
||||
}
|
||||
}
|
||||
|
||||
// PLEASE DO NOT PUT NEW ACCURACY TESTS BELOW THIS POINT! //////////////////////
|
||||
|
||||
TEST_P(BackendOutputAllocationTest, EmptyOutput)
|
||||
|
||||
@@ -1174,6 +1174,28 @@ inline std::ostream& operator<<(std::ostream& os, DistanceTypes op)
|
||||
#undef CASE
|
||||
return os;
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, KmeansFlags op)
|
||||
{
|
||||
int op_(op);
|
||||
switch (op_)
|
||||
{
|
||||
case KmeansFlags::KMEANS_RANDOM_CENTERS:
|
||||
os << "KMEANS_RANDOM_CENTERS";
|
||||
break;
|
||||
case KmeansFlags::KMEANS_PP_CENTERS:
|
||||
os << "KMEANS_PP_CENTERS";
|
||||
break;
|
||||
case KmeansFlags::KMEANS_RANDOM_CENTERS | KmeansFlags::KMEANS_USE_INITIAL_LABELS:
|
||||
os << "KMEANS_RANDOM_CENTERS | KMEANS_USE_INITIAL_LABELS";
|
||||
break;
|
||||
case KmeansFlags::KMEANS_PP_CENTERS | KmeansFlags::KMEANS_USE_INITIAL_LABELS:
|
||||
os << "KMEANS_PP_CENTERS | KMEANS_USE_INITIAL_LABELS";
|
||||
break;
|
||||
default: GAPI_Assert(false && "unknown KmeansFlags value");
|
||||
}
|
||||
return os;
|
||||
}
|
||||
} // namespace cv
|
||||
|
||||
#endif //OPENCV_GAPI_TESTS_COMMON_HPP
|
||||
|
||||
@@ -484,6 +484,72 @@ INSTANTIATE_TEST_CASE_P(NormalizeTestCPU, NormalizeTest,
|
||||
Values(NORM_MINMAX, NORM_INF, NORM_L1, NORM_L2),
|
||||
Values(-1, CV_8U, CV_16U, CV_16S, CV_32F)));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(KMeansNDNoInitTestCPU, KMeansNDNoInitTest,
|
||||
Combine(Values(CV_32FC1),
|
||||
Values(cv::Size(2, 20)),
|
||||
Values(-1),
|
||||
Values(CORE_CPU),
|
||||
Values(5),
|
||||
Values(cv::KMEANS_RANDOM_CENTERS, cv::KMEANS_PP_CENTERS)));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(KMeansNDInitTestCPU, KMeansNDInitTest,
|
||||
Combine(Values(CV_32FC1, CV_32FC3),
|
||||
Values(cv::Size(1, 20),
|
||||
cv::Size(2, 20),
|
||||
cv::Size(5, 720)),
|
||||
Values(-1),
|
||||
Values(CORE_CPU),
|
||||
Values(AbsTolerance(0.01).to_compare_obj()),
|
||||
Values(5, 15),
|
||||
Values(cv::KMEANS_RANDOM_CENTERS | cv::KMEANS_USE_INITIAL_LABELS,
|
||||
cv::KMEANS_PP_CENTERS | cv::KMEANS_USE_INITIAL_LABELS)));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(KMeansNDInitReverseTestCPU, KMeansNDInitTest,
|
||||
Combine(Values(CV_32FC3),
|
||||
Values(cv::Size(20, 1)),
|
||||
Values(-1),
|
||||
Values(CORE_CPU),
|
||||
Values(AbsTolerance(0.01).to_compare_obj()),
|
||||
Values(5, 15),
|
||||
Values(cv::KMEANS_RANDOM_CENTERS | cv::KMEANS_USE_INITIAL_LABELS,
|
||||
cv::KMEANS_PP_CENTERS | cv::KMEANS_USE_INITIAL_LABELS)));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(KMeans2DNoInitTestCPU, KMeans2DNoInitTest,
|
||||
Combine(Values(-1),
|
||||
Values(cv::Size(-1, 20)),
|
||||
Values(-1),
|
||||
Values(CORE_CPU),
|
||||
Values(5),
|
||||
Values(cv::KMEANS_RANDOM_CENTERS, cv::KMEANS_PP_CENTERS)));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(KMeans2DInitTestCPU, KMeans2DInitTest,
|
||||
Combine(Values(-1),
|
||||
Values(cv::Size(-1, 720),
|
||||
cv::Size(-1, 20)),
|
||||
Values(-1),
|
||||
Values(CORE_CPU),
|
||||
Values(5, 15),
|
||||
Values(cv::KMEANS_RANDOM_CENTERS | cv::KMEANS_USE_INITIAL_LABELS,
|
||||
cv::KMEANS_PP_CENTERS | cv::KMEANS_USE_INITIAL_LABELS)));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(KMeans3DNoInitTestCPU, KMeans3DNoInitTest,
|
||||
Combine(Values(-1),
|
||||
Values(cv::Size(-1, 20)),
|
||||
Values(-1),
|
||||
Values(CORE_CPU),
|
||||
Values(5),
|
||||
Values(cv::KMEANS_RANDOM_CENTERS, cv::KMEANS_PP_CENTERS)));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(KMeans3DInitTestCPU, KMeans3DInitTest,
|
||||
Combine(Values(-1),
|
||||
Values(cv::Size(-1, 720),
|
||||
cv::Size(-1, 20)),
|
||||
Values(-1),
|
||||
Values(CORE_CPU),
|
||||
Values(5, 15),
|
||||
Values(cv::KMEANS_RANDOM_CENTERS | cv::KMEANS_USE_INITIAL_LABELS,
|
||||
cv::KMEANS_PP_CENTERS | cv::KMEANS_USE_INITIAL_LABELS)));
|
||||
|
||||
// PLEASE DO NOT PUT NEW ACCURACY TESTS BELOW THIS POINT! //////////////////////
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(BackendOutputAllocationTestCPU, BackendOutputAllocationTest,
|
||||
|
||||
Reference in New Issue
Block a user