【问题标题】:How to fill Matrix with zeros in OpenCV?如何在 OpenCV 中用零填充矩阵?
【发布时间】:2013-06-07 03:56:14
【问题描述】:

下面的代码会导致异常。为什么?

#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 个参数。

【问题讨论】:

  • 这是一个例子cv::Mat depthMap = cv::Mat::zeros(depthMap.rows, depthMap.cols, depthMap.type());

标签: c++ opencv matrix initialization


【解决方案1】:

如何在 OpenCV 中用零填充矩阵?

要用零填充预先存在的Mat 对象,您可以使用Mat::zeros()

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 吗?
  • @SuzanCioc 它可能被解释为void*,即作为指向某些数据的指针。
  • 我没有看到有 4 个参数的原型,最后是 void*
  • @SuzanCioc 我看到了这个:Mat::Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP) 这里是docs.opencv.org/modules/core/doc/basic_structures.html
  • 注意cv::Mat::zeros() 等会创建一个新矩阵,m1 之后会指向这个新矩阵。指向与m1 相同数据的其他实例将继续指向那里。要将现有矩阵归零,请按照@GPPK 的建议使用cv::Mat::setTo()
【解决方案2】:

使用cv::mat::setto

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

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

      您可以选择填充零数据或创建零Mat。

      1. setTo()填充零数据:

        img.setTo(Scalar::all(0));
        
      2. zeros()创建零数据:

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

      img 改变内存地址。

      【讨论】:

        【解决方案5】:

        如果您更喜欢使用模板进行编程,您也可以这样做......

        template<typename _Tp>
        ... some algo ...
        cv::Mat mat = cv::Mat_<_Tp>::zeros(rows, cols);
        mat.at<_Tp>(i, j) = val;
        

        【讨论】:

          【解决方案6】:

          您可以使用它在已经包含数据的 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 );
          

          【讨论】:

            【解决方案7】:

            垫子;

            img=Mat::zeros(图片大小,CV_8UC3);

            如果你希望它是图像 img1

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

            【讨论】:

              【解决方案8】:

              我想您是在谈论填充一些现有垫子的零?这个怎么样? :)

              垫 *= 0;

              【讨论】:

                猜你喜欢
                • 2019-06-15
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多