diff --git a/modules/photo/perf/perf_denoising.cpp b/modules/photo/perf/perf_denoising.cpp new file mode 100644 index 0000000000..3e7b3b88e1 --- /dev/null +++ b/modules/photo/perf/perf_denoising.cpp @@ -0,0 +1,34 @@ +// 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 "perf_precomp.hpp" + +namespace opencv_test +{ + +typedef perf::TestBaseWithParam Size_Denoising; + +PERF_TEST_P(Size_Denoising, fastNlMeansDenoising, + testing::Values(::perf::szVGA, ::perf::sz720p, Size(2592, 1944))) +{ + const Size size = GetParam(); + + Mat original = imread(getDataPath("cv/denoising/lena_noised_gaussian_sigma=10.png"), + IMREAD_GRAYSCALE); + ASSERT_FALSE(original.empty()) << "Could not load input image"; + + Mat tiled; + repeat(original, (size.height + original.rows - 1) / original.rows, + (size.width + original.cols - 1) / original.cols, tiled); + Mat src = tiled(Rect(0, 0, size.width, size.height)).clone(); + Mat dst(size, CV_8UC1); + + declare.in(src).out(dst).time(120); + + TEST_CYCLE() cv::fastNlMeansDenoising(src, dst, 10, 7, 21); + + SANITY_CHECK_NOTHING(); +} + +} // namespace diff --git a/modules/photo/test/test_denoising.cpp b/modules/photo/test/test_denoising.cpp index 2e57369171..2c3159cf2d 100644 --- a/modules/photo/test/test_denoising.cpp +++ b/modules/photo/test/test_denoising.cpp @@ -154,17 +154,6 @@ TEST(Photo_White, issue_2646) ASSERT_EQ(0, nonWhitePixelsCount); } -TEST(Photo_Denoising, speed) -{ - string imgname = string(cvtest::TS::ptr()->get_data_path()) + "shared/5MP.png"; - Mat src = imread(imgname, IMREAD_GRAYSCALE), dst; - - double t = (double)getTickCount(); - fastNlMeansDenoising(src, dst, 5, 7, 21); - t = (double)getTickCount() - t; - printf("execution time: %gms\n", t*1000./getTickFrequency()); -} - // Related issue : https://github.com/opencv/opencv/issues/26582 TEST(Photo_DenoisingGrayscaleMulti16bitL1, regression) { diff --git a/modules/ptcloud/src/plane.cpp b/modules/ptcloud/src/plane.cpp index 70d449d374..510c69439d 100644 --- a/modules/ptcloud/src/plane.cpp +++ b/modules/ptcloud/src/plane.cpp @@ -475,6 +475,29 @@ private: //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static void toPaddedVec4f(const Mat& src, Mat_& dst) +{ + Mat src32; + if (src.depth() == CV_32F) + src32 = src; + else + src.convertTo(src32, CV_32F); + + CV_Assert(src32.channels() == 3 || src32.channels() == 4); + + if (src32.channels() == 4) + { + dst = src32; + return; + } + + dst.create(src32.rows, src32.cols); + dst.setTo(Scalar::all(0)); + int from_to[] = { 0, 0, 1, 1, 2, 2 }; + Mat dstMat = dst; + mixChannels(&src32, 1, &dstMat, 1, from_to, 3); +} + void findPlanes(InputArray points3d_in, InputArray normals_in, OutputArray mask_out, OutputArray plane_coefficients_out, int block_size, int min_size, double threshold, double sensor_error_a, double sensor_error_b, double sensor_error_c, RgbdPlaneMethod method) @@ -482,17 +505,9 @@ void findPlanes(InputArray points3d_in, InputArray normals_in, OutputArray mask_ CV_Assert(method == RGBD_PLANE_METHOD_DEFAULT); Mat_ points3d, normals; - if (points3d_in.depth() == CV_32F) - points3d = points3d_in.getMat(); - else - points3d_in.getMat().convertTo(points3d, CV_32F); + toPaddedVec4f(points3d_in.getMat(), points3d); if (!normals_in.empty()) - { - if (normals_in.depth() == CV_32F) - normals = normals_in.getMat(); - else - normals_in.getMat().convertTo(normals, CV_32F); - } + toPaddedVec4f(normals_in.getMat(), normals); // Pre-computations mask_out.create(points3d.size(), CV_8U); diff --git a/modules/ptcloud/test/test_normal.cpp b/modules/ptcloud/test/test_normal.cpp index 582f131367..e0eca51700 100644 --- a/modules/ptcloud/test/test_normal.cpp +++ b/modules/ptcloud/test/test_normal.cpp @@ -722,4 +722,36 @@ TEST(RGBD_Plane, regression2309ValgrindCheck) findPlanes(points, noArray(), mask, planes, blockSize); } +TEST(RGBD_Plane, regression_3channel_matches_4channel) +{ + const int rows = 240, cols = 320; + + Mat points3(rows, cols, CV_32FC3); + Mat points4(rows, cols, CV_32FC4); + for (int v = 0; v < rows; v++) + { + for (int u = 0; u < cols; u++) + { + const float z = 2.f + 0.001f * u + 0.002f * v; + const Vec3f p((float)u * 0.01f, (float)v * 0.01f, z); + points3.at(v, u) = p; + points4.at(v, u) = Vec4f(p[0], p[1], p[2], 0.f); + } + } + + Mat mask3, mask4; + std::vector planes3, planes4; + findPlanes(points3, noArray(), mask3, planes3); + findPlanes(points4, noArray(), mask4, planes4); + + EXPECT_EQ(points3.size(), mask3.size()); + EXPECT_EQ(CV_8U, mask3.type()); + + ASSERT_EQ(mask4.size(), mask3.size()); + EXPECT_EQ(0, cv::countNonZero(mask3 != mask4)); + ASSERT_EQ(planes4.size(), planes3.size()); + for (size_t i = 0; i < planes3.size(); i++) + EXPECT_LE(cv::norm(planes3[i], planes4[i], NORM_INF), 1e-6) << "plane " << i; +} + }} // namespace diff --git a/modules/ptcloud/test/test_pointcloud_io.cpp b/modules/ptcloud/test/test_pointcloud_io.cpp index 4dbf2e3eb2..847de4ad3a 100644 --- a/modules/ptcloud/test/test_pointcloud_io.cpp +++ b/modules/ptcloud/test/test_pointcloud_io.cpp @@ -289,12 +289,35 @@ TEST(PointCloud, LoadBadExtension) } TEST(PointCloud, SaveBadExtension) +{ + std::vector points { cv::Point3f(1.f, 2.f, 3.f) }; + std::vector normals; + + std::string new_path = tempfile("new.fake"); + + cv::savePointCloud(new_path, points, normals); + + std::ifstream f(new_path.c_str()); + EXPECT_FALSE(f.good()) + << "savePointCloud() created a file for an unsupported extension: " << new_path; + f.close(); + std::remove(new_path.c_str()); +} + +TEST(PointCloud, SaveEmptyVertices) { std::vector points; std::vector normals; - auto folder = cvtest::TS::ptr()->get_data_path(); - cv::savePointCloud(folder + "pointcloudio/fake.fake", points, normals); + std::string new_path = tempfile("new_empty.ply"); + + cv::savePointCloud(new_path, points, normals); + + std::ifstream f(new_path.c_str()); + EXPECT_FALSE(f.good()) + << "savePointCloud() created a file for an empty vertex set: " << new_path; + f.close(); + std::remove(new_path.c_str()); } TEST(PointCloud, LoadPlyEmptyFormatLine) diff --git a/modules/ptcloud/test/test_tsdf.cpp b/modules/ptcloud/test/test_tsdf.cpp index 36b91dc928..5a69369598 100644 --- a/modules/ptcloud/test/test_tsdf.cpp +++ b/modules/ptcloud/test/test_tsdf.cpp @@ -732,9 +732,26 @@ void hugeSceneGrowthTest(VolumeType volumeType) debugVolumeDraw(volume, poses[0], depth, depthFactor, "pts.obj"); } + if (volumeType == VolumeType::ColorHashTSDF) + { + EXPECT_GT(volume.getTotalVolumeUnits(), size_t(8192)) + << "the scene no longer exceeds the initial volume unit capacity, so this " + "test no longer covers hash volume growth"; + } + + Vec6f bb; + volume.getBoundingBox(bb, Volume::BoundingBoxPrecision::VOLUME_UNIT); + EXPECT_GT(bb[3], bb[0]) << "bounding box = " << bb; + EXPECT_GT(bb[4], bb[1]) << "bounding box = " << bb; + EXPECT_GT(bb[5], bb[2]) << "bounding box = " << bb; + // Reset check volume.reset(); + Vec6f bbReset; + volume.getBoundingBox(bbReset, Volume::BoundingBoxPrecision::VOLUME_UNIT); + EXPECT_LE(std::sqrt(bbReset.ddot(bbReset)), std::numeric_limits::epsilon()) + << "bounding box after reset() = " << bbReset; }