Класс OpenCV Stitcher с перекрывающимися стационарными камерами - программирование
Подтвердить что ты не робот

Класс OpenCV Stitcher с перекрывающимися стационарными камерами

Я пытаюсь использовать класс Stitcher 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
}

К сожалению, кажется, что есть ошибка (описанная здесь), заставляя два вида раздвигаться очень странным образом, как в изображения ниже:

Кадр 1: Frame 1

Кадр 2: Frame 2

...

Кадр 8: 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 3Frame 4

Кто-нибудь знает, как я могу решить эту проблему? В основном мне нужно разобраться в преобразовании один раз, а затем использовать его на оставшихся кадрах (мы говорим 30 минут видео).

В идеале я ищу советы по исправлению класса сшивателя, но я бы хотел попробовать ручное кодирование другого решения. Ранняя попытка, связанная с поиском точек SURF, корреляцией их и поиском гомографии, дала довольно плохие результаты по сравнению с классом стикеров, поэтому я предпочел бы использовать ее, если это возможно.

4b9b3361

Ответ 1

Итак, в конце концов, я взломал код stitcher.cpp и получил что-то близкое к решению (но не идеально, поскольку шовный шов все еще перемещается примерно так, чтобы ваш пробег мог меняться).

Изменения в stitcher.hpp

Добавлена ​​новая функция setCameras() в строке 136:

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). Затем строчка разбивает внутреннюю матрицу где-то вдоль линии, заставляя следующий фрейм испортиться. Поэтому, прежде чем мы его обработаем, мы просто reset камеры, используя те, которые мы извлекли из класса.

Будьте осторожны, я должен был провести некоторую проверку ошибок в случае, если строчка не может произвести оценку с настройками по умолчанию - вам может потребоваться итеративно уменьшить доверительный порог с помощью 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, который собирается сделать обновление для более новой версии болью. К сожалению, у меня не хватило времени, поэтому неприятный взлом был всем, чем я мог обходиться!