feat: 切换后端至PaddleOCR-NCNN,切换工程为CMake

1.项目后端整体迁移至PaddleOCR-NCNN算法,已通过基本的兼容性测试
2.工程改为使用CMake组织,后续为了更好地兼容第三方库,不再提供QMake工程
3.重整权利声明文件,重整代码工程,确保最小化侵权风险

Log: 切换后端至PaddleOCR-NCNN,切换工程为CMake
Change-Id: I4d5d2c5d37505a4a24b389b1a4c5d12f17bfa38c
This commit is contained in:
wangzhengyang
2022-05-10 09:54:44 +08:00
parent ecdd171c6f
commit 718c41634f
10018 changed files with 3593797 additions and 186748 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,469 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2010-2012, Institute Of Software Chinese Academy Of Science, all rights reserved.
// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
// Copyright (C) 2010-2012, Multicoreware, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// @Authors
// Jia Haipeng, jiahaipeng95@gmail.com
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "../test_precomp.hpp"
#include "opencv2/ts/ocl_test.hpp"
#ifdef HAVE_OPENCL
namespace opencv_test {
namespace ocl {
//////////////////////////////////////// Merge ///////////////////////////////////////////////
PARAM_TEST_CASE(Merge, MatDepth, int, bool)
{
int depth, nsrc;
bool use_roi;
TEST_DECLARE_INPUT_PARAMETER(src1);
TEST_DECLARE_INPUT_PARAMETER(src2);
TEST_DECLARE_INPUT_PARAMETER(src3);
TEST_DECLARE_INPUT_PARAMETER(src4);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
std::vector<Mat> src_roi;
std::vector<UMat> usrc_roi;
virtual void SetUp()
{
depth = GET_PARAM(0);
nsrc = GET_PARAM(1);
use_roi = GET_PARAM(2);
CV_Assert(nsrc >= 1 && nsrc <= 4);
}
int type()
{
return CV_MAKE_TYPE(depth, randomInt(1, 3));
}
void generateTestData()
{
Size roiSize = randomSize(1, MAX_VALUE);
{
Border src1Border = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(src1, src1_roi, roiSize, src1Border, type(), 2, 11);
Border src2Border = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(src2, src2_roi, roiSize, src2Border, type(), -1540, 1740);
Border src3Border = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(src3, src3_roi, roiSize, src3Border, type(), -1540, 1740);
Border src4Border = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(src4, src4_roi, roiSize, src4Border, type(), -1540, 1740);
}
UMAT_UPLOAD_INPUT_PARAMETER(src1);
UMAT_UPLOAD_INPUT_PARAMETER(src2);
UMAT_UPLOAD_INPUT_PARAMETER(src3);
UMAT_UPLOAD_INPUT_PARAMETER(src4);
src_roi.clear(); usrc_roi.clear(); // for test_loop_times > 1
src_roi.push_back(src1_roi), usrc_roi.push_back(usrc1_roi);
if (nsrc >= 2)
src_roi.push_back(src2_roi), usrc_roi.push_back(usrc2_roi);
if (nsrc >= 3)
src_roi.push_back(src3_roi), usrc_roi.push_back(usrc3_roi);
if (nsrc >= 4)
src_roi.push_back(src4_roi), usrc_roi.push_back(usrc4_roi);
int dcn = 0;
for (int i = 0; i < nsrc; ++i)
dcn += src_roi[i].channels();
Border dstBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(dst, dst_roi, roiSize, dstBorder, CV_MAKE_TYPE(depth, dcn), 5, 16);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
}
void Near(double threshold = 0.)
{
OCL_EXPECT_MATS_NEAR(dst, threshold);
}
};
OCL_TEST_P(Merge, Accuracy)
{
for(int j = 0; j < test_loop_times; j++)
{
generateTestData();
OCL_OFF(cv::merge(src_roi, dst_roi));
OCL_ON(cv::merge(usrc_roi, udst_roi));
Near();
}
}
//////////////////////////////////////// Split ///////////////////////////////////////////////
PARAM_TEST_CASE(Split, MatType, Channels, bool)
{
int depth, cn;
bool use_roi;
TEST_DECLARE_INPUT_PARAMETER(src);
TEST_DECLARE_OUTPUT_PARAMETER(dst1);
TEST_DECLARE_OUTPUT_PARAMETER(dst2);
TEST_DECLARE_OUTPUT_PARAMETER(dst3);
TEST_DECLARE_OUTPUT_PARAMETER(dst4);
std::vector<Mat> dst_roi, dst;
std::vector<UMat> udst_roi, udst;
virtual void SetUp()
{
depth = GET_PARAM(0);
cn = GET_PARAM(1);
use_roi = GET_PARAM(2);
CV_Assert(cn >= 1 && cn <= 4);
}
void generateTestData()
{
Size roiSize = randomSize(1, MAX_VALUE);
Border srcBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, roiSize, srcBorder, CV_MAKE_TYPE(depth, cn), 5, 16);
{
Border dst1Border = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(dst1, dst1_roi, roiSize, dst1Border, depth, 2, 11);
Border dst2Border = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(dst2, dst2_roi, roiSize, dst2Border, depth, -1540, 1740);
Border dst3Border = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(dst3, dst3_roi, roiSize, dst3Border, depth, -1540, 1740);
Border dst4Border = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(dst4, dst4_roi, roiSize, dst4Border, depth, -1540, 1740);
}
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst1);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst2);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst3);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst4);
dst_roi.push_back(dst1_roi), udst_roi.push_back(udst1_roi),
dst.push_back(dst1), udst.push_back(udst1);
if (cn >= 2)
dst_roi.push_back(dst2_roi), udst_roi.push_back(udst2_roi),
dst.push_back(dst2), udst.push_back(udst2);
if (cn >= 3)
dst_roi.push_back(dst3_roi), udst_roi.push_back(udst3_roi),
dst.push_back(dst3), udst.push_back(udst3);
if (cn >= 4)
dst_roi.push_back(dst4_roi), udst_roi.push_back(udst4_roi),
dst.push_back(dst4), udst.push_back(udst4);
}
};
OCL_TEST_P(Split, Accuracy)
{
for (int j = 0; j < test_loop_times; j++)
{
generateTestData();
OCL_OFF(cv::split(src_roi, dst_roi));
OCL_ON(cv::split(usrc_roi, udst_roi));
for (int i = 0; i < cn; ++i)
{
EXPECT_MAT_NEAR(dst[i], udst[i], 0.0);
EXPECT_MAT_NEAR(dst_roi[i], udst_roi[i], 0.0);
}
}
}
//////////////////////////////////////// MixChannels ///////////////////////////////////////////////
PARAM_TEST_CASE(MixChannels, MatType, bool)
{
int depth;
bool use_roi;
TEST_DECLARE_INPUT_PARAMETER(src1);
TEST_DECLARE_INPUT_PARAMETER(src2);
TEST_DECLARE_INPUT_PARAMETER(src3);
TEST_DECLARE_INPUT_PARAMETER(src4);
TEST_DECLARE_OUTPUT_PARAMETER(dst1);
TEST_DECLARE_OUTPUT_PARAMETER(dst2);
TEST_DECLARE_OUTPUT_PARAMETER(dst3);
TEST_DECLARE_OUTPUT_PARAMETER(dst4);
std::vector<Mat> src_roi, dst_roi, dst;
std::vector<UMat> usrc_roi, udst_roi, udst;
std::vector<int> fromTo;
virtual void SetUp()
{
depth = GET_PARAM(0);
use_roi = GET_PARAM(1);
}
// generate number of channels and create type
int type()
{
int cn = randomInt(1, 5);
return CV_MAKE_TYPE(depth, cn);
}
void generateTestData()
{
src_roi.clear();
dst_roi.clear();
dst.clear();
usrc_roi.clear();
udst_roi.clear();
udst.clear();
fromTo.clear();
Size roiSize = randomSize(1, MAX_VALUE);
{
Border src1Border = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(src1, src1_roi, roiSize, src1Border, type(), 2, 11);
Border src2Border = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(src2, src2_roi, roiSize, src2Border, type(), -1540, 1740);
Border src3Border = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(src3, src3_roi, roiSize, src3Border, type(), -1540, 1740);
Border src4Border = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(src4, src4_roi, roiSize, src4Border, type(), -1540, 1740);
}
{
Border dst1Border = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(dst1, dst1_roi, roiSize, dst1Border, type(), 2, 11);
Border dst2Border = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(dst2, dst2_roi, roiSize, dst2Border, type(), -1540, 1740);
Border dst3Border = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(dst3, dst3_roi, roiSize, dst3Border, type(), -1540, 1740);
Border dst4Border = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(dst4, dst4_roi, roiSize, dst4Border, type(), -1540, 1740);
}
UMAT_UPLOAD_INPUT_PARAMETER(src1);
UMAT_UPLOAD_INPUT_PARAMETER(src2);
UMAT_UPLOAD_INPUT_PARAMETER(src3);
UMAT_UPLOAD_INPUT_PARAMETER(src4);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst1);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst2);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst3);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst4);
int nsrc = randomInt(1, 5), ndst = randomInt(1, 5);
src_roi.push_back(src1_roi), usrc_roi.push_back(usrc1_roi);
if (nsrc >= 2)
src_roi.push_back(src2_roi), usrc_roi.push_back(usrc2_roi);
if (nsrc >= 3)
src_roi.push_back(src3_roi), usrc_roi.push_back(usrc3_roi);
if (nsrc >= 4)
src_roi.push_back(src4_roi), usrc_roi.push_back(usrc4_roi);
dst_roi.push_back(dst1_roi), udst_roi.push_back(udst1_roi),
dst.push_back(dst1), udst.push_back(udst1);
if (ndst >= 2)
dst_roi.push_back(dst2_roi), udst_roi.push_back(udst2_roi),
dst.push_back(dst2), udst.push_back(udst2);
if (ndst >= 3)
dst_roi.push_back(dst3_roi), udst_roi.push_back(udst3_roi),
dst.push_back(dst3), udst.push_back(udst3);
if (ndst >= 4)
dst_roi.push_back(dst4_roi), udst_roi.push_back(udst4_roi),
dst.push_back(dst4), udst.push_back(udst4);
int scntotal = 0, dcntotal = 0;
for (int i = 0; i < nsrc; ++i)
scntotal += src_roi[i].channels();
for (int i = 0; i < ndst; ++i)
dcntotal += dst_roi[i].channels();
int npairs = randomInt(1, std::min(scntotal, dcntotal) + 1);
fromTo.resize(npairs << 1);
for (int i = 0; i < npairs; ++i)
{
fromTo[i<<1] = randomInt(0, scntotal);
fromTo[(i<<1)+1] = randomInt(0, dcntotal);
}
}
};
OCL_TEST_P(MixChannels, Accuracy)
{
for (int j = 0; j < test_loop_times + 10; j++)
{
generateTestData();
OCL_OFF(cv::mixChannels(src_roi, dst_roi, fromTo));
OCL_ON(cv::mixChannels(usrc_roi, udst_roi, fromTo));
for (size_t i = 0, size = dst_roi.size(); i < size; ++i)
{
EXPECT_MAT_NEAR(dst[i], udst[i], 0.0);
EXPECT_MAT_NEAR(dst_roi[i], udst_roi[i], 0.0);
}
}
}
//////////////////////////////////////// InsertChannel ///////////////////////////////////////////////
PARAM_TEST_CASE(InsertChannel, MatDepth, Channels, bool)
{
int depth, cn, coi;
bool use_roi;
TEST_DECLARE_INPUT_PARAMETER(src);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
virtual void SetUp()
{
depth = GET_PARAM(0);
cn = GET_PARAM(1);
use_roi = GET_PARAM(2);
}
void generateTestData()
{
Size roiSize = randomSize(1, MAX_VALUE);
coi = randomInt(0, cn);
Border srcBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, roiSize, srcBorder, depth, 2, 11);
Border dstBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(dst, dst_roi, roiSize, dstBorder, CV_MAKE_TYPE(depth, cn), 5, 16);
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
}
};
OCL_TEST_P(InsertChannel, Accuracy)
{
for(int j = 0; j < test_loop_times; j++)
{
generateTestData();
OCL_OFF(cv::insertChannel(src_roi, dst_roi, coi));
OCL_ON(cv::insertChannel(usrc_roi, udst_roi, coi));
OCL_EXPECT_MATS_NEAR(dst, 0);
}
}
//////////////////////////////////////// ExtractChannel ///////////////////////////////////////////////
PARAM_TEST_CASE(ExtractChannel, MatDepth, Channels, bool)
{
int depth, cn, coi;
bool use_roi;
TEST_DECLARE_INPUT_PARAMETER(src);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
virtual void SetUp()
{
depth = GET_PARAM(0);
cn = GET_PARAM(1);
use_roi = GET_PARAM(2);
}
void generateTestData()
{
Size roiSize = randomSize(1, MAX_VALUE);
coi = randomInt(0, cn);
Border srcBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, roiSize, srcBorder, CV_MAKE_TYPE(depth, cn), 2, 11);
Border dstBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(dst, dst_roi, roiSize, dstBorder, depth, 5, 16);
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
}
};
OCL_TEST_P(ExtractChannel, Accuracy)
{
for(int j = 0; j < test_loop_times; j++)
{
generateTestData();
OCL_OFF(cv::extractChannel(src_roi, dst_roi, coi));
OCL_ON(cv::extractChannel(usrc_roi, udst_roi, coi));
OCL_EXPECT_MATS_NEAR(dst, 0);
}
}
//////////////////////////////////////// Instantiation ///////////////////////////////////////////////
OCL_INSTANTIATE_TEST_CASE_P(Channels, Merge, Combine(OCL_ALL_DEPTHS, Values(1, 2, 3, 4), Bool()));
OCL_INSTANTIATE_TEST_CASE_P(Channels, Split, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool()));
OCL_INSTANTIATE_TEST_CASE_P(Channels, MixChannels, Combine(OCL_ALL_DEPTHS, Bool()));
OCL_INSTANTIATE_TEST_CASE_P(Channels, InsertChannel, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool()));
OCL_INSTANTIATE_TEST_CASE_P(Channels, ExtractChannel, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool()));
} } // namespace opencv_test::ocl
#endif // HAVE_OPENCL

View File

@ -0,0 +1,190 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2010-2012, Multicoreware, Inc., all rights reserved.
// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// @Authors
// Peng Xiao, pengxiao@multicorewareinc.com
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors as is and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "../test_precomp.hpp"
#include "opencv2/ts/ocl_test.hpp"
#ifdef HAVE_OPENCL
enum OCL_FFT_TYPE
{
R2R = 0,
C2R = 1,
R2C = 2,
C2C = 3
};
namespace opencv_test {
namespace ocl {
////////////////////////////////////////////////////////////////////////////
// Dft
PARAM_TEST_CASE(Dft, cv::Size, OCL_FFT_TYPE, MatDepth, bool, bool, bool, bool)
{
cv::Size dft_size;
int dft_flags, depth, cn, dft_type;
bool hint;
bool is1d;
TEST_DECLARE_INPUT_PARAMETER(src);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
virtual void SetUp()
{
dft_size = GET_PARAM(0);
dft_type = GET_PARAM(1);
depth = GET_PARAM(2);
dft_flags = 0;
switch (dft_type)
{
case R2R: dft_flags |= cv::DFT_REAL_OUTPUT; cn = 1; break;
case C2R: dft_flags |= cv::DFT_REAL_OUTPUT; cn = 2; break;
case R2C: dft_flags |= cv::DFT_COMPLEX_OUTPUT; cn = 1; break;
case C2C: dft_flags |= cv::DFT_COMPLEX_OUTPUT; cn = 2; break;
}
if (GET_PARAM(3))
dft_flags |= cv::DFT_INVERSE;
if (GET_PARAM(4))
dft_flags |= cv::DFT_ROWS;
if (GET_PARAM(5))
dft_flags |= cv::DFT_SCALE;
hint = GET_PARAM(6);
is1d = (dft_flags & DFT_ROWS) != 0 || dft_size.height == 1;
}
void generateTestData()
{
src = randomMat(dft_size, CV_MAKE_TYPE(depth, cn), 0.0, 100.0);
usrc = src.getUMat(ACCESS_READ);
}
};
OCL_TEST_P(Dft, Mat)
{
generateTestData();
int nonzero_rows = hint ? src.rows - randomInt(1, src.rows-1) : 0;
OCL_OFF(cv::dft(src, dst, dft_flags, nonzero_rows));
OCL_ON(cv::dft(usrc, udst, dft_flags, nonzero_rows));
// In case forward R2C 1d transform dst contains only half of output
// without complex conjugate
if (dft_type == R2C && is1d && (dft_flags & cv::DFT_INVERSE) == 0)
{
dst = dst(cv::Range(0, dst.rows), cv::Range(0, dst.cols/2 + 1));
udst = udst(cv::Range(0, udst.rows), cv::Range(0, udst.cols/2 + 1));
}
double eps = src.size().area() * 1e-4;
EXPECT_MAT_NEAR(dst, udst, eps);
}
////////////////////////////////////////////////////////////////////////////
// MulSpectrums
PARAM_TEST_CASE(MulSpectrums, bool, bool)
{
bool ccorr, useRoi;
TEST_DECLARE_INPUT_PARAMETER(src1);
TEST_DECLARE_INPUT_PARAMETER(src2);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
virtual void SetUp()
{
ccorr = GET_PARAM(0);
useRoi = GET_PARAM(1);
}
void generateTestData()
{
Size srcRoiSize = randomSize(1, MAX_VALUE);
Border src1Border = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(src1, src1_roi, srcRoiSize, src1Border, CV_32FC2, -11, 11);
Border src2Border = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(src2, src2_roi, srcRoiSize, src2Border, CV_32FC2, -11, 11);
Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(dst, dst_roi, srcRoiSize, dstBorder, CV_32FC2, 5, 16);
UMAT_UPLOAD_INPUT_PARAMETER(src1);
UMAT_UPLOAD_INPUT_PARAMETER(src2);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
}
};
OCL_TEST_P(MulSpectrums, Mat)
{
for (int i = 0; i < test_loop_times; ++i)
{
generateTestData();
OCL_OFF(cv::mulSpectrums(src1_roi, src2_roi, dst_roi, 0, ccorr));
OCL_ON(cv::mulSpectrums(usrc1_roi, usrc2_roi, udst_roi, 0, ccorr));
OCL_EXPECT_MATS_NEAR_RELATIVE(dst, 1e-6);
}
}
OCL_INSTANTIATE_TEST_CASE_P(OCL_ImgProc, MulSpectrums, testing::Combine(Bool(), Bool()));
OCL_INSTANTIATE_TEST_CASE_P(Core, Dft, Combine(Values(cv::Size(45, 72), cv::Size(36, 36), cv::Size(512, 1), cv::Size(1280, 768)),
Values((OCL_FFT_TYPE) R2C, (OCL_FFT_TYPE) C2C, (OCL_FFT_TYPE) R2R, (OCL_FFT_TYPE) C2R),
Values(CV_32F, CV_64F),
Bool(), // DFT_INVERSE
Bool(), // DFT_ROWS
Bool(), // DFT_SCALE
Bool() // hint
)
);
} } // namespace opencv_test::ocl
#endif // HAVE_OPENCL

View File

@ -0,0 +1,165 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2010-2012, Multicoreware, Inc., all rights reserved.
// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// @Authors
// Peng Xiao, pengxiao@multicorewareinc.com
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors as is and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "../test_precomp.hpp"
#include "opencv2/ts/ocl_test.hpp"
#ifdef HAVE_OPENCL
namespace opencv_test {
namespace ocl {
////////////////////////////////////////////////////////////////////////////
// GEMM
PARAM_TEST_CASE(Gemm,
MatType,
bool, // GEMM_1_T
bool, // GEMM_2_T
bool, // GEMM_3_T
bool // ROI
)
{
bool use_roi;
int type, flags;
bool atrans, btrans, ctrans;
double alpha, beta;
int M, N, K;
TEST_DECLARE_INPUT_PARAMETER(A);
TEST_DECLARE_INPUT_PARAMETER(B);
TEST_DECLARE_INPUT_PARAMETER(C);
TEST_DECLARE_OUTPUT_PARAMETER(D);
virtual void SetUp()
{
atrans = btrans = ctrans = false;
type = GET_PARAM(0);
use_roi = GET_PARAM(4);
flags = 0;
if (GET_PARAM(1))
flags |= GEMM_1_T, atrans = true;
if (GET_PARAM(2))
flags |= GEMM_2_T, btrans = true;
if (GET_PARAM(3))
flags |= GEMM_3_T, ctrans = true;
}
void generateTestData()
{
M = (int)randomDoubleLog(1, 100);
N = (int)randomDoubleLog(1, 100);
K = (int)randomDoubleLog(1, 1200);
M = roundUp(M, 1);
N = roundUp(N, 1);
K = roundUp(K, 1);
Size ARoiSize = (atrans) ? Size(M, K) : Size(K, M);
Border ABorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(A, A_roi, ARoiSize, ABorder, type, -11, 11);
Size BRoiSize = (btrans) ? Size(K, N) : Size(N, K);
Border BBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(B, B_roi, BRoiSize, BBorder, type, -11, 11);
Size CRoiSize = (ctrans) ? Size(M, N) : Size(N, M);
Border CBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(C, C_roi, CRoiSize, CBorder, type, -11, 11);
Size DRoiSize = Size(N, M);
Border DBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(D, D_roi, DRoiSize, DBorder, type, -11, 11);
alpha = randomDouble(-4, 4);
beta = randomDouble(-4, 4);
UMAT_UPLOAD_INPUT_PARAMETER(A);
UMAT_UPLOAD_INPUT_PARAMETER(B);
UMAT_UPLOAD_INPUT_PARAMETER(C);
UMAT_UPLOAD_OUTPUT_PARAMETER(D);
}
};
OCL_TEST_P(Gemm, Accuracy)
{
for (int i = 0; i < test_loop_times; ++i)
{
generateTestData();
SCOPED_TRACE(cv::format("i=%d: M=%d N=%d K=%d", i, M, N, K));
OCL_OFF(cv::gemm(A_roi, B_roi, alpha, C_roi, beta, D_roi, flags));
OCL_ON(cv::gemm(uA_roi, uB_roi, alpha, uC_roi, beta, uD_roi, flags));
double eps = D_roi.size().area() * (1e-5 * K);
OCL_EXPECT_MATS_NEAR(D, eps);
}
}
OCL_INSTANTIATE_TEST_CASE_P(Core, Gemm, ::testing::Combine(
testing::Values(CV_32FC1, CV_32FC2, CV_64FC1, CV_64FC2),
Bool(), Bool(), Bool(), Bool()));
// Test for non-Intel GPUs to check CL_INVALID_WORK_GROUP_SIZE when localsize > globalsize
OCL_TEST(Gemm, small)
{
UMat A(2, 3, CV_32F), B(4, 3, CV_32F), uC(2, 4, CV_32F);
Mat C(2, 4, CV_32F);
randu(A, -1, 1);
randu(B, -1, 1);
OCL_OFF(cv::gemm(A, B, 1, noArray(), 0, C, GEMM_2_T));
OCL_ON(cv::gemm(A, B, 1, noArray(), 0, uC, GEMM_2_T));
EXPECT_LE(cvtest::norm(C, uC, cv::NORM_INF), 1e-5);
}
} } // namespace opencv_test::ocl
#endif // HAVE_OPENCL

View File

@ -0,0 +1,96 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
// Copyright (C) 2014, Itseez, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
#include "../test_precomp.hpp"
#include "opencv2/ts/ocl_test.hpp"
#ifdef HAVE_OPENCL
namespace opencv_test {
namespace ocl {
TEST(Image2D, createAliasEmptyUMat)
{
if (cv::ocl::haveOpenCL())
{
UMat um;
EXPECT_FALSE(cv::ocl::Image2D::canCreateAlias(um));
}
else
std::cout << "OpenCL runtime not found. Test skipped." << std::endl;
}
TEST(Image2D, createImage2DWithEmptyUMat)
{
if (cv::ocl::haveOpenCL())
{
UMat um;
EXPECT_ANY_THROW(cv::ocl::Image2D image(um));
}
else
std::cout << "OpenCL runtime not found. Test skipped." << std::endl;
}
TEST(Image2D, createAlias)
{
if (cv::ocl::haveOpenCL())
{
const cv::ocl::Device & d = cv::ocl::Device::getDefault();
int minor = d.deviceVersionMinor(), major = d.deviceVersionMajor();
// aliases is OpenCL 1.2 extension
if (1 < major || (1 == major && 2 <= minor))
{
UMat um(128, 128, CV_8UC1);
bool isFormatSupported = false, canCreateAlias = false;
EXPECT_NO_THROW(isFormatSupported = cv::ocl::Image2D::isFormatSupported(CV_8U, 1, false));
EXPECT_NO_THROW(canCreateAlias = cv::ocl::Image2D::canCreateAlias(um));
if (isFormatSupported && canCreateAlias)
{
EXPECT_NO_THROW(cv::ocl::Image2D image(um, false, true));
}
else
std::cout << "Impossible to create alias for selected image. Test skipped." << std::endl;
}
}
else
std::cout << "OpenCL runtime not found. Test skipped" << std::endl;
}
TEST(Image2D, turnOffOpenCL)
{
if (cv::ocl::haveOpenCL())
{
// save the current state
bool useOCL = cv::ocl::useOpenCL();
bool isFormatSupported = false;
cv::ocl::setUseOpenCL(true);
UMat um(128, 128, CV_8UC1);
cv::ocl::setUseOpenCL(false);
EXPECT_NO_THROW(isFormatSupported = cv::ocl::Image2D::isFormatSupported(CV_8U, 1, true));
if (isFormatSupported)
{
EXPECT_NO_THROW(cv::ocl::Image2D image(um));
}
else
std::cout << "CV_8UC1 is not supported for OpenCL images. Test skipped." << std::endl;
// reset state to the previous one
cv::ocl::setUseOpenCL(useOCL);
}
else
std::cout << "OpenCL runtime not found. Test skipped." << std::endl;
}
} } // namespace opencv_test::ocl
#endif // HAVE_OPENCL

View File

@ -0,0 +1,103 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
// Copyright (C) 2014, Advanced Micro Devices, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
#include "../test_precomp.hpp"
#include "opencv2/ts/ocl_test.hpp"
#ifdef HAVE_OPENCL
namespace opencv_test {
namespace ocl {
//////////////////////////////// UMat Expressions /////////////////////////////////////////////////
PARAM_TEST_CASE(UMatExpr, MatDepth, Channels)
{
int type;
Size size;
virtual void SetUp()
{
type = CV_MAKE_TYPE(GET_PARAM(0), GET_PARAM(1));
}
void generateTestData()
{
size = randomSize(1, MAX_VALUE);
}
};
//////////////////////////////// UMat::eye /////////////////////////////////////////////////
OCL_TEST_P(UMatExpr, Eye)
{
for (int j = 0; j < test_loop_times; j++)
{
generateTestData();
Mat m = Mat::eye(size, type);
UMat um = UMat::eye(size, type);
EXPECT_MAT_NEAR(m, um, 0);
}
}
//////////////////////////////// UMat::zeros /////////////////////////////////////////////////
OCL_TEST_P(UMatExpr, Zeros)
{
for (int j = 0; j < test_loop_times; j++)
{
generateTestData();
Mat m = Mat::zeros(size, type);
UMat um = UMat::zeros(size, type);
EXPECT_MAT_NEAR(m, um, 0);
}
}
//////////////////////////////// UMat::ones /////////////////////////////////////////////////
OCL_TEST_P(UMatExpr, Ones)
{
for (int j = 0; j < test_loop_times; j++)
{
generateTestData();
Mat m = Mat::ones(size, type);
UMat um = UMat::ones(size, type);
EXPECT_MAT_NEAR(m, um, 0);
}
}
//////////////////////////////// with usageFlags /////////////////////////////////////////////////
OCL_TEST_P(UMatExpr, WithUsageFlags)
{
for (int j = 0; j < test_loop_times; j++)
{
generateTestData();
UMat u0 = UMat::zeros(size, type, cv::USAGE_ALLOCATE_HOST_MEMORY);
UMat u1 = UMat::ones(size, type, cv::USAGE_ALLOCATE_HOST_MEMORY);
UMat u8 = UMat::eye(size, type, cv::USAGE_ALLOCATE_HOST_MEMORY);
EXPECT_EQ(cv::USAGE_ALLOCATE_HOST_MEMORY, u0.usageFlags);
EXPECT_EQ(cv::USAGE_ALLOCATE_HOST_MEMORY, u1.usageFlags);
EXPECT_EQ(cv::USAGE_ALLOCATE_HOST_MEMORY, u8.usageFlags);
}
}
//////////////////////////////// Instantiation /////////////////////////////////////////////////
OCL_INSTANTIATE_TEST_CASE_P(MatrixOperation, UMatExpr, Combine(OCL_ALL_DEPTHS_16F, OCL_ALL_CHANNELS));
} } // namespace opencv_test::ocl
#endif

View File

@ -0,0 +1,224 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2010-2012, Institute Of Software Chinese Academy Of Science, all rights reserved.
// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
// Copyright (C) 2010-2012, Multicoreware, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// @Authors
// Jia Haipeng, jiahaipeng95@gmail.com
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "../test_precomp.hpp"
#include "opencv2/ts/ocl_test.hpp"
#ifdef HAVE_OPENCL
namespace opencv_test {
namespace ocl {
////////////////////////////////converto/////////////////////////////////////////////////
PARAM_TEST_CASE(ConvertTo, MatDepth, MatDepth, Channels, bool)
{
int src_depth, cn, dstType;
bool use_roi;
TEST_DECLARE_INPUT_PARAMETER(src);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
virtual void SetUp()
{
src_depth = GET_PARAM(0);
cn = GET_PARAM(2);
dstType = CV_MAKE_TYPE(GET_PARAM(1), cn);
use_roi = GET_PARAM(3);
}
void generateTestData()
{
Size roiSize = randomSize(1, MAX_VALUE);
Border srcBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, roiSize, srcBorder, CV_MAKE_TYPE(src_depth, cn), -MAX_VALUE, MAX_VALUE);
Border dstBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(dst, dst_roi, roiSize, dstBorder, dstType, 5, 16);
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
}
};
OCL_TEST_P(ConvertTo, WithScale_Accuracy)
{
for (int j = 0; j < test_loop_times; j++)
{
generateTestData();
double alpha = randomDouble(-4, 4), beta = randomDouble(-4, 4);
OCL_OFF(src_roi.convertTo(dst_roi, dstType, alpha, beta));
OCL_ON(usrc_roi.convertTo(udst_roi, dstType, alpha, beta));
double eps = CV_MAT_DEPTH(dstType) >= CV_32F ? 2e-4 : 1;
OCL_EXPECT_MATS_NEAR(dst, eps);
}
}
OCL_TEST_P(ConvertTo, NoScale_Accuracy)
{
for (int j = 0; j < test_loop_times; j++)
{
generateTestData();
OCL_OFF(src_roi.convertTo(dst_roi, dstType, 1, 0));
OCL_ON(usrc_roi.convertTo(udst_roi, dstType, 1, 0));
double eps = CV_MAT_DEPTH(dstType) >= CV_32F ? 2e-4 : 1;
OCL_EXPECT_MATS_NEAR(dst, eps);
}
}
//////////////////////////////// CopyTo /////////////////////////////////////////////////
PARAM_TEST_CASE(CopyTo, MatDepth, Channels, bool, bool)
{
int depth, cn;
bool use_roi, use_mask;
Scalar val;
TEST_DECLARE_INPUT_PARAMETER(src);
TEST_DECLARE_INPUT_PARAMETER(mask);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
virtual void SetUp()
{
depth = GET_PARAM(0);
cn = GET_PARAM(1);
use_roi = GET_PARAM(2);
use_mask = GET_PARAM(3);
}
void generateTestData(bool one_cn_mask = false)
{
const int type = CV_MAKE_TYPE(depth, cn);
Size roiSize = randomSize(1, MAX_VALUE);
Border srcBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, roiSize, srcBorder, type, -MAX_VALUE, MAX_VALUE);
if (use_mask)
{
Border maskBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
int mask_cn = 1;
if (!one_cn_mask && randomDouble(0.0, 2.0) > 1.0)
mask_cn = cn;
randomSubMat(mask, mask_roi, roiSize, maskBorder, CV_8UC(mask_cn), 0, 2);
cv::threshold(mask, mask, 0.5, 255., THRESH_BINARY);
}
Border dstBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(dst, dst_roi, roiSize, dstBorder, type, 5, 16);
UMAT_UPLOAD_INPUT_PARAMETER(src);
if (use_mask)
UMAT_UPLOAD_INPUT_PARAMETER(mask);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
val = randomScalar(-MAX_VALUE, MAX_VALUE);
}
};
OCL_TEST_P(CopyTo, Accuracy)
{
for (int j = 0; j < test_loop_times; j++)
{
generateTestData();
if (use_mask)
{
OCL_OFF(src_roi.copyTo(dst_roi, mask_roi));
OCL_ON(usrc_roi.copyTo(udst_roi, umask_roi));
}
else
{
OCL_OFF(src_roi.copyTo(dst_roi));
OCL_ON(usrc_roi.copyTo(udst_roi));
}
OCL_EXPECT_MATS_NEAR(dst, 0);
}
}
typedef CopyTo SetTo;
OCL_TEST_P(SetTo, Accuracy)
{
for (int j = 0; j < test_loop_times; j++)
{
generateTestData(true); // see modules/core/src/umatrix.cpp Ln:791 => CV_Assert( mask.size() == size() && mask.type() == CV_8UC1 );
if (use_mask)
{
OCL_OFF(dst_roi.setTo(val, mask_roi));
OCL_ON(udst_roi.setTo(val, umask_roi));
}
else
{
OCL_OFF(dst_roi.setTo(val));
OCL_ON(udst_roi.setTo(val));
}
OCL_EXPECT_MATS_NEAR(dst, 0);
}
}
OCL_INSTANTIATE_TEST_CASE_P(MatrixOperation, ConvertTo, Combine(
OCL_ALL_DEPTHS, OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool()));
OCL_INSTANTIATE_TEST_CASE_P(MatrixOperation, CopyTo, Combine(
OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool(), Bool()));
OCL_INSTANTIATE_TEST_CASE_P(MatrixOperation, SetTo, Combine(
OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool(), Bool()));
} } // namespace opencv_test::ocl
#endif

View File

@ -0,0 +1,318 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../test_precomp.hpp"
#include <opencv2/core/ocl.hpp>
namespace opencv_test { namespace {
static void testOpenCLKernel(cv::ocl::Kernel& k)
{
ASSERT_FALSE(k.empty());
cv::UMat src(cv::Size(4096, 2048), CV_8UC1, cv::Scalar::all(100));
cv::UMat dst(src.size(), CV_8UC1);
size_t globalSize[2] = {(size_t)src.cols, (size_t)src.rows};
size_t localSize[2] = {8, 8};
int64 kernel_time = k.args(
cv::ocl::KernelArg::ReadOnlyNoSize(src), // size is not used (similar to 'dst' size)
cv::ocl::KernelArg::WriteOnly(dst),
(int)5
).runProfiling(2, globalSize, localSize);
ASSERT_GE(kernel_time, (int64)0);
std::cout << "Kernel time: " << (kernel_time * 1e-6) << " ms" << std::endl;
cv::Mat res, reference(src.size(), CV_8UC1, cv::Scalar::all(105));
dst.copyTo(res);
EXPECT_EQ(0, cvtest::norm(reference, res, cv::NORM_INF));
}
TEST(OpenCL, support_binary_programs)
{
cv::ocl::Context ctx = cv::ocl::Context::getDefault();
if (!ctx.ptr())
{
throw cvtest::SkipTestException("OpenCL is not available");
}
cv::ocl::Device device = cv::ocl::Device::getDefault();
if (!device.compilerAvailable())
{
throw cvtest::SkipTestException("OpenCL compiler is not available");
}
std::vector<char> program_binary_code;
cv::String module_name; // empty to disable OpenCL cache
{ // Generate program binary from OpenCL C source
static const char* opencl_kernel_src =
"__kernel void test_kernel(__global const uchar* src, int src_step, int src_offset,\n"
" __global uchar* dst, int dst_step, int dst_offset, int dst_rows, int dst_cols,\n"
" int c)\n"
"{\n"
" int x = get_global_id(0);\n"
" int y = get_global_id(1);\n"
" if (x < dst_cols && y < dst_rows)\n"
" {\n"
" int src_idx = y * src_step + x + src_offset;\n"
" int dst_idx = y * dst_step + x + dst_offset;\n"
" dst[dst_idx] = src[src_idx] + c;\n"
" }\n"
"}\n";
cv::ocl::ProgramSource src(module_name, "simple", opencl_kernel_src, "");
cv::String errmsg;
cv::ocl::Program program(src, "", errmsg);
ASSERT_TRUE(program.ptr() != NULL);
cv::ocl::Kernel k("test_kernel", program);
EXPECT_FALSE(k.empty());
program.getBinary(program_binary_code);
std::cout << "Program binary size: " << program_binary_code.size() << " bytes" << std::endl;
}
cv::ocl::Kernel k;
{ // Load program from binary (without sources)
ASSERT_FALSE(program_binary_code.empty());
cv::ocl::ProgramSource src = cv::ocl::ProgramSource::fromBinary(module_name, "simple_binary", (uchar*)&program_binary_code[0], program_binary_code.size(), "");
cv::String errmsg;
cv::ocl::Program program(src, "", errmsg);
ASSERT_TRUE(program.ptr() != NULL);
k.create("test_kernel", program);
}
testOpenCLKernel(k);
}
TEST(OpenCL, support_SPIR_programs)
{
cv::ocl::Context ctx = cv::ocl::Context::getDefault();
if (!ctx.ptr())
{
throw cvtest::SkipTestException("OpenCL is not available");
}
cv::ocl::Device device = cv::ocl::Device::getDefault();
if (!device.isExtensionSupported("cl_khr_spir"))
{
throw cvtest::SkipTestException("'cl_khr_spir' extension is not supported by OpenCL device");
}
std::vector<char> program_binary_code;
cv::String fname = cv::format("test_kernel.spir%d", device.addressBits());
std::string full_path = cvtest::findDataFile(std::string("opencl/") + fname);
{
std::fstream f(full_path.c_str(), std::ios::in|std::ios::binary);
ASSERT_TRUE(f.is_open());
size_t pos = (size_t)f.tellg();
f.seekg(0, std::fstream::end);
size_t fileSize = (size_t)f.tellg();
std::cout << "Program SPIR size: " << fileSize << " bytes" << std::endl;
f.seekg(pos, std::fstream::beg);
program_binary_code.resize(fileSize);
f.read(&program_binary_code[0], fileSize);
ASSERT_FALSE(f.fail());
}
cv::String module_name; // empty to disable OpenCL cache
cv::ocl::Kernel k;
{ // Load program from SPIR format
ASSERT_FALSE(program_binary_code.empty());
cv::ocl::ProgramSource src = cv::ocl::ProgramSource::fromSPIR(module_name, "simple_spir", (uchar*)&program_binary_code[0], program_binary_code.size(), "");
cv::String errmsg;
cv::ocl::Program program(src, "", errmsg);
if (program.ptr() == NULL && device.isAMD())
{
// https://community.amd.com/t5/opencl/spir-support-in-new-drivers-lost/td-p/170165
throw cvtest::SkipTestException("Bypass AMD OpenCL runtime bug: 'cl_khr_spir' extension is declared, but it doesn't really work");
}
ASSERT_TRUE(program.ptr() != NULL);
k.create("test_kernel", program);
}
testOpenCLKernel(k);
}
TEST(OpenCL, image2Dcount_regression_19334)
{
cv::ocl::Context ctx = cv::ocl::Context::getDefault();
if (!ctx.ptr())
{
throw cvtest::SkipTestException("OpenCL is not available");
}
cv::ocl::Device device = cv::ocl::Device::getDefault();
if (!device.compilerAvailable())
{
throw cvtest::SkipTestException("OpenCL compiler is not available");
}
std::string module_name; // empty to disable OpenCL cache
static const char* opencl_kernel_src =
"__kernel void test_kernel(int a,\n"
" __global const uchar* src0, int src0_step, int src0_offset, int src0_rows, int src0_cols,\n"
" __global const uchar* src1, int src1_step, int src1_offset, int src1_rows, int src1_cols,\n"
" __global const uchar* src2, int src2_step, int src2_offset, int src2_rows, int src2_cols,\n"
" __read_only image2d_t image)\n"
"{\n"
"}";
cv::ocl::ProgramSource src(module_name, "test_opencl_image_arg", opencl_kernel_src, "");
cv::String errmsg;
cv::ocl::Program program(src, "", errmsg);
ASSERT_TRUE(program.ptr() != NULL);
cv::ocl::Kernel k("test_kernel", program);
ASSERT_FALSE(k.empty());
std::vector<UMat> images(4);
for (size_t i = 0; i < images.size(); ++i)
images[i] = UMat(10, 10, CV_8UC1);
cv::ocl::Image2D image;
try
{
cv::ocl::Image2D image_(images.back());
image = image_;
}
catch (const cv::Exception&)
{
throw cvtest::SkipTestException("OpenCL images are not supported");
}
int nargs = 0;
int a = 0;
nargs = k.set(nargs, a);
ASSERT_EQ(1, nargs);
nargs = k.set(nargs, images[0]);
ASSERT_EQ(6, nargs);
nargs = k.set(nargs, images[1]);
ASSERT_EQ(11, nargs);
nargs = k.set(nargs, images[2]);
ASSERT_EQ(16, nargs);
// do not throw (issue of #19334)
ASSERT_NO_THROW(nargs = k.set(nargs, image));
ASSERT_EQ(17, nargs);
// allow to replace image argument if kernel is not running
UMat image2(10, 10, CV_8UC1);
ASSERT_NO_THROW(nargs = k.set(16, cv::ocl::Image2D(image2)));
ASSERT_EQ(17, nargs);
}
TEST(OpenCL, move_construct_assign)
{
cv::ocl::Context ctx1 = cv::ocl::Context::getDefault();
if (!ctx1.ptr())
{
throw cvtest::SkipTestException("OpenCL is not available");
}
void* const ctx_ptr = ctx1.ptr();
cv::ocl::Context ctx2(std::move(ctx1));
ASSERT_EQ(ctx1.ptr(), nullptr);
ASSERT_EQ(ctx2.ptr(), ctx_ptr);
cv::ocl::Context ctx3 = std::move(ctx2);
ASSERT_EQ(ctx2.ptr(), nullptr);
ASSERT_EQ(ctx3.ptr(), ctx_ptr);
cv::ocl::Platform pl1 = cv::ocl::Platform::getDefault();
void* const pl_ptr = pl1.ptr();
cv::ocl::Platform pl2(std::move(pl1));
ASSERT_EQ(pl1.ptr(), nullptr);
ASSERT_EQ(pl2.ptr(), pl_ptr);
cv::ocl::Platform pl3 = std::move(pl2);
ASSERT_EQ(pl2.ptr(), nullptr);
ASSERT_EQ(pl3.ptr(), pl_ptr);
std::vector<cv::ocl::PlatformInfo> platformInfos;
cv::ocl::getPlatfomsInfo(platformInfos);
const cv::String pi_name = platformInfos[0].name();
cv::ocl::PlatformInfo pinfo2(std::move(platformInfos[0]));
ASSERT_EQ(platformInfos[0].name(), cv::String());
ASSERT_EQ(pinfo2.name(), pi_name);
cv::ocl::PlatformInfo pinfo3 = std::move(pinfo2);
ASSERT_EQ(pinfo2.name(), cv::String());
ASSERT_EQ(pinfo3.name(), pi_name);
cv::ocl::Queue q1 = cv::ocl::Queue::getDefault();
void* const q_ptr = q1.ptr();
cv::ocl::Queue q2(std::move(q1));
ASSERT_EQ(q1.ptr(), nullptr);
ASSERT_EQ(q2.ptr(), q_ptr);
cv::ocl::Queue q3 = std::move(q2);
ASSERT_EQ(q2.ptr(), nullptr);
ASSERT_EQ(q3.ptr(), q_ptr);
cv::ocl::Device d1 = cv::ocl::Device::getDefault();
if (!d1.compilerAvailable())
{
throw cvtest::SkipTestException("OpenCL compiler is not available");
}
void* const d_ptr = d1.ptr();
cv::ocl::Device d2(std::move(d1));
ASSERT_EQ(d1.ptr(), nullptr);
ASSERT_EQ(d2.ptr(), d_ptr);
cv::ocl::Device d3 = std::move(d2);
ASSERT_EQ(d2.ptr(), nullptr);
ASSERT_EQ(d3.ptr(), d_ptr);
if (d3.imageSupport()) {
cv::UMat umat1 = cv::UMat::ones(640, 480, CV_32FC1);
cv::ocl::Image2D img1(umat1);
void *const img_ptr = img1.ptr();
cv::ocl::Image2D img2(std::move(img1));
ASSERT_EQ(img1.ptr(), nullptr);
ASSERT_EQ(img2.ptr(), img_ptr);
cv::ocl::Image2D img3 = std::move(img2);
ASSERT_EQ(img2.ptr(), nullptr);
ASSERT_EQ(img3.ptr(), img_ptr);
}
static const char* opencl_kernel_src =
"__kernel void test_kernel(__global const uchar* src, int src_step, int src_offset,\n"
" __global uchar* dst, int dst_step, int dst_offset, int dst_rows, int dst_cols,\n"
" int c)\n"
"{\n"
" int x = get_global_id(0);\n"
" int y = get_global_id(1);\n"
" if (x < dst_cols && y < dst_rows)\n"
" {\n"
" int src_idx = y * src_step + x + src_offset;\n"
" int dst_idx = y * dst_step + x + dst_offset;\n"
" dst[dst_idx] = src[src_idx] + c;\n"
" }\n"
"}\n";
cv::String module_name; // empty to disable OpenCL cache
cv::ocl::ProgramSource ps1(module_name, "move_construct_assign", opencl_kernel_src, "");
cv::ocl::ProgramSource::Impl* const ps_ptr = ps1.getImpl();
cv::ocl::ProgramSource ps2(std::move(ps1));
ASSERT_EQ(ps1.getImpl(), nullptr);
ASSERT_EQ(ps2.getImpl(), ps_ptr);
cv::ocl::ProgramSource ps3 = std::move(ps2);
ASSERT_EQ(ps2.getImpl(), nullptr);
ASSERT_EQ(ps3.getImpl(), ps_ptr);
cv::String errmsg;
cv::ocl::Program prog1(ps3, "", errmsg);
void* const prog_ptr = prog1.ptr();
ASSERT_NE(prog_ptr, nullptr);
cv::ocl::Program prog2(std::move(prog1));
ASSERT_EQ(prog1.ptr(), nullptr);
ASSERT_EQ(prog2.ptr(), prog_ptr);
cv::ocl::Program prog3 = std::move(prog2);
ASSERT_EQ(prog2.ptr(), nullptr);
ASSERT_EQ(prog3.ptr(), prog_ptr);
cv::ocl::Kernel k1("test_kernel", prog3);
void* const k_ptr = k1.ptr();
ASSERT_NE(k_ptr, nullptr);
cv::ocl::Kernel k2(std::move(k1));
ASSERT_EQ(k1.ptr(), nullptr);
ASSERT_EQ(k2.ptr(), k_ptr);
cv::ocl::Kernel k3 = std::move(k2);
ASSERT_EQ(k2.ptr(), nullptr);
ASSERT_EQ(k3.ptr(), k_ptr);
testOpenCLKernel(k3);
}
}} // namespace

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,155 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
#include <opencv2/core/async.hpp>
#include <opencv2/core/detail/async_promise.hpp>
#include <opencv2/core/bindings_utils.hpp>
#if defined(CV_CXX11) && !defined(OPENCV_DISABLE_THREAD_SUPPORT)
#include <thread>
#include <chrono>
#endif
namespace opencv_test { namespace {
TEST(Core_Async, BasicCheck)
{
Mat m(3, 3, CV_32FC1, Scalar::all(5.0f));
AsyncPromise p;
AsyncArray r = p.getArrayResult();
EXPECT_TRUE(r.valid());
// Follow the limitations of std::promise::get_future
// https://en.cppreference.com/w/cpp/thread/promise/get_future
EXPECT_THROW(AsyncArray r2 = p.getArrayResult(), cv::Exception);
p.setValue(m);
Mat m2;
r.get(m2);
EXPECT_EQ(0, cvtest::norm(m, m2, NORM_INF));
// Follow the limitations of std::future::get
// https://en.cppreference.com/w/cpp/thread/future/get
EXPECT_FALSE(r.valid());
Mat m3;
EXPECT_THROW(r.get(m3), cv::Exception);
}
TEST(Core_Async, ExceptionCheck)
{
Mat m(3, 3, CV_32FC1, Scalar::all(5.0f));
AsyncPromise p;
AsyncArray r = p.getArrayResult();
EXPECT_TRUE(r.valid());
try
{
CV_Error(Error::StsOk, "Test: Generated async error");
}
catch (const cv::Exception& e)
{
p.setException(e);
}
try {
Mat m2;
r.get(m2);
FAIL() << "Exception is expected";
}
catch (const cv::Exception& e)
{
EXPECT_EQ(Error::StsOk, e.code) << e.what();
}
// Follow the limitations of std::future::get
// https://en.cppreference.com/w/cpp/thread/future/get
EXPECT_FALSE(r.valid());
}
TEST(Core_Async, LikePythonTest)
{
Mat m(3, 3, CV_32FC1, Scalar::all(5.0f));
AsyncArray r = cv::utils::testAsyncArray(m);
EXPECT_TRUE(r.valid());
Mat m2;
r.get(m2);
EXPECT_EQ(0, cvtest::norm(m, m2, NORM_INF));
// Follow the limitations of std::future::get
// https://en.cppreference.com/w/cpp/thread/future/get
EXPECT_FALSE(r.valid());
}
#if defined(CV_CXX11) && !defined(OPENCV_DISABLE_THREAD_SUPPORT)
TEST(Core_Async, AsyncThread_Simple)
{
Mat m(3, 3, CV_32FC1, Scalar::all(5.0f));
AsyncPromise p;
AsyncArray r = p.getArrayResult();
std::thread t([&]{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
try {
p.setValue(m);
} catch (const std::exception& e) {
std::cout << e.what() << std::endl;
} catch (...) {
std::cout << "Unknown C++ exception" << std::endl;
}
});
try
{
Mat m2;
r.get(m2);
EXPECT_EQ(0, cvtest::norm(m, m2, NORM_INF));
t.join();
}
catch (...)
{
t.join();
throw;
}
}
TEST(Core_Async, AsyncThread_DetachedResult)
{
Mat m(3, 3, CV_32FC1, Scalar::all(5.0f));
AsyncPromise p;
{
AsyncArray r = p.getArrayResult();
r.release();
}
bool exception_ok = false;
std::thread t([&]{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
try {
p.setValue(m);
} catch (const cv::Exception& e) {
if (e.code == Error::StsError)
exception_ok = true;
else
std::cout << e.what() << std::endl;
} catch (const std::exception& e) {
std::cout << e.what() << std::endl;
} catch (...) {
std::cout << "Unknown C++ exception" << std::endl;
}
});
t.join();
EXPECT_TRUE(exception_ok);
}
#endif
}} // namespace

View File

@ -0,0 +1,77 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// Intel License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of Intel Corporation may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "test_precomp.hpp"
namespace opencv_test { namespace {
TEST(Core_Concatenation, empty)
{
const Mat mat0x5(0,5, CV_8U, Scalar::all(1));
const Mat mat10x5(10,5, CV_8U, Scalar::all(1));
const Mat mat20x5(20,5, CV_8U, Scalar::all(1));
const Mat mat5x0(5,0, CV_8U, Scalar::all(1));
const Mat mat5x10(5,10, CV_8U, Scalar::all(1));
const Mat mat5x20(5,20, CV_8U, Scalar::all(1));
Mat result;
cv::hconcat(mat5x0, mat5x0, result);
EXPECT_MAT_N_DIFF(result, mat5x0, 0);
cv::hconcat(mat5x0, mat5x10, result);
EXPECT_MAT_N_DIFF(result, mat5x10, 0);
cv::hconcat(mat5x10, mat5x0, result);
EXPECT_MAT_N_DIFF(result, mat5x10, 0);
cv::hconcat(mat5x10, mat5x10, result);
EXPECT_MAT_N_DIFF(result, mat5x20, 0);
cv::vconcat(mat0x5, mat0x5, result);
EXPECT_MAT_N_DIFF(result, mat0x5, 0);
cv::vconcat(mat0x5, mat10x5, result);
EXPECT_MAT_N_DIFF(result, mat10x5, 0);
cv::vconcat(mat10x5, mat0x5, result);
EXPECT_MAT_N_DIFF(result, mat10x5, 0);
cv::vconcat(mat10x5, mat10x5, result);
EXPECT_MAT_N_DIFF(result, mat20x5, 0);
}
}} // namespace

View File

@ -0,0 +1,108 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the OpenCV Foundation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "test_precomp.hpp"
namespace opencv_test { namespace {
static void mytest(cv::Ptr<cv::ConjGradSolver> solver,cv::Ptr<cv::MinProblemSolver::Function> ptr_F,cv::Mat& x,
cv::Mat& etalon_x,double etalon_res){
solver->setFunction(ptr_F);
//int ndim=MAX(step.cols,step.rows);
double res=solver->minimize(x);
std::cout<<"res:\n\t"<<res<<std::endl;
std::cout<<"x:\n\t"<<x<<std::endl;
std::cout<<"etalon_res:\n\t"<<etalon_res<<std::endl;
std::cout<<"etalon_x:\n\t"<<etalon_x<<std::endl;
double tol = 1e-2;
ASSERT_TRUE(std::abs(res-etalon_res)<tol);
/*for(cv::Mat_<double>::iterator it1=x.begin<double>(),it2=etalon_x.begin<double>();it1!=x.end<double>();it1++,it2++){
ASSERT_TRUE(std::abs((*it1)-(*it2))<tol);
}*/
std::cout<<"--------------------------\n";
}
class SphereF_CG:public cv::MinProblemSolver::Function{
public:
int getDims() const { return 4; }
double calc(const double* x)const{
return x[0]*x[0]+x[1]*x[1]+x[2]*x[2]+x[3]*x[3];
}
// use automatically computed gradient
/*void getGradient(const double* x,double* grad){
for(int i=0;i<4;i++){
grad[i]=2*x[i];
}
}*/
};
class RosenbrockF_CG:public cv::MinProblemSolver::Function{
int getDims() const { return 2; }
double calc(const double* x)const{
return 100*(x[1]-x[0]*x[0])*(x[1]-x[0]*x[0])+(1-x[0])*(1-x[0]);
}
void getGradient(const double* x,double* grad){
grad[0]=-2*(1-x[0])-400*(x[1]-x[0]*x[0])*x[0];
grad[1]=200*(x[1]-x[0]*x[0]);
}
};
TEST(Core_ConjGradSolver, regression_basic){
cv::Ptr<cv::ConjGradSolver> solver=cv::ConjGradSolver::create();
#if 1
{
cv::Ptr<cv::MinProblemSolver::Function> ptr_F(new SphereF_CG());
cv::Mat x=(cv::Mat_<double>(4,1)<<50.0,10.0,1.0,-10.0),
etalon_x=(cv::Mat_<double>(1,4)<<0.0,0.0,0.0,0.0);
double etalon_res=0.0;
mytest(solver,ptr_F,x,etalon_x,etalon_res);
}
#endif
#if 1
{
cv::Ptr<cv::MinProblemSolver::Function> ptr_F(new RosenbrockF_CG());
cv::Mat x=(cv::Mat_<double>(2,1)<<0.0,0.0),
etalon_x=(cv::Mat_<double>(2,1)<<1.0,1.0);
double etalon_res=0.0;
mytest(solver,ptr_F,x,etalon_x,etalon_res);
}
#endif
}
}} // namespace

View File

@ -0,0 +1,298 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "test_precomp.hpp"
namespace opencv_test { namespace {
#define CORE_COUNTNONZERO_ERROR_COUNT 1
#define MESSAGE_ERROR_COUNT "Count non zero elements returned by OpenCV function is incorrect."
#define sign(a) a > 0 ? 1 : a == 0 ? 0 : -1
#define MAX_WIDTH 100
#define MAX_HEIGHT 100
class CV_CountNonZeroTest: public cvtest::BaseTest
{
public:
CV_CountNonZeroTest();
~CV_CountNonZeroTest();
protected:
void run (int);
private:
float eps_32;
double eps_64;
Mat src;
int current_type;
void generate_src_data(cv::Size size, int type);
void generate_src_data(cv::Size size, int type, int count_non_zero);
void generate_src_stat_data(cv::Size size, int type, int distribution);
int get_count_non_zero();
void print_information(int right, int result);
};
CV_CountNonZeroTest::CV_CountNonZeroTest(): eps_32(std::numeric_limits<float>::min()), eps_64(std::numeric_limits<double>::min()), src(Mat()), current_type(-1) {}
CV_CountNonZeroTest::~CV_CountNonZeroTest() {}
void CV_CountNonZeroTest::generate_src_data(cv::Size size, int type)
{
src.create(size, CV_MAKETYPE(type, 1));
for (int j = 0; j < size.width; ++j)
for (int i = 0; i < size.height; ++i)
switch (type)
{
case CV_8U: { src.at<uchar>(i, j) = cv::randu<uchar>(); break; }
case CV_8S: { src.at<char>(i, j) = cv::randu<uchar>() - 128; break; }
case CV_16U: { src.at<ushort>(i, j) = cv::randu<ushort>(); break; }
case CV_16S: { src.at<short>(i, j) = cv::randu<short>(); break; }
case CV_32S: { src.at<int>(i, j) = cv::randu<int>(); break; }
case CV_32F: { src.at<float>(i, j) = cv::randu<float>(); break; }
case CV_64F: { src.at<double>(i, j) = cv::randu<double>(); break; }
default: break;
}
}
void CV_CountNonZeroTest::generate_src_data(cv::Size size, int type, int count_non_zero)
{
src = Mat::zeros(size, CV_MAKETYPE(type, 1));
int n = 0; RNG& rng = ts->get_rng();
while (n < count_non_zero)
{
int i = rng.next()%size.height, j = rng.next()%size.width;
switch (type)
{
case CV_8U: { if (!src.at<uchar>(i, j)) {src.at<uchar>(i, j) = cv::randu<uchar>(); n += (src.at<uchar>(i, j) > 0);} break; }
case CV_8S: { if (!src.at<char>(i, j)) {src.at<char>(i, j) = cv::randu<uchar>() - 128; n += abs(sign(src.at<char>(i, j)));} break; }
case CV_16U: { if (!src.at<ushort>(i, j)) {src.at<ushort>(i, j) = cv::randu<ushort>(); n += (src.at<ushort>(i, j) > 0);} break; }
case CV_16S: { if (!src.at<short>(i, j)) {src.at<short>(i, j) = cv::randu<short>(); n += abs(sign(src.at<short>(i, j)));} break; }
case CV_32S: { if (!src.at<int>(i, j)) {src.at<int>(i, j) = cv::randu<int>(); n += abs(sign(src.at<int>(i, j)));} break; }
case CV_32F: { if (fabs(src.at<float>(i, j)) <= eps_32) {src.at<float>(i, j) = cv::randu<float>(); n += (fabs(src.at<float>(i, j)) > eps_32);} break; }
case CV_64F: { if (fabs(src.at<double>(i, j)) <= eps_64) {src.at<double>(i, j) = cv::randu<double>(); n += (fabs(src.at<double>(i, j)) > eps_64);} break; }
default: break;
}
}
}
void CV_CountNonZeroTest::generate_src_stat_data(cv::Size size, int type, int distribution)
{
src.create(size, CV_MAKETYPE(type, 1));
double mean = 0.0, sigma = 1.0;
double left = -1.0, right = 1.0;
RNG& rng = ts->get_rng();
if (distribution == RNG::NORMAL)
rng.fill(src, RNG::NORMAL, Scalar::all(mean), Scalar::all(sigma));
else if (distribution == RNG::UNIFORM)
rng.fill(src, RNG::UNIFORM, Scalar::all(left), Scalar::all(right));
}
int CV_CountNonZeroTest::get_count_non_zero()
{
int result = 0;
for (int i = 0; i < src.rows; ++i)
for (int j = 0; j < src.cols; ++j)
{
if (current_type == CV_8U) result += (src.at<uchar>(i, j) > 0);
else if (current_type == CV_8S) result += abs(sign(src.at<char>(i, j)));
else if (current_type == CV_16U) result += (src.at<ushort>(i, j) > 0);
else if (current_type == CV_16S) result += abs(sign(src.at<short>(i, j)));
else if (current_type == CV_32S) result += abs(sign(src.at<int>(i, j)));
else if (current_type == CV_32F) result += (fabs(src.at<float>(i, j)) > eps_32);
else result += (fabs(src.at<double>(i, j)) > eps_64);
}
return result;
}
void CV_CountNonZeroTest::print_information(int right, int result)
{
cout << endl; cout << "Checking for the work of countNonZero function..." << endl; cout << endl;
cout << "Type of Mat: ";
switch (current_type)
{
case 0: {cout << "CV_8U"; break;}
case 1: {cout << "CV_8S"; break;}
case 2: {cout << "CV_16U"; break;}
case 3: {cout << "CV_16S"; break;}
case 4: {cout << "CV_32S"; break;}
case 5: {cout << "CV_32F"; break;}
case 6: {cout << "CV_64F"; break;}
default: break;
}
cout << endl;
cout << "Number of rows: " << src.rows << " Number of cols: " << src.cols << endl;
cout << "True count non zero elements: " << right << " Result: " << result << endl;
cout << endl;
}
void CV_CountNonZeroTest::run(int)
{
const size_t N = 1500;
for (int k = 1; k <= 3; ++k)
for (size_t i = 0; i < N; ++i)
{
RNG& rng = ts->get_rng();
int w = rng.next()%MAX_WIDTH + 1, h = rng.next()%MAX_HEIGHT + 1;
current_type = rng.next()%7;
switch (k)
{
case 1: {
generate_src_data(Size(w, h), current_type);
int right = get_count_non_zero(), result = countNonZero(src);
if (result != right)
{
cout << "Number of experiment: " << i << endl;
cout << "Method of data generation: RANDOM" << endl;
print_information(right, result);
CV_Error(CORE_COUNTNONZERO_ERROR_COUNT, MESSAGE_ERROR_COUNT);
return;
}
break;
}
case 2: {
int count_non_zero = rng.next()%(w*h);
generate_src_data(Size(w, h), current_type, count_non_zero);
int result = countNonZero(src);
if (result != count_non_zero)
{
cout << "Number of experiment: " << i << endl;
cout << "Method of data generation: HALF-RANDOM" << endl;
print_information(count_non_zero, result);
CV_Error(CORE_COUNTNONZERO_ERROR_COUNT, MESSAGE_ERROR_COUNT);
return;
}
break;
}
case 3: {
int distribution = cv::randu<uchar>()%2;
generate_src_stat_data(Size(w, h), current_type, distribution);
int right = get_count_non_zero(), result = countNonZero(src);
if (right != result)
{
cout << "Number of experiment: " << i << endl;
cout << "Method of data generation: STATISTIC" << endl;
print_information(right, result);
CV_Error(CORE_COUNTNONZERO_ERROR_COUNT, MESSAGE_ERROR_COUNT);
return;
}
break;
}
default: break;
}
}
}
TEST (Core_CountNonZero, accuracy) { CV_CountNonZeroTest test; test.safe_run(); }
typedef testing::TestWithParam<tuple<int, int> > CountNonZeroND;
TEST_P (CountNonZeroND, ndim)
{
const int dims = get<0>(GetParam());
const int type = get<1>(GetParam());
const int ONE_SIZE = 5;
vector<int> sizes(dims);
fill(sizes.begin(), sizes.end(), ONE_SIZE);
Mat data(sizes, CV_MAKETYPE(type, 1));
data = 0;
EXPECT_EQ(0, cv::countNonZero(data));
data = Scalar::all(1);
int expected = static_cast<int>(pow(static_cast<float>(ONE_SIZE), dims));
EXPECT_EQ(expected, cv::countNonZero(data));
}
INSTANTIATE_TEST_CASE_P(Core, CountNonZeroND,
testing::Combine(
testing::Range(2, 9),
testing::Values(CV_8U, CV_8S, CV_32F)
)
);
typedef testing::TestWithParam<tuple<int, cv::Size> > CountNonZeroBig;
TEST_P(CountNonZeroBig, /**/)
{
const int type = get<0>(GetParam());
const Size sz = get<1>(GetParam());
EXPECT_EQ(0, cv::countNonZero(cv::Mat::zeros(sz, type)));
EXPECT_EQ(sz.area(), cv::countNonZero(cv::Mat::ones(sz, type)));
}
INSTANTIATE_TEST_CASE_P(Core, CountNonZeroBig,
testing::Combine(
testing::Values(CV_8UC1, CV_32FC1),
testing::Values(Size(1, 524190), Size(524190, 1), Size(3840, 2160))
)
);
}} // namespace

View File

@ -0,0 +1,21 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#if defined(HAVE_CUDA)
#include "test_precomp.hpp"
#include <cuda_runtime.h>
#include "opencv2/core/cuda.hpp"
namespace opencv_test { namespace {
TEST(CUDA_Stream, construct_cudaFlags)
{
cv::cuda::Stream stream(cudaStreamNonBlocking);
EXPECT_NE(stream.cudaPtr(), nullptr);
}
}} // namespace
#endif

View File

@ -0,0 +1,106 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the OpenCV Foundation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "test_precomp.hpp"
namespace opencv_test { namespace {
static void mytest(cv::Ptr<cv::DownhillSolver> solver,cv::Ptr<cv::MinProblemSolver::Function> ptr_F,cv::Mat& x,cv::Mat& step,
cv::Mat& etalon_x,double etalon_res){
solver->setFunction(ptr_F);
int ndim=MAX(step.cols,step.rows);
solver->setInitStep(step);
cv::Mat settedStep;
solver->getInitStep(settedStep);
ASSERT_TRUE(settedStep.rows==1 && settedStep.cols==ndim);
ASSERT_TRUE(std::equal(step.begin<double>(),step.end<double>(),settedStep.begin<double>()));
std::cout<<"step set:\n\t"<<step<<std::endl;
double res=solver->minimize(x);
std::cout<<"res:\n\t"<<res<<std::endl;
std::cout<<"x:\n\t"<<x<<std::endl;
std::cout<<"etalon_res:\n\t"<<etalon_res<<std::endl;
std::cout<<"etalon_x:\n\t"<<etalon_x<<std::endl;
double tol=1e-2;//solver->getTermCriteria().epsilon;
ASSERT_TRUE(std::abs(res-etalon_res)<tol);
/*for(cv::Mat_<double>::iterator it1=x.begin<double>(),it2=etalon_x.begin<double>();it1!=x.end<double>();it1++,it2++){
ASSERT_TRUE(std::abs((*it1)-(*it2))<tol);
}*/
std::cout<<"--------------------------\n";
}
class SphereF:public cv::MinProblemSolver::Function{
public:
int getDims() const { return 2; }
double calc(const double* x)const{
return x[0]*x[0]+x[1]*x[1];
}
};
class RosenbrockF:public cv::MinProblemSolver::Function{
int getDims() const { return 2; }
double calc(const double* x)const{
return 100*(x[1]-x[0]*x[0])*(x[1]-x[0]*x[0])+(1-x[0])*(1-x[0]);
}
};
TEST(Core_DownhillSolver, regression_basic){
cv::Ptr<cv::DownhillSolver> solver=cv::DownhillSolver::create();
#if 1
{
cv::Ptr<cv::MinProblemSolver::Function> ptr_F = cv::makePtr<SphereF>();
cv::Mat x=(cv::Mat_<double>(1,2)<<1.0,1.0),
step=(cv::Mat_<double>(2,1)<<-0.5,-0.5),
etalon_x=(cv::Mat_<double>(1,2)<<-0.0,0.0);
double etalon_res=0.0;
mytest(solver,ptr_F,x,step,etalon_x,etalon_res);
}
#endif
#if 1
{
cv::Ptr<cv::MinProblemSolver::Function> ptr_F = cv::makePtr<RosenbrockF>();
cv::Mat x=(cv::Mat_<double>(2,1)<<0.0,0.0),
step=(cv::Mat_<double>(2,1)<<0.5,+0.5),
etalon_x=(cv::Mat_<double>(2,1)<<1.0,1.0);
double etalon_res=0.0;
mytest(solver,ptr_F,x,step,etalon_x,etalon_res);
}
#endif
}
}} // namespace

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,986 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
namespace opencv_test { namespace {
static Mat initDFTWave( int n, bool inv )
{
int i;
double angle = (inv ? 1 : -1)*CV_PI*2/n;
Complexd wi, w1;
Mat wave(1, n, CV_64FC2);
Complexd* w = wave.ptr<Complexd>();
w1.re = cos(angle);
w1.im = sin(angle);
w[0].re = wi.re = 1.;
w[0].im = wi.im = 0.;
for( i = 1; i < n; i++ )
{
double t = wi.re*w1.re - wi.im*w1.im;
wi.im = wi.re*w1.im + wi.im*w1.re;
wi.re = t;
w[i] = wi;
}
return wave;
}
static void DFT_1D( const Mat& _src, Mat& _dst, int flags, const Mat& _wave=Mat())
{
_dst.create(_src.size(), _src.type());
int i, j, k, n = _dst.cols + _dst.rows - 1;
Mat wave = _wave;
double scale = (flags & DFT_SCALE) ? 1./n : 1.;
size_t esz = _src.elemSize();
size_t srcstep = esz, dststep = esz;
const uchar* src0 = _src.ptr();
uchar* dst0 = _dst.ptr();
CV_Assert( _src.cols + _src.rows - 1 == n );
if( wave.empty() )
wave = initDFTWave( n, (flags & DFT_INVERSE) != 0 );
const Complexd* w = wave.ptr<Complexd>();
if( !_src.isContinuous() )
srcstep = _src.step;
if( !_dst.isContinuous() )
dststep = _dst.step;
if( _src.type() == CV_32FC2 )
{
for( i = 0; i < n; i++ )
{
Complexf* dst = (Complexf*)(dst0 + i*dststep);
Complexd sum(0,0);
int delta = i;
k = 0;
for( j = 0; j < n; j++ )
{
const Complexf* src = (const Complexf*)(src0 + j*srcstep);
sum.re += src->re*w[k].re - src->im*w[k].im;
sum.im += src->re*w[k].im + src->im*w[k].re;
k += delta;
k -= (k >= n ? n : 0);
}
dst->re = (float)(sum.re*scale);
dst->im = (float)(sum.im*scale);
}
}
else if( _src.type() == CV_64FC2 )
{
for( i = 0; i < n; i++ )
{
Complexd* dst = (Complexd*)(dst0 + i*dststep);
Complexd sum(0,0);
int delta = i;
k = 0;
for( j = 0; j < n; j++ )
{
const Complexd* src = (const Complexd*)(src0 + j*srcstep);
sum.re += src->re*w[k].re - src->im*w[k].im;
sum.im += src->re*w[k].im + src->im*w[k].re;
k += delta;
k -= (k >= n ? n : 0);
}
dst->re = sum.re*scale;
dst->im = sum.im*scale;
}
}
else
CV_Error(CV_StsUnsupportedFormat, "");
}
static void DFT_2D( const Mat& src, Mat& dst, int flags )
{
const int cn = 2;
int i;
dst.create(src.size(), src.type());
Mat tmp( src.cols, src.rows, src.type());
Mat wave = initDFTWave( dst.cols, (flags & DFT_INVERSE) != 0 );
// 1. row-wise transform
for( i = 0; i < dst.rows; i++ )
{
Mat srci = src.row(i).reshape(cn, src.cols), dsti = tmp.col(i);
DFT_1D(srci, dsti, flags, wave );
}
if( (flags & DFT_ROWS) == 0 )
{
if( dst.cols != dst.rows )
wave = initDFTWave( dst.rows, (flags & DFT_INVERSE) != 0 );
// 2. column-wise transform
for( i = 0; i < dst.cols; i++ )
{
Mat srci = tmp.row(i).reshape(cn, tmp.cols), dsti = dst.col(i);
DFT_1D(srci, dsti, flags, wave );
}
}
else
cvtest::transpose(tmp, dst);
}
static Mat initDCTWave( int n, bool inv )
{
int i, k;
double angle = CV_PI*0.5/n;
Mat wave(n, n, CV_64F);
double scale = sqrt(1./n);
for( k = 0; k < n; k++ )
wave.at<double>(0, k) = scale;
scale *= sqrt(2.);
for( i = 1; i < n; i++ )
for( k = 0; k < n; k++ )
wave.at<double>(i, k) = scale*cos( angle*i*(2*k + 1) );
if( inv )
cv::transpose( wave, wave );
return wave;
}
static void DCT_1D( const Mat& _src, Mat& _dst, int flags, const Mat& _wave=Mat() )
{
_dst.create( _src.size(), _src.type() );
int i, j, n = _dst.cols + _dst.rows - 1;
Mat wave = _wave;
int srcstep = 1, dststep = 1;
double* w;
CV_Assert( _src.cols + _src.rows - 1 == n);
if( wave.empty() )
wave = initDCTWave( n, (flags & DFT_INVERSE) != 0 );
w = wave.ptr<double>();
if( !_src.isContinuous() )
srcstep = (int)(_src.step/_src.elemSize());
if( !_dst.isContinuous() )
dststep = (int)(_dst.step/_dst.elemSize());
if( _src.type() == CV_32FC1 )
{
float *dst = _dst.ptr<float>();
for( i = 0; i < n; i++, dst += dststep )
{
const float* src = _src.ptr<float>();
double sum = 0;
for( j = 0; j < n; j++, src += srcstep )
sum += src[0]*w[j];
w += n;
dst[0] = (float)sum;
}
}
else if( _src.type() == CV_64FC1 )
{
double *dst = _dst.ptr<double>();
for( i = 0; i < n; i++, dst += dststep )
{
const double* src = _src.ptr<double>();
double sum = 0;
for( j = 0; j < n; j++, src += srcstep )
sum += src[0]*w[j];
w += n;
dst[0] = sum;
}
}
else
assert(0);
}
static void DCT_2D( const Mat& src, Mat& dst, int flags )
{
const int cn = 1;
int i;
dst.create( src.size(), src.type() );
Mat tmp(dst.cols, dst.rows, dst.type() );
Mat wave = initDCTWave( dst.cols, (flags & DCT_INVERSE) != 0 );
// 1. row-wise transform
for( i = 0; i < dst.rows; i++ )
{
Mat srci = src.row(i).reshape(cn, src.cols);
Mat dsti = tmp.col(i);
DCT_1D(srci, dsti, flags, wave);
}
if( (flags & DCT_ROWS) == 0 )
{
if( dst.cols != dst.rows )
wave = initDCTWave( dst.rows, (flags & DCT_INVERSE) != 0 );
// 2. column-wise transform
for( i = 0; i < dst.cols; i++ )
{
Mat srci = tmp.row(i).reshape(cn, tmp.cols);
Mat dsti = dst.col(i);
DCT_1D( srci, dsti, flags, wave );
}
}
else
cvtest::transpose( tmp, dst );
}
static void convertFromCCS( const Mat& _src0, const Mat& _src1, Mat& _dst, int flags )
{
if( _dst.rows > 1 && (_dst.cols > 1 || (flags & DFT_ROWS)) )
{
int i, count = _dst.rows, len = _dst.cols;
bool is2d = (flags & DFT_ROWS) == 0;
Mat src0row, src1row, dstrow;
for( i = 0; i < count; i++ )
{
int j = !is2d || i == 0 ? i : count - i;
src0row = _src0.row(i);
src1row = _src1.row(j);
dstrow = _dst.row(i);
convertFromCCS( src0row, src1row, dstrow, 0 );
}
if( is2d )
{
src0row = _src0.col(0);
dstrow = _dst.col(0);
convertFromCCS( src0row, src0row, dstrow, 0 );
if( (len & 1) == 0 )
{
src0row = _src0.col(_src0.cols - 1);
dstrow = _dst.col(len/2);
convertFromCCS( src0row, src0row, dstrow, 0 );
}
}
}
else
{
int i, n = _dst.cols + _dst.rows - 1, n2 = (n+1) >> 1;
int cn = _src0.channels();
int srcstep = cn, dststep = 1;
if( !_dst.isContinuous() )
dststep = (int)(_dst.step/_dst.elemSize());
if( !_src0.isContinuous() )
srcstep = (int)(_src0.step/_src0.elemSize1());
if( _dst.depth() == CV_32F )
{
Complexf* dst = _dst.ptr<Complexf>();
const float* src0 = _src0.ptr<float>();
const float* src1 = _src1.ptr<float>();
int delta0, delta1;
dst->re = src0[0];
dst->im = 0;
if( (n & 1) == 0 )
{
dst[n2*dststep].re = src0[(cn == 1 ? n-1 : n2)*srcstep];
dst[n2*dststep].im = 0;
}
delta0 = srcstep;
delta1 = delta0 + (cn == 1 ? srcstep : 1);
if( cn == 1 )
srcstep *= 2;
for( i = 1; i < n2; i++, delta0 += srcstep, delta1 += srcstep )
{
float t0 = src0[delta0];
float t1 = src0[delta1];
dst[i*dststep].re = t0;
dst[i*dststep].im = t1;
t0 = src1[delta0];
t1 = -src1[delta1];
dst[(n-i)*dststep].re = t0;
dst[(n-i)*dststep].im = t1;
}
}
else
{
Complexd* dst = _dst.ptr<Complexd>();
const double* src0 = _src0.ptr<double>();
const double* src1 = _src1.ptr<double>();
int delta0, delta1;
dst->re = src0[0];
dst->im = 0;
if( (n & 1) == 0 )
{
dst[n2*dststep].re = src0[(cn == 1 ? n-1 : n2)*srcstep];
dst[n2*dststep].im = 0;
}
delta0 = srcstep;
delta1 = delta0 + (cn == 1 ? srcstep : 1);
if( cn == 1 )
srcstep *= 2;
for( i = 1; i < n2; i++, delta0 += srcstep, delta1 += srcstep )
{
double t0 = src0[delta0];
double t1 = src0[delta1];
dst[i*dststep].re = t0;
dst[i*dststep].im = t1;
t0 = src1[delta0];
t1 = -src1[delta1];
dst[(n-i)*dststep].re = t0;
dst[(n-i)*dststep].im = t1;
}
}
}
}
static void fixCCS( Mat& mat, int cols, int flags )
{
int i, rows = mat.rows;
int rows2 = (flags & DFT_ROWS) ? rows : rows/2 + 1, cols2 = cols/2 + 1;
CV_Assert( cols2 == mat.cols );
if( mat.type() == CV_32FC2 )
{
for( i = 0; i < rows2; i++ )
{
Complexf* row = mat.ptr<Complexf>(i);
if( (flags & DFT_ROWS) || i == 0 || (i == rows2 - 1 && rows % 2 == 0) )
{
row[0].im = 0;
if( cols % 2 == 0 )
row[cols2-1].im = 0;
}
else
{
Complexf* row2 = mat.ptr<Complexf>(rows-i);
row2[0].re = row[0].re;
row2[0].im = -row[0].im;
if( cols % 2 == 0 )
{
row2[cols2-1].re = row[cols2-1].re;
row2[cols2-1].im = -row[cols2-1].im;
}
}
}
}
else if( mat.type() == CV_64FC2 )
{
for( i = 0; i < rows2; i++ )
{
Complexd* row = mat.ptr<Complexd>(i);
if( (flags & DFT_ROWS) || i == 0 || (i == rows2 - 1 && rows % 2 == 0) )
{
row[0].im = 0;
if( cols % 2 == 0 )
row[cols2-1].im = 0;
}
else
{
Complexd* row2 = mat.ptr<Complexd>(rows-i);
row2[0].re = row[0].re;
row2[0].im = -row[0].im;
if( cols % 2 == 0 )
{
row2[cols2-1].re = row[cols2-1].re;
row2[cols2-1].im = -row[cols2-1].im;
}
}
}
}
}
static void mulComplex( const Mat& src1, const Mat& src2, Mat& dst, int flags )
{
dst.create(src1.rows, src1.cols, src1.type());
int i, j, depth = src1.depth(), cols = src1.cols*2;
CV_Assert( src1.size == src2.size && src1.type() == src2.type() &&
(src1.type() == CV_32FC2 || src1.type() == CV_64FC2) );
const Mat* src1_ = &src1;
Mat src1_tmp;
if (dst.data == src1.data)
{
src1_tmp = src1.clone();
src1_ = &src1_tmp;
}
const Mat* src2_ = &src2;
Mat src2_tmp;
if (dst.data == src2.data)
{
src2_tmp = src2.clone();
src2_ = &src2_tmp;
}
for( i = 0; i < dst.rows; i++ )
{
if( depth == CV_32F )
{
const float* a = src1_->ptr<float>(i);
const float* b = src2_->ptr<float>(i);
float* c = dst.ptr<float>(i);
if( !(flags & CV_DXT_MUL_CONJ) )
for( j = 0; j < cols; j += 2 )
{
double re = (double)a[j]*(double)b[j] - (double)a[j+1]*(double)b[j+1];
double im = (double)a[j+1]*(double)b[j] + (double)a[j]*(double)b[j+1];
c[j] = (float)re;
c[j+1] = (float)im;
}
else
for( j = 0; j < cols; j += 2 )
{
double re = (double)a[j]*(double)b[j] + (double)a[j+1]*(double)b[j+1];
double im = (double)a[j+1]*(double)b[j] - (double)a[j]*(double)b[j+1];
c[j] = (float)re;
c[j+1] = (float)im;
}
}
else
{
const double* a = src1_->ptr<double>(i);
const double* b = src2_->ptr<double>(i);
double* c = dst.ptr<double>(i);
if( !(flags & CV_DXT_MUL_CONJ) )
for( j = 0; j < cols; j += 2 )
{
double re = a[j]*b[j] - a[j+1]*b[j+1];
double im = a[j+1]*b[j] + a[j]*b[j+1];
c[j] = re;
c[j+1] = im;
}
else
for( j = 0; j < cols; j += 2 )
{
double re = a[j]*b[j] + a[j+1]*b[j+1];
double im = a[j+1]*b[j] - a[j]*b[j+1];
c[j] = re;
c[j+1] = im;
}
}
}
}
class CxCore_DXTBaseTest : public cvtest::ArrayTest
{
public:
typedef cvtest::ArrayTest Base;
CxCore_DXTBaseTest( bool _allow_complex=false, bool _allow_odd=false,
bool _spectrum_mode=false );
protected:
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
int prepare_test_case( int test_case_idx );
double get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ );
int flags; // transformation flags
bool allow_complex; // whether input/output may be complex or not:
// true for DFT and MulSpectrums, false for DCT
bool allow_odd; // whether input/output may be have odd (!=1) dimensions:
// true for DFT and MulSpectrums, false for DCT
bool spectrum_mode; // (2 complex/ccs inputs, 1 complex/ccs output):
// true for MulSpectrums, false for DFT and DCT
bool inplace; // inplace operation (set for each individual test case)
bool temp_dst; // use temporary destination (for real->ccs DFT and ccs MulSpectrums)
};
CxCore_DXTBaseTest::CxCore_DXTBaseTest( bool _allow_complex, bool _allow_odd, bool _spectrum_mode )
: Base(), flags(0), allow_complex(_allow_complex), allow_odd(_allow_odd),
spectrum_mode(_spectrum_mode), inplace(false), temp_dst(false)
{
test_array[INPUT].push_back(NULL);
if( spectrum_mode )
test_array[INPUT].push_back(NULL);
test_array[OUTPUT].push_back(NULL);
test_array[REF_OUTPUT].push_back(NULL);
test_array[TEMP].push_back(NULL);
test_array[TEMP].push_back(NULL);
max_log_array_size = 9;
element_wise_relative_error = spectrum_mode;
}
void CxCore_DXTBaseTest::get_test_array_types_and_sizes( int test_case_idx,
vector<vector<Size> >& sizes,
vector<vector<int> >& types )
{
RNG& rng = ts->get_rng();
int bits = cvtest::randInt(rng);
int depth = cvtest::randInt(rng)%2 + CV_32F;
int cn = !allow_complex || !(bits & 256) ? 1 : 2;
Size size;
Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
flags = bits & (CV_DXT_INVERSE | CV_DXT_SCALE | CV_DXT_ROWS | CV_DXT_MUL_CONJ);
if( spectrum_mode )
flags &= ~CV_DXT_INVERSE;
types[TEMP][0] = types[TEMP][1] = types[INPUT][0] =
types[OUTPUT][0] = CV_MAKETYPE(depth, cn);
size = sizes[INPUT][0];
temp_dst = false;
if( flags & CV_DXT_ROWS && (bits&1024) )
{
if( bits&16 )
size.width = 1;
else
size.height = 1;
flags &= ~CV_DXT_ROWS;
}
const int P2_MIN_SIZE = 32;
if( ((bits >> 10) & 1) == 0 )
{
size.width = (size.width / P2_MIN_SIZE)*P2_MIN_SIZE;
size.width = MAX(size.width, 1);
size.height = (size.height / P2_MIN_SIZE)*P2_MIN_SIZE;
size.height = MAX(size.height, 1);
}
if( !allow_odd )
{
if( size.width > 1 && (size.width&1) != 0 )
size.width = (size.width + 1) & -2;
if( size.height > 1 && (size.height&1) != 0 && !(flags & CV_DXT_ROWS) )
size.height = (size.height + 1) & -2;
}
sizes[INPUT][0] = sizes[OUTPUT][0] = size;
sizes[TEMP][0] = sizes[TEMP][1] = cvSize(0,0);
if( spectrum_mode )
{
if( cn == 1 )
{
types[OUTPUT][0] = depth + 8;
sizes[TEMP][0] = size;
}
sizes[INPUT][0] = sizes[INPUT][1] = size;
types[INPUT][1] = types[INPUT][0];
}
else if( /*(cn == 2 && (bits&32)) ||*/ (cn == 1 && allow_complex) )
{
types[TEMP][0] = depth + 8; // CV_??FC2
sizes[TEMP][0] = size;
size = cvSize(size.width/2+1, size.height);
if( flags & CV_DXT_INVERSE )
{
if( cn == 2 )
{
types[OUTPUT][0] = depth;
sizes[INPUT][0] = size;
}
types[TEMP][1] = types[TEMP][0];
sizes[TEMP][1] = sizes[TEMP][0];
}
else
{
if( allow_complex )
types[OUTPUT][0] = depth + 8;
if( cn == 2 )
{
types[INPUT][0] = depth;
types[TEMP][1] = types[TEMP][0];
sizes[TEMP][1] = size;
}
else
{
types[TEMP][1] = depth;
sizes[TEMP][1] = sizes[TEMP][0];
}
temp_dst = true;
}
}
inplace = false;
if( spectrum_mode ||
(!temp_dst && types[INPUT][0] == types[OUTPUT][0]) ||
(temp_dst && types[INPUT][0] == types[TEMP][1]) )
inplace = (bits & 64) != 0;
types[REF_OUTPUT][0] = types[OUTPUT][0];
sizes[REF_OUTPUT][0] = sizes[OUTPUT][0];
}
double CxCore_DXTBaseTest::get_success_error_level( int test_case_idx, int i, int j )
{
return Base::get_success_error_level( test_case_idx, i, j );
}
int CxCore_DXTBaseTest::prepare_test_case( int test_case_idx )
{
int code = Base::prepare_test_case( test_case_idx );
if( code > 0 )
{
int in_type = test_mat[INPUT][0].type();
int out_type = test_mat[OUTPUT][0].type();
if( CV_MAT_CN(in_type) == 2 && CV_MAT_CN(out_type) == 1 )
fixCCS( test_mat[INPUT][0], test_mat[OUTPUT][0].cols, flags );
if( inplace )
cvtest::copy( test_mat[INPUT][test_case_idx & (int)spectrum_mode],
temp_dst ? test_mat[TEMP][1] :
in_type == out_type ? test_mat[OUTPUT][0] :
test_mat[TEMP][0] );
}
return code;
}
////////////////////// FFT ////////////////////////
class CxCore_DFTTest : public CxCore_DXTBaseTest
{
public:
CxCore_DFTTest();
protected:
void run_func();
void prepare_to_validation( int test_case_idx );
};
CxCore_DFTTest::CxCore_DFTTest() : CxCore_DXTBaseTest( true, true, false )
{
}
void CxCore_DFTTest::run_func()
{
Mat& dst = temp_dst ? test_mat[TEMP][1] : test_mat[OUTPUT][0];
const Mat& src = inplace ? dst : test_mat[INPUT][0];
if(!(flags & CV_DXT_INVERSE))
cv::dft( src, dst, flags );
else
cv::idft(src, dst, flags & ~CV_DXT_INVERSE);
}
void CxCore_DFTTest::prepare_to_validation( int /*test_case_idx*/ )
{
Mat& src = test_mat[INPUT][0];
Mat& dst = test_mat[REF_OUTPUT][0];
Mat* tmp_src = &src;
Mat* tmp_dst = &dst;
int src_cn = src.channels();
int dst_cn = dst.channels();
if( src_cn != 2 || dst_cn != 2 )
{
tmp_src = &test_mat[TEMP][0];
if( !(flags & CV_DXT_INVERSE ) )
{
Mat& cvdft_dst = test_mat[TEMP][1];
convertFromCCS( cvdft_dst, cvdft_dst,
test_mat[OUTPUT][0], flags );
*tmp_src = Scalar::all(0);
cvtest::insert( src, *tmp_src, 0 );
}
else
{
convertFromCCS( src, src, *tmp_src, flags );
tmp_dst = &test_mat[TEMP][1];
}
}
if( src.rows == 1 || (src.cols == 1 && !(flags & CV_DXT_ROWS)) )
DFT_1D( *tmp_src, *tmp_dst, flags );
else
DFT_2D( *tmp_src, *tmp_dst, flags );
if( tmp_dst != &dst )
cvtest::extract( *tmp_dst, dst, 0 );
}
////////////////////// DCT ////////////////////////
class CxCore_DCTTest : public CxCore_DXTBaseTest
{
public:
CxCore_DCTTest();
protected:
void run_func();
void prepare_to_validation( int test_case_idx );
};
CxCore_DCTTest::CxCore_DCTTest() : CxCore_DXTBaseTest( false, false, false )
{
}
void CxCore_DCTTest::run_func()
{
Mat& dst = test_mat[OUTPUT][0];
const Mat& src = inplace ? dst : test_mat[INPUT][0];
if(!(flags & CV_DXT_INVERSE))
cv::dct( src, dst, flags );
else
cv::idct( src, dst, flags & ~CV_DXT_INVERSE);
}
void CxCore_DCTTest::prepare_to_validation( int /*test_case_idx*/ )
{
const Mat& src = test_mat[INPUT][0];
Mat& dst = test_mat[REF_OUTPUT][0];
if( src.rows == 1 || (src.cols == 1 && !(flags & CV_DXT_ROWS)) )
DCT_1D( src, dst, flags );
else
DCT_2D( src, dst, flags );
}
////////////////////// MulSpectrums ////////////////////////
class CxCore_MulSpectrumsTest : public CxCore_DXTBaseTest
{
public:
CxCore_MulSpectrumsTest();
protected:
void run_func();
void prepare_to_validation( int test_case_idx );
double get_success_error_level( int test_case_idx, int i, int j );
};
CxCore_MulSpectrumsTest::CxCore_MulSpectrumsTest() : CxCore_DXTBaseTest( true, true, true )
{
}
double CxCore_MulSpectrumsTest::get_success_error_level( int test_case_idx, int i, int j )
{
CV_UNUSED(test_case_idx);
CV_Assert(i == OUTPUT);
CV_Assert(j == 0);
int elem_depth = CV_MAT_DEPTH(cvGetElemType(test_array[i][j]));
CV_Assert(elem_depth == CV_32F || elem_depth == CV_64F);
element_wise_relative_error = false;
double maxInputValue = 1000; // ArrayTest::get_minmax_bounds
double err = 8 * maxInputValue; // result = A*B + C*D
return (elem_depth == CV_32F ? FLT_EPSILON : DBL_EPSILON) * err;
}
void CxCore_MulSpectrumsTest::run_func()
{
Mat& dst = !test_mat[TEMP].empty() && !test_mat[TEMP][0].empty() ?
test_mat[TEMP][0] : test_mat[OUTPUT][0];
const Mat* src1 = &test_mat[INPUT][0], *src2 = &test_mat[INPUT][1];
if( inplace )
{
if( ts->get_current_test_info()->test_case_idx & 1 )
src2 = &dst;
else
src1 = &dst;
}
cv::mulSpectrums( *src1, *src2, dst, flags, (flags & CV_DXT_MUL_CONJ) != 0 );
}
void CxCore_MulSpectrumsTest::prepare_to_validation( int /*test_case_idx*/ )
{
Mat* src1 = &test_mat[INPUT][0];
Mat* src2 = &test_mat[INPUT][1];
Mat& dst = test_mat[OUTPUT][0];
Mat& dst0 = test_mat[REF_OUTPUT][0];
int cn = src1->channels();
if( cn == 1 )
{
convertFromCCS( *src1, *src1, dst, flags );
convertFromCCS( *src2, *src2, dst0, flags );
src1 = &dst;
src2 = &dst0;
}
mulComplex( *src1, *src2, dst0, flags );
if( cn == 1 )
{
Mat& temp = test_mat[TEMP][0];
convertFromCCS( temp, temp, dst, flags );
}
}
TEST(Core_DCT, accuracy) { CxCore_DCTTest test; test.safe_run(); }
TEST(Core_DFT, accuracy) { CxCore_DFTTest test; test.safe_run(); }
TEST(Core_MulSpectrums, accuracy) { CxCore_MulSpectrumsTest test; test.safe_run(); }
class Core_DFTComplexOutputTest : public cvtest::BaseTest
{
public:
Core_DFTComplexOutputTest() {}
~Core_DFTComplexOutputTest() {}
protected:
void run(int)
{
RNG& rng = theRNG();
for( int i = 0; i < 10; i++ )
{
int m = rng.uniform(2, 11);
int n = rng.uniform(2, 11);
int depth = rng.uniform(0, 2) + CV_32F;
Mat src8u(m, n, depth), src(m, n, depth), dst(m, n, CV_MAKETYPE(depth, 2));
Mat z = Mat::zeros(m, n, depth), dstz;
randu(src8u, Scalar::all(0), Scalar::all(10));
src8u.convertTo(src, src.type());
dst = Scalar::all(123);
Mat mv[] = {src, z}, srcz;
merge(mv, 2, srcz);
dft(srcz, dstz);
dft(src, dst, DFT_COMPLEX_OUTPUT);
if (cvtest::norm(dst, dstz, NORM_INF) > 1e-3)
{
cout << "actual:\n" << dst << endl << endl;
cout << "reference:\n" << dstz << endl << endl;
CV_Error(CV_StsError, "");
}
}
}
};
TEST(Core_DFT, complex_output) { Core_DFTComplexOutputTest test; test.safe_run(); }
TEST(Core_DFT, complex_output2)
{
for( int i = 0; i < 100; i++ )
{
int type = theRNG().uniform(0, 2) ? CV_64F : CV_32F;
int m = theRNG().uniform(1, 10);
int n = theRNG().uniform(1, 10);
Mat x(m, n, type), out;
randu(x, -1., 1.);
dft(x, out, DFT_ROWS | DFT_COMPLEX_OUTPUT);
double nrm = cvtest::norm(out, NORM_INF);
double thresh = n*m*2;
if( nrm > thresh )
{
cout << "x: " << x << endl;
cout << "out: " << out << endl;
ASSERT_LT(nrm, thresh);
}
}
}
class Core_DXTReverseTest : public cvtest::BaseTest
{
public:
enum Mode
{
ModeDFT,
ModeDCT
};
Core_DXTReverseTest(Mode m) : mode(m) {}
private:
Mode mode;
protected:
void run(int)
{
for (int i = 0; i < 3; ++i)
{
if (mode == ModeDCT && i != 0)
continue;
int flags = 0;
int flags_inv = DFT_INVERSE | DFT_SCALE;
int cn_in = 0;
int cn_out = 0;
switch (i)
{
case 0: cn_in = 1; cn_out = 1; break;
case 1: cn_in = 1; cn_out = 2; flags |= DFT_COMPLEX_OUTPUT; flags_inv |= DFT_REAL_OUTPUT; break;
case 2: cn_in = 2; cn_out = 2; break;
};
for (int j = 0; j < 100; ++j)
{
RNG& rng = ts->get_rng();
int type = rng.uniform(0, 2) ? CV_64F : CV_32F;
int m = rng.uniform(1, 10);
int n = rng.uniform(1, 10);
if (mode == ModeDCT)
{
m *= 2;
n *= 2;
}
Mat one(m, n, CV_MAKETYPE(type, cn_in));
cvtest::randUni(rng, one, Scalar::all(-1.), Scalar::all(1.));
Mat out;
Mat two;
if (mode == ModeDFT)
{
cv::dft(one, out, flags);
cv::dft(out, two, flags_inv);
}
else if (mode == ModeDCT)
{
cv::dct(one, out, flags);
cv::dct(out, two, flags_inv);
}
if (out.channels() != cn_out || two.channels() != cn_in || cvtest::norm(one, two, NORM_INF) > 1e-5)
{
cout << "Test #" << j + 1 << " - "
<< "elements: " << m << " x " << n << ", "
<< "channels: "
<< one.channels() << " (" << cn_in << ")" << " -> "
<< out.channels() << " (" << cn_out << ")" << " -> "
<< two.channels() << " (" << cn_in << ")"
<< endl;
cout << "signal:\n" << one << endl << endl;
cout << "spectrum:\n" << out << endl << endl;
cout << "inverse:\n" << two << endl << endl;
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
break;
}
}
}
}
};
TEST(Core_DFT, reverse) { Core_DXTReverseTest test(Core_DXTReverseTest::ModeDFT); test.safe_run(); }
TEST(Core_DCT, reverse) { Core_DXTReverseTest test(Core_DXTReverseTest::ModeDCT); test.safe_run(); }
}} // namespace

View File

@ -0,0 +1,545 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "test_precomp.hpp"
namespace opencv_test { namespace {
#define sign(a) a > 0 ? 1 : a == 0 ? 0 : -1
#define CORE_EIGEN_ERROR_COUNT 1
#define CORE_EIGEN_ERROR_SIZE 2
#define CORE_EIGEN_ERROR_DIFF 3
#define CORE_EIGEN_ERROR_ORTHO 4
#define CORE_EIGEN_ERROR_ORDER 5
#define MESSAGE_ERROR_COUNT "Matrix of eigen values must have the same rows as source matrix and 1 column."
#define MESSAGE_ERROR_SIZE "Source matrix and matrix of eigen vectors must have the same sizes."
#define MESSAGE_ERROR_DIFF_1 "Accuracy of eigen values computing less than required."
#define MESSAGE_ERROR_DIFF_2 "Accuracy of eigen vectors computing less than required."
#define MESSAGE_ERROR_ORTHO "Matrix of eigen vectors is not orthogonal."
#define MESSAGE_ERROR_ORDER "Eigen values are not sorted in descending order."
const int COUNT_NORM_TYPES = 3;
const int NORM_TYPE[COUNT_NORM_TYPES] = {cv::NORM_L1, cv::NORM_L2, cv::NORM_INF};
enum TASK_TYPE_EIGEN {VALUES, VECTORS};
class Core_EigenTest: public cvtest::BaseTest
{
public:
Core_EigenTest();
~Core_EigenTest();
protected:
bool test_values(const cv::Mat& src); // complex test for eigen without vectors
bool check_full(int type); // complex test for symmetric matrix
virtual void run (int) = 0; // main testing method
protected:
float eps_val_32, eps_vec_32;
float eps_val_64, eps_vec_64;
int ntests;
bool check_pair_count(const cv::Mat& src, const cv::Mat& evalues, int low_index = -1, int high_index = -1);
bool check_pair_count(const cv::Mat& src, const cv::Mat& evalues, const cv::Mat& evectors, int low_index = -1, int high_index = -1);
bool check_pairs_order(const cv::Mat& eigen_values); // checking order of eigen values & vectors (it should be none up)
bool check_orthogonality(const cv::Mat& U); // checking is matrix of eigen vectors orthogonal
bool test_pairs(const cv::Mat& src); // complex test for eigen with vectors
void print_information(const size_t norm_idx, const cv::Mat& src, double diff, double max_diff);
};
class Core_EigenTest_Scalar : public Core_EigenTest
{
public:
Core_EigenTest_Scalar() : Core_EigenTest() {}
~Core_EigenTest_Scalar();
virtual void run(int) = 0;
};
class Core_EigenTest_Scalar_32 : public Core_EigenTest_Scalar
{
public:
Core_EigenTest_Scalar_32() : Core_EigenTest_Scalar() {}
~Core_EigenTest_Scalar_32();
void run(int);
};
class Core_EigenTest_Scalar_64 : public Core_EigenTest_Scalar
{
public:
Core_EigenTest_Scalar_64() : Core_EigenTest_Scalar() {}
~Core_EigenTest_Scalar_64();
void run(int);
};
class Core_EigenTest_32 : public Core_EigenTest
{
public:
Core_EigenTest_32(): Core_EigenTest() {}
~Core_EigenTest_32() {}
void run(int);
};
class Core_EigenTest_64 : public Core_EigenTest
{
public:
Core_EigenTest_64(): Core_EigenTest() {}
~Core_EigenTest_64() {}
void run(int);
};
Core_EigenTest_Scalar::~Core_EigenTest_Scalar() {}
Core_EigenTest_Scalar_32::~Core_EigenTest_Scalar_32() {}
Core_EigenTest_Scalar_64::~Core_EigenTest_Scalar_64() {}
void Core_EigenTest_Scalar_32::run(int)
{
for (int i = 0; i < ntests; ++i)
{
float value = cv::randu<float>();
cv::Mat src(1, 1, CV_32FC1, Scalar::all((float)value));
test_values(src);
}
}
void Core_EigenTest_Scalar_64::run(int)
{
for (int i = 0; i < ntests; ++i)
{
float value = cv::randu<float>();
cv::Mat src(1, 1, CV_64FC1, Scalar::all((double)value));
test_values(src);
}
}
void Core_EigenTest_32::run(int) { check_full(CV_32FC1); }
void Core_EigenTest_64::run(int) { check_full(CV_64FC1); }
Core_EigenTest::Core_EigenTest()
: eps_val_32(1e-3f), eps_vec_32(1e-3f),
eps_val_64(1e-4f), eps_vec_64(1e-4f), ntests(100) {}
Core_EigenTest::~Core_EigenTest() {}
bool Core_EigenTest::check_pair_count(const cv::Mat& src, const cv::Mat& evalues, int low_index, int high_index)
{
int n = src.rows, s = sign(high_index);
if (!( (evalues.rows == n - max<int>(0, low_index) - ((int)((n/2.0)*(s*s-s)) + (1+s-s*s)*(n - (high_index+1)))) && (evalues.cols == 1)))
{
std::cout << endl; std::cout << "Checking sizes of eigen values matrix " << evalues << "..." << endl;
std::cout << "Number of rows: " << evalues.rows << " Number of cols: " << evalues.cols << endl;
std::cout << "Size of src symmetric matrix: " << src.rows << " * " << src.cols << endl; std::cout << endl;
CV_Error(CORE_EIGEN_ERROR_COUNT, MESSAGE_ERROR_COUNT);
}
return true;
}
bool Core_EigenTest::check_pair_count(const cv::Mat& src, const cv::Mat& evalues, const cv::Mat& evectors, int low_index, int high_index)
{
int n = src.rows, s = sign(high_index);
int right_eigen_pair_count = n - max<int>(0, low_index) - ((int)((n/2.0)*(s*s-s)) + (1+s-s*s)*(n - (high_index+1)));
if (!(evectors.rows == right_eigen_pair_count && evectors.cols == right_eigen_pair_count))
{
std::cout << endl; std::cout << "Checking sizes of eigen vectors matrix " << evectors << "..." << endl;
std::cout << "Number of rows: " << evectors.rows << " Number of cols: " << evectors.cols << endl;
std:: cout << "Size of src symmetric matrix: " << src.rows << " * " << src.cols << endl; std::cout << endl;
CV_Error (CORE_EIGEN_ERROR_SIZE, MESSAGE_ERROR_SIZE);
}
if (!(evalues.rows == right_eigen_pair_count && evalues.cols == 1))
{
std::cout << endl; std::cout << "Checking sizes of eigen values matrix " << evalues << "..." << endl;
std::cout << "Number of rows: " << evalues.rows << " Number of cols: " << evalues.cols << endl;
std:: cout << "Size of src symmetric matrix: " << src.rows << " * " << src.cols << endl; std::cout << endl;
CV_Error (CORE_EIGEN_ERROR_COUNT, MESSAGE_ERROR_COUNT);
}
return true;
}
void Core_EigenTest::print_information(const size_t norm_idx, const cv::Mat& src, double diff, double max_diff)
{
switch (NORM_TYPE[norm_idx])
{
case cv::NORM_L1: std::cout << "L1"; break;
case cv::NORM_L2: std::cout << "L2"; break;
case cv::NORM_INF: std::cout << "INF"; break;
default: break;
}
cout << "-criteria... " << endl;
cout << "Source size: " << src.rows << " * " << src.cols << endl;
cout << "Difference between original eigen vectors matrix and result: " << diff << endl;
cout << "Maximum allowed difference: " << max_diff << endl; cout << endl;
}
bool Core_EigenTest::check_orthogonality(const cv::Mat& U)
{
int type = U.type();
double eps_vec = type == CV_32FC1 ? eps_vec_32 : eps_vec_64;
cv::Mat UUt; cv::mulTransposed(U, UUt, false);
cv::Mat E = Mat::eye(U.rows, U.cols, type);
for (int i = 0; i < COUNT_NORM_TYPES; ++i)
{
double diff = cvtest::norm(UUt, E, NORM_TYPE[i] | cv::NORM_RELATIVE);
if (diff > eps_vec)
{
std::cout << endl; std::cout << "Checking orthogonality of matrix " << U << ": ";
print_information(i, U, diff, eps_vec);
CV_Error(CORE_EIGEN_ERROR_ORTHO, MESSAGE_ERROR_ORTHO);
}
}
return true;
}
bool Core_EigenTest::check_pairs_order(const cv::Mat& eigen_values)
{
switch (eigen_values.type())
{
case CV_32FC1:
{
for (int i = 0; i < (int)(eigen_values.total() - 1); ++i)
if (!(eigen_values.at<float>(i, 0) > eigen_values.at<float>(i+1, 0)))
{
std::cout << endl; std::cout << "Checking order of eigen values vector " << eigen_values << "..." << endl;
std::cout << "Pair of indexes with non descending of eigen values: (" << i << ", " << i+1 << ")." << endl;
std::cout << endl;
CV_Error(CORE_EIGEN_ERROR_ORDER, MESSAGE_ERROR_ORDER);
}
break;
}
case CV_64FC1:
{
for (int i = 0; i < (int)(eigen_values.total() - 1); ++i)
if (!(eigen_values.at<double>(i, 0) > eigen_values.at<double>(i+1, 0)))
{
std::cout << endl; std::cout << "Checking order of eigen values vector " << eigen_values << "..." << endl;
std::cout << "Pair of indexes with non descending of eigen values: (" << i << ", " << i+1 << ")." << endl;
std::cout << endl;
CV_Error(CORE_EIGEN_ERROR_ORDER, "Eigen values are not sorted in descending order.");
}
break;
}
default:;
}
return true;
}
bool Core_EigenTest::test_pairs(const cv::Mat& src)
{
int type = src.type();
double eps_vec = type == CV_32FC1 ? eps_vec_32 : eps_vec_64;
cv::Mat eigen_values, eigen_vectors;
cv::eigen(src, eigen_values, eigen_vectors);
if (!check_pair_count(src, eigen_values, eigen_vectors))
return false;
if (!check_orthogonality (eigen_vectors))
return false;
if (!check_pairs_order(eigen_values))
return false;
cv::Mat eigen_vectors_t; cv::transpose(eigen_vectors, eigen_vectors_t);
// Check:
// src * eigenvector = eigenval * eigenvector
cv::Mat lhs(src.rows, src.cols, type);
cv::Mat rhs(src.rows, src.cols, type);
lhs = src*eigen_vectors_t;
for (int i = 0; i < src.cols; ++i)
{
double eigenval = 0;
switch (type)
{
case CV_32FC1: eigenval = eigen_values.at<float>(i, 0); break;
case CV_64FC1: eigenval = eigen_values.at<double>(i, 0); break;
}
cv::Mat rhs_v = eigenval * eigen_vectors_t.col(i);
rhs_v.copyTo(rhs.col(i));
}
for (int i = 0; i < COUNT_NORM_TYPES; ++i)
{
double diff = cvtest::norm(lhs, rhs, NORM_TYPE[i] | cv::NORM_RELATIVE);
if (diff > eps_vec)
{
std::cout << endl; std::cout << "Checking accuracy of eigen vectors computing for matrix " << src << ": ";
print_information(i, src, diff, eps_vec);
CV_Error(CORE_EIGEN_ERROR_DIFF, MESSAGE_ERROR_DIFF_2);
}
}
return true;
}
bool Core_EigenTest::test_values(const cv::Mat& src)
{
int type = src.type();
double eps_val = type == CV_32FC1 ? eps_val_32 : eps_val_64;
cv::Mat eigen_values_1, eigen_values_2, eigen_vectors;
if (!test_pairs(src)) return false;
cv::eigen(src, eigen_values_1, eigen_vectors);
cv::eigen(src, eigen_values_2);
if (!check_pair_count(src, eigen_values_2)) return false;
for (int i = 0; i < COUNT_NORM_TYPES; ++i)
{
double diff = cvtest::norm(eigen_values_1, eigen_values_2, NORM_TYPE[i] | cv::NORM_RELATIVE);
if (diff > eps_val)
{
std::cout << endl; std::cout << "Checking accuracy of eigen values computing for matrix " << src << ": ";
print_information(i, src, diff, eps_val);
CV_Error(CORE_EIGEN_ERROR_DIFF, MESSAGE_ERROR_DIFF_1);
}
}
return true;
}
bool Core_EigenTest::check_full(int type)
{
const int MAX_DEGREE = 7;
RNG rng = cv::theRNG(); // fix the seed
for (int i = 0; i < ntests; ++i)
{
int src_size = (int)(std::pow(2.0, (rng.uniform(0, MAX_DEGREE) + 1.)));
cv::Mat src(src_size, src_size, type);
for (int j = 0; j < src.rows; ++j)
for (int k = j; k < src.cols; ++k)
if (type == CV_32FC1) src.at<float>(k, j) = src.at<float>(j, k) = cv::randu<float>();
else src.at<double>(k, j) = src.at<double>(j, k) = cv::randu<double>();
if (!test_values(src)) return false;
}
return true;
}
TEST(Core_Eigen, scalar_32) {Core_EigenTest_Scalar_32 test; test.safe_run(); }
TEST(Core_Eigen, scalar_64) {Core_EigenTest_Scalar_64 test; test.safe_run(); }
TEST(Core_Eigen, vector_32) { Core_EigenTest_32 test; test.safe_run(); }
TEST(Core_Eigen, vector_64) { Core_EigenTest_64 test; test.safe_run(); }
template<typename T>
static void testEigen(const Mat_<T>& src, const Mat_<T>& expected_eigenvalues, bool runSymmetric = false)
{
SCOPED_TRACE(runSymmetric ? "cv::eigen" : "cv::eigenNonSymmetric");
int type = traits::Type<T>::value;
const T eps = src.type() == CV_32F ? 1e-4f : 1e-6f;
Mat eigenvalues, eigenvectors, eigenvalues0;
if (runSymmetric)
{
cv::eigen(src, eigenvalues0, noArray());
cv::eigen(src, eigenvalues, eigenvectors);
}
else
{
cv::eigenNonSymmetric(src, eigenvalues0, noArray());
cv::eigenNonSymmetric(src, eigenvalues, eigenvectors);
}
#if 0
std::cout << "src = " << src << std::endl;
std::cout << "eigenvalues.t() = " << eigenvalues.t() << std::endl;
std::cout << "eigenvectors = " << eigenvectors << std::endl;
#endif
ASSERT_EQ(type, eigenvalues0.type());
ASSERT_EQ(type, eigenvalues.type());
ASSERT_EQ(type, eigenvectors.type());
ASSERT_EQ(src.rows, eigenvalues.rows);
ASSERT_EQ(eigenvalues.rows, eigenvectors.rows);
ASSERT_EQ(src.rows, eigenvectors.cols);
EXPECT_LT(cvtest::norm(eigenvalues, eigenvalues0, NORM_INF), eps);
// check definition: src*eigenvectors.row(i).t() = eigenvalues.at<srcType>(i)*eigenvectors.row(i).t()
for (int i = 0; i < src.rows; i++)
{
EXPECT_NEAR(eigenvalues.at<T>(i), expected_eigenvalues(i), eps) << "i=" << i;
Mat lhs = src*eigenvectors.row(i).t();
Mat rhs = eigenvalues.at<T>(i)*eigenvectors.row(i).t();
EXPECT_LT(cvtest::norm(lhs, rhs, NORM_INF), eps)
<< "i=" << i << " eigenvalue=" << eigenvalues.at<T>(i) << std::endl
<< "lhs=" << lhs.t() << std::endl
<< "rhs=" << rhs.t();
}
}
template<typename T>
static void testEigenSymmetric3x3()
{
/*const*/ T values_[] = {
2, -1, 0,
-1, 2, -1,
0, -1, 2
};
Mat_<T> src(3, 3, values_);
/*const*/ T expected_eigenvalues_[] = { 3.414213562373095f, 2, 0.585786437626905f };
Mat_<T> expected_eigenvalues(3, 1, expected_eigenvalues_);
testEigen(src, expected_eigenvalues);
testEigen(src, expected_eigenvalues, true);
}
TEST(Core_EigenSymmetric, float3x3) { testEigenSymmetric3x3<float>(); }
TEST(Core_EigenSymmetric, double3x3) { testEigenSymmetric3x3<double>(); }
template<typename T>
static void testEigenSymmetric5x5()
{
/*const*/ T values_[5*5] = {
5, -1, 0, 2, 1,
-1, 4, -1, 0, 0,
0, -1, 3, 1, -1,
2, 0, 1, 4, 0,
1, 0, -1, 0, 1
};
Mat_<T> src(5, 5, values_);
/*const*/ T expected_eigenvalues_[] = { 7.028919644935684f, 4.406130784616501f, 3.73626552682258f, 1.438067799899037f, 0.390616243726198f };
Mat_<T> expected_eigenvalues(5, 1, expected_eigenvalues_);
testEigen(src, expected_eigenvalues);
testEigen(src, expected_eigenvalues, true);
}
TEST(Core_EigenSymmetric, float5x5) { testEigenSymmetric5x5<float>(); }
TEST(Core_EigenSymmetric, double5x5) { testEigenSymmetric5x5<double>(); }
template<typename T>
static void testEigen2x2()
{
/*const*/ T values_[] = { 4, 1, 6, 3 };
Mat_<T> src(2, 2, values_);
/*const*/ T expected_eigenvalues_[] = { 6, 1 };
Mat_<T> expected_eigenvalues(2, 1, expected_eigenvalues_);
testEigen(src, expected_eigenvalues);
}
TEST(Core_EigenNonSymmetric, float2x2) { testEigen2x2<float>(); }
TEST(Core_EigenNonSymmetric, double2x2) { testEigen2x2<double>(); }
template<typename T>
static void testEigen3x3()
{
/*const*/ T values_[3*3] = {
3,1,0,
0,3,1,
0,0,3
};
Mat_<T> src(3, 3, values_);
/*const*/ T expected_eigenvalues_[] = { 3, 3, 3 };
Mat_<T> expected_eigenvalues(3, 1, expected_eigenvalues_);
testEigen(src, expected_eigenvalues);
}
TEST(Core_EigenNonSymmetric, float3x3) { testEigen3x3<float>(); }
TEST(Core_EigenNonSymmetric, double3x3) { testEigen3x3<double>(); }
typedef testing::TestWithParam<int> Core_EigenZero;
TEST_P(Core_EigenZero, double)
{
int N = GetParam();
Mat_<double> srcZero = Mat_<double>::zeros(N, N);
Mat_<double> expected_eigenvalueZero = Mat_<double>::zeros(N, 1); // 1D Mat
testEigen(srcZero, expected_eigenvalueZero);
testEigen(srcZero, expected_eigenvalueZero, true);
}
INSTANTIATE_TEST_CASE_P(/**/, Core_EigenZero, testing::Values(2, 3, 5));
TEST(Core_EigenNonSymmetric, convergence)
{
Matx33d m(
0, -1, 0,
1, 0, 1,
0, -1, 0);
Mat eigenvalues, eigenvectors;
// eigen values are complex, algorithm doesn't converge
try
{
cv::eigenNonSymmetric(m, eigenvalues, eigenvectors);
std::cout << Mat(eigenvalues.t()) << std::endl;
}
catch (const cv::Exception& e)
{
EXPECT_EQ(Error::StsNoConv, e.code) << e.what();
}
catch (...)
{
FAIL() << "Unknown exception has been raised";
}
}
}} // namespace

View File

@ -0,0 +1,205 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the OpenCV Foundation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "test_precomp.hpp"
namespace opencv_test { namespace {
enum
{
HAL_EXP = 0,
HAL_LOG = 1,
HAL_SQRT = 2
};
TEST(Core_HAL, mathfuncs)
{
for( int hcase = 0; hcase < 6; hcase++ )
{
int depth = hcase % 2 == 0 ? CV_32F : CV_64F;
double eps = depth == CV_32F ? 1e-5 : 1e-10;
int nfunc = hcase / 2;
int n = 100;
Mat src(1, n, depth), dst(1, n, depth), dst0(1, n, depth);
randu(src, 1, 10);
double min_hal_t = DBL_MAX, min_ocv_t = DBL_MAX;
for( int iter = 0; iter < 10; iter++ )
{
double t = (double)getTickCount();
switch (nfunc)
{
case HAL_EXP:
if( depth == CV_32F )
hal::exp32f(src.ptr<float>(), dst.ptr<float>(), n);
else
hal::exp64f(src.ptr<double>(), dst.ptr<double>(), n);
break;
case HAL_LOG:
if( depth == CV_32F )
hal::log32f(src.ptr<float>(), dst.ptr<float>(), n);
else
hal::log64f(src.ptr<double>(), dst.ptr<double>(), n);
break;
case HAL_SQRT:
if( depth == CV_32F )
hal::sqrt32f(src.ptr<float>(), dst.ptr<float>(), n);
else
hal::sqrt64f(src.ptr<double>(), dst.ptr<double>(), n);
break;
default:
CV_Error(Error::StsBadArg, "unknown function");
}
t = (double)getTickCount() - t;
min_hal_t = std::min(min_hal_t, t);
t = (double)getTickCount();
switch (nfunc)
{
case HAL_EXP:
exp(src, dst0);
break;
case HAL_LOG:
log(src, dst0);
break;
case HAL_SQRT:
pow(src, 0.5, dst0);
break;
default:
CV_Error(Error::StsBadArg, "unknown function");
}
t = (double)getTickCount() - t;
min_ocv_t = std::min(min_ocv_t, t);
}
EXPECT_LE(cvtest::norm(dst, dst0, NORM_INF | NORM_RELATIVE), eps);
double freq = getTickFrequency();
printf("%s (N=%d, %s): hal time=%.2fusec, ocv time=%.2fusec\n",
(nfunc == HAL_EXP ? "exp" : nfunc == HAL_LOG ? "log" : nfunc == HAL_SQRT ? "sqrt" : "???"),
n, (depth == CV_32F ? "f32" : "f64"), min_hal_t*1e6/freq, min_ocv_t*1e6/freq);
}
}
enum
{
HAL_LU = 0,
HAL_CHOL = 1
};
typedef testing::TestWithParam<int> HAL;
TEST_P(HAL, mat_decomp)
{
int hcase = GetParam();
SCOPED_TRACE(cv::format("hcase=%d", hcase));
{
int depth = hcase % 2 == 0 ? CV_32F : CV_64F;
int size = (hcase / 2) % 4;
size = size == 0 ? 3 : size == 1 ? 4 : size == 2 ? 6 : 15;
int nfunc = (hcase / 8);
double eps = depth == CV_32F ? 1e-5 : 1e-10;
if( size == 3 )
return; // TODO ???
Mat a0(size, size, depth), a(size, size, depth), b(size, 1, depth), x(size, 1, depth), x0(size, 1, depth);
randu(a0, -1, 1);
a0 = a0*a0.t();
randu(b, -1, 1);
double min_hal_t = DBL_MAX, min_ocv_t = DBL_MAX;
size_t asize = size*size*a.elemSize();
size_t bsize = size*b.elemSize();
for( int iter = 0; iter < 10; iter++ )
{
memcpy(x.ptr(), b.ptr(), bsize);
memcpy(a.ptr(), a0.ptr(), asize);
double t = (double)getTickCount();
switch (nfunc)
{
case HAL_LU:
if( depth == CV_32F )
hal::LU32f(a.ptr<float>(), a.step, size, x.ptr<float>(), x.step, 1);
else
hal::LU64f(a.ptr<double>(), a.step, size, x.ptr<double>(), x.step, 1);
break;
case HAL_CHOL:
if( depth == CV_32F )
hal::Cholesky32f(a.ptr<float>(), a.step, size, x.ptr<float>(), x.step, 1);
else
hal::Cholesky64f(a.ptr<double>(), a.step, size, x.ptr<double>(), x.step, 1);
break;
default:
CV_Error(Error::StsBadArg, "unknown function");
}
t = (double)getTickCount() - t;
min_hal_t = std::min(min_hal_t, t);
t = (double)getTickCount();
bool solveStatus = solve(a0, b, x0, (nfunc == HAL_LU ? DECOMP_LU : DECOMP_CHOLESKY));
t = (double)getTickCount() - t;
EXPECT_TRUE(solveStatus);
min_ocv_t = std::min(min_ocv_t, t);
}
//std::cout << "x: " << Mat(x.t()) << std::endl;
//std::cout << "x0: " << Mat(x0.t()) << std::endl;
EXPECT_LE(cvtest::norm(x, x0, NORM_INF | NORM_RELATIVE), eps)
<< "x: " << Mat(x.t())
<< "\nx0: " << Mat(x0.t())
<< "\na0: " << a0
<< "\nb: " << b;
double freq = getTickFrequency();
printf("%s (%d x %d, %s): hal time=%.2fusec, ocv time=%.2fusec\n",
(nfunc == HAL_LU ? "LU" : nfunc == HAL_CHOL ? "Cholesky" : "???"),
size, size,
(depth == CV_32F ? "f32" : "f64"),
min_hal_t*1e6/freq, min_ocv_t*1e6/freq);
}
}
INSTANTIATE_TEST_CASE_P(Core, HAL, testing::Range(0, 16));
}} // namespace

View File

@ -0,0 +1,156 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
#include "test_intrin128.simd.hpp"
// see "test_intrin_emulator.cpp"
// see "opencv2/core/private/cv_cpu_include_simd_declarations.hpp"
#define CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY
#undef CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN
#undef CV_CPU_OPTIMIZATION_NAMESPACE_END
#define CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN namespace opt_EMULATOR_CPP {
#define CV_CPU_OPTIMIZATION_NAMESPACE_END }
#include "test_intrin128.simd.hpp"
#undef CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN
#undef CV_CPU_OPTIMIZATION_NAMESPACE_END
#undef CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY
#include "test_intrin128.simd_declarations.hpp"
#undef CV_CPU_DISPATCH_MODES_ALL
#include "opencv2/core/cv_cpu_dispatch.h"
#include "test_intrin256.simd.hpp"
#include "test_intrin256.simd_declarations.hpp"
#undef CV_CPU_DISPATCH_MODES_ALL
#include "opencv2/core/cv_cpu_dispatch.h"
#include "test_intrin512.simd.hpp"
#include "test_intrin512.simd_declarations.hpp"
#ifdef _MSC_VER
# pragma warning(disable:4702) // unreachable code
#endif
namespace opencv_test { namespace hal {
#define CV_CPU_CALL_CPP_EMULATOR_(fn, args) return (opt_EMULATOR_CPP::fn args)
#define CV_CPU_CALL_BASELINE_(fn, args) CV_CPU_CALL_BASELINE(fn, args)
#define DISPATCH_SIMD128(fn, cpu_opt) do { \
CV_CPU_CALL_ ## cpu_opt ## _(fn, ()); \
throw SkipTestException("SIMD128 (" #cpu_opt ") is not available or disabled"); \
} while(0)
#define DISPATCH_SIMD256(fn, cpu_opt) do { \
CV_CPU_CALL_ ## cpu_opt ## _(fn, ()); \
throw SkipTestException("SIMD256 (" #cpu_opt ") is not available or disabled"); \
} while(0)
#define DISPATCH_SIMD512(fn, cpu_opt) do { \
CV_CPU_CALL_ ## cpu_opt ## _(fn, ()); \
throw SkipTestException("SIMD512 (" #cpu_opt ") is not available or disabled"); \
} while(0)
#define DEFINE_SIMD_TESTS(simd_size, cpu_opt) \
TEST(hal_intrin ## simd_size, uint8x16_ ## cpu_opt) { DISPATCH_SIMD ## simd_size(test_hal_intrin_uint8, cpu_opt); } \
TEST(hal_intrin ## simd_size, int8x16_ ## cpu_opt) { DISPATCH_SIMD ## simd_size(test_hal_intrin_int8, cpu_opt); } \
TEST(hal_intrin ## simd_size, uint16x8_ ## cpu_opt) { DISPATCH_SIMD ## simd_size(test_hal_intrin_uint16, cpu_opt); } \
TEST(hal_intrin ## simd_size, int16x8_ ## cpu_opt) { DISPATCH_SIMD ## simd_size(test_hal_intrin_int16, cpu_opt); } \
TEST(hal_intrin ## simd_size, int32x4_ ## cpu_opt) { DISPATCH_SIMD ## simd_size(test_hal_intrin_int32, cpu_opt); } \
TEST(hal_intrin ## simd_size, uint32x4_ ## cpu_opt) { DISPATCH_SIMD ## simd_size(test_hal_intrin_uint32, cpu_opt); } \
TEST(hal_intrin ## simd_size, uint64x2_ ## cpu_opt) { DISPATCH_SIMD ## simd_size(test_hal_intrin_uint64, cpu_opt); } \
TEST(hal_intrin ## simd_size, int64x2_ ## cpu_opt) { DISPATCH_SIMD ## simd_size(test_hal_intrin_int64, cpu_opt); } \
TEST(hal_intrin ## simd_size, float32x4_ ## cpu_opt) { DISPATCH_SIMD ## simd_size(test_hal_intrin_float32, cpu_opt); } \
TEST(hal_intrin ## simd_size, float64x2_ ## cpu_opt) { DISPATCH_SIMD ## simd_size(test_hal_intrin_float64, cpu_opt); } \
namespace intrin128 {
DEFINE_SIMD_TESTS(128, CPP_EMULATOR)
DEFINE_SIMD_TESTS(128, BASELINE)
#if defined CV_CPU_DISPATCH_COMPILE_SSE2 || defined CV_CPU_BASELINE_COMPILE_SSE2
DEFINE_SIMD_TESTS(128, SSE2)
#endif
#if defined CV_CPU_DISPATCH_COMPILE_SSE3 || defined CV_CPU_BASELINE_COMPILE_SSE3
DEFINE_SIMD_TESTS(128, SSE3)
#endif
#if defined CV_CPU_DISPATCH_COMPILE_SSSE3 || defined CV_CPU_BASELINE_COMPILE_SSSE3
DEFINE_SIMD_TESTS(128, SSSE3)
#endif
#if defined CV_CPU_DISPATCH_COMPILE_SSE4_1 || defined CV_CPU_BASELINE_COMPILE_SSE4_1
DEFINE_SIMD_TESTS(128, SSE4_1)
#endif
#if defined CV_CPU_DISPATCH_COMPILE_SSE4_2 || defined CV_CPU_BASELINE_COMPILE_SSE4_2
DEFINE_SIMD_TESTS(128, SSE4_2)
#endif
#if defined CV_CPU_DISPATCH_COMPILE_AVX || defined CV_CPU_BASELINE_COMPILE_AVX
DEFINE_SIMD_TESTS(128, AVX)
#endif
#if defined CV_CPU_DISPATCH_COMPILE_AVX2 || defined CV_CPU_BASELINE_COMPILE_AVX2
DEFINE_SIMD_TESTS(128, AVX2)
#endif
#if defined CV_CPU_DISPATCH_COMPILE_AVX512_SKX || defined CV_CPU_BASELINE_COMPILE_AVX512_SKX
DEFINE_SIMD_TESTS(128, AVX512_SKX)
#endif
TEST(hal_intrin128, float16x8_FP16)
{
CV_CPU_CALL_FP16_(test_hal_intrin_float16, ());
throw SkipTestException("Unsupported hardware: FP16 is not available");
}
} // namespace intrin128
namespace intrin256 {
// Not available due missing C++ backend for SIMD256
//DEFINE_SIMD_TESTS(256, BASELINE)
//#if defined CV_CPU_DISPATCH_COMPILE_AVX
//DEFINE_SIMD_TESTS(256, AVX)
//#endif
#if defined CV_CPU_DISPATCH_COMPILE_AVX2 || defined CV_CPU_BASELINE_COMPILE_AVX2
DEFINE_SIMD_TESTS(256, AVX2)
#endif
#if defined CV_CPU_DISPATCH_COMPILE_AVX512_SKX || defined CV_CPU_BASELINE_COMPILE_AVX512_SKX
DEFINE_SIMD_TESTS(256, AVX512_SKX)
#endif
TEST(hal_intrin256, float16x16_FP16)
{
#if CV_TRY_FP16
//CV_CPU_CALL_FP16_(test_hal_intrin_float16, ());
CV_CPU_CALL_AVX2_(test_hal_intrin_float16, ());
#endif
throw SkipTestException("Unsupported: FP16 is not available");
}
} // namespace intrin256
namespace intrin512 {
#if defined CV_CPU_DISPATCH_COMPILE_AVX512_SKX || defined CV_CPU_BASELINE_COMPILE_AVX512_SKX
DEFINE_SIMD_TESTS(512, AVX512_SKX)
#endif
TEST(hal_intrin512, float16x32_FP16)
{
#if CV_TRY_FP16
CV_CPU_CALL_AVX512_SKX_(test_hal_intrin_float16, ());
#endif
throw SkipTestException("Unsupported: FP16 is not available");
}
} // namespace intrin512
}} // namespace

View File

@ -0,0 +1,22 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY
#define CV__SIMD_FORCE_WIDTH 128
#include "opencv2/core/hal/intrin.hpp"
#undef CV__SIMD_FORCE_WIDTH
#if CV_SIMD_WIDTH != 16
#error "Invalid build configuration"
#endif
#endif // CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY
namespace opencv_test { namespace hal { namespace intrin128 {
CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN
#include "test_intrin_utils.hpp"
CV_CPU_OPTIMIZATION_NAMESPACE_END
}}} //namespace

View File

@ -0,0 +1,23 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#if !defined CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY && \
!defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS // TODO? C++ fallback implementation for SIMD256
#define CV__SIMD_FORCE_WIDTH 256
#include "opencv2/core/hal/intrin.hpp"
#undef CV__SIMD_FORCE_WIDTH
#if CV_SIMD_WIDTH != 32
#error "Invalid build configuration"
#endif
#endif // CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY
namespace opencv_test { namespace hal { namespace intrin256 {
CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN
#include "test_intrin_utils.hpp"
CV_CPU_OPTIMIZATION_NAMESPACE_END
}}} //namespace

View File

@ -0,0 +1,23 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#if !defined CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY && \
!defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS // TODO? C++ fallback implementation for SIMD512
#define CV__SIMD_FORCE_WIDTH 512
#include "opencv2/core/hal/intrin.hpp"
#undef CV__SIMD_FORCE_WIDTH
#if CV_SIMD_WIDTH != 64
#error "Invalid build configuration"
#endif
#endif // CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY
namespace opencv_test { namespace hal { namespace intrin512 {
CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN
#include "test_intrin_utils.hpp"
CV_CPU_OPTIMIZATION_NAMESPACE_END
}}} //namespace

View File

@ -0,0 +1,16 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
// see "opencv2/core/private/cv_cpu_include_simd_declarations.hpp"
//#define CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY
#undef CV_FORCE_SIMD128_CPP
#define CV_FORCE_SIMD128_CPP 1
#undef CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN
#undef CV_CPU_OPTIMIZATION_NAMESPACE_END
#define CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN namespace opt_EMULATOR_CPP {
#define CV_CPU_OPTIMIZATION_NAMESPACE_END }
#include "test_intrin128.simd.hpp"
// tests implementation is in test_intrin_utils.hpp

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,281 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
#include <opencv2/core/utils/logger.hpp>
#include "../src/utils/logtagmanager.hpp"
#include "../src/utils/logtagconfigparser.hpp"
// Because "LogTagConfigParser" isn't exported from "opencv_core", the only way
// to perform test is to compile the source code into "opencv_test_core".
// This workaround may cause step debugger breakpoints to work unreliably.
#if 1
#include "../src/utils/logtagconfigparser.cpp"
#endif
using cv::utils::logging::LogTagConfigParser;
namespace opencv_test {
namespace {
typedef testing::TestWithParam<tuple<std::string, cv::utils::logging::LogLevel>> GlobalShouldSucceedTests;
TEST_P(GlobalShouldSucceedTests, globalCases)
{
const std::string input = get<0>(GetParam());
const cv::utils::logging::LogLevel expectedLevel = get<1>(GetParam());
LogTagConfigParser parser;
parser.parse(input);
EXPECT_FALSE(parser.hasMalformed());
EXPECT_EQ(parser.getMalformed().size(), 0u) << "Malformed list should be empty";
EXPECT_TRUE(parser.getGlobalConfig().isGlobal);
EXPECT_EQ(parser.getGlobalConfig().level, expectedLevel);
EXPECT_EQ(parser.getFullNameConfigs().size(), 0u) << "Specifying global log level should not emit full names";
EXPECT_EQ(parser.getFirstPartConfigs().size(), 0u) << "Specifying global log level should not emit first name part result";
EXPECT_EQ(parser.getAnyPartConfigs().size(), 0u) << "Specifying global log level should not emit any name part result";
}
INSTANTIATE_TEST_CASE_P(Core_LogTagConfigParser, GlobalShouldSucceedTests,
testing::Values(
// Following test cases omit the name part
std::make_tuple("S", cv::utils::logging::LOG_LEVEL_SILENT),
std::make_tuple("SILENT", cv::utils::logging::LOG_LEVEL_SILENT),
std::make_tuple("F", cv::utils::logging::LOG_LEVEL_FATAL),
std::make_tuple("FATAL", cv::utils::logging::LOG_LEVEL_FATAL),
std::make_tuple("E", cv::utils::logging::LOG_LEVEL_ERROR),
std::make_tuple("ERROR", cv::utils::logging::LOG_LEVEL_ERROR),
std::make_tuple("W", cv::utils::logging::LOG_LEVEL_WARNING),
std::make_tuple("WARN", cv::utils::logging::LOG_LEVEL_WARNING),
std::make_tuple("WARNING", cv::utils::logging::LOG_LEVEL_WARNING),
std::make_tuple("I", cv::utils::logging::LOG_LEVEL_INFO),
std::make_tuple("INFO", cv::utils::logging::LOG_LEVEL_INFO),
std::make_tuple("D", cv::utils::logging::LOG_LEVEL_DEBUG),
std::make_tuple("DEBUG", cv::utils::logging::LOG_LEVEL_DEBUG),
std::make_tuple("V", cv::utils::logging::LOG_LEVEL_VERBOSE),
std::make_tuple("VERBOSE", cv::utils::logging::LOG_LEVEL_VERBOSE),
// Following test cases uses a single asterisk as name
std::make_tuple("*:S", cv::utils::logging::LOG_LEVEL_SILENT),
std::make_tuple("*:SILENT", cv::utils::logging::LOG_LEVEL_SILENT),
std::make_tuple("*:V", cv::utils::logging::LOG_LEVEL_VERBOSE),
std::make_tuple("*:VERBOSE", cv::utils::logging::LOG_LEVEL_VERBOSE)
)
);
// GlobalShouldSucceedPairedTests, globalNameHandling
//
// The following tests use a strategy of performing two tests as a pair, and require the pair
// to succeed, in order to avoid false negatives due to default settings.
// The first input string is supposed to set global to SILENT, the second input string VERBOSE.
typedef testing::TestWithParam<tuple<std::string, std::string>> GlobalShouldSucceedPairedTests;
TEST_P(GlobalShouldSucceedPairedTests, globalNameHandling)
{
const auto firstExpected = cv::utils::logging::LOG_LEVEL_SILENT;
const auto secondExpected = cv::utils::logging::LOG_LEVEL_VERBOSE;
//
const std::string firstInput = get<0>(GetParam());
LogTagConfigParser firstParser;
firstParser.parse(firstInput);
ASSERT_FALSE(firstParser.hasMalformed());
ASSERT_EQ(firstParser.getMalformed().size(), 0u) << "Malformed list should be empty";
ASSERT_TRUE(firstParser.getGlobalConfig().isGlobal);
ASSERT_EQ(firstParser.getFullNameConfigs().size(), 0u) << "Specifying global log level should not emit full names";
ASSERT_EQ(firstParser.getFirstPartConfigs().size(), 0u) << "Specifying global log level should not emit first name part result";
ASSERT_EQ(firstParser.getAnyPartConfigs().size(), 0u) << "Specifying global log level should not emit any name part result";
const cv::utils::logging::LogLevel firstActual = firstParser.getGlobalConfig().level;
//
const std::string secondInput = get<1>(GetParam());
LogTagConfigParser secondParser;
secondParser.parse(secondInput);
ASSERT_FALSE(secondParser.hasMalformed());
ASSERT_EQ(secondParser.getMalformed().size(), 0u) << "Malformed list should be empty";
ASSERT_TRUE(secondParser.getGlobalConfig().isGlobal);
ASSERT_EQ(secondParser.getFullNameConfigs().size(), 0u) << "Specifying global log level should not emit full names";
ASSERT_EQ(secondParser.getFirstPartConfigs().size(), 0u) << "Specifying global log level should not emit first name part result";
ASSERT_EQ(secondParser.getAnyPartConfigs().size(), 0u) << "Specifying global log level should not emit any name part result";
const cv::utils::logging::LogLevel secondActual = secondParser.getGlobalConfig().level;
//
EXPECT_EQ(firstActual, firstExpected);
EXPECT_EQ(secondActual, secondExpected);
}
// Following test cases uses lowercase "global" as name
INSTANTIATE_TEST_CASE_P(Core_LogTagConfigParser, GlobalShouldSucceedPairedTests,
testing::Values(
std::make_tuple("global:S", "global:V"),
std::make_tuple("global:SILENT", "global:VERBOSE")
)
);
// In the next few smoke tests, the use of EXPECT versus ASSERT is as follows.
// Each test will try to read the first element from one of the vector results.
// Prior to that, the vector need to be ASSERT'ed to have at least one element.
// All remaining assertions in the test body would use EXPECT instead.
TEST(Core_LogTagConfigParser, FullNameSmokeTest)
{
LogTagConfigParser parser;
parser.parse("something:S");
EXPECT_FALSE(parser.hasMalformed());
EXPECT_EQ(parser.getMalformed().size(), 0u);
ASSERT_EQ(parser.getFullNameConfigs().size(), 1u);
EXPECT_EQ(parser.getFirstPartConfigs().size(), 0u);
EXPECT_EQ(parser.getAnyPartConfigs().size(), 0u);
EXPECT_STREQ(parser.getFullNameConfigs().at(0u).namePart.c_str(), "something");
}
TEST(Core_LogTagConfigParser, FirstPartSmokeTest_NoPeriod)
{
LogTagConfigParser parser;
parser.parse("something*:S");
EXPECT_FALSE(parser.hasMalformed());
EXPECT_EQ(parser.getMalformed().size(), 0u);
EXPECT_EQ(parser.getFullNameConfigs().size(), 0u);
ASSERT_EQ(parser.getFirstPartConfigs().size(), 1u);
EXPECT_EQ(parser.getAnyPartConfigs().size(), 0u);
EXPECT_STREQ(parser.getFirstPartConfigs().at(0u).namePart.c_str(), "something");
}
TEST(Core_LogTagConfigParser, FirstPartSmokeTest_WithPeriod)
{
LogTagConfigParser parser;
parser.parse("something.*:S");
EXPECT_FALSE(parser.hasMalformed());
EXPECT_EQ(parser.getMalformed().size(), 0u);
EXPECT_EQ(parser.getFullNameConfigs().size(), 0u);
ASSERT_EQ(parser.getFirstPartConfigs().size(), 1u);
EXPECT_EQ(parser.getAnyPartConfigs().size(), 0u);
EXPECT_STREQ(parser.getFirstPartConfigs().at(0u).namePart.c_str(), "something");
}
TEST(Core_LogTagConfigParser, AnyPartSmokeTest_PrecedeAsterisk_NoPeriod)
{
LogTagConfigParser parser;
parser.parse("*something:S");
EXPECT_FALSE(parser.hasMalformed());
EXPECT_EQ(parser.getMalformed().size(), 0u);
EXPECT_EQ(parser.getFullNameConfigs().size(), 0u);
EXPECT_EQ(parser.getFirstPartConfigs().size(), 0u);
ASSERT_EQ(parser.getAnyPartConfigs().size(), 1u);
EXPECT_STREQ(parser.getAnyPartConfigs().at(0u).namePart.c_str(), "something");
}
TEST(Core_LogTagConfigParser, AnyPartSmokeTest_PrecedeAsterisk_WithPeriod)
{
LogTagConfigParser parser;
parser.parse("*.something:S");
EXPECT_FALSE(parser.hasMalformed());
EXPECT_EQ(parser.getMalformed().size(), 0u);
EXPECT_EQ(parser.getFullNameConfigs().size(), 0u);
EXPECT_EQ(parser.getFirstPartConfigs().size(), 0u);
ASSERT_EQ(parser.getAnyPartConfigs().size(), 1u);
EXPECT_STREQ(parser.getAnyPartConfigs().at(0u).namePart.c_str(), "something");
}
TEST(Core_LogTagConfigParser, AnyPartSmokeTest_PrecedeFollowAsterisks_NoPeriod)
{
LogTagConfigParser parser;
parser.parse("*something*:S");
EXPECT_FALSE(parser.hasMalformed());
EXPECT_EQ(parser.getMalformed().size(), 0u);
EXPECT_EQ(parser.getFullNameConfigs().size(), 0u);
EXPECT_EQ(parser.getFirstPartConfigs().size(), 0u);
ASSERT_EQ(parser.getAnyPartConfigs().size(), 1u);
EXPECT_STREQ(parser.getAnyPartConfigs().at(0u).namePart.c_str(), "something");
}
TEST(Core_LogTagConfigParser, AnyPartSmokeTest_PrecedeFollowAsterisks_WithPeriod)
{
LogTagConfigParser parser;
parser.parse("*.something.*:S");
EXPECT_FALSE(parser.hasMalformed());
EXPECT_EQ(parser.getMalformed().size(), 0u);
EXPECT_EQ(parser.getFullNameConfigs().size(), 0u);
EXPECT_EQ(parser.getFirstPartConfigs().size(), 0u);
ASSERT_EQ(parser.getAnyPartConfigs().size(), 1u);
EXPECT_STREQ(parser.getAnyPartConfigs().at(0u).namePart.c_str(), "something");
}
TEST(Core_LogTagConfigParser, FullName_EqualSign_ShouldSucceed)
{
LogTagConfigParser parser;
parser.parse("something=S");
EXPECT_FALSE(parser.hasMalformed());
EXPECT_EQ(parser.getMalformed().size(), 0u);
ASSERT_EQ(parser.getFullNameConfigs().size(), 1u);
EXPECT_EQ(parser.getFirstPartConfigs().size(), 0u);
EXPECT_EQ(parser.getAnyPartConfigs().size(), 0u);
EXPECT_STREQ(parser.getFullNameConfigs().at(0u).namePart.c_str(), "something");
}
TEST(Core_LogTagConfigParser, FirstPart_EqualSign_ShouldSucceed)
{
LogTagConfigParser parser;
parser.parse("something*=S");
EXPECT_FALSE(parser.hasMalformed());
EXPECT_EQ(parser.getMalformed().size(), 0u);
EXPECT_EQ(parser.getFullNameConfigs().size(), 0u);
ASSERT_EQ(parser.getFirstPartConfigs().size(), 1u);
EXPECT_EQ(parser.getAnyPartConfigs().size(), 0u);
EXPECT_STREQ(parser.getFirstPartConfigs().at(0u).namePart.c_str(), "something");
}
TEST(Core_LogTagConfigParser, AnyPart_EqualSign_ShouldSucceed)
{
LogTagConfigParser parser;
parser.parse("*something*=S");
EXPECT_FALSE(parser.hasMalformed());
EXPECT_EQ(parser.getMalformed().size(), 0u);
EXPECT_EQ(parser.getFullNameConfigs().size(), 0u);
EXPECT_EQ(parser.getFirstPartConfigs().size(), 0u);
ASSERT_EQ(parser.getAnyPartConfigs().size(), 1u);
EXPECT_STREQ(parser.getAnyPartConfigs().at(0u).namePart.c_str(), "something");
}
TEST(Core_LogTagConfigParser, DuplicateColon_ShouldFail)
{
LogTagConfigParser parser;
parser.parse("something::S");
EXPECT_TRUE(parser.hasMalformed());
EXPECT_EQ(parser.getMalformed().size(), 1u);
EXPECT_EQ(parser.getFullNameConfigs().size(), 0u);
EXPECT_EQ(parser.getFirstPartConfigs().size(), 0u);
EXPECT_EQ(parser.getAnyPartConfigs().size(), 0u);
}
TEST(Core_LogTagConfigParser, DuplicateEqual_ShouldFail)
{
LogTagConfigParser parser;
parser.parse("something==S");
EXPECT_TRUE(parser.hasMalformed());
EXPECT_EQ(parser.getMalformed().size(), 1u);
EXPECT_EQ(parser.getFullNameConfigs().size(), 0u);
EXPECT_EQ(parser.getFirstPartConfigs().size(), 0u);
EXPECT_EQ(parser.getAnyPartConfigs().size(), 0u);
}
TEST(Core_LogTagConfigParser, DuplicateColonAndEqual_ShouldFail)
{
LogTagConfigParser parser;
parser.parse("something:=S");
EXPECT_TRUE(parser.hasMalformed());
EXPECT_EQ(parser.getMalformed().size(), 1u);
EXPECT_EQ(parser.getFullNameConfigs().size(), 0u);
EXPECT_EQ(parser.getFirstPartConfigs().size(), 0u);
EXPECT_EQ(parser.getAnyPartConfigs().size(), 0u);
}
TEST(Core_LogTagConfigParser, DuplicateEqualAndColon_ShouldFail)
{
LogTagConfigParser parser;
parser.parse("something=:S");
EXPECT_TRUE(parser.hasMalformed());
EXPECT_EQ(parser.getMalformed().size(), 1u);
EXPECT_EQ(parser.getFullNameConfigs().size(), 0u);
EXPECT_EQ(parser.getFirstPartConfigs().size(), 0u);
EXPECT_EQ(parser.getAnyPartConfigs().size(), 0u);
}
}} // namespace

View File

@ -0,0 +1,668 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
#include <opencv2/core/utils/logger.hpp>
#include "../src/utils/logtagmanager.hpp"
#include "../src/utils/logtagconfigparser.hpp"
// Because "LogTagManager" isn't exported from "opencv_core", the only way
// to perform test is to compile the source code into "opencv_test_core".
// This workaround may cause step debugger breakpoints to work unreliably.
#if 1
#include "../src/utils/logtagmanager.cpp"
#endif
namespace opencv_test {
namespace {
using LogLevel = cv::utils::logging::LogLevel;
using LogTag = cv::utils::logging::LogTag;
using LogTagManager = cv::utils::logging::LogTagManager;
// Value to initialize log tag constructors
static const LogLevel constTestLevelBegin = cv::utils::logging::LOG_LEVEL_SILENT;
// Value to be set as part of test (to simulate runtime changes)
static const LogLevel constTestLevelChanged = cv::utils::logging::LOG_LEVEL_VERBOSE;
// An alternate value to initialize log tag constructors,
// for test cases where two distinct initialization values are needed.
static const LogLevel constTestLevelAltBegin = cv::utils::logging::LOG_LEVEL_FATAL;
// An alternate value to be set as part of test (to simulate runtime changes),
// for test cases where two distinct runtime set values are needed.
static const LogLevel constTestLevelAltChanged = cv::utils::logging::LOG_LEVEL_DEBUG;
// Enums for specifying which LogTagManager method to call.
// Used in parameterized tests.
enum class ByWhat
{
ByFullName = 0,
ByFirstPart = 1,
ByAnyPart = 2
};
std::ostream& operator<< (std::ostream& strm, ByWhat byWhat)
{
switch (byWhat)
{
case ByWhat::ByFullName:
strm << "ByFullName";
break;
case ByWhat::ByFirstPart:
strm << "ByFirstPart";
break;
case ByWhat::ByAnyPart:
strm << "ByAnyPart";
break;
default:
strm << "(invalid ByWhat enum" << (int)byWhat << ")";
break;
}
return strm;
}
// Enums for describing relative timing.
// Used in parameterized tests.
enum class Timing
{
Never = 0,
Before = 1,
After = 2
};
std::ostream& operator<< (std::ostream& strm, Timing timing)
{
switch (timing)
{
case Timing::Never:
strm << "Never";
break;
case Timing::Before:
strm << "Before";
break;
case Timing::After:
strm << "After";
break;
default:
strm << "(invalid Timing enum" << (int)timing << ")";
break;
}
return strm;
}
// Enums for selecting the substrings used in substring confusion tests.
enum class SubstringType
{
Prefix = 0,
Midstring = 1,
Suffix = 2,
Straddle = 3
};
std::ostream& operator<< (std::ostream& strm, SubstringType substringType)
{
switch (substringType)
{
case SubstringType::Prefix:
strm << "Prefix";
break;
case SubstringType::Midstring:
strm << "Midstring";
break;
case SubstringType::Suffix:
strm << "Suffix";
break;
case SubstringType::Straddle:
strm << "Straddle";
break;
default:
strm << "(invalid SubstringType enum: " << (int)substringType << ")";
break;
}
return strm;
}
// A base fixture consisting of the LogTagManager.
// Note that an instance of LogTagManager contains its own instance of "global" log tag.
class LogTagManagerTestFixture
: public ::testing::Test
{
protected:
LogTagManager m_logTagManager;
public:
LogTagManagerTestFixture(LogLevel initGlobalLogLevel)
: m_logTagManager(initGlobalLogLevel)
{
}
~LogTagManagerTestFixture()
{
}
};
// LogTagManagerGlobalSmokeTest verifies that the "global" log tag works as intended.
class LogTagManagerGlobalSmokeTest
: public LogTagManagerTestFixture
{
protected:
LogTag* m_actualGlobalLogTag;
protected:
static const char* const m_globalTagName;
public:
LogTagManagerGlobalSmokeTest()
: LogTagManagerTestFixture(constTestLevelBegin)
, m_actualGlobalLogTag(nullptr)
{
}
};
const char* const LogTagManagerGlobalSmokeTest::m_globalTagName = "global";
TEST_F(LogTagManagerGlobalSmokeTest, AfterCtorCanGetGlobalWithoutAssign)
{
EXPECT_NE(m_logTagManager.get(m_globalTagName), nullptr);
}
TEST_F(LogTagManagerGlobalSmokeTest, AfterCtorGetGlobalHasDefaultLevel)
{
auto globalLogTag = m_logTagManager.get(m_globalTagName);
ASSERT_NE(globalLogTag, nullptr);
EXPECT_EQ(globalLogTag->level, constTestLevelBegin);
}
TEST_F(LogTagManagerGlobalSmokeTest, AfterCtorCanSetGlobalByFullName)
{
m_logTagManager.setLevelByFullName(m_globalTagName, constTestLevelChanged);
auto globalLogTag = m_logTagManager.get(m_globalTagName);
ASSERT_NE(globalLogTag, nullptr);
EXPECT_EQ(globalLogTag->level, constTestLevelChanged);
}
#if 0
// "global" level is not supposed to be settable by name-parts.
// Therefore this test code is supposed to fail.
TEST_F(LogTagManagerGlobalSmokeTest, DISABLED_AfterCtorCanSetGlobalByFirstPart)
{
m_logTagManager.setLevelByFirstPart(m_globalTagName, constTestLevelChanged);
auto globalLogTag = m_logTagManager.get(m_globalTagName);
ASSERT_NE(globalLogTag, nullptr);
EXPECT_EQ(globalLogTag->level, constTestLevelChanged);
}
#endif
#if 0
// "global" level is not supposed to be settable by name-parts.
// Therefore this test code is supposed to fail.
TEST_F(LogTagManagerGlobalSmokeTest, DISABLED_AfterCtorCanSetGlobalByAnyPart)
{
m_logTagManager.setLevelByAnyPart(m_globalTagName, constTestLevelChanged);
auto globalLogTag = m_logTagManager.get(m_globalTagName);
ASSERT_NE(globalLogTag, nullptr);
EXPECT_EQ(globalLogTag->level, constTestLevelChanged);
}
#endif
// LogTagManagerNonGlobalSmokeTest performs basic smoke tests to verify that
// a log tag (that is not the "global" log tag) can be assigned, and its
// log level can be configured.
class LogTagManagerNonGlobalSmokeTest
: public LogTagManagerTestFixture
{
protected:
LogTag m_something;
protected:
static const char* const m_somethingTagName;
public:
LogTagManagerNonGlobalSmokeTest()
: LogTagManagerTestFixture(constTestLevelAltBegin)
, m_something(m_somethingTagName, constTestLevelBegin)
{
}
};
const char* const LogTagManagerNonGlobalSmokeTest::m_somethingTagName = "something";
TEST_F(LogTagManagerNonGlobalSmokeTest, CanAssignTagAndThenGet)
{
m_logTagManager.assign(m_something.name, &m_something);
ASSERT_EQ(m_logTagManager.get(m_somethingTagName), &m_something);
}
TEST_F(LogTagManagerNonGlobalSmokeTest, CanAssignTagAndThenGetAndShouldHaveDefaultLevel)
{
m_logTagManager.assign(m_something.name, &m_something);
ASSERT_EQ(m_logTagManager.get(m_somethingTagName), &m_something);
EXPECT_EQ(m_logTagManager.get(m_somethingTagName)->level, constTestLevelBegin);
}
TEST_F(LogTagManagerNonGlobalSmokeTest, CanSetLevelByFullNameBeforeAssignTag)
{
m_logTagManager.setLevelByFullName(m_somethingTagName, constTestLevelChanged);
m_logTagManager.assign(m_something.name, &m_something);
ASSERT_EQ(m_logTagManager.get(m_somethingTagName), &m_something);
EXPECT_EQ(m_logTagManager.get(m_somethingTagName)->level, constTestLevelChanged);
EXPECT_NE(m_logTagManager.get(m_somethingTagName)->level, constTestLevelBegin) << "Should not be left unchanged (default value)";
}
TEST_F(LogTagManagerNonGlobalSmokeTest, CanSetLevelByFirstPartBeforeAssignTag)
{
m_logTagManager.setLevelByFirstPart(m_somethingTagName, constTestLevelChanged);
m_logTagManager.assign(m_something.name, &m_something);
ASSERT_EQ(m_logTagManager.get(m_somethingTagName), &m_something);
EXPECT_EQ(m_logTagManager.get(m_somethingTagName)->level, constTestLevelChanged);
EXPECT_NE(m_logTagManager.get(m_somethingTagName)->level, constTestLevelBegin) << "Should not be left unchanged (default value)";
}
TEST_F(LogTagManagerNonGlobalSmokeTest, CanSetLevelByAnyPartBeforeAssignTag)
{
m_logTagManager.setLevelByAnyPart(m_somethingTagName, constTestLevelChanged);
m_logTagManager.assign(m_something.name, &m_something);
ASSERT_EQ(m_logTagManager.get(m_somethingTagName), &m_something);
EXPECT_EQ(m_logTagManager.get(m_somethingTagName)->level, constTestLevelChanged);
EXPECT_NE(m_logTagManager.get(m_somethingTagName)->level, constTestLevelBegin) << "Should not be left unchanged (default value)";
}
TEST_F(LogTagManagerNonGlobalSmokeTest, CanSetLevelByFullNameAfterAssignTag)
{
m_logTagManager.assign(m_something.name, &m_something);
m_logTagManager.setLevelByFullName(m_somethingTagName, constTestLevelChanged);
ASSERT_EQ(m_logTagManager.get(m_somethingTagName), &m_something);
EXPECT_EQ(m_logTagManager.get(m_somethingTagName)->level, constTestLevelChanged);
EXPECT_NE(m_logTagManager.get(m_somethingTagName)->level, constTestLevelBegin) << "Should not be left unchanged (default value)";
}
TEST_F(LogTagManagerNonGlobalSmokeTest, CanSetLevelByFirstPartAfterAssignTag)
{
m_logTagManager.assign(m_something.name, &m_something);
m_logTagManager.setLevelByFirstPart(m_somethingTagName, constTestLevelChanged);
ASSERT_EQ(m_logTagManager.get(m_somethingTagName), &m_something);
EXPECT_EQ(m_logTagManager.get(m_somethingTagName)->level, constTestLevelChanged);
EXPECT_NE(m_logTagManager.get(m_somethingTagName)->level, constTestLevelBegin) << "Should not be left unchanged (default value)";
}
TEST_F(LogTagManagerNonGlobalSmokeTest, CanSetLevelByAnyPartAfterAssignTag)
{
m_logTagManager.assign(m_something.name, &m_something);
m_logTagManager.setLevelByAnyPart(m_somethingTagName, constTestLevelChanged);
ASSERT_EQ(m_logTagManager.get(m_somethingTagName), &m_something);
EXPECT_EQ(m_logTagManager.get(m_somethingTagName)->level, constTestLevelChanged);
EXPECT_NE(m_logTagManager.get(m_somethingTagName)->level, constTestLevelBegin) << "Should not be left unchanged (default value)";
}
// Non-confusion tests use two or more (non-global) log tags with chosen names to verify
// that LogTagManager does not accidentally apply log levels to log tags other than the
// ones intended.
// LogTagManagerSubstrNonConfusionSmokeTest are non-confusion tests that focus on
// substrings. Keep in mind string matching in LogTagManager must be aligned to
// the period delimiter; substrings are not considered for matching.
class LogTagManagerSubstrNonConfusionFixture
: public LogTagManagerTestFixture
, public ::testing::WithParamInterface<std::tuple<SubstringType, bool, Timing, ByWhat>>
{
public:
struct MyTestParam
{
const SubstringType detractorNameSelector;
const bool initTargetTagWithCall;
const Timing whenToAssignDetractorTag;
const ByWhat howToSetDetractorLevel;
MyTestParam(const std::tuple<SubstringType, bool, Timing, ByWhat>& args)
: detractorNameSelector(std::get<0u>(args))
, initTargetTagWithCall(std::get<1u>(args))
, whenToAssignDetractorTag(std::get<2u>(args))
, howToSetDetractorLevel(std::get<3u>(args))
{
}
};
// The following substrings are all derived from "soursop".
// In particular, "ours" is a substring of "soursop".
protected:
LogTag tagSour;
LogTag tagSop;
LogTag tagSoursop;
LogTag tagSourDotSop;
LogTag tagOurs;
protected:
static const char* const strSour; // = "sour";
static const char* const strSop; // = "sop";
static const char* const strSoursop; // = "soursop";
static const char* const strSourDotSop; // = "sour.sop";
static const char* const strOurs; // = "ours";
public:
LogTagManagerSubstrNonConfusionFixture()
: LogTagManagerTestFixture(constTestLevelAltBegin)
, tagSour(strSour, constTestLevelBegin)
, tagSop(strSop, constTestLevelBegin)
, tagSoursop(strSoursop, constTestLevelBegin)
, tagSourDotSop(strSourDotSop, constTestLevelBegin)
, tagOurs(strOurs, constTestLevelBegin)
{
}
const char* selectDetractorName(const MyTestParam& myTestParam)
{
switch (myTestParam.detractorNameSelector)
{
case SubstringType::Prefix:
return strSour;
case SubstringType::Midstring:
return strOurs;
case SubstringType::Suffix:
return strSop;
case SubstringType::Straddle:
return strSourDotSop;
default:
throw std::logic_error("LogTagManagerSubstrNonConfusionTest::selectDetractorName");
}
}
LogTag& selectDetractorTag(const MyTestParam& myTestParam)
{
switch (myTestParam.detractorNameSelector)
{
case SubstringType::Prefix:
return tagSour;
case SubstringType::Midstring:
return tagOurs;
case SubstringType::Suffix:
return tagSop;
case SubstringType::Straddle:
return tagSourDotSop;
default:
throw std::logic_error("LogTagManagerSubstrNonConfusionTest::selectDetractorName");
}
}
};
const char* const LogTagManagerSubstrNonConfusionFixture::strSour = "sour";
const char* const LogTagManagerSubstrNonConfusionFixture::strSop = "sop";
const char* const LogTagManagerSubstrNonConfusionFixture::strSoursop = "soursop";
const char* const LogTagManagerSubstrNonConfusionFixture::strSourDotSop = "sour.sop";
const char* const LogTagManagerSubstrNonConfusionFixture::strOurs = "ours";
INSTANTIATE_TEST_CASE_P(
LogTagManagerSubstrNonConfusionTest,
LogTagManagerSubstrNonConfusionFixture,
::testing::Combine(
::testing::Values(SubstringType::Prefix, SubstringType::Midstring, SubstringType::Suffix, SubstringType::Straddle),
::testing::Values(false, true),
::testing::Values(Timing::Never, Timing::Before, Timing::After),
::testing::Values(ByWhat::ByFullName, ByWhat::ByFirstPart, ByWhat::ByAnyPart)
)
);
TEST_P(LogTagManagerSubstrNonConfusionFixture, ParameterizedTestFunc)
{
const auto myTestParam = MyTestParam(GetParam());
const char* detractorName = selectDetractorName(myTestParam);
LogTag& detractorTag = selectDetractorTag(myTestParam);
// Target tag is assigned
m_logTagManager.assign(tagSoursop.name, &tagSoursop);
// If detractor tag is to be assigned "before"
if (myTestParam.whenToAssignDetractorTag == Timing::Before)
{
m_logTagManager.assign(detractorName, &detractorTag);
}
// Initialize target tag to constTestLevelChanged
if (myTestParam.initTargetTagWithCall)
{
m_logTagManager.setLevelByFullName(strSoursop, constTestLevelChanged);
}
else
{
tagSoursop.level = constTestLevelChanged;
}
// If detractor tag is to be assigned "after"
if (myTestParam.whenToAssignDetractorTag == Timing::After)
{
m_logTagManager.assign(detractorName, &detractorTag);
}
// Set the log level using the detractor name
switch (myTestParam.howToSetDetractorLevel)
{
case ByWhat::ByFullName:
m_logTagManager.setLevelByFullName(detractorName, constTestLevelAltChanged);
break;
case ByWhat::ByFirstPart:
m_logTagManager.setLevelByFirstPart(detractorName, constTestLevelAltChanged);
break;
case ByWhat::ByAnyPart:
m_logTagManager.setLevelByAnyPart(detractorName, constTestLevelAltChanged);
break;
default:
FAIL() << "Invalid parameterized test value, check test case.";
}
// Verifies that the target tag is not disturbed by changes made using detractor name
ASSERT_EQ(m_logTagManager.get(strSoursop), &tagSoursop);
EXPECT_EQ(tagSoursop.level, constTestLevelChanged);
EXPECT_NE(tagSoursop.level, constTestLevelAltChanged) << "Should not be changed unless confusion bug exists";
}
// LogTagManagerNamePartNonConfusionFixture are non-confusion tests that assumes
// no substring confusions are happening, and proceed to test matching by name parts.
// In particular, setLevelByFirstPart() and setLevelByAnyPart() are the focus of these tests.
class LogTagManagerNamePartNonConfusionFixture
: public LogTagManagerTestFixture
, public ::testing::WithParamInterface<std::tuple<int, ByWhat, int, Timing, Timing>>
{
public:
struct MyTestParam
{
// Config tag name can only specify either full name or exactly one name part.
// When specifying exactly one name part, there is a choice of matching the
// first name part of a tag, or matching any name part that appears in a tag
// name regardless of its position.
const int configTagIndex;
const ByWhat configMatchBy;
const int targetTagIndex;
const Timing whenToAssignTargetTag;
const Timing whenToAssignConfigTag;
MyTestParam(const std::tuple<int, ByWhat, int, Timing, Timing>& args)
: configTagIndex(std::get<0u>(args))
, configMatchBy(std::get<1u>(args))
, targetTagIndex(std::get<2u>(args))
, whenToAssignTargetTag(std::get<3u>(args))
, whenToAssignConfigTag(std::get<4u>(args))
{
}
};
protected:
LogTag m_apple;
LogTag m_banana;
LogTag m_coconut;
LogTag m_orange;
LogTag m_pineapple;
LogTag m_bananaDotOrange;
LogTag m_bananaDotPineapple;
LogTag m_coconutDotPineapple;
protected:
static const char* const strApple; // = "apple";
static const char* const strBanana; // = "banana";
static const char* const strCoconut; // = "coconut";
static const char* const strOrange; // = "orange";
static const char* const strPineapple; // = "pineapple";
static const char* const strBananaDotOrange; // = "banana.orange";
static const char* const strBananaDotPineapple; // = "banana.pineapple";
static const char* const strCoconutDotPineapple; // = "coconut.pineapple";
public:
LogTagManagerNamePartNonConfusionFixture()
: LogTagManagerTestFixture(constTestLevelAltBegin)
, m_apple(strApple, constTestLevelBegin)
, m_banana(strBanana, constTestLevelBegin)
, m_coconut(strCoconut, constTestLevelBegin)
, m_orange(strOrange, constTestLevelBegin)
, m_pineapple(strPineapple, constTestLevelBegin)
, m_bananaDotOrange(strBananaDotOrange, constTestLevelBegin)
, m_bananaDotPineapple(strBananaDotPineapple, constTestLevelBegin)
, m_coconutDotPineapple(strCoconutDotPineapple, constTestLevelBegin)
{
}
protected:
LogTag* getLogTagByIndex(int index)
{
switch (index)
{
case 0:
return &m_apple;
case 1:
return &m_banana;
case 2:
return &m_coconut;
case 3:
return &m_orange;
case 4:
return &m_pineapple;
case 5:
return &m_bananaDotOrange;
case 6:
return &m_bananaDotPineapple;
case 7:
return &m_coconutDotPineapple;
default:
ADD_FAILURE() << "Invalid parameterized test value, check test case. "
<< "Function LogTagManagerNamePartNonConfusionFixture::getLogTagByIndex.";
return nullptr;
}
}
// findTabulatedExpectedResult returns the hard-coded expected results for parameterized
// test cases. The tables need updated if the index, name, or ordering of test tags are
// changed.
bool findTabulatedExpectedResult(const MyTestParam& myTestParam) const
{
// expectedResultUsingFirstPart:
// Each row ("config") specifies the tag name specifier used to call setLevelByFirstPart().
// Each column ("target") specifies whether an actual tag with the "target"
// name would have its log level changed because of the call to setLevelByFirstPart().
static const bool expectedResultUsingFirstPart[5][8] =
{
/*byFirstPart(apple)*/ { true, false, false, false, false, false, false, false },
/*byFirstPart(banana)*/ { false, true, false, false, false, true, true, false },
/*byFirstPart(coconut)*/ { false, false, true, false, false, false, false, true },
/*byFirstPart(orange)*/ { false, false, false, true, false, false, false, false },
/*byFirstPart(pineapple)*/ { false, false, false, false, true, false, false, false },
};
// expectedResultUsingAnyPart:
// Each row ("config") specifies the tag name specifier used to call setLevelByAnyPart().
// Each column ("target") specifies whether an actual tag with the "target"
// name would have its log level changed because of the call to setLevelByAnyPart().
static const bool expectedResultUsingAnyPart[5][8] =
{
/*byAnyPart(apple)*/ { true, false, false, false, false, false, false, false },
/*byAnyPart(banana)*/ { false, true, false, false, false, true, true, false },
/*byAnyPart(coconut)*/ { false, false, true, false, false, false, false, true },
/*byAnyPart(orange)*/ { false, false, false, true, false, true, false, false },
/*byAnyPart(pineapple)*/ { false, false, false, false, true, false, true, true },
};
switch (myTestParam.configMatchBy)
{
case ByWhat::ByFirstPart:
return expectedResultUsingFirstPart[myTestParam.configTagIndex][myTestParam.targetTagIndex];
case ByWhat::ByAnyPart:
return expectedResultUsingAnyPart[myTestParam.configTagIndex][myTestParam.targetTagIndex];
default:
ADD_FAILURE() << "Invalid parameterized test value, check test case. "
<< "Function LogTagManagerNamePartNonConfusionFixture::getLogTagByIndex.";
return false;
}
}
};
const char* const LogTagManagerNamePartNonConfusionFixture::strApple = "apple";
const char* const LogTagManagerNamePartNonConfusionFixture::strBanana = "banana";
const char* const LogTagManagerNamePartNonConfusionFixture::strCoconut = "coconut";
const char* const LogTagManagerNamePartNonConfusionFixture::strOrange = "orange";
const char* const LogTagManagerNamePartNonConfusionFixture::strPineapple = "pineapple";
const char* const LogTagManagerNamePartNonConfusionFixture::strBananaDotOrange = "banana.orange";
const char* const LogTagManagerNamePartNonConfusionFixture::strBananaDotPineapple = "banana.pineapple";
const char* const LogTagManagerNamePartNonConfusionFixture::strCoconutDotPineapple = "coconut.pineapple";
INSTANTIATE_TEST_CASE_P(
LogTagManagerNamePartNonConfusionTest,
LogTagManagerNamePartNonConfusionFixture,
::testing::Combine(
::testing::Values(0, 1, 2, 3, 4),
::testing::Values(ByWhat::ByFirstPart, ByWhat::ByAnyPart),
::testing::Values(0, 1, 2, 3, 4, 5, 6, 7),
::testing::Values(Timing::Before, Timing::After),
::testing::Values(Timing::Before, Timing::After, Timing::Never)
)
);
TEST_P(LogTagManagerNamePartNonConfusionFixture, NamePartTestFunc)
{
const auto myTestParam = MyTestParam(GetParam());
LogTag* configTag = getLogTagByIndex(myTestParam.configTagIndex);
LogTag* targetTag = getLogTagByIndex(myTestParam.targetTagIndex);
ASSERT_NE(configTag, nullptr) << "Invalid parameterized test value, check value of myTestParam.configTagIndex.";
ASSERT_NE(targetTag, nullptr) << "Invalid parameterized test value, check value of myTestParam.targetTagIndex.";
if (myTestParam.whenToAssignConfigTag == Timing::Before)
{
m_logTagManager.assign(configTag->name, configTag);
}
if (myTestParam.whenToAssignTargetTag == Timing::Before)
{
m_logTagManager.assign(targetTag->name, targetTag);
}
switch (myTestParam.configMatchBy)
{
case ByWhat::ByFirstPart:
m_logTagManager.setLevelByFirstPart(configTag->name, constTestLevelChanged);
break;
case ByWhat::ByAnyPart:
m_logTagManager.setLevelByAnyPart(configTag->name, constTestLevelChanged);
break;
default:
FAIL() << "Invalid parameterized test value, check test case. "
<< "Fixture LogTagManagerNamePartNonConfusionFixture, Case NamePartTestFunc.";
}
if (myTestParam.whenToAssignConfigTag == Timing::After)
{
m_logTagManager.assign(configTag->name, configTag);
}
if (myTestParam.whenToAssignTargetTag == Timing::After)
{
m_logTagManager.assign(targetTag->name, targetTag);
}
// Verifies the registration of the log tag pointer. If fail, cannot proceed
// because it is not certain whether the returned pointer is valid to dereference
ASSERT_EQ(m_logTagManager.get(targetTag->name), targetTag);
// Verifies the log level of target tag
const bool isChangeExpected = findTabulatedExpectedResult(myTestParam);
if (isChangeExpected)
{
EXPECT_EQ(targetTag->level, constTestLevelChanged);
EXPECT_NE(targetTag->level, constTestLevelBegin);
}
else
{
EXPECT_EQ(targetTag->level, constTestLevelBegin);
EXPECT_NE(targetTag->level, constTestLevelChanged);
}
}
}} // namespace

View File

@ -0,0 +1,154 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the OpenCV Foundation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "test_precomp.hpp"
namespace opencv_test { namespace {
TEST(Core_LPSolver, regression_basic){
cv::Mat A,B,z,etalon_z;
#if 1
//cormen's example #1
A=(cv::Mat_<double>(3,1)<<3,1,2);
B=(cv::Mat_<double>(3,4)<<1,1,3,30,2,2,5,24,4,1,2,36);
std::cout<<"here A goes\n"<<A<<"\n";
cv::solveLP(A,B,z);
std::cout<<"here z goes\n"<<z<<"\n";
etalon_z=(cv::Mat_<double>(3,1)<<8,4,0);
ASSERT_LT(cvtest::norm(z, etalon_z, cv::NORM_L1), 1e-12);
#endif
#if 1
//cormen's example #2
A=(cv::Mat_<double>(1,2)<<18,12.5);
B=(cv::Mat_<double>(3,3)<<1,1,20,1,0,20,0,1,16);
std::cout<<"here A goes\n"<<A<<"\n";
cv::solveLP(A,B,z);
std::cout<<"here z goes\n"<<z<<"\n";
etalon_z=(cv::Mat_<double>(2,1)<<20,0);
ASSERT_LT(cvtest::norm(z, etalon_z, cv::NORM_L1), 1e-12);
#endif
#if 1
//cormen's example #3
A=(cv::Mat_<double>(1,2)<<5,-3);
B=(cv::Mat_<double>(2,3)<<1,-1,1,2,1,2);
std::cout<<"here A goes\n"<<A<<"\n";
cv::solveLP(A,B,z);
std::cout<<"here z goes\n"<<z<<"\n";
etalon_z=(cv::Mat_<double>(2,1)<<1,0);
ASSERT_LT(cvtest::norm(z, etalon_z, cv::NORM_L1), 1e-12);
#endif
}
TEST(Core_LPSolver, regression_init_unfeasible){
cv::Mat A,B,z,etalon_z;
#if 1
//cormen's example #4 - unfeasible
A=(cv::Mat_<double>(1,3)<<-1,-1,-1);
B=(cv::Mat_<double>(2,4)<<-2,-7.5,-3,-10000,-20,-5,-10,-30000);
std::cout<<"here A goes\n"<<A<<"\n";
cv::solveLP(A,B,z);
std::cout<<"here z goes\n"<<z<<"\n";
etalon_z=(cv::Mat_<double>(3,1)<<1250,1000,0);
ASSERT_LT(cvtest::norm(z, etalon_z, cv::NORM_L1), 1e-12);
#endif
}
TEST(DISABLED_Core_LPSolver, regression_absolutely_unfeasible){
cv::Mat A,B,z,etalon_z;
#if 1
//trivial absolutely unfeasible example
A=(cv::Mat_<double>(1,1)<<1);
B=(cv::Mat_<double>(2,2)<<1,-1);
std::cout<<"here A goes\n"<<A<<"\n";
int res=cv::solveLP(A,B,z);
ASSERT_EQ(res,-1);
#endif
}
TEST(Core_LPSolver, regression_multiple_solutions){
cv::Mat A,B,z,etalon_z;
#if 1
//trivial example with multiple solutions
A=(cv::Mat_<double>(2,1)<<1,1);
B=(cv::Mat_<double>(1,3)<<1,1,1);
std::cout<<"here A goes\n"<<A<<"\n";
int res=cv::solveLP(A,B,z);
printf("res=%d\n",res);
printf("scalar %g\n",z.dot(A));
std::cout<<"here z goes\n"<<z<<"\n";
ASSERT_EQ(res,1);
ASSERT_LT(fabs(z.dot(A) - 1), DBL_EPSILON);
#endif
}
TEST(Core_LPSolver, regression_cycling){
cv::Mat A,B,z,etalon_z;
#if 1
//example with cycling from http://people.orie.cornell.edu/miketodd/or630/SimplexCyclingExample.pdf
A=(cv::Mat_<double>(4,1)<<10,-57,-9,-24);
B=(cv::Mat_<double>(3,5)<<0.5,-5.5,-2.5,9,0,0.5,-1.5,-0.5,1,0,1,0,0,0,1);
std::cout<<"here A goes\n"<<A<<"\n";
int res=cv::solveLP(A,B,z);
printf("res=%d\n",res);
printf("scalar %g\n",z.dot(A));
std::cout<<"here z goes\n"<<z<<"\n";
ASSERT_LT(fabs(z.dot(A) - 1), DBL_EPSILON);
//ASSERT_EQ(res,1);
#endif
}
TEST(Core_LPSolver, issue_12337)
{
Mat A=(cv::Mat_<double>(3,1)<<3,1,2);
Mat B=(cv::Mat_<double>(3,4)<<1,1,3,30,2,2,5,24,4,1,2,36);
Mat1f z_float; cv::solveLP(A, B, z_float);
Mat1d z_double; cv::solveLP(A, B, z_double);
Mat1i z_int; cv::solveLP(A, B, z_int);
EXPECT_ANY_THROW(Mat1b z_8u; cv::solveLP(A, B, z_8u));
}
}} // namespace

View File

@ -0,0 +1,10 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
#if defined(HAVE_HPX)
#include <hpx/hpx_main.hpp>
#endif
CV_TEST_MAIN("cv")

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,824 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
#include <cmath>
namespace opencv_test { namespace {
TEST(Core_OutputArrayCreate, _1997)
{
struct local {
static void create(OutputArray arr, Size submatSize, int type)
{
int sizes[] = {submatSize.width, submatSize.height};
arr.create(sizeof(sizes)/sizeof(sizes[0]), sizes, type);
}
};
Mat mat(Size(512, 512), CV_8U);
Size submatSize = Size(256, 256);
ASSERT_NO_THROW(local::create( mat(Rect(Point(), submatSize)), submatSize, mat.type() ));
}
TEST(Core_SaturateCast, NegativeNotClipped)
{
double d = -1.0;
unsigned int val = cv::saturate_cast<unsigned int>(d);
ASSERT_EQ(0xffffffff, val);
}
template<typename T, typename U>
static double maxAbsDiff(const T &t, const U &u)
{
Mat_<double> d;
absdiff(t, u, d);
double ret;
minMaxLoc(d, NULL, &ret);
return ret;
}
TEST(Core_OutputArrayAssign, _Matxd_Matd)
{
Mat expected = (Mat_<double>(2,3) << 1, 2, 3, .1, .2, .3);
Matx23d actualx;
{
OutputArray oa(actualx);
oa.assign(expected);
}
Mat actual = (Mat) actualx;
EXPECT_LE(maxAbsDiff(expected, actual), 0.0);
}
TEST(Core_OutputArrayAssign, _Matxd_Matf)
{
Mat expected = (Mat_<float>(2,3) << 1, 2, 3, .1, .2, .3);
Matx23d actualx;
{
OutputArray oa(actualx);
oa.assign(expected);
}
Mat actual = (Mat) actualx;
EXPECT_LE(maxAbsDiff(expected, actual), FLT_EPSILON);
}
TEST(Core_OutputArrayAssign, _Matxf_Matd)
{
Mat expected = (Mat_<double>(2,3) << 1, 2, 3, .1, .2, .3);
Matx23f actualx;
{
OutputArray oa(actualx);
oa.assign(expected);
}
Mat actual = (Mat) actualx;
EXPECT_LE(maxAbsDiff(expected, actual), FLT_EPSILON);
}
TEST(Core_OutputArrayAssign, _Matxd_UMatd)
{
Mat expected = (Mat_<double>(2,3) << 1, 2, 3, .1, .2, .3);
UMat uexpected = expected.getUMat(ACCESS_READ);
Matx23d actualx;
{
OutputArray oa(actualx);
oa.assign(uexpected);
}
Mat actual = (Mat) actualx;
EXPECT_LE(maxAbsDiff(expected, actual), 0.0);
}
TEST(Core_OutputArrayAssign, _Matxd_UMatf)
{
Mat expected = (Mat_<float>(2,3) << 1, 2, 3, .1, .2, .3);
UMat uexpected = expected.getUMat(ACCESS_READ);
Matx23d actualx;
{
OutputArray oa(actualx);
oa.assign(uexpected);
}
Mat actual = (Mat) actualx;
EXPECT_LE(maxAbsDiff(expected, actual), FLT_EPSILON);
}
TEST(Core_OutputArrayAssign, _Matxf_UMatd)
{
Mat expected = (Mat_<double>(2,3) << 1, 2, 3, .1, .2, .3);
UMat uexpected = expected.getUMat(ACCESS_READ);
Matx23f actualx;
{
OutputArray oa(actualx);
oa.assign(uexpected);
}
Mat actual = (Mat) actualx;
EXPECT_LE(maxAbsDiff(expected, actual), FLT_EPSILON);
}
int fixedType_handler(OutputArray dst)
{
int type = CV_32FC2; // return points only {x, y}
if (dst.fixedType())
{
type = dst.type();
CV_Assert(type == CV_32FC2 || type == CV_32FC3); // allow points + confidence level: {x, y, confidence}
}
const int N = 100;
dst.create(Size(1, N), type);
Mat m = dst.getMat();
if (m.type() == CV_32FC2)
{
for (int i = 0; i < N; i++)
m.at<Vec2f>(i) = Vec2f((float)i, (float)(i*2));
}
else if (m.type() == CV_32FC3)
{
for (int i = 0; i < N; i++)
m.at<Vec3f>(i) = Vec3f((float)i, (float)(i*2), 1.0f / (i + 1));
}
else
{
CV_Assert(0 && "Internal error");
}
return CV_MAT_CN(type);
}
TEST(Core_OutputArray, FixedType)
{
Mat_<Vec2f> pointsOnly;
int num_pointsOnly = fixedType_handler(pointsOnly);
EXPECT_EQ(2, num_pointsOnly);
Mat_<Vec3f> pointsWithConfidence;
int num_pointsWithConfidence = fixedType_handler(pointsWithConfidence);
EXPECT_EQ(3, num_pointsWithConfidence);
Mat defaultResult;
int num_defaultResult = fixedType_handler(defaultResult);
EXPECT_EQ(2, num_defaultResult);
}
TEST(Core_OutputArrayCreate, _13772)
{
cv::Mat1d mat;
cv::OutputArray o(mat);
ASSERT_NO_THROW(o.create(3, 5, CV_64F, -1, true));
}
TEST(Core_String, find_last_of__with__empty_string)
{
cv::String s;
size_t p = s.find_last_of('q', 0);
// npos is not exported: EXPECT_EQ(cv::String::npos, p);
EXPECT_EQ(std::string::npos, p);
}
TEST(Core_String, end_method_regression)
{
cv::String old_string = "012345";
cv::String new_string(old_string.begin(), old_string.end());
EXPECT_EQ(6u, new_string.size());
}
TEST(Core_Copy, repeat_regression_8972)
{
Mat src = (Mat_<int>(1, 4) << 1, 2, 3, 4);
ASSERT_ANY_THROW({
repeat(src, 5, 1, src);
});
}
class ThrowErrorParallelLoopBody : public cv::ParallelLoopBody
{
public:
ThrowErrorParallelLoopBody(cv::Mat& dst, int i) : dst_(dst), i_(i) {}
~ThrowErrorParallelLoopBody() {}
void operator()(const cv::Range& r) const
{
for (int i = r.start; i < r.end; i++)
{
CV_Assert(i != i_);
dst_.row(i).setTo(1);
}
}
protected:
Mat dst_;
int i_;
};
TEST(Core_Parallel, propagate_exceptions)
{
Mat dst1(1000, 100, CV_8SC1, Scalar::all(0));
ASSERT_NO_THROW({
parallel_for_(cv::Range(0, dst1.rows), ThrowErrorParallelLoopBody(dst1, -1));
});
Mat dst2(1000, 100, CV_8SC1, Scalar::all(0));
ASSERT_THROW({
parallel_for_(cv::Range(0, dst2.rows), ThrowErrorParallelLoopBody(dst2, dst2.rows / 2));
}, cv::Exception);
}
TEST(Core_Version, consistency)
{
// this test verifies that OpenCV version loaded in runtime
// is the same this test has been built with
EXPECT_EQ(CV_VERSION_MAJOR, cv::getVersionMajor());
EXPECT_EQ(CV_VERSION_MINOR, cv::getVersionMinor());
EXPECT_EQ(CV_VERSION_REVISION, cv::getVersionRevision());
EXPECT_EQ(String(CV_VERSION), cv::getVersionString());
}
//
// Test core/check.hpp macros
//
void test_check_eq_1(int value_1, int value_2)
{
CV_CheckEQ(value_1, value_2, "Validation check failed");
}
TEST(Core_Check, testEQ_int_fail)
{
try
{
test_check_eq_1(123, 5678);
FAIL() << "Unreachable code called";
}
catch (const cv::Exception& e)
{
EXPECT_STREQ(e.err.c_str(),
"> Validation check failed (expected: 'value_1 == value_2'), where\n"
"> 'value_1' is 123\n"
"> must be equal to\n"
"> 'value_2' is 5678\n"
);
}
catch (const std::exception& e)
{
FAIL() << "Unexpected C++ exception: " << e.what();
}
catch (...)
{
FAIL() << "Unexpected unknown exception";
}
}
TEST(Core_Check, testEQ_int_pass)
{
EXPECT_NO_THROW(
{
test_check_eq_1(1234, 1234);
});
}
void test_check_eq_2(float value_1, float value_2)
{
CV_CheckEQ(value_1, value_2, "Validation check failed (float)");
}
TEST(Core_Check, testEQ_float_fail)
{
try
{
test_check_eq_2(1234.5f, 1234.55f);
FAIL() << "Unreachable code called";
}
catch (const cv::Exception& e)
{
EXPECT_STREQ(e.err.c_str(),
"> Validation check failed (float) (expected: 'value_1 == value_2'), where\n"
"> 'value_1' is 1234.5\n" // TODO Locale handling (use LC_ALL=C on Linux)
"> must be equal to\n"
"> 'value_2' is 1234.55\n"
);
}
catch (const std::exception& e)
{
FAIL() << "Unexpected C++ exception: " << e.what();
}
catch (...)
{
FAIL() << "Unexpected unknown exception";
}
}
TEST(Core_Check, testEQ_float_pass)
{
EXPECT_NO_THROW(
{
test_check_eq_2(1234.6f, 1234.6f);
});
}
void test_check_eq_3(double value_1, double value_2)
{
CV_CheckEQ(value_1, value_2, "Validation check failed (double)");
}
TEST(Core_Check, testEQ_double_fail)
{
try
{
test_check_eq_3(1234.5, 1234.56);
FAIL() << "Unreachable code called";
}
catch (const cv::Exception& e)
{
EXPECT_STREQ(e.err.c_str(),
"> Validation check failed (double) (expected: 'value_1 == value_2'), where\n"
"> 'value_1' is 1234.5\n" // TODO Locale handling (use LC_ALL=C on Linux)
"> must be equal to\n"
"> 'value_2' is 1234.56\n"
);
}
catch (const std::exception& e)
{
FAIL() << "Unexpected C++ exception: " << e.what();
}
catch (...)
{
FAIL() << "Unexpected unknown exception";
}
}
TEST(Core_Check, testEQ_double_pass)
{
EXPECT_NO_THROW(
{
test_check_eq_3(1234.0f, 1234.0f);
});
}
void test_check_ne_1(int value_1, int value_2)
{
CV_CheckNE(value_1, value_2, "Validation NE check failed");
}
TEST(Core_Check, testNE_int_fail)
{
try
{
test_check_ne_1(123, 123);
FAIL() << "Unreachable code called";
}
catch (const cv::Exception& e)
{
EXPECT_STREQ(e.err.c_str(),
"> Validation NE check failed (expected: 'value_1 != value_2'), where\n"
"> 'value_1' is 123\n"
"> must be not equal to\n"
"> 'value_2' is 123\n"
);
}
catch (const std::exception& e)
{
FAIL() << "Unexpected C++ exception: " << e.what();
}
catch (...)
{
FAIL() << "Unexpected unknown exception";
}
}
TEST(Core_Check, testNE_int_pass)
{
EXPECT_NO_THROW(
{
test_check_ne_1(123, 1234);
});
}
void test_check_le_1(int value_1, int value_2)
{
CV_CheckLE(value_1, value_2, "Validation LE check failed");
}
TEST(Core_Check, testLE_int_fail)
{
try
{
test_check_le_1(1234, 123);
FAIL() << "Unreachable code called";
}
catch (const cv::Exception& e)
{
EXPECT_STREQ(e.err.c_str(),
"> Validation LE check failed (expected: 'value_1 <= value_2'), where\n"
"> 'value_1' is 1234\n"
"> must be less than or equal to\n"
"> 'value_2' is 123\n"
);
}
catch (const std::exception& e)
{
FAIL() << "Unexpected C++ exception: " << e.what();
}
catch (...)
{
FAIL() << "Unexpected unknown exception";
}
}
TEST(Core_Check, testLE_int_pass)
{
EXPECT_NO_THROW(
{
test_check_le_1(1234, 1234);
});
EXPECT_NO_THROW(
{
test_check_le_1(123, 1234);
});
}
void test_check_lt_1(int value_1, int value_2)
{
CV_CheckLT(value_1, value_2, "Validation LT check failed");
}
TEST(Core_Check, testLT_int_fail)
{
try
{
test_check_lt_1(1234, 123);
FAIL() << "Unreachable code called";
}
catch (const cv::Exception& e)
{
EXPECT_STREQ(e.err.c_str(),
"> Validation LT check failed (expected: 'value_1 < value_2'), where\n"
"> 'value_1' is 1234\n"
"> must be less than\n"
"> 'value_2' is 123\n"
);
}
catch (const std::exception& e)
{
FAIL() << "Unexpected C++ exception: " << e.what();
}
catch (...)
{
FAIL() << "Unexpected unknown exception";
}
}
TEST(Core_Check, testLT_int_fail_eq)
{
try
{
test_check_lt_1(123, 123);
FAIL() << "Unreachable code called";
}
catch (const cv::Exception& e)
{
EXPECT_STREQ(e.err.c_str(),
"> Validation LT check failed (expected: 'value_1 < value_2'), where\n"
"> 'value_1' is 123\n"
"> must be less than\n"
"> 'value_2' is 123\n"
);
}
catch (const std::exception& e)
{
FAIL() << "Unexpected C++ exception: " << e.what();
}
catch (...)
{
FAIL() << "Unexpected unknown exception";
}
}
TEST(Core_Check, testLT_int_pass)
{
EXPECT_NO_THROW(
{
test_check_lt_1(123, 1234);
});
}
void test_check_ge_1(int value_1, int value_2)
{
CV_CheckGE(value_1, value_2, "Validation GE check failed");
}
TEST(Core_Check, testGE_int_fail)
{
try
{
test_check_ge_1(123, 1234);
FAIL() << "Unreachable code called";
}
catch (const cv::Exception& e)
{
EXPECT_STREQ(e.err.c_str(),
"> Validation GE check failed (expected: 'value_1 >= value_2'), where\n"
"> 'value_1' is 123\n"
"> must be greater than or equal to\n"
"> 'value_2' is 1234\n"
);
}
catch (const std::exception& e)
{
FAIL() << "Unexpected C++ exception: " << e.what();
}
catch (...)
{
FAIL() << "Unexpected unknown exception";
}
}
TEST(Core_Check, testGE_int_pass)
{
EXPECT_NO_THROW(
{
test_check_ge_1(1234, 1234);
});
EXPECT_NO_THROW(
{
test_check_ge_1(1234, 123);
});
}
void test_check_gt_1(int value_1, int value_2)
{
CV_CheckGT(value_1, value_2, "Validation GT check failed");
}
TEST(Core_Check, testGT_int_fail)
{
try
{
test_check_gt_1(123, 1234);
FAIL() << "Unreachable code called";
}
catch (const cv::Exception& e)
{
EXPECT_STREQ(e.err.c_str(),
"> Validation GT check failed (expected: 'value_1 > value_2'), where\n"
"> 'value_1' is 123\n"
"> must be greater than\n"
"> 'value_2' is 1234\n"
);
}
catch (const std::exception& e)
{
FAIL() << "Unexpected C++ exception: " << e.what();
}
catch (...)
{
FAIL() << "Unexpected unknown exception";
}
}
TEST(Core_Check, testGT_int_fail_eq)
{
try
{
test_check_gt_1(123, 123);
FAIL() << "Unreachable code called";
}
catch (const cv::Exception& e)
{
EXPECT_STREQ(e.err.c_str(),
"> Validation GT check failed (expected: 'value_1 > value_2'), where\n"
"> 'value_1' is 123\n"
"> must be greater than\n"
"> 'value_2' is 123\n"
);
}
catch (const std::exception& e)
{
FAIL() << "Unexpected C++ exception: " << e.what();
}
catch (...)
{
FAIL() << "Unexpected unknown exception";
}
}
TEST(Core_Check, testGT_int_pass)
{
EXPECT_NO_THROW(
{
test_check_gt_1(1234, 123);
});
}
void test_check_MatType_1(int src_type)
{
CV_CheckTypeEQ(src_type, CV_32FC1, "Unsupported source type");
}
TEST(Core_Check, testMatType_pass)
{
EXPECT_NO_THROW(
{
test_check_MatType_1(CV_MAKE_TYPE(CV_32F, 1));
});
}
TEST(Core_Check, testMatType_fail_1)
{
try
{
test_check_MatType_1(CV_8UC1);
FAIL() << "Unreachable code called";
}
catch (const cv::Exception& e)
{
EXPECT_STREQ(e.err.c_str(),
"> Unsupported source type (expected: 'src_type == CV_32FC1'), where\n"
"> 'src_type' is 0 (CV_8UC1)\n"
"> must be equal to\n"
"> 'CV_32FC1' is 5 (CV_32FC1)\n"
);
}
catch (const std::exception& e)
{
FAIL() << "Unexpected C++ exception: " << e.what();
}
catch (...)
{
FAIL() << "Unexpected unknown exception";
}
}
void test_check_MatType_2(int src_type)
{
CV_CheckType(src_type, src_type == CV_32FC1 || src_type == CV_32FC3, "Unsupported src");
}
TEST(Core_Check, testMatType_fail_2)
{
try
{
test_check_MatType_2(CV_8UC1);
FAIL() << "Unreachable code called";
}
catch (const cv::Exception& e)
{
EXPECT_STREQ(e.err.c_str(),
"> Unsupported src:\n"
"> 'src_type == CV_32FC1 || src_type == CV_32FC3'\n"
"> where\n"
"> 'src_type' is 0 (CV_8UC1)\n"
);
}
catch (const std::exception& e)
{
FAIL() << "Unexpected C++ exception: " << e.what();
}
catch (...)
{
FAIL() << "Unexpected unknown exception";
}
}
void test_check_MatDepth_1(int src_depth)
{
CV_CheckDepthEQ(src_depth, CV_32F, "Unsupported source depth");
}
TEST(Core_Check, testMatDepth_pass)
{
EXPECT_NO_THROW(
{
test_check_MatDepth_1(CV_MAKE_TYPE(CV_32F, 1));
});
}
TEST(Core_Check, testMatDepth_fail_1)
{
try
{
test_check_MatDepth_1(CV_8U);
FAIL() << "Unreachable code called";
}
catch (const cv::Exception& e)
{
EXPECT_STREQ(e.err.c_str(),
"> Unsupported source depth (expected: 'src_depth == CV_32F'), where\n"
"> 'src_depth' is 0 (CV_8U)\n"
"> must be equal to\n"
"> 'CV_32F' is 5 (CV_32F)\n"
);
}
catch (const std::exception& e)
{
FAIL() << "Unexpected C++ exception: " << e.what();
}
catch (...)
{
FAIL() << "Unexpected unknown exception";
}
}
void test_check_MatDepth_2(int src_depth)
{
CV_CheckDepth(src_depth, src_depth == CV_32F || src_depth == CV_64F, "Unsupported src");
}
TEST(Core_Check, testMatDepth_fail_2)
{
try
{
test_check_MatDepth_2(CV_8U);
FAIL() << "Unreachable code called";
}
catch (const cv::Exception& e)
{
EXPECT_STREQ(e.err.c_str(),
"> Unsupported src:\n"
"> 'src_depth == CV_32F || src_depth == CV_64F'\n"
"> where\n"
"> 'src_depth' is 0 (CV_8U)\n"
);
}
catch (const std::exception& e)
{
FAIL() << "Unexpected C++ exception: " << e.what();
}
catch (...)
{
FAIL() << "Unexpected unknown exception";
}
}
void test_check_Size_1(const Size& srcSz)
{
CV_Check(srcSz, srcSz == Size(4, 3), "Unsupported src size");
}
TEST(Core_Check, testSize_1)
{
try
{
test_check_Size_1(Size(2, 1));
FAIL() << "Unreachable code called";
}
catch (const cv::Exception& e)
{
EXPECT_STREQ(e.err.c_str(),
"> Unsupported src size:\n"
"> 'srcSz == Size(4, 3)'\n"
"> where\n"
"> 'srcSz' is [2 x 1]\n"
);
}
catch (const std::exception& e)
{
FAIL() << "Unexpected C++ exception: " << e.what();
}
catch (...)
{
FAIL() << "Unexpected unknown exception";
}
}
TEST(Core_Allocation, alignedAllocation)
{
// iterate from size=1 to approximate byte size of 8K 32bpp image buffer
for (int i = 0; i < 200; i++) {
const size_t size = static_cast<size_t>(std::pow(1.091, (double)i));
void * const buf = cv::fastMalloc(size);
ASSERT_NE((uintptr_t)0, (uintptr_t)buf)
<< "failed to allocate memory";
ASSERT_EQ((uintptr_t)0, (uintptr_t)buf % CV_MALLOC_ALIGN)
<< "memory not aligned to " << CV_MALLOC_ALIGN;
cv::fastFree(buf);
}
}
#if !(defined(__GNUC__) && __GNUC__ < 5) // GCC 4.8 emits: 'is_trivially_copyable' is not a member of 'std'
TEST(Core_Types, trivially_copyable)
{
EXPECT_TRUE(std::is_trivially_copyable<cv::Complexd>::value);
EXPECT_TRUE(std::is_trivially_copyable<cv::Point>::value);
EXPECT_TRUE(std::is_trivially_copyable<cv::Point3f>::value);
EXPECT_TRUE(std::is_trivially_copyable<cv::Size>::value);
EXPECT_TRUE(std::is_trivially_copyable<cv::Range>::value);
EXPECT_TRUE(std::is_trivially_copyable<cv::Rect>::value);
EXPECT_TRUE(std::is_trivially_copyable<cv::RotatedRect>::value);
//EXPECT_TRUE(std::is_trivially_copyable<cv::Scalar>::value); // derived from Vec (Matx)
}
TEST(Core_Types, trivially_copyable_extra)
{
EXPECT_TRUE(std::is_trivially_copyable<cv::KeyPoint>::value);
EXPECT_TRUE(std::is_trivially_copyable<cv::DMatch>::value);
EXPECT_TRUE(std::is_trivially_copyable<cv::TermCriteria>::value);
EXPECT_TRUE(std::is_trivially_copyable<cv::Moments>::value);
}
#endif
}} // namespace

View File

@ -0,0 +1,238 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
#include "opencv2/ts/ocl_test.hpp"
namespace opencv_test {
namespace ocl {
static
testing::internal::ParamGenerator<std::string> getOpenCLTestConfigurations()
{
if (!cv::ocl::useOpenCL())
{
return testing::ValuesIn(std::vector<std::string>());
}
std::vector<std::string> configurations = {
":GPU:0",
":GPU:1",
":CPU:0",
};
return testing::ValuesIn(configurations);
}
static void executeUMatCall(bool requireOpenCL = true)
{
UMat a(100, 100, CV_8UC1, Scalar::all(0));
UMat b;
cv::add(a, Scalar::all(1), b);
Mat b_cpu = b.getMat(ACCESS_READ);
EXPECT_EQ(0, cv::norm(b_cpu - 1, NORM_INF));
if (requireOpenCL)
{
EXPECT_TRUE(cv::ocl::useOpenCL());
}
}
TEST(OCL_Context, createFromDevice)
{
bool useOCL = cv::ocl::useOpenCL();
OpenCLExecutionContext ctx = OpenCLExecutionContext::getCurrent();
if (!useOCL)
{
ASSERT_TRUE(ctx.empty()); // Other tests should not broke global state
throw SkipTestException("OpenCL is not available / disabled");
}
ASSERT_FALSE(ctx.empty());
ocl::Device device = ctx.getDevice();
ASSERT_FALSE(device.empty());
ocl::Context context = ocl::Context::fromDevice(device);
ocl::Context context2 = ocl::Context::fromDevice(device);
EXPECT_TRUE(context.getImpl() == context2.getImpl()) << "Broken cache for OpenCL context (device)";
}
TEST(OCL_OpenCLExecutionContextDefault, basic)
{
bool useOCL = cv::ocl::useOpenCL();
OpenCLExecutionContext ctx = OpenCLExecutionContext::getCurrent();
if (!useOCL)
{
ASSERT_TRUE(ctx.empty()); // Other tests should not broke global state
throw SkipTestException("OpenCL is not available / disabled");
}
ASSERT_FALSE(ctx.empty());
ocl::Context context = ctx.getContext();
ocl::Context context2 = ocl::Context::getDefault();
EXPECT_TRUE(context.getImpl() == context2.getImpl());
ocl::Device device = ctx.getDevice();
ocl::Device device2 = ocl::Device::getDefault();
EXPECT_TRUE(device.getImpl() == device2.getImpl());
ocl::Queue queue = ctx.getQueue();
ocl::Queue queue2 = ocl::Queue::getDefault();
EXPECT_TRUE(queue.getImpl() == queue2.getImpl());
}
TEST(OCL_OpenCLExecutionContextDefault, createAndBind)
{
bool useOCL = cv::ocl::useOpenCL();
OpenCLExecutionContext ctx = OpenCLExecutionContext::getCurrent();
if (!useOCL)
{
ASSERT_TRUE(ctx.empty()); // Other tests should not broke global state
throw SkipTestException("OpenCL is not available / disabled");
}
ASSERT_FALSE(ctx.empty());
ocl::Context context = ctx.getContext();
ocl::Device device = ctx.getDevice();
OpenCLExecutionContext ctx2 = OpenCLExecutionContext::create(context, device);
ASSERT_FALSE(ctx2.empty());
try
{
ctx2.bind();
executeUMatCall();
ctx.bind();
executeUMatCall();
}
catch (...)
{
ctx.bind(); // restore
throw;
}
}
typedef testing::TestWithParam<std::string> OCL_OpenCLExecutionContext_P;
TEST_P(OCL_OpenCLExecutionContext_P, multipleBindAndExecute)
{
bool useOCL = cv::ocl::useOpenCL();
OpenCLExecutionContext ctx = OpenCLExecutionContext::getCurrent();
if (!useOCL)
{
ASSERT_TRUE(ctx.empty()); // Other tests should not broke global state
throw SkipTestException("OpenCL is not available / disabled");
}
ASSERT_FALSE(ctx.empty());
std::string opencl_device = GetParam();
ocl::Context context = ocl::Context::create(opencl_device);
if (context.empty())
{
throw SkipTestException(std::string("OpenCL device is not available: '") + opencl_device + "'");
}
ocl::Device device = context.device(0);
OpenCLExecutionContext ctx2 = OpenCLExecutionContext::create(context, device);
ASSERT_FALSE(ctx2.empty());
try
{
std::cout << "ctx2..." << std::endl;
ctx2.bind();
executeUMatCall();
std::cout << "ctx..." << std::endl;
ctx.bind();
executeUMatCall();
}
catch (...)
{
ctx.bind(); // restore
throw;
}
}
TEST_P(OCL_OpenCLExecutionContext_P, ScopeTest)
{
bool useOCL = cv::ocl::useOpenCL();
OpenCLExecutionContext ctx = OpenCLExecutionContext::getCurrent();
if (!useOCL)
{
ASSERT_TRUE(ctx.empty()); // Other tests should not broke global state
throw SkipTestException("OpenCL is not available / disabled");
}
ASSERT_FALSE(ctx.empty());
std::string opencl_device = GetParam();
ocl::Context context = ocl::Context::create(opencl_device);
if (context.empty())
{
throw SkipTestException(std::string("OpenCL device is not available: '") + opencl_device + "'");
}
ocl::Device device = context.device(0);
OpenCLExecutionContext ctx2 = OpenCLExecutionContext::create(context, device);
ASSERT_FALSE(ctx2.empty());
try
{
OpenCLExecutionContextScope ctx_scope(ctx2);
executeUMatCall();
}
catch (...)
{
ctx.bind(); // restore
throw;
}
executeUMatCall();
}
INSTANTIATE_TEST_CASE_P(/*nothing*/, OCL_OpenCLExecutionContext_P, getOpenCLTestConfigurations());
typedef testing::TestWithParam<UMatUsageFlags> UsageFlagsFixture;
OCL_TEST_P(UsageFlagsFixture, UsageFlagsRetained)
{
if (!cv::ocl::useOpenCL())
{
throw SkipTestException("OpenCL is not available / disabled");
}
const UMatUsageFlags usage = GetParam();
cv::UMat flip_in(10, 10, CV_32F, usage);
cv::UMat flip_out(usage);
cv::flip(flip_in, flip_out, 1);
cv::ocl::finish();
ASSERT_EQ(usage, flip_in.usageFlags);
ASSERT_EQ(usage, flip_out.usageFlags);
}
INSTANTIATE_TEST_CASE_P(
/*nothing*/,
UsageFlagsFixture,
testing::Values(USAGE_DEFAULT, USAGE_ALLOCATE_HOST_MEMORY, USAGE_ALLOCATE_DEVICE_MEMORY)
);
} } // namespace opencv_test::ocl

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,15 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef __OPENCV_TEST_PRECOMP_HPP__
#define __OPENCV_TEST_PRECOMP_HPP__
#include "opencv2/ts.hpp"
#include "opencv2/ts/ocl_test.hpp"
#include "opencv2/core/core_c.h"
#include "opencv2/core/cvdef.h"
#include "opencv2/core/private.hpp"
#include "opencv2/core/hal/hal.hpp"
#endif

View File

@ -0,0 +1,417 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2013, NVIDIA Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the copyright holders or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "test_precomp.hpp"
namespace opencv_test { namespace {
#ifdef GTEST_CAN_COMPARE_NULL
# define EXPECT_NULL(ptr) EXPECT_EQ(NULL, ptr)
#else
# define EXPECT_NULL(ptr) EXPECT_TRUE(ptr == NULL)
#endif
using namespace cv;
namespace {
struct Reporter {
Reporter(bool* deleted) : deleted_(deleted)
{ *deleted_ = false; }
// the destructor is virtual, so that we can test dynamic_cast later
virtual ~Reporter()
{ *deleted_ = true; }
private:
bool* deleted_;
Reporter(const Reporter&);
Reporter& operator = (const Reporter&);
};
struct ReportingDeleter {
ReportingDeleter(bool* deleted) : deleted_(deleted)
{ *deleted_ = false; }
void operator()(void*)
{ *deleted_ = true; }
private:
bool* deleted_;
};
int dummyObject;
}
TEST(Core_Ptr, default_ctor)
{
Ptr<int> p;
EXPECT_NULL(p.get());
}
TEST(Core_Ptr, owning_ctor)
{
bool deleted = false;
{
Reporter* r = new Reporter(&deleted);
Ptr<void> p(r);
EXPECT_EQ(r, p.get());
}
EXPECT_TRUE(deleted);
{
Ptr<int> p(&dummyObject, ReportingDeleter(&deleted));
EXPECT_EQ(&dummyObject, p.get());
}
EXPECT_TRUE(deleted);
{
Ptr<void> p((void*)0, ReportingDeleter(&deleted));
EXPECT_NULL(p.get());
}
EXPECT_TRUE(deleted); // Differ from OpenCV 3.4 (but conformant to std::shared_ptr, see below)
{
std::shared_ptr<void> p((void*)0, ReportingDeleter(&deleted));
EXPECT_NULL(p.get());
}
EXPECT_TRUE(deleted);
}
TEST(Core_Ptr, sharing_ctor)
{
bool deleted = false;
{
Ptr<Reporter> p1(new Reporter(&deleted));
Ptr<Reporter> p2(p1);
EXPECT_EQ(p1.get(), p2.get());
p1.release();
EXPECT_FALSE(deleted);
}
EXPECT_TRUE(deleted);
{
Ptr<Reporter> p1(new Reporter(&deleted));
Ptr<void> p2(p1);
EXPECT_EQ(p1.get(), p2.get());
p1.release();
EXPECT_FALSE(deleted);
}
EXPECT_TRUE(deleted);
{
Ptr<Reporter> p1(new Reporter(&deleted));
Ptr<int> p2(p1, &dummyObject);
EXPECT_EQ(&dummyObject, p2.get());
p1.release();
EXPECT_FALSE(deleted);
}
EXPECT_TRUE(deleted);
}
TEST(Core_Ptr, assignment)
{
bool deleted1 = false, deleted2 = false;
{
Ptr<Reporter> p1(new Reporter(&deleted1));
p1 = *&p1;
EXPECT_FALSE(deleted1);
}
EXPECT_TRUE(deleted1);
{
Ptr<Reporter> p1(new Reporter(&deleted1));
Ptr<Reporter> p2(new Reporter(&deleted2));
p2 = p1;
EXPECT_TRUE(deleted2);
EXPECT_EQ(p1.get(), p2.get());
p1.release();
EXPECT_FALSE(deleted1);
}
EXPECT_TRUE(deleted1);
{
Ptr<Reporter> p1(new Reporter(&deleted1));
Ptr<void> p2(new Reporter(&deleted2));
p2 = p1;
EXPECT_TRUE(deleted2);
EXPECT_EQ(p1.get(), p2.get());
p1.release();
EXPECT_FALSE(deleted1);
}
EXPECT_TRUE(deleted1);
}
TEST(Core_Ptr, release)
{
bool deleted = false;
Ptr<Reporter> p1(new Reporter(&deleted));
p1.release();
EXPECT_TRUE(deleted);
EXPECT_NULL(p1.get());
}
TEST(Core_Ptr, reset)
{
bool deleted_old = false, deleted_new = false;
{
Ptr<void> p(new Reporter(&deleted_old));
Reporter* r = new Reporter(&deleted_new);
p.reset(r);
EXPECT_TRUE(deleted_old);
EXPECT_EQ(r, p.get());
}
EXPECT_TRUE(deleted_new);
{
Ptr<void> p(new Reporter(&deleted_old));
p.reset(&dummyObject, ReportingDeleter(&deleted_new));
EXPECT_TRUE(deleted_old);
EXPECT_EQ(&dummyObject, p.get());
}
EXPECT_TRUE(deleted_new);
}
TEST(Core_Ptr, swap)
{
bool deleted1 = false, deleted2 = false;
{
Reporter* r1 = new Reporter(&deleted1);
Reporter* r2 = new Reporter(&deleted2);
Ptr<Reporter> p1(r1), p2(r2);
p1.swap(p2);
EXPECT_EQ(r1, p2.get());
EXPECT_EQ(r2, p1.get());
EXPECT_FALSE(deleted1);
EXPECT_FALSE(deleted2);
p1.release();
EXPECT_TRUE(deleted2);
}
EXPECT_TRUE(deleted1);
{
Reporter* r1 = new Reporter(&deleted1);
Reporter* r2 = new Reporter(&deleted2);
Ptr<Reporter> p1(r1), p2(r2);
swap(p1, p2);
EXPECT_EQ(r1, p2.get());
EXPECT_EQ(r2, p1.get());
EXPECT_FALSE(deleted1);
EXPECT_FALSE(deleted2);
p1.release();
EXPECT_TRUE(deleted2);
}
EXPECT_TRUE(deleted1);
}
TEST(Core_Ptr, accessors)
{
{
Ptr<int> p;
EXPECT_NULL(static_cast<int*>(p));
EXPECT_TRUE(p.empty());
}
{
Size* s = new Size();
Ptr<Size> p(s);
EXPECT_EQ(s, static_cast<Size*>(p));
EXPECT_EQ(s, &*p);
EXPECT_EQ(&s->width, &p->width);
EXPECT_FALSE(p.empty());
}
}
namespace {
struct SubReporterBase {
virtual ~SubReporterBase() {}
int padding;
};
/* multiple inheritance, so that casts do something interesting */
struct SubReporter : SubReporterBase, Reporter
{
SubReporter(bool* deleted) : Reporter(deleted)
{}
};
}
TEST(Core_Ptr, casts)
{
bool deleted = false;
{
Ptr<const Reporter> p1(new Reporter(&deleted));
Ptr<Reporter> p2 = p1.constCast<Reporter>();
EXPECT_EQ(p1.get(), p2.get());
p1.release();
EXPECT_FALSE(deleted);
}
EXPECT_TRUE(deleted);
{
SubReporter* sr = new SubReporter(&deleted);
Ptr<Reporter> p1(sr);
// This next check isn't really for Ptr itself; it checks that Reporter
// is at a non-zero offset within SubReporter, so that the next
// check will give us more confidence that the cast actually did something.
EXPECT_NE(static_cast<void*>(sr), static_cast<void*>(p1.get()));
Ptr<SubReporter> p2 = p1.staticCast<SubReporter>();
EXPECT_EQ(sr, p2.get());
p1.release();
EXPECT_FALSE(deleted);
}
EXPECT_TRUE(deleted);
{
SubReporter* sr = new SubReporter(&deleted);
Ptr<Reporter> p1(sr);
EXPECT_NE(static_cast<void*>(sr), static_cast<void*>(p1.get()));
Ptr<void> p2 = p1.dynamicCast<void>();
EXPECT_EQ(sr, p2.get());
p1.release();
EXPECT_FALSE(deleted);
}
EXPECT_TRUE(deleted);
{
Ptr<Reporter> p1(new Reporter(&deleted));
Ptr<SubReporter> p2 = p1.dynamicCast<SubReporter>();
EXPECT_NULL(p2.get());
p1.release();
EXPECT_TRUE(deleted);
}
EXPECT_TRUE(deleted);
}
TEST(Core_Ptr, comparisons)
{
Ptr<int> p1, p2(new int), p3(new int);
Ptr<int> p4(p2, p3.get());
// Not using EXPECT_EQ here, since none of them are really "expected" or "actual".
EXPECT_TRUE(p1 == p1);
EXPECT_TRUE(p2 == p2);
EXPECT_TRUE(p2 != p3);
EXPECT_TRUE(p2 != p4);
EXPECT_TRUE(p3 == p4);
}
TEST(Core_Ptr, make)
{
bool deleted = true;
{
Ptr<void> p = makePtr<Reporter>(&deleted);
EXPECT_FALSE(deleted);
}
EXPECT_TRUE(deleted);
}
}} // namespace
namespace {
struct SpeciallyDeletable
{
SpeciallyDeletable() : deleted(false)
{}
bool deleted;
};
} // namespace
namespace cv {
template<> struct DefaultDeleter<SpeciallyDeletable>
{
void operator()(SpeciallyDeletable * obj) const { obj->deleted = true; }
};
} // namespace
namespace opencv_test { namespace {
TEST(Core_Ptr, specialized_deleter)
{
SpeciallyDeletable sd;
{ Ptr<void> p(&sd); }
ASSERT_TRUE(sd.deleted);
}
TEST(Core_Ptr, specialized_deleter_via_reset)
{
SpeciallyDeletable sd;
{
Ptr<SpeciallyDeletable> p;
p.reset(&sd);
}
ASSERT_TRUE(sd.deleted);
}
}} // namespace

View File

@ -0,0 +1,492 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
#include <opencv2/ts/cuda_test.hpp> // EXPECT_MAT_NEAR
#include <opencv2/core/quaternion.hpp>
#include <opencv2/core/dualquaternion.hpp>
namespace opencv_test{ namespace {
class QuatTest: public ::testing::Test
{
protected:
void SetUp() override
{
q1 = {1,2,3,4};
q2 = {2.5,-2,3.5,4};
q1Unit = {1 / sqrt(30), sqrt(2) /sqrt(15), sqrt(3) / sqrt(10), 2 * sqrt(2) / sqrt(15)};
q1Inv = {1.0 / 30, -1.0 / 15, -1.0 / 10, -2.0 / 15};
}
double scalar = 2.5;
double angle = CV_PI;
double qNorm2 = 2;
Vec<double, 3> axis{1, 1, 1};
Vec<double, 3> unAxis{0, 0, 0};
Vec<double, 3> unitAxis{1.0 / sqrt(3), 1.0 / sqrt(3), 1.0 / sqrt(3)};
Quatd q3 = Quatd::createFromAngleAxis(angle, axis);
Quatd q3UnitAxis = Quatd::createFromAngleAxis(angle, unitAxis);
Quat<double> q3Norm2 = q3 * qNorm2;
Quat<double> q1Inv;
Quat<double> q1;
Quat<double> q2;
Quat<double> q1Unit;
Quatd qNull{0, 0, 0, 0};
Quatd qIdentity{1, 0, 0, 0};
QuatAssumeType assumeUnit = QUAT_ASSUME_UNIT;
};
TEST_F(QuatTest, constructor)
{
Vec<double, 4> coeff{1, 2, 3, 4};
EXPECT_EQ(Quat<double> (coeff), q1);
EXPECT_EQ(q3, q3UnitAxis);
EXPECT_ANY_THROW(Quatd::createFromAngleAxis(angle, unAxis));
Matx33d R1{
-1.0 / 3, 2.0 / 3 , 2.0 / 3,
2.0 / 3 , -1.0 / 3, 2.0 / 3,
2.0 / 3 , 2.0 / 3 , -1.0 / 3
};
Matx33d R2{
-2.0 / 3, -2.0 / 3, -1.0 / 3,
-2.0 / 3, 1.0 / 3, 2.0 / 3,
-1.0 / 3, 2.0 / 3, -2.0 / 3
};
Matx33d R3{
0.818181818181, 0.181818181818, 0.54545455454,
0.545454545545, -0.54545454545, -0.6363636364,
0.181818181818, 0.818181818182, -0.5454545455
};
Matx33d R4{
0.818181818181, -0.181818181818, 0.54545455454,
0.545454545545, 0.54545454545, -0.6363636364,
-0.181818181818, 0.818181818182, 0.5454545455
};
Quatd qMat = Quatd::createFromRotMat(R1);
Quatd qMat2 = Quatd::createFromRotMat(R2);
Quatd qMat3 = Quatd::createFromRotMat(R3);
Quatd qMat4 = Quatd::createFromRotMat(R4);
EXPECT_EQ(qMat2, Quatd(0, -0.408248290463, 0.816496580927, 0.408248904638));
EXPECT_EQ(qMat3, Quatd(-0.426401432711,-0.852802865422, -0.213200716355, -0.2132007163));
EXPECT_EQ(qMat, q3);
EXPECT_EQ(qMat4, -Quatd(0.852802865422, 0.426401432711221, 0.2132007163556, 0.2132007163));
Vec3d rot{angle / sqrt(3),angle / sqrt(3), angle / sqrt(3)};
Quatd rotQuad{0, 1.0 / sqrt(3), 1. / sqrt(3), 1. / sqrt(3)};
Quatd qRot = Quatd::createFromRvec(rot);
EXPECT_EQ(qRot, rotQuad);
EXPECT_EQ(Quatd::createFromRvec(Vec3d(0, 0, 0)), qIdentity);
}
TEST_F(QuatTest, basicfuns)
{
Quat<double> q1Conj{1, -2, -3, -4};
EXPECT_EQ(q3Norm2.normalize(), q3);
EXPECT_EQ(q1.norm(), sqrt(30));
EXPECT_EQ(q1.normalize(), q1Unit);
EXPECT_ANY_THROW(qNull.normalize());
EXPECT_EQ(q1.conjugate(), q1Conj);
EXPECT_EQ(q1.inv(), q1Inv);
EXPECT_EQ(inv(q1), q1Inv);
EXPECT_EQ(q3.inv(assumeUnit) * q3, qIdentity);
EXPECT_EQ(q1.inv() * q1, qIdentity);
EXPECT_ANY_THROW(inv(qNull));
EXPECT_NO_THROW(q1.at(0));
EXPECT_ANY_THROW(q1.at(4));
Matx33d R{
-2.0 / 3, 2.0 / 15 , 11.0 / 15,
2.0 / 3 , -1.0 / 3 , 2.0 / 3 ,
1.0 / 3 , 14.0 / 15, 2.0 / 15
};
Matx33d q1RotMat = q1.toRotMat3x3();
EXPECT_MAT_NEAR(q1RotMat, R, 1e-6);
Vec3d z_axis{0,0,1};
Quatd q_unit1 = Quatd::createFromAngleAxis(angle, z_axis);
Mat pointsA = (Mat_<double>(2, 3) << 1,0,0,1,0,1);
pointsA = pointsA.t();
Mat new_point = q_unit1.toRotMat3x3() * pointsA;
Mat afterRo = (Mat_<double>(3, 2) << -1,-1,0,0,0,1);
EXPECT_MAT_NEAR(afterRo, new_point, 1e-6);
EXPECT_ANY_THROW(qNull.toRotVec());
Vec3d rodVec{CV_PI/sqrt(3), CV_PI/sqrt(3), CV_PI/sqrt(3)};
Vec3d q3Rod = q3.toRotVec();
EXPECT_NEAR(q3Rod[0], rodVec[0], 1e-6);
EXPECT_NEAR(q3Rod[1], rodVec[1], 1e-6);
EXPECT_NEAR(q3Rod[2], rodVec[2], 1e-6);
EXPECT_EQ(log(q1Unit, assumeUnit), log(q1Unit));
EXPECT_EQ(log(qIdentity, assumeUnit), qNull);
EXPECT_EQ(log(q3), Quatd(0, angle * unitAxis[0] / 2, angle * unitAxis[1] / 2, angle * unitAxis[2] / 2));
EXPECT_ANY_THROW(log(qNull));
EXPECT_EQ(log(Quatd(exp(1), 0, 0, 0)), qIdentity);
EXPECT_EQ(exp(qIdentity), Quatd(exp(1), 0, 0, 0));
EXPECT_EQ(exp(qNull), qIdentity);
EXPECT_EQ(exp(Quatd(0, angle * unitAxis[0] / 2, angle * unitAxis[1] / 2, angle * unitAxis[2] / 2)), q3);
EXPECT_EQ(power(q3, 2.0), Quatd::createFromAngleAxis(2*angle, axis));
EXPECT_EQ(power(Quatd(0.5, 0.5, 0.5, 0.5), 2.0, assumeUnit), Quatd(-0.5,0.5,0.5,0.5));
EXPECT_EQ(power(Quatd(0.5, 0.5, 0.5, 0.5), -2.0), Quatd(-0.5,-0.5,-0.5,-0.5));
EXPECT_EQ(sqrt(q1), power(q1, 0.5));
EXPECT_EQ(exp(q3 * log(q1)), power(q1, q3));
EXPECT_EQ(exp(q1 * log(q3)), power(q3, q1, assumeUnit));
EXPECT_EQ(crossProduct(q1, q3), (q1 * q3 - q3 * q1) / 2);
EXPECT_EQ(sinh(qNull), qNull);
EXPECT_EQ(sinh(q1), (exp(q1) - exp(-q1)) / 2);
EXPECT_EQ(sinh(qIdentity), Quatd(sinh(1), 0, 0, 0));
EXPECT_EQ(sinh(q1), Quatd(0.73233760604, -0.44820744998, -0.67231117497, -0.8964148999610843));
EXPECT_EQ(cosh(qNull), qIdentity);
EXPECT_EQ(cosh(q1), Quatd(0.961585117636, -0.34135217456, -0.51202826184, -0.682704349122));
EXPECT_EQ(tanh(q1), sinh(q1) * inv(cosh(q1)));
EXPECT_EQ(sin(qNull), qNull);
EXPECT_EQ(sin(q1), Quatd(91.78371578403, 21.88648685303, 32.829730279543, 43.772973706058));
EXPECT_EQ(cos(qNull), qIdentity);
EXPECT_EQ(cos(q1), Quatd(58.9336461679, -34.0861836904, -51.12927553569, -68.17236738093));
EXPECT_EQ(tan(q1), sin(q1)/cos(q1));
EXPECT_EQ(sinh(asinh(q1)), q1);
Quatd c1 = asinh(sinh(q1));
EXPECT_EQ(sinh(c1), sinh(q1));
EXPECT_EQ(cosh(acosh(q1)), q1);
c1 = acosh(cosh(q1));
EXPECT_EQ(cosh(c1), cosh(q1));
EXPECT_EQ(tanh(atanh(q1)), q1);
c1 = atanh(tanh(q1));
EXPECT_EQ(tanh(q1), tanh(c1));
EXPECT_EQ(asin(sin(q1)), q1);
EXPECT_EQ(sin(asin(q1)), q1);
EXPECT_EQ(acos(cos(q1)), q1);
EXPECT_EQ(cos(acos(q1)), q1);
EXPECT_EQ(atan(tan(q3)), q3);
EXPECT_EQ(tan(atan(q1)), q1);
}
TEST_F(QuatTest, test_operator)
{
Quatd minusQ{-1, -2, -3, -4};
Quatd qAdd{3.5, 0, 6.5, 8};
Quatd qMinus{-1.5, 4, -0.5, 0};
Quatd qMultq{-20, 1, -5, 27};
Quatd qMults{2.5, 5.0, 7.5, 10.0};
Quatd qDvss{1.0 / 2.5, 2.0 / 2.5, 3.0 / 2.5, 4.0 / 2.5};
Quatd qOrigin(q1);
EXPECT_EQ(-q1, minusQ);
EXPECT_EQ(q1 + q2, qAdd);
EXPECT_EQ(q1 + scalar, Quatd(3.5, 2, 3, 4));
EXPECT_EQ(scalar + q1, Quatd(3.5, 2, 3, 4));
EXPECT_EQ(q1 + 2.0, Quatd(3, 2, 3, 4));
EXPECT_EQ(2.0 + q1, Quatd(3, 2, 3, 4));
EXPECT_EQ(q1 - q2, qMinus);
EXPECT_EQ(q1 - scalar, Quatd(-1.5, 2, 3, 4));
EXPECT_EQ(scalar - q1, Quatd(1.5, -2, -3, -4));
EXPECT_EQ(q1 - 2.0, Quatd(-1, 2, 3, 4));
EXPECT_EQ(2.0 - q1, Quatd(1, -2, -3, -4));
EXPECT_EQ(q1 * q2, qMultq);
EXPECT_EQ(q1 * scalar, qMults);
EXPECT_EQ(scalar * q1, qMults);
EXPECT_EQ(q1 / q1, qIdentity);
EXPECT_EQ(q1 / scalar, qDvss);
q1 += q2;
EXPECT_EQ(q1, qAdd);
q1 -= q2;
EXPECT_EQ(q1, qOrigin);
q1 *= q2;
EXPECT_EQ(q1, qMultq);
q1 /= q2;
EXPECT_EQ(q1, qOrigin);
q1 *= scalar;
EXPECT_EQ(q1, qMults);
q1 /= scalar;
EXPECT_EQ(q1, qOrigin);
EXPECT_NO_THROW(q1[0]);
EXPECT_NO_THROW(q1.at(0));
EXPECT_ANY_THROW(q1[4]);
EXPECT_ANY_THROW(q1.at(4));
}
TEST_F(QuatTest, quatAttrs)
{
double angleQ1 = 2 * acos(1.0 / sqrt(30));
Vec3d axis1{0.3713906763541037, 0.557086014, 0.742781352};
Vec<double, 3> q1axis1 = q1.getAxis();
EXPECT_EQ(angleQ1, q1.getAngle());
EXPECT_EQ(angleQ1, q1Unit.getAngle());
EXPECT_EQ(angleQ1, q1Unit.getAngle(assumeUnit));
EXPECT_EQ(0, qIdentity.getAngle());
EXPECT_ANY_THROW(qNull.getAxis());
EXPECT_NEAR(axis1[0], q1axis1[0], 1e-6);
EXPECT_NEAR(axis1[1], q1axis1[1], 1e-6);
EXPECT_NEAR(axis1[2], q1axis1[2], 1e-6);
EXPECT_NEAR(q3Norm2.norm(), qNorm2, 1e-6);
EXPECT_EQ(q3Norm2.getAngle(), angle);
EXPECT_NEAR(axis1[0], axis1[0], 1e-6);
EXPECT_NEAR(axis1[1], axis1[1], 1e-6);
EXPECT_NEAR(axis1[2], axis1[2], 1e-6);
}
TEST_F(QuatTest, interpolation)
{
Quatd qNoRot = Quatd::createFromAngleAxis(0, axis);
Quatd qLerpInter(1.0 / 2, sqrt(3) / 6, sqrt(3) / 6, sqrt(3) / 6);
EXPECT_EQ(Quatd::lerp(qNoRot, q3, 0), qNoRot);
EXPECT_EQ(Quatd::lerp(qNoRot, q3, 1), q3);
EXPECT_EQ(Quatd::lerp(qNoRot, q3, 0.5), qLerpInter);
Quatd q3NrNn2 = qNoRot * qNorm2;
EXPECT_EQ(Quatd::nlerp(q3NrNn2, q3Norm2, 0), qNoRot);
EXPECT_EQ(Quatd::nlerp(q3NrNn2, q3Norm2, 1), q3);
EXPECT_EQ(Quatd::nlerp(q3NrNn2, q3Norm2, 0.5), qLerpInter.normalize());
EXPECT_EQ(Quatd::nlerp(qNoRot, q3, 0, assumeUnit), qNoRot);
EXPECT_EQ(Quatd::nlerp(qNoRot, q3, 1, assumeUnit), q3);
EXPECT_EQ(Quatd::nlerp(qNoRot, q3, 0.5, assumeUnit), qLerpInter.normalize());
Quatd q3Minus(-q3);
EXPECT_EQ(Quatd::nlerp(qNoRot, q3, 0.4), -Quatd::nlerp(qNoRot, q3Minus, 0.4));
EXPECT_EQ(Quatd::slerp(qNoRot, q3, 0, assumeUnit), qNoRot);
EXPECT_EQ(Quatd::slerp(qNoRot, q3, 1, assumeUnit), q3);
EXPECT_EQ(Quatd::slerp(qNoRot, q3, 0.5, assumeUnit), -Quatd::nlerp(qNoRot, -q3, 0.5, assumeUnit));
EXPECT_EQ(Quatd::slerp(qNoRot, q1, 0.5), Quatd(0.76895194, 0.2374325, 0.35614876, 0.47486501));
EXPECT_EQ(Quatd::slerp(-qNoRot, q1, 0.5), Quatd(0.76895194, 0.2374325, 0.35614876, 0.47486501));
EXPECT_EQ(Quatd::slerp(qNoRot, -q1, 0.5), -Quatd::slerp(-qNoRot, q1, 0.5));
Quat<double> tr1 = Quatd::createFromAngleAxis(0, axis);
Quat<double> tr2 = Quatd::createFromAngleAxis(angle / 2, axis);
Quat<double> tr3 = Quatd::createFromAngleAxis(angle, axis);
Quat<double> tr4 = Quatd::createFromAngleAxis(angle, Vec3d{-1/sqrt(2),0,1/(sqrt(2))});
EXPECT_ANY_THROW(Quatd::spline(qNull, tr1, tr2, tr3, 0));
EXPECT_EQ(Quatd::spline(tr1, tr2, tr3, tr4, 0), tr2);
EXPECT_EQ(Quatd::spline(tr1, tr2, tr3, tr4, 1), tr3);
EXPECT_EQ(Quatd::spline(tr1, tr2, tr3, tr4, 0.6, assumeUnit), Quatd::spline(tr1, tr2, tr3, tr4, 0.6));
EXPECT_EQ(Quatd::spline(tr1, tr2, tr3, tr3, 0.5), Quatd::spline(tr1, -tr2, tr3, tr3, 0.5));
EXPECT_EQ(Quatd::spline(tr1, tr2, tr3, tr3, 0.5), -Quatd::spline(-tr1, -tr2, -tr3, tr3, 0.5));
EXPECT_EQ(Quatd::spline(tr1, tr2, tr3, tr3, 0.5), Quatd(0.336889853392, 0.543600719487, 0.543600719487, 0.543600719487));
}
static const Quatd qEuler[24] = {
Quatd(0.7233214, 0.3919013, 0.2005605, 0.5319728), //INT_XYZ
Quatd(0.8223654, 0.0222635, 0.3604221, 0.4396766), //INT_XZY
Quatd(0.822365, 0.439677, 0.0222635, 0.360422), //INT_YXZ
Quatd(0.723321, 0.531973, 0.391901, 0.20056), //INT_YZX
Quatd(0.723321, 0.20056, 0.531973, 0.391901), //INT_ZXY
Quatd(0.822365, 0.360422, 0.439677, 0.0222635), //INT_ZYX
Quatd(0.653285, 0.65328, 0.369641, -0.0990435), //INT_XYX
Quatd(0.653285, 0.65328, 0.0990435, 0.369641), //INT_XZX
Quatd(0.653285, 0.369641, 0.65328, 0.0990435), //INT_YXY
Quatd(0.653285, -0.0990435, 0.65328, 0.369641), //INT_YZY
Quatd(0.653285, 0.369641, -0.0990435, 0.65328), //INT_ZXZ
Quatd(0.653285, 0.0990435, 0.369641, 0.65328), //INT_ZYZ
Quatd(0.822365, 0.0222635, 0.439677, 0.360422), //EXT_XYZ
Quatd(0.723321, 0.391901, 0.531973, 0.20056), //EXT_XZY
Quatd(0.723321, 0.20056, 0.391901, 0.531973), //EXT_YXZ
Quatd(0.822365, 0.360422, 0.0222635, 0.439677), //EXT_YZX
Quatd(0.822365, 0.439677, 0.360422, 0.0222635), //EXT_ZXY
Quatd(0.723321, 0.531973, 0.20056, 0.391901), //EXT_ZYX
Quatd(0.653285, 0.65328, 0.369641, 0.0990435), //EXT_XYX
Quatd(0.653285, 0.65328, -0.0990435, 0.369641), //EXT_XZX
Quatd(0.653285, 0.369641, 0.65328, -0.0990435), //EXT_YXY
Quatd(0.653285, 0.0990435, 0.65328, 0.369641), //EXT_YZY
Quatd(0.653285, 0.369641, 0.0990435, 0.65328), //EXT_ZXZ
Quatd(0.653285, -0.0990435, 0.369641, 0.65328) //EXT_ZYZ
};
TEST_F(QuatTest, EulerAngles)
{
Vec3d test_angle = {0.523598, 0.78539, 1.04719};
for (QuatEnum::EulerAnglesType i = QuatEnum::EulerAnglesType::INT_XYZ; i <= QuatEnum::EulerAnglesType::EXT_ZYZ; i = (QuatEnum::EulerAnglesType)(i + 1))
{
SCOPED_TRACE(cv::format("EulerAnglesType=%d", i));
Quatd q = Quatd::createFromEulerAngles(test_angle, i);
EXPECT_EQ(q, qEuler[i]);
Vec3d Euler_Angles = q.toEulerAngles(i);
EXPECT_NEAR(Euler_Angles[0], test_angle[0], 1e-6);
EXPECT_NEAR(Euler_Angles[1], test_angle[1], 1e-6);
EXPECT_NEAR(Euler_Angles[2], test_angle[2], 1e-6);
}
Quatd qEuler0 = {0, 0, 0, 0};
EXPECT_ANY_THROW(qEuler0.toEulerAngles(QuatEnum::INT_XYZ));
Quatd qEulerLock1 = {0.5612665, 0.43042, 0.5607083, 0.4304935};
Vec3d test_angle_lock1 = {1.3089878, CV_PI * 0.5, 0};
Vec3d Euler_Angles_solute_1 = qEulerLock1.toEulerAngles(QuatEnum::INT_XYZ);
EXPECT_NEAR(Euler_Angles_solute_1[0], test_angle_lock1[0], 1e-6);
EXPECT_NEAR(Euler_Angles_solute_1[1], test_angle_lock1[1], 1e-6);
EXPECT_NEAR(Euler_Angles_solute_1[2], test_angle_lock1[2], 1e-6);
Quatd qEulerLock2 = {0.7010574, 0.0922963, 0.7010573, -0.0922961};
Vec3d test_angle_lock2 = {-0.2618, CV_PI * 0.5, 0};
Vec3d Euler_Angles_solute_2 = qEulerLock2.toEulerAngles(QuatEnum::INT_ZYX);
EXPECT_NEAR(Euler_Angles_solute_2[0], test_angle_lock2[0], 1e-6);
EXPECT_NEAR(Euler_Angles_solute_2[1], test_angle_lock2[1], 1e-6);
EXPECT_NEAR(Euler_Angles_solute_2[2], test_angle_lock2[2], 1e-6);
Vec3d test_angle6 = {CV_PI * 0.25, CV_PI * 0.5, CV_PI * 0.25};
Vec3d test_angle7 = {CV_PI * 0.5, CV_PI * 0.5, 0};
EXPECT_EQ(Quatd::createFromEulerAngles(test_angle6, QuatEnum::INT_ZXY), Quatd::createFromEulerAngles(test_angle7, QuatEnum::INT_ZXY));
}
class DualQuatTest: public ::testing::Test
{
protected:
double scalar = 2.5;
double angle = CV_PI;
Vec<double, 3> axis{1, 1, 1};
Vec<double, 3> unAxis{0, 0, 0};
Vec<double, 3> unitAxis{1.0 / sqrt(3), 1.0 / sqrt(3), 1.0 / sqrt(3)};
DualQuatd dq1{1, 2, 3, 4, 5, 6, 7, 8};
Vec3d trans{0, 0, 5};
double rotation_angle = 2.0 / 3 * CV_PI;
DualQuatd dq2 = DualQuatd::createFromAngleAxisTrans(rotation_angle, axis, trans);
DualQuatd dqAllOne{1, 1, 1, 1, 1, 1, 1, 1};
DualQuatd dqAllZero{0, 0, 0, 0, 0, 0, 0, 0};
DualQuatd dqIdentity{1, 0, 0, 0, 0, 0, 0, 0};
DualQuatd dqTrans{1, 0, 0, 0, 0, 2, 3, 4};
DualQuatd dqOnlyTrans{0, 0, 0, 0, 0, 2, 3, 4};
DualQuatd dualNumber1{-3,0,0,0,-31.1,0,0,0};
DualQuatd dualNumber2{4,0,0,0,5.1,0,0,0};
};
TEST_F(DualQuatTest, constructor)
{
EXPECT_EQ(dq1, DualQuatd::createFromQuat(Quatd(1, 2, 3, 4), Quatd(5, 6, 7, 8)));
EXPECT_EQ(dq2 * dq2.conjugate(), dqIdentity);
EXPECT_NEAR(dq2.getRotation(QUAT_ASSUME_UNIT).norm(), 1, 1e-6);
EXPECT_NEAR(dq2.getRealPart().dot(dq2.getDualPart()), 0, 1e-6);
EXPECT_MAT_NEAR(dq2.getTranslation(QUAT_ASSUME_UNIT), trans, 1e-6);
DualQuatd q_conj = DualQuatd::createFromQuat(dq2.getRealPart().conjugate(), -dq2.getDualPart().conjugate());
DualQuatd q{1,0,0,0,0,3,0,0};
EXPECT_EQ(dq2 * q * q_conj, DualQuatd(1,0,0,0,0,0,3,5));
Matx44d R1 = dq2.toMat();
DualQuatd dq3 = DualQuatd::createFromMat(R1);
EXPECT_EQ(dq3, dq2);
axis = axis / std::sqrt(axis.dot(axis));
Vec3d moment = 1.0 / 2 * (trans.cross(axis) + axis.cross(trans.cross(axis)) *
std::cos(rotation_angle / 2) / std::sin(rotation_angle / 2));
double d = trans.dot(axis);
DualQuatd dq4 = DualQuatd::createFromPitch(rotation_angle, d, axis, moment);
EXPECT_EQ(dq4, dq3);
EXPECT_EQ(dq2, DualQuatd::createFromAffine3(dq2.toAffine3()));
EXPECT_EQ(dq1.normalize(), DualQuatd::createFromAffine3(dq1.toAffine3()));
}
TEST_F(DualQuatTest, test_operator)
{
DualQuatd dq_origin{1, 2, 3, 4, 5, 6, 7, 8};
EXPECT_EQ(dq1 - dqAllOne, DualQuatd(0, 1, 2, 3, 4, 5, 6, 7));
EXPECT_EQ(-dq1, DualQuatd(-1, -2, -3, -4, -5, -6, -7, -8));
EXPECT_EQ(dq1 + dqAllOne, DualQuatd(2, 3, 4, 5, 6, 7, 8, 9));
EXPECT_EQ(dq1 / dq1, dqIdentity);
DualQuatd dq3{-4, 1, 3, 2, -15.5, 0, -3, 8.5};
EXPECT_EQ(dq1 * dq2, dq3);
EXPECT_EQ(dq3 / dq2, dq1);
DualQuatd dq12{2, 4, 6, 8, 10, 12, 14, 16};
EXPECT_EQ(dq1 * 2.0, dq12);
EXPECT_EQ(2.0 * dq1, dq12);
EXPECT_EQ(dq1 - 1.0, DualQuatd(0, 2, 3, 4, 5, 6, 7, 8));
EXPECT_EQ(1.0 - dq1, DualQuatd(0, -2, -3, -4, -5, -6, -7, -8));
EXPECT_EQ(dq1 + 1.0, DualQuatd(2, 2, 3, 4, 5, 6, 7, 8));
EXPECT_EQ(1.0 + dq1, DualQuatd(2, 2, 3, 4, 5, 6, 7, 8));
dq1 += dq2;
EXPECT_EQ(dq1, dq_origin + dq2);
dq1 -= dq2;
EXPECT_EQ(dq1, dq_origin);
dq1 *= dq2;
EXPECT_EQ(dq1, dq_origin * dq2);
dq1 /= dq2;
EXPECT_EQ(dq1, dq_origin);
}
TEST_F(DualQuatTest, basic_ops)
{
EXPECT_EQ(dq1.getRealPart(), Quatd(1, 2, 3, 4));
EXPECT_EQ(dq1.getDualPart(), Quatd(5, 6, 7, 8));
EXPECT_EQ((dq1 * dq2).conjugate(), conjugate(dq1 * dq2));
EXPECT_EQ(dq1.conjugate(), DualQuatd::createFromQuat(dq1.getRealPart().conjugate(), dq1.getDualPart().conjugate()));
EXPECT_EQ((dq2 * dq1).conjugate(), dq1.conjugate() * dq2.conjugate());
EXPECT_EQ(dq1.conjugate() * dq1, dq1.norm() * dq1.norm());
EXPECT_EQ(dq1.conjugate() * dq1, dq1.norm().power(2.0));
EXPECT_EQ(dualNumber2.power(2.0), DualQuatd(16, 0, 0, 0, 40.8, 0, 0, 0));
EXPECT_EQ(dq1.power(2.0), (2.0 * dq1.log()).exp());
EXPECT_EQ(power(dq1, 2.0), (exp(2.0 * log(dq1))));
EXPECT_EQ(dq2.power(3.0 / 2, QUAT_ASSUME_UNIT).power(4.0 / 3, QUAT_ASSUME_UNIT), dq2 * dq2);
EXPECT_EQ(dq2.power(-0.5).power(2.0), dq2.inv());
EXPECT_EQ(power(dq1, dq2), exp(dq2 * log(dq1)));
EXPECT_EQ(power(dq2, dq1, QUAT_ASSUME_UNIT), exp(dq1 * log(dq2)));
EXPECT_EQ((dq2.norm() * dq1).power(2.0), dq1.power(2.0) * dq2.norm().power(2.0));
DualQuatd q1norm = dq1.normalize();
EXPECT_EQ(dq2.norm(), dqIdentity);
EXPECT_NEAR(q1norm.getRealPart().norm(), 1, 1e-6);
EXPECT_NEAR(q1norm.getRealPart().dot(q1norm.getDualPart()), 0, 1e-6);
EXPECT_NEAR(dq1.getRotation().norm(), 1, 1e-6);
EXPECT_NEAR(dq2.getRotation(QUAT_ASSUME_UNIT).norm(), 1, 1e-6);
EXPECT_NEAR(dq2.getRotation(QUAT_ASSUME_UNIT).norm(), 1, 1e-6);
EXPECT_MAT_NEAR(Mat(dq2.getTranslation()), Mat(trans), 1e-6);
EXPECT_MAT_NEAR(Mat(q1norm.getTranslation(QUAT_ASSUME_UNIT)), Mat(dq1.getTranslation()), 1e-6);
EXPECT_EQ(dq2.getTranslation(), dq2.getTranslation(QUAT_ASSUME_UNIT));
EXPECT_EQ(dq1.inv() * dq1, dqIdentity);
EXPECT_EQ(inv(dq1) * dq1, dqIdentity);
EXPECT_EQ(dq2.inv(QUAT_ASSUME_UNIT) * dq2, dqIdentity);
EXPECT_EQ(inv(dq2, QUAT_ASSUME_UNIT) * dq2, dqIdentity);
EXPECT_EQ(dq2.inv(), dq2.conjugate());
EXPECT_EQ(dqIdentity.inv(), dqIdentity);
EXPECT_ANY_THROW(dqAllZero.inv());
EXPECT_EQ(dqAllZero.exp(), dqIdentity);
EXPECT_EQ(exp(dqAllZero), dqIdentity);
EXPECT_ANY_THROW(log(dqAllZero));
EXPECT_EQ(log(dqIdentity), dqAllZero);
EXPECT_EQ(dqIdentity.log(), dqAllZero);
EXPECT_EQ(dualNumber1 * dualNumber2, dualNumber2 * dualNumber1);
EXPECT_EQ(dualNumber2.exp().log(), dualNumber2);
EXPECT_EQ(dq2.log(QUAT_ASSUME_UNIT).exp(), dq2);
EXPECT_EQ(exp(log(dq2, QUAT_ASSUME_UNIT)), dq2);
EXPECT_EQ(dqIdentity.log(QUAT_ASSUME_UNIT).exp(), dqIdentity);
EXPECT_EQ(dq1.log().exp(), dq1);
EXPECT_EQ(dqTrans.log().exp(), dqTrans);
EXPECT_MAT_NEAR(q1norm.toMat(QUAT_ASSUME_UNIT), dq1.toMat(), 1e-6);
Matx44d R1 = dq2.toMat();
Mat point = (Mat_<double>(4, 1) << 3, 0, 0, 1);
Mat new_point = R1 * point;
Mat after = (Mat_<double>(4, 1) << 0, 3, 5 ,1);
EXPECT_MAT_NEAR(new_point, after, 1e-6);
Vec<double, 8> vec = dq1.toVec();
EXPECT_EQ(DualQuatd(vec), dq1);
Affine3d afd = q1norm.toAffine3(QUAT_ASSUME_UNIT);
EXPECT_MAT_NEAR(Mat(afd.translation()), Mat(q1norm.getTranslation(QUAT_ASSUME_UNIT)), 1e-6);
Affine3d dq1_afd = dq1.toAffine3();
EXPECT_MAT_NEAR(dq1_afd.matrix, afd.matrix, 1e-6);
EXPECT_ANY_THROW(dqAllZero.toAffine3());
}
TEST_F(DualQuatTest, interpolation)
{
DualQuatd dq = DualQuatd::createFromAngleAxisTrans(8 * CV_PI / 5, Vec3d{0, 0, 1}, Vec3d{0, 0, 10});
EXPECT_EQ(DualQuatd::sclerp(dqIdentity, dq, 0.5), DualQuatd::sclerp(-dqIdentity, dq, 0.5, false));
EXPECT_EQ(DualQuatd::sclerp(dqIdentity, dq, 0), -dqIdentity);
EXPECT_EQ(DualQuatd::sclerp(dqIdentity, dq2, 1), dq2);
EXPECT_EQ(DualQuatd::sclerp(dqIdentity, dq2, 0.4, false, QUAT_ASSUME_UNIT), DualQuatd(0.91354546, 0.23482951, 0.23482951, 0.23482951, -0.23482951, -0.47824988, 0.69589767, 0.69589767));
EXPECT_EQ(DualQuatd::dqblend(dqIdentity, dq1.normalize(), 0.2, QUAT_ASSUME_UNIT), DualQuatd::dqblend(dqIdentity, -dq1, 0.2));
EXPECT_EQ(DualQuatd::dqblend(dqIdentity, dq2, 0.4), DualQuatd(0.91766294, 0.22941573, 0.22941573, 0.22941573, -0.21130397, -0.48298049, 0.66409818, 0.66409818));
DualQuatd gdb = DualQuatd::gdqblend(Vec<DualQuatd, 3>{dqIdentity, dq, dq2}, Vec3d{0.4, 0, 0.6}, QUAT_ASSUME_UNIT);
EXPECT_EQ(gdb, DualQuatd::dqblend(dqIdentity, dq2, 0.6));
EXPECT_ANY_THROW(DualQuatd::gdqblend(Vec<DualQuatd, 1>{dq2}, Vec2d{0.5, 0.5}));
Mat gdqb_d(1, 2, CV_64FC(7));
gdqb_d.at<Vec<double, 7>>(0, 0) = Vec<double, 7>{1,2,3,4,5,6,7};
gdqb_d.at<Vec<double, 7>>(0, 1) = Vec<double, 7>{1,2,3,4,5,6,7};
EXPECT_ANY_THROW(DualQuatd::gdqblend(gdqb_d, Vec2d{0.5, 0.5}));
Mat gdqb_f(1, 2, CV_32FC(8));
gdqb_f.at<Vec<float, 8>>(0, 0) = Vec<float, 8>{1.f,2.f,3.f,4.f,5.f,6.f,7.f,8.f};
gdqb_f.at<Vec<float, 8>>(0, 1) = Vec<float, 8>{1.f,2.f,3.f,4.f,5.f,6.f,7.f,8.f};
EXPECT_ANY_THROW(DualQuatd::gdqblend(gdqb_f, Vec2d{0.5, 0.5}));
EXPECT_ANY_THROW(DualQuatd::gdqblend(Vec<DualQuatd, 3>{dqIdentity, dq, dq2}, Vec3f{0.4f, 0.f, 0.6f}, QUAT_ASSUME_UNIT));
EXPECT_EQ(gdb, DualQuatd::gdqblend(Vec<DualQuatd, 3>{dqIdentity, dq * dualNumber1, -dq2}, Vec3d{0.4, 0, 0.6}));
}
}} // namespace

View File

@ -0,0 +1,423 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
namespace opencv_test { namespace {
class Core_RandTest : public cvtest::BaseTest
{
public:
Core_RandTest();
protected:
void run(int);
bool check_pdf(const Mat& hist, double scale, int dist_type,
double& refval, double& realval);
};
Core_RandTest::Core_RandTest()
{
}
static double chi2_p95(int n)
{
static float chi2_tab95[] = {
3.841f, 5.991f, 7.815f, 9.488f, 11.07f, 12.59f, 14.07f, 15.51f,
16.92f, 18.31f, 19.68f, 21.03f, 21.03f, 22.36f, 23.69f, 25.00f,
26.30f, 27.59f, 28.87f, 30.14f, 31.41f, 32.67f, 33.92f, 35.17f,
36.42f, 37.65f, 38.89f, 40.11f, 41.34f, 42.56f, 43.77f };
static const double xp = 1.64;
CV_Assert(n >= 1);
if( n <= 30 )
return chi2_tab95[n-1];
return n + sqrt((double)2*n)*xp + 0.6666666666666*(xp*xp - 1);
}
bool Core_RandTest::check_pdf(const Mat& hist, double scale,
int dist_type, double& refval, double& realval)
{
Mat hist0(hist.size(), CV_32F);
const int* H = hist.ptr<int>();
float* H0 = hist0.ptr<float>();
int i, hsz = hist.cols;
double sum = 0;
for( i = 0; i < hsz; i++ )
sum += H[i];
CV_Assert( fabs(1./sum - scale) < FLT_EPSILON );
if( dist_type == CV_RAND_UNI )
{
float scale0 = (float)(1./hsz);
for( i = 0; i < hsz; i++ )
H0[i] = scale0;
}
else
{
double sum2 = 0, r = (hsz-1.)/2;
double alpha = 2*sqrt(2.)/r, beta = -alpha*r;
for( i = 0; i < hsz; i++ )
{
double x = i*alpha + beta;
H0[i] = (float)exp(-x*x);
sum2 += H0[i];
}
sum2 = 1./sum2;
for( i = 0; i < hsz; i++ )
H0[i] = (float)(H0[i]*sum2);
}
double chi2 = 0;
for( i = 0; i < hsz; i++ )
{
double a = H0[i];
double b = H[i]*scale;
if( a > DBL_EPSILON )
chi2 += (a - b)*(a - b)/(a + b);
}
realval = chi2;
double chi2_pval = chi2_p95(hsz - 1 - (dist_type == CV_RAND_NORMAL ? 2 : 0));
refval = chi2_pval*0.01;
return realval <= refval;
}
void Core_RandTest::run( int )
{
static int _ranges[][2] =
{{ 0, 256 }, { -128, 128 }, { 0, 65536 }, { -32768, 32768 },
{ -1000000, 1000000 }, { -1000, 1000 }, { -1000, 1000 }};
const int MAX_SDIM = 10;
const int N = 2000000;
const int maxSlice = 1000;
const int MAX_HIST_SIZE = 1000;
int progress = 0;
RNG& rng = ts->get_rng();
RNG tested_rng = theRNG();
test_case_count = 200;
for( int idx = 0; idx < test_case_count; idx++ )
{
progress = update_progress( progress, idx, test_case_count, 0 );
ts->update_context( this, idx, false );
int depth = cvtest::randInt(rng) % (CV_64F+1);
int c, cn = (cvtest::randInt(rng) % 4) + 1;
int type = CV_MAKETYPE(depth, cn);
int dist_type = cvtest::randInt(rng) % (CV_RAND_NORMAL+1);
int i, k, SZ = N/cn;
Scalar A, B;
double eps = 1.e-4;
if (depth == CV_64F)
eps = 1.e-7;
bool do_sphere_test = dist_type == CV_RAND_UNI;
Mat arr[2], hist[4];
int W[] = {0,0,0,0};
arr[0].create(1, SZ, type);
arr[1].create(1, SZ, type);
bool fast_algo = dist_type == CV_RAND_UNI && depth < CV_32F;
for( c = 0; c < cn; c++ )
{
int a, b, hsz;
if( dist_type == CV_RAND_UNI )
{
a = (int)(cvtest::randInt(rng) % (_ranges[depth][1] -
_ranges[depth][0])) + _ranges[depth][0];
do
{
b = (int)(cvtest::randInt(rng) % (_ranges[depth][1] -
_ranges[depth][0])) + _ranges[depth][0];
}
while( abs(a-b) <= 1 );
if( a > b )
std::swap(a, b);
unsigned r = (unsigned)(b - a);
fast_algo = fast_algo && r <= 256 && (r & (r-1)) == 0;
hsz = min((unsigned)(b - a), (unsigned)MAX_HIST_SIZE);
do_sphere_test = do_sphere_test && b - a >= 100;
}
else
{
int vrange = _ranges[depth][1] - _ranges[depth][0];
int meanrange = vrange/16;
int mindiv = MAX(vrange/20, 5);
int maxdiv = MIN(vrange/8, 10000);
a = cvtest::randInt(rng) % meanrange - meanrange/2 +
(_ranges[depth][0] + _ranges[depth][1])/2;
b = cvtest::randInt(rng) % (maxdiv - mindiv) + mindiv;
hsz = min((unsigned)b*9, (unsigned)MAX_HIST_SIZE);
}
A[c] = a;
B[c] = b;
hist[c].create(1, hsz, CV_32S);
}
cv::RNG saved_rng = tested_rng;
int maxk = fast_algo ? 0 : 1;
for( k = 0; k <= maxk; k++ )
{
tested_rng = saved_rng;
int sz = 0, dsz = 0, slice;
for( slice = 0; slice < maxSlice && sz < SZ; slice++, sz += dsz )
{
dsz = slice+1 < maxSlice ? (int)(cvtest::randInt(rng) % (SZ - sz) + 1) : SZ - sz;
Mat aslice = arr[k].colRange(sz, sz + dsz);
tested_rng.fill(aslice, dist_type, A, B);
}
}
if( maxk >= 1 && cvtest::norm(arr[0], arr[1], NORM_INF) > eps)
{
ts->printf( cvtest::TS::LOG, "RNG output depends on the array lengths (some generated numbers get lost?)" );
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
return;
}
for( c = 0; c < cn; c++ )
{
const uchar* data = arr[0].ptr();
int* H = hist[c].ptr<int>();
int HSZ = hist[c].cols;
double minVal = dist_type == CV_RAND_UNI ? A[c] : A[c] - B[c]*4;
double maxVal = dist_type == CV_RAND_UNI ? B[c] : A[c] + B[c]*4;
double scale = HSZ/(maxVal - minVal);
double delta = -minVal*scale;
hist[c] = Scalar::all(0);
for( i = c; i < SZ*cn; i += cn )
{
double val = depth == CV_8U ? ((const uchar*)data)[i] :
depth == CV_8S ? ((const schar*)data)[i] :
depth == CV_16U ? ((const ushort*)data)[i] :
depth == CV_16S ? ((const short*)data)[i] :
depth == CV_32S ? ((const int*)data)[i] :
depth == CV_32F ? ((const float*)data)[i] :
((const double*)data)[i];
int ival = cvFloor(val*scale + delta);
if( (unsigned)ival < (unsigned)HSZ )
{
H[ival]++;
W[c]++;
}
else if( dist_type == CV_RAND_UNI )
{
if( (minVal <= val && val < maxVal) || (depth >= CV_32F && val == maxVal) )
{
H[ival < 0 ? 0 : HSZ-1]++;
W[c]++;
}
else
{
putchar('^');
}
}
}
if( dist_type == CV_RAND_UNI && W[c] != SZ )
{
ts->printf( cvtest::TS::LOG, "Uniform RNG gave values out of the range [%g,%g) on channel %d/%d\n",
A[c], B[c], c, cn);
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
return;
}
if( dist_type == CV_RAND_NORMAL && W[c] < SZ*.90)
{
ts->printf( cvtest::TS::LOG, "Normal RNG gave too many values out of the range (%g+4*%g,%g+4*%g) on channel %d/%d\n",
A[c], B[c], A[c], B[c], c, cn);
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
return;
}
double refval = 0, realval = 0;
if( !check_pdf(hist[c], 1./W[c], dist_type, refval, realval) )
{
ts->printf( cvtest::TS::LOG, "RNG failed Chi-square test "
"(got %g vs probable maximum %g) on channel %d/%d\n",
realval, refval, c, cn);
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
return;
}
}
// Monte-Carlo test. Compute volume of SDIM-dimensional sphere
// inscribed in [-1,1]^SDIM cube.
if( do_sphere_test )
{
int SDIM = cvtest::randInt(rng) % (MAX_SDIM-1) + 2;
int N0 = (SZ*cn/SDIM), n = 0;
double r2 = 0;
const uchar* data = arr[0].ptr();
double scale[4], delta[4];
for( c = 0; c < cn; c++ )
{
scale[c] = 2./(B[c] - A[c]);
delta[c] = -A[c]*scale[c] - 1;
}
for( i = k = c = 0; i <= SZ*cn - SDIM; i++, k++, c++ )
{
double val = depth == CV_8U ? ((const uchar*)data)[i] :
depth == CV_8S ? ((const schar*)data)[i] :
depth == CV_16U ? ((const ushort*)data)[i] :
depth == CV_16S ? ((const short*)data)[i] :
depth == CV_32S ? ((const int*)data)[i] :
depth == CV_32F ? ((const float*)data)[i] : ((const double*)data)[i];
c &= c < cn ? -1 : 0;
val = val*scale[c] + delta[c];
r2 += val*val;
if( k == SDIM-1 )
{
n += r2 <= 1;
r2 = 0;
k = -1;
}
}
double V = ((double)n/N0)*(1 << SDIM);
// the theoretically computed volume
int sdim = SDIM % 2;
double V0 = sdim + 1;
for( sdim += 2; sdim <= SDIM; sdim += 2 )
V0 *= 2*CV_PI/sdim;
if( fabs(V - V0) > 0.3*fabs(V0) )
{
ts->printf( cvtest::TS::LOG, "RNG failed %d-dim sphere volume test (got %g instead of %g)\n",
SDIM, V, V0);
ts->printf( cvtest::TS::LOG, "depth = %d, N0 = %d\n", depth, N0);
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
return;
}
}
}
}
TEST(Core_Rand, quality) { Core_RandTest test; test.safe_run(); }
class Core_RandRangeTest : public cvtest::BaseTest
{
public:
Core_RandRangeTest() {}
~Core_RandRangeTest() {}
protected:
void run(int)
{
Mat a(Size(1280, 720), CV_8U, Scalar(20));
Mat af(Size(1280, 720), CV_32F, Scalar(20));
theRNG().fill(a, RNG::UNIFORM, -DBL_MAX, DBL_MAX);
theRNG().fill(af, RNG::UNIFORM, -DBL_MAX, DBL_MAX);
int n0 = 0, n255 = 0, nx = 0;
int nfmin = 0, nfmax = 0, nfx = 0;
for( int i = 0; i < a.rows; i++ )
for( int j = 0; j < a.cols; j++ )
{
int v = a.at<uchar>(i,j);
double vf = af.at<float>(i,j);
if( v == 0 ) n0++;
else if( v == 255 ) n255++;
else nx++;
if( vf < FLT_MAX*-0.999f ) nfmin++;
else if( vf > FLT_MAX*0.999f ) nfmax++;
else nfx++;
}
CV_Assert( n0 > nx*2 && n255 > nx*2 );
CV_Assert( nfmin > nfx*2 && nfmax > nfx*2 );
}
};
TEST(Core_Rand, range) { Core_RandRangeTest test; test.safe_run(); }
TEST(Core_RNG_MT19937, regression)
{
cv::RNG_MT19937 rng;
int actual[61] = {0, };
const size_t length = (sizeof(actual) / sizeof(actual[0]));
for (int i = 0; i < 10000; ++i )
{
actual[(unsigned)(rng.next() ^ i) % length]++;
}
int expected[length] = {
177, 158, 180, 177, 160, 179, 143, 162,
177, 144, 170, 174, 165, 168, 168, 156,
177, 157, 159, 169, 177, 182, 166, 154,
144, 180, 168, 152, 170, 187, 160, 145,
139, 164, 157, 179, 148, 183, 159, 160,
196, 184, 149, 142, 162, 148, 163, 152,
168, 173, 160, 181, 172, 181, 155, 153,
158, 171, 138, 150, 150 };
for (size_t i = 0; i < length; ++i)
{
ASSERT_EQ(expected[i], actual[i]);
}
}
TEST(Core_Rand, Regression_Stack_Corruption)
{
int bufsz = 128; //enough for 14 doubles
AutoBuffer<uchar> buffer(bufsz);
size_t offset = 0;
cv::Mat_<cv::Point2d> x(2, 3, (cv::Point2d*)(buffer.data()+offset));
offset += x.total()*x.elemSize();
double& param1 = *(double*)(buffer.data()+offset);
offset += sizeof(double);
double& param2 = *(double*)(buffer.data()+offset);
param1 = -9; param2 = 2;
cv::theRNG().fill(x, cv::RNG::NORMAL, param1, param2);
ASSERT_EQ(param1, -9);
ASSERT_EQ(param2, 2);
}
class RandRowFillParallelLoopBody : public cv::ParallelLoopBody
{
public:
RandRowFillParallelLoopBody(Mat& dst) : dst_(dst) {}
~RandRowFillParallelLoopBody() {}
void operator()(const cv::Range& r) const
{
cv::RNG rng = cv::theRNG(); // copy state
for (int y = r.start; y < r.end; y++)
{
cv::theRNG() = cv::RNG(rng.state + y); // seed is based on processed row
cv::randu(dst_.row(y), Scalar(-100), Scalar(100));
}
// theRNG() state is changed here (but state collision has low probability, so we don't check this)
}
protected:
Mat& dst_;
};
TEST(Core_Rand, parallel_for_stable_results)
{
cv::RNG rng = cv::theRNG(); // save rng state
Mat dst1(1000, 100, CV_8SC1);
parallel_for_(cv::Range(0, dst1.rows), RandRowFillParallelLoopBody(dst1));
cv::theRNG() = rng; // restore rng state
Mat dst2(1000, 100, CV_8SC1);
parallel_for_(cv::Range(0, dst2.rows), RandRowFillParallelLoopBody(dst2));
ASSERT_EQ(0, countNonZero(dst1 != dst2));
}
}} // namespace

View File

@ -0,0 +1,108 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// Intel License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of Intel Corporation may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "test_precomp.hpp"
namespace opencv_test { namespace {
class Core_RotatedRectConstructorTest : public cvtest::BaseTest
{
public:
Core_RotatedRectConstructorTest();
protected:
int prepare_test_case( int );
void run_func();
int validate_test_results( int );
float MAX_COORD_VAL;
Point2f a, b, c;
RotatedRect rec;
};
Core_RotatedRectConstructorTest::Core_RotatedRectConstructorTest()
{
test_case_count = 100;
MAX_COORD_VAL = 1000.0f;
}
int Core_RotatedRectConstructorTest::prepare_test_case( int test_case_idx )
{
cvtest::BaseTest::prepare_test_case( test_case_idx );
RNG& rng = ts->get_rng();
a = Point2f( rng.uniform(-MAX_COORD_VAL, MAX_COORD_VAL), rng.uniform(-MAX_COORD_VAL, MAX_COORD_VAL) );
do
{
b = Point2f( rng.uniform(-MAX_COORD_VAL, MAX_COORD_VAL), rng.uniform(-MAX_COORD_VAL, MAX_COORD_VAL) );
}
while( cv::norm(a - b) <= FLT_EPSILON );
Vec2f along(a - b);
Vec2f perp = Vec2f(-along[1], along[0]);
double d = (double) rng.uniform(1.0f, 5.0f);
if( cvtest::randInt(rng) % 2 == 0 ) d = -d;
c = Point2f( (float) ((double) b.x + d * perp[0]), (float) ((double) b.y + d * perp[1]) );
return 1;
}
void Core_RotatedRectConstructorTest::run_func()
{
rec = RotatedRect(a, b, c);
}
int Core_RotatedRectConstructorTest::validate_test_results( int )
{
Point2f vertices[4];
rec.points(vertices);
int count_match = 0;
for( int i = 0; i < 4; i++ )
{
if( cv::norm(vertices[i] - a) <= 0.001 ) count_match++;
else if( cv::norm(vertices[i] - b) <= 0.001 ) count_match++;
else if( cv::norm(vertices[i] - c) <= 0.001 ) count_match++;
}
if( count_match == 3 )
return cvtest::TS::OK;
ts->printf( cvtest::TS::LOG, "RotatedRect end points don't match those supplied in constructor");
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
return cvtest::TS::OK;
}
TEST(Core_RotatedRect, three_point_constructor) { Core_RotatedRectConstructorTest test; test.safe_run(); }
}} // namespace

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,505 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
#include "opencv2/core/utils/logger.defines.hpp"
#undef CV_LOG_STRIP_LEVEL
#define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_VERBOSE + 1
#include "opencv2/core/utils/logger.hpp"
#include "opencv2/core/utils/buffer_area.private.hpp"
#include "opencv2/core/utils/filesystem.private.hpp"
#ifndef OPENCV_DISABLE_THREAD_SUPPORT
#include "test_utils_tls.impl.hpp"
#endif
namespace opencv_test { namespace {
static const char * const keys =
"{ h help | | print help }"
"{ i info | false | print info }"
"{ t true | true | true value }"
"{ n unused | | dummy }"
;
TEST(CommandLineParser, testFailure)
{
const char* argv[] = {"<bin>", "-q"};
const int argc = 2;
cv::CommandLineParser parser(argc, argv, keys);
EXPECT_ANY_THROW(parser.has("q"));
EXPECT_ANY_THROW(parser.get<bool>("q"));
EXPECT_ANY_THROW(parser.get<bool>(0));
parser.get<bool>("h");
EXPECT_FALSE(parser.check());
}
TEST(CommandLineParser, testHas_noValues)
{
const char* argv[] = {"<bin>", "-h", "--info"};
const int argc = 3;
cv::CommandLineParser parser(argc, argv, keys);
EXPECT_TRUE(parser.has("help"));
EXPECT_TRUE(parser.has("h"));
EXPECT_TRUE(parser.get<bool>("help"));
EXPECT_TRUE(parser.get<bool>("h"));
EXPECT_TRUE(parser.has("info"));
EXPECT_TRUE(parser.has("i"));
EXPECT_TRUE(parser.get<bool>("info"));
EXPECT_TRUE(parser.get<bool>("i"));
EXPECT_TRUE(parser.get<bool>("true"));
EXPECT_TRUE(parser.get<bool>("t"));
EXPECT_FALSE(parser.has("n"));
EXPECT_FALSE(parser.has("unused"));
}
TEST(CommandLineParser, testHas_TrueValues)
{
const char* argv[] = {"<bin>", "-h=TRUE", "--info=true"};
const int argc = 3;
cv::CommandLineParser parser(argc, argv, keys);
EXPECT_TRUE(parser.has("help"));
EXPECT_TRUE(parser.has("h"));
EXPECT_TRUE(parser.get<bool>("help"));
EXPECT_TRUE(parser.get<bool>("h"));
EXPECT_TRUE(parser.has("info"));
EXPECT_TRUE(parser.has("i"));
EXPECT_TRUE(parser.get<bool>("info"));
EXPECT_TRUE(parser.get<bool>("i"));
EXPECT_TRUE(parser.get<bool>("true"));
EXPECT_TRUE(parser.get<bool>("t"));
EXPECT_FALSE(parser.has("n"));
EXPECT_FALSE(parser.has("unused"));
}
TEST(CommandLineParser, testHas_TrueValues1)
{
const char* argv[] = {"<bin>", "-h=1", "--info=1"};
const int argc = 3;
cv::CommandLineParser parser(argc, argv, keys);
EXPECT_TRUE(parser.has("help"));
EXPECT_TRUE(parser.has("h"));
EXPECT_TRUE(parser.get<bool>("help"));
EXPECT_TRUE(parser.get<bool>("h"));
EXPECT_TRUE(parser.has("info"));
EXPECT_TRUE(parser.has("i"));
EXPECT_TRUE(parser.get<bool>("info"));
EXPECT_TRUE(parser.get<bool>("i"));
EXPECT_TRUE(parser.get<bool>("true"));
EXPECT_TRUE(parser.get<bool>("t"));
EXPECT_FALSE(parser.has("n"));
EXPECT_FALSE(parser.has("unused"));
}
TEST(CommandLineParser, testHas_FalseValues0)
{
const char* argv[] = {"<bin>", "-h=0", "--info=0"};
const int argc = 3;
cv::CommandLineParser parser(argc, argv, keys);
EXPECT_TRUE(parser.has("help"));
EXPECT_TRUE(parser.has("h"));
EXPECT_FALSE(parser.get<bool>("help"));
EXPECT_FALSE(parser.get<bool>("h"));
EXPECT_TRUE(parser.has("info"));
EXPECT_TRUE(parser.has("i"));
EXPECT_FALSE(parser.get<bool>("info"));
EXPECT_FALSE(parser.get<bool>("i"));
EXPECT_TRUE(parser.get<bool>("true"));
EXPECT_TRUE(parser.get<bool>("t"));
EXPECT_FALSE(parser.has("n"));
EXPECT_FALSE(parser.has("unused"));
}
TEST(CommandLineParser, testBoolOption_noArgs)
{
const char* argv[] = {"<bin>"};
const int argc = 1;
cv::CommandLineParser parser(argc, argv, keys);
EXPECT_FALSE(parser.get<bool>("help"));
EXPECT_FALSE(parser.get<bool>("h"));
EXPECT_FALSE(parser.get<bool>("info"));
EXPECT_FALSE(parser.get<bool>("i"));
EXPECT_TRUE(parser.get<bool>("true")); // default is true
EXPECT_TRUE(parser.get<bool>("t"));
}
TEST(CommandLineParser, testBoolOption_noValues)
{
const char* argv[] = {"<bin>", "-h", "--info"};
const int argc = 3;
cv::CommandLineParser parser(argc, argv, keys);
EXPECT_TRUE(parser.get<bool>("help"));
EXPECT_TRUE(parser.get<bool>("h"));
EXPECT_TRUE(parser.get<bool>("info"));
EXPECT_TRUE(parser.get<bool>("i"));
EXPECT_TRUE(parser.get<bool>("true"));
EXPECT_TRUE(parser.get<bool>("t"));
}
TEST(CommandLineParser, testBoolOption_TrueValues)
{
const char* argv[] = {"<bin>", "-h=TrUe", "-t=1", "--info=true", "-n=truE"};
const int argc = 5;
cv::CommandLineParser parser(argc, argv, keys);
EXPECT_TRUE(parser.get<bool>("help"));
EXPECT_TRUE(parser.get<bool>("h"));
EXPECT_TRUE(parser.get<bool>("info"));
EXPECT_TRUE(parser.get<bool>("i"));
EXPECT_TRUE(parser.get<bool>("true"));
EXPECT_TRUE(parser.get<bool>("t"));
EXPECT_TRUE(parser.get<bool>("unused"));
EXPECT_TRUE(parser.get<bool>("n"));
}
TEST(CommandLineParser, testBoolOption_FalseValues)
{
const char* argv[] = {"<bin>", "--help=FALSE", "-t=FaLsE", "-i=false", "-n=0"};
const int argc = 5;
cv::CommandLineParser parser(argc, argv, keys);
EXPECT_FALSE(parser.get<bool>("help"));
EXPECT_FALSE(parser.get<bool>("h"));
EXPECT_FALSE(parser.get<bool>("info"));
EXPECT_FALSE(parser.get<bool>("i"));
EXPECT_FALSE(parser.get<bool>("true"));
EXPECT_FALSE(parser.get<bool>("t"));
EXPECT_FALSE(parser.get<bool>("unused"));
EXPECT_FALSE(parser.get<bool>("n"));
}
static const char * const keys2 =
"{ h help | | print help }"
"{ @arg1 | default1 | param1 }"
"{ @arg2 | | param2 }"
"{ n unused | | dummy }"
;
TEST(CommandLineParser, testPositional_noArgs)
{
const char* argv[] = {"<bin>"};
const int argc = 1;
cv::CommandLineParser parser(argc, argv, keys2);
EXPECT_TRUE(parser.has("@arg1"));
EXPECT_FALSE(parser.has("@arg2"));
EXPECT_EQ("default1", parser.get<String>("@arg1"));
EXPECT_EQ("default1", parser.get<String>(0));
EXPECT_EQ("", parser.get<String>("@arg2"));
EXPECT_EQ("", parser.get<String>(1));
}
TEST(CommandLineParser, testPositional_default)
{
const char* argv[] = {"<bin>", "test1", "test2"};
const int argc = 3;
cv::CommandLineParser parser(argc, argv, keys2);
EXPECT_TRUE(parser.has("@arg1"));
EXPECT_TRUE(parser.has("@arg2"));
EXPECT_EQ("test1", parser.get<String>("@arg1"));
EXPECT_EQ("test2", parser.get<String>("@arg2"));
EXPECT_EQ("test1", parser.get<String>(0));
EXPECT_EQ("test2", parser.get<String>(1));
}
TEST(CommandLineParser, testPositional_withFlagsBefore)
{
const char* argv[] = {"<bin>", "-h", "test1", "test2"};
const int argc = 4;
cv::CommandLineParser parser(argc, argv, keys2);
EXPECT_TRUE(parser.has("@arg1"));
EXPECT_TRUE(parser.has("@arg2"));
EXPECT_EQ("test1", parser.get<String>("@arg1"));
EXPECT_EQ("test2", parser.get<String>("@arg2"));
EXPECT_EQ("test1", parser.get<String>(0));
EXPECT_EQ("test2", parser.get<String>(1));
}
TEST(CommandLineParser, testPositional_withFlagsAfter)
{
const char* argv[] = {"<bin>", "test1", "test2", "-h"};
const int argc = 4;
cv::CommandLineParser parser(argc, argv, keys2);
EXPECT_TRUE(parser.has("@arg1"));
EXPECT_TRUE(parser.has("@arg2"));
EXPECT_EQ("test1", parser.get<String>("@arg1"));
EXPECT_EQ("test2", parser.get<String>("@arg2"));
EXPECT_EQ("test1", parser.get<String>(0));
EXPECT_EQ("test2", parser.get<String>(1));
}
TEST(CommandLineParser, testEmptyStringValue)
{
static const char * const keys3 =
"{ @pos0 | | empty default value }"
"{ @pos1 | <none> | forbid empty default value }";
const char* argv[] = {"<bin>"};
const int argc = 1;
cv::CommandLineParser parser(argc, argv, keys3);
// EXPECT_TRUE(parser.has("@pos0"));
EXPECT_EQ("", parser.get<String>("@pos0"));
EXPECT_TRUE(parser.check());
EXPECT_FALSE(parser.has("@pos1"));
parser.get<String>(1);
EXPECT_FALSE(parser.check());
}
TEST(CommandLineParser, positional_regression_5074_equal_sign)
{
static const char * const keys3 =
"{ @eq0 | | }"
"{ eq1 | | }";
const char* argv[] = {"<bin>", "1=0", "--eq1=1=0"};
const int argc = 3;
cv::CommandLineParser parser(argc, argv, keys3);
EXPECT_EQ("1=0", parser.get<String>("@eq0"));
EXPECT_EQ("1=0", parser.get<String>(0));
EXPECT_EQ("1=0", parser.get<String>("eq1"));
EXPECT_TRUE(parser.check());
}
TEST(AutoBuffer, allocate_test)
{
AutoBuffer<int, 5> abuf(2);
EXPECT_EQ(2u, abuf.size());
abuf.allocate(4);
EXPECT_EQ(4u, abuf.size());
abuf.allocate(6);
EXPECT_EQ(6u, abuf.size());
}
TEST(CommandLineParser, testScalar)
{
static const char * const keys3 =
"{ s0 | 3 4 5 | default scalar }"
"{ s1 | | single value scalar }"
"{ s2 | | two values scalar (default with zeros) }"
"{ s3 | | three values scalar }"
"{ s4 | | four values scalar }"
"{ s5 | | five values scalar }";
const char* argv[] = {"<bin>", "--s1=1.1", "--s3=1.1 2.2 3",
"--s4=-4.2 1 0 3", "--s5=5 -4 3 2 1"};
const int argc = 5;
CommandLineParser parser(argc, argv, keys3);
EXPECT_EQ(parser.get<Scalar>("s0"), Scalar(3, 4, 5));
EXPECT_EQ(parser.get<Scalar>("s1"), Scalar(1.1));
EXPECT_EQ(parser.get<Scalar>("s2"), Scalar(0));
EXPECT_EQ(parser.get<Scalar>("s3"), Scalar(1.1, 2.2, 3));
EXPECT_EQ(parser.get<Scalar>("s4"), Scalar(-4.2, 1, 0, 3));
EXPECT_EQ(parser.get<Scalar>("s5"), Scalar(5, -4, 3, 2));
}
TEST(Logger, DISABLED_message)
{
int id = 42;
CV_LOG_VERBOSE(NULL, 0, "Verbose message: " << id);
CV_LOG_VERBOSE(NULL, 1, "Verbose message: " << id);
CV_LOG_DEBUG(NULL, "Debug message: " << id);
CV_LOG_INFO(NULL, "Info message: " << id);
CV_LOG_WARNING(NULL, "Warning message: " << id);
CV_LOG_ERROR(NULL, "Error message: " << id);
CV_LOG_FATAL(NULL, "Fatal message: " << id);
}
static int testLoggerMessageOnce(int id)
{
CV_LOG_ONCE_VERBOSE(NULL, 0, "Verbose message: " << id++);
CV_LOG_ONCE_VERBOSE(NULL, 1, "Verbose message: " << id++);
CV_LOG_ONCE_DEBUG(NULL, "Debug message: " << id++);
CV_LOG_ONCE_INFO(NULL, "Info message: " << id++);
CV_LOG_ONCE_WARNING(NULL, "Warning message: " << id++);
CV_LOG_ONCE_ERROR(NULL, "Error message: " << id++);
// doesn't make sense: CV_LOG_ONCE_FATAL
return id;
}
TEST(Logger, DISABLED_message_once)
{
int check_id_first = testLoggerMessageOnce(42);
EXPECT_GT(check_id_first, 42);
int check_id_second = testLoggerMessageOnce(0);
EXPECT_EQ(0, check_id_second);
}
TEST(Logger, DISABLED_message_if)
{
for (int i = 0; i < 100; i++)
{
CV_LOG_IF_VERBOSE(NULL, 0, i == 0 || i == 42, "Verbose message: " << i);
CV_LOG_IF_VERBOSE(NULL, 1, i == 0 || i == 42, "Verbose message: " << i);
CV_LOG_IF_DEBUG(NULL, i == 0 || i == 42, "Debug message: " << i);
CV_LOG_IF_INFO(NULL, i == 0 || i == 42, "Info message: " << i);
CV_LOG_IF_WARNING(NULL, i == 0 || i == 42, "Warning message: " << i);
CV_LOG_IF_ERROR(NULL, i == 0 || i == 42, "Error message: " << i);
CV_LOG_IF_FATAL(NULL, i == 0 || i == 42, "Fatal message: " << i);
}
}
#if OPENCV_HAVE_FILESYSTEM_SUPPORT
TEST(Samples, findFile)
{
cv::utils::logging::LogLevel prev = cv::utils::logging::setLogLevel(cv::utils::logging::LOG_LEVEL_VERBOSE);
cv::String path;
ASSERT_NO_THROW(path = samples::findFile("lena.jpg", false));
EXPECT_NE(std::string(), path.c_str());
cv::utils::logging::setLogLevel(prev);
}
TEST(Samples, findFile_missing)
{
cv::utils::logging::LogLevel prev = cv::utils::logging::setLogLevel(cv::utils::logging::LOG_LEVEL_VERBOSE);
cv::String path;
ASSERT_ANY_THROW(path = samples::findFile("non-existed.file", true));
cv::utils::logging::setLogLevel(prev);
}
#endif // OPENCV_HAVE_FILESYSTEM_SUPPORT
template <typename T>
inline bool buffers_overlap(T * first, size_t first_num, T * second, size_t second_num)
{
// cerr << "[" << (void*)first << " : " << (void*)(first + first_num) << ")";
// cerr << " X ";
// cerr << "[" << (void*)second << " : " << (void*)(second + second_num) << ")";
// cerr << endl;
bool res = false;
res |= (second <= first) && (first < second + second_num);
res |= (second < first + first_num) && (first + first_num < second + second_num);
return res;
}
typedef testing::TestWithParam<bool> BufferArea;
TEST_P(BufferArea, basic)
{
const bool safe = GetParam();
const size_t SZ = 3;
int * int_ptr = NULL;
uchar * uchar_ptr = NULL;
double * dbl_ptr = NULL;
{
cv::utils::BufferArea area(safe);
area.allocate(int_ptr, SZ);
area.allocate(uchar_ptr, SZ);
area.allocate(dbl_ptr, SZ);
area.commit();
ASSERT_TRUE(int_ptr != NULL);
ASSERT_TRUE(uchar_ptr != NULL);
ASSERT_TRUE(dbl_ptr != NULL);
EXPECT_EQ((size_t)0, (size_t)int_ptr % sizeof(int));
EXPECT_EQ((size_t)0, (size_t)dbl_ptr % sizeof(double));
for (size_t i = 0; i < SZ; ++i)
{
int_ptr[i] = (int)i + 1;
uchar_ptr[i] = (uchar)i + 1;
dbl_ptr[i] = (double)i + 1;
}
area.zeroFill(int_ptr);
area.zeroFill(uchar_ptr);
area.zeroFill(dbl_ptr);
for (size_t i = 0; i < SZ; ++i)
{
EXPECT_EQ((int)0, int_ptr[i]);
EXPECT_EQ((uchar)0, uchar_ptr[i]);
EXPECT_EQ((double)0, dbl_ptr[i]);
}
}
EXPECT_TRUE(int_ptr == NULL);
EXPECT_TRUE(uchar_ptr == NULL);
EXPECT_TRUE(dbl_ptr == NULL);
}
TEST_P(BufferArea, align)
{
const bool safe = GetParam();
const size_t SZ = 3;
const size_t CNT = 5;
typedef int T;
T * buffers[CNT] = {0};
{
cv::utils::BufferArea area(safe);
// allocate buffers with 3 elements with growing alignment (power of two)
for (size_t i = 0; i < CNT; ++i)
{
const ushort ALIGN = static_cast<ushort>(sizeof(T) << i);
EXPECT_TRUE(buffers[i] == NULL);
area.allocate(buffers[i], SZ, ALIGN);
}
area.commit();
for (size_t i = 0; i < CNT; ++i)
{
const ushort ALIGN = static_cast<ushort>(sizeof(T) << i);
EXPECT_TRUE(buffers[i] != NULL);
EXPECT_EQ((size_t)0, reinterpret_cast<size_t>(buffers[i]) % ALIGN);
if (i < CNT - 1)
{
SCOPED_TRACE(i);
EXPECT_FALSE(buffers_overlap(buffers[i], SZ, buffers[i + 1], SZ))
<< "Buffers overlap: "
<< buffers[i] << " (" << SZ << " elems)"
<< " and "
<< buffers[i + 1] << " (" << SZ << " elems)"
<< " (element size: " << sizeof(T) << ")";
}
}
}
for (size_t i = 0; i < CNT; ++i)
{
EXPECT_TRUE(buffers[i] == NULL);
}
}
TEST_P(BufferArea, default_align)
{
const bool safe = GetParam();
const size_t CNT = 100;
const ushort ALIGN = 64;
typedef int T;
T * buffers[CNT] = {0};
{
cv::utils::BufferArea area(safe);
// allocate buffers with 1-99 elements with default alignment
for (size_t i = 0; i < CNT; ++ i)
{
EXPECT_TRUE(buffers[i] == NULL);
area.allocate(buffers[i], i + 1, ALIGN);
}
area.commit();
for (size_t i = 0; i < CNT; ++i)
{
EXPECT_TRUE(buffers[i] != NULL);
EXPECT_EQ((size_t)0, reinterpret_cast<size_t>(buffers[i]) % ALIGN);
if (i < CNT - 1)
{
SCOPED_TRACE(i);
EXPECT_FALSE(buffers_overlap(buffers[i], i + 1, buffers[i + 1], i + 2))
<< "Buffers overlap: "
<< buffers[i] << " (" << i + 1 << " elems)"
<< " and "
<< buffers[i + 1] << " (" << i + 2 << " elems)"
<< " (element size: " << sizeof(T) << ")";
}
}
}
}
TEST_P(BufferArea, bad)
{
const bool safe = GetParam();
int * ptr = 0;
cv::utils::BufferArea area(safe);
EXPECT_ANY_THROW(area.allocate(ptr, 0)); // bad size
EXPECT_ANY_THROW(area.allocate(ptr, 1, 0)); // bad alignment
EXPECT_ANY_THROW(area.allocate(ptr, 1, 3)); // bad alignment
ptr = (int*)1;
EXPECT_ANY_THROW(area.allocate(ptr, 1)); // non-zero pointer
}
INSTANTIATE_TEST_CASE_P(/**/, BufferArea, testing::Values(true, false));
}} // namespace

View File

@ -0,0 +1,134 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
// This is .hpp file included from test_utils.cpp
#ifdef CV_CXX11
#include <thread> // std::thread
#endif
#include "opencv2/core/utils/tls.hpp"
namespace opencv_test { namespace {
class TLSReporter
{
public:
static int g_last_id;
static int g_allocated;
int id;
TLSReporter()
{
id = CV_XADD(&g_last_id, 1);
CV_XADD(&g_allocated, 1);
}
~TLSReporter()
{
CV_XADD(&g_allocated, -1);
}
};
int TLSReporter::g_last_id = 0;
int TLSReporter::g_allocated = 0;
#ifdef CV_CXX11
template<typename T>
static void callNThreadsWithTLS(int N, TLSData<T>& tls)
{
std::vector<std::thread> threads(N);
for (int i = 0; i < N; i++)
{
threads[i] = std::thread([&]() {
TLSReporter* pData = tls.get();
(void)pData;
});
}
for (int i = 0; i < N; i++)
{
threads[i].join();
}
threads.clear();
}
TEST(Core_TLS, HandleThreadTermination)
{
const int init_id = TLSReporter::g_last_id;
const int init_allocated = TLSReporter::g_allocated;
const int N = 4;
TLSData<TLSReporter> tls;
// use TLS
ASSERT_NO_THROW(callNThreadsWithTLS(N, tls));
EXPECT_EQ(init_id + N, TLSReporter::g_last_id);
EXPECT_EQ(init_allocated + 0, TLSReporter::g_allocated);
}
static void testTLSAccumulator(bool detachFirst)
{
const int init_id = TLSReporter::g_last_id;
const int init_allocated = TLSReporter::g_allocated;
const int N = 4;
TLSDataAccumulator<TLSReporter> tls;
{ // empty TLS checks
std::vector<TLSReporter*>& data0 = tls.detachData();
EXPECT_EQ((size_t)0, data0.size());
tls.cleanupDetachedData();
}
// use TLS
ASSERT_NO_THROW(callNThreadsWithTLS(N, tls));
EXPECT_EQ(init_id + N, TLSReporter::g_last_id);
EXPECT_EQ(init_allocated + N, TLSReporter::g_allocated);
if (detachFirst)
{
std::vector<TLSReporter*>& data1 = tls.detachData();
EXPECT_EQ((size_t)N, data1.size());
// no data through gather after detachData()
std::vector<TLSReporter*> data2;
tls.gather(data2);
EXPECT_EQ((size_t)0, data2.size());
tls.cleanupDetachedData();
EXPECT_EQ(init_id + N, TLSReporter::g_last_id);
EXPECT_EQ(init_allocated + 0, TLSReporter::g_allocated);
EXPECT_EQ((size_t)0, data1.size());
}
else
{
std::vector<TLSReporter*> data2;
tls.gather(data2);
EXPECT_EQ((size_t)N, data2.size());
std::vector<TLSReporter*>& data1 = tls.detachData();
EXPECT_EQ((size_t)N, data1.size());
tls.cleanupDetachedData();
EXPECT_EQ((size_t)0, data1.size());
// data2 is not empty, but it has invalid contents
EXPECT_EQ((size_t)N, data2.size());
}
EXPECT_EQ(init_id + N, TLSReporter::g_last_id);
EXPECT_EQ(init_allocated + 0, TLSReporter::g_allocated);
}
TEST(Core_TLS, AccumulatorHoldData_detachData) { testTLSAccumulator(true); }
TEST(Core_TLS, AccumulatorHoldData_gather) { testTLSAccumulator(false); }
#endif
}} // namespace