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:
@@ -26,6 +26,7 @@
|
||||
@defgroup gapi_transform Graph API: Image and channel composition functions
|
||||
@}
|
||||
*/
|
||||
|
||||
namespace cv { namespace gapi {
|
||||
namespace core {
|
||||
using GMat2 = std::tuple<GMat,GMat>;
|
||||
@@ -508,6 +509,77 @@ namespace core {
|
||||
return in.withType(in.depth, in.chan).withSize(dsize);
|
||||
}
|
||||
};
|
||||
|
||||
G_TYPED_KERNEL(
|
||||
GKMeansND,
|
||||
<std::tuple<GOpaque<double>,GMat,GMat>(GMat,int,GMat,TermCriteria,int,KmeansFlags)>,
|
||||
"org.opencv.core.kmeansND") {
|
||||
|
||||
static std::tuple<GOpaqueDesc,GMatDesc,GMatDesc>
|
||||
outMeta(const GMatDesc& in, int K, const GMatDesc& bestLabels, const TermCriteria&, int,
|
||||
KmeansFlags flags) {
|
||||
GAPI_Assert(in.depth == CV_32F);
|
||||
std::vector<int> amount_n_dim = detail::checkVector(in);
|
||||
int amount = amount_n_dim[0], dim = amount_n_dim[1];
|
||||
if (amount == -1) // Mat with height != 1, width != 1, channels != 1 given
|
||||
{ // which means that kmeans will consider the following:
|
||||
amount = in.size.height;
|
||||
dim = in.size.width * in.chan;
|
||||
}
|
||||
// kmeans sets these labels' sizes when no bestLabels given:
|
||||
GMatDesc out_labels(CV_32S, 1, Size{1, amount});
|
||||
// kmeans always sets these centers' sizes:
|
||||
GMatDesc centers (CV_32F, 1, Size{dim, K});
|
||||
if (flags & KMEANS_USE_INITIAL_LABELS)
|
||||
{
|
||||
GAPI_Assert(bestLabels.depth == CV_32S);
|
||||
int labels_amount = detail::checkVector(bestLabels, 1u);
|
||||
GAPI_Assert(labels_amount == amount);
|
||||
out_labels = bestLabels; // kmeans preserves bestLabels' sizes if given
|
||||
}
|
||||
return std::make_tuple(empty_gopaque_desc(), out_labels, centers);
|
||||
}
|
||||
};
|
||||
|
||||
G_TYPED_KERNEL(
|
||||
GKMeansNDNoInit,
|
||||
<std::tuple<GOpaque<double>,GMat,GMat>(GMat,int,TermCriteria,int,KmeansFlags)>,
|
||||
"org.opencv.core.kmeansNDNoInit") {
|
||||
|
||||
static std::tuple<GOpaqueDesc,GMatDesc,GMatDesc>
|
||||
outMeta(const GMatDesc& in, int K, const TermCriteria&, int, KmeansFlags flags) {
|
||||
GAPI_Assert( !(flags & KMEANS_USE_INITIAL_LABELS) );
|
||||
GAPI_Assert(in.depth == CV_32F);
|
||||
std::vector<int> amount_n_dim = detail::checkVector(in);
|
||||
int amount = amount_n_dim[0], dim = amount_n_dim[1];
|
||||
if (amount == -1) // Mat with height != 1, width != 1, channels != 1 given
|
||||
{ // which means that kmeans will consider the following:
|
||||
amount = in.size.height;
|
||||
dim = in.size.width * in.chan;
|
||||
}
|
||||
GMatDesc out_labels(CV_32S, 1, Size{1, amount});
|
||||
GMatDesc centers (CV_32F, 1, Size{dim, K});
|
||||
return std::make_tuple(empty_gopaque_desc(), out_labels, centers);
|
||||
}
|
||||
};
|
||||
|
||||
G_TYPED_KERNEL(GKMeans2D, <std::tuple<GOpaque<double>,GArray<int>,GArray<Point2f>>
|
||||
(GArray<Point2f>,int,GArray<int>,TermCriteria,int,KmeansFlags)>,
|
||||
"org.opencv.core.kmeans2D") {
|
||||
static std::tuple<GOpaqueDesc,GArrayDesc,GArrayDesc>
|
||||
outMeta(const GArrayDesc&,int,const GArrayDesc&,const TermCriteria&,int,KmeansFlags) {
|
||||
return std::make_tuple(empty_gopaque_desc(), empty_array_desc(), empty_array_desc());
|
||||
}
|
||||
};
|
||||
|
||||
G_TYPED_KERNEL(GKMeans3D, <std::tuple<GOpaque<double>,GArray<int>,GArray<Point3f>>
|
||||
(GArray<Point3f>,int,GArray<int>,TermCriteria,int,KmeansFlags)>,
|
||||
"org.opencv.core.kmeans3D") {
|
||||
static std::tuple<GOpaqueDesc,GArrayDesc,GArrayDesc>
|
||||
outMeta(const GArrayDesc&,int,const GArrayDesc&,const TermCriteria&,int,KmeansFlags) {
|
||||
return std::make_tuple(empty_gopaque_desc(), empty_array_desc(), empty_array_desc());
|
||||
}
|
||||
};
|
||||
} // namespace core
|
||||
|
||||
namespace streaming {
|
||||
@@ -1757,6 +1829,79 @@ GAPI_EXPORTS GMat warpAffine(const GMat& src, const Mat& M, const Size& dsize, i
|
||||
int borderMode = cv::BORDER_CONSTANT, const Scalar& borderValue = Scalar());
|
||||
//! @} gapi_transform
|
||||
|
||||
/** @brief Finds centers of clusters and groups input samples around the clusters.
|
||||
|
||||
The function kmeans implements a k-means algorithm that finds the centers of K clusters
|
||||
and groups the input samples around the clusters. As an output, \f$\texttt{bestLabels}_i\f$
|
||||
contains a 0-based cluster index for the \f$i^{th}\f$ sample.
|
||||
|
||||
@note
|
||||
- Function textual ID is "org.opencv.core.kmeansND"
|
||||
- In case of an N-dimentional points' set given, input GMat can have the following traits:
|
||||
2 dimensions, a single row or column if there are N channels,
|
||||
or N columns if there is a single channel. Mat should have @ref CV_32F depth.
|
||||
- Although, if GMat with height != 1, width != 1, channels != 1 given as data, n-dimensional
|
||||
samples are considered given in amount of A, where A = height, n = width * channels.
|
||||
- In case of GMat given as data:
|
||||
- the output labels are returned as 1-channel GMat with sizes
|
||||
width = 1, height = A, where A is samples amount, or width = bestLabels.width,
|
||||
height = bestLabels.height if bestLabels given;
|
||||
- the cluster centers are returned as 1-channel GMat with sizes
|
||||
width = n, height = K, where n is samples' dimentionality and K is clusters' amount.
|
||||
- As one of possible usages, if you want to control the initial labels for each attempt
|
||||
by yourself, you can utilize just the core of the function. To do that, set the number
|
||||
of attempts to 1, initialize labels each time using a custom algorithm, pass them with the
|
||||
( flags = #KMEANS_USE_INITIAL_LABELS ) flag, and then choose the best (most-compact) clustering.
|
||||
|
||||
@param data Data for clustering. An array of N-Dimensional points with float coordinates is needed.
|
||||
Function can take GArray<Point2f>, GArray<Point3f> for 2D and 3D cases or GMat for any
|
||||
dimentionality and channels.
|
||||
@param K Number of clusters to split the set by.
|
||||
@param bestLabels Optional input integer array that can store the supposed initial cluster indices
|
||||
for every sample. Used when ( flags = #KMEANS_USE_INITIAL_LABELS ) flag is set.
|
||||
@param criteria The algorithm termination criteria, that is, the maximum number of iterations
|
||||
and/or the desired accuracy. The accuracy is specified as criteria.epsilon. As soon as each of
|
||||
the cluster centers moves by less than criteria.epsilon on some iteration, the algorithm stops.
|
||||
@param attempts Flag to specify the number of times the algorithm is executed using different
|
||||
initial labellings. The algorithm returns the labels that yield the best compactness (see the first
|
||||
function return value).
|
||||
@param flags Flag that can take values of cv::KmeansFlags .
|
||||
|
||||
@return
|
||||
- Compactness measure that is computed as
|
||||
\f[\sum _i \| \texttt{samples} _i - \texttt{centers} _{ \texttt{labels} _i} \| ^2\f]
|
||||
after every attempt. The best (minimum) value is chosen and the corresponding labels and the
|
||||
compactness value are returned by the function.
|
||||
- Integer array that stores the cluster indices for every sample.
|
||||
- Array of the cluster centers.
|
||||
*/
|
||||
GAPI_EXPORTS std::tuple<GOpaque<double>,GMat,GMat>
|
||||
kmeans(const GMat& data, const int K, const GMat& bestLabels,
|
||||
const TermCriteria& criteria, const int attempts, const KmeansFlags flags);
|
||||
|
||||
/** @overload
|
||||
@note
|
||||
- Function textual ID is "org.opencv.core.kmeansNDNoInit"
|
||||
- #KMEANS_USE_INITIAL_LABELS flag must not be set while using this overload.
|
||||
*/
|
||||
GAPI_EXPORTS std::tuple<GOpaque<double>,GMat,GMat>
|
||||
kmeans(const GMat& data, const int K, const TermCriteria& criteria, const int attempts,
|
||||
const KmeansFlags flags);
|
||||
|
||||
/** @overload
|
||||
@note Function textual ID is "org.opencv.core.kmeans2D"
|
||||
*/
|
||||
GAPI_EXPORTS std::tuple<GOpaque<double>,GArray<int>,GArray<Point2f>>
|
||||
kmeans(const GArray<Point2f>& data, const int K, const GArray<int>& bestLabels,
|
||||
const TermCriteria& criteria, const int attempts, const KmeansFlags flags);
|
||||
|
||||
/** @overload
|
||||
@note Function textual ID is "org.opencv.core.kmeans3D"
|
||||
*/
|
||||
GAPI_EXPORTS std::tuple<GOpaque<double>,GArray<int>,GArray<Point3f>>
|
||||
kmeans(const GArray<Point3f>& data, const int K, const GArray<int>& bestLabels,
|
||||
const TermCriteria& criteria, const int attempts, const KmeansFlags flags);
|
||||
|
||||
namespace streaming {
|
||||
/** @brief Gets dimensions from Mat.
|
||||
|
||||
|
||||
@@ -203,6 +203,27 @@ struct GAPI_EXPORTS GMatDesc
|
||||
|
||||
static inline GMatDesc empty_gmat_desc() { return GMatDesc{-1,-1,{-1,-1}}; }
|
||||
|
||||
namespace gapi { namespace detail {
|
||||
/** Checks GMatDesc fields if the passed matrix is a set of n-dimentional points.
|
||||
@param in GMatDesc to check.
|
||||
@param n expected dimensionality.
|
||||
@return the amount of points. In case input matrix can't be described as vector of points
|
||||
of expected dimensionality, returns -1.
|
||||
*/
|
||||
int checkVector(const GMatDesc& in, const size_t n);
|
||||
|
||||
/** @overload
|
||||
|
||||
Checks GMatDesc fields if the passed matrix can be described as a set of points of any
|
||||
dimensionality.
|
||||
|
||||
@return array of two elements in form of std::vector<int>: the amount of points
|
||||
and their calculated dimensionality. In case input matrix can't be described as vector of points,
|
||||
returns {-1, -1}.
|
||||
*/
|
||||
std::vector<int> checkVector(const GMatDesc& in);
|
||||
}} // namespace gapi::detail
|
||||
|
||||
#if !defined(GAPI_STANDALONE)
|
||||
GAPI_EXPORTS GMatDesc descr_of(const cv::UMat &mat);
|
||||
#endif // !defined(GAPI_STANDALONE)
|
||||
|
||||
@@ -43,15 +43,6 @@ void validateFindingContoursMeta(const int depth, const int chan, const int mode
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Checks if the passed mat is a set of n-dimentional points of the given depth
|
||||
bool isPointsVector(const int chan, const cv::Size &size, const int depth,
|
||||
const int n, const int ddepth = -1)
|
||||
{
|
||||
return (ddepth == depth || ddepth < 0) &&
|
||||
((chan == n && (size.height == 1 || size.width == 1)) ||
|
||||
(chan == 1 && size.width == n));
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
namespace cv { namespace gapi {
|
||||
@@ -212,10 +203,17 @@ namespace imgproc {
|
||||
G_TYPED_KERNEL(GBoundingRectMat, <GOpaque<Rect>(GMat)>,
|
||||
"org.opencv.imgproc.shape.boundingRectMat") {
|
||||
static GOpaqueDesc outMeta(GMatDesc in) {
|
||||
GAPI_Assert((in.depth == CV_8U && in.chan == 1) ||
|
||||
(isPointsVector(in.chan, in.size, in.depth, 2, CV_32S) ||
|
||||
isPointsVector(in.chan, in.size, in.depth, 2, CV_32F)));
|
||||
|
||||
if (in.depth == CV_8U)
|
||||
{
|
||||
GAPI_Assert(in.chan == 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
GAPI_Assert (in.depth == CV_32S || in.depth == CV_32F);
|
||||
int amount = detail::checkVector(in, 2u);
|
||||
GAPI_Assert(amount != -1 &&
|
||||
"Input Mat can't be described as vector of 2-dimentional points");
|
||||
}
|
||||
return empty_gopaque_desc();
|
||||
}
|
||||
};
|
||||
@@ -237,7 +235,9 @@ namespace imgproc {
|
||||
G_TYPED_KERNEL(GFitLine2DMat, <GOpaque<Vec4f>(GMat,DistanceTypes,double,double,double)>,
|
||||
"org.opencv.imgproc.shape.fitLine2DMat") {
|
||||
static GOpaqueDesc outMeta(GMatDesc in,DistanceTypes,double,double,double) {
|
||||
GAPI_Assert(isPointsVector(in.chan, in.size, in.depth, 2, -1));
|
||||
int amount = detail::checkVector(in, 2u);
|
||||
GAPI_Assert(amount != -1 &&
|
||||
"Input Mat can't be described as vector of 2-dimentional points");
|
||||
return empty_gopaque_desc();
|
||||
}
|
||||
};
|
||||
@@ -269,7 +269,9 @@ namespace imgproc {
|
||||
G_TYPED_KERNEL(GFitLine3DMat, <GOpaque<Vec6f>(GMat,DistanceTypes,double,double,double)>,
|
||||
"org.opencv.imgproc.shape.fitLine3DMat") {
|
||||
static GOpaqueDesc outMeta(GMatDesc in,int,double,double,double) {
|
||||
GAPI_Assert(isPointsVector(in.chan, in.size, in.depth, 3, -1));
|
||||
int amount = detail::checkVector(in, 3u);
|
||||
GAPI_Assert(amount != -1 &&
|
||||
"Input Mat can't be described as vector of 3-dimentional points");
|
||||
return empty_gopaque_desc();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -36,6 +36,38 @@ const cv::GOrigin& cv::GMat::priv() const
|
||||
return *m_priv;
|
||||
}
|
||||
|
||||
static std::vector<int> checkVectorImpl(const int width, const int height, const int chan,
|
||||
const int n)
|
||||
{
|
||||
if (width == 1 && (n == -1 || n == chan))
|
||||
{
|
||||
return {height, chan};
|
||||
}
|
||||
else if (height == 1 && (n == -1 || n == chan))
|
||||
{
|
||||
return {width, chan};
|
||||
}
|
||||
else if (chan == 1 && (n == -1 || n == width))
|
||||
{
|
||||
return {height, width};
|
||||
}
|
||||
else // input Mat can't be described as vector of points of given dimensionality
|
||||
{
|
||||
return {-1, -1};
|
||||
}
|
||||
}
|
||||
|
||||
int cv::gapi::detail::checkVector(const cv::GMatDesc& in, const size_t n)
|
||||
{
|
||||
GAPI_Assert(n != 0u);
|
||||
return checkVectorImpl(in.size.width, in.size.height, in.chan, static_cast<int>(n))[0];
|
||||
}
|
||||
|
||||
std::vector<int> cv::gapi::detail::checkVector(const cv::GMatDesc& in)
|
||||
{
|
||||
return checkVectorImpl(in.size.width, in.size.height, in.chan, -1);
|
||||
}
|
||||
|
||||
namespace{
|
||||
template <typename T> cv::GMetaArgs vec_descr_of(const std::vector<T> &vec)
|
||||
{
|
||||
|
||||
@@ -388,6 +388,40 @@ GMat warpAffine(const GMat& src, const Mat& M, const Size& dsize, int flags,
|
||||
return core::GWarpAffine::on(src, M, dsize, flags, borderMode, borderValue);
|
||||
}
|
||||
|
||||
std::tuple<GOpaque<double>,GMat,GMat> kmeans(const GMat& data, const int K, const GMat& bestLabels,
|
||||
const TermCriteria& criteria, const int attempts,
|
||||
const KmeansFlags flags)
|
||||
{
|
||||
return core::GKMeansND::on(data, K, bestLabels, criteria, attempts, flags);
|
||||
}
|
||||
|
||||
std::tuple<GOpaque<double>,GMat,GMat> kmeans(const GMat& data, const int K,
|
||||
const TermCriteria& criteria, const int attempts,
|
||||
const KmeansFlags flags)
|
||||
{
|
||||
return core::GKMeansNDNoInit::on(data, K, criteria, attempts, flags);
|
||||
}
|
||||
|
||||
std::tuple<GOpaque<double>,GArray<int>,GArray<Point2f>> kmeans(const GArray<Point2f>& data,
|
||||
const int K,
|
||||
const GArray<int>& bestLabels,
|
||||
const TermCriteria& criteria,
|
||||
const int attempts,
|
||||
const KmeansFlags flags)
|
||||
{
|
||||
return core::GKMeans2D::on(data, K, bestLabels, criteria, attempts, flags);
|
||||
}
|
||||
|
||||
std::tuple<GOpaque<double>,GArray<int>,GArray<Point3f>> kmeans(const GArray<Point3f>& data,
|
||||
const int K,
|
||||
const GArray<int>& bestLabels,
|
||||
const TermCriteria& criteria,
|
||||
const int attempts,
|
||||
const KmeansFlags flags)
|
||||
{
|
||||
return core::GKMeans3D::on(data, K, bestLabels, criteria, attempts, flags);
|
||||
}
|
||||
|
||||
GOpaque<Size> streaming::size(const GMat& src)
|
||||
{
|
||||
return streaming::GSize::on(src);
|
||||
|
||||
@@ -585,6 +585,63 @@ GAPI_OCV_KERNEL(GCPUWarpAffine, cv::gapi::core::GWarpAffine)
|
||||
}
|
||||
};
|
||||
|
||||
GAPI_OCV_KERNEL(GCPUKMeansND, cv::gapi::core::GKMeansND)
|
||||
{
|
||||
static void run(const cv::Mat& data, const int K, const cv::Mat& inBestLabels,
|
||||
const cv::TermCriteria& criteria, const int attempts,
|
||||
const cv::KmeansFlags flags,
|
||||
double& compactness, cv::Mat& outBestLabels, cv::Mat& centers)
|
||||
{
|
||||
if (flags & cv::KMEANS_USE_INITIAL_LABELS)
|
||||
{
|
||||
inBestLabels.copyTo(outBestLabels);
|
||||
}
|
||||
compactness = cv::kmeans(data, K, outBestLabels, criteria, attempts, flags, centers);
|
||||
}
|
||||
};
|
||||
|
||||
GAPI_OCV_KERNEL(GCPUKMeansNDNoInit, cv::gapi::core::GKMeansNDNoInit)
|
||||
{
|
||||
static void run(const cv::Mat& data, const int K, const cv::TermCriteria& criteria,
|
||||
const int attempts, const cv::KmeansFlags flags,
|
||||
double& compactness, cv::Mat& outBestLabels, cv::Mat& centers)
|
||||
{
|
||||
compactness = cv::kmeans(data, K, outBestLabels, criteria, attempts, flags, centers);
|
||||
}
|
||||
};
|
||||
|
||||
GAPI_OCV_KERNEL(GCPUKMeans2D, cv::gapi::core::GKMeans2D)
|
||||
{
|
||||
static void run(const std::vector<cv::Point2f>& data, const int K,
|
||||
const std::vector<int>& inBestLabels, const cv::TermCriteria& criteria,
|
||||
const int attempts, const cv::KmeansFlags flags,
|
||||
double& compactness, std::vector<int>& outBestLabels,
|
||||
std::vector<cv::Point2f>& centers)
|
||||
{
|
||||
if (flags & cv::KMEANS_USE_INITIAL_LABELS)
|
||||
{
|
||||
outBestLabels = inBestLabels;
|
||||
}
|
||||
compactness = cv::kmeans(data, K, outBestLabels, criteria, attempts, flags, centers);
|
||||
}
|
||||
};
|
||||
|
||||
GAPI_OCV_KERNEL(GCPUKMeans3D, cv::gapi::core::GKMeans3D)
|
||||
{
|
||||
static void run(const std::vector<cv::Point3f>& data, const int K,
|
||||
const std::vector<int>& inBestLabels, const cv::TermCriteria& criteria,
|
||||
const int attempts, const cv::KmeansFlags flags,
|
||||
double& compactness, std::vector<int>& outBestLabels,
|
||||
std::vector<cv::Point3f>& centers)
|
||||
{
|
||||
if (flags & cv::KMEANS_USE_INITIAL_LABELS)
|
||||
{
|
||||
outBestLabels = inBestLabels;
|
||||
}
|
||||
compactness = cv::kmeans(data, K, outBestLabels, criteria, attempts, flags, centers);
|
||||
}
|
||||
};
|
||||
|
||||
GAPI_OCV_KERNEL(GCPUParseSSDBL, cv::gapi::nn::parsers::GParseSSDBL)
|
||||
{
|
||||
static void run(const cv::Mat& in_ssd_result,
|
||||
@@ -714,6 +771,10 @@ cv::gapi::GKernelPackage cv::gapi::core::cpu::kernels()
|
||||
, GCPUNormalize
|
||||
, GCPUWarpPerspective
|
||||
, GCPUWarpAffine
|
||||
, GCPUKMeansND
|
||||
, GCPUKMeansNDNoInit
|
||||
, GCPUKMeans2D
|
||||
, GCPUKMeans3D
|
||||
, GCPUParseSSDBL
|
||||
, GOCVParseSSD
|
||||
, GCPUParseYolo
|
||||
|
||||
@@ -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