如何实时拼接摄像机的图像?

Ale*_*lex 11 c++ opencv image-stitching opencv-stitching opencv3.0

我用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);
}
Run Code Online (Sandbox Code Playgroud)

我只得到10 FPS(每秒帧数),但我需要25 FPS.我该如何加速这个例子呢?

当我使用stitcher.setWarper(new cv::PlaneWarperGpu());然后我得到一个非常放大的图像,这是我不需要的.

需要- 翻译.

例如,我准备不使用:

  • 透视转型
  • 扩展操作
  • 甚至可能是轮换

我该怎么做?或者我如何从每个图像的翻译cv::Stitcher stitcher参数x,y中获取?

更新 - 在Windows 7 x64上的MSVS 2013中进行概要分析: 在此输入图像描述

n00*_*dle 13

cv::Stitcher相当慢.如果您的相机绝对不会相互移动并且转换就像您说的那么简单,您应该能够通过链接单应性将图像叠加到空白画布上.

以下是一些数学 - 如果不清楚我可以使用LaTeX正确编写它,但是SO不支持漂亮的数学:)

你有一组4个摄像头,从左到右(C_1, C_2, C_3, C_4),给出一组4个图像(I_1, I_2, I_3, I_4).

要转换I_1I_2,您有一个3x3转换矩阵,称为单应性.我们称之为H_12.同样,对于I_2I_3我们H_23I_3I_4你就会有H_34.

您可以使用标准方法(重叠相机之间的点匹配)预先校准这些单应性.

您需要创建一个空白矩阵,以充当画布.您可以猜测它的大小(4*image_size就足够了),或者你可以在右上角(调用它P1_tr)并通过三个单应变换它,在全景的右上角给出一个新点,PP_tr(以下假设P1_tr已转换为矩阵):

PP_tr = H_34 * H_23 * H_12 * P1_tr'
Run Code Online (Sandbox Code Playgroud)

这是什么做的,正在P1_tr从并将其转换成第一相机2,然后C_2C_3从最后C_3C_4

你需要创建一个这些图像合成1和2,图像1,2和3,最后的图像1-4,我将把他们作为V_12,V_123V_1234分别.

使用以下方法将图像扭曲到画布上:

cv::warpAffine(I_2, V_12, H_12, V_12.size( ));
Run Code Online (Sandbox Code Playgroud)

然后对下一张图片做同样的事情:

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( ));
Run Code Online (Sandbox Code Playgroud)

现在你有四个画布,所有画布都是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( ));
Run Code Online (Sandbox Code Playgroud)

要将所有图像合并为一个全景图,您可以:

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): 
Run Code Online (Sandbox Code Playgroud)

你在这里做的是将每个画布的相关区域复制到输出图像上,这是一个快速操作.

你应该能够做到这一切在GPU上,取代cv::gpu::Mat的对cv::Matscv::gpu::warpAffine其非GPU对应.

  • 为了使这种方法更有效,你可以预先计算仿射变形映射,因为它们是常量,并使用`cv :: remap`(参见[doc](http://docs.opencv.org/modules/imgproc/doc) /geometric_transformations.html#remap))这比`cv :: warpAffine`快得多. (2认同)