【问题标题】:OpenCV - Zero padding of MatOpenCV - 垫的零填充
【发布时间】:2015-05-26 22:28:58
【问题描述】:

假设我有一个尺寸为 98x158x32(浮点型)的 Mat 变量 small_image。现在我想对这个图像进行零填充(即在图像中添加一个零边框)。我想在图像上方和下方添加 7 个零,在图像左右添加 12 个零。第一个想法是使用 cv copyMakeBorder(参见copyMakeBorder doc),这似乎非常适合:

    int old_size[3];
    old_size[0] = 98;
    old_size[1] = 158;
    old_size[2] = 32;

    int pad_size[3];
    pad_size[0] = old_size[0] + 2 * 7;
    pad_size[1] = old_size[1] + 2 * 12;
    pad_size[2] = old_size[2];

    cv::Mat image_padded(3, pad_size, CV_32FC1, cv::Scalar(0)); //Initialize the larger Mat to 0

    copyMakeBorder(small_image,image_padded,7,7,12,12,BORDER_CONSTANT,Scalar(0));

但是,此代码给出了 memcopy 错误。有人看到这里的问题吗?

post 中描述的替代方法也不起作用:

cv::Rect roi( cv::Point( 12, 7 ), small_image.size() );
small_image.copyTo( image_padded( roi ) );

它声称“断言失败 (m.dims

任何帮助实现零填充将不胜感激!

【问题讨论】:

  • copyMakeBorder 很可能不起作用,因为它是为表示图像的 2D 矩阵设计的(尽管可以是多通道的)。你这里有一个 3D 垫子。

标签: c++ opencv padding


【解决方案1】:

您描述的这两种方法都不起作用,因为它们旨在用于 2D 矩阵。您有一个 3D Mat,它要求您指定所有三个维度的范围。您可以使用() 运算符,该运算符可用于与copyTo 组合的范围数组,如下例所示。

#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>

int main()
{
  int old_size[3];
  old_size[0] = 5;
  old_size[1] = 5;
  old_size[2] = 2;

  int pad_size[3];
  pad_size[0] = old_size[0] + 2 * 1;
  pad_size[1] = old_size[1] + 2 * 2;
  pad_size[2] = old_size[2];

  cv::Mat small_image(3, old_size, CV_32FC1, cv::Scalar(1));
  cv::Mat image_padded(3, pad_size, CV_32FC1, cv::Scalar(0));

  cv::Range ranges[3];
  ranges[0] = cv::Range(1, old_size[0]+1);
  ranges[1] = cv::Range(2, old_size[1]+2);
  ranges[2] = cv::Range(0, old_size[2]);

  small_image.copyTo(image_padded(ranges));

  for (int i = 0; i < pad_size[0]; i++)
    for (int j = 0; j < pad_size[1]; j++)
      for (int k = 0; k < pad_size[2]; k++)
        std::cout << image_padded.at<float>(i, j, k) << ", ";
}

这将给出:

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0

【讨论】:

  • 正是我所需要的并且完美地工作。谢谢!
  • 很好的解决方案!然而,我在Mat image_padded 的正确初始化方面遇到了困难。如果您通过 Mat A; A=imread(..) 加载图像,则需要(至少在 Ubuntu 下)参数:cv::Mat image_padded(2, pad_size, CV_8UC3_U, cv::Scalar(0, 0, 0)) 希望这可以节省某人的时间。
【解决方案2】:

我们还可以使用rowRangecolRange 方法的组合将我们感兴趣的区域设置为 3 维填充图像的子部分(全为零)。这可以很容易地通过将未填充的图像复制到其上。

cv::Mat image_padded(3, pad_size, CV_32FC1, cv::Scalar(0));
int xPad = 12;
int yPad = 7;
Mat area = image_padded.rowRange(xPad, xPad + 98).colRange(yPad, yPad + 158);
small_image.copyTo( area );

【讨论】:

  • 好奇这个 3D 图像的用途
  • 感谢您的建议。这确实似乎是最直观的方法。它不是真正的图像,而是包含数据的 3D 矩阵。对于这篇文章,我只是将变量重命名为更一般的情况。通常,我会在 Matlab 中执行此类操作,但我正在从事的项目将我限制在 C++
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-07
  • 2019-06-15
  • 1970-01-01
  • 2013-06-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多