From 04d907fb976196df62f1259808fe98a44b874db1 Mon Sep 17 00:00:00 2001 From: Amir Tulegenov Date: Tue, 9 Mar 2021 23:51:40 +0600 Subject: [PATCH] Merge pull request #19619 from amirtu:OCV-221_get_and_set_cameras_on_stitcher * Get and set cameras for sticher. * Code review fixes. Co-authored-by: amir.tulegenov Co-authored-by: Alexander Smorkalov --- modules/stitching/include/opencv2/stitching.hpp | 14 ++++ modules/stitching/src/stitcher.cpp | 98 ++++++++++++++++++++++++- modules/stitching/test/test_stitcher.cpp | 28 +++++++ 3 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 modules/stitching/test/test_stitcher.cpp diff --git a/modules/stitching/include/opencv2/stitching.hpp b/modules/stitching/include/opencv2/stitching.hpp index f6e7f70..fb0ebe9 100644 --- a/modules/stitching/include/opencv2/stitching.hpp +++ b/modules/stitching/include/opencv2/stitching.hpp @@ -259,6 +259,20 @@ public: */ CV_WRAP Status estimateTransform(InputArrayOfArrays images, InputArrayOfArrays masks = noArray()); + /** @brief These function restors camera rotation and camera intrinsics of each camera + * that can be got with @ref Stitcher::cameras call + + @param images Input images. + @param cameras Estimated rotation of cameras for each of the input images. + @param component Indices (0-based) of images constituting the final panorama (optional). + @return Status code. + */ + Status setTransform(InputArrayOfArrays images, + const std::vector &cameras, + const std::vector &component); + /** @overload */ + Status setTransform(InputArrayOfArrays images, const std::vector &cameras); + /** @overload */ CV_WRAP Status composePanorama(OutputArray pano); /** @brief These functions try to compose the given images (or images stored internally from the other function diff --git a/modules/stitching/src/stitcher.cpp b/modules/stitching/src/stitcher.cpp index 58aa188..f9ba60c 100644 --- a/modules/stitching/src/stitcher.cpp +++ b/modules/stitching/src/stitcher.cpp @@ -118,7 +118,6 @@ Stitcher::Status Stitcher::estimateTransform(InputArrayOfArrays images, InputArr } - Stitcher::Status Stitcher::composePanorama(OutputArray pano) { CV_INSTRUMENT_REGION(); @@ -541,6 +540,103 @@ Stitcher::Status Stitcher::estimateCameraParams() return OK; } +Stitcher::Status Stitcher::setTransform(InputArrayOfArrays images, const std::vector &cameras) +{ + std::vector component; + for (int i = 0; i < (int)images.total(); i++) + component.push_back(i); + + return setTransform(images, cameras, component); +} + + +Stitcher::Status Stitcher::setTransform( + InputArrayOfArrays images, const std::vector &cameras, const std::vector &component) +{ +// CV_Assert(images.size() == cameras.size()); + + images.getUMatVector(imgs_); + masks_.clear(); + + if ((int)imgs_.size() < 2) + { + LOGLN("Need more images"); + return ERR_NEED_MORE_IMGS; + } + + work_scale_ = 1; + seam_work_aspect_ = 1; + seam_scale_ = 1; + bool is_work_scale_set = false; + bool is_seam_scale_set = false; + seam_est_imgs_.resize(imgs_.size()); + full_img_sizes_.resize(imgs_.size()); + + + for (size_t i = 0; i < imgs_.size(); ++i) + { + full_img_sizes_[i] = imgs_[i].size(); + if (registr_resol_ < 0) + { + work_scale_ = 1; + is_work_scale_set = true; + } + else + { + if (!is_work_scale_set) + { + work_scale_ = std::min(1.0, std::sqrt(registr_resol_ * 1e6 / full_img_sizes_[i].area())); + is_work_scale_set = true; + } + } + if (!is_seam_scale_set) + { + seam_scale_ = std::min(1.0, std::sqrt(seam_est_resol_ * 1e6 / full_img_sizes_[i].area())); + seam_work_aspect_ = seam_scale_ / work_scale_; + is_seam_scale_set = true; + } + + resize(imgs_[i], seam_est_imgs_[i], Size(), seam_scale_, seam_scale_, INTER_LINEAR_EXACT); + } + + features_.clear(); + pairwise_matches_.clear(); + + indices_ = component; + std::vector seam_est_imgs_subset; + std::vector imgs_subset; + std::vector full_img_sizes_subset; + for (size_t i = 0; i < indices_.size(); ++i) + { + imgs_subset.push_back(imgs_[indices_[i]]); + seam_est_imgs_subset.push_back(seam_est_imgs_[indices_[i]]); + full_img_sizes_subset.push_back(full_img_sizes_[indices_[i]]); + } + seam_est_imgs_ = seam_est_imgs_subset; + imgs_ = imgs_subset; + full_img_sizes_ = full_img_sizes_subset; + + if ((int)imgs_.size() < 2) + { + LOGLN("Need more images"); + return ERR_NEED_MORE_IMGS; + } + + cameras_ = cameras; + + std::vector focals; + for (size_t i = 0; i < cameras.size(); ++i) + focals.push_back(cameras_[i].focal); + + std::sort(focals.begin(), focals.end()); + if (focals.size() % 2 == 1) + warped_image_scale_ = static_cast(focals[focals.size() / 2]); + else + warped_image_scale_ = static_cast(focals[focals.size() / 2 - 1] + focals[focals.size() / 2]) * 0.5f; + + return Status::OK; +} + CV_DEPRECATED Ptr createStitcher(bool /*ignored*/) { diff --git a/modules/stitching/test/test_stitcher.cpp b/modules/stitching/test/test_stitcher.cpp new file mode 100644 index 0000000..5ca4cca --- /dev/null +++ b/modules/stitching/test/test_stitcher.cpp @@ -0,0 +1,28 @@ +// 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 "test_precomp.hpp" + +namespace opencv_test { namespace { + +TEST(ImageStitcher, setTransform) +{ + vector images; + images.push_back(imread(string(cvtest::TS::ptr()->get_data_path()) + "stitching/s1.jpg")); + images.push_back(imread(string(cvtest::TS::ptr()->get_data_path()) + "stitching/s2.jpg")); + + Mat expected; + Ptr stitcher = Stitcher::create(Stitcher::PANORAMA); + EXPECT_TRUE(Stitcher::OK == stitcher->estimateTransform(images)); + EXPECT_TRUE(Stitcher::OK == stitcher->composePanorama(expected)); + + Mat result; + Ptr another_stitcher = Stitcher::create(Stitcher::PANORAMA); + EXPECT_TRUE(Stitcher::OK == another_stitcher->setTransform(images, stitcher->cameras())); + EXPECT_TRUE(Stitcher::OK == another_stitcher->composePanorama(result)); + + EXPECT_DOUBLE_EQ(cvtest::norm(expected, result, NORM_INF), .0); +} + +}} // namespace opencv_test -- 2.7.4