1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-30 07:43:03 +04:00

Merge pull request #13267 from LaurentBerger:StitchPython

* Python wrapper for detail

* hide pyrotationwrapper

* copy code in pyopencv_rotationwarper.hpp

* move ImageFeatures MatchInfo and CameraParams in core/misc/

* add python test for detail

* move test_detail in test_stitching

* rename
This commit is contained in:
LaurentBerger
2018-12-18 19:49:16 +01:00
committed by Alexander Alekhin
parent fd27d5ea00
commit 2fb409b286
20 changed files with 1000 additions and 208 deletions
+1 -1
View File
@@ -70,7 +70,7 @@ Ptr<Blender> Blender::createDefault(int type, bool try_gpu)
if (type == NO)
return makePtr<Blender>();
if (type == FEATHER)
return makePtr<FeatherBlender>();
return makePtr<FeatherBlender>(try_gpu);
if (type == MULTI_BAND)
return makePtr<MultiBandBlender>(try_gpu);
CV_Error(Error::StsBadArg, "unsupported blending method");
+90 -40
View File
@@ -47,12 +47,18 @@ namespace detail {
Ptr<ExposureCompensator> ExposureCompensator::createDefault(int type)
{
Ptr<ExposureCompensator> e;
if (type == NO)
return makePtr<NoExposureCompensator>();
if (type == GAIN)
return makePtr<GainCompensator>();
e = makePtr<NoExposureCompensator>();
else if (type == GAIN)
e = makePtr<GainCompensator>();
if (type == GAIN_BLOCKS)
return makePtr<BlocksGainCompensator>();
e = makePtr<BlocksGainCompensator>();
if (e.get() != nullptr)
{
e->setUpdateGain(true);
return e;
}
CV_Error(Error::StsBadArg, "unsupported exposure compensation method");
}
@@ -120,25 +126,27 @@ void GainCompensator::feed(const std::vector<Point> &corners, const std::vector<
}
}
}
double alpha = 0.01;
double beta = 100;
Mat_<double> A(num_images, num_images); A.setTo(0);
Mat_<double> b(num_images, 1); b.setTo(0);
for (int i = 0; i < num_images; ++i)
if (getUpdateGain() || gains_.rows != num_images)
{
for (int j = 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);
}
}
double alpha = 0.01;
double beta = 100;
solve(A, b, gains_);
Mat_<double> A(num_images, num_images); A.setTo(0);
Mat_<double> b(num_images, 1); b.setTo(0);
for (int i = 0; i < num_images; ++i)
{
for (int j = 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);
}
}
solve(A, b, gains_);
}
LOGLN("Exposure compensation, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec");
}
@@ -160,6 +168,24 @@ std::vector<double> GainCompensator::gains() const
return gains_vec;
}
void GainCompensator::getMatGains(std::vector<Mat>& umv)
{
umv.clear();
for (int i = 0; i < gains_.rows; ++i)
umv.push_back(Mat(1,1,CV_64FC1,Scalar(gains_(i, 0))));
}
void GainCompensator::setMatGains(std::vector<Mat>& umv)
{
gains_=Mat_<double>(static_cast<int>(umv.size()),1);
for (int i = 0; i < static_cast<int>(umv.size()); i++)
{
int type = umv[i].type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
CV_CheckType(type, depth == CV_64F && cn == 1, "Only double images are supported for gain");
CV_Assert(umv[i].rows == 1 && umv[i].cols == 1);
gains_(i, 0) = umv[i].at<double>(0, 0);
}
}
void BlocksGainCompensator::feed(const std::vector<Point> &corners, const std::vector<UMat> &images,
const std::vector<std::pair<UMat,uchar> > &masks)
@@ -197,29 +223,32 @@ void BlocksGainCompensator::feed(const std::vector<Point> &corners, const std::v
}
}
GainCompensator compensator;
compensator.feed(block_corners, block_images, block_masks);
std::vector<double> gains = compensator.gains();
gain_maps_.resize(num_images);
Mat_<float> ker(1, 3);
ker(0,0) = 0.25; ker(0,1) = 0.5; ker(0,2) = 0.25;
int bl_idx = 0;
for (int img_idx = 0; img_idx < num_images; ++img_idx)
if (getUpdateGain())
{
Size bl_per_img = bl_per_imgs[img_idx];
gain_maps_[img_idx].create(bl_per_img, CV_32F);
GainCompensator compensator;
compensator.feed(block_corners, block_images, block_masks);
std::vector<double> gains = compensator.gains();
gain_maps_.resize(num_images);
Mat_<float> ker(1, 3);
ker(0, 0) = 0.25; ker(0, 1) = 0.5; ker(0, 2) = 0.25;
int bl_idx = 0;
for (int img_idx = 0; img_idx < num_images; ++img_idx)
{
Mat_<float> gain_map = gain_maps_[img_idx].getMat(ACCESS_WRITE);
for (int by = 0; by < bl_per_img.height; ++by)
for (int bx = 0; bx < bl_per_img.width; ++bx, ++bl_idx)
gain_map(by, bx) = static_cast<float>(gains[bl_idx]);
}
Size bl_per_img = bl_per_imgs[img_idx];
gain_maps_[img_idx].create(bl_per_img, CV_32F);
sepFilter2D(gain_maps_[img_idx], gain_maps_[img_idx], CV_32F, ker, ker);
sepFilter2D(gain_maps_[img_idx], gain_maps_[img_idx], CV_32F, ker, ker);
{
Mat_<float> gain_map = gain_maps_[img_idx].getMat(ACCESS_WRITE);
for (int by = 0; by < bl_per_img.height; ++by)
for (int bx = 0; bx < bl_per_img.width; ++bx, ++bl_idx)
gain_map(by, bx) = static_cast<float>(gains[bl_idx]);
}
sepFilter2D(gain_maps_[img_idx], gain_maps_[img_idx], CV_32F, ker, ker);
sepFilter2D(gain_maps_[img_idx], gain_maps_[img_idx], CV_32F, ker, ker);
}
}
}
@@ -251,5 +280,26 @@ void BlocksGainCompensator::apply(int index, Point /*corner*/, InputOutputArray
}
}
void BlocksGainCompensator::getMatGains(std::vector<Mat>& umv)
{
umv.clear();
for (int i = 0; i < static_cast<int>(gain_maps_.size()); ++i)
{
Mat m;
gain_maps_[i].copyTo(m);
umv.push_back(m);
}
}
void BlocksGainCompensator::setMatGains(std::vector<Mat>& umv)
{
for (int i = 0; i < static_cast<int>(umv.size()); i++)
{
UMat m;
umv[i].copyTo(m);
gain_maps_.push_back(m);
}
}
} // namespace detail
} // namespace cv
+6
View File
@@ -384,6 +384,12 @@ BestOf2NearestMatcher::BestOf2NearestMatcher(bool try_use_gpu, float match_conf,
num_matches_thresh2_ = num_matches_thresh2;
}
Ptr<BestOf2NearestMatcher> BestOf2NearestMatcher::create(bool try_use_gpu, float match_conf, int num_matches_thresh1, int num_matches_thresh2)
{
return makePtr<BestOf2NearestMatcher>(try_use_gpu, match_conf, num_matches_thresh1, num_matches_thresh2);
}
void BestOf2NearestMatcher::match(const ImageFeatures &features1, const ImageFeatures &features2,
MatchesInfo &matches_info)
+45
View File
@@ -47,6 +47,18 @@
namespace cv {
namespace detail {
Ptr<SeamFinder> SeamFinder::createDefault(int type)
{
if (type == NO)
return makePtr<NoSeamFinder>();
if (type == VORONOI_SEAM)
return makePtr<VoronoiSeamFinder>();
if (type == DP_SEAM)
return makePtr<DpSeamFinder>();
CV_Error(Error::StsBadArg, "unsupported exposure compensation method");
}
void PairwiseSeamFinder::find(const std::vector<UMat> &src, const std::vector<Point> &corners,
std::vector<UMat> &masks)
{
@@ -165,6 +177,26 @@ void VoronoiSeamFinder::findInPair(size_t first, size_t second, Rect roi)
DpSeamFinder::DpSeamFinder(CostFunction costFunc) : costFunc_(costFunc), ncomps_(0) {}
DpSeamFinder::DpSeamFinder(String costFunc)
{
ncomps_ = 0;
if (costFunc == "COLOR")
costFunc_ = COLOR;
else if (costFunc == "COLOR_GRAD")
costFunc_ = COLOR_GRAD;
else
CV_Error(-1, "Unknown cost function");
}
void DpSeamFinder::setCostFunction(String costFunc)
{
if (costFunc == "COLOR")
costFunc_ = COLOR;
else if (costFunc == "COLOR_GRAD")
costFunc_ = COLOR_GRAD;
else
CV_Error(-1, "Unknown cost function");
}
void DpSeamFinder::find(const std::vector<UMat> &src, const std::vector<Point> &corners, std::vector<UMat> &masks)
{
@@ -1324,6 +1356,19 @@ void GraphCutSeamFinder::Impl::findInPair(size_t first, size_t second, Rect roi)
}
}
GraphCutSeamFinder::GraphCutSeamFinder(String cost_type, float terminal_cost, float bad_region_penalty)
{
CostType t;
if (cost_type == "COST_COLOR")
t = COST_COLOR;
else if (cost_type == "COST_COLOR_GRAD")
t = COST_COLOR_GRAD;
else
CV_Error(Error::StsBadFunc, "Unknown cost type function");
impl_ = new Impl(t, terminal_cost, bad_region_penalty);
}
GraphCutSeamFinder::GraphCutSeamFinder(int cost_type, float terminal_cost, float bad_region_penalty)
: impl_(new Impl(cost_type, terminal_cost, bad_region_penalty)) {}
+72 -2
View File
@@ -42,8 +42,79 @@
#include "precomp.hpp"
#include "opencl_kernels_stitching.hpp"
#include <iostream>
namespace cv {
PyRotationWarper::PyRotationWarper(String warp_type, float scale)
{
Ptr<WarperCreator> warper_creator;
if (warp_type == "plane")
warper_creator = makePtr<cv::PlaneWarper>();
else if (warp_type == "affine")
warper_creator = makePtr<cv::AffineWarper>();
else if (warp_type == "cylindrical")
warper_creator = makePtr<cv::CylindricalWarper>();
else if (warp_type == "spherical")
warper_creator = makePtr<cv::SphericalWarper>();
else if (warp_type == "fisheye")
warper_creator = makePtr<cv::FisheyeWarper>();
else if (warp_type == "stereographic")
warper_creator = makePtr<cv::StereographicWarper>();
else if (warp_type == "compressedPlaneA2B1")
warper_creator = makePtr<cv::CompressedRectilinearWarper>(2.0f, 1.0f);
else if (warp_type == "compressedPlaneA1.5B1")
warper_creator = makePtr<cv::CompressedRectilinearWarper>(1.5f, 1.0f);
else if (warp_type == "compressedPlanePortraitA2B1")
warper_creator = makePtr<cv::CompressedRectilinearPortraitWarper>(2.0f, 1.0f);
else if (warp_type == "compressedPlanePortraitA1.5B1")
warper_creator = makePtr<cv::CompressedRectilinearPortraitWarper>(1.5f, 1.0f);
else if (warp_type == "paniniA2B1")
warper_creator = makePtr<cv::PaniniWarper>(2.0f, 1.0f);
else if (warp_type == "paniniA1.5B1")
warper_creator = makePtr<cv::PaniniWarper>(1.5f, 1.0f);
else if (warp_type == "paniniPortraitA2B1")
warper_creator = makePtr<cv::PaniniPortraitWarper>(2.0f, 1.0f);
else if (warp_type == "paniniPortraitA1.5B1")
warper_creator = makePtr<cv::PaniniPortraitWarper>(1.5f, 1.0f);
else if (warp_type == "mercator")
warper_creator = makePtr<cv::MercatorWarper>();
else if (warp_type == "transverseMercator")
warper_creator = makePtr<cv::TransverseMercatorWarper>();
if (warper_creator.get() != nullptr)
{
rw = warper_creator->create(scale);
}
else
CV_Error(Error::StsError, "unknown warper :" + warp_type);
}
Point2f PyRotationWarper::warpPoint(const Point2f &pt, InputArray K, InputArray R)
{
return rw.get()->warpPoint(pt, K, R);
}
Rect PyRotationWarper::buildMaps(Size src_size, InputArray K, InputArray R, OutputArray xmap, OutputArray ymap)
{
return rw.get()->buildMaps(src_size, K, R, xmap, ymap);
}
Point PyRotationWarper::warp(InputArray src, InputArray K, InputArray R, int interp_mode, int border_mode,
OutputArray dst)
{
if (rw.get() == nullptr)
CV_Error(Error::StsError, "Warper is null");
Point p = rw.get()->warp(src, K, R, interp_mode, border_mode, dst);
return p;
}
void PyRotationWarper::warpBackward(InputArray src, InputArray K, InputArray R, int interp_mode, int border_mode,
Size dst_size, OutputArray dst)
{
return rw.get()->warpBackward(src, K, R, interp_mode, border_mode, dst_size, dst);
}
Rect PyRotationWarper::warpRoi(Size src_size, InputArray K, InputArray R)
{
return rw.get()->warpRoi(src_size, K, R);
}
namespace detail {
void ProjectorBase::setCameraParams(InputArray _K, InputArray _R, InputArray _T)
@@ -157,7 +228,6 @@ Point PlaneWarper::warp(InputArray src, InputArray K, InputArray R, InputArray T
{
UMat uxmap, uymap;
Rect dst_roi = buildMaps(src.size(), K, R, T, uxmap, uymap);
dst.create(dst_roi.height + 1, dst_roi.width + 1, src.type());
remap(src, dst, uxmap, uymap, interp_mode, border_mode);