首页 文章

具有重叠固定摄像机的OpenCV Stitcher类

提问于
浏览
15

我正在尝试使用OpenCV拼接器类来拼接立体设置中的多个帧,其中两个摄像机都不移动 . 在跨多个帧运行时,我的拼接结果很差 . 我尝试了几种不同的方法,我将在这里解释一下 .

Using 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();
}

这给每个帧提供了非常好的结果,但由于参数估计放在视频中的每个帧,您可以看到参数略有不同的拼接的小差异 .

Using 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
}

可悲的是,似乎有一个错误(documented here)导致两个视图以非常奇怪的方式分开,如下图所示:

第1帧:
Frame 1

第2帧:
Frame 2

...

第8帧:
Frame 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;

结果:
Frame 3

Frame 4

有谁知道如何解决这个问题?基本上我需要计算一次转换,然后在剩下的帧上使用它(我们正在谈论30分钟的视频) .

我理想地寻找关于修补拼接课程的一些建议,但我愿意尝试手动编码不同的解决方案 . 较早的尝试涉及找到SURF点,关联它们并找到单应性,与拼接类相比给出了相当差的结果,所以我宁愿在可能的情况下使用它 .

1 回答

  • 4

    所以最后,我用stitcher.cpp代码破解并得到了接近解决方案的东西(但不完美,因为拼接缝仍然移动了很多,所以你的里程可能会有所不同) .

    Changes to stitcher.hpp

    在第136行添加了新功能 setCameras()

    void setCameras( std::vector<detail::CameraParams> c ) {
    
         this->cameras_ = c;
     }`
    

    添加了一个新的私有成员变量来跟踪这是否是我们的第一次估算:

    bool _not_first;
    

    Changes to 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_);
    // ...
    

    Code calling stitcher object:

    基本上,我们创建一个拼接对象,然后在第一帧上进行变换(将拼接矩阵存储在拼接器类之外) . 然后,缝合器将沿着线的某处打破内在矩阵,导致下一帧陷入混乱 . 因此,在我们处理它之前,我们只需使用从类中提取的相机重置相机 .

    请注意,如果拼接器无法使用默认设置生成估计,我必须进行一些错误检查 - 您可能需要在得到结果之前使用 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代码,这将使更新到新版本变得更加痛苦 . 不幸的是我时间不够,所以我可以得到一个令人讨厌的黑客!

相关问题