【问题标题】:How to replace values in a mat using another mat image如何使用另一个垫子图像替换垫子中的值
【发布时间】:2019-05-05 21:24:28
【问题描述】:

我有一个 480x480 的垫子 A 和 478x478 的垫子 B。 我想在 C++ 中使用 Mat B 填充 Mat A(不包括 A 的边界)。 在 python 中,我使用来自 numpy 的以下符号

A[1:-1,1:-1] = B[:,:,0]

为了在 c++ 中实现同样的效果,我尝试使用以下代码使用通道和范围,但没有成功。

std::vector<Mat> B_channel(3);
split(B, B_channel);
A(cv::Range(1,479), cv::Range(1, 479)) = B_channel[0];

如何在 C++ 中实现相同的功能。

【问题讨论】:

  • “没用”是什么意思?
  • B_channel 中的值不会复制到 A。当我尝试输出 AI 时,看到所有零,这是我用 cv::Mat A = cv::Mat::zeros(cv ::尺寸(480, 480), CV_8UC1)
  • B_channel[0].copyTo(A(Rect(1,1,A.cols-2, A.rows-2)));

标签: c++ numpy opencv


【解决方案1】:

要在 C++ 中实现与 Python 代码相同的效果,您可以执行以下示例:

  cv::Mat A(100, 100, CV_8U, cv::Scalar::all(0));
  cv::Mat B(98, 98, CV_8U, cv::Scalar::all(1));
  std::cout << "sumAll A: " << cv::sum(A) << std::endl;

  B.copyTo(A.colRange(1, A.cols - 1).rowRange(1, A.rows - 1)); // This is the copy part
  std::cout << "sumAll A: " << cv::sum(A) << std::endl;

我打印所有的总和以验证它是否复制了它。第一种情况是 0,第二种情况是 9604。这两种情况都是正确的。需要记住的重要一点:如果大小不匹配,copyTo 将重新初始化矩阵并可能给出意想不到的结果。

为了进一步分解代码,如下:

A.colRange(1, A.cols - 1).rowRange(1, A.rows - 1)

相当于:

 A[1:-1,1:-1]

在 python 中,copyTo 会将值(而不是标题)从一个 cv::Mat 复制到另一个。如果您使用复制运算符 (=),它只会复制标头,在这种情况下,它只是将其写入您使用 A(cv::Range(1,479), cv::Range(1, 479)) 创建的临时标头上,这更多是为了访问 A 中的数据。在指令之后此标头被破坏并且您的数据完全相同。

要获取要复制到的标题部分,可以通过多种方式进行。我写的一个是列和行的范围。另一个是您编写的(采用两个范围),第三个是使用cv::Rect。所以最后这一切都是等价的:

B.copyTo(A.colRange(1, A.cols - 1).rowRange(1, A.rows - 1));
B.copyTo(A(cv::Range(1, A.cols - 1), cv::Range(1, A.rows - 1)));
B.copyTo(A(cv::Rect(1,1,A.cols -2, A.rows -2)));

在最后一种情况下 cv::Rect 是 (x,y, width, height) 因此其他情况是 -2 而不是 -1。

在使用 copyTo 获取图像 B 的子集之前,您可以对 B 执行相同操作。

【讨论】:

  • 感谢您的详细解答。那么这部分 B[:,:,0]
  • @Saikiran 遗憾的是,我不知道比使用 split 更好的方法。但是,如果您希望对所有通道应用相同的边框,您可以使用与之前相同的方法,使用 3 通道矩阵,而不是使用 1 通道矩阵。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-05
  • 2013-04-26
  • 1970-01-01
  • 1970-01-01
  • 2021-11-09
  • 2020-11-23
相关资源
最近更新 更多