mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
390 lines
9.9 KiB
390 lines
9.9 KiB
#include "perf_precomp.hpp" |
|
|
|
namespace opencv_test |
|
{ |
|
using namespace perf; |
|
|
|
namespace { |
|
|
|
typedef perf::TestBaseWithParam<size_t> VectorLength; |
|
|
|
PERF_TEST_P(VectorLength, phase32f, testing::Values(128, 1000, 128*1024, 512*1024, 1024*1024)) |
|
{ |
|
size_t length = GetParam(); |
|
vector<float> X(length); |
|
vector<float> Y(length); |
|
vector<float> angle(length); |
|
|
|
declare.in(X, Y, WARMUP_RNG).out(angle); |
|
|
|
TEST_CYCLE_N(200) cv::phase(X, Y, angle, true); |
|
|
|
SANITY_CHECK(angle, 5e-5); |
|
} |
|
|
|
PERF_TEST_P(VectorLength, phase64f, testing::Values(128, 1000, 128*1024, 512*1024, 1024*1024)) |
|
{ |
|
size_t length = GetParam(); |
|
vector<double> X(length); |
|
vector<double> Y(length); |
|
vector<double> angle(length); |
|
|
|
declare.in(X, Y, WARMUP_RNG).out(angle); |
|
|
|
TEST_CYCLE_N(200) cv::phase(X, Y, angle, true); |
|
|
|
SANITY_CHECK(angle, 5e-5); |
|
} |
|
|
|
// generates random vectors, performs Gram-Schmidt orthogonalization on them |
|
Mat randomOrtho(int rows, int ftype, RNG& rng) |
|
{ |
|
Mat result(rows, rows, ftype); |
|
rng.fill(result, RNG::UNIFORM, cv::Scalar(-1), cv::Scalar(1)); |
|
|
|
for (int i = 0; i < rows; i++) |
|
{ |
|
Mat v = result.row(i); |
|
|
|
for (int j = 0; j < i; j++) |
|
{ |
|
Mat p = result.row(j); |
|
v -= p.dot(v) * p; |
|
} |
|
|
|
v = v * (1. / cv::norm(v)); |
|
} |
|
|
|
return result; |
|
} |
|
|
|
template<typename FType> |
|
Mat buildRandomMat(int rows, int cols, RNG& rng, int rank, bool symmetrical) |
|
{ |
|
int mtype = cv::traits::Depth<FType>::value; |
|
Mat u = randomOrtho(rows, mtype, rng); |
|
Mat v = randomOrtho(cols, mtype, rng); |
|
Mat s(rows, cols, mtype, Scalar(0)); |
|
|
|
std::vector<FType> singVals(rank); |
|
rng.fill(singVals, RNG::UNIFORM, Scalar(0), Scalar(10)); |
|
std::sort(singVals.begin(), singVals.end()); |
|
auto singIter = singVals.rbegin(); |
|
for (int i = 0; i < rank; i++) |
|
{ |
|
s.at<FType>(i, i) = *singIter++; |
|
} |
|
|
|
if (symmetrical) |
|
return u * s * u.t(); |
|
else |
|
return u * s * v.t(); |
|
} |
|
|
|
Mat buildRandomMat(int rows, int cols, int mtype, RNG& rng, int rank, bool symmetrical) |
|
{ |
|
if (mtype == CV_32F) |
|
{ |
|
return buildRandomMat<float>(rows, cols, rng, rank, symmetrical); |
|
} |
|
else if (mtype == CV_64F) |
|
{ |
|
return buildRandomMat<double>(rows, cols, rng, rank, symmetrical); |
|
} |
|
else |
|
{ |
|
CV_Error(cv::Error::StsBadArg, "This type is not supported"); |
|
} |
|
} |
|
|
|
CV_ENUM(SolveDecompEnum, DECOMP_LU, DECOMP_SVD, DECOMP_EIG, DECOMP_CHOLESKY, DECOMP_QR) |
|
|
|
enum RankMatrixOptions |
|
{ |
|
RANK_HALF, RANK_MINUS_1, RANK_FULL |
|
}; |
|
|
|
CV_ENUM(RankEnum, RANK_HALF, RANK_MINUS_1, RANK_FULL) |
|
|
|
enum SolutionsOptions |
|
{ |
|
NO_SOLUTIONS, ONE_SOLUTION, MANY_SOLUTIONS |
|
}; |
|
|
|
CV_ENUM(SolutionsEnum, NO_SOLUTIONS, ONE_SOLUTION, MANY_SOLUTIONS) |
|
|
|
typedef perf::TestBaseWithParam<std::tuple<int, RankEnum, MatDepth, SolveDecompEnum, bool, SolutionsEnum>> SolveTest; |
|
|
|
PERF_TEST_P(SolveTest, randomMat, ::testing::Combine( |
|
::testing::Values(31, 64, 100), |
|
::testing::Values(RANK_HALF, RANK_MINUS_1, RANK_FULL), |
|
::testing::Values(CV_32F, CV_64F), |
|
::testing::Values(DECOMP_LU, DECOMP_SVD, DECOMP_EIG, DECOMP_CHOLESKY, DECOMP_QR), |
|
::testing::Bool(), // normal |
|
::testing::Values(NO_SOLUTIONS, ONE_SOLUTION, MANY_SOLUTIONS) |
|
)) |
|
{ |
|
auto t = GetParam(); |
|
int size = std::get<0>(t); |
|
auto rankEnum = std::get<1>(t); |
|
int mtype = std::get<2>(t); |
|
int method = std::get<3>(t); |
|
bool normal = std::get<4>(t); |
|
auto solutions = std::get<5>(t); |
|
|
|
bool symmetrical = (method == DECOMP_CHOLESKY || method == DECOMP_LU); |
|
|
|
if (normal) |
|
{ |
|
method |= DECOMP_NORMAL; |
|
} |
|
|
|
int rank = size; |
|
switch (rankEnum) |
|
{ |
|
case RANK_HALF: rank /= 2; break; |
|
case RANK_MINUS_1: rank -= 1; break; |
|
default: break; |
|
} |
|
|
|
RNG& rng = theRNG(); |
|
Mat A = buildRandomMat(size, size, mtype, rng, rank, symmetrical); |
|
Mat x(size, 1, mtype); |
|
Mat b(size, 1, mtype); |
|
|
|
switch (solutions) |
|
{ |
|
// no solutions, let's make b random |
|
case NO_SOLUTIONS: |
|
{ |
|
rng.fill(b, RNG::UNIFORM, Scalar(-1), Scalar(1)); |
|
} |
|
break; |
|
// exactly 1 solution, let's combine b from A and x |
|
case ONE_SOLUTION: |
|
{ |
|
rng.fill(x, RNG::UNIFORM, Scalar(-10), Scalar(10)); |
|
b = A * x; |
|
} |
|
break; |
|
// infinitely many solutions, let's make b zero |
|
default: |
|
{ |
|
b = 0; |
|
} |
|
break; |
|
} |
|
|
|
TEST_CYCLE() cv::solve(A, b, x, method); |
|
|
|
SANITY_CHECK_NOTHING(); |
|
} |
|
|
|
typedef perf::TestBaseWithParam<std::tuple<std::tuple<int, int>, RankEnum, MatDepth, bool, bool>> SvdTest; |
|
|
|
PERF_TEST_P(SvdTest, decompose, ::testing::Combine( |
|
::testing::Values(std::make_tuple(5, 15), std::make_tuple(32, 32), std::make_tuple(100, 100)), |
|
::testing::Values(RANK_HALF, RANK_MINUS_1, RANK_FULL), |
|
::testing::Values(CV_32F, CV_64F), |
|
::testing::Bool(), // symmetrical |
|
::testing::Bool() // needUV |
|
)) |
|
{ |
|
auto t = GetParam(); |
|
auto rc = std::get<0>(t); |
|
auto rankEnum = std::get<1>(t); |
|
int mtype = std::get<2>(t); |
|
bool symmetrical = std::get<3>(t); |
|
bool needUV = std::get<4>(t); |
|
|
|
int rows = std::get<0>(rc); |
|
int cols = std::get<1>(rc); |
|
|
|
if (symmetrical) |
|
{ |
|
rows = max(rows, cols); |
|
cols = rows; |
|
} |
|
|
|
int rank = std::min(rows, cols); |
|
switch (rankEnum) |
|
{ |
|
case RANK_HALF: rank /= 2; break; |
|
case RANK_MINUS_1: rank -= 1; break; |
|
default: break; |
|
} |
|
|
|
int flags = needUV ? 0 : SVD::NO_UV; |
|
|
|
RNG& rng = theRNG(); |
|
Mat A = buildRandomMat(rows, cols, mtype, rng, rank, symmetrical); |
|
TEST_CYCLE() cv::SVD svd(A, flags); |
|
|
|
SANITY_CHECK_NOTHING(); |
|
} |
|
|
|
|
|
PERF_TEST_P(SvdTest, backSubst, ::testing::Combine( |
|
::testing::Values(std::make_tuple(5, 15), std::make_tuple(32, 32), std::make_tuple(100, 100)), |
|
::testing::Values(RANK_HALF, RANK_MINUS_1, RANK_FULL), |
|
::testing::Values(CV_32F, CV_64F), |
|
// back substitution works the same regardless of source matrix properties |
|
::testing::Values(true), |
|
// back substitution has no sense without u and v |
|
::testing::Values(true) // needUV |
|
)) |
|
{ |
|
auto t = GetParam(); |
|
auto rc = std::get<0>(t); |
|
auto rankEnum = std::get<1>(t); |
|
int mtype = std::get<2>(t); |
|
|
|
int rows = std::get<0>(rc); |
|
int cols = std::get<1>(rc); |
|
|
|
int rank = std::min(rows, cols); |
|
switch (rankEnum) |
|
{ |
|
case RANK_HALF: rank /= 2; break; |
|
case RANK_MINUS_1: rank -= 1; break; |
|
default: break; |
|
} |
|
|
|
RNG& rng = theRNG(); |
|
Mat A = buildRandomMat(rows, cols, mtype, rng, rank, /* symmetrical */ false); |
|
cv::SVD svd(A); |
|
// preallocate to not spend time on it during backSubst() |
|
Mat dst(cols, 1, mtype); |
|
Mat rhs(rows, 1, mtype); |
|
rng.fill(rhs, RNG::UNIFORM, Scalar(-10), Scalar(10)); |
|
|
|
TEST_CYCLE() svd.backSubst(rhs, dst); |
|
|
|
SANITY_CHECK_NOTHING(); |
|
} |
|
|
|
|
|
typedef perf::TestBaseWithParam< testing::tuple<int, int, int> > KMeans; |
|
|
|
PERF_TEST_P_(KMeans, single_iter) |
|
{ |
|
RNG& rng = theRNG(); |
|
const int K = testing::get<0>(GetParam()); |
|
const int dims = testing::get<1>(GetParam()); |
|
const int N = testing::get<2>(GetParam()); |
|
const int attempts = 5; |
|
|
|
Mat data(N, dims, CV_32F); |
|
rng.fill(data, RNG::UNIFORM, -0.1, 0.1); |
|
|
|
const int N0 = K; |
|
Mat data0(N0, dims, CV_32F); |
|
rng.fill(data0, RNG::UNIFORM, -1, 1); |
|
|
|
for (int i = 0; i < N; i++) |
|
{ |
|
int base = rng.uniform(0, N0); |
|
cv::add(data0.row(base), data.row(i), data.row(i)); |
|
} |
|
|
|
declare.in(data); |
|
|
|
Mat labels, centers; |
|
|
|
TEST_CYCLE() |
|
{ |
|
kmeans(data, K, labels, TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 1, 0), |
|
attempts, KMEANS_PP_CENTERS, centers); |
|
} |
|
|
|
SANITY_CHECK_NOTHING(); |
|
} |
|
|
|
PERF_TEST_P_(KMeans, good) |
|
{ |
|
RNG& rng = theRNG(); |
|
const int K = testing::get<0>(GetParam()); |
|
const int dims = testing::get<1>(GetParam()); |
|
const int N = testing::get<2>(GetParam()); |
|
const int attempts = 5; |
|
|
|
Mat data(N, dims, CV_32F); |
|
rng.fill(data, RNG::UNIFORM, -0.1, 0.1); |
|
|
|
const int N0 = K; |
|
Mat data0(N0, dims, CV_32F); |
|
rng.fill(data0, RNG::UNIFORM, -1, 1); |
|
|
|
for (int i = 0; i < N; i++) |
|
{ |
|
int base = rng.uniform(0, N0); |
|
cv::add(data0.row(base), data.row(i), data.row(i)); |
|
} |
|
|
|
declare.in(data); |
|
|
|
Mat labels, centers; |
|
|
|
TEST_CYCLE() |
|
{ |
|
kmeans(data, K, labels, TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 30, 0), |
|
attempts, KMEANS_PP_CENTERS, centers); |
|
} |
|
|
|
SANITY_CHECK_NOTHING(); |
|
} |
|
|
|
PERF_TEST_P_(KMeans, with_duplicates) |
|
{ |
|
RNG& rng = theRNG(); |
|
const int K = testing::get<0>(GetParam()); |
|
const int dims = testing::get<1>(GetParam()); |
|
const int N = testing::get<2>(GetParam()); |
|
const int attempts = 5; |
|
|
|
Mat data(N, dims, CV_32F, Scalar::all(0)); |
|
|
|
const int N0 = std::max(2, K * 2 / 3); |
|
Mat data0(N0, dims, CV_32F); |
|
rng.fill(data0, RNG::UNIFORM, -1, 1); |
|
|
|
for (int i = 0; i < N; i++) |
|
{ |
|
int base = rng.uniform(0, N0); |
|
data0.row(base).copyTo(data.row(i)); |
|
} |
|
|
|
declare.in(data); |
|
|
|
Mat labels, centers; |
|
|
|
TEST_CYCLE() |
|
{ |
|
kmeans(data, K, labels, TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 30, 0), |
|
attempts, KMEANS_PP_CENTERS, centers); |
|
} |
|
|
|
SANITY_CHECK_NOTHING(); |
|
} |
|
|
|
INSTANTIATE_TEST_CASE_P(/*nothing*/ , KMeans, |
|
testing::Values( |
|
// K clusters, dims, N points |
|
testing::make_tuple(2, 3, 100000), |
|
testing::make_tuple(4, 3, 500), |
|
testing::make_tuple(4, 3, 1000), |
|
testing::make_tuple(4, 3, 10000), |
|
testing::make_tuple(8, 3, 1000), |
|
testing::make_tuple(8, 16, 1000), |
|
testing::make_tuple(8, 64, 1000), |
|
testing::make_tuple(16, 16, 1000), |
|
testing::make_tuple(16, 32, 1000), |
|
testing::make_tuple(32, 16, 1000), |
|
testing::make_tuple(32, 32, 1000), |
|
testing::make_tuple(100, 2, 1000) |
|
) |
|
); |
|
|
|
} |
|
|
|
} // namespace
|
|
|