Я пытаюсь использовать класс брошюровщика 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:
Кадр 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
Добавлена новая функция 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
объект:
Таким образом, в основном, мы создаем объект брошюровщика, затем получаем преобразование в первом кадре (сохраняя матрицы камеры вне класс брошюровщика). Брошюровщик тогда сломает Внутреннюю Матрицу где-нибудь вдоль линии, вызывая перепутывание следующего кадра. Поэтому перед обработкой мы просто сбрасываем камеры, используя те, что были извлечены из класса.
Имейте в виду, мне нужно было проверить ошибки на случай, если брошюровщик не может произвести оценку с настройками по умолчанию — вам может понадобиться итеративно уменьшить порог достоверности, используя 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, из-за которого обновление до новой версии станет проблемой. К сожалению, у меня не хватило времени, так что мерзкий хак — это все, что я мог обойти!
Других решений пока нет …