vendor: OpenCV 5.0.0 snapshot at 755e50675d97db9b7d449d8bd6b09888646f6c6e

This commit is contained in:
Gitea Mirror Bot
2026-08-22 00:11:13 +08:00
commit 12022378a3
3872 changed files with 2513409 additions and 0 deletions
@@ -0,0 +1,42 @@
// 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 {
TEST(xphoto_dctimagedenoising, regression)
{
cv::String subfolder = "cv/xphoto/";
cv::String dir = cvtest::TS::ptr()->get_data_path() + subfolder + "dct_image_denoising/";
int nTests = 1;
double thresholds[] = {0.2};
int psize[] = {8};
double sigma[] = {9.0};
for (int i = 0; i < nTests; ++i)
{
cv::String srcName = dir + cv::format( "sources/%02d.png", i + 1);
cv::Mat src = cv::imread( srcName, 1 );
ASSERT_TRUE(!src.empty());
cv::String previousResultName = dir + cv::format( "results/%02d.png", i + 1 );
cv::Mat previousResult = cv::imread( previousResultName, 1 );
ASSERT_TRUE(!src.empty());
cv::Mat currentResult;
cv::xphoto::dctDenoising(src, currentResult, sigma[i], psize[i]);
cv::Mat sqrError = ( currentResult - previousResult )
.mul( currentResult - previousResult );
cv::Scalar mse = cv::sum(sqrError) / cv::Scalar::all( double(sqrError.total()*sqrError.channels()) );
EXPECT_LE( mse[0] + mse[1] + mse[2] + mse[3], thresholds[i] );
}
}
}} // namespace
@@ -0,0 +1,273 @@
// 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 {
TEST(xphoto_simplecolorbalance, uchar_max_value)
{
const uchar oldMax = 120, newMax = 255;
Mat test = Mat::zeros(3,3,CV_8UC1);
test.at<uchar>(0, 0) = oldMax;
test.at<uchar>(0, 1) = oldMax / 2;
test.at<uchar>(0, 2) = oldMax / 4;
cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB();
wb->setInputMin(0);
wb->setInputMax(oldMax);
wb->setOutputMin(0);
wb->setOutputMax(newMax);
wb->balanceWhite(test, test);
double minDst, maxDst;
cv::minMaxIdx(test, &minDst, &maxDst);
ASSERT_NEAR(maxDst, newMax, 1e-4);
}
TEST(xphoto_simplecolorbalance, uchar_min_value)
{
const uchar oldMin = 120, newMin = 0;
Mat test = Mat::zeros(1,3,CV_8UC1);
test.at<uchar>(0, 0) = oldMin;
test.at<uchar>(0, 1) = (256 + oldMin) / 2;
test.at<uchar>(0, 2) = 255;
cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB();
wb->setInputMin(oldMin);
wb->setInputMax(255);
wb->setOutputMin(newMin);
wb->setOutputMax(255);
wb->balanceWhite(test, test);
double minDst, maxDst;
cv::minMaxIdx(test, &minDst, &maxDst);
ASSERT_NEAR(minDst, newMin, 1e-4);
}
TEST(xphoto_simplecolorbalance, uchar_equal_range)
{
const int N = 4;
uchar data[N] = {0, 1, 16, 255};
Mat test = Mat(1, N, CV_8UC1, data);
Mat result = Mat(1, N, CV_8UC1, data);
cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB();
wb->setInputMin(0);
wb->setInputMax(255);
wb->setOutputMin(0);
wb->setOutputMax(255);
wb->balanceWhite(test, test);
double err;
cv::minMaxIdx(cv::abs(test - result), NULL, &err);
ASSERT_LE(err, 1e-4);
}
TEST(xphoto_simplecolorbalance, uchar_single_value)
{
const int N = 4;
uchar data0[N] = {51, 51, 51, 51};
uchar data1[N] = {33, 33, 33, 33};
Mat test = Mat(1, N, CV_8UC1, data0);
Mat result = Mat(1, N, CV_8UC1, data1);
cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB();
wb->setInputMin(51);
wb->setInputMax(51);
wb->setOutputMin(33);
wb->setOutputMax(200);
wb->balanceWhite(test, test);
double err;
cv::minMaxIdx(cv::abs(test - result), NULL, &err);
ASSERT_LE(err, 1e-4);
}
TEST(xphoto_simplecolorbalance, uchar_p)
{
const int N = 5;
uchar data0[N] = {10, 55, 102, 188, 233};
uchar data1[N] = {0, 1, 90, 254, 255};
Mat test = Mat(1, N, CV_8UC1, data0);
Mat result = Mat(1, N, CV_8UC1, data1);
cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB();
wb->setInputMin(10);
wb->setInputMax(233);
wb->setOutputMin(0);
wb->setOutputMax(255);
wb->setP(21);
wb->balanceWhite(test, test);
double err;
cv::minMaxIdx(cv::abs(test - result), NULL, &err);
ASSERT_LE(err, 1e-4);
}
TEST(xphoto_simplecolorbalance, uchar_c3)
{
const int N = 15;
uchar data0[N] = {10, 55, 102, 55, 102, 188, 102, 188, 233, 188, 233, 10, 233, 10, 55};
uchar data1[N] = {0, 1, 90, 1, 90, 254, 90, 254, 255, 254, 255, 0, 255, 0, 1};
Mat test = Mat(1, N / 3, CV_8UC3, data0);
Mat result = Mat(1, N / 3, CV_8UC3, data1);
cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB();
wb->setInputMin(10);
wb->setInputMax(233);
wb->setOutputMin(0);
wb->setOutputMax(255);
wb->setP(21);
wb->balanceWhite(test, test);
double err;
cv::minMaxIdx(cv::abs(test - result), NULL, &err);
ASSERT_LE(err, 1e-4);
}
TEST(xphoto_simplecolorbalance, float_max_value)
{
const float oldMax = 24000.f, newMax = 65536.f;
Mat test = Mat::zeros(3,3,CV_32FC1);
test.at<float>(0, 0) = oldMax;
test.at<float>(0, 1) = oldMax / 2;
test.at<float>(0, 2) = oldMax / 4;
double minSrc, maxSrc;
cv::minMaxIdx(test, &minSrc, &maxSrc);
cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB();
wb->setInputMin((float)minSrc);
wb->setInputMax((float)maxSrc);
wb->setOutputMin(0);
wb->setOutputMax(newMax);
wb->balanceWhite(test, test);
double minDst, maxDst;
cv::minMaxIdx(test, &minDst, &maxDst);
ASSERT_NEAR(maxDst, newMax, newMax*1e-4);
}
TEST(xphoto_simplecolorbalance, float_min_value)
{
const float oldMin = 24000.f, newMin = 0.f;
Mat test = Mat::zeros(1,3,CV_32FC1);
test.at<float>(0, 0) = oldMin;
test.at<float>(0, 1) = (65536.f + oldMin) / 2;
test.at<float>(0, 2) = 65536.f;
cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB();
wb->setInputMin(oldMin);
wb->setInputMax(65536.f);
wb->setOutputMin(newMin);
wb->setOutputMax(65536.f);
wb->balanceWhite(test, test);
double minDst, maxDst;
cv::minMaxIdx(test, &minDst, &maxDst);
ASSERT_NEAR(minDst, newMin, 65536*1e-4);
}
TEST(xphoto_simplecolorbalance, float_equal_range)
{
const int N = 5;
float data[N] = {0.f, 1.f, 16.2f, 256.3f, 4096.f};
Mat test = Mat(1, N, CV_32FC1, data);
Mat result = Mat(1, N, CV_32FC1, data);
cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB();
wb->setInputMin(0);
wb->setInputMax(4096);
wb->setOutputMin(0);
wb->setOutputMax(4096);
wb->balanceWhite(test, test);
double err;
cv::minMaxIdx(cv::abs(test - result), NULL, &err);
ASSERT_LE(err, 1e-4);
}
TEST(xphoto_simplecolorbalance, float_single_value)
{
const int N = 4;
float data0[N] = {24000.5f, 24000.5f, 24000.5f, 24000.5f};
float data1[N] = {52000.25f, 52000.25f, 52000.25f, 52000.25f};
Mat test = Mat(1, N, CV_32FC1, data0);
Mat result = Mat(1, N, CV_32FC1, data1);
cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB();
wb->setInputMin(24000.5f);
wb->setInputMax(24000.5f);
wb->setOutputMin(52000.25f);
wb->setOutputMax(65536.f);
wb->balanceWhite(test, test);
double err;
cv::minMaxIdx(cv::abs(test - result), NULL, &err);
ASSERT_LE(err, 65536*1e-4);
}
TEST(xphoto_simplecolorbalance, float_p)
{
const int N = 5;
float data0[N] = {16000.f, 20000.5f, 24000.f, 36000.5f, 48000.f};
float data1[N] = {-16381.952f, 0.f, 16381.952f, 65536.f, 114685.952f};
Mat test = Mat(1, N, CV_32FC1, data0);
Mat result = Mat(1, N, CV_32FC1, data1);
cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB();
wb->setInputMin(16000.f);
wb->setInputMax(48000.f);
wb->setOutputMin(0.f);
wb->setOutputMax(65536.f);
wb->setP(21);
wb->balanceWhite(test, test);
double err;
cv::minMaxIdx(cv::abs(test - result), NULL, &err);
ASSERT_LE(err, 65536*1e-4);
}
TEST(xphoto_simplecolorbalance, float_c3)
{
const int N = 15;
float data0[N] = {16000.f, 20000.5f, 24000.f, 20000.5f, 24000.f, 36000.5f, 24000.f, 36000.5f, 48000.f, 36000.5f, 48000.f, 16000.f, 48000.f, 16000.f, 20000.5f};
float data1[N] = {-16381.952f, 0.f, 16381.952f, 0.f, 16381.952f, 65536.f, 16381.952f, 65536.f, 114685.952f, 65536.f, 114685.952f, -16381.952f, 114685.952f, -16381.952f, 0.f};
Mat test = Mat(1, N / 3, CV_32FC3, data0);
Mat result = Mat(1, N / 3, CV_32FC3, data1);
cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB();
wb->setInputMin(16000.f);
wb->setInputMax(48000.f);
wb->setOutputMin(0.f);
wb->setOutputMax(65536.f);
wb->setP(21);
wb->balanceWhite(test, test);
double err;
cv::minMaxIdx(cv::abs(test - result), NULL, &err);
ASSERT_LE(err, 65536*1e-4);
}
}} // namespace
+464
View File
@@ -0,0 +1,464 @@
/*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"
//#define DUMP_RESULTS
//#define TEST_TRANSFORMS
#ifdef TEST_TRANSFORMS
#include "..\..\xphoto\src\bm3d_denoising_invoker_commons.hpp"
#include "..\..\xphoto\src\bm3d_denoising_transforms.hpp"
#include "..\..\xphoto\src\kaiser_window.hpp"
using namespace cv::xphoto;
#endif
#ifdef DUMP_RESULTS
# define DUMP(image, path) imwrite(path, image)
#else
# define DUMP(image, path)
#endif
#ifdef OPENCV_ENABLE_NONFREE
namespace opencv_test { namespace {
TEST(xphoto_DenoisingBm3dGrayscale, regression_L2)
{
std::string folder = std::string(cvtest::TS::ptr()->get_data_path()) + "cv/xphoto/bm3d_image_denoising/";
std::string original_path = folder + "lena_noised_gaussian_sigma=10.png";
std::string expected_path = folder + "lena_noised_denoised_bm3d_wiener_grayscale_l2_tw=4_sw=16_h=10_bm=400.png";
cv::Mat original = cv::imread(original_path, cv::IMREAD_GRAYSCALE);
cv::Mat expected = cv::imread(expected_path, cv::IMREAD_GRAYSCALE);
ASSERT_FALSE(original.empty()) << "Could not load input image " << original_path;
ASSERT_FALSE(expected.empty()) << "Could not load reference image " << expected_path;
// BM3D: two different calls doing exactly the same thing
cv::Mat result, resultSec;
cv::xphoto::bm3dDenoising(original, noArray(), resultSec, 10, 4, 16, 2500, 400, 8, 1, 0.0f, cv::NORM_L2, cv::xphoto::BM3D_STEPALL);
cv::xphoto::bm3dDenoising(original, result, 10, 4, 16, 2500, 400, 8, 1, 0.0f, cv::NORM_L2, cv::xphoto::BM3D_STEPALL);
DUMP(result, expected_path + ".res.png");
ASSERT_EQ(cvtest::norm(result, resultSec, cv::NORM_L2), 0);
ASSERT_LT(cvtest::norm(result, expected, cv::NORM_L2), 200);
}
TEST(xphoto_DenoisingBm3dGrayscale, regression_L2_separate)
{
std::string folder = std::string(cvtest::TS::ptr()->get_data_path()) + "cv/xphoto/bm3d_image_denoising/";
std::string original_path = folder + "lena_noised_gaussian_sigma=10.png";
std::string expected_basic_path = folder + "lena_noised_denoised_bm3d_grayscale_l2_tw=4_sw=16_h=10_bm=2500.png";
std::string expected_path = folder + "lena_noised_denoised_bm3d_wiener_grayscale_l2_tw=4_sw=16_h=10_bm=400.png";
cv::Mat original = cv::imread(original_path, cv::IMREAD_GRAYSCALE);
cv::Mat expected_basic = cv::imread(expected_basic_path, cv::IMREAD_GRAYSCALE);
cv::Mat expected = cv::imread(expected_path, cv::IMREAD_GRAYSCALE);
ASSERT_FALSE(original.empty()) << "Could not load input image " << original_path;
ASSERT_FALSE(expected_basic.empty()) << "Could not load reference image " << expected_basic_path;
ASSERT_FALSE(expected.empty()) << "Could not load input image " << expected_path;
cv::Mat basic, result;
// BM3D step 1
cv::xphoto::bm3dDenoising(original, basic, 10, 4, 16, 2500, -1, 8, 1, 0.0f, cv::NORM_L2, cv::xphoto::BM3D_STEP1);
ASSERT_LT(cvtest::norm(basic, expected_basic, cv::NORM_L2), 200);
DUMP(basic, expected_basic_path + ".res.basic.png");
// BM3D step 2
cv::xphoto::bm3dDenoising(original, basic, result, 10, 4, 16, 2500, 400, 8, 1, 0.0f, cv::NORM_L2, cv::xphoto::BM3D_STEP2);
ASSERT_LT(cvtest::norm(basic, expected_basic, cv::NORM_L2), 200);
DUMP(basic, expected_basic_path + ".res.basic2.png");
DUMP(result, expected_path + ".res.png");
ASSERT_LT(cvtest::norm(result, expected, cv::NORM_L2), 200);
}
TEST(xphoto_DenoisingBm3dGrayscale, regression_L1)
{
std::string folder = std::string(cvtest::TS::ptr()->get_data_path()) + "cv/xphoto/bm3d_image_denoising/";
std::string original_path = folder + "lena_noised_gaussian_sigma=10.png";
std::string expected_path = folder + "lena_noised_denoised_bm3d_grayscale_l1_tw=4_sw=16_h=10_bm=2500.png";
cv::Mat original = cv::imread(original_path, cv::IMREAD_GRAYSCALE);
cv::Mat expected = cv::imread(expected_path, cv::IMREAD_GRAYSCALE);
ASSERT_FALSE(original.empty()) << "Could not load input image " << original_path;
ASSERT_FALSE(expected.empty()) << "Could not load reference image " << expected_path;
cv::Mat result;
cv::xphoto::bm3dDenoising(original, result, 10, 4, 16, 2500, -1, 8, 1, 0.0f, cv::NORM_L1, cv::xphoto::BM3D_STEP1);
DUMP(result, expected_path + ".res.png");
ASSERT_LT(cvtest::norm(result, expected, cv::NORM_L2), 200);
}
TEST(xphoto_DenoisingBm3dGrayscale, regression_L2_8x8)
{
std::string folder = std::string(cvtest::TS::ptr()->get_data_path()) + "cv/xphoto/bm3d_image_denoising/";
std::string original_path = folder + "lena_noised_gaussian_sigma=10.png";
std::string expected_path = folder + "lena_noised_denoised_bm3d_grayscale_l2_tw=8_sw=16_h=10_bm=2500.png";
cv::Mat original = cv::imread(original_path, cv::IMREAD_GRAYSCALE);
cv::Mat expected = cv::imread(expected_path, cv::IMREAD_GRAYSCALE);
ASSERT_FALSE(original.empty()) << "Could not load input image " << original_path;
ASSERT_FALSE(expected.empty()) << "Could not load reference image " << expected_path;
cv::Mat result;
cv::xphoto::bm3dDenoising(original, result, 10, 8, 16, 2500, -1, 8, 1, 0.0f, cv::NORM_L2, cv::xphoto::BM3D_STEP1);
DUMP(result, expected_path + ".res.png");
ASSERT_LT(cvtest::norm(result, expected, cv::NORM_L2), 200);
}
#ifdef TEST_TRANSFORMS
TEST(xphoto_DenoisingBm3dKaiserWindow, regression_4)
{
float beta = 2.0f;
int N = 4;
cv::Mat kaiserWindow;
calcKaiserWindow1D(kaiserWindow, N, beta);
float kaiser4[] = {
0.43869004f,
0.92432547f,
0.92432547f,
0.43869004f
};
for (int i = 0; i < N; ++i)
ASSERT_FLOAT_EQ(kaiser4[i], kaiserWindow.at<float>(i));
}
TEST(xphoto_DenoisingBm3dKaiserWindow, regression_8)
{
float beta = 2.0f;
int N = 8;
cv::Mat kaiserWindow;
calcKaiserWindow1D(kaiserWindow, N, beta);
float kaiser8[] = {
0.43869004f,
0.68134475f,
0.87685609f,
0.98582518f,
0.98582518f,
0.87685609f,
0.68134463f,
0.43869004f
};
for (int i = 0; i < N; ++i)
ASSERT_FLOAT_EQ(kaiser8[i], kaiserWindow.at<float>(i));
}
TEST(xphoto_DenoisingBm3dTransforms, regression_2D_generic)
{
const int templateWindowSize = 8;
const int templateWindowSizeSq = templateWindowSize * templateWindowSize;
uchar src[templateWindowSizeSq];
short dst[templateWindowSizeSq];
short dstSec[templateWindowSizeSq];
// Initialize array
for (uchar i = 0; i < templateWindowSizeSq; ++i)
src[i] = (i % 10) * 10;
// Use tailored transforms
HaarTransform<uchar, short>::RegisterTransforms2D(templateWindowSize);
HaarTransform<uchar, short>::forwardTransform2D(src, dst, templateWindowSize, templateWindowSize);
HaarTransform<uchar, short>::inverseTransform2D(dst, templateWindowSize);
// Use generic transforms
HaarTransform2D::ForwardTransformXxX<uchar, short, templateWindowSize>(src, dstSec, templateWindowSize, templateWindowSize);
HaarTransform2D::InverseTransformXxX<short, templateWindowSize>(dstSec, templateWindowSize);
for (unsigned i = 0; i < templateWindowSizeSq; ++i)
ASSERT_EQ(dst[i], dstSec[i]);
}
TEST(xphoto_DenoisingBm3dTransforms, regression_2D_4x4)
{
const int templateWindowSize = 4;
const int templateWindowSizeSq = templateWindowSize * templateWindowSize;
uchar src[templateWindowSizeSq];
short dst[templateWindowSizeSq];
// Initialize array
for (uchar i = 0; i < templateWindowSizeSq; ++i)
{
src[i] = i;
}
HaarTransform2D::ForwardTransform4x4(src, dst, templateWindowSize, templateWindowSize);
HaarTransform2D::InverseTransform4x4(dst, templateWindowSize);
for (uchar i = 0; i < templateWindowSizeSq; ++i)
ASSERT_EQ(static_cast<short>(src[i]), dst[i]);
}
TEST(xphoto_DenoisingBm3dTransforms, regression_2D_8x8)
{
const int templateWindowSize = 8;
const int templateWindowSizeSq = templateWindowSize * templateWindowSize;
uchar src[templateWindowSizeSq];
short dst[templateWindowSizeSq];
// Initialize array
for (uchar i = 0; i < templateWindowSizeSq; ++i)
{
src[i] = i;
}
HaarTransform2D::ForwardTransform8x8(src, dst, templateWindowSize, templateWindowSize);
HaarTransform2D::InverseTransform8x8(dst, templateWindowSize);
for (uchar i = 0; i < templateWindowSizeSq; ++i)
ASSERT_EQ(static_cast<short>(src[i]), dst[i]);
}
template <typename T, typename DT, typename CT>
static void Test1dTransform(
T *thrMap,
int groupSize,
int templateWindowSizeSq,
BlockMatch<T, DT, CT> *bm,
BlockMatch<T, DT, CT> *bmOrig,
int expectedNonZeroCount = -1)
{
if (expectedNonZeroCount < 0)
expectedNonZeroCount = groupSize * templateWindowSizeSq;
// Test group size
short sumNonZero = 0;
T *thrMapPtr1D = thrMap + (groupSize - 1) * templateWindowSizeSq;
for (int n = 0; n < templateWindowSizeSq; n++)
{
switch (groupSize)
{
case 16:
HaarTransform1D::ForwardTransform16(bm, n);
sumNonZero += HardThreshold<16>(bm, n, thrMapPtr1D);
HaarTransform1D::InverseTransform16(bm, n);
break;
case 8:
HaarTransform1D::ForwardTransform8(bm, n);
sumNonZero += HardThreshold<8>(bm, n, thrMapPtr1D);
HaarTransform1D::InverseTransform8(bm, n);
break;
case 4:
HaarTransform1D::ForwardTransform4(bm, n);
sumNonZero += HardThreshold<4>(bm, n, thrMapPtr1D);
HaarTransform1D::InverseTransform4(bm, n);
break;
case 2:
HaarTransform1D::ForwardTransform2(bm, n);
sumNonZero += HardThreshold<2>(bm, n, thrMapPtr1D);
HaarTransform1D::InverseTransform2(bm, n);
break;
default:
HaarTransform1D::ForwardTransformN(bm, n, groupSize);
sumNonZero += HardThreshold(bm, n, thrMapPtr1D, groupSize);
HaarTransform1D::InverseTransformN(bm, n, groupSize);
}
}
// Assert transform
if (expectedNonZeroCount == groupSize * templateWindowSizeSq)
{
for (int i = 0; i < groupSize; ++i)
for (int j = 0; j < templateWindowSizeSq; ++j)
ASSERT_EQ(bm[i][j], bmOrig[i][j]);
}
// Assert shrinkage
ASSERT_EQ(sumNonZero, expectedNonZeroCount);
}
TEST(xphoto_DenoisingBm3dTransforms, regression_1D_transform)
{
const int templateWindowSize = 4;
const int templateWindowSizeSq = templateWindowSize * templateWindowSize;
const int searchWindowSize = 16;
const int searchWindowSizeSq = searchWindowSize * searchWindowSize;
const float h = 10;
int maxGroupSize = 64;
// Precompute separate maps for transform and shrinkage verification
short *thrMapTransform = NULL;
short *thrMapShrinkage = NULL;
HaarTransform<short, short>::calcThresholdMap3D(thrMapTransform, 0, templateWindowSize, maxGroupSize);
HaarTransform<short, short>::calcThresholdMap3D(thrMapShrinkage, h, templateWindowSize, maxGroupSize);
// Generate some data
BlockMatch<short, int, short> *bm = new BlockMatch<short, int, short>[maxGroupSize];
BlockMatch<short, int, short> *bmOrig = new BlockMatch<short, int, short>[maxGroupSize];
for (int i = 0; i < maxGroupSize; ++i)
{
bm[i].init(templateWindowSizeSq);
bmOrig[i].init(templateWindowSizeSq);
}
for (short i = 0; i < maxGroupSize; ++i)
{
for (short j = 0; j < templateWindowSizeSq; ++j)
{
bm[i][j] = (j + 1);
bmOrig[i][j] = bm[i][j];
}
}
// Verify transforms
Test1dTransform<short, int, short>(thrMapTransform, 2, templateWindowSizeSq, bm, bmOrig);
Test1dTransform<short, int, short>(thrMapTransform, 4, templateWindowSizeSq, bm, bmOrig);
Test1dTransform<short, int, short>(thrMapTransform, 8, templateWindowSizeSq, bm, bmOrig);
Test1dTransform<short, int, short>(thrMapTransform, 16, templateWindowSizeSq, bm, bmOrig);
Test1dTransform<short, int, short>(thrMapTransform, 32, templateWindowSizeSq, bm, bmOrig);
Test1dTransform<short, int, short>(thrMapTransform, 64, templateWindowSizeSq, bm, bmOrig);
// Verify shrinkage
Test1dTransform<short, int, short>(thrMapShrinkage, 2, templateWindowSizeSq, bm, bmOrig, 6);
Test1dTransform<short, int, short>(thrMapShrinkage, 4, templateWindowSizeSq, bm, bmOrig, 6);
Test1dTransform<short, int, short>(thrMapShrinkage, 8, templateWindowSizeSq, bm, bmOrig, 6);
Test1dTransform<short, int, short>(thrMapShrinkage, 16, templateWindowSizeSq, bm, bmOrig, 6);
Test1dTransform<short, int, short>(thrMapShrinkage, 32, templateWindowSizeSq, bm, bmOrig, 6);
Test1dTransform<short, int, short>(thrMapShrinkage, 64, templateWindowSizeSq, bm, bmOrig, 14);
}
const float sqrt2 = std::sqrt(2.0f);
TEST(xphoto_DenoisingBm3dTransforms, regression_1D_generate)
{
const int numberOfElements = 8;
const int arrSize = (numberOfElements << 1) - 1;
float *thrMap1D = NULL;
HaarTransform<short, short>::calcThresholdMap1D(thrMap1D, numberOfElements);
// Expected array
const float kThrMap1D[arrSize] = {
1.0f, // 1 element
sqrt2 / 2.0f, sqrt2, // 2 elements
0.5f, 1.0f, sqrt2, sqrt2, // 4 elements
sqrt2 / 4.0f, sqrt2 / 2.0f, 1.0f, 1.0f, sqrt2, sqrt2, sqrt2, sqrt2 // 8 elements
};
for (int j = 0; j < arrSize; ++j)
ASSERT_EQ(thrMap1D[j], kThrMap1D[j]);
delete[] thrMap1D;
}
TEST(xphoto_DenoisingBm3dTransforms, regression_2D_generate_4x4)
{
const int templateWindowSize = 4;
float *thrMap2D = NULL;
HaarTransform<short, short>::calcThresholdMap2D(thrMap2D, templateWindowSize);
// Expected array
const float kThrMap4x4[templateWindowSize * templateWindowSize] = {
0.25f, 0.5f, sqrt2 / 2.0f, sqrt2 / 2.0f,
0.5f, 1.0f, sqrt2, sqrt2,
sqrt2 / 2.0f, sqrt2, 2.0f, 2.0f,
sqrt2 / 2.0f, sqrt2, 2.0f, 2.0f
};
for (int j = 0; j < templateWindowSize * templateWindowSize; ++j)
ASSERT_EQ(thrMap2D[j], kThrMap4x4[j]);
delete[] thrMap2D;
}
TEST(xphoto_DenoisingBm3dTransforms, regression_2D_generate_8x8)
{
const int templateWindowSize = 8;
float *thrMap2D = NULL;
HaarTransform<short, short>::calcThresholdMap2D(thrMap2D, templateWindowSize);
// Expected array
const float kThrMap8x8[templateWindowSize * templateWindowSize] = {
0.125f, 0.25f, sqrt2 / 4.0f, sqrt2 / 4.0f, 0.5f, 0.5f, 0.5f, 0.5f,
0.25f, 0.5f, sqrt2 / 2.0f, sqrt2 / 2.0f, 1.0f, 1.0f, 1.0f, 1.0f,
sqrt2 / 4.0f, sqrt2 / 2.0f, 1.0f, 1.0f, sqrt2, sqrt2, sqrt2, sqrt2,
sqrt2 / 4.0f, sqrt2 / 2.0f, 1.0f, 1.0f, sqrt2, sqrt2, sqrt2, sqrt2,
0.5f, 1.0f, sqrt2, sqrt2, 2.0f, 2.0f, 2.0f, 2.0f,
0.5f, 1.0f, sqrt2, sqrt2, 2.0f, 2.0f, 2.0f, 2.0f,
0.5f, 1.0f, sqrt2, sqrt2, 2.0f, 2.0f, 2.0f, 2.0f,
0.5f, 1.0f, sqrt2, sqrt2, 2.0f, 2.0f, 2.0f, 2.0f
};
for (int j = 0; j < templateWindowSize * templateWindowSize; ++j)
ASSERT_EQ(thrMap2D[j], kThrMap8x8[j]);
delete[] thrMap2D;
}
TEST(xphoto_Bm3dDenoising, powerOf2)
{
ASSERT_EQ(8, getLargestPowerOf2SmallerThan(9));
ASSERT_EQ(16, getLargestPowerOf2SmallerThan(21));
ASSERT_EQ(4, getLargestPowerOf2SmallerThan(7));
ASSERT_EQ(8, getLargestPowerOf2SmallerThan(8));
ASSERT_EQ(4, getLargestPowerOf2SmallerThan(5));
ASSERT_EQ(4, getLargestPowerOf2SmallerThan(4));
ASSERT_EQ(2, getLargestPowerOf2SmallerThan(3));
ASSERT_EQ(1, getLargestPowerOf2SmallerThan(1));
ASSERT_EQ(0, getLargestPowerOf2SmallerThan(0));
}
#endif // TEST_TRANSFORMS
}} // namespace
#endif // OPENCV_ENABLE_NONFREE
+99
View File
@@ -0,0 +1,99 @@
// 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 {
void ref_autowbGrayworld(InputArray _src, OutputArray _dst, float thresh)
{
Mat src = _src.getMat();
_dst.create(src.size(), src.type());
Mat dst = _dst.getMat();
int width = src.cols,
height = src.rows,
N = width*height,
N3 = N*3;
// Calculate sum of pixel values of each channel
const uchar* src_data = src.ptr<uchar>(0);
unsigned long sum1 = 0, sum2 = 0, sum3 = 0;
int i = 0;
unsigned int minRGB, maxRGB, thresh255 = cvRound(thresh * 255);
for ( ; i < N3; i += 3 )
{
minRGB = std::min(src_data[i], std::min(src_data[i + 1], src_data[i + 2]));
maxRGB = std::max(src_data[i], std::max(src_data[i + 1], src_data[i + 2]));
if ( (maxRGB - minRGB) * 255 > thresh255 * maxRGB ) continue;
sum1 += src_data[i];
sum2 += src_data[i + 1];
sum3 += src_data[i + 2];
}
// Find inverse of averages
double inv1 = sum1 == 0 ? 0.f : (double)N / (double)sum1,
inv2 = sum2 == 0 ? 0.f : (double)N / (double)sum2,
inv3 = sum3 == 0 ? 0.f : (double)N / (double)sum3;
// Find maximum
double inv_max = std::max(std::max(inv1, inv2), inv3);
// Scale by maximum
if ( inv_max > 0 )
{
inv1 = (double) inv1 / inv_max;
inv2 = (double) inv2 / inv_max;
inv3 = (double) inv3 / inv_max;
}
// Fixed point arithmetic, mul by 2^8 then shift back 8 bits
int i_inv1 = cvRound(inv1 * (1 << 8)),
i_inv2 = cvRound(inv2 * (1 << 8)),
i_inv3 = cvRound(inv3 * (1 << 8));
// Scale input pixel values
uchar* dst_data = dst.ptr<uchar>(0);
i = 0;
for ( ; i < N3; i += 3 )
{
dst_data[i] = (uchar)((src_data[i] * i_inv1) >> 8);
dst_data[i + 1] = (uchar)((src_data[i + 1] * i_inv2) >> 8);
dst_data[i + 2] = (uchar)((src_data[i + 2] * i_inv3) >> 8);
}
}
TEST(xphoto_grayworld_white_balance, regression)
{
String dir = cvtest::TS::ptr()->get_data_path() + "cv/xphoto/simple_white_balance/";
const int nTests = 8;
const float wb_thresh = 0.5f;
const float acc_thresh = 2.f;
Ptr<xphoto::GrayworldWB> wb = xphoto::createGrayworldWB();
wb->setSaturationThreshold(wb_thresh);
for ( int i = 0; i < nTests; ++i )
{
String srcName = dir + format("sources/%02d.png", i + 1);
Mat src = imread(srcName, IMREAD_COLOR);
ASSERT_TRUE(!src.empty());
Mat referenceResult;
ref_autowbGrayworld(src, referenceResult, wb_thresh);
Mat currentResult;
wb->balanceWhite(src, currentResult);
ASSERT_LE(cv::norm(currentResult, referenceResult, NORM_INF), acc_thresh);
// test the 16-bit depth:
Mat currentResult_16U, src_16U;
src.convertTo(src_16U, CV_16UC3, 256.0);
wb->balanceWhite(src_16U, currentResult_16U);
currentResult_16U.convertTo(currentResult, CV_8UC3, 1/256.0);
ASSERT_LE(cv::norm(currentResult, referenceResult, NORM_INF), acc_thresh);
}
}
}} // namespace
+71
View File
@@ -0,0 +1,71 @@
// 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 {
using namespace cv::xphoto;
#ifdef OPENCV_ENABLE_NONFREE
void loadImage(string path, Mat &img)
{
img = imread(path, -1);
ASSERT_FALSE(img.empty()) << "Could not load input image " << path;
}
void checkEqual(Mat img0, Mat img1, double threshold, const string& name)
{
double max = 1.0;
minMaxLoc(abs(img0 - img1), NULL, &max);
ASSERT_FALSE(max > threshold) << "max=" << max << " threshold=" << threshold << " method=" << name;
}
TEST(Photo_Tonemap, Durand_regression)
{
string test_path = string(cvtest::TS::ptr()->get_data_path()) + "cv/hdr/tonemap/";
Mat img, expected, result;
loadImage(test_path + "image.hdr", img);
float gamma = 2.2f;
Ptr<TonemapDurand> durand = createTonemapDurand(gamma);
durand->process(img, result);
loadImage(test_path + "durand.png", expected);
result.convertTo(result, CV_8UC3, 255);
checkEqual(result, expected, 3, "Durand");
}
TEST(Photo_Tonemap, Durand_property_regression)
{
const float gamma = 1.0f;
const float contrast = 2.0f;
const float saturation = 3.0f;
const float sigma_color = 4.0f;
const float sigma_space = 5.0f;
const Ptr<TonemapDurand> durand1 = createTonemapDurand(gamma, contrast, saturation, sigma_color, sigma_space);
ASSERT_EQ(gamma, durand1->getGamma());
ASSERT_EQ(contrast, durand1->getContrast());
ASSERT_EQ(saturation, durand1->getSaturation());
ASSERT_EQ(sigma_space, durand1->getSigmaSpace());
ASSERT_EQ(sigma_color, durand1->getSigmaColor());
const Ptr<TonemapDurand> durand2 = createTonemapDurand();
durand2->setGamma(gamma);
durand2->setContrast(contrast);
durand2->setSaturation(saturation);
durand2->setSigmaColor(sigma_color);
durand2->setSigmaSpace(sigma_space);
ASSERT_EQ(gamma, durand2->getGamma());
ASSERT_EQ(contrast, durand2->getContrast());
ASSERT_EQ(saturation, durand2->getSaturation());
ASSERT_EQ(sigma_color, durand2->getSigmaColor());
ASSERT_EQ(sigma_space, durand2->getSigmaSpace());
}
#endif // OPENCV_ENABLE_NONFREE
}} // namespace
+75
View File
@@ -0,0 +1,75 @@
// 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 {
using namespace xphoto;
static void test_inpainting(const Size inputSize, InpaintTypes mode, double expected_psnr, ImreadModes inputMode = IMREAD_COLOR)
{
string original_path = cvtest::findDataFile("cv/shared/lena.png");
string mask_path = cvtest::findDataFile("cv/inpaint/mask.png");
Mat original_ = imread(original_path, inputMode);
ASSERT_FALSE(original_.empty()) << "Could not load input image " << original_path;
Mat mask_ = imread(mask_path, IMREAD_GRAYSCALE);
ASSERT_FALSE(mask_.empty()) << "Could not load error mask " << mask_path;
Mat original, mask;
resize(original_, original, inputSize, 0.0, 0.0, INTER_AREA);
resize(mask_, mask, inputSize, 0.0, 0.0, INTER_NEAREST);
Mat mask_valid = (mask == 0);
Mat im_distorted(inputSize, original.type(), Scalar::all(0));
original.copyTo(im_distorted, mask_valid);
Mat reconstructed;
xphoto::inpaint(im_distorted, mask_valid, reconstructed, mode);
double adiff_psnr = cvtest::PSNR(original, reconstructed);
EXPECT_LE(expected_psnr, adiff_psnr);
#if 0
imshow("original", original);
imshow("im_distorted", im_distorted);
imshow("reconstructed", reconstructed);
std::cout << "adiff_psnr=" << adiff_psnr << std::endl;
waitKey();
#endif
}
TEST(xphoto_inpaint, smoke_FSR_FAST) // fast smoke test, input doesn't fit well for tested algorithm
{
test_inpainting(Size(128, 128), INPAINT_FSR_FAST, 30);
}
TEST(xphoto_inpaint, smoke_FSR_BEST) // fast smoke test, input doesn't fit well for tested algorithm
{
applyTestTag(CV_TEST_TAG_LONG);
test_inpainting(Size(128, 128), INPAINT_FSR_BEST, 30);
}
TEST(xphoto_inpaint, smoke_grayscale_FSR_FAST) // fast smoke test, input doesn't fit well for tested algorithm
{
test_inpainting(Size(128, 128), INPAINT_FSR_FAST, 30, IMREAD_GRAYSCALE);
}
TEST(xphoto_inpaint, smoke_grayscale_FSR_BEST) // fast smoke test, input doesn't fit well for tested algorithm
{
test_inpainting(Size(128, 128), INPAINT_FSR_BEST, 30, IMREAD_GRAYSCALE);
}
TEST(xphoto_inpaint, regression_FSR_FAST)
{
test_inpainting(Size(512, 512), INPAINT_FSR_FAST, 39.5);
}
TEST(xphoto_inpaint, regression_FSR_BEST)
{
applyTestTag(CV_TEST_TAG_VERYLONG); // add --test_tag_enable=verylong to run this test
test_inpainting(Size(512, 512), INPAINT_FSR_BEST, 39.6);
}
}} // namespace
@@ -0,0 +1,47 @@
// 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 {
TEST(xphoto_simplefeatures, regression)
{
float acc_thresh = 0.01f;
// Generate a test image:
Mat test_im(1000, 1000, CV_8UC3);
RNG rng(1234);
rng.fill(test_im, RNG::NORMAL, Scalar(64, 100, 128), Scalar(10, 10, 10));
cvtest::threshold(test_im, test_im, 200.0, 255.0, THRESH_TRUNC);
test_im.at<Vec3b>(0, 0) = Vec3b(240, 220, 200);
// Which should have the following features:
Vec2f ref1(128.0f / (64 + 100 + 128), 100.0f / (64 + 100 + 128));
Vec2f ref2(200.0f / (240 + 220 + 200), 220.0f / (240 + 220 + 200));
vector<Vec2f> dst_features;
Ptr<xphoto::LearningBasedWB> wb = xphoto::createLearningBasedWB();
wb->setRangeMaxVal(255);
wb->setSaturationThreshold(0.98f);
wb->setHistBinNum(64);
wb->extractSimpleFeatures(test_im, dst_features);
ASSERT_LE(cv::norm(dst_features[0], ref1, NORM_INF), acc_thresh);
ASSERT_LE(cv::norm(dst_features[1], ref2, NORM_INF), acc_thresh);
ASSERT_LE(cv::norm(dst_features[2], ref1, NORM_INF), acc_thresh);
ASSERT_LE(cv::norm(dst_features[3], ref1, NORM_INF), acc_thresh);
// check 16 bit depth:
test_im.convertTo(test_im, CV_16U, 256.0);
wb->setRangeMaxVal(65535);
wb->setSaturationThreshold(0.98f);
wb->setHistBinNum(128);
wb->extractSimpleFeatures(test_im, dst_features);
ASSERT_LE(cv::norm(dst_features[0], ref1, NORM_INF), acc_thresh);
ASSERT_LE(cv::norm(dst_features[1], ref2, NORM_INF), acc_thresh);
ASSERT_LE(cv::norm(dst_features[2], ref1, NORM_INF), acc_thresh);
ASSERT_LE(cv::norm(dst_features[3], ref1, NORM_INF), acc_thresh);
}
}} // namespace
+6
View File
@@ -0,0 +1,6 @@
// 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"
CV_TEST_MAIN("")
+109
View File
@@ -0,0 +1,109 @@
// 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 {
Mat testOilPainting(Mat imgSrc, int halfSize, int dynRatio, int colorSpace)
{
vector<int> histogramme;
vector<Vec3f> moyenneRGB;
Mat dst(imgSrc.size(), imgSrc.type());
Mat lum;
if (imgSrc.channels() != 1)
{
cvtColor(imgSrc, lum, colorSpace);
if (lum.channels() > 1)
{
extractChannel(lum, lum, 0);
}
}
else
lum = imgSrc.clone();
lum = lum / dynRatio;
if (dst.channels() == 3)
for (int y = 0; y < imgSrc.rows; y++)
{
Vec3b *vDst = dst.ptr<Vec3b>(y);
for (int x = 0; x < imgSrc.cols; x++, vDst++) //for each pixel
{
Mat mask(lum.size(), CV_8UC1, Scalar::all(0));
Rect r(Point(x - halfSize, y - halfSize), Size(2 * halfSize + 1, 2 * halfSize + 1));
r = r & Rect(Point(0, 0), lum.size());
mask(r).setTo(255);
int histSize[] = { 256 };
float hranges[] = { 0, 256 };
const float* ranges[] = { hranges };
Mat hist;
int channels[] = { 0 };
calcHist(&lum, 1, channels, mask, hist, 1, histSize, ranges, true, false);
double maxVal = 0;
Point pMin, pMax;
minMaxLoc(hist, 0, &maxVal, &pMin, &pMax);
mask.setTo(0, lum != static_cast<int>(pMax.x));
Scalar v = mean(imgSrc, mask);
*vDst = Vec3b(static_cast<uchar>(v[0]), static_cast<uchar>(v[1]), static_cast<uchar>(v[2]));
}
}
else
for (int y = 0; y < imgSrc.rows; y++)
{
uchar *vDst = dst.ptr<uchar>(y);
for (int x = 0; x < imgSrc.cols; x++, vDst++) //for each pixel
{
Mat mask(lum.size(), CV_8UC1, Scalar::all(0));
Rect r(Point(x - halfSize, y - halfSize), Size(2 * halfSize + 1, 2 * halfSize + 1));
r = r & Rect(Point(0, 0), lum.size());
mask(r).setTo(255);
int histSize[] = { 256 };
float hranges[] = { 0, 256 };
const float* ranges[] = { hranges };
Mat hist;
int channels[] = { 0 };
calcHist(&lum, 1, channels, mask, hist, 1, histSize, ranges, true, false);
double maxVal = 0;
Point pMin, pMax;
minMaxLoc(hist, 0, &maxVal, &pMin, &pMax);
mask.setTo(0, lum != static_cast<int>(pMax.x));
Scalar v = mean(imgSrc, mask);
*vDst = static_cast<uchar>(v[0]);
}
}
return dst;
}
TEST(xphoto_oil_painting, regression)
{
string folder = string(cvtest::TS::ptr()->get_data_path()) + "cv/inpaint/";
Mat orig = imread(folder+"exp1.png", IMREAD_COLOR);
ASSERT_TRUE(!orig.empty());
resize(orig, orig, Size(100, 100));
Mat dst1, dst2, dd;
xphoto::oilPainting(orig, dst1, 3, 5, COLOR_BGR2GRAY);
dst2 = testOilPainting(orig, 3, 5, COLOR_BGR2GRAY);
absdiff(dst1, dst2, dd);
vector<Mat> plane;
split(dd, plane);
for (auto p : plane)
{
double maxVal;
Point pIdx;
minMaxLoc(p, NULL, &maxVal, NULL, &pIdx);
int v = p.at<uchar>(pIdx);
ASSERT_LE(v, 2);
}
Mat orig2 = imread(folder + "exp1.png",IMREAD_GRAYSCALE);
ASSERT_TRUE(!orig2.empty());
resize(orig2, orig2, Size(100, 100));
Mat dst3, dst4, ddd;
xphoto::oilPainting(orig2, dst3, 3, 5, COLOR_BGR2GRAY);
dst4 = testOilPainting(orig2, 3, 5, COLOR_BGR2GRAY);
absdiff(dst3, dst4, ddd);
double maxVal;
Point pIdx;
minMaxLoc(ddd, NULL, &maxVal, NULL, &pIdx);
ASSERT_LE(ddd.at<uchar>(pIdx), 2);
}
}} // namespace
+10
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.
#ifndef __OPENCV_TEST_PRECOMP_HPP__
#define __OPENCV_TEST_PRECOMP_HPP__
#include "opencv2/xphoto.hpp"
#include "opencv2/ts.hpp"
#endif