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