使用OpenCV拼接重叠静止摄像机的Stitcher类

16

我正在尝试使用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()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
}

不幸的是,似乎存在一个错误(在这里记录下来),导致两个视图以一种非常奇怪的方式分离,如下面的图片所示:

第一帧: Frame 1

第二帧: Frame 2

...

第八帧: Frame 8

显然这没有用,但我认为这可能只是因为错误,该错误基本上会使内部参数矩阵在每次调用composePanorama()时乘以一个常数。所以我对错误进行了微小的修补,阻止了这种情况发生,但是拼接结果很差。以下是修补程序(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; 

结果: Frame 3 Frame 4

有没有人知道我怎么能解决这个问题?基本上,我需要计算出变换一次,然后在其余帧(大约30分钟的视频)中使用它。

我最好想要一些关于修补拼缝器类的建议,但我也愿意尝试手动编写不同的解决方案。之前的一个尝试涉及查找SURF点、相关性和寻找单应性,与拼缝器类相比效果相当差,因此我宁愿在可能的情况下使用该类。

1个回答

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对象的代码:

基本上,我们创建一个stitcher对象,然后获得第一帧的变换(将摄像机矩阵存储在stitcher类之外)。然后,stitcher将在某个地方中断内部矩阵,导致下一帧出错。因此,在处理它之前,我们只需使用从类中提取的那些摄像机重置它们。

请注意,如果stitcher无法使用默认设置进行估计,我必须进行一些错误检查 - 您可能需要通过setPanoConfidenceThresh(...)迭代减少置信度阈值,直到您获得结果。

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代码的大规模修改,导致升级到新版本会很麻烦。不幸的是,我时间紧迫,只能实现一个恶劣的hack!

你知道在新版本的openCV中这个问题是否仍然存在吗?另外,你有分享你的结果的存储库吗? - theAlse
很抱歉,我不知道 - 自从发布这篇文章以来,我就没有需要使用它。另外,很遗憾我不能提供代码库 - 我正在处理一个非公开资助的项目,所以代码是内部保留的。 - n00dle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接