OpenCV - Mat 的零填充
OpenCV - Zero padding of Mat
假设我有一个尺寸为 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));
但是,这段代码给出了内存复制错误。有人看到这里的问题吗?
此 post 中描述的替代方案也不起作用:
cv::Rect roi( cv::Point( 12, 7 ), small_image.size() );
small_image.copyTo( image_padded( roi ) );
它声称“断言失败(m.dims <= 2)”,而两个 Mat 变量都是 3D 矩阵。
任何帮助实现零填充的帮助将不胜感激!
您描述的两种方法均无效,因为它们旨在用于二维矩阵。您有一个 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
我们还可以结合使用 rowRange
和 colRange
方法将我们感兴趣的区域设置为 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 );
假设我有一个尺寸为 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));
但是,这段代码给出了内存复制错误。有人看到这里的问题吗?
此 post 中描述的替代方案也不起作用:
cv::Rect roi( cv::Point( 12, 7 ), small_image.size() );
small_image.copyTo( image_padded( roi ) );
它声称“断言失败(m.dims <= 2)”,而两个 Mat 变量都是 3D 矩阵。
任何帮助实现零填充的帮助将不胜感激!
您描述的两种方法均无效,因为它们旨在用于二维矩阵。您有一个 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
我们还可以结合使用 rowRange
和 colRange
方法将我们感兴趣的区域设置为 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 );