c++ - 如何实时拼接来自摄像机的图像?

标签 c++ opencv image-stitching opencv3.0 opencv-stitching

我使用 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 中获取每个图像的翻译?

更新 - 在 Windows 7 x64 上的 MSVS 2013 中分析: enter image description here

最佳答案

cv::Stitcher 相当慢。如果你的相机绝对不会相对移动并且转换就像你说的那么简单,你应该能够简单地通过链接将图像叠加到空白 Canvas 上 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_2I_3 我们有 H_23 而对于 I_3I_4 你'将有 H_34

您可以使用标准方法 (point matching between the overlapping cameras) 预先校准这些单应性。

您需要创建一个空白矩阵作为 Canvas 。你可以猜测它的大小(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_3C_4

您需要创建其中一个来组合图像 1 和 2、图像 1,2 和 3,最后是图像 1-4,我将它们称为 V_12V_123V_1234

使用以下方法将图像变形到 Canvas 上:

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( ));

现在你有四个 Canvas ,所有这些都是 4 个组合图像的宽度,并且其中一个图像转换到每个图像的相关位置。

剩下的就是将转换后的图像彼此合并。这可以使用感兴趣区域轻松实现。

可以在帧捕获开始之前提前创建 ROI 掩码。

从一张与 Canvas 大小相同的空白(零)图像开始。将大小为 I_1 的最左边的矩形设置为白色。这是您的第一张图片的 mask 。我们称它为 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): 

你在这里做的是copying the relevant area of each canvas到输出图像上,全景 - 快速操作。

您应该能够在 GPU 上完成所有这些,用 cv::gpu::Mat 代替 cv::Matscv: :gpu::warpAffine 用于其非 GPU 对应项。

关于c++ - 如何实时拼接来自摄像机的图像?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29348674/

相关文章:

c++ - 为什么 "virtuality"方法在 C++ 中隐式传播?

python - 在OpenCV Python中缩减ROI

opencv - JavaCV拼接

opencv - 无法在 opencv c++ 中使用 Stitcher 类拼接许多图像

c++ - 如何快速搜索项目中所有包含的头文件以查找特定符号?

c++ - 如何将 ""替换为 "_"?

opencv - 图像处理中的工业级前景/背景分离

c++ - 在 C++ 和 C 中使用 opencv

c++ - 如何获取快捷目标