我正在尝试使用OpenCV拼接器类来拼接立体设置中的多个帧,其中两个摄像机都不移动。在跨多个帧运行时,我的拼接结果很差。我尝试了几种不同的方法,我将在这里解释一下。
使用stitcher.stitch( )
给定一对立体视图,我为一些帧运行了以下代码(VideoFile
是OpenCV VideoCapture
对象的自定义包装器):
VideoFile f1( ... );
VideoFile f2( ... );
cv::Mat output_frame;
cv::Stitcher stitcher = cv::Stitcher::createDefault(true);
for( int i = 0; i < num_frames; i++ ) {
currentFrames.push_back(f1.frame( ));
currentFrames.push_back(f2.frame( ));
stitcher.stitch( currentFrames, output_mat );
// Write output_mat, put it in a named window, etc...
f1.next_frame();
f2.next_frame();
currentFrames.clear();
}
这给每一帧提供了非常好的结果,但由于参数估计放在视频中的每一帧,你可以看到参数略有不同的拼接的小差异。
使用estimateTransform( )
&amp; composePanorama( )
为了解决上述方法的问题,我决定尝试仅在第一帧上估计参数,然后使用composePanorama( )
来拼接所有后续帧。
for( int i = 0; i < num_frames; i++ ) {
currentFrames.push_back(f1.frame( ));
currentFrames.push_back(f2.frame( ));
if( ! have_transform ) {
status = stitcher.estimateTransform( currentFrames );
}
status = stitcher.composePanorama(currentFrames, output_frame );
// ... as above
}
可悲的是,似乎有一个错误(documented here)导致两个视图以非常奇怪的方式分开,如下图所示:
第1帧:
第2帧:
...
第8帧:
显然这没用,但我认为可能只是因为这个bug,它每次调用composePanorama()
时基本上都会将内部参数矩阵乘以常量。所以我对这个bug做了一个小补丁,阻止了这种情况的发生,但是缝合效果很差。下面的补丁(modules/stitching/src/stitcher.cpp
),之后的结果:
243 for (size_t i = 0; i < imgs_.size(); ++i)
244 {
245 // Update intrinsics
246 // change following to *=1 to prevent scaling error, but messes up stitching.
247 cameras_[i].focal *= compose_work_aspect;
248 cameras_[i].ppx *= compose_work_aspect;
249 cameras_[i].ppy *= compose_work_aspect;
结果:
有没有人知道如何解决这个问题?基本上我需要计算转换一次,然后在剩下的帧上使用它(我们正在谈论30分钟的视频)。
我理想地寻找关于修补拼接课程的一些建议,但我愿意尝试手动编码不同的解决方案。早期的尝试涉及找到SURF点,关联它们并找到单应性,与拼接类相比给出了相当差的结果,所以如果可能的话我宁愿使用它。
答案 0 :(得分:5)
所以最后,我用stitcher.cpp代码破解并得到了一些接近解决方案的东西(但不完美,因为拼接缝仍然移动了很多,所以你的里程可能会有所不同)。
对stitcher.hpp
在第136行添加了新功能setCameras()
:
void setCameras( std::vector<detail::CameraParams> c ) {
this->cameras_ = c;
}`
添加了一个新的私有成员变量,以跟踪这是否是我们的第一次估算:
bool _not_first;
对stitcher.cpp
在estimateTransform()
(第100行):
this->not_first = 0;
images.getMatVector(imgs_);
// ...
在composePanorama()
(第~227行):
// ...
compose_work_aspect = compose_scale / work_scale_;
// Update warped image scale
if( !this->not_first ) {
warped_image_scale_ *= static_cast<float>(compose_work_aspect);
this->not_first = 1;
}
w = warper_->create((float)warped_image_scale_);
// ...
代码调用stitcher
对象:
基本上,我们创建一个拼接对象,然后在第一帧上进行变换(将摄像机矩阵存储在拼接器类中)。然后,缝合器将沿着线的某处打破内在矩阵,导致下一帧陷入混乱。因此,在我们处理它之前,我们只需使用从类中提取的相机重置相机。
请注意,如果拼接器无法使用默认设置生成估计,我必须进行一些错误检查 - 您可能需要在获得结果之前使用setPanoConfidenceThresh(...)
迭代地降低置信度阈值。< / p>
cv::Stitcher stitcher = cv::Stitcher::createDefault(true);
std::vector<cv::detail::CameraParams> cams;
bool have_transform = false;
for( int i = 0; i < num_frames; i++ ) {
currentFrames.push_back(f1.frame( ));
currentFrames.push_back(f2.frame( ));
if( ! have_transform ) {
status = stitcher.estimateTransform( currentFrames );
have_transform = true;
cams = stitcher.cameras();
// some code to check the status of the stitch and handle errors...
}
stitcher.setCameras( cams );
status = stitcher.composePanorama(currentFrames, output_frame );
// ... Doing stuff with the panorama
}
请注意,这是OpenCV代码的黑客攻击,这将使更新版本变得更加痛苦。不幸的是,我的时间不够,所以我可以得到一个讨厌的黑客!