Как сшить изображения с видеокамер в режиме реального времени?

Я использую 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 FPS. Как ускорить этот пример?

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

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

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

  • Перспективное преобразование
  • Операции масштабирования
  • и может быть даже вращением

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

UPDATE - профилирование в MSVS 2013 в Windows 7 x64: enter image description here

Ответ 1

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

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

У вас есть набор из 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 to I_3 имеем H_23, а для I_3 - I_4 у вас будет H_34.

Вы можете предварительно откалибровать эти гомологии заранее, используя стандартный метод (совпадение точек между перекрывающимися камерами).

Вам нужно будет создать пустую матрицу, чтобы действовать как холст. Вы можете догадаться, размер этого (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 и, наконец, изображений 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 на белый. Это маска для вашего первого изображения. Мы назовем его M_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): 

Что вы здесь делаете, копирование соответствующей области каждого холста на выходное изображение, pano - быстрая операция.

Вы можете сделать все это на графическом процессоре, заменив cv::gpu::Mat на cv::Mats и cv::gpu::warpAffine для своего не-графического экземпляра.

Ответ 2

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

Ответ 3

Вы когда-нибудь заставляли это работать? У меня аналогичная проблема с низкой частотой кадров при попытке создать панораму 360 градусов в реальном времени на малиновом ру с 4 камерами. Благодарю. Arman