如何在OpenCV中将矩阵填充为零?

32

以下代码会引发异常。为什么?

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

using namespace cv;
using namespace std;

void main() {

    try {
        Mat m1 = Mat(1,1, CV_64F, 0);
        m1.at<double>(0,0) = 0;
    }
    catch(cv::Exception &e) {
        cerr << e.what() << endl;
    }

}

错误如下:

OpenCV Error: Assertion failed (dims <= 2 && data && (unsigned)i0 < (unsigned)size.p[0] && (unsigned)(i1*DataType<_Tp>::channels) < (unsigned)(size.p[1]*channels()) && ((((sizeof(size_t)<<28)|0x8442211) >> ((DataType<_Tp>::depth) & ((1 << 3
) - 1))*4) & 15) == elemSize1()) in unknown function, file %OPENCV_DIR%\build\include\opencv2\core\mat.hpp, line 537

更新

如果跟踪这段代码,我会发现构造函数的那一行调用了构造函数。

inline Mat::Mat(int _rows, int _cols, int _type, void* _data, size_t _step)

为什么?这个原型有5个参数,而我只提供了4个参数。


4
这是一个例子:cv::Mat depthMap = cv::Mat::zeros(depthMap.rows, depthMap.cols, depthMap.type()); - Mona Jalal
8个回答

43
使用OpenCV中的Mat::zeros()函数可以填充一个已存在的Mat对象为零。
Mat m1 = ...;
m1 = Mat::zeros(1, 1, CV_64F);
为了初始化一个只包含零的Mat,你可以将一个值为0的标量传递给构造函数:
Mat m1 = Mat(1,1, CV_64F, 0.0);
//                        ^^^^double literal
你的版本失败的原因是第四个参数传递了0,导致匹配到以void*为参数类型的函数重载,而不是匹配到以标量为参数类型的函数重载。

谢谢。但是我的示例做了什么?0不会自动转换为Scalar吗? - Suzan Cioc
@SuzanCioc 可能会被解释为 void*,即指向某些数据的指针。 - juanchopanza
我没有看到带有4个参数和以void*结尾的原型。 - Suzan Cioc
3
我看到这个:在这里http://docs.opencv.org/modules/core/doc/basic_structures.html,`Mat::Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP)`。 - juanchopanza
请注意,cv::Mat::zeros()等函数将创建一个新的矩阵,m1将随后指向这个新矩阵。其他指向与m1相同数据的实例将继续指向那里。要将现有矩阵清零,请使用cv::Mat::setTo(),如@GPPK所建议的那样。 - Brandlingo
您可以传递显式的 cv::Scalar(0),以确保调用正确的重载函数。 - slawekwin

15

使用cv::mat::setTo方法。

img.setTo(cv::Scalar(redVal,greenVal,blueVal))


12

因为最后一个参数是可选的,而且数据指针应该指向适当的位置:

//inline Mat::Mat(int _rows, int _cols, int _type, void* _data, size_t _step)
double mydata[1];
Mat m1 = Mat(1,1, CV_64F, mydata); 
m1.at<double>(0,0) = 0;

但最好直接使用这个基于模板的构造函数:

//inline Mat::Mat(int _rows, int _cols, int _type, const Scalar& _s)
Mat m1 = Mat(1,1, CV_64F, cvScalar(0.));

//or even
Mat m1 = Mat(1,1, CV_64F, double(0));

9
您可以选择填充零数据或创建零矩阵。
  1. Filling zero data with setTo():

    img.setTo(Scalar::all(0));
    
  2. Create zero data with zeros():

    img = zeros(img.size(), img.type());
    
会改变内存地址。

6
如果您更喜欢使用模板进行编程,您也可以这样做...
template<typename _Tp>
... some algo ...
cv::Mat mat = cv::Mat_<_Tp>::zeros(rows, cols);
mat.at<_Tp>(i, j) = val;

3
您可以使用此方法在已包含数据的 Mat 对象中填充零:
image1 = Scalar::all(0);

例如,如果您这样使用它:
Mat image,image1;
image = imread("IMG_20160107_185956.jpg", CV_LOAD_IMAGE_COLOR);   // Read the file

if(! image.data )                              // Check for invalid input
{
    cout <<  "Could not open or find the image" << std::endl ;
    return -1;
}
cvtColor(image,image1,CV_BGR2GRAY);
image1 = Scalar::all(0);

它将正常工作。但是您无法将其用于未初始化的Mat。对于此,您可以使用上面答案中提到的其他选项,例如

Mat drawing = Mat::zeros( image.size(), CV_8UC3 );

2

Mat img;

img=Mat::zeros(图像尺寸,CV_8UC3);

如果你想让它成为一个名叫img1的图片

img=Mat::zeros(img1.size,CV_8UC3);


0
我猜你是在谈论如何填充某个已有矩阵的零值?这样怎么样?:)
mat *= 0;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接