Stitching: added CV_16S weights support to the multiband blender

This commit is contained in:
Andrey Kamaev 2012-03-07 14:23:55 +00:00
parent 796f839b75
commit 679f1dad99
2 changed files with 140 additions and 41 deletions

View File

@ -96,7 +96,7 @@ private:
class CV_EXPORTS MultiBandBlender : public Blender
{
public:
MultiBandBlender(int try_gpu = false, int num_bands = 5);
MultiBandBlender(int try_gpu = false, int num_bands = 5, int weight_type = CV_32F);
int numBands() const { return actual_num_bands_; }
void setNumBands(int val) { actual_num_bands_ = val; }
@ -111,6 +111,7 @@ private:
std::vector<Mat> dst_band_weights_;
Rect dst_roi_final_;
bool can_use_gpu_;
int weight_type_; //CV_32F or CV_16S
};

View File

@ -186,7 +186,7 @@ Rect FeatherBlender::createWeightMaps(const vector<Mat> &masks, const vector<Poi
}
MultiBandBlender::MultiBandBlender(int try_gpu, int num_bands)
MultiBandBlender::MultiBandBlender(int try_gpu, int num_bands, int weight_type)
{
setNumBands(num_bands);
#ifdef HAVE_OPENCV_GPU
@ -194,6 +194,8 @@ MultiBandBlender::MultiBandBlender(int try_gpu, int num_bands)
#else
can_use_gpu_ = false;
#endif
CV_Assert(weight_type == CV_32F || weight_type == CV_16S);
weight_type_ = weight_type;
}
@ -215,7 +217,7 @@ void MultiBandBlender::prepare(Rect dst_roi)
dst_pyr_laplace_[0] = dst_;
dst_band_weights_.resize(num_bands_ + 1);
dst_band_weights_[0].create(dst_roi.size(), CV_32F);
dst_band_weights_[0].create(dst_roi.size(), weight_type_);
dst_band_weights_[0].setTo(0);
for (int i = 1; i <= num_bands_; ++i)
@ -223,7 +225,7 @@ void MultiBandBlender::prepare(Rect dst_roi)
dst_pyr_laplace_[i].create((dst_pyr_laplace_[i - 1].rows + 1) / 2,
(dst_pyr_laplace_[i - 1].cols + 1) / 2, CV_16SC3);
dst_band_weights_[i].create((dst_band_weights_[i - 1].rows + 1) / 2,
(dst_band_weights_[i - 1].cols + 1) / 2, CV_32F);
(dst_band_weights_[i - 1].cols + 1) / 2, weight_type_);
dst_pyr_laplace_[i].setTo(Scalar::all(0));
dst_band_weights_[i].setTo(0);
}
@ -232,7 +234,7 @@ void MultiBandBlender::prepare(Rect dst_roi)
void MultiBandBlender::feed(const Mat &img, const Mat &mask, Point tl)
{
CV_Assert(img.type() == CV_16SC3);
CV_Assert(img.type() == CV_16SC3 || img.type() == CV_8UC3);
CV_Assert(mask.type() == CV_8U);
// Keep source image in memory with small border
@ -270,17 +272,27 @@ void MultiBandBlender::feed(const Mat &img, const Mat &mask, Point tl)
copyMakeBorder(img, img_with_border, top, bottom, left, right,
BORDER_REFLECT);
vector<Mat> src_pyr_laplace;
if (can_use_gpu_)
if (can_use_gpu_ && img_with_border.depth() == CV_16S)
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;
mask.convertTo(weight_map, CV_32F, 1./255.);
vector<Mat> weight_pyr_gauss(num_bands_ + 1);
copyMakeBorder(weight_map, weight_pyr_gauss[0], top, bottom, left, right,
BORDER_CONSTANT);
if(weight_type_ == CV_32F)
{
mask.convertTo(weight_map, CV_32F, 1./255.);
}
else// weight_type_ == CV_16S
{
add(mask, 1, weight_map, noArray(), CV_16S);
weight_map.setTo(1, mask == 0);
}
copyMakeBorder(weight_map, weight_pyr_gauss[0], top, bottom, left, right, BORDER_CONSTANT);
for (int i = 0; i < num_bands_; ++i)
pyrDown(weight_pyr_gauss[i], weight_pyr_gauss[i + 1]);
@ -290,27 +302,55 @@ void MultiBandBlender::feed(const Mat &img, const Mat &mask, Point tl)
int x_br = br_new.x - dst_roi_.x;
// Add weighted layer of the source image to the final Laplacian pyramid layer
for (int i = 0; i <= num_bands_; ++i)
if(weight_type_ == CV_32F)
{
for (int y = y_tl; y < y_br; ++y)
for (int i = 0; i <= num_bands_; ++i)
{
int y_ = y - y_tl;
const Point3_<short>* src_row = src_pyr_laplace[i].ptr<Point3_<short> >(y_);
Point3_<short>* dst_row = dst_pyr_laplace_[i].ptr<Point3_<short> >(y);
const float* weight_row = weight_pyr_gauss[i].ptr<float>(y_);
float* dst_weight_row = dst_band_weights_[i].ptr<float>(y);
for (int x = x_tl; x < x_br; ++x)
for (int y = y_tl; y < y_br; ++y)
{
int x_ = x - x_tl;
dst_row[x].x += static_cast<short>(src_row[x_].x * weight_row[x_]);
dst_row[x].y += static_cast<short>(src_row[x_].y * weight_row[x_]);
dst_row[x].z += static_cast<short>(src_row[x_].z * weight_row[x_]);
dst_weight_row[x] += weight_row[x_];
int y_ = y - y_tl;
const Point3_<short>* src_row = src_pyr_laplace[i].ptr<Point3_<short> >(y_);
Point3_<short>* dst_row = dst_pyr_laplace_[i].ptr<Point3_<short> >(y);
const float* weight_row = weight_pyr_gauss[i].ptr<float>(y_);
float* dst_weight_row = dst_band_weights_[i].ptr<float>(y);
for (int x = x_tl; x < x_br; ++x)
{
int x_ = x - x_tl;
dst_row[x].x += static_cast<short>(src_row[x_].x * weight_row[x_]);
dst_row[x].y += static_cast<short>(src_row[x_].y * weight_row[x_]);
dst_row[x].z += static_cast<short>(src_row[x_].z * weight_row[x_]);
dst_weight_row[x] += weight_row[x_];
}
}
x_tl /= 2; y_tl /= 2;
x_br /= 2; y_br /= 2;
}
}
else// weight_type_ == CV_16S
{
for (int i = 0; i <= num_bands_; ++i)
{
for (int y = y_tl; y < y_br; ++y)
{
int y_ = y - y_tl;
const Point3_<short>* src_row = src_pyr_laplace[i].ptr<Point3_<short> >(y_);
Point3_<short>* dst_row = dst_pyr_laplace_[i].ptr<Point3_<short> >(y);
const short* weight_row = weight_pyr_gauss[i].ptr<short>(y_);
short* dst_weight_row = dst_band_weights_[i].ptr<short>(y);
for (int x = x_tl; x < x_br; ++x)
{
int x_ = x - x_tl;
dst_row[x].x += short((src_row[x_].x * weight_row[x_]) >> 8);
dst_row[x].y += short((src_row[x_].y * weight_row[x_]) >> 8);
dst_row[x].z += short((src_row[x_].z * weight_row[x_]) >> 8);
dst_weight_row[x] += weight_row[x_];
}
}
x_tl /= 2; y_tl /= 2;
x_br /= 2; y_br /= 2;
}
x_tl /= 2; y_tl /= 2;
x_br /= 2; y_br /= 2;
}
}
@ -341,18 +381,39 @@ void MultiBandBlender::blend(Mat &dst, Mat &dst_mask)
void normalizeUsingWeightMap(const Mat& weight, Mat& src)
{
CV_Assert(weight.type() == CV_32F);
CV_Assert(src.type() == CV_16SC3);
for (int y = 0; y < src.rows; ++y)
{
Point3_<short> *row = src.ptr<Point3_<short> >(y);
const float *weight_row = weight.ptr<float>(y);
for (int x = 0; x < src.cols; ++x)
if(weight.type() == CV_32FC1)
{
for (int y = 0; y < src.rows; ++y)
{
row[x].x = static_cast<short>(row[x].x / (weight_row[x] + WEIGHT_EPS));
row[x].y = static_cast<short>(row[x].y / (weight_row[x] + WEIGHT_EPS));
row[x].z = static_cast<short>(row[x].z / (weight_row[x] + WEIGHT_EPS));
Point3_<short> *row = src.ptr<Point3_<short> >(y);
const float *weight_row = weight.ptr<float>(y);
for (int x = 0; x < src.cols; ++x)
{
row[x].x = static_cast<short>(row[x].x / (weight_row[x] + WEIGHT_EPS));
row[x].y = static_cast<short>(row[x].y / (weight_row[x] + WEIGHT_EPS));
row[x].z = static_cast<short>(row[x].z / (weight_row[x] + WEIGHT_EPS));
}
}
}
else
{
CV_Assert(weight.type() == CV_16SC1);
for (int y = 0; y < src.rows; ++y)
{
const short *weight_row = weight.ptr<short>(y);
Point3_<short> *row = src.ptr<Point3_<short> >(y);
for (int x = 0; x < src.cols; ++x)
{
int w = weight_row[x] + 1;
row[x].x = static_cast<short>((row[x].x << 8) / w);
row[x].y = static_cast<short>((row[x].y << 8) / w);
row[x].z = static_cast<short>((row[x].z << 8) / w);
}
}
}
}
@ -369,14 +430,51 @@ void createWeightMap(const Mat &mask, float sharpness, Mat &weight)
void createLaplacePyr(const Mat &img, int num_levels, vector<Mat> &pyr)
{
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 (int i = 0; i < num_levels; ++i)
if(img.depth() == CV_8U)
{
pyrUp(pyr[i + 1], tmp, pyr[i].size());
subtract(pyr[i], tmp, pyr[i]);
if(num_levels == 0)
{
img.convertTo(pyr[0], CV_16S);
return;
}
Mat downNext;
Mat current = img;
pyrDown(img, downNext);
for(int i = 1; i < num_levels; ++i)
{
Mat lvl_up;
Mat lvl_down;
pyrDown(downNext, lvl_down);
pyrUp(downNext, lvl_up, current.size());
subtract(current, lvl_up, pyr[i-1], noArray(), CV_16S);
current = downNext;
downNext = lvl_down;
}
{
Mat lvl_up;
pyrUp(downNext, lvl_up, current.size());
subtract(current, lvl_up, pyr[num_levels-1], noArray(), CV_16S);
downNext.convertTo(pyr[num_levels], CV_16S);
}
}
else
{
pyr[0] = img;
for (int i = 0; i < num_levels; ++i)
pyrDown(pyr[i], pyr[i + 1]);
Mat tmp;
for (int i = 0; i < num_levels; ++i)
{
pyrUp(pyr[i + 1], tmp, pyr[i].size());
subtract(pyr[i], tmp, pyr[i]);
}
}
}