mirror of
https://github.com/opencv/opencv.git
synced 2026-07-30 15:53:03 +04:00
GPU: updated upsample, downsample functions, added pyrDown, pyrUp, added support of 16S filtering; put spherical warper on GPU (from opencv_stitching)
This commit is contained in:
@@ -47,14 +47,14 @@ using namespace cv;
|
||||
|
||||
static const float WEIGHT_EPS = 1e-5f;
|
||||
|
||||
Ptr<Blender> Blender::createDefault(int type)
|
||||
Ptr<Blender> Blender::createDefault(int type, bool try_gpu)
|
||||
{
|
||||
if (type == NO)
|
||||
return new Blender();
|
||||
if (type == FEATHER)
|
||||
return new FeatherBlender();
|
||||
if (type == MULTI_BAND)
|
||||
return new MultiBandBlender();
|
||||
return new MultiBandBlender(try_gpu);
|
||||
CV_Error(CV_StsBadArg, "unsupported blending method");
|
||||
return NULL;
|
||||
}
|
||||
@@ -153,6 +153,13 @@ void FeatherBlender::blend(Mat &dst, Mat &dst_mask)
|
||||
}
|
||||
|
||||
|
||||
MultiBandBlender::MultiBandBlender(int try_gpu, int num_bands)
|
||||
{
|
||||
setNumBands(num_bands);
|
||||
can_use_gpu_ = try_gpu && gpu::getCudaEnabledDeviceCount();
|
||||
}
|
||||
|
||||
|
||||
void MultiBandBlender::prepare(Rect dst_roi)
|
||||
{
|
||||
dst_roi_final_ = dst_roi;
|
||||
@@ -222,14 +229,14 @@ void MultiBandBlender::feed(const Mat &img, const Mat &mask, Point tl)
|
||||
int right = br_new.x - tl.x - img.cols;
|
||||
|
||||
// Create the source image Laplacian pyramid
|
||||
vector<Mat> src_pyr_gauss(num_bands_ + 1);
|
||||
copyMakeBorder(img, src_pyr_gauss[0], top, bottom, left, right,
|
||||
Mat img_with_border;
|
||||
copyMakeBorder(img, img_with_border, top, bottom, left, right,
|
||||
BORDER_REFLECT);
|
||||
for (int i = 0; i < num_bands_; ++i)
|
||||
pyrDown(src_pyr_gauss[i], src_pyr_gauss[i + 1]);
|
||||
vector<Mat> src_pyr_laplace;
|
||||
createLaplacePyr(src_pyr_gauss, src_pyr_laplace);
|
||||
src_pyr_gauss.clear();
|
||||
if (can_use_gpu_)
|
||||
createLaplacePyrGpu(img_with_border, num_bands_, src_pyr_laplace);
|
||||
else
|
||||
createLaplacePyr(img_with_border, num_bands_, src_pyr_laplace);
|
||||
|
||||
// Create the weight map Gaussian pyramid
|
||||
Mat weight_map;
|
||||
@@ -267,7 +274,7 @@ void MultiBandBlender::feed(const Mat &img, const Mat &mask, Point tl)
|
||||
}
|
||||
x_tl /= 2; y_tl /= 2;
|
||||
x_br /= 2; y_br /= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -319,21 +326,43 @@ void createWeightMap(const Mat &mask, float sharpness, Mat &weight)
|
||||
}
|
||||
|
||||
|
||||
void createLaplacePyr(const vector<Mat> &pyr_gauss, vector<Mat> &pyr_laplace)
|
||||
void createLaplacePyr(const Mat &img, int num_levels, vector<Mat> &pyr)
|
||||
{
|
||||
if (pyr_gauss.size() == 0)
|
||||
return;
|
||||
pyr_laplace.resize(pyr_gauss.size());
|
||||
pyr.resize(num_levels + 1);
|
||||
pyr[0] = img;
|
||||
for (int i = 0; i < num_levels; ++i)
|
||||
pyrDown(pyr[i], pyr[i + 1]);
|
||||
Mat tmp;
|
||||
for (size_t i = 0; i < pyr_laplace.size() - 1; ++i)
|
||||
for (int i = 0; i < num_levels; ++i)
|
||||
{
|
||||
pyrUp(pyr_gauss[i + 1], tmp, pyr_gauss[i].size());
|
||||
subtract(pyr_gauss[i], tmp, pyr_laplace[i]);
|
||||
pyrUp(pyr[i + 1], tmp, pyr[i].size());
|
||||
subtract(pyr[i], tmp, pyr[i]);
|
||||
}
|
||||
pyr_laplace[pyr_laplace.size() - 1] = pyr_gauss[pyr_laplace.size() - 1].clone();
|
||||
}
|
||||
|
||||
|
||||
void createLaplacePyrGpu(const Mat &img, int num_levels, vector<Mat> &pyr)
|
||||
{
|
||||
pyr.resize(num_levels + 1);
|
||||
|
||||
vector<gpu::GpuMat> gpu_pyr(num_levels + 1);
|
||||
gpu_pyr[0] = img;
|
||||
for (int i = 0; i < num_levels; ++i)
|
||||
gpu::pyrDown(gpu_pyr[i], gpu_pyr[i + 1]);
|
||||
|
||||
gpu::GpuMat tmp;
|
||||
for (int i = 0; i < num_levels; ++i)
|
||||
{
|
||||
gpu::pyrUp(gpu_pyr[i + 1], tmp);
|
||||
gpu::subtract(gpu_pyr[i], tmp, gpu_pyr[i]);
|
||||
pyr[i] = gpu_pyr[i];
|
||||
}
|
||||
|
||||
pyr[num_levels] = gpu_pyr[num_levels];
|
||||
}
|
||||
|
||||
|
||||
|
||||
void restoreImageFromLaplacePyr(vector<Mat> &pyr)
|
||||
{
|
||||
if (pyr.size() == 0)
|
||||
|
||||
@@ -38,77 +38,79 @@
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
#ifndef __OPENCV_BLENDERS_HPP__
|
||||
#define __OPENCV_BLENDERS_HPP__
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
// Simple blender which puts one image over another
|
||||
class Blender
|
||||
{
|
||||
public:
|
||||
enum { NO, FEATHER, MULTI_BAND };
|
||||
static cv::Ptr<Blender> createDefault(int type);
|
||||
|
||||
void prepare(const std::vector<cv::Point> &corners, const std::vector<cv::Size> &sizes);
|
||||
virtual void prepare(cv::Rect dst_roi);
|
||||
virtual void feed(const cv::Mat &img, const cv::Mat &mask, cv::Point tl);
|
||||
virtual void blend(cv::Mat &dst, cv::Mat &dst_mask);
|
||||
|
||||
protected:
|
||||
cv::Mat dst_, dst_mask_;
|
||||
cv::Rect dst_roi_;
|
||||
};
|
||||
|
||||
|
||||
class FeatherBlender : public Blender
|
||||
{
|
||||
public:
|
||||
FeatherBlender(float sharpness = 0.02f) { setSharpness(sharpness); }
|
||||
float sharpness() const { return sharpness_; }
|
||||
void setSharpness(float val) { sharpness_ = val; }
|
||||
|
||||
void prepare(cv::Rect dst_roi);
|
||||
void feed(const cv::Mat &img, const cv::Mat &mask, cv::Point tl);
|
||||
void blend(cv::Mat &dst, cv::Mat &dst_mask);
|
||||
|
||||
private:
|
||||
float sharpness_;
|
||||
cv::Mat weight_map_;
|
||||
cv::Mat dst_weight_map_;
|
||||
};
|
||||
|
||||
|
||||
class MultiBandBlender : public Blender
|
||||
{
|
||||
public:
|
||||
MultiBandBlender(int num_bands = 5) { setNumBands(num_bands); }
|
||||
int numBands() const { return actual_num_bands_; }
|
||||
void setNumBands(int val) { actual_num_bands_ = val; }
|
||||
|
||||
void prepare(cv::Rect dst_roi);
|
||||
void feed(const cv::Mat &img, const cv::Mat &mask, cv::Point tl);
|
||||
void blend(cv::Mat &dst, cv::Mat &dst_mask);
|
||||
|
||||
private:
|
||||
int actual_num_bands_, num_bands_;
|
||||
std::vector<cv::Mat> dst_pyr_laplace_;
|
||||
std::vector<cv::Mat> dst_band_weights_;
|
||||
cv::Rect dst_roi_final_;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Auxiliary functions
|
||||
|
||||
void normalize(const cv::Mat& weight, cv::Mat& src);
|
||||
|
||||
void createWeightMap(const cv::Mat& mask, float sharpness, cv::Mat& weight);
|
||||
|
||||
void createLaplacePyr(const std::vector<cv::Mat>& pyr_gauss, std::vector<cv::Mat>& pyr_laplace);
|
||||
|
||||
// Restores source image in-place (result will be stored in pyr[0])
|
||||
void restoreImageFromLaplacePyr(std::vector<cv::Mat>& pyr);
|
||||
|
||||
#endif // __OPENCV_BLENDERS_HPP__
|
||||
//M*/
|
||||
#ifndef __OPENCV_BLENDERS_HPP__
|
||||
#define __OPENCV_BLENDERS_HPP__
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
// Simple blender which puts one image over another
|
||||
class Blender
|
||||
{
|
||||
public:
|
||||
enum { NO, FEATHER, MULTI_BAND };
|
||||
static cv::Ptr<Blender> createDefault(int type, bool try_gpu = false);
|
||||
|
||||
void prepare(const std::vector<cv::Point> &corners, const std::vector<cv::Size> &sizes);
|
||||
virtual void prepare(cv::Rect dst_roi);
|
||||
virtual void feed(const cv::Mat &img, const cv::Mat &mask, cv::Point tl);
|
||||
virtual void blend(cv::Mat &dst, cv::Mat &dst_mask);
|
||||
|
||||
protected:
|
||||
cv::Mat dst_, dst_mask_;
|
||||
cv::Rect dst_roi_;
|
||||
};
|
||||
|
||||
|
||||
class FeatherBlender : public Blender
|
||||
{
|
||||
public:
|
||||
FeatherBlender(float sharpness = 0.02f) { setSharpness(sharpness); }
|
||||
float sharpness() const { return sharpness_; }
|
||||
void setSharpness(float val) { sharpness_ = val; }
|
||||
|
||||
void prepare(cv::Rect dst_roi);
|
||||
void feed(const cv::Mat &img, const cv::Mat &mask, cv::Point tl);
|
||||
void blend(cv::Mat &dst, cv::Mat &dst_mask);
|
||||
|
||||
private:
|
||||
float sharpness_;
|
||||
cv::Mat weight_map_;
|
||||
cv::Mat dst_weight_map_;
|
||||
};
|
||||
|
||||
|
||||
class MultiBandBlender : public Blender
|
||||
{
|
||||
public:
|
||||
MultiBandBlender(int try_gpu = false, int num_bands = 5);
|
||||
int numBands() const { return actual_num_bands_; }
|
||||
void setNumBands(int val) { actual_num_bands_ = val; }
|
||||
|
||||
void prepare(cv::Rect dst_roi);
|
||||
void feed(const cv::Mat &img, const cv::Mat &mask, cv::Point tl);
|
||||
void blend(cv::Mat &dst, cv::Mat &dst_mask);
|
||||
|
||||
private:
|
||||
int actual_num_bands_, num_bands_;
|
||||
std::vector<cv::Mat> dst_pyr_laplace_;
|
||||
std::vector<cv::Mat> dst_band_weights_;
|
||||
cv::Rect dst_roi_final_;
|
||||
bool can_use_gpu_;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Auxiliary functions
|
||||
|
||||
void normalize(const cv::Mat& weight, cv::Mat& src);
|
||||
|
||||
void createWeightMap(const cv::Mat& mask, float sharpness, cv::Mat& weight);
|
||||
|
||||
void createLaplacePyr(const cv::Mat &img, int num_levels, std::vector<cv::Mat>& pyr);
|
||||
void createLaplacePyrGpu(const cv::Mat &img, int num_levels, std::vector<cv::Mat>& pyr);
|
||||
|
||||
// Restores source image in-place (result will be stored in pyr[0])
|
||||
void restoreImageFromLaplacePyr(std::vector<cv::Mat>& pyr);
|
||||
|
||||
#endif // __OPENCV_BLENDERS_HPP__
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
//
|
||||
//M*/
|
||||
|
||||
// We follow to methods described in these two papers:
|
||||
// We follow to these papers:
|
||||
// 1) Construction of panoramic mosaics with global and local alignment.
|
||||
// Heung-Yeung Shum and Richard Szeliski. 2000.
|
||||
// 2) Eliminating Ghosting and Exposure Artifacts in Image Mosaics.
|
||||
@@ -461,7 +461,7 @@ int main(int argc, char* argv[])
|
||||
|
||||
// Warp images and their masks
|
||||
Ptr<Warper> warper = Warper::createByCameraFocal(static_cast<float>(warped_image_scale * seam_work_aspect),
|
||||
warp_type);
|
||||
warp_type, try_gpu);
|
||||
for (int i = 0; i < num_images; ++i)
|
||||
{
|
||||
corners[i] = warper->warp(images[i], static_cast<float>(cameras[i].focal * seam_work_aspect),
|
||||
@@ -522,7 +522,7 @@ int main(int argc, char* argv[])
|
||||
|
||||
// Update warped image scale
|
||||
warped_image_scale *= static_cast<float>(compose_work_aspect);
|
||||
warper = Warper::createByCameraFocal(warped_image_scale, warp_type);
|
||||
warper = Warper::createByCameraFocal(warped_image_scale, warp_type, try_gpu);
|
||||
|
||||
// Update corners and sizes
|
||||
for (int i = 0; i < num_images; ++i)
|
||||
@@ -565,19 +565,19 @@ int main(int argc, char* argv[])
|
||||
img_warped.convertTo(img_warped_s, CV_16S);
|
||||
img_warped.release();
|
||||
img.release();
|
||||
mask.release();
|
||||
mask.release();
|
||||
|
||||
dilate(masks_warped[img_idx], dilated_mask, Mat());
|
||||
resize(dilated_mask, seam_mask, mask_warped.size());
|
||||
mask_warped = seam_mask & mask_warped;
|
||||
|
||||
if (static_cast<Blender*>(blender) == 0)
|
||||
{
|
||||
blender = Blender::createDefault(blend_type);
|
||||
{
|
||||
blender = Blender::createDefault(blend_type, try_gpu);
|
||||
Size dst_sz = resultRoi(corners, sizes).size();
|
||||
float blend_width = sqrt(static_cast<float>(dst_sz.area())) * blend_strength / 100.f;
|
||||
if (blend_width < 1.f)
|
||||
blender = Blender::createDefault(Blender::NO);
|
||||
blender = Blender::createDefault(Blender::NO, try_gpu);
|
||||
else if (blend_type == Blender::MULTI_BAND)
|
||||
{
|
||||
MultiBandBlender* mb = dynamic_cast<MultiBandBlender*>(static_cast<Blender*>(blender));
|
||||
@@ -594,7 +594,7 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
|
||||
// Blend the current image
|
||||
blender->feed(img_warped_s, mask_warped, corners[img_idx]);
|
||||
blender->feed(img_warped_s, mask_warped, corners[img_idx]);
|
||||
}
|
||||
|
||||
Mat result, result_mask;
|
||||
|
||||
@@ -257,15 +257,7 @@ void FeaturesMatcher::operator ()(const vector<ImageFeatures> &features, vector<
|
||||
|
||||
namespace
|
||||
{
|
||||
class PairLess
|
||||
{
|
||||
public:
|
||||
bool operator()(const pair<int,int>& l, const pair<int,int>& r) const
|
||||
{
|
||||
return l.first < r.first || (l.first == r.first && l.second < r.second);
|
||||
}
|
||||
};
|
||||
typedef set<pair<int,int>,PairLess> MatchesSet;
|
||||
typedef set<pair<int,int> > MatchesSet;
|
||||
|
||||
// These two classes are aimed to find features matches only, not to
|
||||
// estimate homography
|
||||
|
||||
+130
-108
@@ -38,111 +38,133 @@
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
#include "warpers.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
Ptr<Warper> Warper::createByCameraFocal(float focal, int type)
|
||||
{
|
||||
if (type == PLANE)
|
||||
return new PlaneWarper(focal);
|
||||
if (type == CYLINDRICAL)
|
||||
return new CylindricalWarper(focal);
|
||||
if (type == SPHERICAL)
|
||||
return new SphericalWarper(focal);
|
||||
CV_Error(CV_StsBadArg, "unsupported warping type");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void ProjectorBase::setTransformation(const Mat &R)
|
||||
{
|
||||
CV_Assert(R.size() == Size(3, 3));
|
||||
CV_Assert(R.type() == CV_32F);
|
||||
r[0] = R.at<float>(0, 0); r[1] = R.at<float>(0, 1); r[2] = R.at<float>(0, 2);
|
||||
r[3] = R.at<float>(1, 0); r[4] = R.at<float>(1, 1); r[5] = R.at<float>(1, 2);
|
||||
r[6] = R.at<float>(2, 0); r[7] = R.at<float>(2, 1); r[8] = R.at<float>(2, 2);
|
||||
|
||||
Mat Rinv = R.inv();
|
||||
rinv[0] = Rinv.at<float>(0, 0); rinv[1] = Rinv.at<float>(0, 1); rinv[2] = Rinv.at<float>(0, 2);
|
||||
rinv[3] = Rinv.at<float>(1, 0); rinv[4] = Rinv.at<float>(1, 1); rinv[5] = Rinv.at<float>(1, 2);
|
||||
rinv[6] = Rinv.at<float>(2, 0); rinv[7] = Rinv.at<float>(2, 1); rinv[8] = Rinv.at<float>(2, 2);
|
||||
}
|
||||
|
||||
|
||||
void PlaneWarper::detectResultRoi(Point &dst_tl, Point &dst_br)
|
||||
{
|
||||
float tl_uf = numeric_limits<float>::max();
|
||||
float tl_vf = numeric_limits<float>::max();
|
||||
float br_uf = -numeric_limits<float>::max();
|
||||
float br_vf = -numeric_limits<float>::max();
|
||||
|
||||
float u, v;
|
||||
|
||||
projector_.mapForward(0, 0, u, v);
|
||||
tl_uf = min(tl_uf, u); tl_vf = min(tl_vf, v);
|
||||
br_uf = max(br_uf, u); br_vf = max(br_vf, v);
|
||||
|
||||
projector_.mapForward(0, static_cast<float>(src_size_.height - 1), u, v);
|
||||
tl_uf = min(tl_uf, u); tl_vf = min(tl_vf, v);
|
||||
br_uf = max(br_uf, u); br_vf = max(br_vf, v);
|
||||
|
||||
projector_.mapForward(static_cast<float>(src_size_.width - 1), 0, u, v);
|
||||
tl_uf = min(tl_uf, u); tl_vf = min(tl_vf, v);
|
||||
br_uf = max(br_uf, u); br_vf = max(br_vf, v);
|
||||
|
||||
projector_.mapForward(static_cast<float>(src_size_.width - 1), static_cast<float>(src_size_.height - 1), u, v);
|
||||
tl_uf = min(tl_uf, u); tl_vf = min(tl_vf, v);
|
||||
br_uf = max(br_uf, u); br_vf = max(br_vf, v);
|
||||
|
||||
dst_tl.x = static_cast<int>(tl_uf);
|
||||
dst_tl.y = static_cast<int>(tl_vf);
|
||||
dst_br.x = static_cast<int>(br_uf);
|
||||
dst_br.y = static_cast<int>(br_vf);
|
||||
}
|
||||
|
||||
|
||||
void SphericalWarper::detectResultRoi(Point &dst_tl, Point &dst_br)
|
||||
{
|
||||
detectResultRoiByBorder(dst_tl, dst_br);
|
||||
|
||||
float tl_uf = static_cast<float>(dst_tl.x);
|
||||
float tl_vf = static_cast<float>(dst_tl.y);
|
||||
float br_uf = static_cast<float>(dst_br.x);
|
||||
float br_vf = static_cast<float>(dst_br.y);
|
||||
|
||||
float x = projector_.rinv[1];
|
||||
float y = projector_.rinv[4];
|
||||
float z = projector_.rinv[7];
|
||||
if (y > 0.f)
|
||||
{
|
||||
x = projector_.focal * x / z + src_size_.width * 0.5f;
|
||||
y = projector_.focal * y / z + src_size_.height * 0.5f;
|
||||
if (x > 0.f && x < src_size_.width && y > 0.f && y < src_size_.height)
|
||||
{
|
||||
tl_uf = min(tl_uf, 0.f); tl_vf = min(tl_vf, static_cast<float>(CV_PI * projector_.scale));
|
||||
br_uf = max(br_uf, 0.f); br_vf = max(br_vf, static_cast<float>(CV_PI * projector_.scale));
|
||||
}
|
||||
}
|
||||
|
||||
x = projector_.rinv[1];
|
||||
y = -projector_.rinv[4];
|
||||
z = projector_.rinv[7];
|
||||
if (y > 0.f)
|
||||
{
|
||||
x = projector_.focal * x / z + src_size_.width * 0.5f;
|
||||
y = projector_.focal * y / z + src_size_.height * 0.5f;
|
||||
if (x > 0.f && x < src_size_.width && y > 0.f && y < src_size_.height)
|
||||
{
|
||||
tl_uf = min(tl_uf, 0.f); tl_vf = min(tl_vf, static_cast<float>(0));
|
||||
br_uf = max(br_uf, 0.f); br_vf = max(br_vf, static_cast<float>(0));
|
||||
}
|
||||
}
|
||||
|
||||
dst_tl.x = static_cast<int>(tl_uf);
|
||||
dst_tl.y = static_cast<int>(tl_vf);
|
||||
dst_br.x = static_cast<int>(br_uf);
|
||||
dst_br.y = static_cast<int>(br_vf);
|
||||
}
|
||||
//M*/
|
||||
#include "warpers.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
Ptr<Warper> Warper::createByCameraFocal(float focal, int type, bool try_gpu)
|
||||
{
|
||||
bool can_use_gpu = try_gpu && gpu::getCudaEnabledDeviceCount();
|
||||
if (type == PLANE)
|
||||
return new PlaneWarper(focal);
|
||||
if (type == CYLINDRICAL)
|
||||
return new CylindricalWarper(focal);
|
||||
if (type == SPHERICAL)
|
||||
return !can_use_gpu ? new SphericalWarper(focal) : new SphericalWarperGpu(focal);
|
||||
CV_Error(CV_StsBadArg, "unsupported warping type");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void ProjectorBase::setTransformation(const Mat &R)
|
||||
{
|
||||
CV_Assert(R.size() == Size(3, 3));
|
||||
CV_Assert(R.type() == CV_32F);
|
||||
r[0] = R.at<float>(0, 0); r[1] = R.at<float>(0, 1); r[2] = R.at<float>(0, 2);
|
||||
r[3] = R.at<float>(1, 0); r[4] = R.at<float>(1, 1); r[5] = R.at<float>(1, 2);
|
||||
r[6] = R.at<float>(2, 0); r[7] = R.at<float>(2, 1); r[8] = R.at<float>(2, 2);
|
||||
|
||||
Mat Rinv = R.inv();
|
||||
rinv[0] = Rinv.at<float>(0, 0); rinv[1] = Rinv.at<float>(0, 1); rinv[2] = Rinv.at<float>(0, 2);
|
||||
rinv[3] = Rinv.at<float>(1, 0); rinv[4] = Rinv.at<float>(1, 1); rinv[5] = Rinv.at<float>(1, 2);
|
||||
rinv[6] = Rinv.at<float>(2, 0); rinv[7] = Rinv.at<float>(2, 1); rinv[8] = Rinv.at<float>(2, 2);
|
||||
}
|
||||
|
||||
|
||||
void PlaneWarper::detectResultRoi(Point &dst_tl, Point &dst_br)
|
||||
{
|
||||
float tl_uf = numeric_limits<float>::max();
|
||||
float tl_vf = numeric_limits<float>::max();
|
||||
float br_uf = -numeric_limits<float>::max();
|
||||
float br_vf = -numeric_limits<float>::max();
|
||||
|
||||
float u, v;
|
||||
|
||||
projector_.mapForward(0, 0, u, v);
|
||||
tl_uf = min(tl_uf, u); tl_vf = min(tl_vf, v);
|
||||
br_uf = max(br_uf, u); br_vf = max(br_vf, v);
|
||||
|
||||
projector_.mapForward(0, static_cast<float>(src_size_.height - 1), u, v);
|
||||
tl_uf = min(tl_uf, u); tl_vf = min(tl_vf, v);
|
||||
br_uf = max(br_uf, u); br_vf = max(br_vf, v);
|
||||
|
||||
projector_.mapForward(static_cast<float>(src_size_.width - 1), 0, u, v);
|
||||
tl_uf = min(tl_uf, u); tl_vf = min(tl_vf, v);
|
||||
br_uf = max(br_uf, u); br_vf = max(br_vf, v);
|
||||
|
||||
projector_.mapForward(static_cast<float>(src_size_.width - 1), static_cast<float>(src_size_.height - 1), u, v);
|
||||
tl_uf = min(tl_uf, u); tl_vf = min(tl_vf, v);
|
||||
br_uf = max(br_uf, u); br_vf = max(br_vf, v);
|
||||
|
||||
dst_tl.x = static_cast<int>(tl_uf);
|
||||
dst_tl.y = static_cast<int>(tl_vf);
|
||||
dst_br.x = static_cast<int>(br_uf);
|
||||
dst_br.y = static_cast<int>(br_vf);
|
||||
}
|
||||
|
||||
|
||||
void SphericalWarper::detectResultRoi(Point &dst_tl, Point &dst_br)
|
||||
{
|
||||
detectResultRoiByBorder(dst_tl, dst_br);
|
||||
|
||||
float tl_uf = static_cast<float>(dst_tl.x);
|
||||
float tl_vf = static_cast<float>(dst_tl.y);
|
||||
float br_uf = static_cast<float>(dst_br.x);
|
||||
float br_vf = static_cast<float>(dst_br.y);
|
||||
|
||||
float x = projector_.rinv[1];
|
||||
float y = projector_.rinv[4];
|
||||
float z = projector_.rinv[7];
|
||||
if (y > 0.f)
|
||||
{
|
||||
x = projector_.focal * x / z + src_size_.width * 0.5f;
|
||||
y = projector_.focal * y / z + src_size_.height * 0.5f;
|
||||
if (x > 0.f && x < src_size_.width && y > 0.f && y < src_size_.height)
|
||||
{
|
||||
tl_uf = min(tl_uf, 0.f); tl_vf = min(tl_vf, static_cast<float>(CV_PI * projector_.scale));
|
||||
br_uf = max(br_uf, 0.f); br_vf = max(br_vf, static_cast<float>(CV_PI * projector_.scale));
|
||||
}
|
||||
}
|
||||
|
||||
x = projector_.rinv[1];
|
||||
y = -projector_.rinv[4];
|
||||
z = projector_.rinv[7];
|
||||
if (y > 0.f)
|
||||
{
|
||||
x = projector_.focal * x / z + src_size_.width * 0.5f;
|
||||
y = projector_.focal * y / z + src_size_.height * 0.5f;
|
||||
if (x > 0.f && x < src_size_.width && y > 0.f && y < src_size_.height)
|
||||
{
|
||||
tl_uf = min(tl_uf, 0.f); tl_vf = min(tl_vf, static_cast<float>(0));
|
||||
br_uf = max(br_uf, 0.f); br_vf = max(br_vf, static_cast<float>(0));
|
||||
}
|
||||
}
|
||||
|
||||
dst_tl.x = static_cast<int>(tl_uf);
|
||||
dst_tl.y = static_cast<int>(tl_vf);
|
||||
dst_br.x = static_cast<int>(br_uf);
|
||||
dst_br.y = static_cast<int>(br_vf);
|
||||
}
|
||||
|
||||
|
||||
Point SphericalWarperGpu::warp(const Mat &src, float focal, const Mat &R, Mat &dst,
|
||||
int interp_mode, int border_mode)
|
||||
{
|
||||
src_size_ = src.size();
|
||||
projector_.size = src.size();
|
||||
projector_.focal = focal;
|
||||
projector_.setTransformation(R);
|
||||
|
||||
cv::Point dst_tl, dst_br;
|
||||
detectResultRoi(dst_tl, dst_br);
|
||||
|
||||
gpu::buildWarpSphericalMaps(src.size(), Rect(dst_tl, Point(dst_br.x+1, dst_br.y+1)),
|
||||
R, focal, projector_.scale, d_xmap_, d_ymap_);
|
||||
|
||||
dst.create(dst_br.y - dst_tl.y + 1, dst_br.x - dst_tl.x + 1, src.type());
|
||||
remap(src, dst, Mat(d_xmap_), Mat(d_ymap_), interp_mode, border_mode);
|
||||
|
||||
return dst_tl;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
@@ -48,7 +48,7 @@ class Warper
|
||||
{
|
||||
public:
|
||||
enum { PLANE, CYLINDRICAL, SPHERICAL };
|
||||
static cv::Ptr<Warper> createByCameraFocal(float focal, int type);
|
||||
static cv::Ptr<Warper> createByCameraFocal(float focal, int type, bool try_gpu = false);
|
||||
|
||||
virtual ~Warper() {}
|
||||
virtual cv::Point warp(const cv::Mat &src, float focal, const cv::Mat& R, cv::Mat &dst,
|
||||
@@ -73,10 +73,10 @@ template <class P>
|
||||
class WarperBase : public Warper
|
||||
{
|
||||
public:
|
||||
cv::Point warp(const cv::Mat &src, float focal, const cv::Mat &R, cv::Mat &dst,
|
||||
int interp_mode, int border_mode);
|
||||
virtual cv::Point warp(const cv::Mat &src, float focal, const cv::Mat &R, cv::Mat &dst,
|
||||
int interp_mode, int border_mode);
|
||||
|
||||
cv::Rect warpRoi(const cv::Size &sz, float focal, const cv::Mat &R);
|
||||
virtual cv::Rect warpRoi(const cv::Size &sz, float focal, const cv::Mat &R);
|
||||
|
||||
protected:
|
||||
// Detects ROI of the destination image. It's correct for any projection.
|
||||
@@ -95,7 +95,6 @@ struct PlaneProjector : ProjectorBase
|
||||
{
|
||||
void mapForward(float x, float y, float &u, float &v);
|
||||
void mapBackward(float u, float v, float &x, float &y);
|
||||
|
||||
float plane_dist;
|
||||
};
|
||||
|
||||
@@ -129,11 +128,23 @@ class SphericalWarper : public WarperBase<SphericalProjector>
|
||||
public:
|
||||
SphericalWarper(float scale = 300.f) { projector_.scale = scale; }
|
||||
|
||||
private:
|
||||
protected:
|
||||
void detectResultRoi(cv::Point &dst_tl, cv::Point &dst_br);
|
||||
};
|
||||
|
||||
|
||||
class SphericalWarperGpu : public SphericalWarper
|
||||
{
|
||||
public:
|
||||
SphericalWarperGpu(float scale = 300.f) : SphericalWarper(scale) {}
|
||||
cv::Point warp(const cv::Mat &src, float focal, const cv::Mat &R, cv::Mat &dst,
|
||||
int interp_mode, int border_mode);
|
||||
|
||||
private:
|
||||
cv::gpu::GpuMat d_xmap_, d_ymap_, d_dst_;
|
||||
};
|
||||
|
||||
|
||||
struct CylindricalProjector : ProjectorBase
|
||||
{
|
||||
void mapForward(float x, float y, float &u, float &v);
|
||||
|
||||
Reference in New Issue
Block a user