diff --git a/modules/stitching/perf/perf_stich.cpp b/modules/stitching/perf/perf_stich.cpp index 75fb93fea9..22fb3e35e6 100644 --- a/modules/stitching/perf/perf_stich.cpp +++ b/modules/stitching/perf/perf_stich.cpp @@ -13,6 +13,7 @@ using namespace perf; #define WORK_MEGAPIX 0.6 typedef TestBaseWithParam stitch; +typedef TestBaseWithParam stitchExposureCompensation; typedef TestBaseWithParam > stitchDatasets; #ifdef HAVE_OPENCV_XFEATURES2D @@ -20,6 +21,7 @@ typedef TestBaseWithParam > stitchDatasets; #else #define TEST_DETECTORS testing::Values("orb", "akaze") #endif +#define TEST_EXP_COMP_BS testing::Values(32, 16, 12, 10, 8) #define AFFINE_DATASETS testing::Values("s", "budapest", "newspaper", "prague") PERF_TEST_P(stitch, a123, TEST_DETECTORS) @@ -58,6 +60,38 @@ PERF_TEST_P(stitch, a123, TEST_DETECTORS) SANITY_CHECK_NOTHING(); } +PERF_TEST_P(stitchExposureCompensation, a123, TEST_EXP_COMP_BS) +{ + Mat pano; + + vector imgs; + imgs.push_back( imread( getDataPath("stitching/a1.png") ) ); + imgs.push_back( imread( getDataPath("stitching/a2.png") ) ); + imgs.push_back( imread( getDataPath("stitching/a3.png") ) ); + + int bs = GetParam(); + + declare.time(30 * 10).iterations(10); + + while(next()) + { + Ptr stitcher = Stitcher::create(); + stitcher->setWarper(makePtr()); + stitcher->setRegistrationResol(WORK_MEGAPIX); + stitcher->setExposureCompensator( + makePtr(bs, bs)); + + startTimer(); + stitcher->stitch(imgs, pano); + stopTimer(); + } + + EXPECT_NEAR(pano.size().width, 1182, 50); + EXPECT_NEAR(pano.size().height, 682, 30); + + SANITY_CHECK_NOTHING(); +} + PERF_TEST_P(stitch, b12, TEST_DETECTORS) { Mat pano; diff --git a/modules/stitching/src/exposure_compensate.cpp b/modules/stitching/src/exposure_compensate.cpp index 7b72efbd16..2488684912 100644 --- a/modules/stitching/src/exposure_compensate.cpp +++ b/modules/stitching/src/exposure_compensate.cpp @@ -41,6 +41,10 @@ //M*/ #include "precomp.hpp" +#ifdef HAVE_EIGEN +#include +#include +#endif namespace cv { namespace detail { @@ -80,6 +84,7 @@ void GainCompensator::feed(const std::vector &corners, const std::vector< const int num_images = static_cast(images.size()); Mat_ N(num_images, num_images); N.setTo(0); Mat_ I(num_images, num_images); I.setTo(0); + Mat_ skip(num_images, 1); skip.setTo(true); //Rect dst_roi = resultRoi(corners, images); Mat subimg1, subimg2; @@ -99,7 +104,19 @@ void GainCompensator::feed(const std::vector &corners, const std::vector< submask2 = masks[j].first(Rect(roi.tl() - corners[j], roi.br() - corners[j])).getMat(ACCESS_READ); intersect = (submask1 == masks[i].second) & (submask2 == masks[j].second); - N(i, j) = N(j, i) = std::max(1, countNonZero(intersect)); + int intersect_count = countNonZero(intersect); + N(i, j) = N(j, i) = std::max(1, intersect_count); + + // Don't compute Isums if subimages do not intersect anyway + if (intersect_count == 0) + continue; + + // Don't skip images that intersect with at least one other image + if (i != j) + { + skip(i, 0) = false; + skip(j, 0) = false; + } double Isum1 = 0, Isum2 = 0; for (int y = 0; y < roi.height; ++y) @@ -123,22 +140,59 @@ void GainCompensator::feed(const std::vector &corners, const std::vector< double alpha = 0.01; double beta = 100; + int num_eq = num_images - countNonZero(skip); - Mat_ A(num_images, num_images); A.setTo(0); - Mat_ b(num_images, 1); b.setTo(0); - for (int i = 0; i < num_images; ++i) + Mat_ A(num_eq, num_eq); A.setTo(0); + Mat_ b(num_eq, 1); b.setTo(0); + for (int i = 0, ki = 0; i < num_images; ++i) { - for (int j = 0; j < num_images; ++j) + if (skip(i, 0)) + continue; + + for (int j = 0, kj = 0; j < num_images; ++j) { - b(i, 0) += beta * N(i, j); - A(i, i) += beta * N(i, j); - if (j == i) continue; - A(i, i) += 2 * alpha * I(i, j) * I(i, j) * N(i, j); - A(i, j) -= 2 * alpha * I(i, j) * I(j, i) * N(i, j); + if (skip(j, 0)) + continue; + + b(ki, 0) += beta * N(i, j); + A(ki, ki) += beta * N(i, j); + if (j != i) + { + A(ki, ki) += 2 * alpha * I(i, j) * I(i, j) * N(i, j); + A(ki, kj) -= 2 * alpha * I(i, j) * I(j, i) * N(i, j); + } + ++kj; } + ++ki; } - solve(A, b, gains_); + Mat_ l_gains; + +#ifdef HAVE_EIGEN + Eigen::MatrixXf eigen_A, eigen_b, eigen_x; + cv2eigen(A, eigen_A); + cv2eigen(b, eigen_b); + + Eigen::LLT solver(eigen_A); +#if ENABLE_LOG + if (solver.info() != Eigen::ComputationInfo::Success) + LOGLN("Failed to solve exposure compensation system"); +#endif + eigen_x = solver.solve(eigen_b); + + eigen2cv(eigen_x, l_gains); +#else + solve(A, b, l_gains); +#endif + + gains_.create(num_images, 1); + for (int i = 0, j = 0; i < num_images; ++i) + { + if (skip(i, 0)) + gains_.at(i, 0) = 1; + else + gains_.at(i, 0) = l_gains(j++, 0); + } LOGLN("Exposure compensation, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec"); }