vendor: OpenCV 5.0.0 snapshot at 40738fb16ceddb5fb3fea747585f7ce6abb0605b

This commit is contained in:
Gitea Mirror Bot
2026-08-22 00:10:33 +08:00
commit f7f077da11
6933 changed files with 2335208 additions and 0 deletions
@@ -0,0 +1,239 @@
/*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
// Nathan, liujun@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 {
PARAM_TEST_CASE(AccumulateBase, std::pair<MatDepth, MatDepth>, Channels, bool)
{
int sdepth, ddepth, channels;
bool useRoi;
double alpha;
TEST_DECLARE_INPUT_PARAMETER(src);
TEST_DECLARE_INPUT_PARAMETER(mask);
TEST_DECLARE_INPUT_PARAMETER(src2);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
virtual void SetUp()
{
const std::pair<MatDepth, MatDepth> depths = GET_PARAM(0);
sdepth = depths.first, ddepth = depths.second;
channels = GET_PARAM(1);
useRoi = GET_PARAM(2);
}
void random_roi()
{
const int stype = CV_MAKE_TYPE(sdepth, channels),
dtype = CV_MAKE_TYPE(ddepth, channels);
Size roiSize = randomSize(1, 10);
Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, roiSize, srcBorder, stype, -MAX_VALUE, MAX_VALUE);
Border maskBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(mask, mask_roi, roiSize, maskBorder, CV_8UC1, -MAX_VALUE, MAX_VALUE);
cvtest::threshold(mask, mask, 80, 255, THRESH_BINARY);
Border src2Border = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(src2, src2_roi, roiSize, src2Border, stype, -MAX_VALUE, MAX_VALUE);
Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(dst, dst_roi, roiSize, dstBorder, dtype, -MAX_VALUE, MAX_VALUE);
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_INPUT_PARAMETER(mask);
UMAT_UPLOAD_INPUT_PARAMETER(src2);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
alpha = randomDouble(-5, 5);
}
};
/////////////////////////////////// Accumulate ///////////////////////////////////
typedef AccumulateBase Accumulate;
OCL_TEST_P(Accumulate, Mat)
{
for (int i = 0; i < test_loop_times; ++i)
{
random_roi();
OCL_OFF(cv::accumulate(src_roi, dst_roi));
OCL_ON(cv::accumulate(usrc_roi, udst_roi));
OCL_EXPECT_MATS_NEAR(dst, 1e-6);
}
}
OCL_TEST_P(Accumulate, Mask)
{
for (int i = 0; i < test_loop_times; ++i)
{
random_roi();
OCL_OFF(cv::accumulate(src_roi, dst_roi, mask_roi));
OCL_ON(cv::accumulate(usrc_roi, udst_roi, umask_roi));
OCL_EXPECT_MATS_NEAR(dst, 1e-6);
}
}
/////////////////////////////////// AccumulateSquare ///////////////////////////////////
typedef AccumulateBase AccumulateSquare;
OCL_TEST_P(AccumulateSquare, Mat)
{
for (int i = 0; i < test_loop_times; ++i)
{
random_roi();
OCL_OFF(cv::accumulateSquare(src_roi, dst_roi));
OCL_ON(cv::accumulateSquare(usrc_roi, udst_roi));
OCL_EXPECT_MATS_NEAR(dst, 1e-2);
}
}
OCL_TEST_P(AccumulateSquare, Mask)
{
for (int i = 0; i < test_loop_times; ++i)
{
random_roi();
OCL_OFF(cv::accumulateSquare(src_roi, dst_roi, mask_roi));
OCL_ON(cv::accumulateSquare(usrc_roi, udst_roi, umask_roi));
OCL_EXPECT_MATS_NEAR(dst, 1e-2);
}
}
/////////////////////////////////// AccumulateProduct ///////////////////////////////////
typedef AccumulateBase AccumulateProduct;
OCL_TEST_P(AccumulateProduct, Mat)
{
for (int i = 0; i < test_loop_times; ++i)
{
random_roi();
OCL_OFF(cv::accumulateProduct(src_roi, src2_roi, dst_roi));
OCL_ON(cv::accumulateProduct(usrc_roi, usrc2_roi, udst_roi));
OCL_EXPECT_MATS_NEAR(dst, 1e-2);
}
}
OCL_TEST_P(AccumulateProduct, Mask)
{
for (int i = 0; i < test_loop_times; ++i)
{
random_roi();
OCL_OFF(cv::accumulateProduct(src_roi, src2_roi, dst_roi, mask_roi));
OCL_ON(cv::accumulateProduct(usrc_roi, usrc2_roi, udst_roi, umask_roi));
OCL_EXPECT_MATS_NEAR(dst, 1e-2);
}
}
/////////////////////////////////// AccumulateWeighted ///////////////////////////////////
typedef AccumulateBase AccumulateWeighted;
OCL_TEST_P(AccumulateWeighted, Mat)
{
for (int i = 0; i < test_loop_times; ++i)
{
random_roi();
OCL_OFF(cv::accumulateWeighted(src_roi, dst_roi, alpha));
OCL_ON(cv::accumulateWeighted(usrc_roi, udst_roi, alpha));
OCL_EXPECT_MATS_NEAR(dst, 1e-2);
}
}
OCL_TEST_P(AccumulateWeighted, Mask)
{
for (int i = 0; i < test_loop_times; ++i)
{
random_roi();
OCL_OFF(cv::accumulateWeighted(src_roi, dst_roi, alpha));
OCL_ON(cv::accumulateWeighted(usrc_roi, udst_roi, alpha));
OCL_EXPECT_MATS_NEAR(dst, 1e-2);
}
}
/////////////////////////////////// Instantiation ///////////////////////////////////
#define OCL_DEPTH_ALL_COMBINATIONS \
testing::Values(std::make_pair<MatDepth, MatDepth>(CV_8U, CV_32F), \
std::make_pair<MatDepth, MatDepth>(CV_16U, CV_32F), \
std::make_pair<MatDepth, MatDepth>(CV_32F, CV_32F), \
std::make_pair<MatDepth, MatDepth>(CV_8U, CV_64F), \
std::make_pair<MatDepth, MatDepth>(CV_16U, CV_64F), \
std::make_pair<MatDepth, MatDepth>(CV_32F, CV_64F), \
std::make_pair<MatDepth, MatDepth>(CV_64F, CV_64F))
OCL_INSTANTIATE_TEST_CASE_P(ImgProc, Accumulate, Combine(OCL_DEPTH_ALL_COMBINATIONS, OCL_ALL_CHANNELS, Bool()));
OCL_INSTANTIATE_TEST_CASE_P(ImgProc, AccumulateSquare, Combine(OCL_DEPTH_ALL_COMBINATIONS, OCL_ALL_CHANNELS, Bool()));
OCL_INSTANTIATE_TEST_CASE_P(ImgProc, AccumulateProduct, Combine(OCL_DEPTH_ALL_COMBINATIONS, OCL_ALL_CHANNELS, Bool()));
OCL_INSTANTIATE_TEST_CASE_P(ImgProc, AccumulateWeighted, Combine(OCL_DEPTH_ALL_COMBINATIONS, OCL_ALL_CHANNELS, Bool()));
} } // namespace opencv_test::ocl
#endif
+127
View File
@@ -0,0 +1,127 @@
/*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
// Nathan, liujun@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 {
PARAM_TEST_CASE(BlendLinear, MatDepth, Channels, bool)
{
int depth, channels;
bool useRoi;
TEST_DECLARE_INPUT_PARAMETER(src1);
TEST_DECLARE_INPUT_PARAMETER(src2);
TEST_DECLARE_INPUT_PARAMETER(weights2);
TEST_DECLARE_INPUT_PARAMETER(weights1);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
virtual void SetUp()
{
depth = GET_PARAM(0);
channels = GET_PARAM(1);
useRoi = GET_PARAM(2);
}
void random_roi()
{
const int type = CV_MAKE_TYPE(depth, channels);
const double upValue = 256;
Size roiSize = randomSize(1, MAX_VALUE);
Border src1Border = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(src1, src1_roi, roiSize, src1Border, type, -upValue, upValue);
Border src2Border = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(src2, src2_roi, roiSize, src2Border, type, -upValue, upValue);
Border weights1Border = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(weights1, weights1_roi, roiSize, weights1Border, CV_32FC1, -upValue, upValue);
Border weights2Border = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(weights2, weights2_roi, roiSize, weights2Border, CV_32FC1, 1e-2, upValue);
weights2_roi -= weights1_roi;
CV_Assert(checkNorm2(weights2_roi, weights2(Rect(weights2Border.lef, weights2Border.top,
roiSize.width, roiSize.height))) < 1e-6);
Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(dst, dst_roi, roiSize, dstBorder, type, 5, 16);
UMAT_UPLOAD_INPUT_PARAMETER(src1);
UMAT_UPLOAD_INPUT_PARAMETER(src2);
UMAT_UPLOAD_INPUT_PARAMETER(weights1);
UMAT_UPLOAD_INPUT_PARAMETER(weights2);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
}
void Near(double eps = 0.0)
{
OCL_EXPECT_MATS_NEAR(dst, eps);
}
};
OCL_TEST_P(BlendLinear, Accuracy)
{
for (int i = 0; i < test_loop_times; ++i)
{
random_roi();
OCL_OFF(cv::blendLinear(src1_roi, src2_roi, weights1_roi, weights2_roi, dst_roi));
OCL_ON(cv::blendLinear(usrc1_roi, usrc2_roi, uweights1_roi, uweights2_roi, udst_roi));
Near(depth <= CV_32S ? 1.0 : 0.5);
}
}
OCL_INSTANTIATE_TEST_CASE_P(ImgProc, BlendLinear, Combine(testing::Values(CV_8U, CV_32F), OCL_ALL_CHANNELS, Bool()));
} } // namespace opencv_test::ocl
#endif
+236
View File
@@ -0,0 +1,236 @@
/*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.
//
// 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 {
////////////////////////////////////////// boxFilter ///////////////////////////////////////////////////////
PARAM_TEST_CASE(BoxFilterBase, MatDepth, Channels, BorderType, bool, bool)
{
static const int kernelMinSize = 2;
static const int kernelMaxSize = 10;
int depth, cn, borderType;
Size ksize, dsize;
Point anchor;
bool normalize, useRoi;
TEST_DECLARE_INPUT_PARAMETER(src);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
virtual void SetUp()
{
depth = GET_PARAM(0);
cn = GET_PARAM(1);
borderType = GET_PARAM(2); // only not isolated border tested, because CPU module doesn't support isolated border case.
normalize = GET_PARAM(3);
useRoi = GET_PARAM(4);
}
void random_roi()
{
int type = CV_MAKE_TYPE(depth, cn);
ksize = randomSize(kernelMinSize, kernelMaxSize);
Size roiSize = randomSize(ksize.width, MAX_VALUE, ksize.height, MAX_VALUE);
Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, roiSize, srcBorder, type, -MAX_VALUE, MAX_VALUE);
Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(dst, dst_roi, roiSize, dstBorder, type, -MAX_VALUE, MAX_VALUE);
anchor.x = randomInt(-1, ksize.width);
anchor.y = randomInt(-1, ksize.height);
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
}
void Near(double threshold = 0.0)
{
OCL_EXPECT_MATS_NEAR(dst, threshold);
}
};
typedef BoxFilterBase BoxFilter;
OCL_TEST_P(BoxFilter, Mat)
{
for (int j = 0; j < test_loop_times; j++)
{
random_roi();
OCL_OFF(cv::boxFilter(src_roi, dst_roi, -1, ksize, anchor, normalize, borderType));
OCL_ON(cv::boxFilter(usrc_roi, udst_roi, -1, ksize, anchor, normalize, borderType));
Near(depth <= CV_32S ? 1 : 3e-3);
}
}
typedef BoxFilterBase SqrBoxFilter;
OCL_TEST_P(SqrBoxFilter, Mat)
{
for (int j = 0; j < test_loop_times; j++)
{
random_roi();
int ddepth = depth == CV_8U ? CV_32S : CV_64F;
OCL_OFF(cv::sqrBoxFilter(src_roi, dst_roi, ddepth, ksize, anchor, normalize, borderType));
OCL_ON(cv::sqrBoxFilter(usrc_roi, udst_roi, ddepth, ksize, anchor, normalize, borderType));
Near(depth <= CV_32S ? 1 : 7e-2);
}
}
OCL_INSTANTIATE_TEST_CASE_P(ImageProc, BoxFilter,
Combine(
Values(CV_8U, CV_16U, CV_16S, CV_32S, CV_32F),
OCL_ALL_CHANNELS,
Values((BorderType)BORDER_CONSTANT,
(BorderType)BORDER_REPLICATE,
(BorderType)BORDER_REFLECT,
(BorderType)BORDER_REFLECT_101),
Bool(),
Bool() // ROI
)
);
OCL_INSTANTIATE_TEST_CASE_P(ImageProc, SqrBoxFilter,
Combine(
Values(CV_8U, CV_16U, CV_16S, CV_32F, CV_64F),
OCL_ALL_CHANNELS,
Values((BorderType)BORDER_CONSTANT,
(BorderType)BORDER_REPLICATE,
(BorderType)BORDER_REFLECT,
(BorderType)BORDER_REFLECT_101),
Bool(),
Bool() // ROI
)
);
PARAM_TEST_CASE(BoxFilter3x3_cols16_rows2_Base, MatDepth, Channels, BorderType, bool, bool)
{
int depth, cn, borderType;
Size ksize, dsize;
Point anchor;
bool normalize, useRoi;
TEST_DECLARE_INPUT_PARAMETER(src);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
virtual void SetUp()
{
depth = GET_PARAM(0);
cn = GET_PARAM(1);
borderType = GET_PARAM(2); // only not isolated border tested, because CPU module doesn't support isolated border case.
normalize = GET_PARAM(3);
useRoi = GET_PARAM(4);
}
void random_roi()
{
int type = CV_MAKE_TYPE(depth, cn);
ksize = Size(3,3);
Size roiSize = randomSize(ksize.width, MAX_VALUE, ksize.height, MAX_VALUE);
roiSize.width = std::max(ksize.width + 13, roiSize.width & (~0xf));
roiSize.height = std::max(ksize.height + 1, roiSize.height & (~0x1));
Border srcBorder = {0, 0, 0, 0};
randomSubMat(src, src_roi, roiSize, srcBorder, type, -MAX_VALUE, MAX_VALUE);
Border dstBorder = {0, 0, 0, 0};
randomSubMat(dst, dst_roi, roiSize, dstBorder, type, -MAX_VALUE, MAX_VALUE);
anchor.x = -1;
anchor.y = -1;
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
}
void Near(double threshold = 0.0)
{
OCL_EXPECT_MATS_NEAR(dst, threshold);
}
};
typedef BoxFilter3x3_cols16_rows2_Base BoxFilter3x3_cols16_rows2;
OCL_TEST_P(BoxFilter3x3_cols16_rows2, Mat)
{
for (int j = 0; j < test_loop_times; j++)
{
random_roi();
OCL_OFF(cv::boxFilter(src_roi, dst_roi, -1, ksize, anchor, normalize, borderType));
OCL_ON(cv::boxFilter(usrc_roi, udst_roi, -1, ksize, anchor, normalize, borderType));
Near(depth <= CV_32S ? 1 : 3e-3);
}
}
OCL_INSTANTIATE_TEST_CASE_P(ImageProc, BoxFilter3x3_cols16_rows2,
Combine(
Values((MatDepth)CV_8U),
Values((Channels)1),
Values((BorderType)BORDER_CONSTANT,
(BorderType)BORDER_REPLICATE,
(BorderType)BORDER_REFLECT,
(BorderType)BORDER_REFLECT_101),
Bool(),
Values(false) // ROI
)
);
} } // namespace opencv_test::ocl
#endif // HAVE_OPENCL
+140
View File
@@ -0,0 +1,140 @@
/*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 {
////////////////////////////////////////////////////////
// Canny
IMPLEMENT_PARAM_CLASS(ApertureSize, int)
IMPLEMENT_PARAM_CLASS(L2gradient, bool)
IMPLEMENT_PARAM_CLASS(UseRoi, bool)
PARAM_TEST_CASE(Canny, Channels, ApertureSize, L2gradient, UseRoi)
{
int cn, aperture_size;
bool useL2gradient, use_roi;
TEST_DECLARE_INPUT_PARAMETER(src);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
virtual void SetUp()
{
cn = GET_PARAM(0);
aperture_size = GET_PARAM(1);
useL2gradient = GET_PARAM(2);
use_roi = GET_PARAM(3);
}
void generateTestData()
{
Mat img = readImageType("shared/fruits.png", CV_8UC(cn));
ASSERT_FALSE(img.empty()) << "can't load shared/fruits.png";
Size roiSize = img.size();
int type = img.type();
Border srcBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, roiSize, srcBorder, type, 2, 100);
img.copyTo(src_roi);
Border dstBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(dst, dst_roi, roiSize, dstBorder, type, 5, 16);
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
}
};
OCL_TEST_P(Canny, Accuracy)
{
generateTestData();
const double low_thresh = 50.0, high_thresh = 100.0;
double eps = 0.03;
OCL_OFF(cv::Canny(src_roi, dst_roi, low_thresh, high_thresh, aperture_size, useL2gradient));
OCL_ON(cv::Canny(usrc_roi, udst_roi, low_thresh, high_thresh, aperture_size, useL2gradient));
EXPECT_MAT_SIMILAR(dst_roi, udst_roi, eps);
EXPECT_MAT_SIMILAR(dst, udst, eps);
}
OCL_TEST_P(Canny, AccuracyCustomGradient)
{
generateTestData();
const double low_thresh = 50.0, high_thresh = 100.0;
double eps = 0.03;
OCL_OFF(cv::Canny(src_roi, dst_roi, low_thresh, high_thresh, aperture_size, useL2gradient));
OCL_ON(
UMat dx, dy;
Sobel(usrc_roi, dx, CV_16S, 1, 0, aperture_size, 1, 0, BORDER_REPLICATE);
Sobel(usrc_roi, dy, CV_16S, 0, 1, aperture_size, 1, 0, BORDER_REPLICATE);
cv::Canny(dx, dy, udst_roi, low_thresh, high_thresh, useL2gradient);
);
EXPECT_MAT_SIMILAR(dst_roi, udst_roi, eps);
EXPECT_MAT_SIMILAR(dst, udst, eps);
}
OCL_INSTANTIATE_TEST_CASE_P(ImgProc, Canny, testing::Combine(
testing::Values(1, 3),
testing::Values(ApertureSize(3), ApertureSize(5)),
testing::Values(L2gradient(false), L2gradient(true)),
testing::Values(UseRoi(false), UseRoi(true))));
} // namespace ocl
} // namespace opencv_test
#endif // HAVE_OPENCL
+532
View File
@@ -0,0 +1,532 @@
/*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 {
///////////////////////////////////////////////////////////////////////////////////////////////////////
// cvtColor
PARAM_TEST_CASE(CvtColor, MatDepth, bool)
{
int depth;
bool use_roi;
TEST_DECLARE_INPUT_PARAMETER(src);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
virtual void SetUp()
{
depth = GET_PARAM(0);
use_roi = GET_PARAM(1);
}
virtual void generateTestData(int channelsIn, int channelsOut)
{
const int srcType = CV_MAKE_TYPE(depth, channelsIn);
const int dstType = CV_MAKE_TYPE(depth, channelsOut);
Size roiSize = randomSize(1, MAX_VALUE);
Border srcBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, roiSize, srcBorder, srcType, 2, 100);
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);
}
void Near(double threshold)
{
OCL_EXPECT_MATS_NEAR(dst, threshold);
}
void performTest(int channelsIn, int channelsOut, int code, double threshold = 1e-3)
{
for (int j = 0; j < test_loop_times; j++)
{
generateTestData(channelsIn, channelsOut);
OCL_OFF(cv::cvtColor(src_roi, dst_roi, code, channelsOut));
OCL_ON(cv::cvtColor(usrc_roi, udst_roi, code, channelsOut));
int h_limit = 256;
switch (code)
{
case COLOR_RGB2HLS: case COLOR_BGR2HLS:
h_limit = 180;
/* fallthrough */
case COLOR_RGB2HLS_FULL: case COLOR_BGR2HLS_FULL:
{
ASSERT_EQ(dst_roi.type(), udst_roi.type());
ASSERT_EQ(dst_roi.size(), udst_roi.size());
Mat gold, actual;
dst_roi.convertTo(gold, CV_32FC3);
udst_roi.getMat(ACCESS_READ).convertTo(actual, CV_32FC3);
Mat absdiff1, absdiff2, absdiff3;
cv::absdiff(gold, actual, absdiff1);
cv::absdiff(gold, actual + h_limit, absdiff2);
cv::absdiff(gold, actual - h_limit, absdiff3);
Mat diff = cv::min(cv::min(absdiff1, absdiff2), absdiff3);
EXPECT_LE(cvtest::norm(diff, NORM_INF), threshold);
break;
}
default:
Near(threshold);
}
}
}
};
#define CVTCODE(name) COLOR_ ## name
// RGB[A] <-> BGR[A]
OCL_TEST_P(CvtColor, BGR2BGRA) { performTest(3, 4, CVTCODE(BGR2BGRA)); }
OCL_TEST_P(CvtColor, RGB2RGBA) { performTest(3, 4, CVTCODE(RGB2RGBA)); }
OCL_TEST_P(CvtColor, BGRA2BGR) { performTest(4, 3, CVTCODE(BGRA2BGR)); }
OCL_TEST_P(CvtColor, RGBA2RGB) { performTest(4, 3, CVTCODE(RGBA2RGB)); }
OCL_TEST_P(CvtColor, BGR2RGBA) { performTest(3, 4, CVTCODE(BGR2RGBA)); }
OCL_TEST_P(CvtColor, RGB2BGRA) { performTest(3, 4, CVTCODE(RGB2BGRA)); }
OCL_TEST_P(CvtColor, RGBA2BGR) { performTest(4, 3, CVTCODE(RGBA2BGR)); }
OCL_TEST_P(CvtColor, BGRA2RGB) { performTest(4, 3, CVTCODE(BGRA2RGB)); }
OCL_TEST_P(CvtColor, BGR2RGB) { performTest(3, 3, CVTCODE(BGR2RGB)); }
OCL_TEST_P(CvtColor, RGB2BGR) { performTest(3, 3, CVTCODE(RGB2BGR)); }
OCL_TEST_P(CvtColor, BGRA2RGBA) { performTest(4, 4, CVTCODE(BGRA2RGBA)); }
OCL_TEST_P(CvtColor, RGBA2BGRA) { performTest(4, 4, CVTCODE(RGBA2BGRA)); }
// RGB <-> Gray
OCL_TEST_P(CvtColor, RGB2GRAY) { performTest(3, 1, CVTCODE(RGB2GRAY)); }
OCL_TEST_P(CvtColor, GRAY2RGB) { performTest(1, 3, CVTCODE(GRAY2RGB)); }
OCL_TEST_P(CvtColor, BGR2GRAY) { performTest(3, 1, CVTCODE(BGR2GRAY)); }
OCL_TEST_P(CvtColor, GRAY2BGR) { performTest(1, 3, CVTCODE(GRAY2BGR)); }
OCL_TEST_P(CvtColor, RGBA2GRAY) { performTest(4, 1, CVTCODE(RGBA2GRAY)); }
OCL_TEST_P(CvtColor, GRAY2RGBA) { performTest(1, 4, CVTCODE(GRAY2RGBA)); }
OCL_TEST_P(CvtColor, BGRA2GRAY) { performTest(4, 1, CVTCODE(BGRA2GRAY), cv::ocl::Device::getDefault().isNVidia() ? 1 : 1e-3); }
OCL_TEST_P(CvtColor, GRAY2BGRA) { performTest(1, 4, CVTCODE(GRAY2BGRA)); }
// RGB <-> YUV
OCL_TEST_P(CvtColor, RGB2YUV) { performTest(3, 3, CVTCODE(RGB2YUV)); }
OCL_TEST_P(CvtColor, BGR2YUV) { performTest(3, 3, CVTCODE(BGR2YUV)); }
OCL_TEST_P(CvtColor, RGBA2YUV) { performTest(4, 3, CVTCODE(RGB2YUV)); }
OCL_TEST_P(CvtColor, BGRA2YUV) { performTest(4, 3, CVTCODE(BGR2YUV)); }
OCL_TEST_P(CvtColor, YUV2RGB) { performTest(3, 3, CVTCODE(YUV2RGB)); }
OCL_TEST_P(CvtColor, YUV2BGR) { performTest(3, 3, CVTCODE(YUV2BGR)); }
OCL_TEST_P(CvtColor, YUV2RGBA) { performTest(3, 4, CVTCODE(YUV2RGB)); }
OCL_TEST_P(CvtColor, YUV2BGRA) { performTest(3, 4, CVTCODE(YUV2BGR)); }
// RGB <-> YCrCb
#define EPS_FOR_FLOATING_POINT(e) (CV_32F <= depth ? e : 1)
OCL_TEST_P(CvtColor, RGB2YCrCb) { performTest(3, 3, CVTCODE(RGB2YCrCb), EPS_FOR_FLOATING_POINT(1e-3)); }
OCL_TEST_P(CvtColor, BGR2YCrCb) { performTest(3, 3, CVTCODE(BGR2YCrCb), EPS_FOR_FLOATING_POINT(1e-3)); }
OCL_TEST_P(CvtColor, RGBA2YCrCb) { performTest(4, 3, CVTCODE(RGB2YCrCb), EPS_FOR_FLOATING_POINT(1e-3)); }
OCL_TEST_P(CvtColor, BGRA2YCrCb) { performTest(4, 3, CVTCODE(BGR2YCrCb), EPS_FOR_FLOATING_POINT(1e-3)); }
OCL_TEST_P(CvtColor, YCrCb2RGB) { performTest(3, 3, CVTCODE(YCrCb2RGB)); }
OCL_TEST_P(CvtColor, YCrCb2BGR) { performTest(3, 3, CVTCODE(YCrCb2BGR)); }
OCL_TEST_P(CvtColor, YCrCb2RGBA) { performTest(3, 4, CVTCODE(YCrCb2RGB)); }
OCL_TEST_P(CvtColor, YCrCb2BGRA) { performTest(3, 4, CVTCODE(YCrCb2BGR)); }
// RGB <-> XYZ
#ifdef HAVE_IPP
#define IPP_EPS depth <= CV_32S ? 1 : 5e-5
#else
#define IPP_EPS 1e-3
#endif
OCL_TEST_P(CvtColor, RGB2XYZ) { performTest(3, 3, CVTCODE(RGB2XYZ), IPP_EPS); }
OCL_TEST_P(CvtColor, BGR2XYZ) { performTest(3, 3, CVTCODE(BGR2XYZ), IPP_EPS); }
OCL_TEST_P(CvtColor, RGBA2XYZ) { performTest(4, 3, CVTCODE(RGB2XYZ), IPP_EPS); }
OCL_TEST_P(CvtColor, BGRA2XYZ) { performTest(4, 3, CVTCODE(BGR2XYZ), IPP_EPS); }
OCL_TEST_P(CvtColor, XYZ2RGB) { performTest(3, 3, CVTCODE(XYZ2RGB), IPP_EPS); }
OCL_TEST_P(CvtColor, XYZ2BGR) { performTest(3, 3, CVTCODE(XYZ2BGR), IPP_EPS); }
OCL_TEST_P(CvtColor, XYZ2RGBA) { performTest(3, 4, CVTCODE(XYZ2RGB), IPP_EPS); }
OCL_TEST_P(CvtColor, XYZ2BGRA) { performTest(3, 4, CVTCODE(XYZ2BGR), IPP_EPS); }
#undef IPP_EPS
// RGB <-> HSV
#ifdef HAVE_IPP
#define IPP_EPS depth <= CV_32S ? 1 : 4e-5
#else
#define IPP_EPS EPS_FOR_FLOATING_POINT(1e-3)
#endif
typedef CvtColor CvtColor8u32f;
OCL_TEST_P(CvtColor8u32f, RGB2HSV) { performTest(3, 3, CVTCODE(RGB2HSV), IPP_EPS); }
OCL_TEST_P(CvtColor8u32f, BGR2HSV) { performTest(3, 3, CVTCODE(BGR2HSV), IPP_EPS); }
OCL_TEST_P(CvtColor8u32f, RGBA2HSV) { performTest(4, 3, CVTCODE(RGB2HSV), IPP_EPS); }
OCL_TEST_P(CvtColor8u32f, BGRA2HSV) { performTest(4, 3, CVTCODE(BGR2HSV), IPP_EPS); }
OCL_TEST_P(CvtColor8u32f, RGB2HSV_FULL) { performTest(3, 3, CVTCODE(RGB2HSV_FULL), IPP_EPS); }
OCL_TEST_P(CvtColor8u32f, BGR2HSV_FULL) { performTest(3, 3, CVTCODE(BGR2HSV_FULL), IPP_EPS); }
OCL_TEST_P(CvtColor8u32f, RGBA2HSV_FULL) { performTest(4, 3, CVTCODE(RGB2HSV_FULL), IPP_EPS); }
OCL_TEST_P(CvtColor8u32f, BGRA2HSV_FULL) { performTest(4, 3, CVTCODE(BGR2HSV_FULL), IPP_EPS); }
#undef IPP_EPS
OCL_TEST_P(CvtColor8u32f, HSV2RGB) { performTest(3, 3, CVTCODE(HSV2RGB), depth == CV_8U ? 1 : 4e-1); }
OCL_TEST_P(CvtColor8u32f, HSV2BGR) { performTest(3, 3, CVTCODE(HSV2BGR), depth == CV_8U ? 1 : 4e-1); }
OCL_TEST_P(CvtColor8u32f, HSV2RGBA) { performTest(3, 4, CVTCODE(HSV2RGB), depth == CV_8U ? 1 : 4e-1); }
OCL_TEST_P(CvtColor8u32f, HSV2BGRA) { performTest(3, 4, CVTCODE(HSV2BGR), depth == CV_8U ? 1 : 4e-1); }
OCL_TEST_P(CvtColor8u32f, HSV2RGB_FULL) { performTest(3, 3, CVTCODE(HSV2RGB_FULL), depth == CV_8U ? 1 : 4e-1); }
OCL_TEST_P(CvtColor8u32f, HSV2BGR_FULL) { performTest(3, 3, CVTCODE(HSV2BGR_FULL), depth == CV_8U ? 1 : 4e-1); }
OCL_TEST_P(CvtColor8u32f, HSV2RGBA_FULL) { performTest(3, 4, CVTCODE(HSV2BGR_FULL), depth == CV_8U ? 1 : 4e-1); }
OCL_TEST_P(CvtColor8u32f, HSV2BGRA_FULL) { performTest(3, 4, CVTCODE(HSV2BGR_FULL), depth == CV_8U ? 1 : 4e-1); }
// RGB <-> HLS
#ifdef HAVE_IPP
#define IPP_EPS depth == CV_8U ? 2 : 1e-3
#else
#define IPP_EPS depth == CV_8U ? 1 : 1e-3
#endif
OCL_TEST_P(CvtColor8u32f, RGB2HLS) { performTest(3, 3, CVTCODE(RGB2HLS), depth == CV_8U ? 1 : 1e-3); }
OCL_TEST_P(CvtColor8u32f, BGR2HLS) { performTest(3, 3, CVTCODE(BGR2HLS), depth == CV_8U ? 1 : 1e-3); }
OCL_TEST_P(CvtColor8u32f, RGBA2HLS) { performTest(4, 3, CVTCODE(RGB2HLS), depth == CV_8U ? 1 : 1e-3); }
OCL_TEST_P(CvtColor8u32f, BGRA2HLS) { performTest(4, 3, CVTCODE(BGR2HLS), depth == CV_8U ? 1 : 1e-3); }
OCL_TEST_P(CvtColor8u32f, RGB2HLS_FULL) { performTest(3, 3, CVTCODE(RGB2HLS_FULL), IPP_EPS); }
OCL_TEST_P(CvtColor8u32f, BGR2HLS_FULL) { performTest(3, 3, CVTCODE(BGR2HLS_FULL), IPP_EPS); }
OCL_TEST_P(CvtColor8u32f, RGBA2HLS_FULL) { performTest(4, 3, CVTCODE(RGB2HLS_FULL), IPP_EPS); }
OCL_TEST_P(CvtColor8u32f, BGRA2HLS_FULL) { performTest(4, 3, CVTCODE(BGR2HLS_FULL), IPP_EPS); }
OCL_TEST_P(CvtColor8u32f, HLS2RGB) { performTest(3, 3, CVTCODE(HLS2RGB), 1); }
OCL_TEST_P(CvtColor8u32f, HLS2BGR) { performTest(3, 3, CVTCODE(HLS2BGR), 1); }
OCL_TEST_P(CvtColor8u32f, HLS2RGBA) { performTest(3, 4, CVTCODE(HLS2RGB), 1); }
OCL_TEST_P(CvtColor8u32f, HLS2BGRA) { performTest(3, 4, CVTCODE(HLS2BGR), 1); }
OCL_TEST_P(CvtColor8u32f, HLS2RGB_FULL) { performTest(3, 3, CVTCODE(HLS2RGB_FULL), 1); }
OCL_TEST_P(CvtColor8u32f, HLS2BGR_FULL) { performTest(3, 3, CVTCODE(HLS2BGR_FULL), 1); }
OCL_TEST_P(CvtColor8u32f, HLS2RGBA_FULL) { performTest(3, 4, CVTCODE(HLS2RGB_FULL), 1); }
OCL_TEST_P(CvtColor8u32f, HLS2BGRA_FULL) { performTest(3, 4, CVTCODE(HLS2BGR_FULL), 1); }
#undef IPP_EPS
// RGB5x5 <-> RGB
typedef CvtColor CvtColor8u;
OCL_TEST_P(CvtColor8u, BGR5652BGR) { performTest(2, 3, CVTCODE(BGR5652BGR)); }
OCL_TEST_P(CvtColor8u, BGR5652RGB) { performTest(2, 3, CVTCODE(BGR5652RGB)); }
OCL_TEST_P(CvtColor8u, BGR5652BGRA) { performTest(2, 4, CVTCODE(BGR5652BGRA)); }
OCL_TEST_P(CvtColor8u, BGR5652RGBA) { performTest(2, 4, CVTCODE(BGR5652RGBA)); }
OCL_TEST_P(CvtColor8u, BGR5552BGR) { performTest(2, 3, CVTCODE(BGR5552BGR)); }
OCL_TEST_P(CvtColor8u, BGR5552RGB) { performTest(2, 3, CVTCODE(BGR5552RGB)); }
OCL_TEST_P(CvtColor8u, BGR5552BGRA) { performTest(2, 4, CVTCODE(BGR5552BGRA)); }
OCL_TEST_P(CvtColor8u, BGR5552RGBA) { performTest(2, 4, CVTCODE(BGR5552RGBA)); }
OCL_TEST_P(CvtColor8u, BGR2BGR565) { performTest(3, 2, CVTCODE(BGR2BGR565)); }
OCL_TEST_P(CvtColor8u, RGB2BGR565) { performTest(3, 2, CVTCODE(RGB2BGR565)); }
OCL_TEST_P(CvtColor8u, BGRA2BGR565) { performTest(4, 2, CVTCODE(BGRA2BGR565)); }
OCL_TEST_P(CvtColor8u, RGBA2BGR565) { performTest(4, 2, CVTCODE(RGBA2BGR565)); }
OCL_TEST_P(CvtColor8u, BGR2BGR555) { performTest(3, 2, CVTCODE(BGR2BGR555)); }
OCL_TEST_P(CvtColor8u, RGB2BGR555) { performTest(3, 2, CVTCODE(RGB2BGR555)); }
OCL_TEST_P(CvtColor8u, BGRA2BGR555) { performTest(4, 2, CVTCODE(BGRA2BGR555)); }
OCL_TEST_P(CvtColor8u, RGBA2BGR555) { performTest(4, 2, CVTCODE(RGBA2BGR555)); }
// RGB5x5 <-> Gray
OCL_TEST_P(CvtColor8u, BGR5652GRAY) { performTest(2, 1, CVTCODE(BGR5652GRAY)); }
OCL_TEST_P(CvtColor8u, BGR5552GRAY) { performTest(2, 1, CVTCODE(BGR5552GRAY)); }
OCL_TEST_P(CvtColor8u, GRAY2BGR565) { performTest(1, 2, CVTCODE(GRAY2BGR565)); }
OCL_TEST_P(CvtColor8u, GRAY2BGR555) { performTest(1, 2, CVTCODE(GRAY2BGR555)); }
// RGBA <-> mRGBA
#if defined(HAVE_IPP) || defined(__arm__)
#define IPP_EPS depth <= CV_32S ? 1 : 1e-3
#else
#define IPP_EPS 1e-3
#endif
OCL_TEST_P(CvtColor8u, RGBA2mRGBA) { performTest(4, 4, CVTCODE(RGBA2mRGBA), IPP_EPS); }
OCL_TEST_P(CvtColor8u, mRGBA2RGBA) { performTest(4, 4, CVTCODE(mRGBA2RGBA), IPP_EPS); }
// RGB <-> Lab
OCL_TEST_P(CvtColor8u32f, BGR2Lab) { performTest(3, 3, CVTCODE(BGR2Lab)); }
OCL_TEST_P(CvtColor8u32f, RGB2Lab) { performTest(3, 3, CVTCODE(RGB2Lab)); }
OCL_TEST_P(CvtColor8u32f, LBGR2Lab) { performTest(3, 3, CVTCODE(LBGR2Lab), IPP_EPS); }
OCL_TEST_P(CvtColor8u32f, LRGB2Lab) { performTest(3, 3, CVTCODE(LRGB2Lab), IPP_EPS); }
OCL_TEST_P(CvtColor8u32f, BGRA2Lab) { performTest(4, 3, CVTCODE(BGR2Lab)); }
OCL_TEST_P(CvtColor8u32f, RGBA2Lab) { performTest(4, 3, CVTCODE(RGB2Lab)); }
OCL_TEST_P(CvtColor8u32f, LBGRA2Lab) { performTest(4, 3, CVTCODE(LBGR2Lab), IPP_EPS); }
OCL_TEST_P(CvtColor8u32f, LRGBA2Lab) { performTest(4, 3, CVTCODE(LRGB2Lab), IPP_EPS); }
#undef IPP_EPS
OCL_TEST_P(CvtColor8u32f, Lab2BGR) { performTest(3, 3, CVTCODE(Lab2BGR), depth == CV_8U ? 1 : 1e-5); }
OCL_TEST_P(CvtColor8u32f, Lab2RGB) { performTest(3, 3, CVTCODE(Lab2RGB), depth == CV_8U ? 1 : 1e-5); }
OCL_TEST_P(CvtColor8u32f, Lab2LBGR) { performTest(3, 3, CVTCODE(Lab2LBGR), depth == CV_8U ? 1 : 1e-5); }
OCL_TEST_P(CvtColor8u32f, Lab2LRGB) { performTest(3, 3, CVTCODE(Lab2LRGB), depth == CV_8U ? 1 : 1e-5); }
OCL_TEST_P(CvtColor8u32f, Lab2BGRA) { performTest(3, 4, CVTCODE(Lab2BGR), depth == CV_8U ? 1 : 1e-5); }
OCL_TEST_P(CvtColor8u32f, Lab2RGBA) { performTest(3, 4, CVTCODE(Lab2RGB), depth == CV_8U ? 1 : 1e-5); }
OCL_TEST_P(CvtColor8u32f, Lab2LBGRA) { performTest(3, 4, CVTCODE(Lab2LBGR), depth == CV_8U ? 1 : 1e-5); }
OCL_TEST_P(CvtColor8u32f, Lab2LRGBA) { performTest(3, 4, CVTCODE(Lab2LRGB), depth == CV_8U ? 1 : 1e-5); }
// RGB -> Luv
OCL_TEST_P(CvtColor8u32f, BGR2Luv) { performTest(3, 3, CVTCODE(BGR2Luv), depth == CV_8U ? 1 : 1.5e-2); }
OCL_TEST_P(CvtColor8u32f, RGB2Luv) { performTest(3, 3, CVTCODE(RGB2Luv), depth == CV_8U ? 1 : 1.5e-2); }
OCL_TEST_P(CvtColor8u32f, LBGR2Luv) { performTest(3, 3, CVTCODE(LBGR2Luv), depth == CV_8U ? 1 : 6e-3); }
OCL_TEST_P(CvtColor8u32f, LRGB2Luv) { performTest(3, 3, CVTCODE(LRGB2Luv), depth == CV_8U ? 1 : 6e-3); }
OCL_TEST_P(CvtColor8u32f, BGRA2Luv) { performTest(4, 3, CVTCODE(BGR2Luv), depth == CV_8U ? 1 : 2e-2); }
OCL_TEST_P(CvtColor8u32f, RGBA2Luv) { performTest(4, 3, CVTCODE(RGB2Luv), depth == CV_8U ? 1 : 2e-2); }
OCL_TEST_P(CvtColor8u32f, LBGRA2Luv) { performTest(4, 3, CVTCODE(LBGR2Luv), depth == CV_8U ? 1 : 6e-3); }
OCL_TEST_P(CvtColor8u32f, LRGBA2Luv) { performTest(4, 3, CVTCODE(LRGB2Luv), depth == CV_8U ? 1 : 6e-3); }
OCL_TEST_P(CvtColor8u32f, Luv2BGR) { performTest(3, 3, CVTCODE(Luv2BGR), depth == CV_8U ? 1 : 7e-5); }
OCL_TEST_P(CvtColor8u32f, Luv2RGB) { performTest(3, 3, CVTCODE(Luv2RGB), depth == CV_8U ? 1 : 7e-5); }
OCL_TEST_P(CvtColor8u32f, Luv2LBGR) { performTest(3, 3, CVTCODE(Luv2LBGR), depth == CV_8U ? 1 : 1e-5); }
OCL_TEST_P(CvtColor8u32f, Luv2LRGB) { performTest(3, 3, CVTCODE(Luv2LRGB), depth == CV_8U ? 1 : 1e-5); }
OCL_TEST_P(CvtColor8u32f, Luv2BGRA) { performTest(3, 4, CVTCODE(Luv2BGR), depth == CV_8U ? 1 : 7e-5); }
OCL_TEST_P(CvtColor8u32f, Luv2RGBA) { performTest(3, 4, CVTCODE(Luv2RGB), depth == CV_8U ? 1 : 7e-5); }
OCL_TEST_P(CvtColor8u32f, Luv2LBGRA) { performTest(3, 4, CVTCODE(Luv2LBGR), depth == CV_8U ? 1 : 1e-5); }
OCL_TEST_P(CvtColor8u32f, Luv2LRGBA) { performTest(3, 4, CVTCODE(Luv2LRGB), depth == CV_8U ? 1 : 1e-5); }
// YUV420 -> RGBA
struct CvtColor_YUV2RGB_420 :
public CvtColor
{
void generateTestData(int channelsIn, int channelsOut)
{
const int srcType = CV_MAKE_TYPE(depth, channelsIn);
const int dstType = CV_MAKE_TYPE(depth, channelsOut);
Size roiSize = randomSize(1, MAX_VALUE);
roiSize.width *= 2;
roiSize.height *= 3;
Border srcBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, roiSize, srcBorder, srcType, 2, 100);
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(CvtColor_YUV2RGB_420, YUV2RGBA_NV12) { performTest(1, 4, CVTCODE(YUV2RGBA_NV12), EPS_FOR_FLOATING_POINT(1e-3)); }
OCL_TEST_P(CvtColor_YUV2RGB_420, YUV2BGRA_NV12) { performTest(1, 4, CVTCODE(YUV2BGRA_NV12), EPS_FOR_FLOATING_POINT(1e-3)); }
OCL_TEST_P(CvtColor_YUV2RGB_420, YUV2RGB_NV12) { performTest(1, 3, CVTCODE(YUV2RGB_NV12), EPS_FOR_FLOATING_POINT(1e-3)); }
OCL_TEST_P(CvtColor_YUV2RGB_420, YUV2BGR_NV12) { performTest(1, 3, CVTCODE(YUV2BGR_NV12), EPS_FOR_FLOATING_POINT(1e-3)); }
OCL_TEST_P(CvtColor_YUV2RGB_420, YUV2RGBA_NV21) { performTest(1, 4, CVTCODE(YUV2RGBA_NV21), EPS_FOR_FLOATING_POINT(1e-3)); }
OCL_TEST_P(CvtColor_YUV2RGB_420, YUV2BGRA_NV21) { performTest(1, 4, CVTCODE(YUV2BGRA_NV21), EPS_FOR_FLOATING_POINT(1e-3)); }
OCL_TEST_P(CvtColor_YUV2RGB_420, YUV2RGB_NV21) { performTest(1, 3, CVTCODE(YUV2RGB_NV21), EPS_FOR_FLOATING_POINT(1e-3)); }
OCL_TEST_P(CvtColor_YUV2RGB_420, YUV2BGR_NV21) { performTest(1, 3, CVTCODE(YUV2BGR_NV21), EPS_FOR_FLOATING_POINT(1e-3)); }
OCL_TEST_P(CvtColor_YUV2RGB_420, YUV2RGBA_YV12) { performTest(1, 4, CVTCODE(YUV2RGBA_YV12)); }
OCL_TEST_P(CvtColor_YUV2RGB_420, YUV2BGRA_YV12) { performTest(1, 4, CVTCODE(YUV2BGRA_YV12)); }
OCL_TEST_P(CvtColor_YUV2RGB_420, YUV2RGB_YV12) { performTest(1, 3, CVTCODE(YUV2RGB_YV12)); }
OCL_TEST_P(CvtColor_YUV2RGB_420, YUV2BGR_YV12) { performTest(1, 3, CVTCODE(YUV2BGR_YV12)); }
OCL_TEST_P(CvtColor_YUV2RGB_420, YUV2RGBA_IYUV) { performTest(1, 4, CVTCODE(YUV2RGBA_IYUV)); }
OCL_TEST_P(CvtColor_YUV2RGB_420, YUV2BGRA_IYUV) { performTest(1, 4, CVTCODE(YUV2BGRA_IYUV)); }
OCL_TEST_P(CvtColor_YUV2RGB_420, YUV2RGB_IYUV) { performTest(1, 3, CVTCODE(YUV2RGB_IYUV)); }
OCL_TEST_P(CvtColor_YUV2RGB_420, YUV2BGR_IYUV) { performTest(1, 3, CVTCODE(YUV2BGR_IYUV)); }
OCL_TEST_P(CvtColor_YUV2RGB_420, YUV2GRAY_420) { performTest(1, 1, CVTCODE(YUV2GRAY_420)); }
// RGBA -> YUV420
struct CvtColor_RGB2YUV_420 :
public CvtColor
{
void generateTestData(int channelsIn, int channelsOut)
{
const int srcType = CV_MAKE_TYPE(depth, channelsIn);
const int dstType = CV_MAKE_TYPE(depth, channelsOut);
Size srcRoiSize = randomSize(1, MAX_VALUE);
srcRoiSize.width *= 2;
srcRoiSize.height *= 2;
Border srcBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, srcRoiSize, srcBorder, srcType, 2, 100);
Size dstRoiSize(srcRoiSize.width, srcRoiSize.height / 2 * 3);
Border dstBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(dst, dst_roi, dstRoiSize, dstBorder, dstType, 5, 16);
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
}
};
OCL_TEST_P(CvtColor_RGB2YUV_420, RGBA2YUV_YV12) { performTest(4, 1, CVTCODE(RGBA2YUV_YV12), 1); }
OCL_TEST_P(CvtColor_RGB2YUV_420, BGRA2YUV_YV12) { performTest(4, 1, CVTCODE(BGRA2YUV_YV12), 1); }
OCL_TEST_P(CvtColor_RGB2YUV_420, RGB2YUV_YV12) { performTest(3, 1, CVTCODE(RGB2YUV_YV12), 1); }
OCL_TEST_P(CvtColor_RGB2YUV_420, BGR2YUV_YV12) { performTest(3, 1, CVTCODE(BGR2YUV_YV12), 1); }
OCL_TEST_P(CvtColor_RGB2YUV_420, RGBA2YUV_IYUV) { performTest(4, 1, CVTCODE(RGBA2YUV_IYUV), 1); }
OCL_TEST_P(CvtColor_RGB2YUV_420, BGRA2YUV_IYUV) { performTest(4, 1, CVTCODE(BGRA2YUV_IYUV), 1); }
OCL_TEST_P(CvtColor_RGB2YUV_420, RGB2YUV_IYUV) { performTest(3, 1, CVTCODE(RGB2YUV_IYUV), 1); }
OCL_TEST_P(CvtColor_RGB2YUV_420, BGR2YUV_IYUV) { performTest(3, 1, CVTCODE(BGR2YUV_IYUV), 1); }
// YUV422 -> RGBA
struct CvtColor_YUV2RGB_422 :
public CvtColor
{
void generateTestData(int channelsIn, int channelsOut)
{
const int srcType = CV_MAKE_TYPE(depth, channelsIn);
const int dstType = CV_MAKE_TYPE(depth, channelsOut);
Size roiSize = randomSize(1, MAX_VALUE);
roiSize.width *= 2;
Border srcBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, roiSize, srcBorder, srcType, 2, 100);
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(CvtColor_YUV2RGB_422, YUV2RGB_UYVY) { performTest(2, 3, CVTCODE(YUV2RGB_UYVY)); }
OCL_TEST_P(CvtColor_YUV2RGB_422, YUV2BGR_UYVY) { performTest(2, 3, CVTCODE(YUV2BGR_UYVY)); }
OCL_TEST_P(CvtColor_YUV2RGB_422, YUV2RGBA_UYVY) { performTest(2, 4, CVTCODE(YUV2RGBA_UYVY)); }
OCL_TEST_P(CvtColor_YUV2RGB_422, YUV2BGRA_UYVY) { performTest(2, 4, CVTCODE(YUV2BGRA_UYVY)); }
OCL_TEST_P(CvtColor_YUV2RGB_422, YUV2RGB_YUY2) { performTest(2, 3, CVTCODE(YUV2RGB_YUY2)); }
OCL_TEST_P(CvtColor_YUV2RGB_422, YUV2BGR_YUY2) { performTest(2, 3, CVTCODE(YUV2BGR_YUY2)); }
OCL_TEST_P(CvtColor_YUV2RGB_422, YUV2RGBA_YUY2) { performTest(2, 4, CVTCODE(YUV2RGBA_YUY2)); }
OCL_TEST_P(CvtColor_YUV2RGB_422, YUV2BGRA_YUY2) { performTest(2, 4, CVTCODE(YUV2BGRA_YUY2)); }
OCL_TEST_P(CvtColor_YUV2RGB_422, YUV2RGB_YVYU) { performTest(2, 3, CVTCODE(YUV2RGB_YVYU)); }
OCL_TEST_P(CvtColor_YUV2RGB_422, YUV2BGR_YVYU) { performTest(2, 3, CVTCODE(YUV2BGR_YVYU)); }
OCL_TEST_P(CvtColor_YUV2RGB_422, YUV2RGBA_YVYU) { performTest(2, 4, CVTCODE(YUV2RGBA_YVYU)); }
OCL_TEST_P(CvtColor_YUV2RGB_422, YUV2BGRA_YVYU) { performTest(2, 4, CVTCODE(YUV2BGRA_YVYU)); }
// RGBA -> YUV422
struct CvtColor_RGB2YUV_422 :
public CvtColor
{
void generateTestData(int channelsIn, int channelsOut)
{
const int srcType = CV_MAKE_TYPE(depth, channelsIn);
const int dstType = CV_MAKE_TYPE(depth, channelsOut);
Size roiSize = randomSize(1, MAX_VALUE);
roiSize.width *= 2;
roiSize.height *= 2;
Border srcBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, roiSize, srcBorder, srcType, 2, 100);
Border dstBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(dst, dst_roi, roiSize, dstBorder, dstType, 6, 16);
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
}
};
OCL_TEST_P(CvtColor_RGB2YUV_422, RGB2YUV_UYVY) { performTest(3, 2, CVTCODE(RGB2YUV_UYVY)); }
OCL_TEST_P(CvtColor_RGB2YUV_422, BGR2YUV_UYVY) { performTest(3, 2, CVTCODE(BGR2YUV_UYVY)); }
OCL_TEST_P(CvtColor_RGB2YUV_422, RGBA2YUV_UYVY) { performTest(4, 2, CVTCODE(RGBA2YUV_UYVY)); }
OCL_TEST_P(CvtColor_RGB2YUV_422, BGRA2YUV_UYVY) { performTest(4, 2, CVTCODE(BGRA2YUV_UYVY)); }
OCL_TEST_P(CvtColor_RGB2YUV_422, RGB2YUV_YUY2) { performTest(3, 2, CVTCODE(RGB2YUV_YUY2)); }
OCL_TEST_P(CvtColor_RGB2YUV_422, BGR2YUV_YUY2) { performTest(3, 2, CVTCODE(BGR2YUV_YUY2)); }
OCL_TEST_P(CvtColor_RGB2YUV_422, RGBA2YUV_YUY2) { performTest(4, 2, CVTCODE(RGBA2YUV_YUY2)); }
OCL_TEST_P(CvtColor_RGB2YUV_422, BGRA2YUV_YUY2) { performTest(4, 2, CVTCODE(BGRA2YUV_YUY2)); }
OCL_TEST_P(CvtColor_RGB2YUV_422, RGB2YUV_YVYU) { performTest(3, 2, CVTCODE(RGB2YUV_YVYU)); }
OCL_TEST_P(CvtColor_RGB2YUV_422, BGR2YUV_YVYU) { performTest(3, 2, CVTCODE(BGR2YUV_YVYU)); }
OCL_TEST_P(CvtColor_RGB2YUV_422, RGBA2YUV_YVYU) { performTest(4, 2, CVTCODE(RGBA2YUV_YVYU)); }
OCL_TEST_P(CvtColor_RGB2YUV_422, BGRA2YUV_YVYU) { performTest(4, 2, CVTCODE(BGRA2YUV_YVYU)); }
OCL_INSTANTIATE_TEST_CASE_P(ImgProc, CvtColor8u,
testing::Combine(testing::Values(MatDepth(CV_8U)), Bool()));
OCL_INSTANTIATE_TEST_CASE_P(ImgProc, CvtColor8u32f,
testing::Combine(testing::Values(MatDepth(CV_8U), MatDepth(CV_32F)), Bool()));
OCL_INSTANTIATE_TEST_CASE_P(ImgProc, CvtColor,
testing::Combine(
testing::Values(MatDepth(CV_8U), MatDepth(CV_16U), MatDepth(CV_32F)),
Bool()));
OCL_INSTANTIATE_TEST_CASE_P(ImgProc, CvtColor_YUV2RGB_420,
testing::Combine(
testing::Values(MatDepth(CV_8U)),
Bool()));
OCL_INSTANTIATE_TEST_CASE_P(ImgProc, CvtColor_RGB2YUV_420,
testing::Combine(
testing::Values(MatDepth(CV_8U)),
Bool()));
OCL_INSTANTIATE_TEST_CASE_P(ImgProc, CvtColor_YUV2RGB_422,
testing::Combine(
testing::Values(MatDepth(CV_8U)),
Bool()));
OCL_INSTANTIATE_TEST_CASE_P(ImgProc, CvtColor_RGB2YUV_422,
testing::Combine(
testing::Values(MatDepth(CV_8U)),
Bool()));
} } // namespace opencv_test::ocl
#endif
+142
View File
@@ -0,0 +1,142 @@
/*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.
//
// 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 {
/////////////////////////////////////////////////////////////////////////////////////////////////
// Filter2D
PARAM_TEST_CASE(Filter2D, MatDepth, Channels, int, int, BorderType, bool, bool)
{
static const int kernelMinSize = 2;
static const int kernelMaxSize = 10;
int type;
Size size;
Point anchor;
int borderType;
int widthMultiple;
bool useRoi;
Mat kernel;
double delta;
TEST_DECLARE_INPUT_PARAMETER(src);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
virtual void SetUp()
{
type = CV_MAKE_TYPE(GET_PARAM(0), GET_PARAM(1));
Size ksize(GET_PARAM(2), GET_PARAM(2));
widthMultiple = GET_PARAM(3);
borderType = GET_PARAM(4) | (GET_PARAM(5) ? BORDER_ISOLATED : 0);
useRoi = GET_PARAM(6);
Mat temp = randomMat(ksize, CV_MAKE_TYPE(((CV_64F == CV_MAT_DEPTH(type)) ? CV_64F : CV_32F), 1), -MAX_VALUE, MAX_VALUE);
cv::normalize(temp, kernel, 1.0, 0.0, NORM_L1);
}
void random_roi()
{
size = randomSize(1, MAX_VALUE);
// Make sure the width is a multiple of the requested value, and no more.
size.width &= ~((widthMultiple * 2) - 1);
size.width += widthMultiple;
Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, size, srcBorder, type, -MAX_VALUE, MAX_VALUE);
Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(dst, dst_roi, size, dstBorder, type, -MAX_VALUE, MAX_VALUE);
anchor.x = randomInt(-1, kernel.size[0]);
anchor.y = randomInt(-1, kernel.size[1]);
delta = randomDouble(-100, 100);
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
}
void Near(double threshold = 0.0)
{
EXPECT_MAT_NEAR(dst, udst, threshold);
EXPECT_MAT_NEAR(dst_roi, udst_roi, threshold);
}
};
OCL_TEST_P(Filter2D, Mat)
{
for (int j = 0; j < test_loop_times; j++)
{
random_roi();
OCL_OFF(cv::filter2D(src_roi, dst_roi, -1, kernel, anchor, delta, borderType));
OCL_ON(cv::filter2D(usrc_roi, udst_roi, -1, kernel, anchor, delta, borderType));
Near(1.0);
}
}
OCL_INSTANTIATE_TEST_CASE_P(ImageProc, Filter2D,
Combine(
Values(CV_8U, CV_16U, CV_32F),
OCL_ALL_CHANNELS,
Values(3, 5, 7), // Kernel size
Values(1, 4, 8), // Width multiple
Values((BorderType)BORDER_CONSTANT,
(BorderType)BORDER_REPLICATE,
(BorderType)BORDER_REFLECT,
(BorderType)BORDER_REFLECT_101),
Bool(), // BORDER_ISOLATED
Bool() // ROI
)
);
} } // namespace opencv_test::ocl
#endif // HAVE_OPENCL
+766
View File
@@ -0,0 +1,766 @@
/*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
// Niko Li, newlife20080214@gmail.com
// Jia Haipeng, jiahaipeng95@gmail.com
// Zero Lin, Zero.Lin@amd.com
// Zhang Ying, zhangying913@gmail.com
// Yao Wang, bitwangyaoyao@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 "cvconfig.h"
#include "opencv2/ts/ocl_test.hpp"
#ifdef HAVE_OPENCL
namespace opencv_test {
namespace ocl {
PARAM_TEST_CASE(FilterTestBase, MatType,
int, // kernel size
Size, // dx, dy
BorderType, // border type
double, // optional parameter
bool, // roi or not
int) // width multiplier
{
int type, borderType, ksize;
Size size;
double param;
bool useRoi;
int widthMultiple;
TEST_DECLARE_INPUT_PARAMETER(src);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
virtual void SetUp()
{
type = GET_PARAM(0);
ksize = GET_PARAM(1);
size = GET_PARAM(2);
borderType = GET_PARAM(3);
param = GET_PARAM(4);
useRoi = GET_PARAM(5);
widthMultiple = GET_PARAM(6);
}
void random_roi(int minSize = 1)
{
if (minSize == 0)
minSize = ksize;
Size roiSize = randomSize(minSize, MAX_VALUE);
roiSize.width &= ~((widthMultiple * 2) - 1);
roiSize.width += widthMultiple;
Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, roiSize, srcBorder, type, 5, 256);
Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(dst, dst_roi, roiSize, dstBorder, type, -60, 70);
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
}
void Near()
{
int depth = CV_MAT_DEPTH(type);
bool isFP = depth >= CV_32F;
if (isFP)
Near(1e-6, true);
else
Near(1, false);
}
void Near(double threshold, bool relative)
{
if (relative)
OCL_EXPECT_MATS_NEAR_RELATIVE(dst, threshold);
else
OCL_EXPECT_MATS_NEAR(dst, threshold);
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Bilateral
typedef FilterTestBase Bilateral;
OCL_TEST_P(Bilateral, Mat)
{
for (int j = 0; j < test_loop_times; j++)
{
random_roi();
double sigmacolor = rng.uniform(20, 100);
double sigmaspace = rng.uniform(10, 40);
OCL_OFF(cv::bilateralFilter(src_roi, dst_roi, ksize, sigmacolor, sigmaspace, borderType));
OCL_ON(cv::bilateralFilter(usrc_roi, udst_roi, ksize, sigmacolor, sigmaspace, borderType));
Near();
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// Laplacian
typedef FilterTestBase LaplacianTest;
OCL_TEST_P(LaplacianTest, Accuracy)
{
double scale = param;
for (int j = 0; j < test_loop_times; j++)
{
random_roi();
OCL_OFF(cv::Laplacian(src_roi, dst_roi, -1, ksize, scale, 10, borderType));
OCL_ON(cv::Laplacian(usrc_roi, udst_roi, -1, ksize, scale, 10, borderType));
Near();
}
}
PARAM_TEST_CASE(Deriv3x3_cols16_rows2_Base, MatType,
int, // kernel size
Size, // dx, dy
BorderType, // border type
double, // optional parameter
bool, // roi or not
int) // width multiplier
{
int type, borderType, ksize;
Size size;
double param;
bool useRoi;
int widthMultiple;
TEST_DECLARE_INPUT_PARAMETER(src);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
virtual void SetUp()
{
type = GET_PARAM(0);
ksize = GET_PARAM(1);
size = GET_PARAM(2);
borderType = GET_PARAM(3);
param = GET_PARAM(4);
useRoi = GET_PARAM(5);
widthMultiple = GET_PARAM(6);
}
void random_roi()
{
size = Size(3, 3);
Size roiSize = randomSize(size.width, MAX_VALUE, size.height, MAX_VALUE);
roiSize.width = std::max(size.width + 13, roiSize.width & (~0xf));
roiSize.height = std::max(size.height + 1, roiSize.height & (~0x1));
Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, roiSize, srcBorder, type, 5, 256);
Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(dst, dst_roi, roiSize, dstBorder, type, -60, 70);
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
}
void Near()
{
Near(1, false);
}
void Near(double threshold, bool relative)
{
if (relative)
OCL_EXPECT_MATS_NEAR_RELATIVE(dst, threshold);
else
OCL_EXPECT_MATS_NEAR(dst, threshold);
}
};
typedef Deriv3x3_cols16_rows2_Base Laplacian3_cols16_rows2;
OCL_TEST_P(Laplacian3_cols16_rows2, Accuracy)
{
double scale = param;
for (int j = 0; j < test_loop_times; j++)
{
random_roi();
OCL_OFF(cv::Laplacian(src_roi, dst_roi, -1, ksize, scale, 10, borderType));
OCL_ON(cv::Laplacian(usrc_roi, udst_roi, -1, ksize, scale, 10, borderType));
Near();
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// Sobel
typedef FilterTestBase SobelTest;
OCL_TEST_P(SobelTest, Mat)
{
int dx = size.width, dy = size.height;
double scale = param;
for (int j = 0; j < test_loop_times; j++)
{
random_roi();
OCL_OFF(cv::Sobel(src_roi, dst_roi, -1, dx, dy, ksize, scale, /* delta */0, borderType));
OCL_ON(cv::Sobel(usrc_roi, udst_roi, -1, dx, dy, ksize, scale, /* delta */0, borderType));
Near();
}
}
typedef Deriv3x3_cols16_rows2_Base Sobel3x3_cols16_rows2;
OCL_TEST_P(Sobel3x3_cols16_rows2, Mat)
{
int dx = size.width, dy = size.height;
double scale = param;
for (int j = 0; j < test_loop_times; j++)
{
random_roi();
OCL_OFF(cv::Sobel(src_roi, dst_roi, -1, dx, dy, ksize, scale, /* delta */0, borderType));
OCL_ON(cv::Sobel(usrc_roi, udst_roi, -1, dx, dy, ksize, scale, /* delta */0, borderType));
Near();
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// Scharr
typedef FilterTestBase ScharrTest;
OCL_TEST_P(ScharrTest, Mat)
{
int dx = size.width, dy = size.height;
double scale = param;
for (int j = 0; j < test_loop_times; j++)
{
random_roi();
OCL_OFF(cv::Scharr(src_roi, dst_roi, -1, dx, dy, scale, /* delta */ 0, borderType));
OCL_ON(cv::Scharr(usrc_roi, udst_roi, -1, dx, dy, scale, /* delta */ 0, borderType));
Near();
}
}
typedef Deriv3x3_cols16_rows2_Base Scharr3x3_cols16_rows2;
OCL_TEST_P(Scharr3x3_cols16_rows2, Mat)
{
int dx = size.width, dy = size.height;
double scale = param;
for (int j = 0; j < test_loop_times; j++)
{
random_roi();
OCL_OFF(cv::Scharr(src_roi, dst_roi, -1, dx, dy, scale, /* delta */ 0, borderType));
OCL_ON(cv::Scharr(usrc_roi, udst_roi, -1, dx, dy, scale, /* delta */ 0, borderType));
Near();
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// GaussianBlur
typedef FilterTestBase GaussianBlurTest;
OCL_TEST_P(GaussianBlurTest, Mat)
{
for (int j = 0; j < test_loop_times + 1; j++)
{
random_roi();
double sigma1 = rng.uniform(0.1, 1.0);
double sigma2 = j % 2 == 0 ? sigma1 : rng.uniform(0.1, 1.0);
OCL_OFF(cv::GaussianBlur(src_roi, dst_roi, Size(ksize, ksize), sigma1, sigma2, borderType));
OCL_ON(cv::GaussianBlur(usrc_roi, udst_roi, Size(ksize, ksize), sigma1, sigma2, borderType));
Near(CV_MAT_DEPTH(type) >= CV_32F ? 1e-3 : 4, CV_MAT_DEPTH(type) >= CV_32F);
}
}
PARAM_TEST_CASE(GaussianBlur_multicols_Base, MatType,
int, // kernel size
Size, // dx, dy
BorderType, // border type
double, // optional parameter
bool, // roi or not
int) // width multiplier
{
int type, borderType, ksize;
Size size;
double param;
bool useRoi;
int widthMultiple;
TEST_DECLARE_INPUT_PARAMETER(src);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
virtual void SetUp()
{
type = GET_PARAM(0);
ksize = GET_PARAM(1);
size = GET_PARAM(2);
borderType = GET_PARAM(3);
param = GET_PARAM(4);
useRoi = GET_PARAM(5);
widthMultiple = GET_PARAM(6);
}
void random_roi()
{
size = Size(ksize, ksize);
Size roiSize = randomSize(size.width, MAX_VALUE, size.height, MAX_VALUE);
if (ksize == 3)
{
roiSize.width = std::max((size.width + 15) & 0x10, roiSize.width & (~0xf));
roiSize.height = std::max(size.height + 1, roiSize.height & (~0x1));
}
else if (ksize == 5)
{
roiSize.width = std::max((size.width + 3) & 0x4, roiSize.width & (~0x3));
}
Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, roiSize, srcBorder, type, 5, 256);
Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(dst, dst_roi, roiSize, dstBorder, type, -60, 70);
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
}
void Near()
{
Near(1, false);
}
void Near(double threshold, bool relative)
{
if (relative)
OCL_EXPECT_MATS_NEAR_RELATIVE(dst, threshold);
else
OCL_EXPECT_MATS_NEAR(dst, threshold);
}
};
typedef GaussianBlur_multicols_Base GaussianBlur_multicols;
OCL_TEST_P(GaussianBlur_multicols, Mat)
{
Size kernelSize(ksize, ksize);
for (int j = 0; j < test_loop_times; j++)
{
random_roi();
double sigma1 = rng.uniform(0.1, 1.0);
double sigma2 = j % 2 == 0 ? sigma1 : rng.uniform(0.1, 1.0);
OCL_OFF(cv::GaussianBlur(src_roi, dst_roi, Size(ksize, ksize), sigma1, sigma2, borderType));
OCL_ON(cv::GaussianBlur(usrc_roi, udst_roi, Size(ksize, ksize), sigma1, sigma2, borderType));
Near(CV_MAT_DEPTH(type) >= CV_32F ? 1e-3 : 4, CV_MAT_DEPTH(type) >= CV_32F);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// Erode
typedef FilterTestBase Erode;
OCL_TEST_P(Erode, Mat)
{
Size kernelSize(ksize, ksize);
int iterations = (int)param;
for (int j = 0; j < test_loop_times; j++)
{
random_roi();
Mat kernel = ksize==0 ? Mat() : randomMat(kernelSize, CV_8UC1, 0, 2);
OCL_OFF(cv::erode(src_roi, dst_roi, kernel, Point(-1, -1), iterations) );
OCL_ON(cv::erode(usrc_roi, udst_roi, kernel, Point(-1, -1), iterations) );
Near();
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// Dilate
typedef FilterTestBase Dilate;
OCL_TEST_P(Dilate, Mat)
{
Size kernelSize(ksize, ksize);
int iterations = (int)param;
for (int j = 0; j < test_loop_times; j++)
{
random_roi();
Mat kernel = ksize==0 ? Mat() : randomMat(kernelSize, CV_8UC1, 0, 2);
OCL_OFF(cv::dilate(src_roi, dst_roi, kernel, Point(-1, -1), iterations) );
OCL_ON(cv::dilate(usrc_roi, udst_roi, kernel, Point(-1, -1), iterations) );
Near();
}
}
PARAM_TEST_CASE(MorphFilter3x3_cols16_rows2_Base, MatType,
int, // kernel size
Size, // dx, dy
BorderType, // border type
double, // optional parameter
bool, // roi or not
int) // width multiplier
{
int type, borderType, ksize;
Size size;
double param;
bool useRoi;
int widthMultiple;
TEST_DECLARE_INPUT_PARAMETER(src);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
virtual void SetUp()
{
type = GET_PARAM(0);
ksize = GET_PARAM(1);
size = GET_PARAM(2);
borderType = GET_PARAM(3);
param = GET_PARAM(4);
useRoi = GET_PARAM(5);
widthMultiple = GET_PARAM(6);
}
void random_roi()
{
size = Size(3, 3);
Size roiSize = randomSize(size.width, MAX_VALUE, size.height, MAX_VALUE);
roiSize.width = std::max(size.width + 13, roiSize.width & (~0xf));
roiSize.height = std::max(size.height + 1, roiSize.height & (~0x1));
Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, roiSize, srcBorder, type, 5, 256);
Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(dst, dst_roi, roiSize, dstBorder, type, -60, 70);
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
}
void Near()
{
Near(1, false);
}
void Near(double threshold, bool relative)
{
if (relative)
OCL_EXPECT_MATS_NEAR_RELATIVE(dst, threshold);
else
OCL_EXPECT_MATS_NEAR(dst, threshold);
}
};
typedef MorphFilter3x3_cols16_rows2_Base MorphFilter3x3_cols16_rows2;
OCL_TEST_P(MorphFilter3x3_cols16_rows2, Mat)
{
Size kernelSize(ksize, ksize);
int iterations = (int)param;
for (int j = 0; j < test_loop_times; j++)
{
random_roi();
Mat kernel = ksize==0 ? Mat() : randomMat(kernelSize, CV_8UC1, 0, 3);
OCL_OFF(cv::dilate(src_roi, dst_roi, kernel, Point(-1, -1), iterations) );
OCL_ON(cv::dilate(usrc_roi, udst_roi, kernel, Point(-1, -1), iterations) );
Near();
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// MorphologyEx
IMPLEMENT_PARAM_CLASS(MorphOp, int)
PARAM_TEST_CASE(MorphologyEx, MatType,
int, // kernel size
MorphOp, // MORPH_OP
int, // iterations
bool)
{
int type, ksize, op, iterations;
bool useRoi;
TEST_DECLARE_INPUT_PARAMETER(src);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
virtual void SetUp()
{
type = GET_PARAM(0);
ksize = GET_PARAM(1);
op = GET_PARAM(2);
iterations = GET_PARAM(3);
useRoi = GET_PARAM(4);
}
void random_roi(int minSize = 1)
{
if (minSize == 0)
minSize = ksize;
Size roiSize = randomSize(minSize, MAX_VALUE);
Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, roiSize, srcBorder, type, 5, 256);
Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(dst, dst_roi, roiSize, dstBorder, type, -60, 70);
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
}
void Near()
{
int depth = CV_MAT_DEPTH(type);
bool isFP = depth >= CV_32F;
if (isFP)
Near(1e-6, true);
else
Near(1, false);
}
void Near(double threshold, bool relative)
{
if (relative)
OCL_EXPECT_MATS_NEAR_RELATIVE(dst, threshold);
else
OCL_EXPECT_MATS_NEAR(dst, threshold);
}
};
OCL_TEST_P(MorphologyEx, Mat)
{
Size kernelSize(ksize, ksize);
for (int j = 0; j < test_loop_times; j++)
{
random_roi();
Mat kernel = randomMat(kernelSize, CV_8UC1, 0, 3);
OCL_OFF(cv::morphologyEx(src_roi, dst_roi, op, kernel, Point(-1, -1), iterations) );
OCL_ON(cv::morphologyEx(usrc_roi, udst_roi, op, kernel, Point(-1, -1), iterations) );
Near();
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define FILTER_BORDER_SET_NO_ISOLATED \
Values((BorderType)BORDER_CONSTANT, (BorderType)BORDER_REPLICATE, (BorderType)BORDER_REFLECT, (BorderType)BORDER_WRAP, (BorderType)BORDER_REFLECT_101/*, \
(int)BORDER_CONSTANT|BORDER_ISOLATED, (int)BORDER_REPLICATE|BORDER_ISOLATED, \
(int)BORDER_REFLECT|BORDER_ISOLATED, (int)BORDER_WRAP|BORDER_ISOLATED, \
(int)BORDER_REFLECT_101|BORDER_ISOLATED*/) // WRAP and ISOLATED are not supported by cv:: version
#define FILTER_BORDER_SET_NO_WRAP_NO_ISOLATED \
Values((BorderType)BORDER_CONSTANT, (BorderType)BORDER_REPLICATE, (BorderType)BORDER_REFLECT, /*(int)BORDER_WRAP,*/ (BorderType)BORDER_REFLECT_101/*, \
(int)BORDER_CONSTANT|BORDER_ISOLATED, (int)BORDER_REPLICATE|BORDER_ISOLATED, \
(int)BORDER_REFLECT|BORDER_ISOLATED, (int)BORDER_WRAP|BORDER_ISOLATED, \
(int)BORDER_REFLECT_101|BORDER_ISOLATED*/) // WRAP and ISOLATED are not supported by cv:: version
#define FILTER_TYPES Values(CV_8UC1, CV_8UC3, CV_8UC4, CV_16UC1, CV_16UC3, CV_16UC4, CV_32FC1, CV_32FC3, CV_32FC4)
OCL_INSTANTIATE_TEST_CASE_P(Filter, Bilateral, Combine(
Values(CV_8UC1, CV_8UC3),
Values(5, 9), // kernel size
Values(Size(0, 0)), // not used
FILTER_BORDER_SET_NO_ISOLATED,
Values(0.0), // not used
Bool(),
Values(1, 4)));
OCL_INSTANTIATE_TEST_CASE_P(Filter, LaplacianTest, Combine(
FILTER_TYPES,
Values(1, 3, 5), // kernel size
Values(Size(0, 0)), // not used
FILTER_BORDER_SET_NO_WRAP_NO_ISOLATED,
Values(1.0, 0.2, 3.0), // kernel scale
Bool(),
Values(1))); // not used
OCL_INSTANTIATE_TEST_CASE_P(Filter, Laplacian3_cols16_rows2, Combine(
Values((MatType)CV_8UC1),
Values(3), // kernel size
Values(Size(0, 0)), // not used
FILTER_BORDER_SET_NO_WRAP_NO_ISOLATED,
Values(1.0, 0.2, 3.0), // kernel scale
Bool(),
Values(1))); // not used
OCL_INSTANTIATE_TEST_CASE_P(Filter, SobelTest, Combine(
FILTER_TYPES,
Values(3, 5), // kernel size
Values(Size(1, 0), Size(1, 1), Size(2, 0), Size(2, 1)), // dx, dy
FILTER_BORDER_SET_NO_WRAP_NO_ISOLATED,
Values(0.0), // not used
Bool(),
Values(1))); // not used
OCL_INSTANTIATE_TEST_CASE_P(Filter, Sobel3x3_cols16_rows2, Combine(
Values((MatType)CV_8UC1),
Values(3), // kernel size
Values(Size(1, 0), Size(1, 1), Size(2, 0), Size(2, 1)), // dx, dy
FILTER_BORDER_SET_NO_WRAP_NO_ISOLATED,
Values(0.0), // not used
Bool(),
Values(1))); // not used
OCL_INSTANTIATE_TEST_CASE_P(Filter, ScharrTest, Combine(
FILTER_TYPES,
Values(0), // not used
Values(Size(0, 1), Size(1, 0)), // dx, dy
FILTER_BORDER_SET_NO_WRAP_NO_ISOLATED,
Values(1.0, 0.2), // kernel scale
Bool(),
Values(1))); // not used
OCL_INSTANTIATE_TEST_CASE_P(Filter, Scharr3x3_cols16_rows2, Combine(
FILTER_TYPES,
Values(0), // not used
Values(Size(0, 1), Size(1, 0)), // dx, dy
FILTER_BORDER_SET_NO_WRAP_NO_ISOLATED,
Values(1.0, 0.2), // kernel scale
Bool(),
Values(1))); // not used
OCL_INSTANTIATE_TEST_CASE_P(Filter, GaussianBlurTest, Combine(
FILTER_TYPES,
Values(3, 5), // kernel size
Values(Size(0, 0)), // not used
FILTER_BORDER_SET_NO_WRAP_NO_ISOLATED,
Values(0.0), // not used
Bool(),
Values(1))); // not used
OCL_INSTANTIATE_TEST_CASE_P(Filter, GaussianBlur_multicols, Combine(
Values((MatType)CV_8UC1),
Values(3, 5), // kernel size
Values(Size(0, 0)), // not used
FILTER_BORDER_SET_NO_WRAP_NO_ISOLATED,
Values(0.0), // not used
Bool(),
Values(1))); // not used
OCL_INSTANTIATE_TEST_CASE_P(Filter, Erode, Combine(
Values(CV_8UC1, CV_8UC3, CV_8UC4, CV_32FC1, CV_32FC3, CV_32FC4, CV_64FC1, CV_64FC4),
Values(0, 5, 7, 9), // kernel size, 0 means kernel = Mat()
Values(Size(0, 0)), //not used
Values((BorderType)BORDER_CONSTANT),
Values(1.0, 2.0, 3.0, 4.0),
Bool(),
Values(1))); // not used
OCL_INSTANTIATE_TEST_CASE_P(Filter, Dilate, Combine(
Values(CV_8UC1, CV_8UC3, CV_8UC4, CV_32FC1, CV_32FC3, CV_32FC4, CV_64FC1, CV_64FC4),
Values(0, 3, 5, 7, 9), // kernel size, 0 means kernel = Mat()
Values(Size(0, 0)), // not used
Values((BorderType)BORDER_CONSTANT),
Values(1.0, 2.0, 3.0, 4.0),
Bool(),
Values(1))); // not used
OCL_INSTANTIATE_TEST_CASE_P(Filter, MorphFilter3x3_cols16_rows2, Combine(
Values((MatType)CV_8UC1),
Values(0, 3), // kernel size, 0 means kernel = Mat()
Values(Size(0, 0)), // not used
Values((BorderType)BORDER_CONSTANT),
Values(1.0, 2.0, 3.0),
Bool(),
Values(1))); // not used
OCL_INSTANTIATE_TEST_CASE_P(Filter, MorphologyEx, Combine(
Values(CV_8UC1, CV_8UC3, CV_8UC4, CV_32FC1, CV_32FC3, CV_32FC4),
Values(3, 5, 7), // kernel size
Values((MorphOp)MORPH_OPEN, (MorphOp)MORPH_CLOSE, (MorphOp)MORPH_GRADIENT, (MorphOp)MORPH_TOPHAT, (MorphOp)MORPH_BLACKHAT), // used as generator of operations
Values(1, 2, 3),
Bool()));
} } // namespace opencv_test::ocl
#endif // HAVE_OPENCL
+304
View File
@@ -0,0 +1,304 @@
/*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.
// Copyright (C) 2014, Itseez, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// @Authors
// Niko Li, newlife20080214@gmail.com
// Jia Haipeng, jiahaipeng95@gmail.com
// Shengen Yan, yanshengen@gmail.com
// Jiang Liyuan, lyuan001.good@163.com
// Rock Li, Rock.Li@amd.com
// Wu Zailong, bullet@yeah.net
// Xu Pang, pangxu010@163.com
// Sen Liu, swjtuls1987@126.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 {
///////////////////////////////////////////////////////////////////////////////
PARAM_TEST_CASE(CalcBackProject, MatDepth, int, bool)
{
int depth, N;
bool useRoi;
std::vector<float> ranges;
std::vector<int> channels;
double scale;
std::vector<Mat> images;
std::vector<Mat> images_roi;
std::vector<UMat> uimages;
std::vector<UMat> uimages_roi;
TEST_DECLARE_INPUT_PARAMETER(hist);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
virtual void SetUp()
{
depth = GET_PARAM(0);
N = GET_PARAM(1);
useRoi = GET_PARAM(2);
ASSERT_GE(2, N);
images.resize(N);
images_roi.resize(N);
uimages.resize(N);
uimages_roi.resize(N);
}
void random_roi()
{
Size roiSize = randomSize(1, MAX_VALUE);
int totalChannels = 0;
ranges.clear();
channels.clear();
for (int i = 0; i < N; ++i)
{
Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
int cn = randomInt(1, 5);
randomSubMat(images[i], images_roi[i], roiSize, srcBorder, CV_MAKE_TYPE(depth, cn), 0, 125);
ranges.push_back(10);
ranges.push_back(100);
channels.push_back(randomInt(0, cn) + totalChannels);
totalChannels += cn;
}
Mat tmpHist;
{
std::vector<int> hist_size(N);
for (int i = 0 ; i < N; ++i)
hist_size[i] = randomInt(10, 50);
cv::calcHist(images_roi, channels, noArray(), tmpHist, hist_size, ranges);
ASSERT_EQ(CV_32FC1, tmpHist.type());
}
Border histBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(hist, hist_roi, tmpHist.size(), histBorder, tmpHist.type(), 0, MAX_VALUE);
tmpHist.copyTo(hist_roi);
Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(dst, dst_roi, roiSize, dstBorder, CV_MAKE_TYPE(depth, 1), 5, 16);
for (int i = 0; i < N; ++i)
{
images[i].copyTo(uimages[i]);
Size _wholeSize;
Point ofs;
images_roi[i].locateROI(_wholeSize, ofs);
uimages_roi[i] = uimages[i](Rect(ofs.x, ofs.y, images_roi[i].cols, images_roi[i].rows));
}
UMAT_UPLOAD_INPUT_PARAMETER(hist);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
scale = randomDouble(0.1, 1);
}
void test_by_pict()
{
Mat frame1 = readImage("optflow/RubberWhale1.png", IMREAD_GRAYSCALE);
UMat usrc;
frame1.copyTo(usrc);
int histSize = randomInt(3, 29);
float hue_range[] = { 0, 180 };
const float* ranges1 = { hue_range };
Mat hist1;
//compute histogram
calcHist(&frame1, 1, 0, Mat(), hist1, 1, &histSize, &ranges1, true, false);
normalize(hist1, hist1, 0, 255, NORM_MINMAX, -1, Mat());
Mat dst1;
UMat udst1, src, uhist1;
hist1.copyTo(uhist1);
std::vector<UMat> uims;
uims.push_back(usrc);
std::vector<float> urngs;
urngs.push_back(0);
urngs.push_back(180);
std::vector<int> chs;
chs.push_back(0);
OCL_OFF(calcBackProject(&frame1, 1, 0, hist1, dst1, &ranges1, 1, true));
OCL_ON(calcBackProject(uims, chs, uhist1, udst1, urngs, 1.0));
if (cv::ocl::useOpenCL() && cv::ocl::Device::getDefault().isAMD())
{
Size dstSize = dst1.size();
int nDiffs = (int)(0.03f*dstSize.height*dstSize.width);
//check if the dst mats are the same except 3% difference
EXPECT_MAT_N_DIFF(dst1, udst1, nDiffs);
}
else
{
EXPECT_MAT_NEAR(dst1, udst1, 0.0);
}
}
};
//////////////////////////////// CalcBackProject //////////////////////////////////////////////
OCL_TEST_P(CalcBackProject, Mat)
{
for (int j = 0; j < test_loop_times; j++)
{
random_roi();
OCL_OFF(cv::calcBackProject(images_roi, channels, hist_roi, dst_roi, ranges, scale));
OCL_ON(cv::calcBackProject(uimages_roi, channels, uhist_roi, udst_roi, ranges, scale));
Size dstSize = dst_roi.size();
int nDiffs = std::max((int)(0.07f*dstSize.area()), 1);
//check if the dst mats are the same except 7% difference
EXPECT_MAT_N_DIFF(dst_roi, udst_roi, nDiffs);
}
}
OCL_TEST_P(CalcBackProject, Mat_RealImage)
{
//check on given image
test_by_pict();
}
//////////////////////////////// CalcHist //////////////////////////////////////////////
PARAM_TEST_CASE(CalcHist, bool)
{
bool useRoi;
TEST_DECLARE_INPUT_PARAMETER(src);
TEST_DECLARE_OUTPUT_PARAMETER(hist);
virtual void SetUp()
{
useRoi = GET_PARAM(0);
}
void random_roi()
{
Size roiSize = randomSize(1, MAX_VALUE);
Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, roiSize, srcBorder, CV_8UC1, 0, 256);
Border histBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(hist, hist_roi, Size(256, 1), histBorder, CV_32SC1, 0, MAX_VALUE);
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_OUTPUT_PARAMETER(hist);
}
};
OCL_TEST_P(CalcHist, Mat)
{
const std::vector<int> channels(1, 0);
std::vector<float> ranges(2);
std::vector<int> histSize(1, 256);
ranges[0] = 0;
ranges[1] = 256;
for (int j = 0; j < test_loop_times; j++)
{
random_roi();
OCL_OFF(cv::calcHist(std::vector<Mat>(1, src_roi), channels, noArray(), hist_roi, histSize, ranges, false));
OCL_ON(cv::calcHist(std::vector<UMat>(1, usrc_roi), channels, noArray(), uhist_roi, histSize, ranges, false));
OCL_EXPECT_MATS_NEAR(hist, 0.0);
}
}
TEST(CalcHistMask, CheckMask)
{
Mat gray = imread(cvtest::findDataFile("shared/baboon.png"), IMREAD_GRAYSCALE);
ASSERT_FALSE(gray.empty());
cv::Rect roi(gray.cols/4, gray.rows/4, gray.cols/2, gray.rows/2);
Mat mask = Mat::zeros(gray.size(), CV_8UC1);
mask(roi).setTo(255);
Mat mask_bool = Mat::zeros(gray.size(), CV_BoolC1);
mask_bool(roi).setTo(1);
Mat gray_roi = gray(roi);
const std::vector<int> channels(1, 0);
std::vector<int> histSize(1, 256);
std::vector<float> ranges(2);
ranges[0] = 0;
ranges[1] = 256;
Mat hist_mask, hist_bool, hist_roi;
cv::calcHist(std::vector<Mat>(1, gray_roi), channels, Mat(), hist_roi, histSize, ranges, false);
cv::calcHist(std::vector<Mat>(1, gray), channels, mask, hist_mask, histSize, ranges, false);
cv::calcHist(std::vector<Mat>(1, gray), channels, mask_bool, hist_bool, histSize, ranges, false);
EXPECT_MAT_NEAR(hist_roi, hist_mask, 0.0);
EXPECT_MAT_NEAR(hist_mask, hist_bool, 0.0);
}
/////////////////////////////////////////////////////////////////////////////////////
OCL_INSTANTIATE_TEST_CASE_P(Imgproc, CalcBackProject, Combine(Values((MatDepth)CV_8U), Values(1, 2), Bool()));
OCL_INSTANTIATE_TEST_CASE_P(Imgproc, CalcHist, Values(true, false));
} } // namespace opencv_test::ocl
#endif // HAVE_OPENCL
@@ -0,0 +1,184 @@
// 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 {
struct Vec2fComparator
{
bool operator()(const Vec2f& a, const Vec2f b) const
{
if(a[0] != b[0]) return a[0] < b[0];
else return a[1] < b[1];
}
};
/////////////////////////////// HoughLines ////////////////////////////////////
PARAM_TEST_CASE(HoughLines, double, double, int)
{
double rhoStep, thetaStep;
int threshold;
Size src_size;
Mat src, dst;
UMat usrc, udst;
virtual void SetUp()
{
rhoStep = GET_PARAM(0);
thetaStep = GET_PARAM(1);
threshold = GET_PARAM(2);
}
void generateTestData()
{
src_size = randomSize(500, 1920);
src.create(src_size, CV_8UC1);
src.setTo(Scalar::all(0));
line(src, Point(0, 100), Point(100, 100), Scalar::all(255), 1);
line(src, Point(0, 200), Point(100, 200), Scalar::all(255), 1);
line(src, Point(0, 400), Point(100, 400), Scalar::all(255), 1);
line(src, Point(100, 0), Point(100, 200), Scalar::all(255), 1);
line(src, Point(200, 0), Point(200, 200), Scalar::all(255), 1);
line(src, Point(400, 0), Point(400, 200), Scalar::all(255), 1);
src.copyTo(usrc);
}
void readRealTestData()
{
Mat img = readImage("shared/pic5.png", IMREAD_GRAYSCALE);
Canny(img, src, 100, 150, 3);
src.copyTo(usrc);
}
void Near(double eps = 0.)
{
EXPECT_EQ(dst.size(), udst.size());
if (dst.total() > 0)
{
Mat lines_cpu, lines_gpu;
dst.copyTo(lines_cpu);
udst.copyTo(lines_gpu);
std::sort(lines_cpu.begin<Vec2f>(), lines_cpu.end<Vec2f>(), Vec2fComparator());
std::sort(lines_gpu.begin<Vec2f>(), lines_gpu.end<Vec2f>(), Vec2fComparator());
EXPECT_LE(TestUtils::checkNorm2(lines_cpu, lines_gpu), eps);
}
}
};
OCL_TEST_P(HoughLines, RealImage)
{
readRealTestData();
OCL_OFF(cv::HoughLines(src, dst, rhoStep, thetaStep, threshold));
OCL_ON(cv::HoughLines(usrc, udst, rhoStep, thetaStep, threshold));
Near(1e-5);
}
OCL_TEST_P(HoughLines, GeneratedImage)
{
for (int j = 0; j < test_loop_times; j++)
{
generateTestData();
OCL_OFF(cv::HoughLines(src, dst, rhoStep, thetaStep, threshold));
OCL_ON(cv::HoughLines(usrc, udst, rhoStep, thetaStep, threshold));
Near(1e-5);
}
}
/////////////////////////////// HoughLinesP ///////////////////////////////////
PARAM_TEST_CASE(HoughLinesP, int, double, double)
{
double rhoStep, thetaStep, minLineLength, maxGap;
int threshold;
Size src_size;
Mat src, dst;
UMat usrc, udst;
virtual void SetUp()
{
rhoStep = 1.0;
thetaStep = CV_PI / 180;
threshold = GET_PARAM(0);
minLineLength = GET_PARAM(1);
maxGap = GET_PARAM(2);
}
void readRealTestData()
{
Mat img = readImage("shared/pic5.png", IMREAD_GRAYSCALE);
Canny(img, src, 50, 200, 3);
src.copyTo(usrc);
}
void Near(double eps = 0.)
{
Mat lines_gpu = udst.getMat(ACCESS_READ);
if (dst.total() > 0 && lines_gpu.total() > 0)
{
Mat result_cpu(src.size(), CV_8UC1, Scalar::all(0));
Mat result_gpu(src.size(), CV_8UC1, Scalar::all(0));
MatConstIterator_<Vec4i> it = dst.begin<Vec4i>(), end = dst.end<Vec4i>();
for ( ; it != end; it++)
{
Vec4i p = *it;
line(result_cpu, Point(p[0], p[1]), Point(p[2], p[3]), Scalar(255));
}
it = lines_gpu.begin<Vec4i>(), end = lines_gpu.end<Vec4i>();
for ( ; it != end; it++)
{
Vec4i p = *it;
line(result_gpu, Point(p[0], p[1]), Point(p[2], p[3]), Scalar(255));
}
EXPECT_MAT_SIMILAR(result_cpu, result_gpu, eps);
}
}
};
OCL_TEST_P(HoughLinesP, RealImage)
{
readRealTestData();
OCL_OFF(cv::HoughLinesP(src, dst, rhoStep, thetaStep, threshold, minLineLength, maxGap));
OCL_ON(cv::HoughLinesP(usrc, udst, rhoStep, thetaStep, threshold, minLineLength, maxGap));
Near(0.25);
}
OCL_INSTANTIATE_TEST_CASE_P(Imgproc, HoughLines, Combine(Values(1, 0.5), // rhoStep
Values(CV_PI / 180.0, CV_PI / 360.0), // thetaStep
Values(85, 150))); // threshold
OCL_INSTANTIATE_TEST_CASE_P(Imgproc, HoughLinesP, Combine(Values(100, 150), // threshold
Values(50, 100), // minLineLength
Values(5, 10))); // maxLineGap
} } // namespace opencv_test::ocl
#endif // HAVE_OPENCL
+596
View File
@@ -0,0 +1,596 @@
/*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
// Niko Li, newlife20080214@gmail.com
// Jia Haipeng, jiahaipeng95@gmail.com
// Shengen Yan, yanshengen@gmail.com
// Jiang Liyuan, lyuan001.good@163.com
// Rock Li, Rock.Li@amd.com
// Wu Zailong, bullet@yeah.net
// Xu Pang, pangxu010@163.com
// Sen Liu, swjtuls1987@126.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 {
///////////////////////////////////////////////////////////////////////////////
PARAM_TEST_CASE(ImgprocTestBase, MatType,
int, // blockSize
int, // border type
bool) // roi or not
{
int type, borderType, blockSize;
bool useRoi;
TEST_DECLARE_INPUT_PARAMETER(src);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
virtual void SetUp()
{
type = GET_PARAM(0);
blockSize = GET_PARAM(1);
borderType = GET_PARAM(2);
useRoi = GET_PARAM(3);
}
void random_roi()
{
Size roiSize = randomSize(1, MAX_VALUE);
Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, roiSize, srcBorder, type, 5, 256);
Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(dst, dst_roi, roiSize, dstBorder, type, 5, 16);
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
}
void Near(double threshold = 0.0, bool relative = false)
{
if (relative)
OCL_EXPECT_MATS_NEAR_RELATIVE(dst, threshold);
else
OCL_EXPECT_MATS_NEAR(dst, threshold);
}
};
//////////////////////////////// copyMakeBorder ////////////////////////////////////////////
PARAM_TEST_CASE(CopyMakeBorder, MatDepth, // depth
Channels, // channels
bool, // isolated or not
BorderType, // border type
bool) // roi or not
{
int type, borderType;
bool useRoi;
TestUtils::Border border;
Scalar val;
TEST_DECLARE_INPUT_PARAMETER(src);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
virtual void SetUp()
{
type = CV_MAKE_TYPE(GET_PARAM(0), GET_PARAM(1));
borderType = GET_PARAM(3);
if (GET_PARAM(2))
borderType |= BORDER_ISOLATED;
useRoi = GET_PARAM(4);
}
void random_roi()
{
border = randomBorder(0, MAX_VALUE << 2);
val = randomScalar(-MAX_VALUE, MAX_VALUE);
Size roiSize = randomSize(1, MAX_VALUE);
Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, roiSize, srcBorder, type, -MAX_VALUE, MAX_VALUE);
Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
dstBorder.top += border.top;
dstBorder.lef += border.lef;
dstBorder.rig += border.rig;
dstBorder.bot += border.bot;
randomSubMat(dst, dst_roi, roiSize, dstBorder, type, -MAX_VALUE, MAX_VALUE);
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
}
void Near()
{
OCL_EXPECT_MATS_NEAR(dst, 0);
}
};
OCL_TEST_P(CopyMakeBorder, Mat)
{
for (int i = 0; i < test_loop_times; ++i)
{
random_roi();
OCL_OFF(cv::copyMakeBorder(src_roi, dst_roi, border.top, border.bot, border.lef, border.rig, borderType, val));
OCL_ON(cv::copyMakeBorder(usrc_roi, udst_roi, border.top, border.bot, border.lef, border.rig, borderType, val));
Near();
}
}
//////////////////////////////// equalizeHist //////////////////////////////////////////////
typedef ImgprocTestBase EqualizeHist;
OCL_TEST_P(EqualizeHist, Mat)
{
for (int j = 0; j < test_loop_times; j++)
{
random_roi();
OCL_OFF(cv::equalizeHist(src_roi, dst_roi));
OCL_ON(cv::equalizeHist(usrc_roi, udst_roi));
Near(1);
}
}
//////////////////////////////// Corners test //////////////////////////////////////////
struct CornerTestBase :
public ImgprocTestBase
{
void random_roi()
{
Mat image = readImageType("../gpu/stereobm/aloe-L.png", type);
ASSERT_FALSE(image.empty());
bool isFP = CV_MAT_DEPTH(type) >= CV_32F;
float val = 255.0f;
if (isFP)
{
image.convertTo(image, -1, 1.0 / 255);
val /= 255.0f;
}
Size roiSize = image.size();
Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
Size wholeSize = Size(roiSize.width + srcBorder.lef + srcBorder.rig, roiSize.height + srcBorder.top + srcBorder.bot);
src = randomMat(wholeSize, type, -val, val, false);
src_roi = src(Rect(srcBorder.lef, srcBorder.top, roiSize.width, roiSize.height));
image.copyTo(src_roi);
Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(dst, dst_roi, roiSize, dstBorder, CV_32FC1, 5, 16);
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
}
};
typedef CornerTestBase CornerMinEigenVal;
OCL_TEST_P(CornerMinEigenVal, Mat)
{
for (int j = 0; j < test_loop_times; j++)
{
random_roi();
int apertureSize = 3;
OCL_OFF(cv::cornerMinEigenVal(src_roi, dst_roi, blockSize, apertureSize, borderType));
OCL_ON(cv::cornerMinEigenVal(usrc_roi, udst_roi, blockSize, apertureSize, borderType));
// The corner kernel uses native_sqrt() which has implementation defined accuracy.
// If we're using a CL implementation that isn't intel, test with relaxed accuracy.
if (!ocl::useOpenCL() || ocl::Device::getDefault().isIntel())
Near(1e-5, true);
else
Near(0.1, true);
}
}
//////////////////////////////// cornerHarris //////////////////////////////////////////
typedef CornerTestBase CornerHarris;
OCL_TEST_P(CornerHarris, Mat)
{
for (int j = 0; j < test_loop_times; j++)
{
random_roi();
int apertureSize = 3;
double k = randomDouble(0.01, 0.9);
OCL_OFF(cv::cornerHarris(src_roi, dst_roi, blockSize, apertureSize, k, borderType));
OCL_ON(cv::cornerHarris(usrc_roi, udst_roi, blockSize, apertureSize, k, borderType));
Near(1e-6, true);
}
}
//////////////////////////////// preCornerDetect //////////////////////////////////////////
typedef ImgprocTestBase PreCornerDetect;
OCL_TEST_P(PreCornerDetect, Mat)
{
for (int j = 0; j < test_loop_times; j++)
{
random_roi();
const int apertureSize = blockSize;
OCL_OFF(cv::preCornerDetect(src_roi, dst_roi, apertureSize, borderType));
OCL_ON(cv::preCornerDetect(usrc_roi, udst_roi, apertureSize, borderType));
Near(1e-6, true);
}
}
////////////////////////////////// integral /////////////////////////////////////////////////
struct Integral :
public ImgprocTestBase
{
int sdepth, sqdepth;
TEST_DECLARE_OUTPUT_PARAMETER(dst2);
virtual void SetUp()
{
type = GET_PARAM(0);
sdepth = GET_PARAM(1);
sqdepth = GET_PARAM(2);
useRoi = GET_PARAM(3);
}
void random_roi()
{
ASSERT_EQ(CV_MAT_CN(type), 1);
Size roiSize = randomSize(1, MAX_VALUE), isize = Size(roiSize.width + 1, roiSize.height + 1);
Border srcBorder = randomBorder(0, useRoi ? 2 : 0);
randomSubMat(src, src_roi, roiSize, srcBorder, type, 5, 256);
Border dstBorder = randomBorder(0, useRoi ? 2 : 0);
randomSubMat(dst, dst_roi, isize, dstBorder, sdepth, 5, 16);
Border dst2Border = randomBorder(0, useRoi ? 2 : 0);
randomSubMat(dst2, dst2_roi, isize, dst2Border, sqdepth, 5, 16);
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst2);
}
void Near2(double threshold = 0.0, bool relative = false)
{
if (relative)
OCL_EXPECT_MATS_NEAR_RELATIVE(dst2, threshold);
else
OCL_EXPECT_MATS_NEAR(dst2, threshold);
}
};
OCL_TEST_P(Integral, Mat1)
{
for (int j = 0; j < test_loop_times; j++)
{
random_roi();
OCL_OFF(cv::integral(src_roi, dst_roi, sdepth));
OCL_ON(cv::integral(usrc_roi, udst_roi, sdepth));
Near();
}
}
OCL_TEST_P(Integral, Mat2)
{
for (int j = 0; j < test_loop_times; j++)
{
random_roi();
OCL_OFF(cv::integral(src_roi, dst_roi, dst2_roi, sdepth, sqdepth));
OCL_ON(cv::integral(usrc_roi, udst_roi, udst2_roi, sdepth, sqdepth));
Near();
sqdepth == CV_32F ? Near2(1e-6, true) : Near2();
}
}
//////////////////////////////////////// threshold //////////////////////////////////////////////
struct Threshold :
public ImgprocTestBase
{
int thresholdType;
virtual void SetUp()
{
type = GET_PARAM(0);
thresholdType = GET_PARAM(2);
useRoi = GET_PARAM(3);
}
};
OCL_TEST_P(Threshold, Mat)
{
for (int j = 0; j < test_loop_times; j++)
{
random_roi();
double maxVal = randomDouble(20.0, 127.0);
double thresh = randomDouble(0.0, maxVal);
OCL_OFF(cv::threshold(src_roi, dst_roi, thresh, maxVal, thresholdType));
OCL_ON(cv::threshold(usrc_roi, udst_roi, thresh, maxVal, thresholdType));
Near(1);
}
}
struct Threshold_Dryrun :
public ImgprocTestBase
{
int thresholdType;
virtual void SetUp()
{
type = GET_PARAM(0);
thresholdType = GET_PARAM(2);
useRoi = GET_PARAM(3);
}
};
OCL_TEST_P(Threshold_Dryrun, Mat)
{
for (int j = 0; j < test_loop_times; j++)
{
random_roi();
double maxVal = randomDouble(20.0, 127.0);
double thresh = randomDouble(0.0, maxVal);
const int _thresholdType = thresholdType | THRESH_DRYRUN;
src_roi.copyTo(dst_roi);
usrc_roi.copyTo(udst_roi);
OCL_OFF(cv::threshold(src_roi, dst_roi, thresh, maxVal, _thresholdType));
OCL_ON(cv::threshold(usrc_roi, udst_roi, thresh, maxVal, _thresholdType));
OCL_EXPECT_MATS_NEAR(dst, 0);
}
}
struct Threshold_masked :
public ImgprocTestBase
{
int thresholdType;
virtual void SetUp()
{
type = GET_PARAM(0);
thresholdType = GET_PARAM(2);
useRoi = GET_PARAM(3);
}
};
OCL_TEST_P(Threshold_masked, Mat)
{
for (int j = 0; j < test_loop_times; j++)
{
random_roi();
double maxVal = randomDouble(20.0, 127.0);
double thresh = randomDouble(0.0, maxVal);
const int _thresholdType = thresholdType;
cv::Size sz = src_roi.size();
cv::Mat mask_roi = cv::Mat::zeros(sz, CV_8UC1);
cv::RotatedRect ellipseRect((cv::Point2f)cv::Point(sz.width/2, sz.height/2), (cv::Size2f)sz, 0);
cv::ellipse(mask_roi, ellipseRect, cv::Scalar::all(255), cv::FILLED);//for very different mask alignments
cv::UMat umask_roi(mask_roi.size(), mask_roi.type());
mask_roi.copyTo(umask_roi.getMat(cv::AccessFlag::ACCESS_WRITE));
src_roi.copyTo(dst_roi);
usrc_roi.copyTo(udst_roi);
OCL_OFF(cv::thresholdWithMask(src_roi, dst_roi, mask_roi, thresh, maxVal, _thresholdType));
OCL_ON(cv::thresholdWithMask(usrc_roi, udst_roi, umask_roi, thresh, maxVal, _thresholdType));
OCL_EXPECT_MATS_NEAR(dst, 0);
}
}
/////////////////////////////////////////// CLAHE //////////////////////////////////////////////////
PARAM_TEST_CASE(CLAHETest, Size, double, bool)
{
Size gridSize;
double clipLimit;
bool useRoi;
TEST_DECLARE_INPUT_PARAMETER(src);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
virtual void SetUp()
{
gridSize = GET_PARAM(0);
clipLimit = GET_PARAM(1);
useRoi = GET_PARAM(2);
}
void random_roi()
{
Size roiSize = randomSize(std::max(gridSize.height, gridSize.width), MAX_VALUE);
Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, roiSize, srcBorder, CV_8UC1, 5, 256);
Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(dst, dst_roi, roiSize, dstBorder, CV_8UC1, 5, 16);
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
}
void Near(double threshold = 0.0)
{
OCL_EXPECT_MATS_NEAR(dst, threshold);
}
};
OCL_TEST_P(CLAHETest, Accuracy)
{
for (int i = 0; i < test_loop_times; ++i)
{
random_roi();
Ptr<CLAHE> clahe = cv::createCLAHE(clipLimit, gridSize);
OCL_OFF(clahe->apply(src_roi, dst_roi));
OCL_ON(clahe->apply(usrc_roi, udst_roi));
Near(1.0);
}
}
/////////////////////////////////////////////////////////////////////////////////////
OCL_INSTANTIATE_TEST_CASE_P(Imgproc, EqualizeHist, Combine(
Values((MatType)CV_8UC1),
Values(0), // not used
Values(0), // not used
Bool()));
OCL_INSTANTIATE_TEST_CASE_P(Imgproc, CornerMinEigenVal, Combine(
Values((MatType)CV_8UC1, (MatType)CV_32FC1),
Values(3, 5),
Values((BorderType)BORDER_CONSTANT, (BorderType)BORDER_REPLICATE,
(BorderType)BORDER_REFLECT, (BorderType)BORDER_REFLECT101),
Bool()));
OCL_INSTANTIATE_TEST_CASE_P(Imgproc, CornerHarris, Combine(
Values((MatType)CV_8UC1, CV_32FC1),
Values(3, 5),
Values( (BorderType)BORDER_CONSTANT, (BorderType)BORDER_REPLICATE,
(BorderType)BORDER_REFLECT, (BorderType)BORDER_REFLECT_101),
Bool()));
OCL_INSTANTIATE_TEST_CASE_P(Imgproc, PreCornerDetect, Combine(
Values((MatType)CV_8UC1, CV_32FC1),
Values(3, 5),
Values( (BorderType)BORDER_CONSTANT, (BorderType)BORDER_REPLICATE,
(BorderType)BORDER_REFLECT, (BorderType)BORDER_REFLECT_101),
Bool()));
OCL_INSTANTIATE_TEST_CASE_P(Imgproc, Integral, Combine(
Values((MatType)CV_8UC1), // TODO does not work with CV_32F, CV_64F
Values(CV_32SC1, CV_32FC1), // desired sdepth
Values(CV_32FC1, CV_64FC1), // desired sqdepth
Bool()));
OCL_INSTANTIATE_TEST_CASE_P(Imgproc, Threshold, Combine(
Values(CV_8UC1, CV_8UC2, CV_8UC3, CV_8UC4,
CV_16SC1, CV_16SC2, CV_16SC3, CV_16SC4,
CV_32FC1, CV_32FC2, CV_32FC3, CV_32FC4),
Values(0),
Values(ThreshOp(THRESH_BINARY),
ThreshOp(THRESH_BINARY_INV), ThreshOp(THRESH_TRUNC),
ThreshOp(THRESH_TOZERO), ThreshOp(THRESH_TOZERO_INV)),
Bool()));
OCL_INSTANTIATE_TEST_CASE_P(Imgproc, Threshold_Dryrun, Combine(
Values(CV_8UC1, CV_8UC2, CV_8UC3, CV_8UC4,
CV_16SC1, CV_16SC2, CV_16SC3, CV_16SC4,
CV_32FC1, CV_32FC2, CV_32FC3, CV_32FC4),
Values(0),
Values(ThreshOp(THRESH_BINARY),
ThreshOp(THRESH_BINARY_INV), ThreshOp(THRESH_TRUNC),
ThreshOp(THRESH_TOZERO), ThreshOp(THRESH_TOZERO_INV)),
Bool()));
OCL_INSTANTIATE_TEST_CASE_P(Imgproc, Threshold_masked, Combine(
Values(CV_8UC1, CV_8UC3, CV_16SC1, CV_16SC3, CV_16UC1, CV_16UC3, CV_32FC1, CV_32FC3, CV_64FC1, CV_64FC3),
Values(0),
Values(ThreshOp(THRESH_BINARY),
ThreshOp(THRESH_BINARY_INV), ThreshOp(THRESH_TRUNC),
ThreshOp(THRESH_TOZERO), ThreshOp(THRESH_TOZERO_INV)),
Bool()));
OCL_INSTANTIATE_TEST_CASE_P(Imgproc, CLAHETest, Combine(
Values(Size(4, 4), Size(32, 8), Size(8, 64)),
Values(0.0, 10.0, 62.0, 300.0),
Bool()));
OCL_INSTANTIATE_TEST_CASE_P(ImgprocTestBase, CopyMakeBorder, Combine(
testing::Values((MatDepth)CV_8U, (MatDepth)CV_16S, (MatDepth)CV_32S, (MatDepth)CV_32F),
testing::Values(Channels(1), Channels(3), (Channels)4),
Bool(), // border isolated or not
Values((BorderType)BORDER_CONSTANT, (BorderType)BORDER_REPLICATE, (BorderType)BORDER_REFLECT,
(BorderType)BORDER_WRAP, (BorderType)BORDER_REFLECT_101),
Bool()));
} } // namespace opencv_test::ocl
#endif // HAVE_OPENCL
@@ -0,0 +1,133 @@
/*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.
//
//
// 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 {
///////////////////////////////////////////// matchTemplate //////////////////////////////////////////////////////////
CV_ENUM(MatchTemplType, cv::TM_CCORR, cv::TM_CCORR_NORMED, cv::TM_SQDIFF, cv::TM_SQDIFF_NORMED, cv::TM_CCOEFF, cv::TM_CCOEFF_NORMED)
PARAM_TEST_CASE(MatchTemplate, MatDepth, Channels, MatchTemplType, bool)
{
int type;
int depth;
int method;
bool use_roi;
TEST_DECLARE_INPUT_PARAMETER(image);
TEST_DECLARE_INPUT_PARAMETER(templ);
TEST_DECLARE_OUTPUT_PARAMETER(result);
virtual void SetUp()
{
type = CV_MAKE_TYPE(GET_PARAM(0), GET_PARAM(1));
depth = GET_PARAM(0);
method = GET_PARAM(2);
use_roi = GET_PARAM(3);
}
void generateTestData()
{
Size image_roiSize = randomSize(2, 100);
Size templ_roiSize = Size(randomInt(1, image_roiSize.width), randomInt(1, image_roiSize.height));
Size result_roiSize = Size(image_roiSize.width - templ_roiSize.width + 1,
image_roiSize.height - templ_roiSize.height + 1);
const double upValue = 256;
Border imageBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(image, image_roi, image_roiSize, imageBorder, type, -upValue, upValue);
Border templBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(templ, templ_roi, templ_roiSize, templBorder, type, -upValue, upValue);
Border resultBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(result, result_roi, result_roiSize, resultBorder, CV_32FC1, -upValue, upValue);
UMAT_UPLOAD_INPUT_PARAMETER(image);
UMAT_UPLOAD_INPUT_PARAMETER(templ);
UMAT_UPLOAD_OUTPUT_PARAMETER(result);
}
void Near()
{
bool isNormed =
method == TM_CCORR_NORMED ||
method == TM_SQDIFF_NORMED ||
method == TM_CCOEFF_NORMED;
if (isNormed)
OCL_EXPECT_MATS_NEAR(result, 3e-2);
else
OCL_EXPECT_MATS_NEAR_RELATIVE_SPARSE(result, 1.5e-2);
}
};
OCL_TEST_P(MatchTemplate, Mat)
{
for (int j = 0; j < test_loop_times; j++)
{
generateTestData();
OCL_OFF(cv::matchTemplate(image_roi, templ_roi, result_roi, method));
OCL_ON(cv::matchTemplate(uimage_roi, utempl_roi, uresult_roi, method));
Near();
}
}
OCL_INSTANTIATE_TEST_CASE_P(ImageProc, MatchTemplate, Combine(
Values(CV_8U, CV_32F),
Values(1, 2, 3, 4),
MatchTemplType::all(),
Bool())
);
} } // namespace opencv_test::ocl
#endif
@@ -0,0 +1,111 @@
/*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.
//
//
// 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 {
/////////////////////////////////////////////medianFilter//////////////////////////////////////////////////////////
PARAM_TEST_CASE(MedianFilter, MatDepth, Channels, int, bool)
{
int type;
int ksize;
bool use_roi;
TEST_DECLARE_INPUT_PARAMETER(src);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
virtual void SetUp()
{
type = CV_MAKE_TYPE(GET_PARAM(0), GET_PARAM(1));
ksize = GET_PARAM(2);
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, type, -MAX_VALUE, MAX_VALUE);
Border dstBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(dst, dst_roi, roiSize, dstBorder, type, -MAX_VALUE, MAX_VALUE);
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
}
void Near(double threshold = 0.0)
{
EXPECT_MAT_NEAR(dst, udst, threshold);
EXPECT_MAT_NEAR(dst_roi, udst_roi, threshold);
}
};
OCL_TEST_P(MedianFilter, Mat)
{
for (int j = 0; j < test_loop_times; j++)
{
generateTestData();
OCL_OFF(cv::medianBlur(src_roi, dst_roi, ksize));
OCL_ON(cv::medianBlur(usrc_roi, udst_roi, ksize));
Near(0);
}
}
OCL_INSTANTIATE_TEST_CASE_P(ImageProc, MedianFilter, Combine(
Values(CV_8U, CV_16U, CV_16S, CV_32F),
OCL_ALL_CHANNELS,
Values(3, 5),
Bool())
);
} } // namespace opencv_test::ocl
#endif
+171
View File
@@ -0,0 +1,171 @@
///////////////////////////////////////////////////////////////////////////////////////
//
// 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.
// Third party copyrights are property of their respective owners.
//
// @Authors
// Yao Wang yao@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 {
PARAM_TEST_CASE(PyrTestBase, MatDepth, Channels, BorderType, bool)
{
int depth, channels, borderType;
bool use_roi;
TEST_DECLARE_INPUT_PARAMETER(src);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
virtual void SetUp()
{
depth = GET_PARAM(0);
channels = GET_PARAM(1);
borderType = GET_PARAM(2);
use_roi = GET_PARAM(3);
}
void generateTestData(Size src_roiSize, Size dst_roiSize)
{
Border srcBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, src_roiSize, srcBorder, CV_MAKETYPE(depth, channels), -MAX_VALUE, MAX_VALUE);
Border dstBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(dst, dst_roi, dst_roiSize, dstBorder, CV_MAKETYPE(depth, channels), -MAX_VALUE, MAX_VALUE);
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
}
void Near(double threshold = 0.0)
{
OCL_EXPECT_MATS_NEAR(dst, threshold);
}
};
/////////////////////// PyrDown //////////////////////////
typedef PyrTestBase PyrDown;
OCL_TEST_P(PyrDown, Mat)
{
for (int j = 0; j < test_loop_times; j++)
{
Size src_roiSize = randomSize(1, MAX_VALUE);
Size dst_roiSize = Size(randomInt((src_roiSize.width - 1) / 2, (src_roiSize.width + 3) / 2),
randomInt((src_roiSize.height - 1) / 2, (src_roiSize.height + 3) / 2));
dst_roiSize = dst_roiSize.empty() ? Size((src_roiSize.width + 1) / 2, (src_roiSize.height + 1) / 2) : dst_roiSize;
generateTestData(src_roiSize, dst_roiSize);
OCL_OFF(pyrDown(src_roi, dst_roi, dst_roiSize, borderType));
OCL_ON(pyrDown(usrc_roi, udst_roi, dst_roiSize, borderType));
Near(depth == CV_32F ? 1e-4f : 1.0f);
}
}
OCL_INSTANTIATE_TEST_CASE_P(ImgprocPyr, PyrDown, Combine(
Values(CV_8U, CV_16U, CV_16S, CV_32F, CV_64F),
Values(1, 2, 3, 4),
Values((BorderType)BORDER_REPLICATE,
(BorderType)BORDER_REFLECT, (BorderType)BORDER_REFLECT_101),
Bool()
));
/////////////////////// PyrUp //////////////////////////
typedef PyrTestBase PyrUp;
OCL_TEST_P(PyrUp, Mat)
{
for (int j = 0; j < test_loop_times; j++)
{
Size src_roiSize = randomSize(1, MAX_VALUE);
Size dst_roiSize = Size(2 * src_roiSize.width, 2 * src_roiSize.height);
generateTestData(src_roiSize, dst_roiSize);
OCL_OFF(pyrUp(src_roi, dst_roi, dst_roiSize, borderType));
OCL_ON(pyrUp(usrc_roi, udst_roi, dst_roiSize, borderType));
Near(depth == CV_32F ? 1e-4f : 1.0f);
}
}
typedef PyrTestBase PyrUp_cols2;
OCL_TEST_P(PyrUp_cols2, Mat)
{
for (int j = 0; j < test_loop_times; j++)
{
Size src_roiSize = randomSize(1, MAX_VALUE);
src_roiSize.width += (src_roiSize.width % 2);
Size dst_roiSize = Size(2 * src_roiSize.width, 2 * src_roiSize.height);
generateTestData(src_roiSize, dst_roiSize);
OCL_OFF(pyrUp(src_roi, dst_roi, dst_roiSize, borderType));
OCL_ON(pyrUp(usrc_roi, udst_roi, dst_roiSize, borderType));
Near(depth == CV_32F ? 1e-4f : 1.0f);
}
}
OCL_INSTANTIATE_TEST_CASE_P(ImgprocPyr, PyrUp, Combine(
Values(CV_8U, CV_16U, CV_16S, CV_32F, CV_64F),
Values(1, 2, 3, 4),
Values((BorderType)BORDER_REFLECT_101),
Bool()
));
OCL_INSTANTIATE_TEST_CASE_P(ImgprocPyr, PyrUp_cols2, Combine(
Values((MatDepth)CV_8U),
Values((Channels)1),
Values((BorderType)BORDER_REFLECT_101),
Bool()
));
} } // namespace opencv_test::ocl
#endif // HAVE_OPENCL
@@ -0,0 +1,168 @@
/*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.
//
// 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 {
/////////////////////////////////////////////////////////////////////////////////////////////////
// sepFilter2D
PARAM_TEST_CASE(SepFilter2D, MatDepth, Channels, BorderType, bool, bool)
{
static const int kernelMinSize = 2;
static const int kernelMaxSize = 10;
int type;
Point anchor;
int borderType;
bool useRoi;
Mat kernelX, kernelY;
double delta;
TEST_DECLARE_INPUT_PARAMETER(src);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
virtual void SetUp()
{
type = CV_MAKE_TYPE(GET_PARAM(0), GET_PARAM(1));
borderType = GET_PARAM(2) | (GET_PARAM(3) ? BORDER_ISOLATED : 0);
useRoi = GET_PARAM(4);
}
void random_roi(bool bitExact)
{
Size ksize = randomSize(kernelMinSize, kernelMaxSize);
if (1 != ksize.width % 2)
ksize.width++;
if (1 != ksize.height % 2)
ksize.height++;
Mat temp = randomMat(Size(ksize.width, 1), CV_32FC1, -0.5, 1.0);
cv::normalize(temp, kernelX, 1.0, 0.0, NORM_L1);
temp = randomMat(Size(1, ksize.height), CV_32FC1, -0.5, 1.0);
cv::normalize(temp, kernelY, 1.0, 0.0, NORM_L1);
if (bitExact)
{
kernelX.convertTo(temp, CV_32S, 256);
temp.convertTo(kernelX, CV_32F, 1.0 / 256);
kernelY.convertTo(temp, CV_32S, 256);
temp.convertTo(kernelY, CV_32F, 1.0 / 256);
}
Size roiSize = randomSize(ksize.width, MAX_VALUE, ksize.height, MAX_VALUE);
Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, roiSize, srcBorder, type, -MAX_VALUE, MAX_VALUE);
Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(dst, dst_roi, roiSize, dstBorder, type, -MAX_VALUE, MAX_VALUE);
anchor.x = anchor.y = -1;
delta = randomDouble(-100, 100);
if (bitExact)
{
delta = (int)(delta * 256) / 256.0;
}
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
}
void Near(double threshold = 0.0)
{
OCL_EXPECT_MATS_NEAR(dst, threshold);
}
};
OCL_TEST_P(SepFilter2D, Mat)
{
for (int j = 0; j < test_loop_times + 3; j++)
{
random_roi(false);
OCL_OFF(cv::sepFilter2D(src_roi, dst_roi, -1, kernelX, kernelY, anchor, delta, borderType));
OCL_ON(cv::sepFilter2D(usrc_roi, udst_roi, -1, kernelX, kernelY, anchor, delta, borderType));
Near(1.0);
}
}
OCL_TEST_P(SepFilter2D, Mat_BitExact)
{
for (int j = 0; j < test_loop_times + 3; j++)
{
random_roi(true);
OCL_OFF(cv::sepFilter2D(src_roi, dst_roi, -1, kernelX, kernelY, anchor, delta, borderType));
OCL_ON(cv::sepFilter2D(usrc_roi, udst_roi, -1, kernelX, kernelY, anchor, delta, borderType));
if (src_roi.depth() < CV_32F)
Near(0.0);
else
Near(1e-3);
}
}
OCL_INSTANTIATE_TEST_CASE_P(ImageProc, SepFilter2D,
Combine(
Values(CV_8U, CV_32F),
OCL_ALL_CHANNELS,
Values(
(BorderType)BORDER_CONSTANT,
(BorderType)BORDER_REPLICATE,
(BorderType)BORDER_REFLECT,
(BorderType)BORDER_REFLECT_101),
Bool(), // BORDER_ISOLATED
Bool() // ROI
)
);
} } // namespace opencv_test::ocl
#endif // HAVE_OPENCL
+649
View File
@@ -0,0 +1,649 @@
/*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
// Niko Li, newlife20080214@gmail.com
// Jia Haipeng, jiahaipeng95@gmail.com
// Shengen Yan, yanshengen@gmail.com
// Jiang Liyuan, lyuan001.good@163.com
// Rock Li, Rock.Li@amd.com
// Wu Zailong, bullet@yeah.net
// Xu Pang, pangxu010@163.com
// Sen Liu, swjtuls1987@126.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 {
enum
{
noType = -1
};
/////////////////////////////////////////////////////////////////////////////////////////////////
// warpAffine & warpPerspective
PARAM_TEST_CASE(WarpTestBase, MatType, Interpolation, bool, bool)
{
int type, interpolation;
Size dsize;
bool useRoi, mapInverse;
int depth;
TEST_DECLARE_INPUT_PARAMETER(src);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
virtual void SetUp()
{
type = GET_PARAM(0);
interpolation = GET_PARAM(1);
mapInverse = GET_PARAM(2);
useRoi = GET_PARAM(3);
depth = CV_MAT_DEPTH(type);
if (mapInverse)
interpolation |= WARP_INVERSE_MAP;
}
void random_roi()
{
dsize = randomSize(1, MAX_VALUE);
Size roiSize = randomSize(1, MAX_VALUE);
Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, roiSize, srcBorder, type, -MAX_VALUE, MAX_VALUE);
Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(dst, dst_roi, dsize, dstBorder, type, -MAX_VALUE, MAX_VALUE);
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
}
void Near(double threshold = 0.0)
{
if (depth < CV_32F)
EXPECT_MAT_N_DIFF_EPS(dst_roi, udst_roi, 1, cvRound(dst_roi.total()*threshold));
else
OCL_EXPECT_MATS_NEAR_RELATIVE(dst, threshold);
}
};
PARAM_TEST_CASE(WarpTest_cols4_Base, MatType, Interpolation, bool, bool)
{
int type, interpolation;
Size dsize;
bool useRoi, mapInverse;
int depth;
TEST_DECLARE_INPUT_PARAMETER(src);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
virtual void SetUp()
{
type = GET_PARAM(0);
interpolation = GET_PARAM(1);
mapInverse = GET_PARAM(2);
useRoi = GET_PARAM(3);
depth = CV_MAT_DEPTH(type);
if (mapInverse)
interpolation |= WARP_INVERSE_MAP;
}
void random_roi()
{
dsize = randomSize(1, MAX_VALUE);
dsize.width = ((dsize.width >> 2) + 1) * 4;
Size roiSize = randomSize(1, MAX_VALUE);
Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, roiSize, srcBorder, type, -MAX_VALUE, MAX_VALUE);
Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(dst, dst_roi, dsize, dstBorder, type, -MAX_VALUE, MAX_VALUE);
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
}
void Near(double threshold = 0.0)
{
if (depth < CV_32F)
EXPECT_MAT_N_DIFF(dst_roi, udst_roi, cvRound(dst_roi.total()*threshold));
else
OCL_EXPECT_MATS_NEAR_RELATIVE(dst, threshold);
}
};
/////warpAffine
typedef WarpTestBase WarpAffine;
/////warpAffine
typedef WarpTestBase WarpAffine;
OCL_TEST_P(WarpAffine, Mat)
{
for (int j = 0; j < test_loop_times; j++)
{
double eps = depth < CV_32F ? ( depth < CV_16U ? 0.09 : 0.04 ) : 0.06;
random_roi();
Mat M = getRotationMatrix2D(Point2f(src_roi.cols / 2.0f, src_roi.rows / 2.0f),
rng.uniform(-180.f, 180.f), rng.uniform(0.4f, 2.0f));
OCL_OFF(cv::warpAffine(src_roi, dst_roi, M, dsize, interpolation));
OCL_ON(cv::warpAffine(usrc_roi, udst_roi, M, dsize, interpolation));
Near(eps);
}
}
OCL_TEST_P(WarpAffine, inplace_25853) // when src and dst are the same variable, ocl on/off should produce consistent and correct results
{
for (int j = 0; j < test_loop_times; j++)
{
double eps = depth < CV_32F ? ( depth < CV_16U ? 0.09 : 0.04 ) : 0.06;
random_roi();
Mat M = getRotationMatrix2D(Point2f(src_roi.cols / 2.0f, src_roi.rows / 2.0f),
rng.uniform(-180.f, 180.f), rng.uniform(0.4f, 2.0f));
OCL_OFF(cv::warpAffine(src_roi, src_roi, M, dsize, interpolation));
OCL_ON(cv::warpAffine(usrc_roi, usrc_roi, M, dsize, interpolation));
dst_roi = src_roi.clone();
udst_roi = usrc_roi.clone();
Near(eps);
}
}
typedef WarpTest_cols4_Base WarpAffine_cols4;
OCL_TEST_P(WarpAffine_cols4, Mat)
{
for (int j = 0; j < test_loop_times; j++)
{
double eps = depth < CV_32F ? 0.04 : 0.06;
random_roi();
Mat M = getRotationMatrix2D(Point2f(src_roi.cols / 2.0f, src_roi.rows / 2.0f),
rng.uniform(-180.f, 180.f), rng.uniform(0.4f, 2.0f));
OCL_OFF(cv::warpAffine(src_roi, dst_roi, M, dsize, interpolation));
OCL_ON(cv::warpAffine(usrc_roi, udst_roi, M, dsize, interpolation));
Near(eps);
}
}
//// warpPerspective
typedef WarpTestBase WarpPerspective;
OCL_TEST_P(WarpPerspective, Mat)
{
for (int j = 0; j < test_loop_times; j++)
{
double eps = depth < CV_32F ? 0.03 : 0.06;
random_roi();
float cols = static_cast<float>(src_roi.cols), rows = static_cast<float>(src_roi.rows);
float cols2 = cols / 2.0f, rows2 = rows / 2.0f;
Point2f sp[] = { Point2f(0.0f, 0.0f), Point2f(cols, 0.0f), Point2f(0.0f, rows), Point2f(cols, rows) };
Point2f dp[] = { Point2f(rng.uniform(0.0f, cols2), rng.uniform(0.0f, rows2)),
Point2f(rng.uniform(cols2, cols), rng.uniform(0.0f, rows2)),
Point2f(rng.uniform(0.0f, cols2), rng.uniform(rows2, rows)),
Point2f(rng.uniform(cols2, cols), rng.uniform(rows2, rows)) };
Mat M = getPerspectiveTransform(sp, dp);
OCL_OFF(cv::warpPerspective(src_roi, dst_roi, M, dsize, interpolation));
OCL_ON(cv::warpPerspective(usrc_roi, udst_roi, M, dsize, interpolation));
Near(eps);
}
}
typedef WarpTest_cols4_Base WarpPerspective_cols4;
OCL_TEST_P(WarpPerspective_cols4, Mat)
{
for (int j = 0; j < test_loop_times; j++)
{
double eps = depth < CV_32F ? 0.03 : 0.06;
random_roi();
float cols = static_cast<float>(src_roi.cols), rows = static_cast<float>(src_roi.rows);
float cols2 = cols / 2.0f, rows2 = rows / 2.0f;
Point2f sp[] = { Point2f(0.0f, 0.0f), Point2f(cols, 0.0f), Point2f(0.0f, rows), Point2f(cols, rows) };
Point2f dp[] = { Point2f(rng.uniform(0.0f, cols2), rng.uniform(0.0f, rows2)),
Point2f(rng.uniform(cols2, cols), rng.uniform(0.0f, rows2)),
Point2f(rng.uniform(0.0f, cols2), rng.uniform(rows2, rows)),
Point2f(rng.uniform(cols2, cols), rng.uniform(rows2, rows)) };
Mat M = getPerspectiveTransform(sp, dp);
OCL_OFF(cv::warpPerspective(src_roi, dst_roi, M, dsize, interpolation));
OCL_ON(cv::warpPerspective(usrc_roi, udst_roi, M, dsize, interpolation));
Near(eps);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////
//// resize
PARAM_TEST_CASE(Resize, MatType, double, double, Interpolation, bool, int)
{
int type, interpolation;
int widthMultiple;
double fx, fy;
bool useRoi;
TEST_DECLARE_INPUT_PARAMETER(src);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
virtual void SetUp()
{
type = GET_PARAM(0);
fx = GET_PARAM(1);
fy = GET_PARAM(2);
interpolation = GET_PARAM(3);
useRoi = GET_PARAM(4);
widthMultiple = GET_PARAM(5);
}
void random_roi()
{
CV_Assert(fx > 0 && fy > 0);
Size srcRoiSize = randomSize(10, MAX_VALUE), dstRoiSize;
// Make sure the width is a multiple of the requested value, and no more
srcRoiSize.width += widthMultiple - 1 - (srcRoiSize.width - 1) % widthMultiple;
dstRoiSize.width = cvRound(srcRoiSize.width * fx);
dstRoiSize.height = cvRound(srcRoiSize.height * fy);
if (dstRoiSize.empty())
{
random_roi();
return;
}
Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, srcRoiSize, srcBorder, type, -MAX_VALUE, MAX_VALUE);
Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(dst, dst_roi, dstRoiSize, dstBorder, type, -MAX_VALUE, MAX_VALUE);
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
}
};
#if defined(__aarch64__) || defined(__arm__)
const int integerEps = 3;
#else
const int integerEps = 1;
#endif
OCL_TEST_P(Resize, Mat)
{
for (int j = 0; j < test_loop_times; j++)
{
int depth = CV_MAT_DEPTH(type);
double eps = depth <= CV_32S ? integerEps : 5e-2;
random_roi();
OCL_OFF(cv::resize(src_roi, dst_roi, Size(), fx, fy, interpolation));
OCL_ON(cv::resize(usrc_roi, udst_roi, Size(), fx, fy, interpolation));
OCL_EXPECT_MAT_N_DIFF(dst, eps);
}
}
OCL_TEST(Resize, overflow_21198)
{
Mat src(Size(600, 600), CV_16UC3, Scalar::all(32768));
UMat src_u;
src.copyTo(src_u);
Mat dst;
cv::resize(src, dst, Size(1024, 1024), 0, 0, INTER_LINEAR);
UMat dst_u;
cv::resize(src_u, dst_u, Size(1024, 1024), 0, 0, INTER_LINEAR);
EXPECT_LE(cv::norm(dst_u, dst, NORM_INF), 1.0f);
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// remap
PARAM_TEST_CASE(Remap, MatDepth, Channels, std::pair<MatType, MatType>, BorderType, bool)
{
int srcType, map1Type, map2Type;
int borderType;
bool useRoi;
Scalar val;
TEST_DECLARE_INPUT_PARAMETER(src);
TEST_DECLARE_INPUT_PARAMETER(map1);
TEST_DECLARE_INPUT_PARAMETER(map2);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
virtual void SetUp()
{
srcType = CV_MAKE_TYPE(GET_PARAM(0), GET_PARAM(1));
map1Type = GET_PARAM(2).first;
map2Type = GET_PARAM(2).second;
borderType = GET_PARAM(3);
useRoi = GET_PARAM(4);
}
void random_roi()
{
val = randomScalar(-MAX_VALUE, MAX_VALUE);
Size srcROISize = randomSize(1, MAX_VALUE);
Size dstROISize = randomSize(1, MAX_VALUE);
Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, srcROISize, srcBorder, srcType, 5, 256);
Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(dst, dst_roi, dstROISize, dstBorder, srcType, -MAX_VALUE, MAX_VALUE);
int mapMaxValue = MAX_VALUE << 2;
Border map1Border = randomBorder(0, useRoi ? MAX_VALUE : 0);
randomSubMat(map1, map1_roi, dstROISize, map1Border, map1Type, -mapMaxValue, mapMaxValue);
Border map2Border = randomBorder(0, useRoi ? MAX_VALUE + 1 : 0);
if (map2Type != noType)
{
int mapMinValue = -mapMaxValue;
if (map2Type == CV_16UC1 || map2Type == CV_16SC1)
mapMinValue = 0, mapMaxValue = INTER_TAB_SIZE2;
randomSubMat(map2, map2_roi, dstROISize, map2Border, map2Type, mapMinValue, mapMaxValue);
}
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_INPUT_PARAMETER(map1);
UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
if (noType != map2Type)
UMAT_UPLOAD_INPUT_PARAMETER(map2);
}
};
typedef Remap Remap_INTER_NEAREST;
OCL_TEST_P(Remap_INTER_NEAREST, Mat)
{
for (int j = 0; j < test_loop_times; j++)
{
random_roi();
OCL_OFF(cv::remap(src_roi, dst_roi, map1_roi, map2_roi, INTER_NEAREST, borderType, val));
OCL_ON(cv::remap(usrc_roi, udst_roi, umap1_roi, umap2_roi, INTER_NEAREST, borderType, val));
OCL_EXPECT_MAT_N_DIFF(dst, 1.0);
}
}
typedef Remap Remap_INTER_LINEAR;
OCL_TEST_P(Remap_INTER_LINEAR, Mat)
{
for (int j = 0; j < test_loop_times; j++)
{
random_roi();
double eps = 2.0;
#ifdef __ANDROID__
// TODO investigate accuracy
if (cv::ocl::Device::getDefault().isNVidia())
eps = 8.0;
#elif defined(__arm__)
eps = 8.0;
#endif
OCL_OFF(cv::remap(src_roi, dst_roi, map1_roi, map2_roi, INTER_LINEAR, borderType, val));
OCL_ON(cv::remap(usrc_roi, udst_roi, umap1_roi, umap2_roi, INTER_LINEAR, borderType, val));
OCL_EXPECT_MAT_N_DIFF(dst, eps);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// remap relative
PARAM_TEST_CASE(RemapRelative, MatDepth, Channels, Interpolation, BorderType, bool)
{
int srcType;
int interpolation;
int borderType;
bool useFixedPoint;
Scalar val;
TEST_DECLARE_INPUT_PARAMETER(map1);
TEST_DECLARE_INPUT_PARAMETER(map2);
TEST_DECLARE_OUTPUT_PARAMETER(dst);
UMat uSrc;
UMat uMapRelativeX32F;
UMat uMapRelativeY32F;
UMat uMapAbsoluteX32F;
UMat uMapAbsoluteY32F;
UMat uMapRelativeX16S;
UMat uMapRelativeY16S;
UMat uMapAbsoluteX16S;
UMat uMapAbsoluteY16S;
virtual void SetUp()
{
srcType = CV_MAKE_TYPE(GET_PARAM(0), GET_PARAM(1));
interpolation = GET_PARAM(2);
borderType = GET_PARAM(3);
useFixedPoint = GET_PARAM(4);
const int nChannels = CV_MAT_CN(srcType);
const cv::Size size(127, 61);
cv::Mat data64FC1(1, size.area()*nChannels, CV_64FC1);
data64FC1.forEach<double>([&](double& pixel, const int* position) {pixel = static_cast<double>(position[1]);});
cv::Mat src;
data64FC1.reshape(nChannels, size.height).convertTo(src, srcType);
cv::Mat mapRelativeX32F(size, CV_32FC1);
mapRelativeX32F.setTo(cv::Scalar::all(-0.25));
cv::Mat mapRelativeY32F(size, CV_32FC1);
mapRelativeY32F.setTo(cv::Scalar::all(-0.25));
cv::Mat mapAbsoluteX32F = mapRelativeX32F.clone();
mapAbsoluteX32F.forEach<float>([&](float& pixel, const int* position) {
pixel += static_cast<float>(position[1]);
});
cv::Mat mapAbsoluteY32F = mapRelativeY32F.clone();
mapAbsoluteY32F.forEach<float>([&](float& pixel, const int* position) {
pixel += static_cast<float>(position[0]);
});
OCL_ON(src.copyTo(uSrc));
OCL_ON(mapRelativeX32F.copyTo(uMapRelativeX32F));
OCL_ON(mapRelativeY32F.copyTo(uMapRelativeY32F));
OCL_ON(mapAbsoluteX32F.copyTo(uMapAbsoluteX32F));
OCL_ON(mapAbsoluteY32F.copyTo(uMapAbsoluteY32F));
if (useFixedPoint)
{
const bool nninterpolation = (interpolation == cv::INTER_NEAREST) || (interpolation == cv::INTER_NEAREST_EXACT);
OCL_ON(cv::convertMaps(uMapAbsoluteX32F, uMapAbsoluteY32F, uMapAbsoluteX16S, uMapAbsoluteY16S, CV_16SC2, nninterpolation));
OCL_ON(cv::convertMaps(uMapRelativeX32F, uMapRelativeY32F, uMapRelativeX16S, uMapRelativeY16S, CV_16SC2, nninterpolation));
}
}
};
OCL_TEST_P(RemapRelative, Mat)
{
cv::UMat uDstAbsolute;
cv::UMat uDstRelative;
if (useFixedPoint)
{
OCL_ON(cv::remap(uSrc, uDstAbsolute, uMapAbsoluteX16S, uMapAbsoluteY16S, interpolation, borderType));
OCL_ON(cv::remap(uSrc, uDstRelative, uMapRelativeX16S, uMapRelativeY16S, interpolation | WARP_RELATIVE_MAP, borderType));
}
else
{
OCL_ON(cv::remap(uSrc, uDstAbsolute, uMapAbsoluteX32F, uMapAbsoluteY32F, interpolation, borderType));
OCL_ON(cv::remap(uSrc, uDstRelative, uMapRelativeX32F, uMapRelativeY32F, interpolation | WARP_RELATIVE_MAP, borderType));
}
cv::Mat dstAbsolute;
OCL_ON(uDstAbsolute.copyTo(dstAbsolute));
cv::Mat dstRelative;
OCL_ON(uDstRelative.copyTo(dstRelative));
EXPECT_MAT_NEAR(dstAbsolute, dstRelative, dstAbsolute.depth() == CV_32F ? 1e-3 : 1.0);
}
/////////////////////////////////////////////////////////////////////////////////////
OCL_INSTANTIATE_TEST_CASE_P(ImgprocWarp, WarpAffine, Combine(
Values(CV_8UC1, CV_8UC3, CV_8UC4, CV_32FC1, CV_32FC3, CV_32FC4),
Values((Interpolation)INTER_NEAREST, (Interpolation)INTER_LINEAR, (Interpolation)INTER_CUBIC),
Bool(),
Bool()));
OCL_INSTANTIATE_TEST_CASE_P(ImgprocWarp, WarpAffine_cols4, Combine(
Values((MatType)CV_8UC1),
Values((Interpolation)INTER_NEAREST, (Interpolation)INTER_LINEAR, (Interpolation)INTER_CUBIC),
Bool(),
Bool()));
OCL_INSTANTIATE_TEST_CASE_P(ImgprocWarp, WarpPerspective, Combine(
Values(CV_8UC1, CV_8UC3, CV_8UC4, CV_32FC1, CV_32FC3, CV_32FC4),
Values((Interpolation)INTER_NEAREST, (Interpolation)INTER_LINEAR, (Interpolation)INTER_CUBIC),
Bool(),
Bool()));
OCL_INSTANTIATE_TEST_CASE_P(ImgprocWarp, WarpPerspective_cols4, Combine(
Values((MatType)CV_8UC1),
Values((Interpolation)INTER_NEAREST, (Interpolation)INTER_LINEAR, (Interpolation)INTER_CUBIC),
Bool(),
Bool()));
OCL_INSTANTIATE_TEST_CASE_P(ImgprocWarp, Resize, Combine(
Values(CV_8UC1, CV_8UC4, CV_16UC2, CV_32FC1, CV_32FC4),
Values(0.5, 1.5, 2.0, 0.2),
Values(0.5, 1.5, 2.0, 0.2),
Values((Interpolation)INTER_NEAREST, (Interpolation)INTER_LINEAR),
Bool(),
Values(1, 16)));
OCL_INSTANTIATE_TEST_CASE_P(ImgprocWarpLinearExact, Resize, Combine(
Values(CV_8UC1, CV_8UC4, CV_16UC2),
Values(0.5, 1.5, 2.0, 0.2),
Values(0.5, 1.5, 2.0, 0.2),
Values((Interpolation)INTER_LINEAR_EXACT),
Bool(),
Values(1, 16)));
OCL_INSTANTIATE_TEST_CASE_P(ImgprocWarpResizeArea, Resize, Combine(
Values((MatType)CV_8UC1, CV_8UC4, CV_32FC1, CV_32FC4),
Values(0.7, 0.4, 0.5),
Values(0.3, 0.6, 0.5),
Values((Interpolation)INTER_AREA),
Bool(),
Values(1, 16)));
OCL_INSTANTIATE_TEST_CASE_P(ImgprocWarp, Remap_INTER_LINEAR, Combine(
Values(CV_8U, CV_16U, CV_32F),
Values(1, 3, 4),
Values(std::pair<MatType, MatType>((MatType)CV_32FC1, (MatType)CV_32FC1),
std::pair<MatType, MatType>((MatType)CV_16SC2, (MatType)CV_16UC1),
std::pair<MatType, MatType>((MatType)CV_32FC2, noType)),
Values((BorderType)BORDER_CONSTANT,
(BorderType)BORDER_REPLICATE,
(BorderType)BORDER_WRAP,
(BorderType)BORDER_REFLECT,
(BorderType)BORDER_REFLECT_101),
Bool()));
OCL_INSTANTIATE_TEST_CASE_P(ImgprocWarp, Remap_INTER_NEAREST, Combine(
Values(CV_8U, CV_16U, CV_32F),
Values(1, 3, 4),
Values(std::pair<MatType, MatType>((MatType)CV_32FC1, (MatType)CV_32FC1),
std::pair<MatType, MatType>((MatType)CV_32FC2, noType),
std::pair<MatType, MatType>((MatType)CV_16SC2, (MatType)CV_16UC1),
std::pair<MatType, MatType>((MatType)CV_16SC2, noType)),
Values((BorderType)BORDER_CONSTANT,
(BorderType)BORDER_REPLICATE,
(BorderType)BORDER_WRAP,
(BorderType)BORDER_REFLECT,
(BorderType)BORDER_REFLECT_101),
Bool()));
OCL_INSTANTIATE_TEST_CASE_P(ImgprocWarp, RemapRelative, Combine(
Values(CV_8U, CV_16U, CV_32F, CV_64F),
Values(1, 3, 4),
Values((Interpolation)INTER_NEAREST,
(Interpolation)INTER_LINEAR,
(Interpolation)INTER_CUBIC,
(Interpolation)INTER_LANCZOS4),
Values((BorderType)BORDER_CONSTANT,
(BorderType)BORDER_REPLICATE,
(BorderType)BORDER_WRAP,
(BorderType)BORDER_REFLECT,
(BorderType)BORDER_REFLECT_101),
Bool()));
} } // namespace opencv_test::ocl
#endif // HAVE_OPENCL
@@ -0,0 +1,323 @@
/*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 {
class CV_BilateralFilterTest :
public cvtest::BaseTest
{
public:
enum
{
MAX_WIDTH = 1920, MIN_WIDTH = 1,
MAX_HEIGHT = 1080, MIN_HEIGHT = 1
};
CV_BilateralFilterTest();
~CV_BilateralFilterTest();
protected:
virtual void run_func();
virtual int prepare_test_case(int test_case_index);
virtual int validate_test_results(int test_case_index);
private:
void reference_bilateral_filter(const Mat& src, Mat& dst, int d, double sigma_color,
double sigma_space, int borderType = BORDER_DEFAULT);
int getRandInt(RNG& rng, int min_value, int max_value) const;
double _sigma_color;
double _sigma_space;
Mat _src;
Mat _parallel_dst;
int _d;
};
CV_BilateralFilterTest::CV_BilateralFilterTest() :
cvtest::BaseTest(), _src(), _parallel_dst(), _d()
{
test_case_count = 1000;
}
CV_BilateralFilterTest::~CV_BilateralFilterTest()
{
}
int CV_BilateralFilterTest::getRandInt(RNG& rng, int min_value, int max_value) const
{
double rand_value = rng.uniform(log((double)min_value), log((double)max_value + 1));
return cvRound(exp((double)rand_value));
}
void CV_BilateralFilterTest::reference_bilateral_filter(const Mat &src, Mat &dst, int d,
double sigma_color, double sigma_space, int borderType)
{
int cn = src.channels();
int i, j, k, maxk, radius;
double minValSrc = -1, maxValSrc = 1;
const int kExpNumBinsPerChannel = 1 << 12;
int kExpNumBins = 0;
float lastExpVal = 1.f;
float len, scale_index;
Size size = src.size();
dst.create(size, src.type());
CV_Assert( (src.type() == CV_32FC1 || src.type() == CV_32FC3) &&
src.type() == dst.type() && src.size() == dst.size() &&
src.data != dst.data );
constexpr double eps = 1e-6;
if( sigma_color <= eps || sigma_space <= eps )
{
src.copyTo(dst);
return;
}
double gauss_color_coeff = -0.5/(sigma_color*sigma_color);
double gauss_space_coeff = -0.5/(sigma_space*sigma_space);
if( d <= 0 )
radius = cvRound(sigma_space*1.5);
else
radius = d/2;
radius = MAX(radius, 1);
d = radius*2 + 1;
// compute the min/max range for the input image (even if multichannel)
// TODO cvtest
cv::minMaxLoc( src.reshape(1), &minValSrc, &maxValSrc );
if(std::abs(minValSrc - maxValSrc) < FLT_EPSILON)
{
src.copyTo(dst);
return;
}
// temporary copy of the image with borders for easy processing
Mat temp;
cv::copyMakeBorder( src, temp, radius, radius, radius, radius, borderType );
cv::patchNaNs(temp);
// allocate lookup tables
vector<float> _space_weight(d*d);
vector<int> _space_ofs(d*d);
float* space_weight = &_space_weight[0];
int* space_ofs = &_space_ofs[0];
// assign a length which is slightly more than needed
len = (float)(maxValSrc - minValSrc) * cn;
kExpNumBins = kExpNumBinsPerChannel * cn;
vector<float> _expLUT(kExpNumBins+2);
float* expLUT = &_expLUT[0];
scale_index = kExpNumBins/len;
// initialize the exp LUT
for( i = 0; i < kExpNumBins+2; i++ )
{
if( lastExpVal > 0.f )
{
double val = i / scale_index;
expLUT[i] = (float)std::exp(val * val * gauss_color_coeff);
lastExpVal = expLUT[i];
}
else
expLUT[i] = 0.f;
}
// initialize space-related bilateral filter coefficients
for( i = -radius, maxk = 0; i <= radius; i++ )
for( j = -radius; j <= radius; j++ )
{
double r = std::sqrt((double)i*i + (double)j*j);
if( r > radius )
continue;
space_weight[maxk] = (float)std::exp(r*r*gauss_space_coeff);
space_ofs[maxk++] = (int)(i*(temp.step/sizeof(float)) + j*cn);
}
for( i = 0; i < size.height; i++ )
{
const float* sptr = temp.ptr<float>(i+radius) + radius*cn;
float* dptr = dst.ptr<float>(i);
if( cn == 1 )
{
for( j = 0; j < size.width; j++ )
{
float sum = 0, wsum = 0;
float val0 = sptr[j];
for( k = 0; k < maxk; k++ )
{
float val = sptr[j + space_ofs[k]];
float alpha = (float)(std::abs(val - val0)*scale_index);
int idx = cvFloor(alpha);
alpha -= idx;
float w = space_weight[k]*(expLUT[idx] + alpha*(expLUT[idx+1] - expLUT[idx]));
sum += val*w;
wsum += w;
}
dptr[j] = (float)(sum/wsum);
}
}
else
{
CV_Assert( cn == 3 );
for( j = 0; j < size.width*3; j += 3 )
{
float sum_b = 0, sum_g = 0, sum_r = 0, wsum = 0;
float b0 = sptr[j], g0 = sptr[j+1], r0 = sptr[j+2];
for( k = 0; k < maxk; k++ )
{
const float* sptr_k = sptr + j + space_ofs[k];
float b = sptr_k[0], g = sptr_k[1], r = sptr_k[2];
float alpha = (float)((std::abs(b - b0) +
std::abs(g - g0) + std::abs(r - r0))*scale_index);
int idx = cvFloor(alpha);
alpha -= idx;
float w = space_weight[k]*(expLUT[idx] + alpha*(expLUT[idx+1] - expLUT[idx]));
sum_b += b*w; sum_g += g*w; sum_r += r*w;
wsum += w;
}
wsum = 1.f/wsum;
b0 = sum_b*wsum;
g0 = sum_g*wsum;
r0 = sum_r*wsum;
dptr[j] = b0; dptr[j+1] = g0; dptr[j+2] = r0;
}
}
}
}
int CV_BilateralFilterTest::prepare_test_case(int /* test_case_index */)
{
const static int types[] = { CV_32FC1, CV_32FC3, CV_8UC1, CV_8UC3 };
RNG& rng = ts->get_rng();
Size size(getRandInt(rng, MIN_WIDTH, MAX_WIDTH), getRandInt(rng, MIN_HEIGHT, MAX_HEIGHT));
int type = types[rng(sizeof(types) / sizeof(types[0]))];
_d = rng.uniform(0., 1.) > 0.5 ? 5 : 3;
_src.create(size, type);
rng.fill(_src, RNG::UNIFORM, 0, 256);
_sigma_color = _sigma_space = rng.uniform(0., 10.);
return 1;
}
int CV_BilateralFilterTest::validate_test_results(int test_case_index)
{
double eps = (_src.depth() < CV_32F)?1:5e-3;
double e;
Mat reference_dst, reference_src;
if (_src.depth() == CV_32F)
{
reference_bilateral_filter(_src, reference_dst, _d, _sigma_color, _sigma_space);
e = cvtest::norm(reference_dst, _parallel_dst, NORM_INF|NORM_RELATIVE);
}
else
{
int type = _src.type();
_src.convertTo(reference_src, CV_32F);
reference_bilateral_filter(reference_src, reference_dst, _d, _sigma_color, _sigma_space);
reference_dst.convertTo(reference_dst, type);
e = cvtest::norm(reference_dst, _parallel_dst, NORM_INF);
}
if (e > eps)
{
ts->printf(cvtest::TS::CONSOLE, "actual error: %g, expected: %g", e, eps);
ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
}
else
ts->set_failed_test_info(cvtest::TS::OK);
return BaseTest::validate_test_results(test_case_index);
}
void CV_BilateralFilterTest::run_func()
{
bilateralFilter(_src, _parallel_dst, _d, _sigma_color, _sigma_space);
}
TEST(Imgproc_BilateralFilter, accuracy)
{
CV_BilateralFilterTest test;
test.safe_run();
}
// Regression test for issue #28254
// Out-of-bounds read in AVX2 bilateralFilter 32f path with BORDER_CONSTANT
TEST(Imgproc_BilateralFilter, regression_28254_oob_read)
{
// Create a 64x64 CV_32FC1 image with values in range [100, 200]
// Image must be large enough (width >= 32) to trigger SIMD/AVX2 code path.
// Values are set so BORDER_CONSTANT padding (default 0) is outside the range,
// which triggers the out-of-bounds condition in the LUT access.
cv::Mat src(64, 64, CV_32FC1);
cv::randu(src, 100.0f, 200.0f);
cv::Mat dst;
// Parameters that trigger the bug
int d = -1;
double sigmaColor = 2.7;
double sigmaSpace = 44.5;
int borderType = cv::BORDER_CONSTANT;
// This should not crash or trigger AddressSanitizer
EXPECT_NO_THROW(
cv::bilateralFilter(src, dst, d, sigmaColor, sigmaSpace, borderType)
);
// Verify output is valid
EXPECT_FALSE(dst.empty());
EXPECT_EQ(dst.size(), src.size());
EXPECT_EQ(dst.type(), src.type());
}
}} // namespace
+228
View File
@@ -0,0 +1,228 @@
/*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 {
static void Canny_reference_follow( int x, int y, float lowThreshold, const Mat& mag, Mat& dst )
{
static const int ofs[][2] = {{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1},{0,1},{1,1}};
int i;
dst.at<uchar>(y, x) = (uchar)255;
for( i = 0; i < 8; i++ )
{
int x1 = x + ofs[i][0];
int y1 = y + ofs[i][1];
if( (unsigned)x1 < (unsigned)mag.cols &&
(unsigned)y1 < (unsigned)mag.rows &&
mag.at<float>(y1, x1) > lowThreshold &&
!dst.at<uchar>(y1, x1) )
Canny_reference_follow( x1, y1, lowThreshold, mag, dst );
}
}
static void Canny_reference( const Mat& src, Mat& dst,
double threshold1, double threshold2,
int aperture_size, bool use_true_gradient )
{
dst.create(src.size(), src.type());
int m = aperture_size;
Point anchor(m/2, m/2);
const double tan_pi_8 = tan(CV_PI/8.);
const double tan_3pi_8 = tan(CV_PI*3/8);
float lowThreshold = (float)MIN(threshold1, threshold2);
float highThreshold = (float)MAX(threshold1, threshold2);
int x, y, width = src.cols, height = src.rows;
Mat dxkernel = cvtest::calcSobelKernel2D( 1, 0, m, 0 );
Mat dykernel = cvtest::calcSobelKernel2D( 0, 1, m, 0 );
Mat dx, dy, mag(height, width, CV_32F);
cvtest::filter2D(src, dx, CV_32S, dxkernel, anchor, 0, BORDER_REPLICATE);
cvtest::filter2D(src, dy, CV_32S, dykernel, anchor, 0, BORDER_REPLICATE);
// calc gradient magnitude
for( y = 0; y < height; y++ )
{
for( x = 0; x < width; x++ )
{
int dxval = dx.at<int>(y, x), dyval = dy.at<int>(y, x);
mag.at<float>(y, x) = use_true_gradient ?
(float)sqrt((double)(dxval*dxval + dyval*dyval)) :
(float)(fabs((double)dxval) + fabs((double)dyval));
}
}
// calc gradient direction, do nonmaxima suppression
for( y = 0; y < height; y++ )
{
for( x = 0; x < width; x++ )
{
float a = mag.at<float>(y, x), b = 0, c = 0;
int y1 = 0, y2 = 0, x1 = 0, x2 = 0;
if( a <= lowThreshold )
continue;
int dxval = dx.at<int>(y, x);
int dyval = dy.at<int>(y, x);
double tg = dxval ? (double)dyval/dxval : DBL_MAX*CV_SIGN(dyval);
if( fabs(tg) < tan_pi_8 )
{
y1 = y2 = y; x1 = x + 1; x2 = x - 1;
}
else if( tan_pi_8 <= tg && tg <= tan_3pi_8 )
{
y1 = y + 1; y2 = y - 1; x1 = x + 1; x2 = x - 1;
}
else if( -tan_3pi_8 <= tg && tg <= -tan_pi_8 )
{
y1 = y - 1; y2 = y + 1; x1 = x + 1; x2 = x - 1;
}
else
{
CV_Assert( fabs(tg) > tan_3pi_8 );
x1 = x2 = x; y1 = y + 1; y2 = y - 1;
}
if( (unsigned)y1 < (unsigned)height && (unsigned)x1 < (unsigned)width )
b = (float)fabs(mag.at<float>(y1, x1));
if( (unsigned)y2 < (unsigned)height && (unsigned)x2 < (unsigned)width )
c = (float)fabs(mag.at<float>(y2, x2));
if( (a > b || (a == b && ((x1 == x+1 && y1 == y) || (x1 == x && y1 == y+1)))) && a > c )
;
else
mag.at<float>(y, x) = -a;
}
}
dst = Scalar::all(0);
// hysteresis threshold
for( y = 0; y < height; y++ )
{
for( x = 0; x < width; x++ )
if( mag.at<float>(y, x) > highThreshold && !dst.at<uchar>(y, x) )
Canny_reference_follow( x, y, lowThreshold, mag, dst );
}
}
//==============================================================================
// aperture, true gradient
typedef testing::TestWithParam<testing::tuple<int, bool>> Canny_Modes;
TEST_P(Canny_Modes, accuracy)
{
const int aperture = get<0>(GetParam());
const bool trueGradient = get<1>(GetParam());
const double range = aperture == 3 ? 300. : 1000.;
RNG & rng = TS::ptr()->get_rng();
for (int ITER = 0; ITER < 20; ++ITER)
{
SCOPED_TRACE(cv::format("iteration %d", ITER));
const std::string fname = cvtest::findDataFile("shared/fruits.png");
const Mat original = cv::imread(fname, IMREAD_GRAYSCALE);
const double thresh1 = rng.uniform(0., range);
const double thresh2 = rng.uniform(0., range * 0.3);
const Size sz(rng.uniform(127, 800), rng.uniform(127, 600));
const Size osz = original.size();
// preparation
Mat img;
if (sz.width >= osz.width || sz.height >= osz.height)
{
// larger image -> scale
resize(original, img, sz, 0, 0, INTER_LINEAR_EXACT);
}
else
{
// smaller image -> crop
Point origin(rng.uniform(0, osz.width - sz.width), rng.uniform(0, osz.height - sz.height));
Rect roi(origin, sz);
original(roi).copyTo(img);
}
GaussianBlur(img, img, Size(5, 5), 0);
// regular function
Mat result;
{
cv::Canny(img, result, thresh1, thresh2, aperture, trueGradient);
}
// custom derivatives
Mat customResult;
{
Mat dxkernel = cvtest::calcSobelKernel2D(1, 0, aperture, 0);
Mat dykernel = cvtest::calcSobelKernel2D(0, 1, aperture, 0);
Point anchor(aperture / 2, aperture / 2);
cv::Mat dx, dy;
cvtest::filter2D(img, dx, CV_16S, dxkernel, anchor, 0, BORDER_REPLICATE);
cvtest::filter2D(img, dy, CV_16S, dykernel, anchor, 0, BORDER_REPLICATE);
cv::Canny(dx, dy, customResult, thresh1, thresh2, trueGradient);
}
Mat reference;
Canny_reference(img, reference, thresh1, thresh2, aperture, trueGradient);
EXPECT_MAT_NEAR(result, reference, 0);
EXPECT_MAT_NEAR(customResult, reference, 0);
}
}
INSTANTIATE_TEST_CASE_P(/**/, Canny_Modes,
testing::Combine(
testing::Values(3, 5),
testing::Values(true, false)));
}} // namespace
/* End of file. */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,799 @@
/*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 {
class CV_ConnectedComponentsTest : public cvtest::BaseTest
{
public:
CV_ConnectedComponentsTest();
~CV_ConnectedComponentsTest();
protected:
void run(int);
};
CV_ConnectedComponentsTest::CV_ConnectedComponentsTest() {}
CV_ConnectedComponentsTest::~CV_ConnectedComponentsTest() {}
// This function force a row major order for the labels
void normalizeLabels(Mat1i& imgLabels, int iNumLabels) {
vector<int> vecNewLabels(iNumLabels + 1, 0);
int iMaxNewLabel = 0;
for (int r = 0; r < imgLabels.rows; ++r) {
for (int c = 0; c < imgLabels.cols; ++c) {
int iCurLabel = imgLabels(r, c);
if (iCurLabel > 0) {
if (vecNewLabels[iCurLabel] == 0) {
vecNewLabels[iCurLabel] = ++iMaxNewLabel;
}
imgLabels(r, c) = vecNewLabels[iCurLabel];
}
}
}
}
void CV_ConnectedComponentsTest::run(int /* start_from */)
{
int ccltype[] = { cv::CCL_DEFAULT, cv::CCL_WU, cv::CCL_GRANA, cv::CCL_BOLELLI, cv::CCL_SAUF, cv::CCL_BBDT, cv::CCL_SPAGHETTI };
string exp_path = string(ts->get_data_path()) + "connectedcomponents/ccomp_exp.png";
Mat exp = imread(exp_path, IMREAD_GRAYSCALE);
Mat orig = imread(string(ts->get_data_path()) + "connectedcomponents/concentric_circles.png", 0);
if (orig.empty())
{
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA);
return;
}
Mat bw = orig > 128;
for (uint cclt = 0; cclt < sizeof(ccltype) / sizeof(int); ++cclt)
{
Mat1i labelImage;
int nLabels = connectedComponents(bw, labelImage, 8, CV_32S, ccltype[cclt]);
normalizeLabels(labelImage, nLabels);
// Validate test results
for (int r = 0; r < labelImage.rows; ++r) {
for (int c = 0; c < labelImage.cols; ++c) {
int l = labelImage.at<int>(r, c);
bool pass = l >= 0 && l <= nLabels;
if (!pass) {
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
return;
}
}
}
if (exp.empty() || orig.size() != exp.size())
{
imwrite(exp_path, labelImage);
exp = labelImage;
}
if (0 != cvtest::norm(labelImage > 0, exp > 0, NORM_INF))
{
ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
return;
}
if (nLabels != cvtest::norm(labelImage, NORM_INF) + 1)
{
ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
return;
}
}
ts->set_failed_test_info(cvtest::TS::OK);
}
TEST(Imgproc_ConnectedComponents, regression) { CV_ConnectedComponentsTest test; test.safe_run(); }
TEST(Imgproc_ConnectedComponents, grana_buffer_overflow)
{
cv::Mat darkMask;
darkMask.create(31, 87, CV_8U);
darkMask = 0;
cv::Mat labels;
cv::Mat stats;
cv::Mat centroids;
int nbComponents = cv::connectedComponentsWithStats(darkMask, labels, stats, centroids, 8, CV_32S, cv::CCL_GRANA);
EXPECT_EQ(1, nbComponents);
}
static cv::Mat createCrashMat(int numThreads) {
const int h = numThreads * 4 * 2 + 8;
const double nParallelStripes = std::max(1, std::min(h / 2, numThreads * 4));
const int w = 4;
const int nstripes = cvRound(nParallelStripes <= 0 ? h : MIN(MAX(nParallelStripes, 1.), h));
const cv::Range stripeRange(0, nstripes);
const cv::Range wholeRange(0, h);
cv::Mat m(h, w, CV_8U);
m = 0;
// Look for a range that starts with odd value and ends with even value
cv::Range bugRange;
for (int s = stripeRange.start; s < stripeRange.end; s++) {
cv::Range sr(s, s + 1);
cv::Range r;
r.start = (int)(wholeRange.start +
((uint64)sr.start * (wholeRange.end - wholeRange.start) + nstripes / 2) / nstripes);
r.end = sr.end >= nstripes ?
wholeRange.end :
(int)(wholeRange.start +
((uint64)sr.end * (wholeRange.end - wholeRange.start) + nstripes / 2) / nstripes);
if (r.start > 0 && r.start % 2 == 1 && r.end % 2 == 0 && r.end >= r.start + 2) {
bugRange = r;
break;
}
}
if (bugRange.empty()) { // Could not create a buggy range
return m;
}
// Fill in bug Range
for (int x = 1; x < w; x++) {
m.at<char>(bugRange.start - 1, x) = 1;
}
m.at<char>(bugRange.start + 0, 0) = 1;
m.at<char>(bugRange.start + 0, 1) = 1;
m.at<char>(bugRange.start + 0, 3) = 1;
m.at<char>(bugRange.start + 1, 1) = 1;
m.at<char>(bugRange.start + 2, 1) = 1;
m.at<char>(bugRange.start + 2, 3) = 1;
m.at<char>(bugRange.start + 3, 0) = 1;
m.at<char>(bugRange.start + 3, 1) = 1;
return m;
}
TEST(Imgproc_ConnectedComponents, parallel_wu_labels)
{
cv::Mat mat = createCrashMat(cv::getNumThreads());
if (mat.empty()) {
return;
}
const int nbPixels = cv::countNonZero(mat);
cv::Mat labels;
cv::Mat stats;
cv::Mat centroids;
int nb = 0;
EXPECT_NO_THROW(nb = cv::connectedComponentsWithStats(mat, labels, stats, centroids, 8, CV_32S, cv::CCL_WU));
int area = 0;
for (int i = 1; i < nb; ++i) {
area += stats.at<int32_t>(i, cv::CC_STAT_AREA);
}
EXPECT_EQ(nbPixels, area);
}
TEST(Imgproc_ConnectedComponents, missing_background_pixels)
{
cv::Mat m = Mat::ones(10, 10, CV_8U);
cv::Mat labels;
cv::Mat stats;
cv::Mat centroids;
EXPECT_NO_THROW(cv::connectedComponentsWithStats(m, labels, stats, centroids, 8, CV_32S, cv::CCL_WU));
EXPECT_EQ(stats.at<int32_t>(0, cv::CC_STAT_WIDTH), 0);
EXPECT_EQ(stats.at<int32_t>(0, cv::CC_STAT_HEIGHT), 0);
EXPECT_EQ(stats.at<int32_t>(0, cv::CC_STAT_LEFT), -1);
EXPECT_TRUE(std::isnan(centroids.at<double>(0, 0)));
EXPECT_TRUE(std::isnan(centroids.at<double>(0, 1)));
}
TEST(Imgproc_ConnectedComponents, spaghetti_bbdt_sauf_stats)
{
cv::Mat1b img({16, 16}, { (unsigned char)
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0,
0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0,
0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1,
0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1,
0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
});
cv::Mat1i labels;
cv::Mat1i stats;
cv::Mat1d centroids;
int ccltype[] = { cv::CCL_WU, cv::CCL_GRANA, cv::CCL_BOLELLI, cv::CCL_SAUF, cv::CCL_BBDT, cv::CCL_SPAGHETTI };
for (uint cclt = 0; cclt < sizeof(ccltype) / sizeof(int); ++cclt) {
EXPECT_NO_THROW(cv::connectedComponentsWithStats(img, labels, stats, centroids, 8, CV_32S, ccltype[cclt]));
EXPECT_EQ(stats(0, cv::CC_STAT_LEFT), 0);
EXPECT_EQ(stats(0, cv::CC_STAT_TOP), 0);
EXPECT_EQ(stats(0, cv::CC_STAT_WIDTH), 16);
EXPECT_EQ(stats(0, cv::CC_STAT_HEIGHT), 15);
EXPECT_EQ(stats(0, cv::CC_STAT_AREA), 144);
EXPECT_EQ(stats(1, cv::CC_STAT_LEFT), 1);
EXPECT_EQ(stats(1, cv::CC_STAT_TOP), 1);
EXPECT_EQ(stats(1, cv::CC_STAT_WIDTH), 3);
EXPECT_EQ(stats(1, cv::CC_STAT_HEIGHT), 3);
EXPECT_EQ(stats(1, cv::CC_STAT_AREA), 9);
EXPECT_EQ(stats(2, cv::CC_STAT_LEFT), 1);
EXPECT_EQ(stats(2, cv::CC_STAT_TOP), 1);
EXPECT_EQ(stats(2, cv::CC_STAT_WIDTH), 8);
EXPECT_EQ(stats(2, cv::CC_STAT_HEIGHT), 7);
EXPECT_EQ(stats(2, cv::CC_STAT_AREA), 40);
EXPECT_EQ(stats(3, cv::CC_STAT_LEFT), 10);
EXPECT_EQ(stats(3, cv::CC_STAT_TOP), 2);
EXPECT_EQ(stats(3, cv::CC_STAT_WIDTH), 5);
EXPECT_EQ(stats(3, cv::CC_STAT_HEIGHT), 2);
EXPECT_EQ(stats(3, cv::CC_STAT_AREA), 8);
EXPECT_EQ(stats(4, cv::CC_STAT_LEFT), 11);
EXPECT_EQ(stats(4, cv::CC_STAT_TOP), 5);
EXPECT_EQ(stats(4, cv::CC_STAT_WIDTH), 3);
EXPECT_EQ(stats(4, cv::CC_STAT_HEIGHT), 3);
EXPECT_EQ(stats(4, cv::CC_STAT_AREA), 9);
EXPECT_EQ(stats(5, cv::CC_STAT_LEFT), 2);
EXPECT_EQ(stats(5, cv::CC_STAT_TOP), 9);
EXPECT_EQ(stats(5, cv::CC_STAT_WIDTH), 1);
EXPECT_EQ(stats(5, cv::CC_STAT_HEIGHT), 1);
EXPECT_EQ(stats(5, cv::CC_STAT_AREA), 1);
EXPECT_EQ(stats(6, cv::CC_STAT_LEFT), 12);
EXPECT_EQ(stats(6, cv::CC_STAT_TOP), 9);
EXPECT_EQ(stats(6, cv::CC_STAT_WIDTH), 1);
EXPECT_EQ(stats(6, cv::CC_STAT_HEIGHT), 1);
EXPECT_EQ(stats(6, cv::CC_STAT_AREA), 1);
// Labels' order could be different!
if (cclt == cv::CCL_WU || cclt == cv::CCL_SAUF) {
// CCL_SAUF, CCL_WU
EXPECT_EQ(stats(9, cv::CC_STAT_LEFT), 1);
EXPECT_EQ(stats(9, cv::CC_STAT_TOP), 11);
EXPECT_EQ(stats(9, cv::CC_STAT_WIDTH), 4);
EXPECT_EQ(stats(9, cv::CC_STAT_HEIGHT), 2);
EXPECT_EQ(stats(9, cv::CC_STAT_AREA), 8);
EXPECT_EQ(stats(7, cv::CC_STAT_LEFT), 6);
EXPECT_EQ(stats(7, cv::CC_STAT_TOP), 10);
EXPECT_EQ(stats(7, cv::CC_STAT_WIDTH), 4);
EXPECT_EQ(stats(7, cv::CC_STAT_HEIGHT), 2);
EXPECT_EQ(stats(7, cv::CC_STAT_AREA), 8);
EXPECT_EQ(stats(8, cv::CC_STAT_LEFT), 0);
EXPECT_EQ(stats(8, cv::CC_STAT_TOP), 10);
EXPECT_EQ(stats(8, cv::CC_STAT_WIDTH), 16);
EXPECT_EQ(stats(8, cv::CC_STAT_HEIGHT), 6);
EXPECT_EQ(stats(8, cv::CC_STAT_AREA), 21);
}
else {
// CCL_BBDT, CCL_GRANA, CCL_SPAGHETTI, CCL_BOLELLI
EXPECT_EQ(stats(7, cv::CC_STAT_LEFT), 1);
EXPECT_EQ(stats(7, cv::CC_STAT_TOP), 11);
EXPECT_EQ(stats(7, cv::CC_STAT_WIDTH), 4);
EXPECT_EQ(stats(7, cv::CC_STAT_HEIGHT), 2);
EXPECT_EQ(stats(7, cv::CC_STAT_AREA), 8);
EXPECT_EQ(stats(8, cv::CC_STAT_LEFT), 6);
EXPECT_EQ(stats(8, cv::CC_STAT_TOP), 10);
EXPECT_EQ(stats(8, cv::CC_STAT_WIDTH), 4);
EXPECT_EQ(stats(8, cv::CC_STAT_HEIGHT), 2);
EXPECT_EQ(stats(8, cv::CC_STAT_AREA), 8);
EXPECT_EQ(stats(9, cv::CC_STAT_LEFT), 0);
EXPECT_EQ(stats(9, cv::CC_STAT_TOP), 10);
EXPECT_EQ(stats(9, cv::CC_STAT_WIDTH), 16);
EXPECT_EQ(stats(9, cv::CC_STAT_HEIGHT), 6);
EXPECT_EQ(stats(9, cv::CC_STAT_AREA), 21);
}
EXPECT_EQ(stats(10, cv::CC_STAT_LEFT), 9);
EXPECT_EQ(stats(10, cv::CC_STAT_TOP), 12);
EXPECT_EQ(stats(10, cv::CC_STAT_WIDTH), 5);
EXPECT_EQ(stats(10, cv::CC_STAT_HEIGHT), 2);
EXPECT_EQ(stats(10, cv::CC_STAT_AREA), 7);
}
}
TEST(Imgproc_ConnectedComponents, chessboard_even)
{
auto size = {16, 16};
cv::Mat1b input(size, { (unsigned char)
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1
});
cv::Mat1i output_8c(size, {
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1
});
cv::Mat1i output_4c(size, {
1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0,
0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16,
17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24, 0,
0, 25, 0, 26, 0, 27, 0, 28, 0, 29, 0, 30, 0, 31, 0, 32,
33, 0, 34, 0, 35, 0, 36, 0, 37, 0, 38, 0, 39, 0, 40, 0,
0, 41, 0, 42, 0, 43, 0, 44, 0, 45, 0, 46, 0, 47, 0, 48,
49, 0, 50, 0, 51, 0, 52, 0, 53, 0, 54, 0, 55, 0, 56, 0,
0, 57, 0, 58, 0, 59, 0, 60, 0, 61, 0, 62, 0, 63, 0, 64,
65, 0, 66, 0, 67, 0, 68, 0, 69, 0, 70, 0, 71, 0, 72, 0,
0, 73, 0, 74, 0, 75, 0, 76, 0, 77, 0, 78, 0, 79, 0, 80,
81, 0, 82, 0, 83, 0, 84, 0, 85, 0, 86, 0, 87, 0, 88, 0,
0, 89, 0, 90, 0, 91, 0, 92, 0, 93, 0, 94, 0, 95, 0, 96,
97, 0, 98, 0, 99, 0, 100, 0, 101, 0, 102, 0, 103, 0, 104, 0,
0, 105, 0, 106, 0, 107, 0, 108, 0, 109, 0, 110, 0, 111, 0, 112,
113, 0, 114, 0, 115, 0, 116, 0, 117, 0, 118, 0, 119, 0, 120, 0,
0, 121, 0, 122, 0, 123, 0, 124, 0, 125, 0, 126, 0, 127, 0, 128
});
// Chessboard image with even number of rows and cols
// Note that this is the maximum number of labels for 4-way connectivity
int ccltype[] = { cv::CCL_DEFAULT, cv::CCL_WU, cv::CCL_GRANA, cv::CCL_BOLELLI, cv::CCL_SAUF, cv::CCL_BBDT, cv::CCL_SPAGHETTI };
cv::Mat1i labels;
cv::Mat diff;
int nLabels = 0;
for (size_t cclt = 0; cclt < sizeof(ccltype) / sizeof(int); ++cclt) {
EXPECT_NO_THROW(nLabels = cv::connectedComponents(input, labels, 8, CV_32S, ccltype[cclt]));
normalizeLabels(labels, nLabels);
diff = labels != output_8c;
EXPECT_EQ(cv::countNonZero(diff), 0);
EXPECT_NO_THROW(nLabels = cv::connectedComponents(input, labels, 4, CV_32S, ccltype[cclt]));
normalizeLabels(labels, nLabels);
diff = labels != output_4c;
EXPECT_EQ(cv::countNonZero(diff), 0);
}
}
TEST(Imgproc_ConnectedComponents, chessboard_odd)
{
auto size = {15, 15};
cv::Mat1b input(size, { (unsigned char)
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1
});
cv::Mat1i output_8c(size, {
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1
});
cv::Mat1i output_4c(size, {
1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8,
0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0,
16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23,
0, 24, 0, 25, 0, 26, 0, 27, 0, 28, 0, 29, 0, 30, 0,
31, 0, 32, 0, 33, 0, 34, 0, 35, 0, 36, 0, 37, 0, 38,
0, 39, 0, 40, 0, 41, 0, 42, 0, 43, 0, 44, 0, 45, 0,
46, 0, 47, 0, 48, 0, 49, 0, 50, 0, 51, 0, 52, 0, 53,
0, 54, 0, 55, 0, 56, 0, 57, 0, 58, 0, 59, 0, 60, 0,
61, 0, 62, 0, 63, 0, 64, 0, 65, 0, 66, 0, 67, 0, 68,
0, 69, 0, 70, 0, 71, 0, 72, 0, 73, 0, 74, 0, 75, 0,
76, 0, 77, 0, 78, 0, 79, 0, 80, 0, 81, 0, 82, 0, 83,
0, 84, 0, 85, 0, 86, 0, 87, 0, 88, 0, 89, 0, 90, 0,
91, 0, 92, 0, 93, 0, 94, 0, 95, 0, 96, 0, 97, 0, 98,
0, 99, 0, 100, 0, 101, 0, 102, 0, 103, 0, 104, 0, 105, 0,
106, 0, 107, 0, 108, 0, 109, 0, 110, 0, 111, 0, 112, 0, 113
});
// Chessboard image with odd number of rows and cols
// Note that this is the maximum number of labels for 4-way connectivity
int ccltype[] = { cv::CCL_DEFAULT, cv::CCL_WU, cv::CCL_GRANA, cv::CCL_BOLELLI, cv::CCL_SAUF, cv::CCL_BBDT, cv::CCL_SPAGHETTI };
cv::Mat1i labels;
cv::Mat diff;
int nLabels = 0;
for (size_t cclt = 0; cclt < sizeof(ccltype) / sizeof(int); ++cclt) {
EXPECT_NO_THROW(nLabels = cv::connectedComponents(input, labels, 8, CV_32S, ccltype[cclt]));
normalizeLabels(labels, nLabels);
diff = labels != output_8c;
EXPECT_EQ(cv::countNonZero(diff), 0);
EXPECT_NO_THROW(nLabels = cv::connectedComponents(input, labels, 4, CV_32S, ccltype[cclt]));
normalizeLabels(labels, nLabels);
diff = labels != output_4c;
EXPECT_EQ(cv::countNonZero(diff), 0);
}
}
TEST(Imgproc_ConnectedComponents, maxlabels_8conn_even)
{
auto size = {16, 16};
cv::Mat1b input(size, { (unsigned char)
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
});
cv::Mat1i output_8c(size, {
1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
25, 0, 26, 0, 27, 0, 28, 0, 29, 0, 30, 0, 31, 0, 32, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
33, 0, 34, 0, 35, 0, 36, 0, 37, 0, 38, 0, 39, 0, 40, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
41, 0, 42, 0, 43, 0, 44, 0, 45, 0, 46, 0, 47, 0, 48, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
49, 0, 50, 0, 51, 0, 52, 0, 53, 0, 54, 0, 55, 0, 56, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
57, 0, 58, 0, 59, 0, 60, 0, 61, 0, 62, 0, 63, 0, 64, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
});
cv::Mat1i output_4c(size, {
1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
25, 0, 26, 0, 27, 0, 28, 0, 29, 0, 30, 0, 31, 0, 32, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
33, 0, 34, 0, 35, 0, 36, 0, 37, 0, 38, 0, 39, 0, 40, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
41, 0, 42, 0, 43, 0, 44, 0, 45, 0, 46, 0, 47, 0, 48, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
49, 0, 50, 0, 51, 0, 52, 0, 53, 0, 54, 0, 55, 0, 56, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
57, 0, 58, 0, 59, 0, 60, 0, 61, 0, 62, 0, 63, 0, 64, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
});
int ccltype[] = { cv::CCL_DEFAULT, cv::CCL_WU, cv::CCL_GRANA, cv::CCL_BOLELLI, cv::CCL_SAUF, cv::CCL_BBDT, cv::CCL_SPAGHETTI };
cv::Mat1i labels;
cv::Mat diff;
int nLabels = 0;
for (size_t cclt = 0; cclt < sizeof(ccltype) / sizeof(int); ++cclt) {
EXPECT_NO_THROW(nLabels = cv::connectedComponents(input, labels, 8, CV_32S, ccltype[cclt]));
normalizeLabels(labels, nLabels);
diff = labels != output_8c;
EXPECT_EQ(cv::countNonZero(diff), 0);
EXPECT_NO_THROW(nLabels = cv::connectedComponents(input, labels, 4, CV_32S, ccltype[cclt]));
normalizeLabels(labels, nLabels);
diff = labels != output_4c;
EXPECT_EQ(cv::countNonZero(diff), 0);
}
}
TEST(Imgproc_ConnectedComponents, maxlabels_8conn_odd)
{
auto size = {15, 15};
cv::Mat1b input(size, { (unsigned char)
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1
});
cv::Mat1i output_8c(size, {
1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
25, 0, 26, 0, 27, 0, 28, 0, 29, 0, 30, 0, 31, 0, 32,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
33, 0, 34, 0, 35, 0, 36, 0, 37, 0, 38, 0, 39, 0, 40,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
41, 0, 42, 0, 43, 0, 44, 0, 45, 0, 46, 0, 47, 0, 48,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
49, 0, 50, 0, 51, 0, 52, 0, 53, 0, 54, 0, 55, 0, 56,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
57, 0, 58, 0, 59, 0, 60, 0, 61, 0, 62, 0, 63, 0, 64
});
cv::Mat1i output_4c(size, {
1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
25, 0, 26, 0, 27, 0, 28, 0, 29, 0, 30, 0, 31, 0, 32,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
33, 0, 34, 0, 35, 0, 36, 0, 37, 0, 38, 0, 39, 0, 40,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
41, 0, 42, 0, 43, 0, 44, 0, 45, 0, 46, 0, 47, 0, 48,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
49, 0, 50, 0, 51, 0, 52, 0, 53, 0, 54, 0, 55, 0, 56,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
57, 0, 58, 0, 59, 0, 60, 0, 61, 0, 62, 0, 63, 0, 64
});
int ccltype[] = { cv::CCL_DEFAULT, cv::CCL_WU, cv::CCL_GRANA, cv::CCL_BOLELLI, cv::CCL_SAUF, cv::CCL_BBDT, cv::CCL_SPAGHETTI };
cv::Mat1i labels;
cv::Mat diff;
int nLabels = 0;
for (size_t cclt = 0; cclt < sizeof(ccltype) / sizeof(int); ++cclt) {
EXPECT_NO_THROW(nLabels = cv::connectedComponents(input, labels, 8, CV_32S, ccltype[cclt]));
normalizeLabels(labels, nLabels);
diff = labels != output_8c;
EXPECT_EQ(cv::countNonZero(diff), 0);
EXPECT_NO_THROW(nLabels = cv::connectedComponents(input, labels, 4, CV_32S, ccltype[cclt]));
normalizeLabels(labels, nLabels);
diff = labels != output_4c;
EXPECT_EQ(cv::countNonZero(diff), 0);
}
}
TEST(Imgproc_ConnectedComponents, single_row)
{
auto size = {1, 15};
cv::Mat1b input(size, {1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1});
cv::Mat1i output_8c(size, {1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8});
cv::Mat1i output_4c(size, {1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8});
int ccltype[] = { cv::CCL_DEFAULT, cv::CCL_WU, cv::CCL_GRANA, cv::CCL_BOLELLI, cv::CCL_SAUF, cv::CCL_BBDT, cv::CCL_SPAGHETTI };
cv::Mat1i labels;
cv::Mat diff;
int nLabels = 0;
for (size_t cclt = 0; cclt < sizeof(ccltype) / sizeof(int); ++cclt) {
EXPECT_NO_THROW(nLabels = cv::connectedComponents(input, labels, 8, CV_32S, ccltype[cclt]));
normalizeLabels(labels, nLabels);
diff = labels != output_8c;
EXPECT_EQ(cv::countNonZero(diff), 0);
EXPECT_NO_THROW(nLabels = cv::connectedComponents(input, labels, 4, CV_32S, ccltype[cclt]));
normalizeLabels(labels, nLabels);
diff = labels != output_4c;
EXPECT_EQ(cv::countNonZero(diff), 0);
}
}
TEST(Imgproc_ConnectedComponents, single_column)
{
auto size = {15, 1};
cv::Mat1b input(size, {(unsigned char)1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1});
cv::Mat1i output_8c(size, {1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8});
cv::Mat1i output_4c(size, {1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8});
int ccltype[] = { cv::CCL_DEFAULT, cv::CCL_WU, cv::CCL_GRANA, cv::CCL_BOLELLI, cv::CCL_SAUF, cv::CCL_BBDT, cv::CCL_SPAGHETTI };
cv::Mat1i labels;
cv::Mat diff;
int nLabels = 0;
for (size_t cclt = 0; cclt < sizeof(ccltype) / sizeof(int); ++cclt) {
EXPECT_NO_THROW(nLabels = cv::connectedComponents(input, labels, 8, CV_32S, ccltype[cclt]));
normalizeLabels(labels, nLabels);
diff = labels != output_8c;
EXPECT_EQ(cv::countNonZero(diff), 0);
EXPECT_NO_THROW(nLabels = cv::connectedComponents(input, labels, 4, CV_32S, ccltype[cclt]));
normalizeLabels(labels, nLabels);
diff = labels != output_4c;
EXPECT_EQ(cv::countNonZero(diff), 0);
}
}
TEST(Imgproc_ConnectedComponents, 4conn_regression_21366)
{
Mat src = Mat::zeros(Size(10, 10), CV_8UC1);
{
Mat labels, stats, centroids;
EXPECT_NO_THROW(cv::connectedComponentsWithStats(src, labels, stats, centroids, 4));
}
}
TEST(Imgproc_ConnectedComponents, regression_27568)
{
Mat image = Mat::zeros(Size(512, 512), CV_8UC1);
for (int row = 0; row < image.rows; row += 2)
{
for (int col = 0; col < image.cols; col += 2)
{
image.at<uint8_t>(row, col) = 1;
}
}
for (const int connectivity : {4, 8})
{
for (const int ccltype : {CCL_DEFAULT, CCL_WU, CCL_GRANA, CCL_BOLELLI, CCL_SAUF, CCL_BBDT, CCL_SPAGHETTI})
{
{
Mat labels, stats, centroids;
try
{
connectedComponentsWithStats(
image, labels, stats, centroids, connectivity, CV_16U, ccltype);
ADD_FAILURE();
}
catch (const Exception& exception)
{
EXPECT_TRUE(
strstr(
exception.what(),
"Total number of labels overflowed label type. Try using CV_32S instead of CV_16U as ltype"));
}
}
{
Mat labels, stats, centroids;
EXPECT_NO_THROW(
connectedComponentsWithStats(
image, labels, stats, centroids, connectivity, CV_32S, ccltype));
}
}
}
}
}
} // namespace
+223
View File
@@ -0,0 +1,223 @@
/*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"
#include <opencv2/highgui.hpp>
namespace opencv_test { namespace {
//rotate/flip a quadrant appropriately
static void rot(int n, int *x, int *y, int rx, int ry)
{
if (ry == 0) {
if (rx == 1) {
*x = n-1 - *x;
*y = n-1 - *y;
}
//Swap x and y
int t = *x;
*x = *y;
*y = t;
}
}
static void d2xy(int n, int d, int *x, int *y)
{
int rx, ry, s, t=d;
*x = *y = 0;
for (s=1; s<n; s*=2)
{
rx = 1 & (t/2);
ry = 1 & (t ^ rx);
rot(s, x, y, rx, ry);
*x += s * rx;
*y += s * ry;
t /= 4;
}
}
static Mat draw_hilbert(int n = 64, int scale = 10)
{
int n2 = n*n, w = (n + 2)*scale;
Point ofs(scale, scale);
Mat img(w, w, CV_8U);
img.setTo(Scalar::all(0));
Point p(0,0);
for( int i = 0; i < n2; i++ )
{
Point q(0,0);
d2xy(n2, i, &q.x, &q.y);
line(img, p*scale + ofs, q*scale + ofs, Scalar::all(255));
p = q;
}
dilate(img, img, Mat());
return img;
}
TEST(Imgproc_FindContours, hilbert)
{
Mat img = draw_hilbert();
vector<vector<Point> > contours;
findContours(img, contours, noArray(), RETR_LIST, CHAIN_APPROX_NONE);
ASSERT_EQ(1, (int)contours.size());
ASSERT_EQ(78632, (int)contours[0].size());
findContours(img, contours, noArray(), RETR_LIST, CHAIN_APPROX_SIMPLE);
ASSERT_EQ(1, (int)contours.size());
ASSERT_EQ(9832, (int)contours[0].size());
}
TEST(Imgproc_FindContours, border)
{
Mat img;
cv::copyMakeBorder(Mat::zeros(8, 10, CV_8U), img, 1, 1, 1, 1, BORDER_CONSTANT, Scalar(1));
std::vector<std::vector<cv::Point> > contours;
findContours(img, contours, RETR_LIST, CHAIN_APPROX_NONE);
Mat img_draw_contours = Mat::zeros(img.size(), CV_8U);
for (size_t cpt = 0; cpt < contours.size(); cpt++)
{
drawContours(img_draw_contours, contours, static_cast<int>(cpt), cv::Scalar(1));
}
ASSERT_EQ(0, cvtest::norm(img, img_draw_contours, NORM_INF));
}
TEST(Imgproc_FindContours, regression_4363_shared_nbd)
{
// Create specific test image
Mat1b img(12, 69, (const uchar&)0);
img(1, 1) = 1;
// Vertical rectangle with hole sharing the same NBD
for (int r = 1; r <= 10; ++r) {
for (int c = 3; c <= 5; ++c) {
img(r, c) = 1;
}
}
img(9, 4) = 0;
// 124 small CCs
for (int r = 1; r <= 7; r += 2) {
for (int c = 7; c <= 67; c += 2) {
img(r, c) = 1;
}
}
// Last CC
img(9, 7) = 1;
vector< vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(img, contours, hierarchy, RETR_TREE, CHAIN_APPROX_NONE);
bool found = false;
size_t index = 0;
for (vector< vector<Point> >::const_iterator i = contours.begin(); i != contours.end(); ++i)
{
const vector<Point>& c = *i;
if (!c.empty() && c[0] == Point(7, 9))
{
found = true;
index = (size_t)(i - contours.begin());
break;
}
}
EXPECT_TRUE(found) << "Desired result: point (7,9) is a contour - Actual result: point (7,9) is not a contour";
if (found)
{
ASSERT_EQ(contours.size(), hierarchy.size());
EXPECT_LT(hierarchy[index][3], 0) << "Desired result: (7,9) has no parent - Actual result: parent of (7,9) is another contour. index = " << index;
}
}
TEST(Imgproc_DrawContours, regression_26264)
{
Mat img = draw_hilbert(32);
img.push_back(~img);
for (int i = 50; i < 200; i += 17)
{
rectangle(img, Rect(i, i, img.cols - (i*2), img.rows - (i*2)), Scalar(0), 7);
rectangle(img, Rect(i, i, img.cols - (i*2), img.rows - (i*2)), Scalar(255), 1);
}
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(img, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);
img.setTo(Scalar::all(0));
Mat img1 = img.clone();
Mat img2 = img.clone();
Mat img3 = img.clone();
int idx = 0;
while (idx >= 0)
{
drawContours(img, contours, idx, Scalar::all(255), FILLED, LINE_8, hierarchy);
drawContours(img2, contours, idx, Scalar::all(255), 1, LINE_8, hierarchy);
idx = hierarchy[idx][0];
}
drawContours(img1, contours, -1, Scalar::all(255), FILLED, LINE_8, hierarchy);
drawContours(img3, contours, -1, Scalar::all(255), 1, LINE_8, hierarchy);
ASSERT_EQ(0, cvtest::norm(img, img1, NORM_INF));
ASSERT_EQ(0, cvtest::norm(img2, img3, NORM_INF));
}
TEST(Imgproc_DrawContours, MatListOfMatIntScalarInt)
{
Mat gray0 = Mat::zeros(10, 10, CV_8U);
rectangle(gray0, Point(1, 2), Point(7, 8), Scalar(100));
vector<Mat> contours;
findContours(gray0, contours, noArray(), RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
drawContours(gray0, contours, -1, Scalar(0), FILLED);
int nz = countNonZero(gray0);
EXPECT_EQ(nz, 0);
}
}} // namespace
/* End of file. */
+485
View File
@@ -0,0 +1,485 @@
// 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 {
// debug function
template <typename T>
inline static void print_pts(const T& c)
{
for (const auto& one_pt : c)
{
cout << one_pt << " ";
}
cout << endl;
}
// debug function
template <typename T>
inline static void print_pts_2(vector<T>& cs)
{
int cnt = 0;
cout << "Contours:" << endl;
for (const auto& one_c : cs)
{
cout << cnt++ << " : ";
print_pts(one_c);
}
};
// draw 1-2 px blob with orientation defined by 'kind'
template <typename T>
inline static void drawSmallContour(Mat& img, Point pt, int kind, int color_)
{
const T color = static_cast<T>(color_);
img.at<T>(pt) = color;
switch (kind)
{
case 1: img.at<T>(pt + Point(1, 0)) = color; break;
case 2: img.at<T>(pt + Point(1, -1)) = color; break;
case 3: img.at<T>(pt + Point(0, -1)) = color; break;
case 4: img.at<T>(pt + Point(-1, -1)) = color; break;
case 5: img.at<T>(pt + Point(-1, 0)) = color; break;
case 6: img.at<T>(pt + Point(-1, 1)) = color; break;
case 7: img.at<T>(pt + Point(0, 1)) = color; break;
case 8: img.at<T>(pt + Point(1, 1)) = color; break;
default: break;
}
}
inline static void drawContours(Mat& img,
const vector<vector<Point>>& contours,
const Scalar& color = Scalar::all(255))
{
for (const auto& contour : contours)
{
for (size_t n = 0, end = contour.size(); n < end; ++n)
{
size_t m = n + 1;
if (n == end - 1)
m = 0;
line(img, contour[m], contour[n], color, 1, LINE_8);
}
}
}
//==================================================================================================
// Test parameters - mode + method
typedef testing::TestWithParam<tuple<int, int>> Imgproc_FindContours_Modes1;
// Draw random rectangle and find contours
//
TEST_P(Imgproc_FindContours_Modes1, rectangle)
{
const int mode = get<0>(GetParam());
const int method = get<1>(GetParam());
const size_t ITER = 100;
RNG rng = TS::ptr()->get_rng();
for (size_t i = 0; i < ITER; ++i)
{
SCOPED_TRACE(cv::format("i=%zu", i));
const Size sz(rng.uniform(640, 1920), rng.uniform(480, 1080));
Mat img(sz, CV_8UC1, Scalar::all(0));
Mat img32s(sz, CV_32SC1, Scalar::all(0));
const Rect r(Point(rng.uniform(1, sz.width / 2 - 1), rng.uniform(1, sz.height / 2)),
Point(rng.uniform(sz.width / 2 - 1, sz.width - 1),
rng.uniform(sz.height / 2 - 1, sz.height - 1)));
rectangle(img, r, Scalar::all(255));
rectangle(img32s, r, Scalar::all(255), FILLED);
const vector<Point> ext_ref {r.tl(),
r.tl() + Point(0, r.height - 1),
r.br() + Point(-1, -1),
r.tl() + Point(r.width - 1, 0)};
const vector<Point> int_ref {ext_ref[0] + Point(0, 1),
ext_ref[0] + Point(1, 0),
ext_ref[3] + Point(-1, 0),
ext_ref[3] + Point(0, 1),
ext_ref[2] + Point(0, -1),
ext_ref[2] + Point(-1, 0),
ext_ref[1] + Point(1, 0),
ext_ref[1] + Point(0, -1)};
const size_t ext_perimeter = r.width * 2 + r.height * 2;
const size_t int_perimeter = ext_perimeter - 4;
vector<vector<Point>> contours;
vector<vector<schar>> chains;
vector<Vec4i> hierarchy;
// run functionn
if (mode == RETR_FLOODFILL)
if (method == 0)
findContours(img32s, chains, hierarchy, mode, method);
else
findContours(img32s, contours, hierarchy, mode, method);
else if (method == 0)
findContours(img, chains, hierarchy, mode, method);
else
findContours(img, contours, hierarchy, mode, method);
// verify results
if (mode == RETR_EXTERNAL)
{
if (method == 0)
{
ASSERT_EQ(1U, chains.size());
}
else
{
ASSERT_EQ(1U, contours.size());
if (method == CHAIN_APPROX_NONE)
{
EXPECT_EQ(int_perimeter, contours[0].size());
}
else if (method == CHAIN_APPROX_SIMPLE)
{
EXPECT_MAT_NEAR(Mat(ext_ref), Mat(contours[0]), 0);
}
}
}
else
{
if (method == 0)
{
ASSERT_EQ(2U, chains.size());
}
else
{
ASSERT_EQ(2U, contours.size());
if (mode == RETR_LIST)
{
if (method == CHAIN_APPROX_NONE)
{
EXPECT_EQ(int_perimeter - 4, contours[0].size());
EXPECT_EQ(int_perimeter, contours[1].size());
}
else if (method == CHAIN_APPROX_SIMPLE)
{
EXPECT_MAT_NEAR(Mat(int_ref), Mat(contours[0]), 0);
EXPECT_MAT_NEAR(Mat(ext_ref), Mat(contours[1]), 0);
}
}
else if (mode == RETR_CCOMP || mode == RETR_TREE)
{
if (method == CHAIN_APPROX_NONE)
{
EXPECT_EQ(int_perimeter, contours[0].size());
EXPECT_EQ(int_perimeter - 4, contours[1].size());
}
else if (method == CHAIN_APPROX_SIMPLE)
{
EXPECT_MAT_NEAR(Mat(ext_ref), Mat(contours[0]), 0);
EXPECT_MAT_NEAR(Mat(int_ref), Mat(contours[1]), 0);
}
}
else if (mode == RETR_FLOODFILL)
{
if (method == CHAIN_APPROX_NONE)
{
EXPECT_EQ(int_perimeter + 4, contours[0].size());
}
else if (method == CHAIN_APPROX_SIMPLE)
{
EXPECT_EQ(int_ref.size(), contours[0].size());
EXPECT_MAT_NEAR(Mat(ext_ref), Mat(contours[1]), 0);
}
}
}
}
}
}
// Draw many small 1-2px blobs and find contours
//
TEST_P(Imgproc_FindContours_Modes1, small)
{
const int mode = get<0>(GetParam());
const int method = get<1>(GetParam());
const size_t DIM = 1000;
const Size sz(DIM, DIM);
const int num = (DIM / 10) * (DIM / 10); // number of 10x10 squares
Mat img(sz, CV_8UC1, Scalar::all(0));
Mat img32s(sz, CV_32SC1, Scalar::all(0));
vector<Point> pts;
int extra_contours_32s = 0;
for (int j = 0; j < num; ++j)
{
const int kind = j % 9;
Point pt {(j % 100) * 10 + 4, (j / 100) * 10 + 4};
drawSmallContour<uchar>(img, pt, kind, 255);
drawSmallContour<int>(img32s, pt, kind, j + 1);
pts.push_back(pt);
// NOTE: for some reason these small diagonal contours (NW, SE)
// result in 2 external contours for FLOODFILL mode
if (kind == 8 || kind == 4)
++extra_contours_32s;
}
{
vector<vector<Point>> contours;
vector<vector<schar>> chains;
vector<Vec4i> hierarchy;
if (mode == RETR_FLOODFILL)
{
if (method == 0)
{
findContours(img32s, chains, hierarchy, mode, method);
ASSERT_EQ(pts.size() * 2 + extra_contours_32s, chains.size());
}
else
{
findContours(img32s, contours, hierarchy, mode, method);
ASSERT_EQ(pts.size() * 2 + extra_contours_32s, contours.size());
}
}
else
{
if (method == 0)
{
findContours(img, chains, hierarchy, mode, method);
ASSERT_EQ(pts.size(), chains.size());
}
else
{
findContours(img, contours, hierarchy, mode, method);
ASSERT_EQ(pts.size(), contours.size());
}
}
}
}
// Draw many nested rectangles and find contours
//
TEST_P(Imgproc_FindContours_Modes1, deep)
{
const int mode = get<0>(GetParam());
const int method = get<1>(GetParam());
const size_t DIM = 1000;
const Size sz(DIM, DIM);
const size_t NUM = 249U;
Mat img(sz, CV_8UC1, Scalar::all(0));
Mat img32s(sz, CV_32SC1, Scalar::all(0));
Rect rect(1, 1, 998, 998);
for (size_t i = 0; i < NUM; ++i)
{
rectangle(img, rect, Scalar::all(255));
rectangle(img32s, rect, Scalar::all((double)i + 1), FILLED);
rect.x += 2;
rect.y += 2;
rect.width -= 4;
rect.height -= 4;
}
{
vector<vector<Point>> contours {{{0, 0}, {1, 1}}};
vector<vector<schar>> chains {{1, 2, 3}};
vector<Vec4i> hierarchy;
if (mode == RETR_FLOODFILL)
{
if (method == 0)
{
findContours(img32s, chains, hierarchy, mode, method);
ASSERT_EQ(2 * NUM, chains.size());
}
else
{
findContours(img32s, contours, hierarchy, mode, method);
ASSERT_EQ(2 * NUM, contours.size());
}
}
else
{
const size_t expected_count = (mode == RETR_EXTERNAL) ? 1U : 2 * NUM;
if (method == 0)
{
findContours(img, chains, hierarchy, mode, method);
ASSERT_EQ(expected_count, chains.size());
}
else
{
findContours(img, contours, hierarchy, mode, method);
ASSERT_EQ(expected_count, contours.size());
}
}
}
}
INSTANTIATE_TEST_CASE_P(
,
Imgproc_FindContours_Modes1,
testing::Combine(
testing::Values(RETR_EXTERNAL, RETR_LIST, RETR_CCOMP, RETR_TREE, RETR_FLOODFILL),
testing::Values(0,
CHAIN_APPROX_NONE,
CHAIN_APPROX_SIMPLE,
CHAIN_APPROX_TC89_L1,
CHAIN_APPROX_TC89_KCOS)));
//==================================================================================================
typedef testing::TestWithParam<tuple<int, int>> Imgproc_FindContours_Modes2;
// Very approximate backport of an old accuracy test
//
TEST_P(Imgproc_FindContours_Modes2, new_accuracy)
{
const int mode = get<0>(GetParam());
const int method = get<1>(GetParam());
RNG& rng = TS::ptr()->get_rng();
const int blob_count = rng.uniform(1, 10);
const Size sz(rng.uniform(640, 1920), rng.uniform(480, 1080));
const int blob_sz = 50;
// prepare image
Mat img(sz, CV_8UC1, Scalar::all(0));
vector<RotatedRect> rects;
for (int i = 0; i < blob_count; ++i)
{
const Point2f center((float)rng.uniform(blob_sz, sz.width - blob_sz),
(float)rng.uniform(blob_sz, sz.height - blob_sz));
const Size2f rsize((float)rng.uniform(1, blob_sz), (float)rng.uniform(1, blob_sz));
RotatedRect rect(center, rsize, rng.uniform(0.f, 180.f));
rects.push_back(rect);
ellipse(img, rect, Scalar::all(100), FILLED);
}
// draw contours manually
Mat cont_img(sz, CV_8UC1, Scalar::all(0));
for (int y = 1; y < sz.height - 1; ++y)
{
for (int x = 1; x < sz.width - 1; ++x)
{
if (img.at<uchar>(y, x) != 0 &&
((img.at<uchar>(y - 1, x) == 0) || (img.at<uchar>(y + 1, x) == 0) ||
(img.at<uchar>(y, x + 1) == 0) || (img.at<uchar>(y, x - 1) == 0)))
{
cont_img.at<uchar>(y, x) = 255;
}
}
}
// find contours
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(img, contours, hierarchy, mode, method);
// 0 < contours <= rects
EXPECT_GT(contours.size(), 0U);
EXPECT_GE(rects.size(), contours.size());
// draw contours
Mat res_img(sz, CV_8UC1, Scalar::all(0));
drawContours(res_img, contours);
// compare resulting drawn contours with manually drawn contours
const double diff1 = cvtest::norm(cont_img, res_img, NORM_L1) / 255;
if (method == CHAIN_APPROX_NONE || method == CHAIN_APPROX_SIMPLE)
{
EXPECT_EQ(0., diff1);
}
}
TEST_P(Imgproc_FindContours_Modes2, approx)
{
const int mode = get<0>(GetParam());
const int method = get<1>(GetParam());
const Size sz {500, 500};
Mat img = Mat::zeros(sz, CV_8UC1);
for (int c = 0; c < 4; ++c)
{
if (c != 0)
{
// noise + filter + threshold
RNG& rng = TS::ptr()->get_rng();
cvtest::randUni(rng, img, 0, 255);
Mat fimg;
boxFilter(img, fimg, CV_8U, Size(5, 5));
Mat timg;
const int level = 44 + c * 42;
// 'level' goes through:
// 86 - some black speckles on white
// 128 - 50/50 black/white
// 170 - some white speckles on black
cv::threshold(fimg, timg, level, 255, THRESH_BINARY);
}
else
{
// circle with cut
const Point center {250, 250};
const int r {20};
const Point cut {r, r};
circle(img, center, r, Scalar(255), FILLED);
rectangle(img, center, center + cut, Scalar(0), FILLED);
}
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(img, contours, hierarchy, mode, method);
// TODO: check something
}
}
// TODO: offset test
// no RETR_FLOODFILL - no CV_32S input images
INSTANTIATE_TEST_CASE_P(
,
Imgproc_FindContours_Modes2,
testing::Combine(testing::Values(RETR_EXTERNAL, RETR_LIST, RETR_CCOMP, RETR_TREE),
testing::Values(CHAIN_APPROX_NONE,
CHAIN_APPROX_SIMPLE,
CHAIN_APPROX_TC89_L1,
CHAIN_APPROX_TC89_KCOS)));
TEST(Imgproc_FindContours, link_runs)
{
const Size sz {500, 500};
Mat img = Mat::zeros(sz, CV_8UC1);
// noise + filter + threshold
RNG& rng = TS::ptr()->get_rng();
cvtest::randUni(rng, img, 0, 255);
Mat fimg;
boxFilter(img, fimg, CV_8U, Size(5, 5));
const int level = 135;
cv::threshold(fimg, img, level, 255, THRESH_BINARY);
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContoursLinkRuns(img, contours, hierarchy);
if (cvtest::debugLevel >= 10)
{
print_pts_2(contours);
Mat res = Mat::zeros(sz, CV_8UC1);
drawContours(res, contours);
imshow("res", res);
imshow("img", img);
waitKey(0);
}
}
}} // namespace opencv_test
@@ -0,0 +1,254 @@
// 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 {
//helps to temporarily change the number of threads and restore it back after the scope
struct CvNThreadScope{
int nprev;
CvNThreadScope(int n){
nprev=cv::getNumThreads();
cv::setNumThreads(n);
}
~CvNThreadScope(){
cv::setNumThreads(nprev);
}
};
// Order-independent contour-set comparison
static bool trucoContoursMatch(const vector<vector<Point>>& cont1, const vector<vector<Point>>& cont2)
{
//order senstive hash
auto Hash=[](const std::vector<cv::Point>& contour) {
// FNV-1a 64-bit hash constants
constexpr uint64_t FNV_OFFSET = 1469598103934665603ULL;
constexpr uint64_t FNV_PRIME = 1099511628211ULL;
uint64_t hash = FNV_OFFSET;
// Mix in the size so that contours with different lengths
// but same prefix produce different hashes
uint64_t size = static_cast<uint64_t>(contour.size());
for (int i = 0; i < 8; ++i) {
hash ^= (size >> (i * 8)) & 0xFF;
hash *= FNV_PRIME;
}
// Mix in each point's x and y coordinates byte by byte
for (const cv::Point& p : contour) {
uint32_t x = static_cast<uint32_t>(p.x);
uint32_t y = static_cast<uint32_t>(p.y);
for (int i = 0; i < 4; ++i) {
hash ^= (x >> (i * 8)) & 0xFF;
hash *= FNV_PRIME;
}
for (int i = 0; i < 4; ++i) {
hash ^= (y >> (i * 8)) & 0xFF;
hash *= FNV_PRIME;
}
}
return hash;
};
std::set<uint64> hashes1,hashes2;
for(auto &contour:cont1){
hashes1.insert( Hash(contour));
}
for(auto &contour:cont2){
hashes2.insert( Hash(contour));
}
for(auto &h1:hashes1){//element in cont and not in cont2
if( hashes2.find(h1) ==hashes2.end()) return false;
}
return true;
}
typedef testing::TestWithParam<ContourApproximationModes> Imgproc_FindTRUContours;
TEST_P(Imgproc_FindTRUContours, nthreads_consistency)
{
ContourApproximationModes method = GetParam();
const Size sz(1000, 1000);
RNG& rng = TS::ptr()->get_rng();
Mat noise(sz, CV_8UC1);
cvtest::randUni(rng, noise, 0, 255);
Mat blurred;
boxFilter(noise, blurred, CV_8U, Size(5, 5));
Mat img;
cv::threshold(blurred, img, 128, 255, THRESH_BINARY);
vector<vector<Point>> ref_contours;
vector<vector<Point>> ref_contours_m0;
{
CvNThreadScope nt(1);
findContours(img, ref_contours, RETR_LIST, method);
}
std::vector<int> thread_counts;
for(int i=2;i<40;i++) thread_counts.push_back(i);
for (int t : thread_counts)
{
SCOPED_TRACE(cv::format("nthreads=%d method=%d", t, (int)method));
CvNThreadScope nt(t);
vector<vector<Point>> contours;
findContours(img, contours, RETR_LIST, method); //will use TRUCO because NOT using hierarchy AND RETR_LIST
auto match=trucoContoursMatch(ref_contours, contours);
EXPECT_TRUE(match);
}
}
TEST_P(Imgproc_FindTRUContours, circles_vs_standard)
{
ContourApproximationModes method = GetParam();
const Size sz(4000, 4000);
const int ITER = cvtest::debugLevel >= 10?100:10;
const int NUM_CIRCLES = 250;
RNG& rng = TS::ptr()->get_rng();
for (int iter = 0; iter < ITER; ++iter)
{
SCOPED_TRACE(cv::format("iter=%d method=%d", iter, (int)method));
Mat img(sz, CV_8UC1, Scalar::all(0));
for (int i = 0; i < NUM_CIRCLES; ++i)
{
Point center(rng.uniform(50, sz.width - 50),
rng.uniform(50, sz.height - 50));
int radius = rng.uniform(10, 150);
circle(img, center, radius, Scalar::all(255), FILLED);
}
Mat binary;
adaptiveThreshold(img, binary, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 11, 0);
vector<vector<Point>> ref_contours;
vector<Vec4i> hierarchy;
findContours(binary, ref_contours, hierarchy, RETR_LIST, method); //will call suzuki abe because using hierarchy
EXPECT_TRUE(!hierarchy.empty());
vector<vector<Point>> truco_contours;
findContours(binary, truco_contours, RETR_LIST, method);
EXPECT_TRUE(trucoContoursMatch(ref_contours, truco_contours)); //will use TRUCO because NOT using hierarchy AND RETR_LIST
}
}
TEST_P(Imgproc_FindTRUContours, noise_threshold)
{
ContourApproximationModes method = GetParam();
const Size sz(1500, 1500);
RNG& rng = TS::ptr()->get_rng();
const int levels[] = {86, 128, 170};
const int ITER = 2;
std::vector<int> thread_counts;
for(int i=2; i<40; i+=3) thread_counts.push_back(i);
for(int i=0; i<ITER; i++)
{
for (int level : levels)
{
SCOPED_TRACE(cv::format("level=%d method=%d", level, (int)method));
Mat noise(sz, CV_8UC1);
cvtest::randUni(rng, noise, 0, 255);
Mat blurred;
boxFilter(noise, blurred, CV_8U, Size(5, 5));
Mat binary;
cv::threshold(blurred, binary, level, 255, THRESH_BINARY);
vector<vector<Point>> ref_contours;
vector<Vec4i> hierarchy;
findContours(binary, ref_contours, hierarchy, RETR_LIST, method);//will call suzuki&abe because using hierarchy
EXPECT_TRUE(!hierarchy.empty());
for(auto nt: thread_counts){
CvNThreadScope ts(nt);
vector<vector<Point>> truco_contours;
findContours(binary, truco_contours, RETR_LIST, method);//will call TRUCO abe because NOT using hierarchy
EXPECT_TRUE(trucoContoursMatch(ref_contours, truco_contours));
}
}
}
}
TEST_P(Imgproc_FindTRUContours, nested_rectangles)
{
ContourApproximationModes method = GetParam();
const int DIM = 1500;
const Size sz(DIM, DIM);
const int NUM = 25;
Mat img(sz, CV_8UC1, Scalar::all(0));
Rect rect(1, 1, DIM - 2, DIM - 2);
for (int i = 0; i < NUM; ++i)
{
rectangle(img, rect, Scalar::all(255));
rect.x += 10;
rect.y += 10;
rect.width -= 20;
rect.height -= 20;
if (rect.width <= 0 || rect.height <= 0)
break;
}
vector<vector<Point>> ref_contours;
vector<Vec4i> hierarchy;
findContours(img, ref_contours, hierarchy, RETR_LIST, method);//will call suzuki abe because using hierarchy
EXPECT_TRUE(!hierarchy.empty());
vector<vector<Point>> truco_contours;
findContours(img, truco_contours, RETR_LIST, method);//will use TRUCO because NOT using hierarchy AND RETR_LIST
EXPECT_TRUE(trucoContoursMatch(ref_contours, truco_contours));
}
TEST_P(Imgproc_FindTRUContours, mixed_figures)
{
ContourApproximationModes method = GetParam();
const Size sz(1800, 1600);
RNG& rng = TS::ptr()->get_rng();
const int ITER = cvtest::debugLevel >= 10?100:10;
for (int iter = 0; iter < ITER; ++iter)
{
SCOPED_TRACE(cv::format("iter=%d method=%d", iter, (int)method));
Mat img(sz, CV_8UC1, Scalar::all(0));
for (int i = 0; i < 5; ++i)
{
Rect r(rng.uniform(10, sz.width / 2),
rng.uniform(10, sz.height / 2),
rng.uniform(20, 100),
rng.uniform(20, 100));
r &= Rect(0, 0, sz.width - 1, sz.height - 1);
rectangle(img, r, Scalar::all(255), FILLED);
}
for (int i = 0; i < 5; ++i)
{
Point center(rng.uniform(50, sz.width - 50),
rng.uniform(50, sz.height - 50));
int radius = rng.uniform(10, 50);
circle(img, center, radius, Scalar::all(255), FILLED);
}
for (int i = 0; i < 3; ++i)
{
Point pts[3];
for (auto& p : pts)
p = Point(rng.uniform(10, sz.width - 10),
rng.uniform(10, sz.height - 10));
const Point* ppts = pts;
int npts = 3;
fillPoly(img, &ppts, &npts, 1, Scalar::all(255));
}
vector<vector<Point>> ref_contours;
vector<Vec4i> hierarchy;
findContours(img, ref_contours, hierarchy, RETR_LIST, method);//will call suzuki abe because using hierarchy
EXPECT_TRUE(!hierarchy.empty());
vector<vector<Point>> truco_contours;
findContours(img, truco_contours, RETR_LIST, method);//will use TRUCO because NOT using hierarchy AND RETR_LIST
EXPECT_TRUE(trucoContoursMatch(ref_contours, truco_contours));
}
}
INSTANTIATE_TEST_CASE_P(Imgproc, Imgproc_FindTRUContours,
testing::Values(CHAIN_APPROX_NONE,CHAIN_APPROX_SIMPLE, CHAIN_APPROX_TC89_L1, CHAIN_APPROX_TC89_KCOS));
}} // namespace
@@ -0,0 +1,97 @@
/*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) 2015-2023, 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 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(Imgproc_CornerSubPix, out_of_image_corners)
{
const uint8_t image_pixels[] = {
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1,
0, 0, 0, 0, 0, 0, 2,
0, 0, 0, 0, 0, 0, 3};
cv::Mat image(cv::Size(7, 7), CV_8UC1, (void*)image_pixels, cv::Mat::AUTO_STEP);
std::vector<cv::Point2f> corners = {cv::Point2f(5.25, 6.5)};
cv::Size win(1, 1);
cv::Size zeroZone(-1, -1);
cv::TermCriteria criteria;
cv::cornerSubPix(image, corners, win, zeroZone, criteria);
ASSERT_EQ(corners.size(), 1u);
ASSERT_TRUE(Rect(0, 0, image.cols, image.rows).contains(corners.front()));
}
// See https://github.com/opencv/opencv/issues/26016
TEST(Imgproc_CornerSubPix, corners_on_the_edge)
{
cv::Mat image(500, 500, CV_8UC1);
RNG& rng = TS::ptr()->get_rng();
cvtest::randUni(rng, image, 0, 255);
cv::Size win(1, 1);
cv::Size zeroZone(-1, -1);
cv::TermCriteria criteria;
std::vector<cv::Point2f> cornersOK1 = { cv::Point2f(250, std::nextafter(499.5f, 499.5f - 1.0f)) };
EXPECT_NO_THROW( cv::cornerSubPix(image, cornersOK1, win, zeroZone, criteria) ) << cornersOK1;
std::vector<cv::Point2f> cornersOK2 = { cv::Point2f(250, 499.5f) };
EXPECT_NO_THROW( cv::cornerSubPix(image, cornersOK2, win, zeroZone, criteria) ) << cornersOK2;
std::vector<cv::Point2f> cornersOK3 = { cv::Point2f(250, std::nextafter(499.5f, 499.5f + 1.0f)) };
EXPECT_NO_THROW( cv::cornerSubPix(image, cornersOK3, win, zeroZone, criteria) ) << cornersOK3;
std::vector<cv::Point2f> cornersOK4 = { cv::Point2f(250, std::nextafter(500.0f, 500.0f - 1.0f)) };
EXPECT_NO_THROW( cv::cornerSubPix(image, cornersOK4, win, zeroZone, criteria) ) << cornersOK4;
std::vector<cv::Point2f> cornersNG1 = { cv::Point2f(250, 500.0f) };
EXPECT_ANY_THROW( cv::cornerSubPix(image, cornersNG1, win, zeroZone, criteria) ) << cornersNG1;
std::vector<cv::Point2f> cornersNG2 = { cv::Point2f(250, std::nextafter(500.0f, 500.0f + 1.0f)) };
EXPECT_ANY_THROW( cv::cornerSubPix(image, cornersNG2, win, zeroZone, criteria) ) << cornersNG2;
}
}} // namespace
+887
View File
@@ -0,0 +1,887 @@
#include "test_precomp.hpp"
namespace opencv_test { namespace {
#undef RGB
#undef YUV
typedef Vec3b YUV;
typedef Vec3b RGB;
int countOfDifferencies(const Mat& gold, const Mat& result, int maxAllowedDifference = 1)
{
Mat diff;
absdiff(gold, result, diff);
return countNonZero(diff.reshape(1) > maxAllowedDifference);
}
class YUVreader
{
public:
virtual ~YUVreader() {}
virtual YUV read(const Mat& yuv, int row, int col) = 0;
virtual int channels() = 0;
virtual Size size(Size imgSize) = 0;
virtual bool requiresEvenHeight() { return true; }
virtual bool requiresEvenWidth() { return true; }
static YUVreader* getReader(int code);
};
class RGBreader
{
public:
virtual ~RGBreader() {}
virtual RGB read(const Mat& rgb, int row, int col) = 0;
virtual int channels() = 0;
static RGBreader* getReader(int code);
};
class RGBwriter
{
public:
virtual ~RGBwriter() {}
virtual void write(Mat& rgb, int row, int col, const RGB& val) = 0;
virtual int channels() = 0;
static RGBwriter* getWriter(int code);
};
class GRAYwriter
{
public:
virtual ~GRAYwriter() {}
virtual void write(Mat& gray, int row, int col, const uchar& val)
{
gray.at<uchar>(row, col) = val;
}
virtual int channels() { return 1; }
static GRAYwriter* getWriter(int code);
};
class YUVwriter
{
public:
virtual ~YUVwriter() {}
virtual void write(Mat& yuv, int row, int col, const YUV& val) = 0;
virtual int channels() = 0;
virtual Size size(Size imgSize) = 0;
virtual bool requiresEvenHeight() { return true; }
virtual bool requiresEvenWidth() { return true; }
static YUVwriter* getWriter(int code);
};
class RGB888Writer : public RGBwriter
{
void write(Mat& rgb, int row, int col, const RGB& val)
{
rgb.at<Vec3b>(row, col) = val;
}
int channels() { return 3; }
};
class BGR888Writer : public RGBwriter
{
void write(Mat& rgb, int row, int col, const RGB& val)
{
Vec3b tmp(val[2], val[1], val[0]);
rgb.at<Vec3b>(row, col) = tmp;
}
int channels() { return 3; }
};
class RGBA8888Writer : public RGBwriter
{
void write(Mat& rgb, int row, int col, const RGB& val)
{
Vec4b tmp(val[0], val[1], val[2], 255);
rgb.at<Vec4b>(row, col) = tmp;
}
int channels() { return 4; }
};
class BGRA8888Writer : public RGBwriter
{
void write(Mat& rgb, int row, int col, const RGB& val)
{
Vec4b tmp(val[2], val[1], val[0], 255);
rgb.at<Vec4b>(row, col) = tmp;
}
int channels() { return 4; }
};
class YUV420pWriter: public YUVwriter
{
int channels() { return 1; }
Size size(Size imgSize) { return Size(imgSize.width, imgSize.height + imgSize.height/2); }
};
class YV12Writer: public YUV420pWriter
{
void write(Mat& yuv, int row, int col, const YUV& val)
{
int h = yuv.rows * 2 / 3;
yuv.ptr<uchar>(row)[col] = val[0];
if( row % 2 == 0 && col % 2 == 0 )
{
yuv.ptr<uchar>(h + row/4)[col/2 + ((row/2) % 2) * (yuv.cols/2)] = val[2];
yuv.ptr<uchar>(h + (row/2 + h/2)/2)[col/2 + ((row/2 + h/2) % 2) * (yuv.cols/2)] = val[1];
}
}
};
class I420Writer: public YUV420pWriter
{
void write(Mat& yuv, int row, int col, const YUV& val)
{
int h = yuv.rows * 2 / 3;
yuv.ptr<uchar>(row)[col] = val[0];
if( row % 2 == 0 && col % 2 == 0 )
{
yuv.ptr<uchar>(h + row/4)[col/2 + ((row/2) % 2) * (yuv.cols/2)] = val[1];
yuv.ptr<uchar>(h + (row/2 + h/2)/2)[col/2 + ((row/2 + h/2) % 2) * (yuv.cols/2)] = val[2];
}
}
};
class YUV422Writer: public YUVwriter
{
int channels() { return 2; }
Size size(Size imgSize) { return Size(imgSize.width, imgSize.height); }
};
class UYVYWriter: public YUV422Writer
{
virtual void write(Mat& yuv, int row, int col, const YUV& val)
{
yuv.ptr<Vec2b>(row)[col][1] = val[0];
yuv.ptr<Vec2b>(row)[(col/2)*2][0] = val[1];
yuv.ptr<Vec2b>(row)[(col/2)*2 + 1][0] = val[2];
}
};
class YUY2Writer: public YUV422Writer
{
virtual void write(Mat& yuv, int row, int col, const YUV& val)
{
yuv.ptr<Vec2b>(row)[col][0] = val[0];
yuv.ptr<Vec2b>(row)[(col/2)*2][1] = val[1];
yuv.ptr<Vec2b>(row)[(col/2)*2 + 1][1] = val[2];
}
};
class YVYUWriter: public YUV422Writer
{
virtual void write(Mat& yuv, int row, int col, const YUV& val)
{
yuv.ptr<Vec2b>(row)[col][0] = val[0];
yuv.ptr<Vec2b>(row)[(col/2)*2 + 1][1] = val[1];
yuv.ptr<Vec2b>(row)[(col/2)*2][1] = val[2];
}
};
class YUV420Reader: public YUVreader
{
int channels() { return 1; }
Size size(Size imgSize) { return Size(imgSize.width, imgSize.height * 3 / 2); }
};
class YUV422Reader: public YUVreader
{
int channels() { return 2; }
Size size(Size imgSize) { return imgSize; }
bool requiresEvenHeight() { return false; }
};
class NV21Reader: public YUV420Reader
{
YUV read(const Mat& yuv, int row, int col)
{
uchar y = yuv.ptr<uchar>(row)[col];
uchar u = yuv.ptr<uchar>(yuv.rows * 2 / 3 + row/2)[(col/2)*2 + 1];
uchar v = yuv.ptr<uchar>(yuv.rows * 2 / 3 + row/2)[(col/2)*2];
return YUV(y, u, v);
}
};
struct NV12Reader: public YUV420Reader
{
YUV read(const Mat& yuv, int row, int col)
{
uchar y = yuv.ptr<uchar>(row)[col];
uchar u = yuv.ptr<uchar>(yuv.rows * 2 / 3 + row/2)[(col/2)*2];
uchar v = yuv.ptr<uchar>(yuv.rows * 2 / 3 + row/2)[(col/2)*2 + 1];
return YUV(y, u, v);
}
};
class YV12Reader: public YUV420Reader
{
YUV read(const Mat& yuv, int row, int col)
{
int h = yuv.rows * 2 / 3;
uchar y = yuv.ptr<uchar>(row)[col];
uchar u = yuv.ptr<uchar>(h + (row/2 + h/2)/2)[col/2 + ((row/2 + h/2) % 2) * (yuv.cols/2)];
uchar v = yuv.ptr<uchar>(h + row/4)[col/2 + ((row/2) % 2) * (yuv.cols/2)];
return YUV(y, u, v);
}
};
class IYUVReader: public YUV420Reader
{
YUV read(const Mat& yuv, int row, int col)
{
int h = yuv.rows * 2 / 3;
uchar y = yuv.ptr<uchar>(row)[col];
uchar u = yuv.ptr<uchar>(h + row/4)[col/2 + ((row/2) % 2) * (yuv.cols/2)];
uchar v = yuv.ptr<uchar>(h + (row/2 + h/2)/2)[col/2 + ((row/2 + h/2) % 2) * (yuv.cols/2)];
return YUV(y, u, v);
}
};
class UYVYReader: public YUV422Reader
{
YUV read(const Mat& yuv, int row, int col)
{
uchar y = yuv.ptr<Vec2b>(row)[col][1];
uchar u = yuv.ptr<Vec2b>(row)[(col/2)*2][0];
uchar v = yuv.ptr<Vec2b>(row)[(col/2)*2 + 1][0];
return YUV(y, u, v);
}
};
class YUY2Reader: public YUV422Reader
{
YUV read(const Mat& yuv, int row, int col)
{
uchar y = yuv.ptr<Vec2b>(row)[col][0];
uchar u = yuv.ptr<Vec2b>(row)[(col/2)*2][1];
uchar v = yuv.ptr<Vec2b>(row)[(col/2)*2 + 1][1];
return YUV(y, u, v);
}
};
class YVYUReader: public YUV422Reader
{
YUV read(const Mat& yuv, int row, int col)
{
uchar y = yuv.ptr<Vec2b>(row)[col][0];
uchar u = yuv.ptr<Vec2b>(row)[(col/2)*2 + 1][1];
uchar v = yuv.ptr<Vec2b>(row)[(col/2)*2][1];
return YUV(y, u, v);
}
};
class YUV888Reader : public YUVreader
{
YUV read(const Mat& yuv, int row, int col)
{
return yuv.at<YUV>(row, col);
}
int channels() { return 3; }
Size size(Size imgSize) { return imgSize; }
bool requiresEvenHeight() { return false; }
bool requiresEvenWidth() { return false; }
};
class RGB888Reader : public RGBreader
{
RGB read(const Mat& rgb, int row, int col)
{
return rgb.at<RGB>(row, col);
}
int channels() { return 3; }
};
class BGR888Reader : public RGBreader
{
RGB read(const Mat& rgb, int row, int col)
{
RGB tmp = rgb.at<RGB>(row, col);
return RGB(tmp[2], tmp[1], tmp[0]);
}
int channels() { return 3; }
};
class RGBA8888Reader : public RGBreader
{
RGB read(const Mat& rgb, int row, int col)
{
Vec4b rgba = rgb.at<Vec4b>(row, col);
return RGB(rgba[0], rgba[1], rgba[2]);
}
int channels() { return 4; }
};
class BGRA8888Reader : public RGBreader
{
RGB read(const Mat& rgb, int row, int col)
{
Vec4b rgba = rgb.at<Vec4b>(row, col);
return RGB(rgba[2], rgba[1], rgba[0]);
}
int channels() { return 4; }
};
class YUV2RGB_Converter
{
public:
RGB convert(YUV yuv)
{
int y = std::max(0, yuv[0] - 16);
int u = yuv[1] - 128;
int v = yuv[2] - 128;
uchar r = saturate_cast<uchar>(1.164f * y + 1.596f * v);
uchar g = saturate_cast<uchar>(1.164f * y - 0.813f * v - 0.391f * u);
uchar b = saturate_cast<uchar>(1.164f * y + 2.018f * u);
return RGB(r, g, b);
}
};
class YUV2GRAY_Converter
{
public:
uchar convert(YUV yuv)
{
return yuv[0];
}
};
class RGB2YUV_Converter
{
public:
YUV convert(RGB rgb)
{
int r = rgb[0];
int g = rgb[1];
int b = rgb[2];
uchar y = saturate_cast<uchar>((int)( 0.257f*r + 0.504f*g + 0.098f*b + 0.5f) + 16);
uchar u = saturate_cast<uchar>((int)(-0.148f*r - 0.291f*g + 0.439f*b + 0.5f) + 128);
uchar v = saturate_cast<uchar>((int)( 0.439f*r - 0.368f*g - 0.071f*b + 0.5f) + 128);
return YUV(y, u, v);
}
};
class RGB2YUV422_Converter
{
public:
YUV convert(RGB rgb1, RGB rgb2, int idx)
{
int r1 = rgb1[0];
int g1 = rgb1[1];
int b1 = rgb1[2];
int r2 = rgb2[0];
int g2 = rgb2[1];
int b2 = rgb2[2];
// Coefficients below based on ITU.BT-601, ISBN 1-878707-09-4 (https://fourcc.org/fccyvrgb.php)
// The conversion coefficients for RGB to YUV422 are based on the ones for RGB to YUV.
// For both Y components, the coefficients are applied as given in the link to each input RGB pixel
// separately. For U and V, they are reduced by half to account for two RGB pixels contributing
// to the same U and V values. In other words, the U and V contributions from the two RGB pixels
// are averaged. The integer versions are obtained by multiplying the float versions by 16384
// and rounding to the nearest integer.
uchar y1 = saturate_cast<uchar>((int)( 0.257f*r1 + 0.504f*g1 + 0.098f*b1 + 16));
uchar y2 = saturate_cast<uchar>((int)( 0.257f*r2 + 0.504f*g2 + 0.098f*b2 + 16));
uchar u = saturate_cast<uchar>((int)(-0.074f*(r1+r2) - 0.1455f*(g1+g2) + 0.2195f*(b1+b2) + 128));
uchar v = saturate_cast<uchar>((int)( 0.2195f*(r1+r2) - 0.184f*(g1+g2) - 0.0355f*(b1+b2) + 128));
return YUV((idx==0)?y1:y2, u, v);
}
};
YUVreader* YUVreader::getReader(int code)
{
switch(code)
{
case COLOR_YUV2RGB_NV12:
case COLOR_YUV2BGR_NV12:
case COLOR_YUV2RGBA_NV12:
case COLOR_YUV2BGRA_NV12:
return new NV12Reader();
case COLOR_YUV2RGB_NV21:
case COLOR_YUV2BGR_NV21:
case COLOR_YUV2RGBA_NV21:
case COLOR_YUV2BGRA_NV21:
return new NV21Reader();
case COLOR_YUV2RGB_YV12:
case COLOR_YUV2BGR_YV12:
case COLOR_YUV2RGBA_YV12:
case COLOR_YUV2BGRA_YV12:
return new YV12Reader();
case COLOR_YUV2RGB_IYUV:
case COLOR_YUV2BGR_IYUV:
case COLOR_YUV2RGBA_IYUV:
case COLOR_YUV2BGRA_IYUV:
return new IYUVReader();
case COLOR_YUV2RGB_UYVY:
case COLOR_YUV2BGR_UYVY:
case COLOR_YUV2RGBA_UYVY:
case COLOR_YUV2BGRA_UYVY:
return new UYVYReader();
//case COLOR_YUV2RGB_VYUY = 109,
//case COLOR_YUV2BGR_VYUY = 110,
//case COLOR_YUV2RGBA_VYUY = 113,
//case COLOR_YUV2BGRA_VYUY = 114,
// return ??
case COLOR_YUV2RGB_YUY2:
case COLOR_YUV2BGR_YUY2:
case COLOR_YUV2RGBA_YUY2:
case COLOR_YUV2BGRA_YUY2:
return new YUY2Reader();
case COLOR_YUV2RGB_YVYU:
case COLOR_YUV2BGR_YVYU:
case COLOR_YUV2RGBA_YVYU:
case COLOR_YUV2BGRA_YVYU:
return new YVYUReader();
case COLOR_YUV2GRAY_420:
return new NV21Reader();
case COLOR_YUV2GRAY_UYVY:
return new UYVYReader();
case COLOR_YUV2GRAY_YUY2:
return new YUY2Reader();
case COLOR_YUV2BGR:
case COLOR_YUV2RGB:
return new YUV888Reader();
default:
return 0;
}
}
RGBreader* RGBreader::getReader(int code)
{
switch(code)
{
case COLOR_RGB2YUV_YV12:
case COLOR_RGB2YUV_I420:
case COLOR_RGB2YUV_UYVY:
case COLOR_RGB2YUV_YUY2:
case COLOR_RGB2YUV_YVYU:
return new RGB888Reader();
case COLOR_BGR2YUV_YV12:
case COLOR_BGR2YUV_I420:
case COLOR_BGR2YUV_UYVY:
case COLOR_BGR2YUV_YUY2:
case COLOR_BGR2YUV_YVYU:
return new BGR888Reader();
case COLOR_RGBA2YUV_I420:
case COLOR_RGBA2YUV_YV12:
case COLOR_RGBA2YUV_UYVY:
case COLOR_RGBA2YUV_YUY2:
case COLOR_RGBA2YUV_YVYU:
return new RGBA8888Reader();
case COLOR_BGRA2YUV_YV12:
case COLOR_BGRA2YUV_I420:
case COLOR_BGRA2YUV_UYVY:
case COLOR_BGRA2YUV_YUY2:
case COLOR_BGRA2YUV_YVYU:
return new BGRA8888Reader();
default:
return 0;
};
}
RGBwriter* RGBwriter::getWriter(int code)
{
switch(code)
{
case COLOR_YUV2RGB_NV12:
case COLOR_YUV2RGB_NV21:
case COLOR_YUV2RGB_YV12:
case COLOR_YUV2RGB_IYUV:
case COLOR_YUV2RGB_UYVY:
//case COLOR_YUV2RGB_VYUY:
case COLOR_YUV2RGB_YUY2:
case COLOR_YUV2RGB_YVYU:
case COLOR_YUV2RGB:
return new RGB888Writer();
case COLOR_YUV2BGR_NV12:
case COLOR_YUV2BGR_NV21:
case COLOR_YUV2BGR_YV12:
case COLOR_YUV2BGR_IYUV:
case COLOR_YUV2BGR_UYVY:
//case COLOR_YUV2BGR_VYUY:
case COLOR_YUV2BGR_YUY2:
case COLOR_YUV2BGR_YVYU:
case COLOR_YUV2BGR:
return new BGR888Writer();
case COLOR_YUV2RGBA_NV12:
case COLOR_YUV2RGBA_NV21:
case COLOR_YUV2RGBA_YV12:
case COLOR_YUV2RGBA_IYUV:
case COLOR_YUV2RGBA_UYVY:
//case COLOR_YUV2RGBA_VYUY:
case COLOR_YUV2RGBA_YUY2:
case COLOR_YUV2RGBA_YVYU:
return new RGBA8888Writer();
case COLOR_YUV2BGRA_NV12:
case COLOR_YUV2BGRA_NV21:
case COLOR_YUV2BGRA_YV12:
case COLOR_YUV2BGRA_IYUV:
case COLOR_YUV2BGRA_UYVY:
//case COLOR_YUV2BGRA_VYUY:
case COLOR_YUV2BGRA_YUY2:
case COLOR_YUV2BGRA_YVYU:
return new BGRA8888Writer();
default:
return 0;
};
}
GRAYwriter* GRAYwriter::getWriter(int code)
{
switch(code)
{
case COLOR_YUV2GRAY_420:
case COLOR_YUV2GRAY_UYVY:
case COLOR_YUV2GRAY_YUY2:
return new GRAYwriter();
default:
return 0;
}
}
YUVwriter* YUVwriter::getWriter(int code)
{
switch(code)
{
case COLOR_RGB2YUV_YV12:
case COLOR_BGR2YUV_YV12:
case COLOR_RGBA2YUV_YV12:
case COLOR_BGRA2YUV_YV12:
return new YV12Writer();
case COLOR_RGB2YUV_UYVY:
case COLOR_BGR2YUV_UYVY:
case COLOR_RGBA2YUV_UYVY:
case COLOR_BGRA2YUV_UYVY:
return new UYVYWriter();
case COLOR_RGB2YUV_YUY2:
case COLOR_BGR2YUV_YUY2:
case COLOR_RGBA2YUV_YUY2:
case COLOR_BGRA2YUV_YUY2:
return new YUY2Writer();
case COLOR_RGB2YUV_YVYU:
case COLOR_BGR2YUV_YVYU:
case COLOR_RGBA2YUV_YVYU:
case COLOR_BGRA2YUV_YVYU:
return new YVYUWriter();
case COLOR_RGB2YUV_I420:
case COLOR_BGR2YUV_I420:
case COLOR_RGBA2YUV_I420:
case COLOR_BGRA2YUV_I420:
return new I420Writer();
default:
return 0;
};
}
template<class convertor>
void referenceYUV2RGB(const Mat& yuv, Mat& rgb, YUVreader* yuvReader, RGBwriter* rgbWriter)
{
convertor cvt;
for(int row = 0; row < rgb.rows; ++row)
for(int col = 0; col < rgb.cols; ++col)
rgbWriter->write(rgb, row, col, cvt.convert(yuvReader->read(yuv, row, col)));
}
template<class convertor>
void referenceYUV2GRAY(const Mat& yuv, Mat& rgb, YUVreader* yuvReader, GRAYwriter* grayWriter)
{
convertor cvt;
for(int row = 0; row < rgb.rows; ++row)
for(int col = 0; col < rgb.cols; ++col)
grayWriter->write(rgb, row, col, cvt.convert(yuvReader->read(yuv, row, col)));
}
template<class convertor>
void referenceRGB2YUV(const Mat& rgb, Mat& yuv, RGBreader* rgbReader, YUVwriter* yuvWriter)
{
convertor cvt;
for(int row = 0; row < rgb.rows; ++row)
for(int col = 0; col < rgb.cols; ++col)
yuvWriter->write(yuv, row, col, cvt.convert(rgbReader->read(rgb, row, col)));
}
template<class convertor>
void referenceRGB2YUV422(const Mat& rgb, Mat& yuv, RGBreader* rgbReader, YUVwriter* yuvWriter)
{
convertor cvt;
for(int row = 0; row < rgb.rows; ++row)
{
for(int col = 0; col < rgb.cols; col+=2)
{
yuvWriter->write(yuv, row, col, cvt.convert(rgbReader->read(rgb, row, col), rgbReader->read(rgb, row, col+1), 0));
yuvWriter->write(yuv, row, col+1, cvt.convert(rgbReader->read(rgb, row, col), rgbReader->read(rgb, row, col+1), 1));
}
}
}
struct ConversionYUV
{
explicit ConversionYUV( const int code )
{
yuvReader_ = YUVreader :: getReader(code);
yuvWriter_ = YUVwriter :: getWriter(code);
rgbReader_ = RGBreader :: getReader(code);
rgbWriter_ = RGBwriter :: getWriter(code);
grayWriter_ = GRAYwriter:: getWriter(code);
}
~ConversionYUV()
{
if (yuvReader_)
delete yuvReader_;
if (yuvWriter_)
delete yuvWriter_;
if (rgbReader_)
delete rgbReader_;
if (rgbWriter_)
delete rgbWriter_;
if (grayWriter_)
delete grayWriter_;
}
int getDcn()
{
return (rgbWriter_ != 0) ? rgbWriter_->channels() : ((grayWriter_ != 0) ? grayWriter_->channels() : yuvWriter_->channels());
}
int getScn()
{
return (yuvReader_ != 0) ? yuvReader_->channels() : rgbReader_->channels();
}
Size getSrcSize( const Size& imgSize )
{
return (yuvReader_ != 0) ? yuvReader_->size(imgSize) : imgSize;
}
Size getDstSize( const Size& imgSize )
{
return (yuvWriter_ != 0) ? yuvWriter_->size(imgSize) : imgSize;
}
bool requiresEvenHeight()
{
return (yuvReader_ != 0) ? yuvReader_->requiresEvenHeight() : ((yuvWriter_ != 0) ? yuvWriter_->requiresEvenHeight() : false);
}
bool requiresEvenWidth()
{
return (yuvReader_ != 0) ? yuvReader_->requiresEvenWidth() : ((yuvWriter_ != 0) ? yuvWriter_->requiresEvenWidth() : false);
}
YUVreader* yuvReader_;
YUVwriter* yuvWriter_;
RGBreader* rgbReader_;
RGBwriter* rgbWriter_;
GRAYwriter* grayWriter_;
};
bool is_rgb2yuv422(int code)
{
switch (code)
{
case COLOR_RGB2YUV_UYVY:
case COLOR_BGR2YUV_UYVY:
case COLOR_RGBA2YUV_UYVY:
case COLOR_BGRA2YUV_UYVY:
case COLOR_RGB2YUV_YUY2:
case COLOR_BGR2YUV_YUY2:
case COLOR_RGBA2YUV_YUY2:
case COLOR_BGRA2YUV_YUY2:
case COLOR_RGB2YUV_YVYU:
case COLOR_BGR2YUV_YVYU:
case COLOR_RGBA2YUV_YVYU:
case COLOR_BGRA2YUV_YVYU:
return true;
default:
return false;
}
}
CV_ENUM(YUVCVTS, COLOR_YUV2RGB_NV12, COLOR_YUV2BGR_NV12, COLOR_YUV2RGB_NV21, COLOR_YUV2BGR_NV21,
COLOR_YUV2RGBA_NV12, COLOR_YUV2BGRA_NV12, COLOR_YUV2RGBA_NV21, COLOR_YUV2BGRA_NV21,
COLOR_YUV2RGB_YV12, COLOR_YUV2BGR_YV12, COLOR_YUV2RGB_IYUV, COLOR_YUV2BGR_IYUV,
COLOR_YUV2RGBA_YV12, COLOR_YUV2BGRA_YV12, COLOR_YUV2RGBA_IYUV, COLOR_YUV2BGRA_IYUV,
COLOR_YUV2RGB_UYVY, COLOR_YUV2BGR_UYVY, COLOR_YUV2RGBA_UYVY, COLOR_YUV2BGRA_UYVY,
COLOR_YUV2RGB_YUY2, COLOR_YUV2BGR_YUY2, COLOR_YUV2RGB_YVYU, COLOR_YUV2BGR_YVYU,
COLOR_YUV2RGBA_YUY2, COLOR_YUV2BGRA_YUY2, COLOR_YUV2RGBA_YVYU, COLOR_YUV2BGRA_YVYU,
COLOR_YUV2GRAY_420, COLOR_YUV2GRAY_UYVY, COLOR_YUV2GRAY_YUY2,
COLOR_YUV2BGR, COLOR_YUV2RGB, COLOR_RGB2YUV_YV12, COLOR_BGR2YUV_YV12, COLOR_RGBA2YUV_YV12,
COLOR_BGRA2YUV_YV12, COLOR_RGB2YUV_I420, COLOR_BGR2YUV_I420, COLOR_RGBA2YUV_I420, COLOR_BGRA2YUV_I420,
COLOR_RGB2YUV_UYVY, COLOR_BGR2YUV_UYVY, COLOR_RGBA2YUV_UYVY, COLOR_BGRA2YUV_UYVY,
COLOR_RGB2YUV_YUY2, COLOR_BGR2YUV_YUY2, COLOR_RGB2YUV_YVYU, COLOR_BGR2YUV_YVYU,
COLOR_RGBA2YUV_YUY2, COLOR_BGRA2YUV_YUY2, COLOR_RGBA2YUV_YVYU, COLOR_BGRA2YUV_YVYU)
typedef ::testing::TestWithParam<YUVCVTS> Imgproc_ColorYUV;
TEST_P(Imgproc_ColorYUV, accuracy)
{
int code = GetParam();
bool yuv422 = is_rgb2yuv422(code);
RNG& random = theRNG();
ConversionYUV cvt(code);
const int scn = cvt.getScn();
const int dcn = cvt.getDcn();
for(int iter = 0; iter < 30; ++iter)
{
Size sz(random.uniform(1, 641), random.uniform(1, 481));
if(cvt.requiresEvenWidth()) sz.width += sz.width % 2;
if(cvt.requiresEvenHeight()) sz.height += sz.height % 2;
Size srcSize = cvt.getSrcSize(sz);
Mat src = Mat(srcSize.height, srcSize.width * scn, CV_8UC1).reshape(scn);
Size dstSize = cvt.getDstSize(sz);
Mat dst = Mat(dstSize.height, dstSize.width * dcn, CV_8UC1).reshape(dcn);
Mat gold(dstSize, CV_8UC(dcn));
random.fill(src, RNG::UNIFORM, 0, 256);
if(cvt.rgbWriter_)
referenceYUV2RGB<YUV2RGB_Converter> (src, gold, cvt.yuvReader_, cvt.rgbWriter_);
else if(cvt.grayWriter_)
referenceYUV2GRAY<YUV2GRAY_Converter>(src, gold, cvt.yuvReader_, cvt.grayWriter_);
else if(cvt.yuvWriter_)
{
if(!yuv422)
referenceRGB2YUV<RGB2YUV_Converter> (src, gold, cvt.rgbReader_, cvt.yuvWriter_);
else
referenceRGB2YUV422<RGB2YUV422_Converter> (src, gold, cvt.rgbReader_, cvt.yuvWriter_);
}
cv::cvtColor(src, dst, code, -1);
EXPECT_EQ(0, countOfDifferencies(gold, dst));
}
}
TEST_P(Imgproc_ColorYUV, roi_accuracy)
{
int code = GetParam();
bool yuv422 = is_rgb2yuv422(code);
RNG& random = theRNG();
ConversionYUV cvt(code);
const int scn = cvt.getScn();
const int dcn = cvt.getDcn();
for(int iter = 0; iter < 30; ++iter)
{
Size sz(random.uniform(1, 641), random.uniform(1, 481));
if(cvt.requiresEvenWidth()) sz.width += sz.width % 2;
if(cvt.requiresEvenHeight()) sz.height += sz.height % 2;
int roi_offset_top = random.uniform(0, 6);
int roi_offset_bottom = random.uniform(0, 6);
int roi_offset_left = random.uniform(0, 6);
int roi_offset_right = random.uniform(0, 6);
Size srcSize = cvt.getSrcSize(sz);
Mat src_full(srcSize.height + roi_offset_top + roi_offset_bottom, srcSize.width + roi_offset_left + roi_offset_right, CV_8UC(scn));
Size dstSize = cvt.getDstSize(sz);
Mat dst_full(dstSize.height + roi_offset_left + roi_offset_right, dstSize.width + roi_offset_top + roi_offset_bottom, CV_8UC(dcn), Scalar::all(0));
Mat gold_full(dst_full.size(), CV_8UC(dcn), Scalar::all(0));
random.fill(src_full, RNG::UNIFORM, 0, 256);
Mat src = src_full(Range(roi_offset_top, roi_offset_top + srcSize.height), Range(roi_offset_left, roi_offset_left + srcSize.width));
Mat dst = dst_full(Range(roi_offset_left, roi_offset_left + dstSize.height), Range(roi_offset_top, roi_offset_top + dstSize.width));
Mat gold = gold_full(Range(roi_offset_left, roi_offset_left + dstSize.height), Range(roi_offset_top, roi_offset_top + dstSize.width));
if(cvt.rgbWriter_)
referenceYUV2RGB<YUV2RGB_Converter> (src, gold, cvt.yuvReader_, cvt.rgbWriter_);
else if(cvt.grayWriter_)
referenceYUV2GRAY<YUV2GRAY_Converter>(src, gold, cvt.yuvReader_, cvt.grayWriter_);
else if(cvt.yuvWriter_)
{
if(!yuv422)
referenceRGB2YUV<RGB2YUV_Converter> (src, gold, cvt.rgbReader_, cvt.yuvWriter_);
else
referenceRGB2YUV422<RGB2YUV422_Converter> (src, gold, cvt.rgbReader_, cvt.yuvWriter_);
}
cv::cvtColor(src, dst, code, -1);
EXPECT_EQ(0, countOfDifferencies(gold_full, dst_full));
}
}
INSTANTIATE_TEST_CASE_P(cvt420, Imgproc_ColorYUV,
::testing::Values((int)COLOR_YUV2RGB_NV12, (int)COLOR_YUV2BGR_NV12, (int)COLOR_YUV2RGB_NV21, (int)COLOR_YUV2BGR_NV21,
(int)COLOR_YUV2RGBA_NV12, (int)COLOR_YUV2BGRA_NV12, (int)COLOR_YUV2RGBA_NV21, (int)COLOR_YUV2BGRA_NV21,
(int)COLOR_YUV2RGB_YV12, (int)COLOR_YUV2BGR_YV12, (int)COLOR_YUV2RGB_IYUV, (int)COLOR_YUV2BGR_IYUV,
(int)COLOR_YUV2RGBA_YV12, (int)COLOR_YUV2BGRA_YV12, (int)COLOR_YUV2RGBA_IYUV, (int)COLOR_YUV2BGRA_IYUV,
(int)COLOR_YUV2GRAY_420, (int)COLOR_RGB2YUV_YV12, (int)COLOR_BGR2YUV_YV12, (int)COLOR_RGBA2YUV_YV12,
(int)COLOR_BGRA2YUV_YV12, (int)COLOR_RGB2YUV_I420, (int)COLOR_BGR2YUV_I420, (int)COLOR_RGBA2YUV_I420,
(int)COLOR_BGRA2YUV_I420));
INSTANTIATE_TEST_CASE_P(cvt422, Imgproc_ColorYUV,
::testing::Values((int)COLOR_YUV2RGB_UYVY, (int)COLOR_YUV2BGR_UYVY, (int)COLOR_YUV2RGBA_UYVY, (int)COLOR_YUV2BGRA_UYVY,
(int)COLOR_YUV2RGB_YUY2, (int)COLOR_YUV2BGR_YUY2, (int)COLOR_YUV2RGB_YVYU, (int)COLOR_YUV2BGR_YVYU,
(int)COLOR_YUV2RGBA_YUY2, (int)COLOR_YUV2BGRA_YUY2, (int)COLOR_YUV2RGBA_YVYU, (int)COLOR_YUV2BGRA_YVYU,
(int)COLOR_YUV2GRAY_UYVY, (int)COLOR_YUV2GRAY_YUY2,
(int)COLOR_RGB2YUV_UYVY, (int)COLOR_BGR2YUV_UYVY, (int)COLOR_RGBA2YUV_UYVY, (int)COLOR_BGRA2YUV_UYVY,
(int)COLOR_RGB2YUV_YUY2, (int)COLOR_BGR2YUV_YUY2, (int)COLOR_RGB2YUV_YVYU, (int)COLOR_BGR2YUV_YVYU,
(int)COLOR_RGBA2YUV_YUY2, (int)COLOR_BGRA2YUV_YUY2, (int)COLOR_RGBA2YUV_YVYU, (int)COLOR_BGRA2YUV_YVYU,
(int)COLOR_RGB2YUV_YUY2));
}
TEST(cvtColorUYVY, size_issue_21035)
{
Mat input = Mat::zeros(1, 1, CV_8UC2);
Mat output;
EXPECT_THROW(cv::cvtColor(input, output, cv::COLOR_YUV2BGR_UYVY), cv::Exception);
}
} // namespace
@@ -0,0 +1,212 @@
/*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"
#include <numeric>
namespace opencv_test { namespace {
BIGDATA_TEST(Imgproc_DistanceTransform, large_image_12218)
{
const int lls_maxcnt = 79992000; // labels's maximum count
const int lls_mincnt = 1; // labels's minimum count
int i, j, nz;
Mat src(8000, 20000, CV_8UC1), dst, labels;
for( i = 0; i < src.rows; i++ )
for( j = 0; j < src.cols; j++ )
src.at<uchar>(i, j) = (j > (src.cols / 2)) ? 0 : 255;
distanceTransform(src, dst, labels, cv::DIST_L2, cv::DIST_MASK_3, DIST_LABEL_PIXEL);
double scale = (double)lls_mincnt / (double)lls_maxcnt;
labels.convertTo(labels, CV_32SC1, scale);
Size size = labels.size();
nz = cv::countNonZero(labels);
EXPECT_EQ(nz, (size.height*size.width / 2));
}
TEST(Imgproc_DistanceTransform, wide_image_22732)
{
Mat src = Mat::zeros(1, 4099, CV_8U); // 4099 or larger used to be bad
Mat dist(src.rows, src.cols, CV_32F);
distanceTransform(src, dist, DIST_L2, DIST_MASK_PRECISE, CV_32F);
int nz = countNonZero(dist);
EXPECT_EQ(nz, 0);
}
TEST(Imgproc_DistanceTransform, large_square_22732)
{
Mat src = Mat::zeros(8000, 8005, CV_8U), dist;
distanceTransform(src, dist, DIST_L2, DIST_MASK_PRECISE, CV_32F);
int nz = countNonZero(dist);
EXPECT_EQ(dist.size(), src.size());
EXPECT_EQ(dist.type(), CV_32F);
EXPECT_EQ(nz, 0);
Point p0(src.cols-1, src.rows-1);
src.setTo(1);
src.at<uchar>(p0) = 0;
distanceTransform(src, dist, DIST_L2, DIST_MASK_PRECISE, CV_32F);
EXPECT_EQ(dist.size(), src.size());
EXPECT_EQ(dist.type(), CV_32F);
bool first = true;
int nerrs = 0;
for (int y = 0; y < dist.rows; y++)
for (int x = 0; x < dist.cols; x++) {
float d = dist.at<float>(y, x);
double dx = (double)(x - p0.x), dy = (double)(y - p0.y);
float d0 = (float)sqrt(dx*dx + dy*dy);
if (std::abs(d0 - d) > 1) {
if (first) {
printf("y=%d, x=%d. dist_ref=%.2f, dist=%.2f\n", y, x, d0, d);
first = false;
}
nerrs++;
}
}
EXPECT_EQ(0, nerrs) << "reference distance map is different from computed one at " << nerrs << " pixels\n";
}
BIGDATA_TEST(Imgproc_DistanceTransform, issue_23895_3x3)
{
Mat src = Mat::zeros(50000, 50000, CV_8U), dist;
distanceTransform(src.col(0), dist, DIST_L2, DIST_MASK_3);
int nz = countNonZero(dist);
EXPECT_EQ(nz, 0);
}
BIGDATA_TEST(Imgproc_DistanceTransform, issue_23895_5x5)
{
Mat src = Mat::zeros(50000, 50000, CV_8U), dist;
distanceTransform(src.col(0), dist, DIST_L2, DIST_MASK_5);
int nz = countNonZero(dist);
EXPECT_EQ(nz, 0);
}
BIGDATA_TEST(Imgproc_DistanceTransform, issue_23895_5x5_labels)
{
Mat src = Mat::zeros(50000, 50000, CV_8U), dist, labels;
distanceTransform(src.col(0), dist, labels, DIST_L2, DIST_MASK_5);
int nz = countNonZero(dist);
EXPECT_EQ(nz, 0);
}
TEST(Imgproc_DistanceTransform, max_distance_3x3)
{
Mat src = Mat::ones(1, 70000, CV_8U), dist;
src.at<uint8_t>(0, 0) = 0;
distanceTransform(src, dist, DIST_L2, DIST_MASK_3);
double minVal, maxVal;
minMaxLoc(dist, &minVal, &maxVal);
EXPECT_GE(maxVal, 65533);
}
TEST(Imgproc_DistanceTransform, max_distance_5x5)
{
Mat src = Mat::ones(1, 70000, CV_8U), dist;
src.at<uint8_t>(0, 0) = 0;
distanceTransform(src, dist, DIST_L2, DIST_MASK_5);
double minVal, maxVal;
minMaxLoc(dist, &minVal, &maxVal);
EXPECT_GE(maxVal, 65533);
}
TEST(Imgproc_DistanceTransform, max_distance_5x5_labels)
{
Mat src = Mat::ones(1, 70000, CV_8U), dist, labels;
src.at<uint8_t>(0, 0) = 0;
distanceTransform(src, dist, labels, DIST_L2, DIST_MASK_5);
double minVal, maxVal;
minMaxLoc(dist, &minVal, &maxVal);
EXPECT_GE(maxVal, 65533);
}
TEST(Imgproc_DistanceTransform, precise_long_dist)
{
static const int maxDist = 1 << 16;
Mat src = Mat::ones(1, 70000, CV_8U), dist;
src.at<uint8_t>(0, 0) = 0;
distanceTransform(src, dist, DIST_L2, DIST_MASK_PRECISE, CV_32F);
Mat expected(src.size(), CV_32F);
std::iota(expected.begin<float>(), expected.end<float>(), 0.f);
expected.colRange(maxDist, expected.cols).setTo(maxDist);
EXPECT_EQ(cv::norm(expected, dist, NORM_INF), 0);
}
TEST(Imgproc_DistanceTransform, ipp_deterministic_corner)
{
setNumThreads(1);
Mat src(1, 4096, CV_8U, Scalar(255)), dist;
src.at<uint8_t>(0, 0) = 0;
distanceTransform(src, dist, DIST_L2, DIST_MASK_PRECISE);
for (int i = 0; i < src.cols; ++i)
{
float expected = static_cast<float>(i);
ASSERT_EQ(expected, dist.at<float>(0, i)) << cv::format("diff: %e", expected - dist.at<float>(0, i));
}
}
TEST(Imgproc_DistanceTransform, ipp_deterministic)
{
setNumThreads(1);
RNG& rng = TS::ptr()->get_rng();
Mat src(1, 800, CV_8U, Scalar(255)), dist;
int p1 = cvtest::randInt(rng) % src.cols;
int p2 = cvtest::randInt(rng) % src.cols;
int p3 = cvtest::randInt(rng) % src.cols;
src.at<uint8_t>(0, p1) = 0;
src.at<uint8_t>(0, p2) = 0;
src.at<uint8_t>(0, p3) = 0;
distanceTransform(src, dist, DIST_L2, DIST_MASK_PRECISE);
for (int i = 0; i < src.cols; ++i)
{
float expected = static_cast<float>(min(min(abs(i - p1), abs(i - p2)), abs(i - p3)));
ASSERT_EQ(expected, dist.at<float>(0, i)) << cv::format("diff: %e", expected - dist.at<float>(0, i));
}
}
}} // namespace
File diff suppressed because it is too large Load Diff
+250
View File
@@ -0,0 +1,250 @@
// 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 "opencv2/imgproc.hpp"
#include "test_precomp.hpp"
using namespace cv;
using namespace std;
namespace opencv_test { namespace {
//==============================================================================
// Utility
template <typename T>
inline T sqr(T val)
{
return val * val;
}
inline static float calcEMD(Mat w1, Mat w2, Mat& flow, int dist, int dims)
{
float mass1 = 0.f, mass2 = 0.f, work = 0.f;
for (int i = 0; i < flow.rows; ++i)
{
mass1 += w1.at<float>(i, 0);
for (int j = 0; j < flow.cols; ++j)
{
if (i == 0)
mass2 += w2.at<float>(j, 0);
float dist_ = 0.f;
switch (dist)
{
case DIST_L1:
{
for (int k = 1; k <= dims; ++k)
{
dist_ += abs(w1.at<float>(i, k) - w2.at<float>(j, k));
}
break;
}
case DIST_L2:
{
for (int k = 1; k <= dims; ++k)
{
dist_ += sqr(w1.at<float>(i, k) - w2.at<float>(j, k));
}
dist_ = sqrt(dist_);
break;
}
case DIST_C:
{
for (int k = 1; k <= dims; ++k)
{
const float val = abs(w1.at<float>(i, k) - w2.at<float>(j, k));
if (val > dist_)
dist_ = val;
}
break;
}
}
const float weight = flow.at<float>(i, j);
work += dist_ * weight;
}
}
return work / max(mass1, mass2);
}
//==============================================================================
TEST(Imgproc_EMD, regression)
{
// input data
const float M = 10000;
Matx<float, 4, 1> w1 {50, 60, 50, 50};
Matx<float, 5, 1> w2 {30, 20, 70, 30, 60};
Matx<float, 4, 5> cost {16, 16, 13, 22, 17, 14, 14, 13, 19, 15,
19, 19, 20, 23, M, M, 0, M, 0, 0};
// expected results
const double emd0 = 2460. / 210;
Matx<float, 4, 5> flow0 {0, 0, 50, 0, 0, 0, 0, 20, 0, 40, 30, 20, 0, 0, 0, 0, 0, 0, 30, 20};
// basic call with cost
{
float emd = 0.f;
ASSERT_NO_THROW(emd = EMD(w1, w2, DIST_USER, cost));
EXPECT_NEAR(emd, emd0, 1e-6 * emd0);
}
// basic call with cost and flow output
{
Mat flow;
float emd = 0.f;
ASSERT_NO_THROW(emd = EMD(w1, w2, DIST_USER, cost, nullptr, flow));
EXPECT_NEAR(emd, emd0, 1e-6 * emd0);
EXPECT_MAT_NEAR(Mat(flow0), flow, 1e-6);
}
// no cost and DIST_USER - error
{
Mat flow;
EXPECT_THROW(EMD(w1, w2, DIST_USER, noArray(), nullptr, flow), cv::Exception);
EXPECT_THROW(EMD(w1, w2, DIST_USER), cv::Exception);
}
}
TEST(Imgproc_EMD, distance_types)
{
// 1D (sum = 210)
Matx<float, 4, 2> w1 {50, 1, 60, 2, 50, 3, 50, 4};
Matx<float, 5, 2> w2 {30, 1, 20, 2, 70, 3, 30, 4, 60, 5};
// 2D (sum = 210)
Matx<float, 4, 3> w3 {50, 0, 0, 60, 0, 1, 50, 1, 0, 50, 1, 1};
Matx<float, 5, 3> w4 {20, 0, 1, 70, 1, 0, 30, 1, 1, 60, 2, 2, 30, 3, 3};
// basic call with all distance types
{
const vector<DistanceTypes> good_types {DIST_L1, DIST_L2, DIST_C};
for (const auto& dt : good_types)
{
SCOPED_TRACE(cv::format("dt=%d", dt));
float emd = 0.f;
Mat flow;
// 1D
{
ASSERT_NO_THROW(emd = EMD(w1, w2, dt, noArray(), nullptr, flow));
const float emd0 = calcEMD(Mat(w1), Mat(w2), flow, dt, 1);
EXPECT_NEAR(emd0, emd, 1e-6);
}
// 2D
{
ASSERT_NO_THROW(emd = EMD(w3, w4, dt, noArray(), nullptr, flow));
const float emd0 = calcEMD(Mat(w3), Mat(w4), flow, dt, 2);
EXPECT_NEAR(emd0, emd, 1e-6);
}
}
}
}
typedef testing::TestWithParam<int> Imgproc_EMD_dist;
TEST_P(Imgproc_EMD_dist, random_flow_verify)
{
const int dist = GetParam();
for (size_t iter = 0; iter < 100; ++iter)
{
SCOPED_TRACE(cv::format("iter=%zu", iter));
RNG& rng = TS::ptr()->get_rng();
const int dims = rng.uniform(1, 10);
Mat w1(rng.uniform(1, 10), dims + 1, CV_32FC1);
Mat w2(rng.uniform(1, 10), dims + 1, CV_32FC1);
// weights > 0
{
Mat w1_weights = w1.col(0);
Mat w2_weights = w2.col(0);
cvtest::randUni(rng, w1_weights, 0, 100);
cvtest::randUni(rng, w2_weights, 0, 100);
}
// coord
{
Mat w1_coord = w1.colRange(1, dims + 1);
Mat w2_coord = w2.colRange(1, dims + 1);
cvtest::randUni(rng, w1_coord, -10, +10);
cvtest::randUni(rng, w2_coord, -10, +10);
}
float emd1 = 0.f, emd2 = 0.f;
const float eps = 1e-5f;
Mat flow;
{
ASSERT_NO_THROW(emd1 = EMD(w1, w2, dist, noArray(), nullptr, flow));
const float emd0 = calcEMD(w1, w2, flow, dist, dims);
EXPECT_NEAR(emd0, emd1, eps);
}
{
ASSERT_NO_THROW(emd2 = EMD(w2, w1, dist, noArray(), nullptr, flow));
const float emd0 = calcEMD(w2, w1, flow, dist, dims);
EXPECT_NEAR(emd0, emd2, eps);
}
EXPECT_NEAR(emd1, emd2, eps);
}
}
INSTANTIATE_TEST_CASE_P(, Imgproc_EMD_dist, testing::Values(DIST_L1, DIST_L2, DIST_C));
TEST(Imgproc_EMD, invalid)
{
Matx<float, 4, 2> w1 {50, 1, 60, 2, 50, 3, 50, 4};
Matx<float, 5, 2> w2 {30, 1, 20, 2, 70, 3, 30, 4, 60, 5};
// empty signature
{
Mat empty;
EXPECT_THROW(EMD(empty, w2, DIST_USER), cv::Exception);
EXPECT_THROW(EMD(w1, empty, DIST_USER), cv::Exception);
}
// zero total weight, negative weight
{
Matx<float, 3, 1> wz {0, 0, 0};
Matx<float, 3, 2> wz1 {0, 1, 0, 2, 0, 3};
Matx<float, 3, 1> wn {0, 3, -2};
Matx<float, 3, 2> wn1 {0, 1, 3, 2, -2, 3};
EXPECT_THROW(EMD(wz, w2, DIST_USER), cv::Exception);
EXPECT_THROW(EMD(wz1, w2, DIST_USER), cv::Exception);
EXPECT_THROW(EMD(wn, w2, DIST_USER), cv::Exception);
EXPECT_THROW(EMD(wn1, w2, DIST_USER), cv::Exception);
}
// user distance type, but no cost matrix provided or is wrong
{
Mat cost(3, 3, CV_32FC1, Scalar::all(0)), cost8u(4, 5, CV_8UC1, Scalar::all(0)), empty;
EXPECT_THROW(EMD(w1, w2, DIST_USER, noArray()), cv::Exception);
EXPECT_THROW(EMD(w1, w2, DIST_USER, empty), cv::Exception);
EXPECT_THROW(EMD(w1, w2, DIST_USER, cost8u), cv::Exception);
EXPECT_THROW(EMD(w1, w2, DIST_USER, cost), cv::Exception);
}
// lower_bound is set together with cost
{
Mat cost(4, 5, CV_32FC1, Scalar::all(0));
float bound = 0.f;
EXPECT_THROW(EMD(w1, w2, DIST_USER, cost, &bound), cv::Exception);
}
// zero dimensions with non-user distance type
const vector<DistanceTypes> good_types {DIST_L1, DIST_L2, DIST_C};
for (const auto& dt : good_types)
{
SCOPED_TRACE(cv::format("dt=%d", dt));
Matx<float, 4, 1> w01 {20, 30, 40, 50};
Matx<float, 5, 1> w02 {20, 30, 40, 50, 10};
EXPECT_THROW(EMD(w01, w02, dt), cv::Exception);
}
// wrong distance type
const vector<DistanceTypes> bad_types {DIST_L12, DIST_FAIR, DIST_WELSCH, DIST_HUBER};
for (const auto& dt : bad_types)
{
SCOPED_TRACE(cv::format("dt=%d", dt));
EXPECT_THROW(EMD(w1, w2, dt), cv::Exception);
}
}
}} // namespace opencv_test
File diff suppressed because it is too large Load Diff
+61
View File
@@ -0,0 +1,61 @@
/*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(Imgproc_FloodFill, maskValue)
{
const int n = 50;
Mat img = Mat::zeros(n, n, CV_8U);
Mat mask;
circle(img, Point(n/2, n/2), 20, Scalar(100), 4);
int flags = 4 + FLOODFILL_MASK_ONLY;
floodFill(img, mask, Point(n/2 + 13, n/2), Scalar(100), NULL, Scalar(), Scalar(), flags);
ASSERT_EQ(1, cvtest::norm(mask.rowRange(1, n-1).colRange(1, n-1), NORM_INF));
}
}} // namespace
/* End of file. */
+178
View File
@@ -0,0 +1,178 @@
/*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 {
class CV_GrabcutTest : public cvtest::BaseTest
{
public:
CV_GrabcutTest();
~CV_GrabcutTest();
protected:
bool verify(const Mat& mask, const Mat& exp);
void run(int);
};
CV_GrabcutTest::CV_GrabcutTest() {}
CV_GrabcutTest::~CV_GrabcutTest() {}
bool CV_GrabcutTest::verify(const Mat& mask, const Mat& exp)
{
const float maxDiffRatio = 0.005f;
int expArea = countNonZero( exp );
int nonIntersectArea = countNonZero( mask != exp );
float curRatio = (float)nonIntersectArea / (float)expArea;
ts->printf( cvtest::TS::LOG, "nonIntersectArea/expArea = %f\n", curRatio );
return curRatio < maxDiffRatio;
}
void CV_GrabcutTest::run( int /* start_from */)
{
cvtest::DefaultRngAuto defRng;
Mat img = imread(string(ts->get_data_path()) + "shared/airplane.png");
Mat mask_prob = imread(string(ts->get_data_path()) + "grabcut/mask_prob.png", 0);
Mat exp_mask1 = imread(string(ts->get_data_path()) + "grabcut/exp_mask1.png", 0);
Mat exp_mask2 = imread(string(ts->get_data_path()) + "grabcut/exp_mask2.png", 0);
if (img.empty() || (!mask_prob.empty() && img.size() != mask_prob.size()) ||
(!exp_mask1.empty() && img.size() != exp_mask1.size()) ||
(!exp_mask2.empty() && img.size() != exp_mask2.size()) )
{
ts->set_failed_test_info(cvtest::TS::FAIL_MISSING_TEST_DATA);
return;
}
Rect rect(Point(24, 126), Point(483, 294));
Mat exp_bgdModel, exp_fgdModel;
Mat mask;
Mat bgdModel, fgdModel;
grabCut( img, mask, rect, bgdModel, fgdModel, 0, GC_INIT_WITH_RECT );
bgdModel.copyTo(exp_bgdModel);
fgdModel.copyTo(exp_fgdModel);
grabCut( img, mask, rect, bgdModel, fgdModel, 2, GC_EVAL_FREEZE_MODEL );
// Multiply images by 255 for more visuality of test data.
if( mask_prob.empty() )
{
mask.copyTo( mask_prob );
imwrite(string(ts->get_data_path()) + "grabcut/mask_prob.png", mask_prob);
}
if( exp_mask1.empty() )
{
exp_mask1 = (mask & 1) * 255;
imwrite(string(ts->get_data_path()) + "grabcut/exp_mask1.png", exp_mask1);
}
if (!verify((mask & 1) * 255, exp_mask1))
{
ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
return;
}
// The model should not be changed after calling with GC_EVAL_FREEZE_MODEL
double sumBgdModel = cv::sum(cv::abs(bgdModel) - cv::abs(exp_bgdModel))[0];
double sumFgdModel = cv::sum(cv::abs(fgdModel) - cv::abs(exp_fgdModel))[0];
if (sumBgdModel >= 0.1 || sumFgdModel >= 0.1)
{
ts->printf(cvtest::TS::LOG, "sumBgdModel = %f, sumFgdModel = %f\n", sumBgdModel, sumFgdModel);
ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
return;
}
mask = mask_prob;
bgdModel.release();
fgdModel.release();
rect = Rect();
grabCut( img, mask, rect, bgdModel, fgdModel, 0, GC_INIT_WITH_MASK );
grabCut( img, mask, rect, bgdModel, fgdModel, 1, GC_EVAL );
if( exp_mask2.empty() )
{
exp_mask2 = (mask & 1) * 255;
imwrite(string(ts->get_data_path()) + "grabcut/exp_mask2.png", exp_mask2);
}
if (!verify((mask & 1) * 255, exp_mask2))
{
ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
return;
}
ts->set_failed_test_info(cvtest::TS::OK);
}
TEST(Imgproc_GrabCut, regression) { CV_GrabcutTest test; test.safe_run(); }
TEST(Imgproc_GrabCut, repeatability)
{
cvtest::TS& ts = *cvtest::TS::ptr();
Mat image_1 = imread(string(ts.get_data_path()) + "grabcut/image1652.ppm", IMREAD_COLOR);
Mat mask_1 = imread(string(ts.get_data_path()) + "grabcut/mask1652.ppm", IMREAD_GRAYSCALE);
Rect roi_1(0, 0, 150, 150);
Mat image_2 = image_1.clone();
Mat mask_2 = mask_1.clone();
Rect roi_2 = roi_1;
Mat image_3 = image_1.clone();
Mat mask_3 = mask_1.clone();
Rect roi_3 = roi_1;
Mat bgdModel_1, fgdModel_1;
Mat bgdModel_2, fgdModel_2;
Mat bgdModel_3, fgdModel_3;
theRNG().state = 12378213;
grabCut(image_1, mask_1, roi_1, bgdModel_1, fgdModel_1, 1, GC_INIT_WITH_MASK);
theRNG().state = 12378213;
grabCut(image_2, mask_2, roi_2, bgdModel_2, fgdModel_2, 1, GC_INIT_WITH_MASK);
theRNG().state = 12378213;
grabCut(image_3, mask_3, roi_3, bgdModel_3, fgdModel_3, 1, GC_INIT_WITH_MASK);
EXPECT_EQ(0, countNonZero(mask_1 != mask_2));
EXPECT_EQ(0, countNonZero(mask_1 != mask_3));
EXPECT_EQ(0, countNonZero(mask_2 != mask_3));
}
}} // namespace
+230
View File
@@ -0,0 +1,230 @@
/*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(Imgproc_Hist_Calc, calcHist_regression_11544)
{
cv::Mat1w m = cv::Mat1w::zeros(10, 10);
int n_images = 1;
int channels[] = { 0 };
cv::Mat mask;
cv::MatND hist1, hist2;
cv::MatND hist1_opt, hist2_opt;
int dims = 1;
int hist_size[] = { 1000 };
float range1[] = { 0, 900 };
float range2[] = { 0, 1000 };
const float* ranges1[] = { range1 };
const float* ranges2[] = { range2 };
setUseOptimized(false);
cv::calcHist(&m, n_images, channels, mask, hist1, dims, hist_size, ranges1);
cv::calcHist(&m, n_images, channels, mask, hist2, dims, hist_size, ranges2);
setUseOptimized(true);
cv::calcHist(&m, n_images, channels, mask, hist1_opt, dims, hist_size, ranges1);
cv::calcHist(&m, n_images, channels, mask, hist2_opt, dims, hist_size, ranges2);
for(int i = 0; i < 1000; i++)
{
EXPECT_EQ(hist1.at<float>(i), hist1_opt.at<float>(i)) << i;
EXPECT_EQ(hist2.at<float>(i), hist2_opt.at<float>(i)) << i;
}
}
TEST(Imgproc_Hist_Calc, badarg)
{
const int channels[] = {0};
float range1[] = {0, 10};
float range2[] = {10, 20};
const float * ranges[] = {range1, range2};
Mat img = cv::Mat::zeros(10, 10, CV_8UC1);
Mat imgInt = cv::Mat::zeros(10, 10, CV_32SC1);
Mat hist;
const int hist_size[] = { 100, 100 };
// base run
EXPECT_NO_THROW(cv::calcHist(&img, 1, channels, noArray(), hist, 1, hist_size, ranges, true));
// bad parameters
EXPECT_THROW(cv::calcHist(NULL, 1, channels, noArray(), hist, 1, hist_size, ranges, true), cv::Exception);
EXPECT_THROW(cv::calcHist(&img, 0, channels, noArray(), hist, 1, hist_size, ranges, true), cv::Exception);
EXPECT_THROW(cv::calcHist(&img, 1, NULL, noArray(), hist, 2, hist_size, ranges, true), cv::Exception);
EXPECT_THROW(cv::calcHist(&img, 1, channels, noArray(), noArray(), 1, hist_size, ranges, true), cv::Exception);
EXPECT_THROW(cv::calcHist(&img, 1, channels, noArray(), hist, -1, hist_size, ranges, true), cv::Exception);
EXPECT_THROW(cv::calcHist(&img, 1, channels, noArray(), hist, 1, NULL, ranges, true), cv::Exception);
EXPECT_THROW(cv::calcHist(&imgInt, 1, channels, noArray(), hist, 1, hist_size, NULL, true), cv::Exception);
// special case
EXPECT_NO_THROW(cv::calcHist(&img, 1, channels, noArray(), hist, 1, hist_size, NULL, true));
Mat backProj;
// base run
EXPECT_NO_THROW(cv::calcBackProject(&img, 1, channels, hist, backProj, ranges, 1, true));
// bad parameters
EXPECT_THROW(cv::calcBackProject(NULL, 1, channels, hist, backProj, ranges, 1, true), cv::Exception);
EXPECT_THROW(cv::calcBackProject(&img, 0, channels, hist, backProj, ranges, 1, true), cv::Exception);
EXPECT_THROW(cv::calcBackProject(&img, 1, channels, noArray(), backProj, ranges, 1, true), cv::Exception);
EXPECT_THROW(cv::calcBackProject(&img, 1, channels, hist, noArray(), ranges, 1, true), cv::Exception);
EXPECT_THROW(cv::calcBackProject(&imgInt, 1, channels, hist, backProj, NULL, 1, true), cv::Exception);
// special case
EXPECT_NO_THROW(cv::calcBackProject(&img, 1, channels, hist, backProj, NULL, 1, true));
}
TEST(Imgproc_Hist_Calc, IPP_ranges_with_equal_exponent_21595)
{
const int channels[] = { 0 };
float range1[] = { -0.5f, 1.5f };
const float* ranges[] = { range1 };
const int hist_size[] = { 2 };
uint8_t m[1][6] = { { 0, 1, 0, 1 , 1, 1 } };
cv::Mat images_u = Mat(1, 6, CV_8UC1, m);
cv::Mat histogram_u;
cv::calcHist(&images_u, 1, channels, noArray(), histogram_u, 1, hist_size, ranges);
ASSERT_EQ(histogram_u.at<float>(0), 2.f) << "0 not counts correctly, res: " << histogram_u.at<float>(0);
ASSERT_EQ(histogram_u.at<float>(1), 4.f) << "1 not counts correctly, res: " << histogram_u.at<float>(0);
}
TEST(Imgproc_Hist_Calc, IPP_ranges_with_nonequal_exponent_21595)
{
const int channels[] = { 0 };
float range1[] = { -1.3f, 1.5f };
const float* ranges[] = { range1 };
const int hist_size[] = { 3 };
uint8_t m[1][6] = { { 0, 1, 0, 1 , 1, 1 } };
cv::Mat images_u = Mat(1, 6, CV_8UC1, m);
cv::Mat histogram_u;
cv::calcHist(&images_u, 1, channels, noArray(), histogram_u, 1, hist_size, ranges);
ASSERT_EQ(histogram_u.at<float>(0), 0.f) << "not equal to zero, res: " << histogram_u.at<float>(0);
ASSERT_EQ(histogram_u.at<float>(1), 2.f) << "0 not counts correctly, res: " << histogram_u.at<float>(1);
ASSERT_EQ(histogram_u.at<float>(2), 4.f) << "1 not counts correctly, res: " << histogram_u.at<float>(2);
}
////////////////////////////////////////// equalizeHist() /////////////////////////////////////////
void equalizeHistReference(const Mat& src, Mat& dst)
{
std::vector<int> hist(256, 0);
for (int y = 0; y < src.rows; y++)
{
const uchar* srow = src.ptr(y);
for (int x = 0; x < src.cols; x++)
{
hist[srow[x]]++;
}
}
int first = 0;
while (!hist[first]) ++first;
int total = (int)src.total();
if (hist[first] == total)
{
dst.setTo(first);
return;
}
std::vector<uchar> lut(256);
lut[first] = 0;
float scale = (255.f)/(total - hist[first]);
int sum = 0;
for (int i = first + 1; i < 256; ++i)
{
sum += hist[i];
lut[i] = saturate_cast<uchar>(sum * scale);
}
cv::LUT(src, lut, dst);
}
typedef ::testing::TestWithParam<std::tuple<cv::Size, int>> Imgproc_Equalize_Hist;
TEST_P(Imgproc_Equalize_Hist, accuracy)
{
auto p = GetParam();
cv::Size size = std::get<0>(p);
int idx = std::get<1>(p);
RNG &rng = cvtest::TS::ptr()->get_rng();
rng.state += idx;
cv::Mat src(size, CV_8U);
cvtest::randUni(rng, src, Scalar::all(0), Scalar::all(255));
cv::Mat dst, gold;
equalizeHistReference(src, gold);
cv::equalizeHist(src, dst);
ASSERT_EQ(CV_8UC1, dst.type());
ASSERT_EQ(gold.size(), dst.size());
EXPECT_MAT_NEAR(dst, gold, 1);
EXPECT_MAT_N_DIFF(dst, gold, 0.05 * size.area()); // The 5% range could be accomodated to HAL
}
INSTANTIATE_TEST_CASE_P(Imgproc_Hist, Imgproc_Equalize_Hist, ::testing::Combine(
::testing::Values(cv::Size(123, 321), cv::Size(256, 256), cv::Size(1024, 768)),
::testing::Range(0, 10)));
// See https://github.com/opencv/opencv/issues/24757
TEST(Imgproc_Hist_Compare, intersect_regression_24757)
{
cv::Mat src1 = cv::Mat::zeros(128,1, CV_32FC1);
cv::Mat src2 = cv::Mat(128,1, CV_32FC1, cv::Scalar(std::numeric_limits<double>::max()));
// Ideal result Wrong result
src1.at<float>(32 * 0,0) = +1.0f; // work = +1.0 +1.0
src1.at<float>(32 * 1,0) = +55555555.5f; // work = +55555556.5 +55555555.5
src1.at<float>(32 * 2,0) = -55555555.5f; // work = +1.0 0.0
src1.at<float>(32 * 3,0) = -1.0f; // work = 0.0 -1.0
EXPECT_DOUBLE_EQ(compareHist(src1, src2, cv::HISTCMP_INTERSECT), 0.0);
}
}} // namespace
/* End Of File */
+321
View File
@@ -0,0 +1,321 @@
/*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.
// Copyright (C) 2014, Itseez, 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 {
#ifndef DEBUG_IMAGES
#define DEBUG_IMAGES 0
#endif
//#define GENERATE_DATA // generate data in debug mode via CPU code path (without IPP / OpenCL and other accelerators)
using namespace cv;
using namespace std;
static string getTestCaseName(const string& picture_name, double minDist, double edgeThreshold, double accumThreshold, int minRadius, int maxRadius)
{
string results_name = cv::format("circles_%s_%.0f_%.0f_%.0f_%d_%d",
picture_name.c_str(), minDist, edgeThreshold, accumThreshold, minRadius, maxRadius);
string temp(results_name);
size_t pos = temp.find_first_of("\\/.");
while (pos != string::npos) {
temp.replace(pos, 1, "_");
pos = temp.find_first_of("\\/.");
}
return temp;
}
#if DEBUG_IMAGES
static void highlightCircles(const string& imagePath, const vector<Vec3f>& circles, const string& outputImagePath)
{
Mat imgDebug = imread(imagePath, IMREAD_COLOR);
const Scalar yellow(0, 255, 255);
for (vector<Vec3f>::const_iterator iter = circles.begin(); iter != circles.end(); ++iter)
{
const Vec3f& circle = *iter;
float x = circle[0];
float y = circle[1];
float r = max(circle[2], 2.0f);
cv::circle(imgDebug, Point(int(x), int(y)), int(r), yellow);
}
imwrite(outputImagePath, imgDebug);
}
#endif
typedef tuple<string, double, double, double, int, int> Image_MinDist_EdgeThreshold_AccumThreshold_MinRadius_MaxRadius_t;
class HoughCirclesTestFixture : public testing::TestWithParam<Image_MinDist_EdgeThreshold_AccumThreshold_MinRadius_MaxRadius_t>
{
string picture_name;
double minDist;
double edgeThreshold;
double accumThreshold;
int minRadius;
int maxRadius;
public:
HoughCirclesTestFixture()
{
picture_name = get<0>(GetParam());
minDist = get<1>(GetParam());
edgeThreshold = get<2>(GetParam());
accumThreshold = get<3>(GetParam());
minRadius = get<4>(GetParam());
maxRadius = get<5>(GetParam());
}
HoughCirclesTestFixture(const string& picture, double minD, double edge, double accum, int minR, int maxR) :
picture_name(picture), minDist(minD), edgeThreshold(edge), accumThreshold(accum), minRadius(minR), maxRadius(maxR)
{
}
template <typename CircleType>
void run_test(const char* xml_name)
{
string test_case_name = getTestCaseName(picture_name, minDist, edgeThreshold, accumThreshold, minRadius, maxRadius);
string filename = cvtest::TS::ptr()->get_data_path() + picture_name;
Mat src = imread(filename, IMREAD_GRAYSCALE);
EXPECT_FALSE(src.empty()) << "Invalid test image: " << filename;
GaussianBlur(src, src, Size(9, 9), 2, 2);
vector<CircleType> circles;
const double dp = 1.0;
HoughCircles(src, circles, cv::HOUGH_GRADIENT, dp, minDist, edgeThreshold, accumThreshold, minRadius, maxRadius);
string imgProc = string(cvtest::TS::ptr()->get_data_path()) + "imgproc/";
#if DEBUG_IMAGES
highlightCircles(filename, circles, imgProc + test_case_name + ".png");
#endif
string xml = imgProc + xml_name;
#ifdef GENERATE_DATA
{
FileStorage fs(xml, FileStorage::READ);
ASSERT_TRUE(!fs.isOpened() || fs[test_case_name].empty());
}
{
FileStorage fs(xml, FileStorage::APPEND);
EXPECT_TRUE(fs.isOpened()) << "Cannot open sanity data file: " << xml;
fs << test_case_name << circles;
}
#else
FileStorage fs(xml, FileStorage::READ);
FileNode node = fs[test_case_name];
ASSERT_FALSE(node.empty()) << "Missing test data: " << test_case_name << std::endl << "XML: " << xml;
vector<CircleType> exp_circles;
read(fs[test_case_name], exp_circles, vector<CircleType>());
fs.release();
EXPECT_EQ(exp_circles.size(), circles.size());
#endif
}
};
TEST_P(HoughCirclesTestFixture, regression)
{
run_test<Vec3f>("HoughCircles.xml");
}
TEST_P(HoughCirclesTestFixture, regression4f)
{
run_test<Vec4f>("HoughCircles4f.xml");
}
INSTANTIATE_TEST_CASE_P(ImgProc, HoughCirclesTestFixture, testing::Combine(
// picture_name:
testing::Values("imgproc/stuff.jpg"),
// minDist:
testing::Values(20),
// edgeThreshold:
testing::Values(20),
// accumThreshold:
testing::Values(30),
// minRadius:
testing::Values(20),
// maxRadius:
testing::Values(200)
));
class HoughCirclesTest : public testing::TestWithParam<HoughModes>
{
protected:
HoughModes method;
public:
HoughCirclesTest() { method = GetParam(); }
};
TEST_P(HoughCirclesTest, DefaultMaxRadius)
{
string picture_name = "imgproc/stuff.jpg";
string filename = cvtest::TS::ptr()->get_data_path() + picture_name;
Mat src = imread(filename, IMREAD_GRAYSCALE);
EXPECT_FALSE(src.empty()) << "Invalid test image: " << filename;
GaussianBlur(src, src, Size(9, 9), 2, 2);
double dp = 1.0;
double minDist = 20.0;
double edgeThreshold = 20.0;
double param2 = method == HOUGH_GRADIENT_ALT ? 0.9 : 30.;
int minRadius = method == HOUGH_GRADIENT_ALT ? 10 : 20;
int maxRadius = 0;
vector<Vec3f> circles;
vector<Vec4f> circles4f;
HoughCircles(src, circles, method, dp, minDist, edgeThreshold, param2, minRadius, maxRadius);
HoughCircles(src, circles4f, method, dp, minDist, edgeThreshold, param2, minRadius, maxRadius);
#if DEBUG_IMAGES
string imgProc = string(cvtest::TS::ptr()->get_data_path()) + "imgproc/";
highlightCircles(filename, circles, imgProc + "HoughCirclesTest_DefaultMaxRadius.png");
#endif
int maxDimension = std::max(src.rows, src.cols);
if(method == HOUGH_GRADIENT_ALT)
{
EXPECT_EQ(circles.size(), size_t(3)) << "Should find 3 circles";
}
else
{
EXPECT_GT(circles.size(), size_t(0)) << "Should find at least some circles";
}
for (size_t i = 0; i < circles.size(); ++i)
{
EXPECT_GE(circles[i][2], minRadius) << "Radius should be >= minRadius";
EXPECT_LE(circles[i][2], maxDimension) << "Radius should be <= max image dimension";
}
}
TEST_P(HoughCirclesTest, CentersOnly)
{
string picture_name = "imgproc/stuff.jpg";
string filename = cvtest::TS::ptr()->get_data_path() + picture_name;
Mat src = imread(filename, IMREAD_GRAYSCALE);
EXPECT_FALSE(src.empty()) << "Invalid test image: " << filename;
GaussianBlur(src, src, Size(9, 9), 2, 2);
double dp = 1.0;
double minDist = 20.0;
double edgeThreshold = 20.0;
double param2 = method == HOUGH_GRADIENT_ALT ? 0.9 : 30.;
int minRadius = method == HOUGH_GRADIENT_ALT ? 10 : 20;
int maxRadius = -1;
vector<Vec3f> circles;
vector<Vec4f> circles4f;
HoughCircles(src, circles, method, dp, minDist, edgeThreshold, param2, minRadius, maxRadius);
HoughCircles(src, circles4f, method, dp, minDist, edgeThreshold, param2, minRadius, maxRadius);
#if DEBUG_IMAGES
string imgProc = string(cvtest::TS::ptr()->get_data_path()) + "imgproc/";
highlightCircles(filename, circles, imgProc + "HoughCirclesTest_DefaultMaxRadius.png");
#endif
if(method == HOUGH_GRADIENT_ALT)
{
EXPECT_EQ(circles.size(), size_t(3)) << "Should find 3 circles";
}
else
{
EXPECT_GT(circles.size(), size_t(0)) << "Should find at least some circles";
}
for (size_t i = 0; i < circles.size(); ++i)
{
if( method == HOUGH_GRADIENT )
{
EXPECT_EQ(circles[i][2], 0.0f) << "Did not ask for radius";
}
EXPECT_EQ(circles[i][0], circles4f[i][0]);
EXPECT_EQ(circles[i][1], circles4f[i][1]);
EXPECT_EQ(circles[i][2], circles4f[i][2]);
}
}
TEST_P(HoughCirclesTest, ManySmallCircles)
{
string picture_name = "imgproc/beads.jpg";
string filename = cvtest::TS::ptr()->get_data_path() + picture_name;
Mat src = imread(filename, IMREAD_GRAYSCALE);
EXPECT_FALSE(src.empty()) << "Invalid test image: " << filename;
const double dp = method == HOUGH_GRADIENT_ALT ? 1.5 : 1.0;
double minDist = 10;
double edgeThreshold = 90;
double accumThreshold = 11;
double minCos2 = 0.85;
double param2 = method == HOUGH_GRADIENT_ALT ? minCos2 : accumThreshold;
int minRadius = 7;
int maxRadius = 18;
int ncircles_min = method == HOUGH_GRADIENT_ALT ? 2000 : 3000;
Mat src_smooth;
if( method == HOUGH_GRADIENT_ALT )
GaussianBlur(src, src_smooth, Size(7, 7), 1.5, 1.5);
else
src.copyTo(src_smooth);
vector<Vec3f> circles;
vector<Vec4f> circles4f;
HoughCircles(src_smooth, circles, method, dp, minDist, edgeThreshold, param2, minRadius, maxRadius);
HoughCircles(src_smooth, circles4f, method, dp, minDist, edgeThreshold, param2, minRadius, maxRadius);
#if DEBUG_IMAGES
string imgProc = string(cvtest::TS::ptr()->get_data_path()) + "imgproc/";
string test_case_name = getTestCaseName(picture_name, minDist, edgeThreshold, accumThreshold, minRadius, maxRadius);
highlightCircles(filename, circles, imgProc + test_case_name + ".png");
#endif
EXPECT_GT(circles.size(), size_t(ncircles_min)) << "Should find a lot of circles";
EXPECT_EQ(circles.size(), circles4f.size());
}
INSTANTIATE_TEST_CASE_P(HoughGradient, HoughCirclesTest, testing::Values(HOUGH_GRADIENT));
INSTANTIATE_TEST_CASE_P(HoughGradientAlt, HoughCirclesTest, testing::Values(HOUGH_GRADIENT_ALT));
}} // namespace
+473
View File
@@ -0,0 +1,473 @@
/*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.
// Copyright (C) 2014, Itseez, 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 GENERATE_DATA // generate data in debug mode via CPU code path (without IPP / OpenCL and other accelerators)
namespace opencv_test { namespace {
template<typename T>
struct SimilarWith
{
T value;
float theta_eps;
float rho_eps;
SimilarWith(T val, float e, float r_e): value(val), theta_eps(e), rho_eps(r_e) { }
bool operator()(const T& other);
};
template<>
bool SimilarWith<Vec2f>::operator()(const Vec2f& other)
{
return std::abs(other[0] - value[0]) < rho_eps && std::abs(other[1] - value[1]) < theta_eps;
}
template<>
bool SimilarWith<Vec3f>::operator()(const Vec3f& other)
{
return std::abs(other[0] - value[0]) < rho_eps && std::abs(other[1] - value[1]) < theta_eps;
}
template<>
bool SimilarWith<Vec4i>::operator()(const Vec4i& other)
{
return cv::norm(value, other) < theta_eps;
}
template <typename T>
int countMatIntersection(const Mat& expect, const Mat& actual, float eps, float rho_eps)
{
int count = 0;
if (!expect.empty() && !actual.empty())
{
for (MatConstIterator_<T> it=expect.begin<T>(); it!=expect.end<T>(); it++)
{
MatConstIterator_<T> f = std::find_if(actual.begin<T>(), actual.end<T>(), SimilarWith<T>(*it, eps, rho_eps));
if (f != actual.end<T>())
count++;
}
}
return count;
}
String getTestCaseName(String filename)
{
string temp(filename);
size_t pos = temp.find_first_of("\\/.");
while ( pos != string::npos ) {
temp.replace( pos, 1, "_" );
pos = temp.find_first_of("\\/.");
}
return String(temp);
}
class BaseHoughLineTest
{
public:
enum {STANDART = 0, PROBABILISTIC};
protected:
template<typename LinesType, typename LineType>
void run_test(int type, const char* xml_name);
string picture_name;
double rhoStep;
double thetaStep;
int threshold;
int minLineLength;
int maxGap;
};
typedef tuple<string, double, double, int> Image_RhoStep_ThetaStep_Threshold_t;
class StandartHoughLinesTest : public BaseHoughLineTest, public testing::TestWithParam<Image_RhoStep_ThetaStep_Threshold_t>
{
public:
StandartHoughLinesTest()
{
picture_name = get<0>(GetParam());
rhoStep = get<1>(GetParam());
thetaStep = get<2>(GetParam());
threshold = get<3>(GetParam());
minLineLength = 0;
maxGap = 0;
}
};
typedef tuple<string, double, double, int, int, int> Image_RhoStep_ThetaStep_Threshold_MinLine_MaxGap_t;
class ProbabilisticHoughLinesTest : public BaseHoughLineTest, public testing::TestWithParam<Image_RhoStep_ThetaStep_Threshold_MinLine_MaxGap_t>
{
public:
ProbabilisticHoughLinesTest()
{
picture_name = get<0>(GetParam());
rhoStep = get<1>(GetParam());
thetaStep = get<2>(GetParam());
threshold = get<3>(GetParam());
minLineLength = get<4>(GetParam());
maxGap = get<5>(GetParam());
}
};
typedef tuple<double, double, double, double> HoughLinesPointSetInput_t;
class HoughLinesPointSetTest : public testing::TestWithParam<HoughLinesPointSetInput_t>
{
protected:
void run_test();
double Rho;
double Theta;
double rhoMin, rhoMax, rhoStep;
double thetaMin, thetaMax, thetaStep;
public:
HoughLinesPointSetTest()
{
rhoMin = get<0>(GetParam());
rhoMax = get<1>(GetParam());
rhoStep = (rhoMax - rhoMin) / 360.0f;
thetaMin = get<2>(GetParam());
thetaMax = get<3>(GetParam());
thetaStep = CV_PI / 180.0f;
Rho = 320.00000;
Theta = 1.04719;
}
};
template<typename LinesType, typename LineType>
void BaseHoughLineTest::run_test(int type, const char* xml_name)
{
string filename = cvtest::TS::ptr()->get_data_path() + picture_name;
Mat src = imread(filename, IMREAD_GRAYSCALE);
ASSERT_FALSE(src.empty()) << "Invalid test image: " << filename;
string xml = string(cvtest::TS::ptr()->get_data_path()) + "imgproc/" + xml_name;
Mat dst;
Canny(src, dst, 100, 150, 3);
ASSERT_FALSE(dst.empty()) << "Failed Canny edge detector";
LinesType lines;
if (type == STANDART)
HoughLines(dst, lines, rhoStep, thetaStep, threshold, 0, 0);
else if (type == PROBABILISTIC)
HoughLinesP(dst, lines, rhoStep, thetaStep, threshold, minLineLength, maxGap);
String test_case_name = format("lines_%s_%.0f_%.2f_%d_%d_%d", picture_name.c_str(), rhoStep, thetaStep,
threshold, minLineLength, maxGap);
test_case_name = getTestCaseName(test_case_name);
#ifdef GENERATE_DATA
{
FileStorage fs(xml, FileStorage::READ);
ASSERT_TRUE(!fs.isOpened() || fs[test_case_name].empty());
}
{
FileStorage fs(xml, FileStorage::APPEND);
EXPECT_TRUE(fs.isOpened()) << "Cannot open sanity data file: " << xml;
fs << test_case_name << Mat(lines);
}
#else
FileStorage fs(xml, FileStorage::READ);
FileNode node = fs[test_case_name];
ASSERT_FALSE(node.empty()) << "Missing test data: " << test_case_name << std::endl << "XML: " << xml;
Mat exp_lines_;
read(fs[test_case_name], exp_lines_, Mat());
fs.release();
LinesType exp_lines;
exp_lines_.copyTo(exp_lines);
int count = -1;
if (type == STANDART)
count = countMatIntersection<LineType>(Mat(exp_lines), Mat(lines), (float) thetaStep + FLT_EPSILON, (float) rhoStep + FLT_EPSILON);
else if (type == PROBABILISTIC)
count = countMatIntersection<LineType>(Mat(exp_lines), Mat(lines), 1e-4f, 0.f);
#if defined HAVE_IPP && IPP_VERSION_X100 >= 810 && !IPP_DISABLE_HOUGH
EXPECT_LE(std::abs((double)count - Mat(exp_lines).total()), Mat(exp_lines).total() * 0.25)
<< "count=" << count << " expected=" << Mat(exp_lines).total();
#else
EXPECT_EQ(count, (int)Mat(exp_lines).total());
#endif
#endif // GENERATE_DATA
}
void HoughLinesPointSetTest::run_test(void)
{
Mat lines_f, lines_i;
vector<Point2f> pointf;
vector<Point2i> pointi;
vector<Vec3d> line_polar_f, line_polar_i;
const float Points[20][2] = {
{ 0.0f, 369.0f }, { 10.0f, 364.0f }, { 20.0f, 358.0f }, { 30.0f, 352.0f },
{ 40.0f, 346.0f }, { 50.0f, 341.0f }, { 60.0f, 335.0f }, { 70.0f, 329.0f },
{ 80.0f, 323.0f }, { 90.0f, 318.0f }, { 100.0f, 312.0f }, { 110.0f, 306.0f },
{ 120.0f, 300.0f }, { 130.0f, 295.0f }, { 140.0f, 289.0f }, { 150.0f, 284.0f },
{ 160.0f, 277.0f }, { 170.0f, 271.0f }, { 180.0f, 266.0f }, { 190.0f, 260.0f }
};
// Float
for (int i = 0; i < 20; i++)
{
pointf.push_back(Point2f(Points[i][0],Points[i][1]));
}
HoughLinesPointSet(pointf, lines_f, 20, 1,
rhoMin, rhoMax, rhoStep,
thetaMin, thetaMax, thetaStep);
lines_f.copyTo( line_polar_f );
// Integer
for( int i = 0; i < 20; i++ )
{
pointi.push_back( Point2i( (int)Points[i][0], (int)Points[i][1] ) );
}
HoughLinesPointSet( pointi, lines_i, 20, 1,
rhoMin, rhoMax, rhoStep,
thetaMin, thetaMax, thetaStep );
lines_i.copyTo( line_polar_i );
EXPECT_EQ((int)(line_polar_f.at(0).val[1] * 100000.0f), (int)(Rho * 100000.0f));
EXPECT_EQ((int)(line_polar_f.at(0).val[2] * 100000.0f), (int)(Theta * 100000.0f));
EXPECT_EQ((int)(line_polar_i.at(0).val[1] * 100000.0f), (int)(Rho * 100000.0f));
EXPECT_EQ((int)(line_polar_i.at(0).val[2] * 100000.0f), (int)(Theta * 100000.0f));
}
TEST_P(StandartHoughLinesTest, regression)
{
run_test<Mat, Vec2f>(STANDART, "HoughLines.xml");
}
TEST_P(ProbabilisticHoughLinesTest, regression)
{
run_test<Mat, Vec4i>(PROBABILISTIC, "HoughLinesP.xml");
}
TEST_P(StandartHoughLinesTest, regression_Vec2f)
{
run_test<std::vector<Vec2f>, Vec2f>(STANDART, "HoughLines2f.xml");
}
TEST_P(StandartHoughLinesTest, regression_Vec3f)
{
run_test<std::vector<Vec3f>, Vec3f>(STANDART, "HoughLines3f.xml");
}
TEST_P(HoughLinesPointSetTest, regression)
{
run_test();
}
TEST(HoughLinesPointSet, regression_21029)
{
std::vector<Point2f> points;
points.push_back(Point2f(100, 100));
points.push_back(Point2f(1000, 1000));
points.push_back(Point2f(10000, 10000));
points.push_back(Point2f(100000, 100000));
double rhoMin = 0;
double rhoMax = 10;
double rhoStep = 0.1;
double thetaMin = 85 * CV_PI / 180.0;
double thetaMax = 95 * CV_PI / 180.0;
double thetaStep = 1 * CV_PI / 180.0;
int lines_max = 5;
int threshold = 100;
Mat lines;
HoughLinesPointSet(points, lines,
lines_max, threshold,
rhoMin, rhoMax, rhoStep,
thetaMin, thetaMax, thetaStep
);
EXPECT_TRUE(lines.empty());
}
TEST(HoughLines, regression_21983)
{
Mat img(200, 200, CV_8UC1, Scalar(0));
line(img, Point(0, 100), Point(100, 100), Scalar(255));
std::vector<Vec2f> lines;
HoughLines(img, lines, 1, CV_PI/180, 90, 0, 0, 0.001, 1.58);
ASSERT_EQ(lines.size(), 1U);
EXPECT_EQ(lines[0][0], 100);
EXPECT_NEAR(lines[0][1], 1.57179642, 1e-4);
}
TEST(HoughLines, regression_25038_vertical)
{
cv::Mat img = cv::Mat::zeros(8, 8, CV_8UC1);
img.col(3).setTo(255);
cv::Mat lines;
cv::HoughLines(img, lines, 0.5, CV_PI/4., 2);
EXPECT_EQ(1, lines.cols);
EXPECT_EQ(1, lines.rows);
EXPECT_EQ(2, lines.channels());
EXPECT_NEAR(3, lines.at<cv::Vec2f>(0)[0], 1e-5);
EXPECT_NEAR(0, lines.at<cv::Vec2f>(0)[1], 1e-5);
cv::HoughLines(img, lines, 0.05, CV_PI/4., 2);
EXPECT_EQ(1, lines.cols);
EXPECT_EQ(1, lines.rows);
EXPECT_EQ(2, lines.channels());
EXPECT_NEAR(3, lines.at<cv::Vec2f>(0)[0], 1e-5);
EXPECT_NEAR(0, lines.at<cv::Vec2f>(0)[1], 1e-5);
}
TEST(HoughLines, regression_25038_even)
{
cv::Mat img = cv::Mat::zeros(8, 8, CV_8UC1);
img.col(4).setTo(255);
cv::Mat lines;
cv::HoughLines(img, lines, 0.5, CV_PI/4., 2);
EXPECT_EQ(1, lines.cols);
EXPECT_EQ(1, lines.rows);
EXPECT_EQ(2, lines.channels());
EXPECT_NEAR(4, lines.at<cv::Vec2f>(0)[0], 1e-5);
EXPECT_NEAR(0, lines.at<cv::Vec2f>(0)[1], 1e-5);
cv::HoughLines(img, lines, 0.05, CV_PI/4., 2);
EXPECT_EQ(1, lines.cols);
EXPECT_EQ(1, lines.rows);
EXPECT_EQ(2, lines.channels());
EXPECT_NEAR(4, lines.at<cv::Vec2f>(0)[0], 1e-5);
EXPECT_NEAR(0, lines.at<cv::Vec2f>(0)[1], 1e-5);
}
TEST(HoughLines, regression_25038_horizontal)
{
cv::Mat img = cv::Mat::zeros(8, 8, CV_8UC1);
img.row(3).setTo(255);
cv::Mat lines;
cv::HoughLines(img, lines, 0.5, CV_PI/4., 2);
EXPECT_EQ(1, lines.cols);
EXPECT_EQ(1, lines.rows);
EXPECT_EQ(2, lines.channels());
EXPECT_NEAR(3, lines.at<cv::Vec2f>(0)[0], 1e-5);
EXPECT_NEAR(CV_PI/2., lines.at<cv::Vec2f>(0)[1], 1e-5);
cv::HoughLines(img, lines, 0.05, CV_PI/4., 2);
EXPECT_EQ(1, lines.cols);
EXPECT_EQ(1, lines.rows);
EXPECT_EQ(2, lines.channels());
EXPECT_NEAR(3, lines.at<cv::Vec2f>(0)[0], 1e-5);
EXPECT_NEAR(CV_PI/2., lines.at<cv::Vec2f>(0)[1], 1e-5);
}
TEST(WeightedHoughLines, horizontal)
{
Mat img(25, 25, CV_8UC1, Scalar(0));
// draw lines. from top to bottom, stronger to weaker.
line(img, Point(0, 6), Point(25, 6), Scalar(240));
line(img, Point(0, 12), Point(25, 12), Scalar(255));
line(img, Point(0, 18), Point(25, 18), Scalar(220));
// detect lines
std::vector<Vec2f> lines;
int threshold{220*25-1};
bool use_edgeval{true};
HoughLines(img, lines, 1, CV_PI/180, threshold, 0, 0, 0.0, CV_PI, use_edgeval);
// check results
ASSERT_EQ(3U, lines.size());
// detected lines is assumed sorted from stronger to weaker.
EXPECT_EQ(12, lines[0][0]);
EXPECT_EQ(6, lines[1][0]);
EXPECT_EQ(18, lines[2][0]);
EXPECT_NEAR(CV_PI/2, lines[0][1], CV_PI/180 + 1e-6);
EXPECT_NEAR(CV_PI/2, lines[1][1], CV_PI/180 + 1e-6);
EXPECT_NEAR(CV_PI/2, lines[2][1], CV_PI/180 + 1e-6);
}
TEST(WeightedHoughLines, diagonal)
{
Mat img(25, 25, CV_8UC1, Scalar(0));
// draw lines.
line(img, Point(0, 0), Point(25, 25), Scalar(128));
line(img, Point(0, 25), Point(25, 0), Scalar(255));
// detect lines
std::vector<Vec2f> lines;
int threshold{128*25-1};
bool use_edgeval{true};
HoughLines(img, lines, 1, CV_PI/180, threshold, 0, 0, 0.0, CV_PI, use_edgeval);
// check results
ASSERT_EQ(2U, lines.size());
// detected lines is assumed sorted from stronger to weaker.
EXPECT_EQ(18, lines[0][0]); // 25*sqrt(2)/2 = 17.67 ~ 18
EXPECT_EQ(0, lines[1][0]);
EXPECT_NEAR(CV_PI/4, lines[0][1], CV_PI/180 + 1e-6);
EXPECT_NEAR(CV_PI*3/4, lines[1][1], CV_PI/180 + 1e-6);
}
INSTANTIATE_TEST_CASE_P( ImgProc, StandartHoughLinesTest, testing::Combine(testing::Values( "shared/pic5.png", "../stitching/a1.png" ),
testing::Values( 1, 10 ),
testing::Values( 0.05, 0.1 ),
testing::Values( 80, 150 )
));
INSTANTIATE_TEST_CASE_P( ImgProc, ProbabilisticHoughLinesTest, testing::Combine(testing::Values( "shared/pic5.png", "shared/pic1.png" ),
testing::Values( 5, 10 ),
testing::Values( 0.05, 0.1 ),
testing::Values( 75, 150 ),
testing::Values( 0, 10 ),
testing::Values( 0, 4 )
));
INSTANTIATE_TEST_CASE_P( Imgproc, HoughLinesPointSetTest, testing::Combine(testing::Values( 0.0f, 120.0f ),
testing::Values( 360.0f, 480.0f ),
testing::Values( 0.0f, (CV_PI / 18.0f) ),
testing::Values( (CV_PI / 2.0f), (CV_PI * 5.0f / 12.0f) )
));
}} // namespace
@@ -0,0 +1,84 @@
/*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 {
class CV_ImgprocUMatTest : public cvtest::BaseTest
{
public:
CV_ImgprocUMatTest() {}
~CV_ImgprocUMatTest() {}
protected:
void run(int)
{
string imgpath = string(ts->get_data_path()) + "shared/lena.png";
Mat img = imread(imgpath, IMREAD_COLOR), gray, smallimg, result;
UMat uimg = img.getUMat(ACCESS_READ), ugray, usmallimg, uresult;
cvtColor(img, gray, COLOR_BGR2GRAY);
resize(gray, smallimg, Size(), 0.75, 0.75, INTER_LINEAR_EXACT);
equalizeHist(smallimg, result);
cvtColor(uimg, ugray, COLOR_BGR2GRAY);
resize(ugray, usmallimg, Size(), 0.75, 0.75, INTER_LINEAR_EXACT);
equalizeHist(usmallimg, uresult);
#if 0
imshow("orig", uimg);
imshow("small", usmallimg);
imshow("equalized gray", uresult);
waitKey();
destroyWindow("orig");
destroyWindow("small");
destroyWindow("equalized gray");
#endif
ts->set_failed_test_info(cvtest::TS::OK);
(void)uresult.getMat(ACCESS_READ);
}
};
TEST(Imgproc_UMat, regression) { CV_ImgprocUMatTest test; test.safe_run(); }
}} // namespace
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+117
View File
@@ -0,0 +1,117 @@
// 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 <vector>
namespace opencv_test { namespace {
Mat CropMid(InputArray src, int w, int h)
{
Mat mat = src.getMat();
return mat(Rect(mat.cols / 2 - w / 2, mat.rows / 2 - h / 2, w, h));
}
Mat GenerateTestImage(Size size)
{
Mat image = Mat::zeros(size.height * 2, size.width * 2, CV_32F);
rectangle(image,
Point(static_cast<int>(size.width * 0.1), static_cast<int>(size.height * 0.1)),
Point(static_cast<int>(size.width * 0.9), static_cast<int>(size.height * 0.9)),
Scalar(1),
-1);
return image;
}
void TestPhaseCorrelationIterative(const Size& size, const double maxShift)
{
const auto iters = std::max(201., maxShift * 10 + 1);
const Point2d shiftOffset(-maxShift * 0.5, -maxShift * 0.5);
Mat image1 = GenerateTestImage(size);
Mat crop1 = CropMid(image1, size.width, size.height);
Mat image2 = image1.clone();
std::vector<double> pcErrors;
std::vector<double> ipcErrors;
for (int i = 0; i < iters; ++i)
{
const auto shift =
Point2d(maxShift * i / (iters - 1), maxShift * i / (iters - 1)) + shiftOffset;
const Mat Tmat = (Mat_<double>(2, 3) << 1., 0., shift.x, 0., 1., shift.y);
warpAffine(image1, image2, Tmat, image2.size());
Mat crop2 = CropMid(image2, size.width, size.height);
const auto ipcshift = phaseCorrelateIterative(crop1, crop2);
const auto pcshift = phaseCorrelate(crop1, crop2);
pcErrors.push_back(
0.5 * std::abs(pcshift.x - shift.y) + 0.5 * std::abs(pcshift.y - shift.x));
ipcErrors.push_back(
0.5 * std::abs(ipcshift.x - shift.y) + 0.5 * std::abs(ipcshift.y - shift.x));
// error should be low
EXPECT_NEAR(ipcshift.x - shift.x, 0.0, 0.1);
EXPECT_NEAR(ipcshift.y - shift.y, 0.0, 0.1);
}
cv::Scalar pcMean, pcStddev, ipcMean, ipcStddev;
meanStdDev(ipcErrors, ipcMean, ipcStddev);
meanStdDev(pcErrors, pcMean, pcStddev);
// average error should be low
ASSERT_LT(ipcMean[0], 0.03);
// average error should be less than non-iterative average error
ASSERT_LT(ipcMean[0], pcMean[0]);
// error stddev should be less than non-iterative error stddev
ASSERT_LT(ipcStddev[0], pcStddev[0]);
}
TEST(Imgproc_PhaseCorrelationIterative, 256x128_accuracy)
{
TestPhaseCorrelationIterative(Size(256, 128), 1);
}
TEST(Imgproc_PhaseCorrelationIterative, 64x64_accuracy_shift_1)
{
TestPhaseCorrelationIterative(Size(64, 64), 1);
}
TEST(Imgproc_PhaseCorrelationIterative, 64x64_accuracy_shift_16)
{
TestPhaseCorrelationIterative(Size(64, 64), 16);
}
TEST(Imgproc_PhaseCorrelationIterative, 0x0_image)
{
ASSERT_ANY_THROW(TestPhaseCorrelationIterative(Size(0, 0), 1));
}
TEST(Imgproc_PhaseCorrelationIterative, 1x1_image)
{
ASSERT_ANY_THROW(TestPhaseCorrelationIterative(Size(1, 1), 1));
}
TEST(Imgproc_PhaseCorrelationIterative, accuracy_real_img)
{
Mat img = imread(cvtest::TS::ptr()->get_data_path() + "shared/airplane.png", IMREAD_GRAYSCALE);
if (img.empty())
return;
img.convertTo(img, CV_64FC1);
const int xLen = 256;
const int yLen = 256;
const int xShift = 40;
const int yShift = 14;
Mat roi1 = img(Rect(xShift, yShift, xLen, yLen));
Mat roi2 = img(Rect(0, 0, xLen, yLen));
const Point2d ipcShift = phaseCorrelateIterative(roi1, roi2);
ASSERT_NEAR(ipcShift.x, (double)xShift, 1.);
ASSERT_NEAR(ipcShift.y, (double)yShift, 1.);
}
}} // namespace opencv_test
+498
View File
@@ -0,0 +1,498 @@
// 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 {
const Size img_size(640, 480);
const int LSD_TEST_SEED = 0x134679;
const int EPOCHS = 20;
class LSDBase : public testing::Test
{
public:
LSDBase() { }
protected:
Mat test_image;
vector<Vec4f> lines;
RNG rng;
int passedtests;
void GenerateWhiteNoise(Mat& image);
void GenerateConstColor(Mat& image);
void GenerateLines(Mat& image, const unsigned int numLines);
void GenerateRotatedRect(Mat& image);
virtual void SetUp();
};
class Imgproc_LSD_ADV: public LSDBase
{
public:
Imgproc_LSD_ADV() { }
protected:
};
class Imgproc_LSD_STD: public LSDBase
{
public:
Imgproc_LSD_STD() { }
protected:
};
class Imgproc_LSD_NONE: public LSDBase
{
public:
Imgproc_LSD_NONE() { }
protected:
};
class Imgproc_LSD_Common : public LSDBase
{
public:
Imgproc_LSD_Common() { }
protected:
};
void LSDBase::GenerateWhiteNoise(Mat& image)
{
image = Mat(img_size, CV_8UC1);
rng.fill(image, RNG::UNIFORM, 0, 256);
}
void LSDBase::GenerateConstColor(Mat& image)
{
image = Mat(img_size, CV_8UC1, Scalar::all(rng.uniform(0, 256)));
}
void LSDBase::GenerateLines(Mat& image, const unsigned int numLines)
{
image = Mat(img_size, CV_8UC1, Scalar::all(rng.uniform(0, 128)));
for(unsigned int i = 0; i < numLines; ++i)
{
int y = rng.uniform(10, img_size.width - 10);
Point p1(y, 10);
Point p2(y, img_size.height - 10);
line(image, p1, p2, Scalar(255), 3);
}
}
void LSDBase::GenerateRotatedRect(Mat& image)
{
image = Mat::zeros(img_size, CV_8UC1);
Point center(rng.uniform(img_size.width/4, img_size.width*3/4),
rng.uniform(img_size.height/4, img_size.height*3/4));
Size rect_size(rng.uniform(img_size.width/8, img_size.width/6),
rng.uniform(img_size.height/8, img_size.height/6));
float angle = rng.uniform(0.f, 360.f);
Point2f vertices[4];
RotatedRect rRect = RotatedRect(center, rect_size, angle);
rRect.points(vertices);
for (int i = 0; i < 4; i++)
{
line(image, vertices[i], vertices[(i + 1) % 4], Scalar(255), 3);
}
}
void LSDBase::SetUp()
{
lines.clear();
test_image = Mat();
rng = RNG(LSD_TEST_SEED);
passedtests = 0;
}
TEST_F(Imgproc_LSD_ADV, whiteNoise)
{
for (int i = 0; i < EPOCHS; ++i)
{
GenerateWhiteNoise(test_image);
Ptr<LineSegmentDetector> detector = createLineSegmentDetector(LSD_REFINE_ADV);
detector->detect(test_image, lines);
if(40u >= lines.size()) ++passedtests;
}
ASSERT_EQ(EPOCHS, passedtests);
}
TEST_F(Imgproc_LSD_ADV, constColor)
{
for (int i = 0; i < EPOCHS; ++i)
{
GenerateConstColor(test_image);
Ptr<LineSegmentDetector> detector = createLineSegmentDetector(LSD_REFINE_ADV);
detector->detect(test_image, lines);
if(0u == lines.size()) ++passedtests;
}
ASSERT_EQ(EPOCHS, passedtests);
}
TEST_F(Imgproc_LSD_ADV, lines)
{
for (int i = 0; i < EPOCHS; ++i)
{
const unsigned int numOfLines = 1;
GenerateLines(test_image, numOfLines);
Ptr<LineSegmentDetector> detector = createLineSegmentDetector(LSD_REFINE_ADV);
detector->detect(test_image, lines);
if(numOfLines * 2 == lines.size()) ++passedtests; // * 2 because of Gibbs effect
}
ASSERT_EQ(EPOCHS, passedtests);
}
TEST_F(Imgproc_LSD_ADV, rotatedRect)
{
for (int i = 0; i < EPOCHS; ++i)
{
GenerateRotatedRect(test_image);
Ptr<LineSegmentDetector> detector = createLineSegmentDetector(LSD_REFINE_ADV);
detector->detect(test_image, lines);
if(2u <= lines.size()) ++passedtests;
}
ASSERT_EQ(EPOCHS, passedtests);
}
TEST_F(Imgproc_LSD_STD, whiteNoise)
{
for (int i = 0; i < EPOCHS; ++i)
{
GenerateWhiteNoise(test_image);
Ptr<LineSegmentDetector> detector = createLineSegmentDetector(LSD_REFINE_STD);
detector->detect(test_image, lines);
if(50u >= lines.size()) ++passedtests;
}
ASSERT_EQ(EPOCHS, passedtests);
}
TEST_F(Imgproc_LSD_STD, constColor)
{
for (int i = 0; i < EPOCHS; ++i)
{
GenerateConstColor(test_image);
Ptr<LineSegmentDetector> detector = createLineSegmentDetector(LSD_REFINE_STD);
detector->detect(test_image, lines);
if(0u == lines.size()) ++passedtests;
}
ASSERT_EQ(EPOCHS, passedtests);
}
TEST_F(Imgproc_LSD_STD, lines)
{
for (int i = 0; i < EPOCHS; ++i)
{
const unsigned int numOfLines = 1;
GenerateLines(test_image, numOfLines);
Ptr<LineSegmentDetector> detector = createLineSegmentDetector(LSD_REFINE_STD);
detector->detect(test_image, lines);
if(numOfLines * 2 == lines.size()) ++passedtests; // * 2 because of Gibbs effect
}
ASSERT_EQ(EPOCHS, passedtests);
}
TEST_F(Imgproc_LSD_STD, rotatedRect)
{
for (int i = 0; i < EPOCHS; ++i)
{
GenerateRotatedRect(test_image);
Ptr<LineSegmentDetector> detector = createLineSegmentDetector(LSD_REFINE_STD);
detector->detect(test_image, lines);
if(4u <= lines.size()) ++passedtests;
}
ASSERT_EQ(EPOCHS, passedtests);
}
TEST_F(Imgproc_LSD_NONE, whiteNoise)
{
for (int i = 0; i < EPOCHS; ++i)
{
GenerateWhiteNoise(test_image);
Ptr<LineSegmentDetector> detector = createLineSegmentDetector(LSD_REFINE_NONE);
detector->detect(test_image, lines);
if(50u >= lines.size()) ++passedtests;
}
ASSERT_EQ(EPOCHS, passedtests);
}
TEST_F(Imgproc_LSD_NONE, constColor)
{
for (int i = 0; i < EPOCHS; ++i)
{
GenerateConstColor(test_image);
Ptr<LineSegmentDetector> detector = createLineSegmentDetector(LSD_REFINE_NONE);
detector->detect(test_image, lines);
if(0u == lines.size()) ++passedtests;
}
ASSERT_EQ(EPOCHS, passedtests);
}
TEST_F(Imgproc_LSD_NONE, lines)
{
for (int i = 0; i < EPOCHS; ++i)
{
const unsigned int numOfLines = 1;
GenerateLines(test_image, numOfLines);
Ptr<LineSegmentDetector> detector = createLineSegmentDetector(LSD_REFINE_NONE);
detector->detect(test_image, lines);
if(numOfLines * 2 == lines.size()) ++passedtests; // * 2 because of Gibbs effect
}
ASSERT_EQ(EPOCHS, passedtests);
}
TEST_F(Imgproc_LSD_NONE, rotatedRect)
{
for (int i = 0; i < EPOCHS; ++i)
{
GenerateRotatedRect(test_image);
Ptr<LineSegmentDetector> detector = createLineSegmentDetector(LSD_REFINE_NONE);
detector->detect(test_image, lines);
if(8u <= lines.size()) ++passedtests;
}
ASSERT_EQ(EPOCHS, passedtests);
}
TEST_F(Imgproc_LSD_Common, supportsVec4iResult)
{
for (int i = 0; i < EPOCHS; ++i)
{
GenerateWhiteNoise(test_image);
Ptr<LineSegmentDetector> detector = createLineSegmentDetector(LSD_REFINE_STD);
detector->detect(test_image, lines);
std::vector<Vec4i> linesVec4i;
detector->detect(test_image, linesVec4i);
if (lines.size() == linesVec4i.size())
{
bool pass = true;
for (size_t lineIndex = 0; pass && lineIndex < lines.size(); lineIndex++)
{
for (int ch = 0; ch < 4; ch++)
{
if (cv::saturate_cast<int>(lines[lineIndex][ch]) != linesVec4i[lineIndex][ch])
{
pass = false;
break;
}
}
}
if (pass)
++passedtests;
}
}
ASSERT_EQ(EPOCHS, passedtests);
}
TEST_F(Imgproc_LSD_Common, drawSegmentsVec4f)
{
GenerateConstColor(test_image);
std::vector<Vec4f> linesVec4f;
RNG cr(0); // constant seed for deterministic test
for (int j = 0; j < 10; j++) {
linesVec4f.push_back(
Vec4f(float(cr) * test_image.cols, float(cr) * test_image.rows, float(cr) * test_image.cols, float(cr) * test_image.rows));
}
Mat actual = Mat::zeros(test_image.size(), CV_8UC3);
Mat expected = Mat::zeros(test_image.size(), CV_8UC3);
Ptr<LineSegmentDetector> detector = createLineSegmentDetector(LSD_REFINE_STD);
detector->drawSegments(actual, linesVec4f);
// something should be drawn
ASSERT_EQ(sum(actual == expected) != Scalar::all(0), true);
for (size_t lineIndex = 0; lineIndex < linesVec4f.size(); lineIndex++)
{
const Vec4f &v = linesVec4f[lineIndex];
const Point2f b(v[0], v[1]);
const Point2f e(v[2], v[3]);
line(expected, b, e, Scalar(0, 0, 255), 1);
}
ASSERT_EQ(sum(actual != expected) == Scalar::all(0), true);
}
TEST_F(Imgproc_LSD_Common, drawSegmentsVec4i)
{
GenerateConstColor(test_image);
std::vector<Vec4i> linesVec4i;
RNG cr(0); // constant seed for deterministic test
for (int j = 0; j < 10; j++) {
linesVec4i.push_back(
Vec4i(cr(test_image.cols), cr(test_image.rows), cr(test_image.cols), cr(test_image.rows)));
}
Mat actual = Mat::zeros(test_image.size(), CV_8UC3);
Mat expected = Mat::zeros(test_image.size(), CV_8UC3);
Ptr<LineSegmentDetector> detector = createLineSegmentDetector(LSD_REFINE_STD);
detector->drawSegments(actual, linesVec4i);
// something should be drawn
ASSERT_EQ(sum(actual == expected) != Scalar::all(0), true);
for (size_t lineIndex = 0; lineIndex < linesVec4i.size(); lineIndex++)
{
const Vec4f &v = linesVec4i[lineIndex];
const Point2f b(v[0], v[1]);
const Point2f e(v[2], v[3]);
line(expected, b, e, Scalar(0, 0, 255), 1);
}
ASSERT_EQ(sum(actual != expected) == Scalar::all(0), true);
}
TEST_F(Imgproc_LSD_Common, compareSegmentsVec4f)
{
GenerateConstColor(test_image);
Ptr<LineSegmentDetector> detector = createLineSegmentDetector(LSD_REFINE_STD);
std::vector<Vec4f> lines1, lines2;
lines1.push_back(Vec4f(0, 0, 100, 200));
lines2.push_back(Vec4f(0, 0, 100, 200));
int result1 = detector->compareSegments(test_image.size(), lines1, lines2);
ASSERT_EQ(result1, 0);
lines2.push_back(Vec4f(100, 100, 110, 100));
int result2 = detector->compareSegments(test_image.size(), lines1, lines2);
ASSERT_EQ(result2, 11);
}
TEST_F(Imgproc_LSD_Common, compareSegmentsVec4i)
{
GenerateConstColor(test_image);
Ptr<LineSegmentDetector> detector = createLineSegmentDetector(LSD_REFINE_STD);
std::vector<Vec4i> lines1, lines2;
lines1.push_back(Vec4i(0, 0, 100, 200));
lines2.push_back(Vec4i(0, 0, 100, 200));
int result1 = detector->compareSegments(test_image.size(), lines1, lines2);
ASSERT_EQ(result1, 0);
lines2.push_back(Vec4i(100, 100, 110, 100));
int result2 = detector->compareSegments(test_image.size(), lines1, lines2);
ASSERT_EQ(result2, 11);
}
TEST_F(Imgproc_LSD_Common, drawSegmentsEmpty)
{
Ptr<LineSegmentDetector> detector = createLineSegmentDetector(LSD_REFINE_STD);
Mat1b img = Mat1b::zeros(240, 320);
std::vector<Vec4i> lines_4i;
detector->detect(img, lines_4i);
Mat3b img_color = Mat3b::zeros(240, 320);
ASSERT_NO_THROW(
detector->drawSegments(img_color, lines_4i);
);
}
///////////////////////////////////////////////////////////////////////////
TEST(Imgproc_fitLine_vector_3d, regression)
{
std::vector<Point3f> points_vector;
Point3f p21(4,4,4);
Point3f p22(8,8,8);
points_vector.push_back(p21);
points_vector.push_back(p22);
std::vector<float> line;
cv::fitLine(points_vector, line, DIST_L2, 0 ,0 ,0);
ASSERT_EQ(line.size(), (size_t)6);
}
TEST(Imgproc_fitLine_vector_2d, regression)
{
std::vector<Point2f> points_vector;
Point2f p21(4,4);
Point2f p22(8,8);
Point2f p23(16,16);
points_vector.push_back(p21);
points_vector.push_back(p22);
points_vector.push_back(p23);
std::vector<float> line;
cv::fitLine(points_vector, line, DIST_L2, 0 ,0 ,0);
ASSERT_EQ(line.size(), (size_t)4);
}
TEST(Imgproc_fitLine_Mat_2dC2, regression)
{
cv::Mat mat1 = Mat::zeros(3, 1, CV_32SC2);
std::vector<float> line1;
cv::fitLine(mat1, line1, DIST_L2, 0 ,0 ,0);
ASSERT_EQ(line1.size(), (size_t)4);
}
TEST(Imgproc_fitLine_Mat_2dC1, regression)
{
cv::Matx<int, 3, 2> mat2;
std::vector<float> line2;
cv::fitLine(mat2, line2, DIST_L2, 0 ,0 ,0);
ASSERT_EQ(line2.size(), (size_t)4);
}
TEST(Imgproc_fitLine_Mat_3dC3, regression)
{
cv::Mat mat1 = Mat::zeros(2, 1, CV_32SC3);
std::vector<float> line1;
cv::fitLine(mat1, line1, DIST_L2, 0 ,0 ,0);
ASSERT_EQ(line1.size(), (size_t)6);
}
TEST(Imgproc_fitLine_Mat_3dC1, regression)
{
cv::Mat mat2 = Mat::zeros(2, 3, CV_32SC1);
std::vector<float> line2;
cv::fitLine(mat2, line2, DIST_L2, 0 ,0 ,0);
ASSERT_EQ(line2.size(), (size_t)6);
}
}} // 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.
#include "test_precomp.hpp"
#if defined(HAVE_HPX)
#include <hpx/hpx_main.hpp>
#endif
CV_TEST_MAIN("cv")
+154
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) 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 CV_TEST_DXT_MUL_CONJ 8
namespace opencv_test { namespace {
/// phase correlation
class CV_PhaseCorrelatorTest : public cvtest::ArrayTest
{
public:
CV_PhaseCorrelatorTest();
protected:
void run( int );
};
CV_PhaseCorrelatorTest::CV_PhaseCorrelatorTest() {}
void CV_PhaseCorrelatorTest::run( int )
{
ts->set_failed_test_info(cvtest::TS::OK);
Mat r1 = Mat::ones(Size(129, 128), CV_64F);
Mat r2 = Mat::ones(Size(129, 128), CV_64F);
double expectedShiftX = -10.0;
double expectedShiftY = -20.0;
// draw 10x10 rectangles @ (100, 100) and (90, 80) should see ~(-10, -20) shift here...
cv::rectangle(r1, Point(100, 100), Point(110, 110), Scalar(0, 0, 0), cv::FILLED);
cv::rectangle(r2, Point(90, 80), Point(100, 90), Scalar(0, 0, 0), cv::FILLED);
Mat hann;
createHanningWindow(hann, r1.size(), CV_64F);
Point2d phaseShift = phaseCorrelate(r1, r2, hann);
// test accuracy should be less than 1 pixel...
if(std::abs(expectedShiftX - phaseShift.x) >= 1 || std::abs(expectedShiftY - phaseShift.y) >= 1)
{
ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
}
}
TEST(Imgproc_PhaseCorrelatorTest, accuracy) { CV_PhaseCorrelatorTest test; test.safe_run(); }
TEST(Imgproc_PhaseCorrelatorTest, accuracy_real_img)
{
Mat img = imread(cvtest::TS::ptr()->get_data_path() + "shared/airplane.png", IMREAD_GRAYSCALE);
img.convertTo(img, CV_64FC1);
const int xLen = 129;
const int yLen = 129;
const int xShift = 40;
const int yShift = 14;
Mat roi1 = img(Rect(xShift, yShift, xLen, yLen));
Mat roi2 = img(Rect(0, 0, xLen, yLen));
Mat hann;
createHanningWindow(hann, roi1.size(), CV_64F);
Point2d phaseShift = phaseCorrelate(roi1, roi2, hann);
ASSERT_NEAR(phaseShift.x, (double)xShift, 1.);
ASSERT_NEAR(phaseShift.y, (double)yShift, 1.);
}
TEST(Imgproc_PhaseCorrelatorTest, accuracy_1d_odd_fft) {
Mat r1 = Mat::ones(Size(129, 1), CV_64F)*255; // 129 will be completed to 135 before FFT
Mat r2 = Mat::ones(Size(129, 1), CV_64F)*255;
const int xShift = 10;
for(int i = 6; i < 20; i++)
{
r1.at<double>(i) = 1;
r2.at<double>(i + xShift) = 1;
}
Point2d phaseShift = phaseCorrelate(r1, r2);
ASSERT_NEAR(phaseShift.x, (double)xShift, 1.);
}
TEST(Imgproc_PhaseCorrelatorTest, float32_overflow) {
// load
Mat im = imread(cvtest::TS::ptr()->get_data_path() + "shared/baboon.png", IMREAD_GRAYSCALE);
ASSERT_EQ(im.type(), CV_8UC1);
// convert to 32F, scale values as if original image was 16U
constexpr auto u8Max = std::numeric_limits<std::uint8_t>::max();
constexpr auto u16Max = std::numeric_limits<std::uint16_t>::max();
im.convertTo(im, CV_32FC1, double(u16Max) / double(u8Max));
// enlarge and create ROIs
const auto w = im.cols * 5;
const auto h = im.rows * 5;
const auto roiW = (w * 2) / 3; // 50% overlap
Mat imLarge;
resize(im, imLarge, { w, h });
const auto roiLeft = imLarge(Rect(0, 0, roiW, h));
const auto roiRight = imLarge(Rect(w - roiW, 0, roiW, h));
// correlate
double response = 0.0;
Point2d phaseShift = phaseCorrelate(roiLeft, roiRight, cv::noArray(), &response);
ASSERT_TRUE(std::isnormal(phaseShift.x) || 0.0 == phaseShift.x);
ASSERT_TRUE(std::isnormal(phaseShift.y) || 0.0 == phaseShift.y);
ASSERT_TRUE(std::isnormal(response) || 0.0 == response);
EXPECT_NEAR(std::abs(phaseShift.x), w / 3.0, 1.0);
EXPECT_NEAR(std::abs(phaseShift.y), 0.0, 1.0);
}
}} // namespace
+18
View File
@@ -0,0 +1,18 @@
// 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/ts_gtest.h"
#include "opencv2/ts/ocl_test.hpp"
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/geometry.hpp"
#include "opencv2/core/private.hpp"
#include "opencv2/core/softfloat.hpp" // softfloat, uint32_t
#endif
+48
View File
@@ -0,0 +1,48 @@
// 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(Imgproc_PyrUp, pyrUp_regression_22184)
{
Mat src(100,100,CV_16UC3,Scalar(255,255,255));
Mat dst(100 * 2 + 1, 100 * 2 + 1, CV_16UC3, Scalar(0,0,0));
pyrUp(src, dst, Size(dst.cols, dst.rows));
double min_val = 0;
minMaxLoc(dst, &min_val);
ASSERT_GT(cvRound(min_val), 0);
}
TEST(Imgproc_PyrUp, pyrUp_regression_22194)
{
Mat src(13, 13,CV_16UC3,Scalar(0,0,0));
{
int swidth = src.cols;
int sheight = src.rows;
int cn = src.channels();
int count = 0;
for (int y = 0; y < sheight; y++)
{
ushort *src_c = src.ptr<ushort>(y);
for (int x = 0; x < swidth * cn; x++)
{
src_c[x] = (count++) % 10;
}
}
}
Mat dst(src.cols * 2 - 1, src.rows * 2 - 1, CV_16UC3, Scalar(0,0,0));
pyrUp(src, dst, Size(dst.cols, dst.rows));
{
ushort *dst_c = dst.ptr<ushort>(dst.rows - 1);
ASSERT_EQ(dst_c[0], 6);
ASSERT_EQ(dst_c[1], 6);
ASSERT_EQ(dst_c[2], 1);
}
}
}
}
@@ -0,0 +1,303 @@
// 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 const int fixedShiftU8 = 8;
template <typename T, int fixedShift>
void eval4(int64_t xcoeff0, int64_t xcoeff1, int64_t ycoeff0, int64_t ycoeff1, int cn,
uint8_t* src_pt00, uint8_t* src_pt01, uint8_t* src_pt10, uint8_t* src_pt11, uint8_t* dst_pt)
{
static const int64_t fixedRound = ((1LL << (fixedShift * 2)) >> 1);
int64_t val = (((T*)src_pt00)[cn] * xcoeff0 + ((T*)src_pt01)[cn] * xcoeff1) * ycoeff0 +
(((T*)src_pt10)[cn] * xcoeff0 + ((T*)src_pt11)[cn] * xcoeff1) * ycoeff1 ;
((T*)dst_pt)[cn] = saturate_cast<T>((val + fixedRound) >> (fixedShift * 2));
}
TEST(Resize_Bitexact, Linear8U)
{
static const int64_t fixedOne = (1L << fixedShiftU8);
struct testmode
{
int type;
Size sz;
} modes[] = {
{ CV_8UC1, Size( 512, 768) }, // 1/2 1
{ CV_8UC3, Size( 512, 768) },
{ CV_8UC1, Size(1024, 384) }, // 1 1/2
{ CV_8UC4, Size(1024, 384) },
{ CV_8UC1, Size( 512, 384) }, // 1/2 1/2
{ CV_8UC2, Size( 512, 384) },
{ CV_8UC3, Size( 512, 384) },
{ CV_8UC4, Size( 512, 384) },
{ CV_8UC1, Size( 256, 192) }, // 1/4 1/4
{ CV_8UC2, Size( 256, 192) },
{ CV_8UC3, Size( 256, 192) },
{ CV_8UC4, Size( 256, 192) },
{ CV_8UC1, Size( 4, 3) }, // 1/256 1/256
{ CV_8UC2, Size( 4, 3) },
{ CV_8UC3, Size( 4, 3) },
{ CV_8UC4, Size( 4, 3) },
{ CV_8UC1, Size( 342, 384) }, // 1/3 1/2
{ CV_8UC1, Size( 342, 256) }, // 1/3 1/3
{ CV_8UC2, Size( 342, 256) },
{ CV_8UC3, Size( 342, 256) },
{ CV_8UC4, Size( 342, 256) },
{ CV_8UC1, Size( 512, 256) }, // 1/2 1/3
{ CV_8UC1, Size( 146, 110) }, // 1/7 1/7
{ CV_8UC3, Size( 146, 110) },
{ CV_8UC4, Size( 146, 110) },
{ CV_8UC1, Size( 931, 698) }, // 10/11 10/11
{ CV_8UC2, Size( 931, 698) },
{ CV_8UC3, Size( 931, 698) },
{ CV_8UC4, Size( 931, 698) },
{ CV_8UC1, Size( 853, 640) }, // 10/12 10/12
{ CV_8UC3, Size( 853, 640) },
{ CV_8UC4, Size( 853, 640) },
{ CV_8UC1, Size(1004, 753) }, // 251/256 251/256
{ CV_8UC2, Size(1004, 753) },
{ CV_8UC3, Size(1004, 753) },
{ CV_8UC4, Size(1004, 753) },
{ CV_8UC1, Size(2048,1536) }, // 2 2
{ CV_8UC2, Size(2048,1536) },
{ CV_8UC4, Size(2048,1536) },
{ CV_8UC1, Size(3072,2304) }, // 3 3
{ CV_8UC3, Size(3072,2304) },
{ CV_8UC1, Size(7168,5376) } // 7 7
};
for (int modeind = 0, _modecnt = sizeof(modes) / sizeof(modes[0]); modeind < _modecnt; ++modeind)
{
int type = modes[modeind].type, depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
int dcols = modes[modeind].sz.width, drows = modes[modeind].sz.height;
int cols = 1024, rows = 768;
double inv_scale_x = (double)dcols / cols;
double inv_scale_y = (double)drows / rows;
softdouble scale_x = softdouble::one() / softdouble(inv_scale_x);
softdouble scale_y = softdouble::one() / softdouble(inv_scale_y);
Mat src(rows, cols, type), refdst(drows, dcols, type), dst;
RNG rnd(0x123456789abcdefULL);
for (int j = 0; j < rows; j++)
{
uint8_t* line = src.ptr(j);
for (int i = 0; i < cols; i++)
for (int c = 0; c < cn; c++)
{
double val = j < rows / 2 ? ( i < cols / 2 ? ((sin((i + 1)*CV_PI / 256.)*sin((j + 1)*CV_PI / 256.)*sin((cn + 4)*CV_PI / 8.) + 1.)*128.) :
(((i / 128 + j / 128) % 2) * 250 + (j / 128) % 2) ) :
( i < cols / 2 ? ((i / 128) * (85 - j / 256 * 40) * ((j / 128) % 2) + (7 - i / 128) * (85 - j / 256 * 40) * ((j / 128 + 1) % 2)) :
((uchar)rnd) ) ;
if (depth == CV_8U)
line[i*cn + c] = (uint8_t)val;
else if (depth == CV_16U)
((uint16_t*)line)[i*cn + c] = (uint16_t)val;
else if (depth == CV_16S)
((int16_t*)line)[i*cn + c] = (int16_t)val;
else if (depth == CV_32S)
((int32_t*)line)[i*cn + c] = (int32_t)val;
else
CV_Assert(0);
}
}
for (int j = 0; j < drows; j++)
{
softdouble src_row_flt = scale_y*(softdouble(j) + softdouble(0.5)) - softdouble(0.5);
int src_row = cvFloor(src_row_flt);
int64_t ycoeff1 = cvRound64((src_row_flt - softdouble(src_row))*softdouble(fixedOne));
int64_t ycoeff0 = fixedOne - ycoeff1;
for (int i = 0; i < dcols; i++)
{
softdouble src_col_flt = scale_x*(softdouble(i) + softdouble(0.5)) - softdouble(0.5);
int src_col = cvFloor(src_col_flt);
int64_t xcoeff1 = cvRound64((src_col_flt - softdouble(src_col))*softdouble(fixedOne));
int64_t xcoeff0 = fixedOne - xcoeff1;
uint8_t* dst_pt = refdst.ptr(j, i);
uint8_t* src_pt00 = src.ptr( src_row < 0 ? 0 : src_row >= rows ? rows - 1 : src_row ,
src_col < 0 ? 0 : src_col >= cols ? cols - 1 : src_col );
uint8_t* src_pt01 = src.ptr( src_row < 0 ? 0 : src_row >= rows ? rows - 1 : src_row ,
(src_col + 1) < 0 ? 0 : (src_col + 1) >= cols ? cols - 1 : (src_col + 1));
uint8_t* src_pt10 = src.ptr((src_row + 1) < 0 ? 0 : (src_row + 1) >= rows ? rows - 1 : (src_row + 1),
src_col < 0 ? 0 : src_col >= cols ? cols - 1 : src_col );
uint8_t* src_pt11 = src.ptr((src_row + 1) < 0 ? 0 : (src_row + 1) >= rows ? rows - 1 : (src_row + 1),
(src_col + 1) < 0 ? 0 : (src_col + 1) >= cols ? cols - 1 : (src_col + 1));
for (int c = 0; c < cn; c++)
{
if (depth == CV_8U)
eval4< uint8_t, fixedShiftU8>(xcoeff0, xcoeff1, ycoeff0, ycoeff1, c, src_pt00, src_pt01, src_pt10, src_pt11, dst_pt);
else if (depth == CV_16U)
eval4<uint16_t, fixedShiftU8>(xcoeff0, xcoeff1, ycoeff0, ycoeff1, c, src_pt00, src_pt01, src_pt10, src_pt11, dst_pt);
else if (depth == CV_16S)
eval4< int16_t, fixedShiftU8>(xcoeff0, xcoeff1, ycoeff0, ycoeff1, c, src_pt00, src_pt01, src_pt10, src_pt11, dst_pt);
else if (depth == CV_32S)
eval4< int32_t, fixedShiftU8>(xcoeff0, xcoeff1, ycoeff0, ycoeff1, c, src_pt00, src_pt01, src_pt10, src_pt11, dst_pt);
else
CV_Assert(0);
}
}
}
cv::resize(src, dst, Size(dcols, drows), 0, 0, cv::INTER_LINEAR_EXACT);
EXPECT_GE(0, cvtest::norm(refdst, dst, cv::NORM_L1))
<< "Resize " << cn << "-chan mat from " << cols << "x" << rows << " to " << dcols << "x" << drows << " failed with max diff " << cvtest::norm(refdst, dst, cv::NORM_INF);
}
}
PARAM_TEST_CASE(Resize_Bitexact, int)
{
public:
int depth;
virtual void SetUp()
{
depth = GET_PARAM(0);
}
double CountDiff(const Mat& src)
{
Mat dstExact; cv::resize(src, dstExact, Size(), 2, 1, INTER_NEAREST_EXACT);
Mat dstNonExact; cv::resize(src, dstNonExact, Size(), 2, 1, INTER_NEAREST);
return cv::norm(dstExact, dstNonExact, NORM_INF);
}
};
TEST_P(Resize_Bitexact, Nearest8U_vsNonExact)
{
Mat mat_color, mat_gray;
Mat src_color = imread(cvtest::findDataFile("shared/lena.png"));
Mat src_gray; cv::cvtColor(src_color, src_gray, COLOR_BGR2GRAY);
src_color.convertTo(mat_color, depth);
src_gray.convertTo(mat_gray, depth);
EXPECT_EQ(CountDiff(mat_color), 0) << "color, type: " << depth;
EXPECT_EQ(CountDiff(mat_gray), 0) << "gray, type: " << depth;
}
// Now INTER_NEAREST's convention and INTER_NEAREST_EXACT's one are different.
INSTANTIATE_TEST_CASE_P(DISABLED_Imgproc, Resize_Bitexact,
testing::Values(CV_8U, CV_16U, CV_32F, CV_64F)
);
TEST(Resize_Bitexact, Nearest8U)
{
Mat src[6], dst[6];
// 2x decimation
src[0] = (Mat_<uint8_t>(1, 6) << 0, 1, 2, 3, 4, 5);
dst[0] = (Mat_<uint8_t>(1, 3) << 1, 3, 5);
// decimation odd to 1
src[1] = (Mat_<uint8_t>(1, 5) << 0, 1, 2, 3, 4);
dst[1] = (Mat_<uint8_t>(1, 1) << 2);
// decimation n*2-1 to n
src[2] = (Mat_<uint8_t>(1, 5) << 0, 1, 2, 3, 4);
dst[2] = (Mat_<uint8_t>(1, 3) << 0, 2, 4);
// decimation n*2+1 to n
src[3] = (Mat_<uint8_t>(1, 5) << 0, 1, 2, 3, 4);
dst[3] = (Mat_<uint8_t>(1, 2) << 1, 3);
// zoom
src[4] = (Mat_<uint8_t>(3, 5) <<
0, 1, 2, 3, 4,
5, 6, 7, 8, 9,
10, 11, 12, 13, 14);
dst[4] = (Mat_<uint8_t>(5, 7) <<
0, 1, 1, 2, 3, 3, 4,
0, 1, 1, 2, 3, 3, 4,
5, 6, 6, 7, 8, 8, 9,
10, 11, 11, 12, 13, 13, 14,
10, 11, 11, 12, 13, 13, 14);
src[5] = (Mat_<uint8_t>(2, 3) <<
0, 1, 2,
3, 4, 5);
dst[5] = (Mat_<uint8_t>(4, 6) <<
0, 0, 1, 1, 2, 2,
0, 0, 1, 1, 2, 2,
3, 3, 4, 4, 5, 5,
3, 3, 4, 4, 5, 5);
for (int i = 0; i < 6; i++)
{
Mat calc;
resize(src[i], calc, dst[i].size(), 0, 0, INTER_NEAREST_EXACT);
EXPECT_EQ(cvtest::norm(calc, dst[i], cv::NORM_L1), 0);
resize(src[i].t(), calc, dst[i].t().size(), 0, 0, INTER_NEAREST_EXACT);
EXPECT_EQ(cvtest::norm(calc, dst[i].t(), cv::NORM_L1), 0);
}
}
// Regression test for #28429: INTER_NEAREST_EXACT matches Pillow's
// center-of-pixel nearest-neighbor mapping.
TEST(Resize_Bitexact, NearestExact_PillowCompat)
{
auto center_pixel_map = [](int src_dim, int dst_dim, std::vector<int>& mapping) {
softdouble scale = softdouble(src_dim) / softdouble(dst_dim);
softdouble f = scale * softdouble(0.5);
mapping.resize(dst_dim);
for (int i = 0; i < dst_dim; i++)
{
mapping[i] = std::min(cvTrunc(f), src_dim - 1);
f += scale;
}
};
// Test dimension pairs including multiples of 64 that triggered the bug
const int cases[][4] = {
{128, 147, 160, 160}, // original reproducer from #28429
{128, 128, 160, 160}, // square with problematic height
{192, 192, 256, 256}, // another multiple of 64
{129, 147, 160, 160}, // non-problematic control case
};
for (const auto& c : cases)
{
int src_h = c[0], src_w = c[1], dst_h = c[2], dst_w = c[3];
std::vector<int> x_map, y_map;
center_pixel_map(src_w, dst_w, x_map);
center_pixel_map(src_h, dst_h, y_map);
Mat src(src_h, src_w, CV_8UC3);
randu(src, Scalar::all(0), Scalar::all(256));
Mat result;
resize(src, result, Size(dst_w, dst_h), 0, 0, INTER_NEAREST_EXACT);
int nerrs = 0;
for (int y = 0; y < dst_h; y++)
{
for (int x = 0; x < dst_w; x++)
{
Vec3b expected = src.at<Vec3b>(y_map[y], x_map[x]);
Vec3b actual = result.at<Vec3b>(y, x);
nerrs += expected != actual;
if (nerrs <= 10) {
EXPECT_EQ(expected, actual)
<< "Mismatch at dst(" << y << "," << x << ") -> src("
<< y_map[y] << "," << x_map[x] << ") for "
<< src_h << "x" << src_w << " -> " << dst_h << "x" << dst_w;
}
}
}
ASSERT_EQ(nerrs, 0) << "nerrs=" << nerrs << " when"
<< " src_h=" << src_h << ", src_w=" << src_w
<< " dst_h=" << dst_h << ", dst_w=" << dst_w;
}
}
}} // namespace
@@ -0,0 +1,309 @@
// 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 const int fixedShiftU8 = 8;
static const int64_t fixedOneU8 = (1L << fixedShiftU8);
static const int fixedShiftU16 = 16;
static const int64_t fixedOneU16 = (1L << fixedShiftU16);
int64_t vU8[][9] = {
{ fixedOneU8 }, // size 1, sigma 0
{ fixedOneU8 >> 2, fixedOneU8 >> 1, fixedOneU8 >> 2 }, // size 3, sigma 0
{ fixedOneU8 >> 4, fixedOneU8 >> 2, 6 * (fixedOneU8 >> 4), fixedOneU8 >> 2, fixedOneU8 >> 4 }, // size 5, sigma 0
{ fixedOneU8 >> 5, 7 * (fixedOneU8 >> 6), 7 * (fixedOneU8 >> 5), 9 * (fixedOneU8 >> 5), 7 * (fixedOneU8 >> 5), 7 * (fixedOneU8 >> 6), fixedOneU8 >> 5 }, // size 7, sigma 0
{ 4, 13, 30, 51, 60, 51, 30, 13, 4 }, // size 9, sigma 0
#if 1
#define CV_TEST_INACCURATE_GAUSSIAN_BLUR
{ 81, 94, 81 }, // size 3, sigma 1.75
{ 65, 126, 65 }, // size 3, sigma 0.875
{ 0, 7, 242, 7, 0 }, // size 5, sigma 0.375
{ 4, 56, 136, 56, 4 } // size 5, sigma 0.75
#endif
};
int64_t vU16[][9] = {
{ fixedOneU16 }, // size 1, sigma 0
{ fixedOneU16 >> 2, fixedOneU16 >> 1, fixedOneU16 >> 2 }, // size 3, sigma 0
{ fixedOneU16 >> 4, fixedOneU16 >> 2, 6 * (fixedOneU16 >> 4), fixedOneU16 >> 2, fixedOneU16 >> 4 }, // size 5, sigma 0
{ fixedOneU16 >> 5, 7 * (fixedOneU16 >> 6), 7 * (fixedOneU16 >> 5), 9 * (fixedOneU16 >> 5), 7 * (fixedOneU16 >> 5), 7 * (fixedOneU16 >> 6), fixedOneU16 >> 5 }, // size 7, sigma 0
{ 4<<8, 13<<8, 30<<8, 51<<8, 60<<8, 51<<8, 30<<8, 13<<8, 4<<8 } // size 9, sigma 0
};
template <typename T, int fixedShift>
T eval(Mat src, vector<int64_t> kernelx, vector<int64_t> kernely)
{
static const int64_t fixedRound = ((1LL << (fixedShift * 2)) >> 1);
int64_t val = 0;
for (size_t j = 0; j < kernely.size(); j++)
{
int64_t lineval = 0;
for (size_t i = 0; i < kernelx.size(); i++)
lineval += src.at<T>((int)j, (int)i) * kernelx[i];
val += lineval * kernely[j];
}
return saturate_cast<T>((val + fixedRound) >> (fixedShift * 2));
}
struct testmode
{
int type;
Size sz;
Size kernel;
double sigma_x;
double sigma_y;
vector<int64_t> kernel_x;
vector<int64_t> kernel_y;
};
int bordermodes[] = {
BORDER_CONSTANT | BORDER_ISOLATED,
BORDER_REPLICATE | BORDER_ISOLATED,
BORDER_REFLECT | BORDER_ISOLATED,
BORDER_WRAP | BORDER_ISOLATED,
BORDER_REFLECT_101 | BORDER_ISOLATED
// BORDER_CONSTANT,
// BORDER_REPLICATE,
// BORDER_REFLECT,
// BORDER_WRAP,
// BORDER_REFLECT_101
};
template <int fixedShift>
void checkMode(const testmode& mode)
{
int type = mode.type, depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
int dcols = mode.sz.width, drows = mode.sz.height;
Size kernel = mode.kernel;
int rows = drows + 20, cols = dcols + 20;
Mat src(rows, cols, type), refdst(drows, dcols, type), dst;
for (int j = 0; j < rows; j++)
{
uint8_t* line = src.ptr(j);
for (int i = 0; i < cols; i++)
for (int c = 0; c < cn; c++)
{
RNG rnd(0x123456789abcdefULL);
double val = j < rows / 2 ? (i < cols / 2 ? ((sin((i + 1)*CV_PI / 256.)*sin((j + 1)*CV_PI / 256.)*sin((cn + 4)*CV_PI / 8.) + 1.)*128.) :
(((i / 128 + j / 128) % 2) * 250 + (j / 128) % 2)) :
(i < cols / 2 ? ((i / 128) * (85 - j / 256 * 40) * ((j / 128) % 2) + (7 - i / 128) * (85 - j / 256 * 40) * ((j / 128 + 1) % 2)) :
((uchar)rnd));
if (depth == CV_8U)
line[i*cn + c] = (uint8_t)val;
else if (depth == CV_16U)
((uint16_t*)line)[i*cn + c] = (uint16_t)val;
else if (depth == CV_16S)
((int16_t*)line)[i*cn + c] = (int16_t)val;
else if (depth == CV_32S)
((int32_t*)line)[i*cn + c] = (int32_t)val;
else
CV_Assert(0);
}
}
Mat src_roi = src(Rect(10, 10, dcols, drows));
for (int borderind = 0, _bordercnt = sizeof(bordermodes) / sizeof(bordermodes[0]); borderind < _bordercnt; ++borderind)
{
Mat src_border;
cv::copyMakeBorder(src_roi, src_border, kernel.height / 2, kernel.height / 2, kernel.width / 2, kernel.width / 2, bordermodes[borderind]);
for (int c = 0; c < src_border.channels(); c++)
{
int fromTo[2] = { c, 0 };
int toFrom[2] = { 0, c };
Mat src_chan(src_border.size(), CV_MAKETYPE(src_border.depth(),1));
Mat dst_chan(refdst.size(), CV_MAKETYPE(refdst.depth(), 1));
mixChannels(src_border, src_chan, fromTo, 1);
for (int j = 0; j < drows; j++)
for (int i = 0; i < dcols; i++)
{
if (depth == CV_8U)
dst_chan.at<uint8_t>(j, i) = eval<uint8_t, fixedShift>(src_chan(Rect(i,j,kernel.width,kernel.height)), mode.kernel_x, mode.kernel_y);
else if (depth == CV_16U)
dst_chan.at<uint16_t>(j, i) = eval<uint16_t, fixedShift>(src_chan(Rect(i, j, kernel.width, kernel.height)), mode.kernel_x, mode.kernel_y);
else if (depth == CV_16S)
dst_chan.at<int16_t>(j, i) = eval<int16_t, fixedShift>(src_chan(Rect(i, j, kernel.width, kernel.height)), mode.kernel_x, mode.kernel_y);
else if (depth == CV_32S)
dst_chan.at<int32_t>(j, i) = eval<int32_t, fixedShift>(src_chan(Rect(i, j, kernel.width, kernel.height)), mode.kernel_x, mode.kernel_y);
else
CV_Assert(0);
}
mixChannels(dst_chan, refdst, toFrom, 1);
}
cv::GaussianBlur(src_roi, dst, kernel, mode.sigma_x, mode.sigma_y, bordermodes[borderind]);
EXPECT_GE(0, cvtest::norm(refdst, dst, cv::NORM_L1))
<< "GaussianBlur " << cn << "-chan mat " << drows << "x" << dcols << " by kernel " << kernel << " sigma(" << mode.sigma_x << ";" << mode.sigma_y << ") failed with max diff " << cvtest::norm(refdst, dst, cv::NORM_INF);
}
}
TEST(GaussianBlur_Bitexact, Linear8U)
{
testmode modes[] = {
{ CV_8UC1, Size( 1, 1), Size(3, 3), 0, 0, vector<int64_t>(vU8[1], vU8[1]+3), vector<int64_t>(vU8[1], vU8[1]+3) },
{ CV_8UC1, Size( 2, 2), Size(3, 3), 0, 0, vector<int64_t>(vU8[1], vU8[1]+3), vector<int64_t>(vU8[1], vU8[1]+3) },
{ CV_8UC1, Size( 3, 1), Size(3, 3), 0, 0, vector<int64_t>(vU8[1], vU8[1]+3), vector<int64_t>(vU8[1], vU8[1]+3) },
{ CV_8UC1, Size( 1, 3), Size(3, 3), 0, 0, vector<int64_t>(vU8[1], vU8[1]+3), vector<int64_t>(vU8[1], vU8[1]+3) },
{ CV_8UC1, Size( 3, 3), Size(3, 3), 0, 0, vector<int64_t>(vU8[1], vU8[1]+3), vector<int64_t>(vU8[1], vU8[1]+3) },
{ CV_8UC1, Size( 3, 3), Size(5, 5), 0, 0, vector<int64_t>(vU8[2], vU8[2]+5), vector<int64_t>(vU8[2], vU8[2]+5) },
{ CV_8UC1, Size( 3, 3), Size(7, 7), 0, 0, vector<int64_t>(vU8[3], vU8[3]+7), vector<int64_t>(vU8[3], vU8[3]+7) },
{ CV_8UC1, Size( 5, 5), Size(3, 3), 0, 0, vector<int64_t>(vU8[1], vU8[1]+3), vector<int64_t>(vU8[1], vU8[1]+3) },
{ CV_8UC1, Size( 5, 5), Size(5, 5), 0, 0, vector<int64_t>(vU8[2], vU8[2]+5), vector<int64_t>(vU8[2], vU8[2]+5) },
{ CV_8UC1, Size( 3, 5), Size(5, 5), 0, 0, vector<int64_t>(vU8[2], vU8[2]+5), vector<int64_t>(vU8[2], vU8[2]+5) },
{ CV_8UC1, Size( 5, 5), Size(5, 5), 0, 0, vector<int64_t>(vU8[2], vU8[2]+5), vector<int64_t>(vU8[2], vU8[2]+5) },
{ CV_8UC1, Size( 5, 5), Size(7, 7), 0, 0, vector<int64_t>(vU8[3], vU8[3]+7), vector<int64_t>(vU8[3], vU8[3]+7) },
{ CV_8UC1, Size( 7, 7), Size(7, 7), 0, 0, vector<int64_t>(vU8[3], vU8[3]+7), vector<int64_t>(vU8[3], vU8[3]+7) },
{ CV_8UC1, Size( 256, 128), Size(3, 3), 0, 0, vector<int64_t>(vU8[1], vU8[1]+3), vector<int64_t>(vU8[1], vU8[1]+3) },
{ CV_8UC2, Size( 256, 128), Size(3, 3), 0, 0, vector<int64_t>(vU8[1], vU8[1]+3), vector<int64_t>(vU8[1], vU8[1]+3) },
{ CV_8UC3, Size( 256, 128), Size(3, 3), 0, 0, vector<int64_t>(vU8[1], vU8[1]+3), vector<int64_t>(vU8[1], vU8[1]+3) },
{ CV_8UC4, Size( 256, 128), Size(3, 3), 0, 0, vector<int64_t>(vU8[1], vU8[1]+3), vector<int64_t>(vU8[1], vU8[1]+3) },
{ CV_8UC1, Size( 256, 128), Size(5, 5), 0, 0, vector<int64_t>(vU8[2], vU8[2]+5), vector<int64_t>(vU8[2], vU8[2]+5) },
{ CV_8UC1, Size( 256, 128), Size(7, 7), 0, 0, vector<int64_t>(vU8[3], vU8[3]+7), vector<int64_t>(vU8[3], vU8[3]+7) },
{ CV_8UC1, Size( 256, 128), Size(9, 9), 0, 0, vector<int64_t>(vU8[4], vU8[4]+9), vector<int64_t>(vU8[4], vU8[4]+9) },
#ifdef CV_TEST_INACCURATE_GAUSSIAN_BLUR
{ CV_8UC1, Size( 256, 128), Size(3, 3), 1.75, 0.875, vector<int64_t>(vU8[5], vU8[5]+3), vector<int64_t>(vU8[6], vU8[6]+3) },
{ CV_8UC2, Size( 256, 128), Size(3, 3), 1.75, 0.875, vector<int64_t>(vU8[5], vU8[5]+3), vector<int64_t>(vU8[6], vU8[6]+3) },
{ CV_8UC3, Size( 256, 128), Size(3, 3), 1.75, 0.875, vector<int64_t>(vU8[5], vU8[5]+3), vector<int64_t>(vU8[6], vU8[6]+3) },
{ CV_8UC4, Size( 256, 128), Size(3, 3), 1.75, 0.875, vector<int64_t>(vU8[5], vU8[5]+3), vector<int64_t>(vU8[6], vU8[6]+3) },
{ CV_8UC1, Size( 256, 128), Size(5, 5), 0.375, 0.75, vector<int64_t>(vU8[7], vU8[7]+5), vector<int64_t>(vU8[8], vU8[8]+5) }
#endif
};
for (int modeind = 0, _modecnt = sizeof(modes) / sizeof(modes[0]); modeind < _modecnt; ++modeind)
{
checkMode<fixedShiftU8>(modes[modeind]);
}
}
TEST(GaussianBlur_Bitexact, Linear16U)
{
testmode modes[] = {
{ CV_16UC1, Size( 1, 1), Size(3, 3), 0, 0, vector<int64_t>(vU16[1], vU16[1]+3), vector<int64_t>(vU16[1], vU16[1]+3) },
{ CV_16UC1, Size( 2, 2), Size(3, 3), 0, 0, vector<int64_t>(vU16[1], vU16[1]+3), vector<int64_t>(vU16[1], vU16[1]+3) },
{ CV_16UC1, Size( 3, 1), Size(3, 3), 0, 0, vector<int64_t>(vU16[1], vU16[1]+3), vector<int64_t>(vU16[1], vU16[1]+3) },
{ CV_16UC1, Size( 1, 3), Size(3, 3), 0, 0, vector<int64_t>(vU16[1], vU16[1]+3), vector<int64_t>(vU16[1], vU16[1]+3) },
{ CV_16UC1, Size( 3, 3), Size(3, 3), 0, 0, vector<int64_t>(vU16[1], vU16[1]+3), vector<int64_t>(vU16[1], vU16[1]+3) },
{ CV_16UC1, Size( 3, 3), Size(5, 5), 0, 0, vector<int64_t>(vU16[2], vU16[2]+5), vector<int64_t>(vU16[2], vU16[2]+5) },
{ CV_16UC1, Size( 3, 3), Size(7, 7), 0, 0, vector<int64_t>(vU16[3], vU16[3]+7), vector<int64_t>(vU16[3], vU16[3]+7) },
{ CV_16UC1, Size( 5, 5), Size(3, 3), 0, 0, vector<int64_t>(vU16[1], vU16[1]+3), vector<int64_t>(vU16[1], vU16[1]+3) },
{ CV_16UC1, Size( 5, 5), Size(5, 5), 0, 0, vector<int64_t>(vU16[2], vU16[2]+5), vector<int64_t>(vU16[2], vU16[2]+5) },
{ CV_16UC1, Size( 3, 5), Size(5, 5), 0, 0, vector<int64_t>(vU16[2], vU16[2]+5), vector<int64_t>(vU16[2], vU16[2]+5) },
{ CV_16UC1, Size( 5, 5), Size(5, 5), 0, 0, vector<int64_t>(vU16[2], vU16[2]+5), vector<int64_t>(vU16[2], vU16[2]+5) },
{ CV_16UC1, Size( 5, 5), Size(7, 7), 0, 0, vector<int64_t>(vU16[3], vU16[3]+7), vector<int64_t>(vU16[3], vU16[3]+7) },
{ CV_16UC1, Size( 7, 7), Size(7, 7), 0, 0, vector<int64_t>(vU16[3], vU16[3]+7), vector<int64_t>(vU16[3], vU16[3]+7) },
{ CV_16UC1, Size( 256, 128), Size(3, 3), 0, 0, vector<int64_t>(vU16[1], vU16[1]+3), vector<int64_t>(vU16[1], vU16[1]+3) },
{ CV_16UC2, Size( 256, 128), Size(3, 3), 0, 0, vector<int64_t>(vU16[1], vU16[1]+3), vector<int64_t>(vU16[1], vU16[1]+3) },
{ CV_16UC3, Size( 256, 128), Size(3, 3), 0, 0, vector<int64_t>(vU16[1], vU16[1]+3), vector<int64_t>(vU16[1], vU16[1]+3) },
{ CV_16UC4, Size( 256, 128), Size(3, 3), 0, 0, vector<int64_t>(vU16[1], vU16[1]+3), vector<int64_t>(vU16[1], vU16[1]+3) },
{ CV_16UC1, Size( 256, 128), Size(5, 5), 0, 0, vector<int64_t>(vU16[2], vU16[2]+5), vector<int64_t>(vU16[2], vU16[2]+5) },
{ CV_16UC1, Size( 256, 128), Size(7, 7), 0, 0, vector<int64_t>(vU16[3], vU16[3]+7), vector<int64_t>(vU16[3], vU16[3]+7) },
{ CV_16UC1, Size( 256, 128), Size(9, 9), 0, 0, vector<int64_t>(vU16[4], vU16[4]+9), vector<int64_t>(vU16[4], vU16[4]+9) },
};
for (int modeind = 0, _modecnt = sizeof(modes) / sizeof(modes[0]); modeind < _modecnt; ++modeind)
{
checkMode<16>(modes[modeind]);
}
}
TEST(GaussianBlur_Bitexact, regression_15015)
{
Mat src(100,100,CV_8UC3,Scalar(255,255,255));
Mat dst;
GaussianBlur(src, dst, Size(5, 5), 0);
ASSERT_EQ(0.0, cvtest::norm(dst, src, NORM_INF));
}
TEST(GaussianBlur_Bitexact, overflow_20121)
{
Mat src(100, 100, CV_16UC1, Scalar(65535));
Mat dst;
GaussianBlur(src, dst, cv::Size(9, 9), 0.0);
double min_val;
minMaxLoc(dst, &min_val);
ASSERT_EQ(cvRound(min_val), 65535);
}
static void checkGaussianBlur_8Uvs32F(const Mat& src8u, const Mat& src32f, int N, double sigma)
{
Mat dst8u; GaussianBlur(src8u, dst8u, Size(N, N), sigma); // through bit-exact path
Mat dst8u_32f; dst8u.convertTo(dst8u_32f, CV_32F);
Mat dst32f; GaussianBlur(src32f, dst32f, Size(N, N), sigma); // without bit-exact computations
double normINF_32f = cv::norm(dst8u_32f, dst32f, NORM_INF);
EXPECT_LE(normINF_32f, 1.0);
}
TEST(GaussianBlur_Bitexact, regression_9863)
{
Mat src8u = imread(cvtest::findDataFile("shared/lena.png"));
Mat src32f; src8u.convertTo(src32f, CV_32F);
checkGaussianBlur_8Uvs32F(src8u, src32f, 151, 30);
}
TEST(GaussianBlur_Bitexact, overflow_20792)
{
Mat src(128, 128, CV_16UC1, Scalar(255));
Mat dst;
double sigma = theRNG().uniform(0.0, 0.2); // a peaky kernel
GaussianBlur(src, dst, Size(7, 7), sigma, 0.9);
int count = (int)countNonZero(dst);
int nintyPercent = (int)(src.rows*src.cols * 0.9);
EXPECT_GT(count, nintyPercent);
}
CV_ENUM(GaussInputType, CV_8U, CV_16S);
CV_ENUM(GaussBorder, BORDER_CONSTANT, BORDER_REPLICATE, BORDER_REFLECT_101);
struct GaussianBlurVsBitexact: public testing::TestWithParam<tuple<GaussInputType, int, double, GaussBorder>>
{
virtual void SetUp()
{
orig = imread(findDataFile("shared/lena.png"));
EXPECT_FALSE(orig.empty()) << "Cannot find test image shared/lena.png";
}
Mat orig;
};
// NOTE: The test was designed for IPP (-DOPENCV_IPP_GAUSSIAN_BLUR=ON)
// Should be extended after new HAL integration
TEST_P(GaussianBlurVsBitexact, approx)
{
auto testParams = GetParam();
int dtype = get<0>(testParams);
int ksize = get<1>(testParams);
double sigma = get<2>(testParams);
int border = get<3>(testParams);
Mat src;
orig.convertTo(src, dtype);
cv::Mat gt;
GaussianBlur(src, gt, Size(ksize, ksize), sigma, sigma, border, ALGO_HINT_ACCURATE);
cv::Mat dst;
GaussianBlur(src, dst, Size(ksize, ksize), sigma, sigma, border, ALGO_HINT_APPROX);
EXPECT_LE(cvtest::norm(dst, gt, NORM_INF), 1);
EXPECT_LE(cvtest::norm(dst, gt, NORM_L1 | NORM_RELATIVE), 0.06); // Less 6% of different pixels
}
INSTANTIATE_TEST_CASE_P(/*nothing*/, GaussianBlurVsBitexact,
testing::Combine(
GaussInputType::all(),
testing::Values(3, 5, 7),
testing::Values(0.75, 1.25),
GaussBorder::all()
)
);
}} // namespace
+328
View File
@@ -0,0 +1,328 @@
// 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.
/*
StackBlur - a fast almost Gaussian Blur
Theory: http://underdestruction.com/2004/02/25/stackblur-2004
The code has been borrowed from (https://github.com/flozz/StackBlur).
Below is the original copyright
*/
/*
Copyright (c) 2010 Mario Klingemann
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
#include "test_precomp.hpp"
namespace opencv_test { namespace {
template<typename T>
void _stackblurRef(const Mat& src, Mat& dst, Size ksize)
{
CV_Assert(!src.empty());
CV_Assert(ksize.width > 0 && ksize.height > 0 && ksize.height % 2 == 1 && ksize.width % 2 == 1);
dst.create(src.size(), src.type());
const int CN = src.channels();
int rowsImg = src.rows;
int colsImg = src.cols;
int wm = colsImg - 1;
int radiusW = ksize.width / 2;
int stackLenW = ksize.width;
const float mulW = 1.0f / (((float )radiusW + 1.0f) * ((float )radiusW + 1.0f));
// Horizontal direction
std::vector<T> stack(stackLenW * CN);
for (int row = 0; row < rowsImg; row++)
{
std::vector<float> sum(CN, 0);
std::vector<float> sumIn(CN, 0);
std::vector<float> sumOut(CN, 0);
const T* srcPtr = src.ptr<T>(row);
for (int i = 0; i <= radiusW; i++)
{
for (int ci = 0; ci < CN; ci++)
{
T tmp = *(srcPtr + ci);
stack[i * CN + ci] = tmp;
sum[ci] += tmp * (i + 1);
sumOut[ci] += tmp;
}
}
for (int i = 1; i <= radiusW; i++)
{
if (i <= wm) srcPtr += CN;
for(int ci = 0; ci < CN; ci++)
{
T tmp = *(srcPtr + ci);
stack[(i + radiusW) * CN + ci] = tmp;
sum[ci] += tmp * (radiusW + 1 - i);
sumIn[ci] += tmp;
}
}
int sp = radiusW;
int xp = radiusW ;
if (xp > wm) xp = wm;
T* dstPtr = dst.ptr<T>(row);
srcPtr = src.ptr<T>(row) + xp * CN;
int stackStart= 0;
for (int i = 0; i < colsImg; i++)
{
stackStart = sp + stackLenW - radiusW;
if (stackStart >= stackLenW) stackStart -= stackLenW;
for(int ci = 0; ci < CN; ci++)
{
*(dstPtr + ci) = cv::saturate_cast<T>(sum[ci] * mulW);
sum[ci] -= sumOut[ci];
sumOut[ci] -= stack[stackStart*CN + ci];
}
const T* srcNew = srcPtr;
if(xp < wm)
srcNew += CN;
for (int ci = 0; ci < CN; ci++)
{
stack[stackStart * CN + ci] = *(srcNew + ci);
sumIn[ci] += *(srcNew + ci);
sum[ci] += sumIn[ci];
}
int sp1 = sp + 1;
if (sp1 >= stackLenW)
sp1 = 0;
for(int ci = 0; ci < CN; ci++)
{
T tmp = stack[sp1*CN + ci];
sumOut[ci] += tmp;
sumIn[ci] -= tmp;
}
dstPtr += CN;
if (xp < wm)
{
xp++;
srcPtr += CN;
}
++sp;
if (sp >= stackLenW)
sp = 0;
}
}
// Vertical direction
int hm = rowsImg - 1;
int widthElem = colsImg * CN;
int radiusH = ksize.height / 2;
int stackLenH = ksize.height;
const float mulH = 1.0f / (((float )radiusH + 1.0f) * ((float )radiusH + 1.0f));
stack.resize(stackLenH, 0);
for (int col = 0; col < widthElem; col++)
{
const T* srcPtr =dst.ptr<T>() + col;
float sum0 = 0;
float sumIn0 = 0;
float sumOut0 = 0;
for (int i = 0; i <= radiusH; i++)
{
T tmp = (T)(*srcPtr);
stack[i] = tmp;
sum0 += tmp * (i + 1);
sumOut0 += tmp;
}
for (int i = 1; i <= radiusH; i++)
{
if (i <= hm) srcPtr += widthElem;
T tmp = (T)(*srcPtr);
stack[i + radiusH] = tmp;
sum0 += tmp * (radiusH - i + 1);
sumIn0 += tmp;
}
int sp = radiusH;
int yp = radiusH;
if (yp > hm) yp = hm;
T* dstPtr = dst.ptr<T>() + col;
srcPtr = dst.ptr<T>(yp) + col;
const T* srcNew;
int stackStart = 0;
for (int i = 0; i < rowsImg; i++)
{
stackStart = sp + stackLenH - radiusH;
if (stackStart >= stackLenH) stackStart -= stackLenH;
*(dstPtr) = saturate_cast<T>(sum0 * mulH);
sum0 -= sumOut0;
sumOut0 -= stack[stackStart];
srcNew = srcPtr;
if (yp < hm)
srcNew += widthElem;
stack[stackStart] = *(srcNew);
sumIn0 += *(srcNew);
sum0 += sumIn0;
int sp1 = sp + 1;
sp1 &= -(sp1 < stackLenH);
sumOut0 += stack[sp1];
sumIn0 -= stack[sp1];
dstPtr += widthElem;
if (yp < hm)
{
yp++;
srcPtr += widthElem;
}
++sp;
if (sp >= stackLenH) sp = 0;
}
}
}
void stackBlurRef(const Mat& img, Mat& dst, Size ksize)
{
if(img.depth() == CV_8U)
_stackblurRef<uchar>(img, dst, ksize);
else if (img.depth() == CV_16S)
_stackblurRef<short>(img, dst, ksize);
else if (img.depth() == CV_16U)
_stackblurRef<ushort>(img, dst, ksize);
else if (img.depth() == CV_32F)
_stackblurRef<float>(img, dst, ksize);
else
CV_Error(Error::StsNotImplemented,
("Unsupported Mat type in stackBlurRef, "
"the supported formats are: CV_8U, CV_16U, CV_16S and CV_32F."));
}
std::vector<Size> kernelSizeVec = {
Size(3, 3),
Size(5, 5),
Size(101, 101),
Size(3, 9)
};
typedef testing::TestWithParam<tuple<int, int, int> > StackBlur;
TEST_P (StackBlur, regression)
{
Mat img_ = imread(findDataFile("shared/fruits.png"), 1);
const int cn = get<0>(GetParam());
const int kIndex = get<1>(GetParam());
const int dtype = get<2>(GetParam());
Size ksize = kernelSizeVec[kIndex];
Mat img, dstRef, dst;
convert(img_, img, dtype);
vector<Mat> channels;
split(img, channels);
channels.push_back(channels[0]); // channels size is 4.
Mat imgCn;
if (cn == 1)
imgCn = channels[0];
else if (cn == 4)
merge(channels, imgCn);
else
imgCn = img;
stackBlurRef(imgCn, dstRef, ksize);
stackBlur(imgCn, dst, ksize);
EXPECT_LE(cvtest::norm(dstRef, dst, NORM_INF), 2.);
}
INSTANTIATE_TEST_CASE_P(Imgproc, StackBlur,
testing::Combine(
testing::Values(1, 3, 4),
testing::Values(0, 1, 2, 3),
testing::Values(CV_8U, CV_16S, CV_16U, CV_32F)
)
);
typedef testing::TestWithParam<tuple<int> > StackBlur_GaussianBlur;
// StackBlur should produce similar results as GaussianBlur output.
TEST_P(StackBlur_GaussianBlur, compare)
{
Mat img_ = imread(findDataFile("shared/fruits.png"), 1);
const int dtype = get<0>(GetParam());
Size ksize(3, 3);
Mat img, dstS, dstG;
convert(img_, img, dtype);
stackBlur(img, dstS, ksize);
GaussianBlur(img, dstG, ksize, 0);
EXPECT_LE(cvtest::norm(dstS, dstG, NORM_INF), 13.);
}
INSTANTIATE_TEST_CASE_P(Imgproc, StackBlur_GaussianBlur, testing::Values(CV_8U, CV_16S, CV_16U, CV_32F));
TEST(Imgproc_StackBlur, regression_28233)
{
Mat src1(1, 1, CV_8UC1, Scalar(123));
Mat dst1;
EXPECT_NO_THROW(stackBlur(src1, dst1, Size(9, 1)));
EXPECT_EQ(dst1.at<uchar>(0, 0), 123);
Mat src2(3, 3, CV_8UC1, Scalar(50));
Mat dst2;
EXPECT_NO_THROW(stackBlur(src2, dst2, Size(11, 11)));
EXPECT_EQ(dst2.at<uchar>(1, 1), 50);
}
}
}
@@ -0,0 +1,17 @@
#include "test_precomp.hpp"
namespace opencv_test { namespace {
TEST(MorphShapes, getStructuringElementDiamond)
{
cv::Mat element = cv::getStructuringElement(cv::MORPH_DIAMOND, cv::Size(5,5));
cv::Mat expected = (cv::Mat_<uchar>(5,5) <<
0,0,1,0,0,
0,1,1,1,0,
1,1,1,1,1,
0,1,1,1,0,
0,0,1,0,0);
EXPECT_EQ(0, cvtest::norm(element, expected, cv::NORM_INF));
}
}} // namespace
+344
View File
@@ -0,0 +1,344 @@
/*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(Imgproc_MatchTemplate, bug_9597) {
const uint8_t img[] = {
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 246, 246, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 246, 246, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 246, 246, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 246, 246, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 246,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 246, 246, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 246, 246, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 246, 246, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 246, 246, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 247, 247, 247, 247, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 247, 247, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245};
const uint8_t tmpl[] = {
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245 };
cv::Mat cvimg(cv::Size(61, 82), CV_8UC1, (void*)img, cv::Mat::AUTO_STEP);
cv::Mat cvtmpl(cv::Size(17, 17), CV_8UC1, (void*)tmpl, cv::Mat::AUTO_STEP);
cv::Mat result;
cv::matchTemplate(cvimg, cvtmpl, result, cv::TM_SQDIFF);
double minValue;
cv::minMaxLoc(result, &minValue, NULL, NULL, NULL);
ASSERT_GE(minValue, 0);
}
//==============================================================================
static void matchTemplate_reference(Mat & img, Mat & templ, Mat & result, const int method)
{
CV_Assert(cv::TM_SQDIFF <= method && method <= cv::TM_CCOEFF_NORMED);
const Size res_sz(img.cols - templ.cols + 1, img.rows - templ.rows + 1);
result.create(res_sz, CV_32FC1);
const int depth = img.depth();
const int cn = img.channels();
const int area = templ.size().area();
const int width_n = templ.cols * cn;
const int height = templ.rows;
int a_step = (int)(img.step / img.elemSize1());
int b_step = (int)(templ.step / templ.elemSize1());
Scalar b_mean = Scalar::all(0);
Scalar b_sdv = Scalar::all(0);
cv::meanStdDev(templ, b_mean, b_sdv);
double b_sum2 = 0.;
for (int i = 0; i < cn; i++ )
b_sum2 += (b_sdv.val[i] * b_sdv.val[i] + b_mean.val[i] * b_mean.val[i]) * area;
if (b_sdv.val[0] * b_sdv.val[0] + b_sdv.val[1] * b_sdv.val[1] +
b_sdv.val[2] * b_sdv.val[2] + b_sdv.val[3] * b_sdv.val[3] < DBL_EPSILON &&
method == cv::TM_CCOEFF_NORMED)
{
result = Scalar::all(1.);
return;
}
double b_denom = 1.;
if (method & 1) // _NORMED
{
b_denom = 0;
if (method != cv::TM_CCOEFF_NORMED)
{
b_denom = b_sum2;
}
else
{
for (int i = 0; i < cn; i++)
b_denom += b_sdv.val[i] * b_sdv.val[i] * area;
}
b_denom = sqrt(b_denom);
if (b_denom == 0)
b_denom = 1.;
}
for (int i = 0; i < result.rows; i++)
{
for (int j = 0; j < result.cols; j++)
{
Scalar a_sum(0), a_sum2(0);
Scalar ccorr(0);
double value = 0.;
if (depth == CV_8U)
{
const uchar* a = img.ptr<uchar>(i, j); // ??? ->data.ptr + i*img->step + j*cn;
const uchar* b = templ.ptr<uchar>();
if( cn == 1 || method < cv::TM_CCOEFF )
{
for (int k = 0; k < height; k++, a += a_step, b += b_step)
for (int l = 0; l < width_n; l++)
{
ccorr.val[0] += a[l]*b[l];
a_sum.val[0] += a[l];
a_sum2.val[0] += a[l]*a[l];
}
}
else
{
for (int k = 0; k < height; k++, a += a_step, b += b_step)
for (int l = 0; l < width_n; l += 3)
{
ccorr.val[0] += a[l]*b[l];
ccorr.val[1] += a[l+1]*b[l+1];
ccorr.val[2] += a[l+2]*b[l+2];
a_sum.val[0] += a[l];
a_sum.val[1] += a[l+1];
a_sum.val[2] += a[l+2];
a_sum2.val[0] += a[l]*a[l];
a_sum2.val[1] += a[l+1]*a[l+1];
a_sum2.val[2] += a[l+2]*a[l+2];
}
}
}
else // CV_32F
{
const float* a = img.ptr<float>(i, j); // ???? (const float*)(img->data.ptr + i*img->step) + j*cn;
const float* b = templ.ptr<float>();
if( cn == 1 || method < cv::TM_CCOEFF )
{
for (int k = 0; k < height; k++, a += a_step, b += b_step)
for (int l = 0; l < width_n; l++)
{
ccorr.val[0] += a[l]*b[l];
a_sum.val[0] += a[l];
a_sum2.val[0] += a[l]*a[l];
}
}
else
{
for (int k = 0; k < height; k++, a += a_step, b += b_step)
for (int l = 0; l < width_n; l += 3)
{
ccorr.val[0] += a[l]*b[l];
ccorr.val[1] += a[l+1]*b[l+1];
ccorr.val[2] += a[l+2]*b[l+2];
a_sum.val[0] += a[l];
a_sum.val[1] += a[l+1];
a_sum.val[2] += a[l+2];
a_sum2.val[0] += a[l]*a[l];
a_sum2.val[1] += a[l+1]*a[l+1];
a_sum2.val[2] += a[l+2]*a[l+2];
}
}
}
switch( method )
{
case cv::TM_CCORR:
case cv::TM_CCORR_NORMED:
value = ccorr.val[0];
break;
case cv::TM_SQDIFF:
case cv::TM_SQDIFF_NORMED:
value = (a_sum2.val[0] + b_sum2 - 2*ccorr.val[0]);
break;
default:
value = (ccorr.val[0] - a_sum.val[0]*b_mean.val[0]+
ccorr.val[1] - a_sum.val[1]*b_mean.val[1]+
ccorr.val[2] - a_sum.val[2]*b_mean.val[2]);
}
if( method & 1 )
{
double denom;
// calc denominator
if( method != cv::TM_CCOEFF_NORMED )
{
denom = a_sum2.val[0] + a_sum2.val[1] + a_sum2.val[2];
}
else
{
denom = a_sum2.val[0] - (a_sum.val[0]*a_sum.val[0])/area;
denom += a_sum2.val[1] - (a_sum.val[1]*a_sum.val[1])/area;
denom += a_sum2.val[2] - (a_sum.val[2]*a_sum.val[2])/area;
}
denom = sqrt(MAX(denom,0))*b_denom;
if( fabs(value) < denom )
value /= denom;
else if( fabs(value) < denom*1.125 )
value = value > 0 ? 1 : -1;
else
value = method != cv::TM_SQDIFF_NORMED ? 0 : 1;
}
result.at<float>(i, j) = (float)value;
}
}
}
//==============================================================================
CV_ENUM(MatchModes, TM_SQDIFF, TM_SQDIFF_NORMED, TM_CCORR, TM_CCORR_NORMED, TM_CCOEFF, TM_CCOEFF_NORMED);
typedef testing::TestWithParam<testing::tuple<perf::MatDepth, int, MatchModes>> matchTemplate_Modes;
TEST_P(matchTemplate_Modes, accuracy)
{
const int data_type = CV_MAKE_TYPE(get<0>(GetParam()), get<1>(GetParam()));
const int method = get<2>(GetParam());
RNG & rng = TS::ptr()->get_rng();
for (int ITER = 0; ITER < 20; ++ITER)
{
SCOPED_TRACE(cv::format("iteration %d", ITER));
const Size imgSize(rng.uniform(128, 320), rng.uniform(128, 240));
const Size templSize(rng.uniform(1, 30), rng.uniform(1, 30));
Mat img(imgSize, data_type, Scalar::all(0));
Mat templ(templSize, data_type, Scalar::all(0));
cvtest::randUni(rng, img, Scalar::all(0), Scalar::all(255));
cvtest::randUni(rng, templ, Scalar::all(0), Scalar::all(255));
Mat result;
cv::matchTemplate(img, templ, result, method);
Mat reference;
matchTemplate_reference(img, templ, reference, method);
EXPECT_MAT_NEAR_RELATIVE(result, reference, 1e-3);
}
}
INSTANTIATE_TEST_CASE_P(/**/,
matchTemplate_Modes,
testing::Combine(
testing::Values(CV_8U, CV_32F),
testing::Values(1, 3),
testing::Values(TM_SQDIFF, TM_SQDIFF_NORMED, TM_CCORR, TM_CCORR_NORMED, TM_CCOEFF, TM_CCOEFF_NORMED)));
}} // namespace
@@ -0,0 +1,290 @@
// 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 {
CV_ENUM(MatchTemplType, cv::TM_CCORR, cv::TM_CCORR_NORMED,
cv::TM_SQDIFF, cv::TM_SQDIFF_NORMED,
cv::TM_CCOEFF, cv::TM_CCOEFF_NORMED)
class Imgproc_MatchTemplateWithMask : public TestWithParam<std::tuple<MatType,MatType>>
{
protected:
// Member functions inherited from ::testing::Test
void SetUp() override;
// Matrices for test calculations (always CV_32)
Mat img_;
Mat templ_;
Mat mask_;
Mat templ_masked_;
Mat img_roi_masked_;
// Matrices for call to matchTemplate (have test type)
Mat img_testtype_;
Mat templ_testtype_;
Mat mask_testtype_;
Mat result_;
// Constants
static const Size IMG_SIZE;
static const Size TEMPL_SIZE;
static const Point TEST_POINT;
};
// Arbitraryly chosen test constants
const Size Imgproc_MatchTemplateWithMask::IMG_SIZE(160, 100);
const Size Imgproc_MatchTemplateWithMask::TEMPL_SIZE(21, 13);
const Point Imgproc_MatchTemplateWithMask::TEST_POINT(8, 9);
void Imgproc_MatchTemplateWithMask::SetUp()
{
int type = std::get<0>(GetParam());
int type_mask = std::get<1>(GetParam());
// Matrices are created with the depth to test (for the call to matchTemplate()), but are also
// converted to CV_32 for the test calculations, because matchTemplate() also only operates on
// and returns CV_32.
img_testtype_.create(IMG_SIZE, type);
templ_testtype_.create(TEMPL_SIZE, type);
mask_testtype_.create(TEMPL_SIZE, type_mask);
randu(img_testtype_, 0, 10);
randu(templ_testtype_, 0, 10);
randu(mask_testtype_, 0, 5);
img_testtype_.convertTo(img_, CV_32F);
templ_testtype_.convertTo(templ_, CV_32F);
mask_testtype_.convertTo(mask_, CV_32F);
if (CV_MAT_DEPTH(type_mask) == CV_8U)
{
// CV_8U masks are interpreted as binary masks
mask_.setTo(Scalar::all(1), mask_ != 0);
}
if (mask_.channels() != templ_.channels())
{
std::vector<Mat> mask_channels(templ_.channels(), mask_);
merge(mask_channels.data(), templ_.channels(), mask_);
}
Rect roi(TEST_POINT, TEMPL_SIZE);
img_roi_masked_ = img_(roi).mul(mask_);
templ_masked_ = templ_.mul(mask_);
}
TEST_P(Imgproc_MatchTemplateWithMask, CompareNaiveImplSQDIFF)
{
matchTemplate(img_testtype_, templ_testtype_, result_, cv::TM_SQDIFF, mask_testtype_);
// Naive implementation for one point
Mat temp = img_roi_masked_ - templ_masked_;
Scalar temp_s = sum(temp.mul(temp));
double val = temp_s[0] + temp_s[1] + temp_s[2] + temp_s[3];
EXPECT_NEAR(val, result_.at<float>(TEST_POINT), TEMPL_SIZE.area()*abs(val)*FLT_EPSILON);
}
TEST_P(Imgproc_MatchTemplateWithMask, CompareNaiveImplSQDIFF_NORMED)
{
matchTemplate(img_testtype_, templ_testtype_, result_, cv::TM_SQDIFF_NORMED, mask_testtype_);
// Naive implementation for one point
Mat temp = img_roi_masked_ - templ_masked_;
Scalar temp_s = sum(temp.mul(temp));
double val = temp_s[0] + temp_s[1] + temp_s[2] + temp_s[3];
// Normalization
temp_s = sum(templ_masked_.mul(templ_masked_));
double norm = temp_s[0] + temp_s[1] + temp_s[2] + temp_s[3];
temp_s = sum(img_roi_masked_.mul(img_roi_masked_));
norm *= temp_s[0] + temp_s[1] + temp_s[2] + temp_s[3];
norm = sqrt(norm);
val /= norm;
EXPECT_NEAR(val, result_.at<float>(TEST_POINT), TEMPL_SIZE.area()*abs(val)*FLT_EPSILON);
}
TEST_P(Imgproc_MatchTemplateWithMask, CompareNaiveImplCCORR)
{
matchTemplate(img_testtype_, templ_testtype_, result_, cv::TM_CCORR, mask_testtype_);
// Naive implementation for one point
Scalar temp_s = sum(templ_masked_.mul(img_roi_masked_));
double val = temp_s[0] + temp_s[1] + temp_s[2] + temp_s[3];
EXPECT_NEAR(val, result_.at<float>(TEST_POINT), TEMPL_SIZE.area()*abs(val)*FLT_EPSILON);
}
TEST_P(Imgproc_MatchTemplateWithMask, CompareNaiveImplCCORR_NORMED)
{
matchTemplate(img_testtype_, templ_testtype_, result_, cv::TM_CCORR_NORMED, mask_testtype_);
// Naive implementation for one point
Scalar temp_s = sum(templ_masked_.mul(img_roi_masked_));
double val = temp_s[0] + temp_s[1] + temp_s[2] + temp_s[3];
// Normalization
temp_s = sum(templ_masked_.mul(templ_masked_));
double norm = temp_s[0] + temp_s[1] + temp_s[2] + temp_s[3];
temp_s = sum(img_roi_masked_.mul(img_roi_masked_));
norm *= temp_s[0] + temp_s[1] + temp_s[2] + temp_s[3];
norm = sqrt(norm);
val /= norm;
EXPECT_NEAR(val, result_.at<float>(TEST_POINT), TEMPL_SIZE.area()*abs(val)*FLT_EPSILON);
}
TEST_P(Imgproc_MatchTemplateWithMask, CompareNaiveImplCCOEFF)
{
matchTemplate(img_testtype_, templ_testtype_, result_, cv::TM_CCOEFF, mask_testtype_);
// Naive implementation for one point
Scalar temp_s = sum(mask_);
for (int i = 0; i < 4; i++)
{
if (temp_s[i] != 0.0)
temp_s[i] = 1.0 / temp_s[i];
else
temp_s[i] = 1.0;
}
Mat temp = mask_.clone(); temp = temp_s; // Workaround to multiply Mat by Scalar
Mat temp2 = mask_.clone(); temp2 = sum(templ_masked_); // Workaround to multiply Mat by Scalar
Mat templx = templ_masked_ - mask_.mul(temp).mul(temp2);
temp2 = sum(img_roi_masked_); // Workaround to multiply Mat by Scalar
Mat imgx = img_roi_masked_ - mask_.mul(temp).mul(temp2);
temp_s = sum(templx.mul(imgx));
double val = temp_s[0] + temp_s[1] + temp_s[2] + temp_s[3];
EXPECT_NEAR(val, result_.at<float>(TEST_POINT), TEMPL_SIZE.area()*abs(val)*FLT_EPSILON);
}
TEST_P(Imgproc_MatchTemplateWithMask, CompareNaiveImplCCOEFF_NORMED)
{
matchTemplate(img_testtype_, templ_testtype_, result_, cv::TM_CCOEFF_NORMED, mask_testtype_);
// Naive implementation for one point
Scalar temp_s = sum(mask_);
for (int i = 0; i < 4; i++)
{
if (temp_s[i] != 0.0)
temp_s[i] = 1.0 / temp_s[i];
else
temp_s[i] = 1.0;
}
Mat temp = mask_.clone(); temp = temp_s; // Workaround to multiply Mat by Scalar
Mat temp2 = mask_.clone(); temp2 = sum(templ_masked_); // Workaround to multiply Mat by Scalar
Mat templx = templ_masked_ - mask_.mul(temp).mul(temp2);
temp2 = sum(img_roi_masked_); // Workaround to multiply Mat by Scalar
Mat imgx = img_roi_masked_ - mask_.mul(temp).mul(temp2);
temp_s = sum(templx.mul(imgx));
double val = temp_s[0] + temp_s[1] + temp_s[2] + temp_s[3];
// Normalization
temp_s = sum(templx.mul(templx));
double norm = temp_s[0] + temp_s[1] + temp_s[2] + temp_s[3];
temp_s = sum(imgx.mul(imgx));
norm *= temp_s[0] + temp_s[1] + temp_s[2] + temp_s[3];
norm = sqrt(norm);
val /= norm;
EXPECT_NEAR(val, result_.at<float>(TEST_POINT), TEMPL_SIZE.area()*abs(val)*FLT_EPSILON);
}
INSTANTIATE_TEST_CASE_P(SingleChannelMask, Imgproc_MatchTemplateWithMask,
Combine(
Values(CV_32FC1, CV_32FC3, CV_8UC1, CV_8UC3),
Values(CV_32FC1, CV_8UC1)));
INSTANTIATE_TEST_CASE_P(MultiChannelMask, Imgproc_MatchTemplateWithMask,
Combine(
Values(CV_32FC3, CV_8UC3),
Values(CV_32FC3, CV_8UC3)));
class Imgproc_MatchTemplateWithMask2 : public TestWithParam<std::tuple<MatType,MatType,
MatchTemplType>>
{
protected:
// Member functions inherited from ::testing::Test
void SetUp() override;
// Data members
Mat img_;
Mat templ_;
Mat mask_;
Mat result_withoutmask_;
Mat result_withmask_;
// Constants
static const Size IMG_SIZE;
static const Size TEMPL_SIZE;
};
// Arbitraryly chosen test constants
const Size Imgproc_MatchTemplateWithMask2::IMG_SIZE(160, 100);
const Size Imgproc_MatchTemplateWithMask2::TEMPL_SIZE(21, 13);
void Imgproc_MatchTemplateWithMask2::SetUp()
{
int type = std::get<0>(GetParam());
int type_mask = std::get<1>(GetParam());
img_.create(IMG_SIZE, type);
templ_.create(TEMPL_SIZE, type);
mask_.create(TEMPL_SIZE, type_mask);
randu(img_, 0, 100);
randu(templ_, 0, 100);
if (CV_MAT_DEPTH(type_mask) == CV_8U)
{
// CV_8U implies binary mask, so all nonzero values should work
randu(mask_, 1, 255);
}
else
{
mask_ = Scalar(1, 1, 1, 1);
}
}
TEST_P(Imgproc_MatchTemplateWithMask2, CompareWithAndWithoutMask)
{
int method = std::get<2>(GetParam());
matchTemplate(img_, templ_, result_withmask_, method, mask_);
matchTemplate(img_, templ_, result_withoutmask_, method);
// Get maximum result for relative error calculation
double min_val, max_val;
minMaxLoc(abs(result_withmask_), &min_val, &max_val);
// Get maximum of absolute diff for comparison
double mindiff, maxdiff;
minMaxLoc(abs(result_withmask_ - result_withoutmask_), &mindiff, &maxdiff);
EXPECT_LT(maxdiff, max_val*TEMPL_SIZE.area()*FLT_EPSILON);
}
INSTANTIATE_TEST_CASE_P(SingleChannelMask, Imgproc_MatchTemplateWithMask2,
Combine(
Values(CV_32FC1, CV_32FC3, CV_8UC1, CV_8UC3),
Values(CV_32FC1, CV_8UC1),
Values(cv::TM_SQDIFF, cv::TM_SQDIFF_NORMED, cv::TM_CCORR, cv::TM_CCORR_NORMED,
cv::TM_CCOEFF, cv::TM_CCOEFF_NORMED)));
INSTANTIATE_TEST_CASE_P(MultiChannelMask, Imgproc_MatchTemplateWithMask2,
Combine(
Values(CV_32FC3, CV_8UC3),
Values(CV_32FC3, CV_8UC3),
Values(cv::TM_SQDIFF, cv::TM_SQDIFF_NORMED, cv::TM_CCORR, cv::TM_CCORR_NORMED,
cv::TM_CCOEFF, cv::TM_CCOEFF_NORMED)));
TEST(Imgproc_MatchTemplateWithMask, bug_26389) {
const Mat image = Mat::ones(Size(10, 10), CV_8UC1);
const Mat templ = Mat::ones(Size(10, 7), CV_8UC1);
const Mat mask = Mat::ones(Size(10, 7), CV_8UC1);
for (const int method : {TM_CCOEFF, TM_CCOEFF_NORMED})
{
Mat result;
matchTemplate(image, templ, result, method, mask);
}
}
}} // namespace
+264
View File
@@ -0,0 +1,264 @@
/*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 {
BIGDATA_TEST(Imgproc_Threshold, huge)
{
Mat m(65000, 40000, CV_8U);
ASSERT_FALSE(m.isContinuous());
uint64 i, n = (uint64)m.rows*m.cols;
for( i = 0; i < n; i++ )
m.data[i] = (uchar)(i & 255);
cv::threshold(m, m, 127, 255, cv::THRESH_BINARY);
int nz = cv::countNonZero(m); // FIXIT 'int' is not enough here (overflow is possible with other inputs)
ASSERT_EQ((uint64)nz, n / 2);
}
TEST(Imgproc_Threshold, threshold_dryrun)
{
Size sz(16, 16);
Mat input_original(sz, CV_8U, Scalar::all(2));
Mat input = input_original.clone();
std::vector<int> threshTypes = {THRESH_BINARY, THRESH_BINARY_INV, THRESH_TRUNC, THRESH_TOZERO, THRESH_TOZERO_INV};
std::vector<int> threshFlags = {0, THRESH_OTSU, THRESH_TRIANGLE};
for(int threshType : threshTypes)
{
for(int threshFlag : threshFlags)
{
const int _threshType = threshType | threshFlag | THRESH_DRYRUN;
cv::threshold(input, input, 2.0, 0.0, _threshType);
EXPECT_MAT_NEAR(input, input_original, 0);
}
}
}
typedef tuple < bool, int, int, int, int > Imgproc_Threshold_Masked_Params_t;
typedef testing::TestWithParam< Imgproc_Threshold_Masked_Params_t > Imgproc_Threshold_Masked_Fixed;
TEST_P(Imgproc_Threshold_Masked_Fixed, threshold_mask_fixed)
{
bool useROI = get<0>(GetParam());
int depth = get<1>(GetParam());
int cn = get<2>(GetParam());
int threshType = get<3>(GetParam());
int threshFlag = get<4>(GetParam());
const int _threshType = threshType | threshFlag;
Size sz(127, 127);
Size wrapperSize = useROI ? Size(sz.width+4, sz.height+4) : sz;
Mat wrapper(wrapperSize, CV_MAKETYPE(depth, cn));
Mat input = useROI ? Mat(wrapper, Rect(Point(), sz)) : wrapper;
cv::randu(input, cv::Scalar::all(0), cv::Scalar::all(255));
Mat mask = cv::Mat::zeros(sz, CV_8UC1);
cv::RotatedRect ellipseRect((cv::Point2f)cv::Point(sz.width/2, sz.height/2), (cv::Size2f)sz, 0);
cv::ellipse(mask, ellipseRect, cv::Scalar::all(255), cv::FILLED);//for very different mask alignments
Mat output_with_mask = cv::Mat::zeros(sz, input.type());
cv::thresholdWithMask(input, output_with_mask, mask, 127, 255, _threshType);
cv::bitwise_not(mask, mask);
input.copyTo(output_with_mask, mask);
Mat output_without_mask;
cv::threshold(input, output_without_mask, 127, 255, _threshType);
input.copyTo(output_without_mask, mask);
EXPECT_MAT_NEAR(output_with_mask, output_without_mask, 0);
}
INSTANTIATE_TEST_CASE_P(/*nothing*/, Imgproc_Threshold_Masked_Fixed,
testing::Combine(
testing::Values(false, true),//use roi
testing::Values(CV_8U, CV_16U, CV_16S, CV_32F, CV_64F),//depth
testing::Values(1, 3),//channels
testing::Values(THRESH_BINARY, THRESH_BINARY_INV, THRESH_TRUNC, THRESH_TOZERO, THRESH_TOZERO_INV),// threshTypes
testing::Values(0)
)
);
typedef testing::TestWithParam< Imgproc_Threshold_Masked_Params_t > Imgproc_Threshold_Masked_Auto;
TEST_P(Imgproc_Threshold_Masked_Auto, threshold_mask_auto)
{
bool useROI = get<0>(GetParam());
int depth = get<1>(GetParam());
int cn = get<2>(GetParam());
int threshType = get<3>(GetParam());
int threshFlag = get<4>(GetParam());
if (threshFlag == THRESH_TRIANGLE && depth != CV_8U)
throw SkipTestException("THRESH_TRIANGLE option supports CV_8UC1 input only");
const int _threshType = threshType | threshFlag;
Size sz(127, 127);
Size wrapperSize = useROI ? Size(sz.width+4, sz.height+4) : sz;
Mat wrapper(wrapperSize, CV_MAKETYPE(depth, cn));
Mat input = useROI ? Mat(wrapper, Rect(Point(), sz)) : wrapper;
cv::randu(input, cv::Scalar::all(0), cv::Scalar::all(255));
//for OTSU and TRIANGLE, we use a rectangular mask that can be just cropped
//in order to compute the threshold of the non-masked version
Mat mask = cv::Mat::zeros(sz, CV_8UC1);
cv::Rect roiRect(sz.width/4, sz.height/4, sz.width/2, sz.height/2);
cv::rectangle(mask, roiRect, cv::Scalar::all(255), cv::FILLED);
Mat output_with_mask = cv::Mat::zeros(sz, input.type());
const double autoThreshWithMask = cv::thresholdWithMask(input, output_with_mask, mask, 127, 255, _threshType);
output_with_mask = Mat(output_with_mask, roiRect);
Mat output_without_mask;
const double autoThresholdWithoutMask = cv::threshold(Mat(input, roiRect), output_without_mask, 127, 255, _threshType);
ASSERT_EQ(autoThreshWithMask, autoThresholdWithoutMask);
EXPECT_MAT_NEAR(output_with_mask, output_without_mask, 0);
}
INSTANTIATE_TEST_CASE_P(/*nothing*/, Imgproc_Threshold_Masked_Auto,
testing::Combine(
testing::Values(false, true),//use roi
testing::Values(CV_8U, CV_16U),//depth
testing::Values(1),//channels
testing::Values(THRESH_BINARY, THRESH_BINARY_INV, THRESH_TRUNC, THRESH_TOZERO, THRESH_TOZERO_INV),// threshTypes
testing::Values(THRESH_OTSU, THRESH_TRIANGLE)
)
);
TEST(Imgproc_Threshold, regression_THRESH_TOZERO_IPP_16085)
{
Size sz(16, 16);
Mat input(sz, CV_32F, Scalar::all(2));
Mat result;
cv::threshold(input, result, 2.0, 0.0, THRESH_TOZERO);
EXPECT_EQ(0, cv::norm(result, NORM_INF));
}
TEST(Imgproc_Threshold, regression_THRESH_TOZERO_IPP_21258)
{
Size sz(16, 16);
float val = nextafterf(16.0f, 0.0f); // 0x417fffff, all bits in mantissa are 1
Mat input(sz, CV_32F, Scalar::all(val));
Mat result;
cv::threshold(input, result, val, 0.0, THRESH_TOZERO);
EXPECT_EQ(0, cv::norm(result, NORM_INF));
}
TEST(Imgproc_Threshold, regression_THRESH_TOZERO_IPP_21258_Min)
{
Size sz(16, 16);
float min_val = -std::numeric_limits<float>::max();
Mat input(sz, CV_32F, Scalar::all(min_val));
Mat result;
cv::threshold(input, result, min_val, 0.0, THRESH_TOZERO);
EXPECT_EQ(0, cv::norm(result, NORM_INF));
}
TEST(Imgproc_Threshold, regression_THRESH_TOZERO_IPP_21258_Max)
{
Size sz(16, 16);
float max_val = std::numeric_limits<float>::max();
Mat input(sz, CV_32F, Scalar::all(max_val));
Mat result;
cv::threshold(input, result, max_val, 0.0, THRESH_TOZERO);
EXPECT_EQ(0, cv::norm(result, NORM_INF));
}
TEST(Imgproc_AdaptiveThreshold, mean)
{
const string input_path = cvtest::findDataFile("../cv/shared/baboon.png");
Mat input = imread(input_path, IMREAD_GRAYSCALE);
Mat result;
cv::adaptiveThreshold(input, result, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 15, 8);
const string gt_path = cvtest::findDataFile("../cv/imgproc/adaptive_threshold1.png");
Mat gt = imread(gt_path, IMREAD_GRAYSCALE);
EXPECT_EQ(0, cv::norm(result, gt, NORM_INF));
}
TEST(Imgproc_AdaptiveThreshold, mean_inv)
{
const string input_path = cvtest::findDataFile("../cv/shared/baboon.png");
Mat input = imread(input_path, IMREAD_GRAYSCALE);
Mat result;
cv::adaptiveThreshold(input, result, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, 15, 8);
const string gt_path = cvtest::findDataFile("../cv/imgproc/adaptive_threshold1.png");
Mat gt = imread(gt_path, IMREAD_GRAYSCALE);
gt = Mat(gt.rows, gt.cols, CV_8UC1, cv::Scalar(255)) - gt;
EXPECT_EQ(0, cv::norm(result, gt, NORM_INF));
}
TEST(Imgproc_AdaptiveThreshold, gauss)
{
const string input_path = cvtest::findDataFile("../cv/shared/baboon.png");
Mat input = imread(input_path, IMREAD_GRAYSCALE);
Mat result;
cv::adaptiveThreshold(input, result, 200, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 21, -5);
const string gt_path = cvtest::findDataFile("../cv/imgproc/adaptive_threshold2.png");
Mat gt = imread(gt_path, IMREAD_GRAYSCALE);
EXPECT_EQ(0, cv::norm(result, gt, NORM_INF));
}
TEST(Imgproc_AdaptiveThreshold, gauss_inv)
{
const string input_path = cvtest::findDataFile("../cv/shared/baboon.png");
Mat input = imread(input_path, IMREAD_GRAYSCALE);
Mat result;
cv::adaptiveThreshold(input, result, 200, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY_INV, 21, -5);
const string gt_path = cvtest::findDataFile("../cv/imgproc/adaptive_threshold2.png");
Mat gt = imread(gt_path, IMREAD_GRAYSCALE);
gt = Mat(gt.rows, gt.cols, CV_8UC1, cv::Scalar(200)) - gt;
EXPECT_EQ(0, cv::norm(result, gt, NORM_INF));
}
}} // namespace
+43
View File
@@ -0,0 +1,43 @@
/*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"