在opencv自带的例子stitch_detail.cpp中,计算出来的CameraParams::R矩阵可以计算出图像的每个坐标的旋转量。但是每一幅图最后的位置(左上原点的坐标)怎么确定?怎么获得图像xyz轴的平移量?(z轴应该是指图像的缩放)
调整图像(透视变换)的代码片段如下:
is_compose_scale_set = false; // false
Mat img_warped, img_warped_s;
Mat dilated_mask,
seam_mask,
mask,
mask_warped;
Ptr<Blender> blender;
double compose_seam_aspect = 1;
double compose_work_aspect = 1;
Mat full_img;
Ptr<RotationWarper> warper;
Ptr<WarperCreator> warper_creator;
#if defined(HAVE_OPENCV_GPU)
if (try_gpu && gpu::getCudaEnabledDeviceCount() > 0){
warper_creator = new cv::PlaneWarperGpu();
}else
#endif
{
warper_creator = new cv::PlaneWarper();
}
for(int img_idx = 0; img_idx < precom_num; ++img_idx){
full_img = img_OriMat[img_idx];
if (!is_compose_scale_set) // 合成等级设定
{
if (compose_megapix > 0)
compose_scale = min(1.0, sqrt(compose_megapix * 1e6 / full_img.size().area()));
is_compose_scale_set = true;
// Compute relative scales
//compose_seam_aspect = compose_scale / seam_scale;
compose_work_aspect = compose_scale / work_scale;
// Update warped image scale
warped_image_scale *= static_cast<float>(compose_work_aspect);
warper = warper_creator->create(warped_image_scale);
// Update corners and sizes
for (int i = 0; i < precom_num; ++i){
// Update intrinsics
cameras[i].focal *= compose_work_aspect;
cameras[i].ppx *= compose_work_aspect;
cameras[i].ppy *= compose_work_aspect;
// Update corner and size
Size sz = full_img_sizes[i];
if (std::abs(compose_scale - 1) > 1e-1)
{
sz.width = cvRound(full_img_sizes[i].width * compose_scale);
sz.height = cvRound(full_img_sizes[i].height * compose_scale);
}
Mat K;
cameras[i].K().convertTo(K, CV_32F);
Rect roi = warper->warpRoi(sz, K, cameras[i].R); //
corners[i] = roi.tl();
sizes[i] = roi.size();
}
}
Mat img; // 增加
if (abs(compose_scale - 1) > 1e-1)
cv::resize(full_img, img, Size(), compose_scale, compose_scale);
else
img = full_img;
full_img.release();
Size img_size = img.size();
Mat K;
cameras[img_idx].K().convertTo(K, CV_32F);
warper->warp(img, K, cameras[img_idx].R, INTER_LINEAR, BORDER_REFLECT, img_warped);
// Warp the current image mask
mask.create(img_size, CV_8U);
mask.setTo(Scalar::all(255));
warper->warp(mask, K, cameras[img_idx].R, INTER_NEAREST, BORDER_CONSTANT, mask_warped);
img_warped.convertTo(img_warped_s, CV_16S);
img_warped.release();
img.release();
mask.release();
cv::dilate(mask_warped, dilated_mask, Mat()); // 膨胀
cv::resize(dilated_mask, seam_mask, mask_warped.size());
mask_warped = seam_mask & mask_warped;
if (blender.empty())
{
blender = Blender::createDefault(0, try_gpu);
Size dst_sz = resultRoi(corners, sizes).size(); // 获得最终画布的大小
float blend_width = sqrt(static_cast<float>(dst_sz.area())) * 5 / 100.f;
if (blend_width < 1.f)
blender = Blender::createDefault(Blender::NO, try_gpu);
blender->prepare(corners, sizes);
}
// Blend the current image
blender->feed(img_warped_s, mask_warped, corners[img_idx]);
char ppa[100] = {0};
sprintf_s(ppa,100,"img_warped_s_%d.jpg",img_idx);
imwrite(ppa, img_warped_s);
} // for end
Mat result, result_mask;
blender->blend(result, result_mask);
// 返回图像
return result;
查了代码发现,除了R,corners会影响拼接图像的原点坐标,sizes是其大小。在warpers_inl.hpp中又看到:
template <class P>
Rect RotationWarperBase<P>::warpRoi(Size src_size, const Mat &K, const Mat &R)
{
projector_.setCameraParams(K, R);
Point dst_tl, dst_br;
detectResultRoi(src_size, dst_tl, dst_br);
return Rect(dst_tl, Point(dst_br.x + 1, dst_br.y + 1));
}
setCameraParams的定义在warpers.cpp中:
void ProjectorBase::setCameraParams(const Mat &K, const Mat &R, const Mat &T)
{
CV_Assert(K.size() == Size(3, 3) && K.type() == CV_32F);
CV_Assert(R.size() == Size(3, 3) && R.type() == CV_32F);
CV_Assert((T.size() == Size(1, 3) || T.size() == Size(3, 1)) && T.type() == CV_32F);
Mat_<float> K_(K);
k[0] = K_(0,0); k[1] = K_(0,1); k[2] = K_(0,2);
k[3] = K_(1,0); k[4] = K_(1,1); k[5] = K_(1,2);
k[6] = K_(2,0); k[7] = K_(2,1); k[8] = K_(2,2);
Mat_<float> Rinv = R.t();
rinv[0] = Rinv(0,0); rinv[1] = Rinv(0,1); rinv[2] = Rinv(0,2);
rinv[3] = Rinv(1,0); rinv[4] = Rinv(1,1); rinv[5] = Rinv(1,2);
rinv[6] = Rinv(2,0); rinv[7] = Rinv(2,1); rinv[8] = Rinv(2,2);
Mat_<float> R_Kinv = R * K.inv();
r_kinv[0] = R_Kinv(0,0); r_kinv[1] = R_Kinv(0,1); r_kinv[2] = R_Kinv(0,2);
r_kinv[3] = R_Kinv(1,0); r_kinv[4] = R_Kinv(1,1); r_kinv[5] = R_Kinv(1,2);
r_kinv[6] = R_Kinv(2,0); r_kinv[7] = R_Kinv(2,1); r_kinv[8] = R_Kinv(2,2);
Mat_<float> K_Rinv = K * Rinv;
k_rinv[0] = K_Rinv(0,0); k_rinv[1] = K_Rinv(0,1); k_rinv[2] = K_Rinv(0,2);
k_rinv[3] = K_Rinv(1,0); k_rinv[4] = K_Rinv(1,1); k_rinv[5] = K_Rinv(1,2);
k_rinv[6] = K_Rinv(2,0); k_rinv[7] = K_Rinv(2,1); k_rinv[8] = K_Rinv(2,2);
Mat_<float> T_(T.reshape(0, 3));
t[0] = T_(0,0); t[1] = T_(1,0); t[2] = T_(2,0);
}
其中的参数的定义在warpers.hpp中:
struct CV_EXPORTS ProjectorBase
{
void setCameraParams(const Mat &K = Mat::eye(3, 3, CV_32F),
const Mat &R = Mat::eye(3, 3, CV_32F),
const Mat &T = Mat::zeros(3, 1, CV_32F));
float scale;
float k[9];
float rinv[9];
float r_kinv[9];
float k_rinv[9];
float t[3];
};
detectResultRoi的定义在warpers_inl.hpp中:
template <class P>
void RotationWarperBase<P>::detectResultRoi(Size src_size, Point &dst_tl, Point &dst_br)
{
float tl_uf = std::numeric_limits<float>::max();
float tl_vf = std::numeric_limits<float>::max();
float br_uf = -std::numeric_limits<float>::max();
float br_vf = -std::numeric_limits<float>::max();
float u, v;
for (int y = 0; y < src_size.height; ++y)
{
for (int x = 0; x < src_size.width; ++x)
{
projector_.mapForward(static_cast<float>(x), static_cast<float>(y), u, v);
tl_uf = std::min(tl_uf, u); tl_vf = std::min(tl_vf, v);
br_uf = std::max(br_uf, u); br_vf = std::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);
}
请问大家有知道这之中是用什么算法算的吗?能不能给点资料或者提示?
目前已知的是:
corners的计算和R矩阵有关,但是计算过程不明了。
corners的xy值应该可以对应着图像的原点,但是打印出来是负数,不理解。
sizes应该有缩放的信息,可能对应着z的平移量。
先谢过啦!