32

The code below causes an exception. Why?

#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;
    }

}

Error is follows:

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

UPDATE

If tracing this code, I see that constructor line calls the constructor

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

Why? This prototype has 5 parameters, while I am providing 4 arguments.

Suzan Cioc
  • 29,281
  • 63
  • 213
  • 385

8 Answers8

43

How to fill Matrix with zeros in OpenCV?

To fill a pre-existing Mat object with zeros, you can use Mat::zeros()

Mat m1 = ...;
m1 = Mat::zeros(1, 1, CV_64F);

To intialize a Mat so that it contains only zeros, you can pass a scalar with value 0 to the constructor:

Mat m1 = Mat(1,1, CV_64F, 0.0);
//                        ^^^^double literal

The reason your version failed is that passing 0 as fourth argument matches the overload taking a void* better than the one taking a scalar.

juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • Thanks. But what does my sample does? Doesn't `0` converted automatically to `Scalar`? – Suzan Cioc Jun 11 '13 at 10:26
  • @SuzanCioc it could be that it is interpreted as `void*`, i.e. as a pointer to some data. – juanchopanza Jun 11 '13 at 10:29
  • I see no prototype with 4 parameters and `void*` at the end. – Suzan Cioc Jun 11 '13 at 10:32
  • 3
    @SuzanCioc I see this: `Mat::Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP)` here http://docs.opencv.org/modules/core/doc/basic_structures.html – juanchopanza Jun 11 '13 at 10:36
  • Note that `cv::Mat::zeros()` and the like will create a new matrix, `m1` will afterwards point to this new matrix. Other instances which point to the same data as `m1` will continue to point there. To zero a existing matrix use `cv::Mat::setTo()` as suggested by @GPPK. – Brandlingo Jun 17 '15 at 14:22
  • you can also pass explicit `cv::Scalar(0)` to ensure proper overload is called – slawekwin Mar 17 '17 at 08:34
15

use cv::mat::setto

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

GPPK
  • 6,546
  • 4
  • 32
  • 57
12

Because the last parameter is optional and also the data pointer should point somewhere appropriate:

//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;

But better do it directly with this template-based constructor:

//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));
LovaBill
  • 5,107
  • 1
  • 24
  • 32
8

You can choose filling zero data or create zero Mat.

  1. Filling zero data with setTo():

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

    img = zeros(img.size(), img.type());
    

The img changes address of memory.

Lenik
  • 13,946
  • 17
  • 75
  • 103
James Koo
  • 91
  • 1
  • 4
6

If You are more into programming with templates, You may also do it this way...

template<typename _Tp>
... some algo ...
cv::Mat mat = cv::Mat_<_Tp>::zeros(rows, cols);
mat.at<_Tp>(i, j) = val;
Nik Ved
  • 168
  • 2
  • 8
3

You can use this to fill zeroes in a Mat object already containing data:

image1 = Scalar::all(0);

For eg, if you use it this way:

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

It will work fine. But you cannot use this for uninitialised Mat. For that you can go for other options mentioned in above answers, like

Mat drawing = Mat::zeros( image.size(), CV_8UC3 );
Shameel Mohamed
  • 607
  • 5
  • 23
2

Mat img;

img=Mat::zeros(size of image,CV_8UC3);

if you want it to be of an image img1

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

Lonewolf
  • 66
  • 2
  • 10
0

I presume you are talking about filling zeros of some existing mat? How about this? :)

mat *= 0;

Cynichniy Bandera
  • 5,991
  • 2
  • 29
  • 33