我正在尝试使用OpenCV缝合器类从立体声设置中缝合多个帧,而这两个摄像机都不移动。跨多个帧运行时,拼接效果不佳。我尝试了几种不同的方法,在这里我将尝试解释。

使用stitcher.stitch( )

给定一对立体 View ,我为某些帧运行了以下代码(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
}

不幸的是,似乎有一个bug(documented here)导致两个 View 以非常奇怪的方式分开,如下图所示:

框架1:

框架2:

...

框架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;

结果:

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

理想情况下,我正在寻找有关修补拼接器类的建议,但我愿意尝试对其他解决方案进行手动编码。较早的尝试包括找到SURF点,将它们相关联并找到单应性,与缝合器类相比,结果差很多,因此,我尽可能使用它。

最佳答案

因此,最后,我修改了Stitcher.cpp代码并获得了一些接近解决方案的方法(但不是很完美,因为缝线仍在移动很多,因此您的行程可能会有所不同)。
更改为stitcher.hpp
在第136行添加了一个新函数setCameras():

void setCameras( std::vector<detail::CameraParams> c ) {

     this->cameras_ = c;
 }`
添加了一个新的私有(private)成员变量来跟踪这是否是我们的第一个估计:
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(...)反复降低置信度阈值,然后才能得出结果。
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代码的破解,这将使更新到较新版本变得很痛苦。不幸的是,我时间不足,所以我可以绕开所有讨厌的东西!

10-08 12:36