diff --git a/modules/stitching/include/opencv2/stitching/detail/exposure_compensate.hpp b/modules/stitching/include/opencv2/stitching/detail/exposure_compensate.hpp index 81f3fa3a71..8d684acd04 100644 --- a/modules/stitching/include/opencv2/stitching/detail/exposure_compensate.hpp +++ b/modules/stitching/include/opencv2/stitching/detail/exposure_compensate.hpp @@ -110,15 +110,24 @@ intensities, see @cite BL07 and @cite WJ10 for details. class CV_EXPORTS_W GainCompensator : public ExposureCompensator { public: + CV_WRAP GainCompensator() + : GainCompensator(1) {} + CV_WRAP GainCompensator(int nr_feeds) + : nr_feeds_(nr_feeds) {} void feed(const std::vector &corners, const std::vector &images, const std::vector > &masks) CV_OVERRIDE; + void singleFeed(const std::vector &corners, const std::vector &images, + const std::vector > &masks); CV_WRAP void apply(int index, Point corner, InputOutputArray image, InputArray mask) CV_OVERRIDE; CV_WRAP void getMatGains(CV_OUT std::vector& umv) CV_OVERRIDE ; CV_WRAP void setMatGains(std::vector& umv) CV_OVERRIDE ; + CV_WRAP void setNrFeeds(int nr_feeds) { nr_feeds_ = nr_feeds; } + CV_WRAP int getNrFeeds() { return nr_feeds_; } std::vector gains() const; private: Mat_ gains_; + int nr_feeds_; }; /** @brief Exposure compensator which tries to remove exposure related artifacts by adjusting image block @@ -128,18 +137,22 @@ class CV_EXPORTS_W BlocksGainCompensator : public ExposureCompensator { public: CV_WRAP BlocksGainCompensator(int bl_width = 32, int bl_height = 32) - : bl_width_(bl_width), bl_height_(bl_height) {setUpdateGain(true);} + : BlocksGainCompensator(bl_width, bl_height, 1) {} + CV_WRAP BlocksGainCompensator(int bl_width, int bl_height, int nr_feeds) + : bl_width_(bl_width), bl_height_(bl_height), nr_feeds_(nr_feeds) {setUpdateGain(true);} void feed(const std::vector &corners, const std::vector &images, const std::vector > &masks) CV_OVERRIDE; CV_WRAP void apply(int index, Point corner, InputOutputArray image, InputArray mask) CV_OVERRIDE; CV_WRAP void getMatGains(CV_OUT std::vector& umv) CV_OVERRIDE; CV_WRAP void setMatGains(std::vector& umv) CV_OVERRIDE; + CV_WRAP void setNrFeeds(int nr_feeds) { nr_feeds_ = nr_feeds; } + CV_WRAP int getNrFeeds() { return nr_feeds_; } private: int bl_width_, bl_height_; std::vector gain_maps_; + int nr_feeds_; }; - //! @} } // namespace detail diff --git a/modules/stitching/perf/perf_stich.cpp b/modules/stitching/perf/perf_stich.cpp index 8d5527cd04..36f12f0cc3 100644 --- a/modules/stitching/perf/perf_stich.cpp +++ b/modules/stitching/perf/perf_stich.cpp @@ -15,6 +15,7 @@ using namespace perf; typedef TestBaseWithParam stitch; typedef TestBaseWithParam stitchExposureCompensation; typedef TestBaseWithParam > stitchDatasets; +typedef TestBaseWithParam> stitchExposureCompMultiFeed; #ifdef HAVE_OPENCV_XFEATURES2D #define TEST_DETECTORS testing::Values("surf", "orb", "akaze") @@ -22,6 +23,8 @@ typedef TestBaseWithParam > stitchDatasets; #define TEST_DETECTORS testing::Values("orb", "akaze") #endif #define TEST_EXP_COMP_BS testing::Values(32, 16, 12, 10, 8) +#define TEST_EXP_COMP_NR_FEED testing::Values(1, 2, 3, 4, 5) +#define TEST_EXP_COMP_MODE testing::Values("gain", "blocks") #define AFFINE_DATASETS testing::Values("s", "budapest", "newspaper", "prague") PERF_TEST_P(stitch, a123, TEST_DETECTORS) @@ -92,6 +95,45 @@ PERF_TEST_P(stitchExposureCompensation, a123, TEST_EXP_COMP_BS) SANITY_CHECK_NOTHING(); } +PERF_TEST_P(stitchExposureCompMultiFeed, a123, testing::Combine(TEST_EXP_COMP_MODE, TEST_EXP_COMP_NR_FEED)) +{ + const int block_size = 32; + 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") ) ); + + string mode = get<0>(GetParam()); + int nr_feeds = get<1>(GetParam()); + + declare.time(30 * 10).iterations(10); + + Ptr exp_comp; + if (mode == "blocks") + exp_comp = makePtr(block_size, block_size, nr_feeds); + else if (mode == "gain") + exp_comp = makePtr(nr_feeds); + + while(next()) + { + Ptr stitcher = Stitcher::create(); + stitcher->setWarper(makePtr()); + stitcher->setRegistrationResol(WORK_MEGAPIX); + stitcher->setExposureCompensator(exp_comp); + + 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 2ddc6d0f5e..97d113f2e5 100644 --- a/modules/stitching/src/exposure_compensate.cpp +++ b/modules/stitching/src/exposure_compensate.cpp @@ -85,6 +85,33 @@ void GainCompensator::feed(const std::vector &corners, const std::vector< int64 t = getTickCount(); #endif + const int num_images = static_cast(images.size()); + Mat accumulated_gains; + + for (int n = 0; n < nr_feeds_; ++n) + { + if (n > 0) + { + // Apply previous iteration gains + for (int i = 0; i < num_images; ++i) + apply(i, corners[i], images[i], masks[i].first); + } + + singleFeed(corners, images, masks); + + if (n == 0) + accumulated_gains = gains_.clone(); + else + multiply(accumulated_gains, gains_, accumulated_gains); + } + gains_ = accumulated_gains; + + LOGLN("Exposure compensation, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec"); +} + +void GainCompensator::singleFeed(const std::vector &corners, const std::vector &images, + const std::vector > &masks) +{ CV_Assert(corners.size() == images.size() && images.size() == masks.size()); const int num_images = static_cast(images.size()); @@ -204,8 +231,6 @@ void GainCompensator::feed(const std::vector &corners, const std::vector< gains_.at(i, 0) = l_gains(j++, 0); } } - - LOGLN("Exposure compensation, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec"); } @@ -282,7 +307,7 @@ void BlocksGainCompensator::feed(const std::vector &corners, const std::v if (getUpdateGain()) { - GainCompensator compensator; + GainCompensator compensator(nr_feeds_); compensator.feed(block_corners, block_images, block_masks); std::vector gains = compensator.gains(); gain_maps_.resize(num_images);