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

Я использую 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 переводов для каждого из изображений?

ОБНОВЛЕНИЕ — профилирование в MSVS 2013 на Windows 7 x64:
введите описание изображения здесь

10

Решение

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, у вас есть матрица преобразования 3х3, называемая гомографией. Мы назовем это H_12, Аналогично для I_2 в 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):

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

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

11

Другие решения

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

По вопросам рекламы [email protected]