From 3d50df37c2643c7ac5848712f17dfd964f04b0f9 Mon Sep 17 00:00:00 2001 From: Alexey Spizhevoy Date: Tue, 24 May 2011 09:58:25 +0000 Subject: [PATCH] reduced memory requirements for multi-band blending --- modules/stitching/autocalib.cpp | 15 +++---- modules/stitching/blenders.cpp | 74 ++++++++++++++++++++------------- modules/stitching/blenders.hpp | 3 +- 3 files changed, 55 insertions(+), 37 deletions(-) diff --git a/modules/stitching/autocalib.cpp b/modules/stitching/autocalib.cpp index e80e49edb6..c6cd712129 100644 --- a/modules/stitching/autocalib.cpp +++ b/modules/stitching/autocalib.cpp @@ -99,18 +99,19 @@ void estimateFocal(const vector &features, const vector 0) - { - nth_element(all_focals.begin(), all_focals.end(), all_focals.begin() + all_focals.size()/2); - for (int i = 0; i < num_images; ++i) - focals[i] = all_focals[all_focals.size()/2]; - } - else + if (static_cast(all_focals.size()) < num_images - 1) { + LOGLN("Can't estimate focal length, will use anaive approach"); double focals_sum = 0; for (int i = 0; i < num_images; ++i) focals_sum += features[i].img_size.width + features[i].img_size.height; for (int i = 0; i < num_images; ++i) focals[i] = focals_sum / num_images; } + else + { + nth_element(all_focals.begin(), all_focals.end(), all_focals.begin() + all_focals.size()/2); + for (int i = 0; i < num_images; ++i) + focals[i] = all_focals[all_focals.size()/2]; + } } diff --git a/modules/stitching/blenders.cpp b/modules/stitching/blenders.cpp index 1d9c4fa5d7..cce1381b1a 100644 --- a/modules/stitching/blenders.cpp +++ b/modules/stitching/blenders.cpp @@ -125,16 +125,14 @@ void FeatherBlender::feed(const Mat &img, const Mat &mask, Point tl) CV_Assert(img.type() == CV_16SC3); CV_Assert(mask.type() == CV_8U); + createWeightMap(mask, sharpness_, weight_map_); int dx = tl.x - dst_roi_.x; int dy = tl.y - dst_roi_.y; - createWeightMap(mask, sharpness_, weight_map_); - for (int y = 0; y < img.rows; ++y) { const Point3_* src_row = img.ptr >(y); Point3_* dst_row = dst_.ptr >(dy + y); - const float* weight_row = weight_map_.ptr(y); float* dst_weight_row = dst_weight_map_.ptr(dy + y); @@ -159,6 +157,9 @@ void FeatherBlender::blend(Mat &dst, Mat &dst_mask) void MultiBandBlender::prepare(Rect dst_roi) { + dst_roi_final_ = dst_roi; + dst_roi.width += ((1 << num_bands_) - dst_roi.width % (1 << num_bands_)) % (1 << num_bands_); + dst_roi.height += ((1 << num_bands_) - dst_roi.height % (1 << num_bands_)) % (1 << num_bands_); Blender::prepare(dst_roi); dst_pyr_laplace_.resize(num_bands_ + 1); @@ -185,13 +186,25 @@ void MultiBandBlender::feed(const Mat &img, const Mat &mask, Point tl) CV_Assert(img.type() == CV_16SC3); CV_Assert(mask.type() == CV_8U); - //int gap = 10 * (1 << num_bands_); - //Point tl_new(max(dst_roi_.x, tl.x - gap), - // max(dst_roi_.y, tl.y - gap)); - //Point br_new(min(dst_roi_.br().x, tl.x + img.cols + gap), - // min(dst_roi_.br().y, tl.y + img.rows + gap)); - Point tl_new(dst_roi_.tl()); - Point br_new(dst_roi_.br()); + int gap = 3 * (1 << num_bands_); + Point tl_new(max(dst_roi_.x, tl.x - gap), + max(dst_roi_.y, tl.y - gap)); + Point br_new(min(dst_roi_.br().x, tl.x + img.cols + gap), + min(dst_roi_.br().y, tl.y + img.rows + gap)); + + tl_new.x = dst_roi_.x + (((tl_new.x - dst_roi_.x) >> num_bands_) << num_bands_); + tl_new.y = dst_roi_.y + (((tl_new.y - dst_roi_.y) >> num_bands_) << num_bands_); + int width = br_new.x - tl_new.x; + int height = br_new.y - tl_new.y; + width += ((1 << num_bands_) - width % (1 << num_bands_)) % (1 << num_bands_); + height += ((1 << num_bands_) - height % (1 << num_bands_)) % (1 << num_bands_); + br_new.x = tl_new.x + width; + br_new.y = tl_new.y + height; + int dy = max(br_new.y - dst_roi_.br().y, 0); + int dx = max(br_new.x - dst_roi_.br().x, 0); + tl_new.x -= dx; br_new.x -= dx; + tl_new.y -= dy; br_new.y -= dy; + int top = tl.y - tl_new.y; int left = tl.x - tl_new.x; int bottom = br_new.y - tl.y - img.rows; @@ -217,30 +230,33 @@ void MultiBandBlender::feed(const Mat &img, const Mat &mask, Point tl) for (int i = 0; i < num_bands_; ++i) pyrDown(weight_pyr_gauss[i], weight_pyr_gauss[i + 1]); + int y_tl = tl_new.y - dst_roi_.y; + int y_br = br_new.y - dst_roi_.y; + int x_tl = tl_new.x - dst_roi_.x; + int x_br = br_new.x - dst_roi_.x; + // Add weighted layer of the source image to the final Laplacian pyramid layer for (int i = 0; i <= num_bands_; ++i) { - int dx = 0; - int dy = 0; - //int dx = (tl_new.x >> i) - (dst_roi_.x >> i); - //int dy = (tl_new.y >> i) - (dst_roi_.y >> i); - - for (int y = 0; y < src_pyr_laplace[i].rows; ++y) + for (int y = y_tl; y < y_br; ++y) { - const Point3_* src_row = src_pyr_laplace[i].ptr >(y); - Point3_* dst_row = dst_pyr_laplace_[i].ptr >(y + dy); + int y_ = y - y_tl; + const Point3_* src_row = src_pyr_laplace[i].ptr >(y_); + Point3_* dst_row = dst_pyr_laplace_[i].ptr >(y); + const float* weight_row = weight_pyr_gauss[i].ptr(y_); + float* dst_weight_row = dst_band_weights_[i].ptr(y); - const float* weight_row = weight_pyr_gauss[i].ptr(y); - float* dst_weight_row = dst_band_weights_[i].ptr(y + dy); - - for (int x = 0; x < src_pyr_laplace[i].cols; ++x) + for (int x = x_tl; x < x_br; ++x) { - dst_row[x + dx].x += static_cast(src_row[x].x * weight_row[x]); - dst_row[x + dx].y += static_cast(src_row[x].y * weight_row[x]); - dst_row[x + dx].z += static_cast(src_row[x].z * weight_row[x]); - dst_weight_row[x + dx] += weight_row[x]; + int x_ = x - x_tl; + dst_row[x].x += static_cast(src_row[x_].x * weight_row[x_]); + dst_row[x].y += static_cast(src_row[x_].y * weight_row[x_]); + dst_row[x].z += static_cast(src_row[x_].z * weight_row[x_]); + dst_weight_row[x] += weight_row[x_]; } } + x_tl /= 2; y_tl /= 2; + x_br /= 2; y_br /= 2; } } @@ -253,7 +269,9 @@ void MultiBandBlender::blend(Mat &dst, Mat &dst_mask) restoreImageFromLaplacePyr(dst_pyr_laplace_); dst_ = dst_pyr_laplace_[0]; + dst_ = dst_(Range(0, dst_roi_final_.height), Range(0, dst_roi_final_.width)); dst_mask_ = dst_band_weights_[0] > WEIGHT_EPS; + dst_mask_ = dst_mask_(Range(0, dst_roi_final_.height), Range(0, dst_roi_final_.width)); dst_pyr_laplace_.clear(); dst_band_weights_.clear(); @@ -313,9 +331,7 @@ void createLaplacePyr(const vector &pyr_gauss, vector &pyr_laplace) { if (pyr_gauss.size() == 0) return; - pyr_laplace.resize(pyr_gauss.size()); - Mat tmp; for (size_t i = 0; i < pyr_laplace.size() - 1; ++i) { @@ -330,7 +346,6 @@ void restoreImageFromLaplacePyr(vector &pyr) { if (pyr.size() == 0) return; - Mat tmp; for (size_t i = pyr.size() - 1; i > 0; --i) { @@ -339,3 +354,4 @@ void restoreImageFromLaplacePyr(vector &pyr) } } + diff --git a/modules/stitching/blenders.hpp b/modules/stitching/blenders.hpp index fbe3dac72b..ffd29e4e27 100644 --- a/modules/stitching/blenders.hpp +++ b/modules/stitching/blenders.hpp @@ -95,6 +95,7 @@ private: int num_bands_; std::vector dst_pyr_laplace_; std::vector dst_band_weights_; + cv::Rect dst_roi_final_; }; @@ -109,7 +110,7 @@ void createWeightMap(const cv::Mat& mask, float sharpness, cv::Mat& weight); void createLaplacePyr(const std::vector& pyr_gauss, std::vector& pyr_laplace); -// Restores source image in-place. Result will be stored in pyr[0]. +// Restores source image in-place (result will be stored in pyr[0]) void restoreImageFromLaplacePyr(std::vector& pyr); #endif // __OPENCV_BLENDERS_HPP__