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:
committed by
Alexander Alekhin
parent
fd27d5ea00
commit
2fb409b286
@@ -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");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)) {}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user