2015-03-30 4 views
8

Я использую 4 стационарные камеры. Камеры не перемещаются относительно друг друга. И я хочу сшить видеоизображения из них в одно видеоизображение в режиме реального времени.Как я могу сшить изображения с видеокамер в режиме реального времени?

Я использую для этого OpenCV 2.4.10 и cv:stitcher класс, как это:

// use 4 video-cameras 
cv::VideoCapture cap0(0), cap1(1), cap2(2), cap3(3); 

bool try_use_gpu = true; // use GPU 
cv::Stitcher stitcher = cv::Stitcher::createDefault(try_use_gpu); 
stitcher.setWarper(new cv::CylindricalWarperGpu()); 
stitcher.setWaveCorrection(false); 
stitcher.setSeamEstimationResol(0.001); 
stitcher.setPanoConfidenceThresh(0.1); 

//stitcher.setSeamFinder(new cv::detail::GraphCutSeamFinder(cv::detail::GraphCutSeamFinderBase::COST_COLOR_GRAD)); 
stitcher.setSeamFinder(new cv::detail::NoSeamFinder()); 
stitcher.setBlender(cv::detail::Blender::createDefault(cv::detail::Blender::NO, true)); 
//stitcher.setExposureCompensator(cv::detail::ExposureCompensator::createDefault(cv::detail::ExposureCompensator::NO)); 
stitcher.setExposureCompensator(new cv::detail::NoExposureCompensator()); 


std::vector<cv::Mat> images(4); 
cap0 >> images[0]; 
cap1 >> images[1]; 
cap2 >> images[2]; 
cap3 >> images[3]; 

// call once! 
cv::Stitcher::Status status = stitcher.estimateTransform(images); 


while(true) { 

    // **lack of speed, even if I use old frames** 
    // std::vector<cv::Mat> images(4); 
    //cap0 >> images[0]; 
    //cap1 >> images[1]; 
    //cap2 >> images[2]; 
    //cap3 >> images[3]; 

    cv::Stitcher::Status status = stitcher.composePanorama(images, pano_result); 
} 

я получаю только 10 FPS (кадров в секунду), но мне нужно 25 кадров в секунду. Как ускорить этот пример?

Когда я использую stitcher.setWarper(new cv::PlaneWarperGpu());, тогда я получаю очень увеличенное изображение, мне это не нужно.

Мне нужен только - Перевод.

К примеру, я готов не использовать:

  • преобразования Perspective
  • Масштабные операции
  • и может быть даже Ротации

Как я могу это сделать? Или как я могу получить от cv::Stitcher stitcher параметров x,y переводов для каждого изображения?

ОБНОВЛЕНИЕ - профилирование в МСВС 2013 на Windows 7 x64: enter image description here

+0

Какую машину вы используете? У вас включен tbb? Кроме того, можете ли вы представить несколько изображений в качестве примера для сшивания вместе? – Antonio

+0

@ Антонио 8 ГБ оперативной памяти + процессор (Intel Core i5 760 - 4 ядра) + графический процессор (nVidia GeForce GTX 970 - 1664). TBB отключен. OpenCV 2.4.10 скомпилирован с CUDA 6.5 и отключен OpenMP/TBB. – Alex

+1

TBB может помочь в многопоточности процесса ... Для какой системы вы создали и с помощью каких средств сборки? Кроме того, одна быстрая задача - поместить объявление/определение массива изображений из цикла while. (Вы распределяете и освобождаете при каждом цикле). Я предлагаю вам установить таймер вокруг вашей функции строчки, чтобы проверить, что этот вызов функции является фактическим узким местом. – Antonio

ответ

10

cv::Stitcher довольно медленно. Если ваши камеры определенно не перемещаются относительно друг друга, и преобразование так же просто, как вы говорите, вы должны иметь возможность накладывать изображения на пустой холст просто путем цепочки homographies.

Следующие несколько математический - если это не ясно, что я могу написать это правильно с помощью LaTeX, но ТАК не поддерживаю довольно математику :)

У вас есть набор из 4 камер, слева справа, (C_1, C_2, C_3, C_4), давая набор из 4 изображений (I_1, I_2, I_3, I_4).

Чтобы преобразовать из I_1 в I_2, у вас есть матрица преобразования 3x3, называемая гомографией. Мы назовем это H_12. Аналогично для I_2 до I_3 у нас есть H_23 и для I_3 до I_4 у вас будет H_34.

Предварительно откалибруйте эти гомологии заранее, используя стандартный метод (point matching between the overlapping cameras).

Вам нужно будет создать пустую матрицу, чтобы действовать как холст. Вы можете догадаться, размер этого (4 * image_size будет достаточным), или вы можете взять верхний правый угол (назовите это P1_tr) и преобразовать его по трем гомографиям, давая новую точку в правом верхнем углу панорамы, PP_tr (Здесь предполагается, что P1_tr был преобразован в матрицу):

PP_tr = H_34 * H_23 * H_12 * P1_tr' 

что это делает, принимает P1_tr и превращая его первым в камеру 2, а затем из C_2 в C_3 и, наконец, от C_3 до C_4

Вам необходимо создать один из них для объединения изображений 1 и 2, изображений 1,2 и 3 a наконец, изображения 1-4, я назову их V_12, V_123 и V_1234 соответственно.

Используйте следующие деформировать изображение на холсте:

cv::warpAffine(I_2, V_12, H_12, V_12.size()); 

Затем сделать то же самое со следующими изображениями:

cv::warpAffine(I_3, V_123, H_23*H_12, V_123.size()); 
cv::warpAffine(I_4, V_1234, H_34*H_23*H_12, V_1234.size()); 

Теперь у вас есть четыре полотна, все из которых являются ширина из 4 комбинированных изображений, и с одним из изображений, преобразованных в соответствующее место на каждом.

Осталось только объединить преобразованные изображения друг на друга. Это легко достигается с помощью регионов, представляющих интерес.

Создание масок ROI может быть сделано заблаговременно, перед началом кадра.

Начните с пустого (нулевого) изображения того же размера, что и ваши холсты. Установите крайний левый прямоугольник размером I_1 на белый. Это маска для вашего первого изображения. Назовем это .

Далее, чтобы получить маску для второго преобразованного изображения, мы делаем

cv::warpAffine(M_1, M_2, H_12, M_1.size()); 
cv::warpAffine(M_2, M_3, H_23*H_12, M_1.size()); 
cv::warpAffine(M_3, M_4, H_34*H_23*H_12, M_1.size()); 

Привести все изображения в одну панораму, вы делаете:

cv::Mat pano = zeros(M_1.size(), CV_8UC3); 
I_1.copyTo(pano, M_1); 
V_12.copyTo(pano, M_2): 
V_123.copyTo(pano, M_3): 
V_1234.copyTo(pano, M_4): 

Что вы делаете здесь copying the relevant area of each canvas на выходное изображение, панора - быстрая операция.

Вы должны быть в состоянии сделать все это на GPU, подставляя cv::gpu::Mat «S для cv::Mats и cv::gpu::warpAffine для его не-GPU собрата.

+2

Чтобы сделать этот подход еще более эффективным, вы можете предварительно вычислить карты аффинных деформаций, поскольку они являются постоянными и использовать 'cv :: remap' (см. [Doc] (http://docs.opencv.org/modules/imgproc/ doc/geometric_transformations.html # remap)), который намного быстрее, чем 'cv :: warpAffine'. – AldurDisciple

+0

Ницца, да, это очень хорошая идея. Я действительно делал это в прошлом, и он работает очень хорошо, просто не пришло в голову, когда я писал выше. – n00dle

+0

@ n00dle Большое спасибо! Но вы сказали, что я должен найти: ** 3x3 ** матрицу преобразования, называемую ** гомографией **, и использовать: 'cv :: warpAffine();', но поскольку я знаю 'warpAffine();' использует * * матрица аффинного преобразования (2x3) **. Означает ли это, что я должен использовать 'warpAffine();' после 'оценкиRigidTransform();'? Или я должен использовать 'warpPerspective();' after' findHomography(); '? И как я могу получить 'map1, map2' для' ramap(); 'из гомографии, которую я нашел с помощью' findHomography(); '? – Alex

0

Примечание: Я оставляю этот ответ только документаций о том, что был судим, как метод, который я предложил, кажется, не работает, в то время как очевидно, что GPU уже используется при использовании cv :: Mat.


Попробуйте использовать gpu::GpuMat:

std::vector<cv::Mat> images(4); 
std::vector<gpu::GpuMat> gpuImages(4); 
gpu::GpuMat pano_result_gpu; 
cv::Mat pano_result; 
bool firstTime = true; 

[...] 

cap0 >> images[0]; 
cap1 >> images[1]; 
cap2 >> images[2]; 
cap3 >> images[3]; 
for (int i = 0; i < 4; i++) 
    gpuImages[i].upload(images[i]); 
if (firstTime) { 
    cv::Stitcher::Status status = stitcher.estimateTransform(gpuImages); 
    firstTime = false; 
    } 
cv::Stitcher::Status status = stitcher.composePanorama(gpuImages, pano_result_gpu); 
pano_result_gpu.download(pano_result); 
+0

Когда я использую 'cv :: gpu :: GpuMat' вместо' cv :: Mat' в 'оценкеTransform();' или в 'composePanorama();' затем я получаю сообщение об ошибке в Windows 7x64 + OpenCV 2.4.9: * Ошибка OpenCV: утверждение не выполнено (func! = 0) в cv :: resize, файл C: \ opencv_2.4.9 \ o pencv \ sources \ modules \ imgproc \ src \ imgwarp.cpp, line 1980 * – Alex

+0

@Alex Это, по крайней мере, доказывает, что графический процессор не использовался раньше :) Пожалуйста, обновите свой вопрос и опубликуйте код, который вы найдете в 'C: \ opencv_2.4.9 \ o pencv \ sources \ modules \ imgproc \ src \ imgwarp.cpp' around line 1980 – Antonio

+0

Но результат профилирования MSVS 2013, который я добавил к моему вопросу, показывает мне, что GPU использовал много раз :) Код от ошибки здесь: http://pastebin.com/VVN1gMK2 – Alex