diff --git a/modules/gpu/include/opencv2/gpu/gpu.hpp b/modules/gpu/include/opencv2/gpu/gpu.hpp index 1d2bb701d7a1bbe1e4057abafff6f4eb009c56b4..3d73633cba25df68050c069f1d08feaaba689b4c 100644 --- a/modules/gpu/include/opencv2/gpu/gpu.hpp +++ b/modules/gpu/include/opencv2/gpu/gpu.hpp @@ -1462,6 +1462,8 @@ namespace cv void operator()(const GpuMat& img, const GpuMat& mask, std::vector& keypoints, std::vector& descriptors, bool useProvidedKeypoints = false); + void releaseMemory(); + //! max keypoints = min(keypointsRatio * img.size().area(), 65535) float keypointsRatio; diff --git a/modules/gpu/src/brute_force_matcher.cpp b/modules/gpu/src/brute_force_matcher.cpp index 2fb2d9dd33ced67d07055d1fb595601e5d6a4daa..f4ec3cc52f6511514aec1ade4da7532267b48c72 100644 --- a/modules/gpu/src/brute_force_matcher.cpp +++ b/modules/gpu/src/brute_force_matcher.cpp @@ -203,8 +203,8 @@ void cv::gpu::BruteForceMatcher_GPU_base::matchSingle(const GpuMat& queryDescs, const int nQuery = queryDescs.rows; - trainIdx.create(1, nQuery, CV_32S); - distance.create(1, nQuery, CV_32F); + ensureSizeIsEnough(1, nQuery, CV_32S, trainIdx); + ensureSizeIsEnough(1, nQuery, CV_32F, distance); match_caller_t func = match_callers[distType][queryDescs.depth()]; CV_Assert(func != 0); @@ -335,9 +335,9 @@ void cv::gpu::BruteForceMatcher_GPU_base::matchCollection(const GpuMat& queryDes const int nQuery = queryDescs.rows; - trainIdx.create(1, nQuery, CV_32S); - imgIdx.create(1, nQuery, CV_32S); - distance.create(1, nQuery, CV_32F); + ensureSizeIsEnough(1, nQuery, CV_32S, trainIdx); + ensureSizeIsEnough(1, nQuery, CV_32S, imgIdx); + ensureSizeIsEnough(1, nQuery, CV_32F, distance); match_caller_t func = match_callers[distType][queryDescs.depth()]; CV_Assert(func != 0); @@ -435,8 +435,8 @@ void cv::gpu::BruteForceMatcher_GPU_base::knnMatch(const GpuMat& queryDescs, con const int nQuery = queryDescs.rows; const int nTrain = trainDescs.rows; - trainIdx.create(nQuery, k, CV_32S); - distance.create(nQuery, k, CV_32F); + ensureSizeIsEnough(nQuery, k, CV_32S, trainIdx); + ensureSizeIsEnough(nQuery, k, CV_32F, distance); ensureSizeIsEnough(nQuery, nTrain, CV_32FC1, allDist); if (stream) @@ -593,8 +593,8 @@ void cv::gpu::BruteForceMatcher_GPU_base::radiusMatch(const GpuMat& queryDescs, ensureSizeIsEnough(1, nQuery, CV_32SC1, nMatches); if (trainIdx.empty()) { - trainIdx.create(nQuery, nTrain, CV_32SC1); - distance.create(nQuery, nTrain, CV_32FC1); + ensureSizeIsEnough(nQuery, nTrain, CV_32SC1, trainIdx); + ensureSizeIsEnough(nQuery, nTrain, CV_32FC1, distance); } if (stream) diff --git a/modules/gpu/src/filtering.cpp b/modules/gpu/src/filtering.cpp index 0ea4fc561c72808a6171af9f19a899074f3f0430..2d1a934101e4196e51fba551267b978184931210 100644 --- a/modules/gpu/src/filtering.cpp +++ b/modules/gpu/src/filtering.cpp @@ -192,8 +192,8 @@ namespace Size src_size = src.size(); dst.create(src_size, dstType); + ensureSizeIsEnough(src_size, bufType, dstBuf); - //dstBuf.create(src_size, bufType); if (stream) { diff --git a/modules/gpu/src/surf.cpp b/modules/gpu/src/surf.cpp index f4c641a98cbbeb681a10ba28f73dfb238bd12f43..e4c06ac92c318d2e82fc77083316258bbd4da276 100644 --- a/modules/gpu/src/surf.cpp +++ b/modules/gpu/src/surf.cpp @@ -59,6 +59,7 @@ void cv::gpu::SURF_GPU::operator()(const GpuMat&, const GpuMat&, GpuMat&, GpuMat void cv::gpu::SURF_GPU::operator()(const GpuMat&, const GpuMat&, vector&) { throw_nogpu(); } void cv::gpu::SURF_GPU::operator()(const GpuMat&, const GpuMat&, vector&, GpuMat&, bool) { throw_nogpu(); } void cv::gpu::SURF_GPU::operator()(const GpuMat&, const GpuMat&, vector&, vector&, bool) { throw_nogpu(); } +void cv::gpu::SURF_GPU::releaseMemory() { throw_nogpu(); } #else /* !defined (HAVE_CUDA) */ @@ -201,7 +202,7 @@ namespace const int nFeatures = keypoints.cols; if (nFeatures > 0) { - descriptors.create(nFeatures, descriptorSize, CV_32F); + ensureSizeIsEnough(nFeatures, descriptorSize, CV_32F, descriptors); compute_descriptors_gpu(descriptors, keypoints.ptr(SURF_GPU::SF_X), keypoints.ptr(SURF_GPU::SF_Y), keypoints.ptr(SURF_GPU::SF_SIZE), keypoints.ptr(SURF_GPU::SF_DIR), nFeatures); } @@ -431,4 +432,15 @@ void cv::gpu::SURF_GPU::operator()(const GpuMat& img, const GpuMat& mask, vector downloadDescriptors(descriptorsGPU, descriptors); } +void cv::gpu::SURF_GPU::releaseMemory() +{ + sum.release(); + mask1.release(); + maskSum.release(); + intBuffer.release(); + det.release(); + trace.release(); + maxPosBuffer.release(); +} + #endif /* !defined (HAVE_CUDA) */ diff --git a/modules/stitching/main.cpp b/modules/stitching/main.cpp index 26226ebe839bd4e9f425521074b50a4810430fc3..fbd4657b39cc7a3bdb25ac5ae6cb8616e147268f 100644 --- a/modules/stitching/main.cpp +++ b/modules/stitching/main.cpp @@ -363,6 +363,8 @@ int main(int argc, char* argv[]) images[i] = img.clone(); } + finder.releaseMemory(); + full_img.release(); img.release(); @@ -373,6 +375,7 @@ int main(int argc, char* argv[]) vector pairwise_matches; BestOf2NearestMatcher matcher(try_gpu, match_conf); matcher(features, pairwise_matches); + matcher.releaseMemory(); LOGLN("Pairwise matching, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec"); // Leave only images we are sure are from the same panorama @@ -571,7 +574,7 @@ int main(int argc, char* argv[]) resize(dilated_mask, seam_mask, mask_warped.size()); mask_warped = seam_mask & mask_warped; - if (static_cast(blender) == 0) + if (blender.empty()) { blender = Blender::createDefault(blend_type, try_gpu); Size dst_sz = resultRoi(corners, sizes).size(); @@ -598,7 +601,7 @@ int main(int argc, char* argv[]) } Mat result, result_mask; - blender->blend(result, result_mask); + blender->blend(result, result_mask); LOGLN("Compositing, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec"); diff --git a/modules/stitching/matchers.cpp b/modules/stitching/matchers.cpp index 12a8ba253047068eda84a96e903929d4dbf9954a..640fe5d5782029f6f1d586ca8e010b4b2dbc1c2c 100644 --- a/modules/stitching/matchers.cpp +++ b/modules/stitching/matchers.cpp @@ -96,11 +96,17 @@ namespace num_layers_descr_ = num_layers_descr; } + void releaseMemory(); + protected: void find(const Mat &image, ImageFeatures &features); private: + GpuMat image_; + GpuMat gray_image_; SURF_GPU surf_; + GpuMat keypoints_; + GpuMat descriptors_; int num_octaves_, num_layers_; int num_octaves_descr_, num_layers_descr_; }; @@ -118,22 +124,34 @@ namespace void GpuSurfFeaturesFinder::find(const Mat &image, ImageFeatures &features) { - GpuMat gray_image; CV_Assert(image.depth() == CV_8U); - cvtColor(GpuMat(image), gray_image, CV_BGR2GRAY); - GpuMat d_keypoints; - GpuMat d_descriptors; + ensureSizeIsEnough(image.size(), image.type(), image_); + image_.upload(image); + + ensureSizeIsEnough(image.size(), CV_8UC1, gray_image_); + cvtColor(image_, gray_image_, CV_BGR2GRAY); + surf_.nOctaves = num_octaves_; surf_.nOctaveLayers = num_layers_; - surf_(gray_image, GpuMat(), d_keypoints); + surf_(gray_image_, GpuMat(), keypoints_); surf_.nOctaves = num_octaves_descr_; surf_.nOctaveLayers = num_layers_descr_; - surf_(gray_image, GpuMat(), d_keypoints, d_descriptors, true); - surf_.downloadKeypoints(d_keypoints, features.keypoints); + surf_.upright = true; + surf_(gray_image_, GpuMat(), keypoints_, descriptors_, true); + surf_.downloadKeypoints(keypoints_, features.keypoints); - d_descriptors.download(features.descriptors); + descriptors_.download(features.descriptors); + } + + void GpuSurfFeaturesFinder::releaseMemory() + { + surf_.releaseMemory(); + image_.release(); + gray_image_.release(); + keypoints_.release(); + descriptors_.release(); } } // anonymous namespace @@ -153,6 +171,11 @@ void SurfFeaturesFinder::find(const Mat &image, ImageFeatures &features) (*impl_)(image, features); } +void SurfFeaturesFinder::releaseMemory() +{ + impl_->releaseMemory(); +} + ////////////////////////////////////////////////////////////////////////////// @@ -279,10 +302,13 @@ namespace GpuMatcher(float match_conf) : match_conf_(match_conf) {} void match(const ImageFeatures &features1, const ImageFeatures &features2, MatchesInfo& matches_info); + void releaseMemory(); + private: float match_conf_; GpuMat descriptors1_, descriptors2_; GpuMat train_idx_, distance_, all_dist_; + vector< vector > pair_matches; }; @@ -326,14 +352,19 @@ namespace void GpuMatcher::match(const ImageFeatures &features1, const ImageFeatures &features2, MatchesInfo& matches_info) { - matches_info.matches.clear(); + matches_info.matches.clear(); + + ensureSizeIsEnough(features1.descriptors.size(), features1.descriptors.type(), descriptors1_); + ensureSizeIsEnough(features2.descriptors.size(), features2.descriptors.type(), descriptors2_); + descriptors1_.upload(features1.descriptors); descriptors2_.upload(features2.descriptors); + BruteForceMatcher_GPU< L2 > matcher; - vector< vector > pair_matches; MatchesSet matches; // Find 1->2 matches + pair_matches.clear(); matcher.knnMatch(descriptors1_, descriptors2_, train_idx_, distance_, all_dist_, 2); matcher.knnMatchDownload(train_idx_, distance_, pair_matches); for (size_t i = 0; i < pair_matches.size(); ++i) @@ -365,6 +396,16 @@ namespace } } + void GpuMatcher::releaseMemory() + { + descriptors1_.release(); + descriptors2_.release(); + train_idx_.release(); + distance_.release(); + all_dist_.release(); + vector< vector >().swap(pair_matches); + } + } // anonymous namespace @@ -456,3 +497,8 @@ void BestOf2NearestMatcher::match(const ImageFeatures &features1, const ImageFea // Rerun motion estimation on inliers only matches_info.H = findHomography(src_points, dst_points, CV_RANSAC); } + +void BestOf2NearestMatcher::releaseMemory() +{ + impl_->releaseMemory(); +} diff --git a/modules/stitching/matchers.hpp b/modules/stitching/matchers.hpp index 601043fa2853d8e1d24a74e7275dd4286e331360..fe7fbe060e0d5ef908bec949fe9cb5ebcac2003a 100644 --- a/modules/stitching/matchers.hpp +++ b/modules/stitching/matchers.hpp @@ -59,6 +59,8 @@ public: virtual ~FeaturesFinder() {} void operator ()(const cv::Mat &image, ImageFeatures &features); + virtual void releaseMemory() {} + protected: virtual void find(const cv::Mat &image, ImageFeatures &features) = 0; }; @@ -71,6 +73,8 @@ public: int num_octaves = 3, int num_layers = 4, int num_octaves_descr = 4, int num_layers_descr = 2); + void releaseMemory(); + protected: void find(const cv::Mat &image, ImageFeatures &features); @@ -104,6 +108,8 @@ public: bool isThreadSafe() const { return is_thread_safe_; } + virtual void releaseMemory() {} + protected: FeaturesMatcher(bool is_thread_safe = false) : is_thread_safe_(is_thread_safe) {} @@ -120,6 +126,8 @@ public: BestOf2NearestMatcher(bool try_use_gpu = true, float match_conf = 0.55f, int num_matches_thresh1 = 6, int num_matches_thresh2 = 6); + void releaseMemory(); + protected: void match(const ImageFeatures &features1, const ImageFeatures &features2, MatchesInfo &matches_info); diff --git a/modules/stitching/precomp.hpp b/modules/stitching/precomp.hpp index 340342267fecbf4c7efae318f753ad87d631bf34..16bdf6048c6a19d7c2503261c10eb0d7507e8b1b 100644 --- a/modules/stitching/precomp.hpp +++ b/modules/stitching/precomp.hpp @@ -50,6 +50,7 @@ #include #include #include +#include #include "opencv2/core/core.hpp" #include "opencv2/core/internal.hpp" #include "opencv2/imgproc/imgproc.hpp"