【问题标题】:OpenCV - Accessing Mat data using for loopOpenCV - 使用 for 循环访问 Mat 数据
【发布时间】:2021-12-17 18:02:41
【问题描述】:

我正在尝试创建卷积函数,但在访问内核数据 (cv::Mat) 期间遇到了问题。

我创建了 3x3 内核:

  cv::Mat krn(3, 3, CV_32FC1);
  krn.setTo(1);
  krn = krn/9;

然后我尝试遍历它。接下来image Mat 将是我要应用卷积运算符的图像,输出将是卷积的结果:

     for (int r = 0; r < image.rows - krn.rows; ++r) {

        for (int c = 0; c < image.cols - krn.cols; ++c) {

        int sum = 0;

        for (int rs = 0; rs < krn.rows; ++rs) {
          for (int cs = 0; cs < krn.cols; ++cs) {

            sum += krn.data[rs * krn.cols + cs] * image.data[(r + rs) * image.cols + c + cs];
          }
        }
        output.data[(r+1)*src.cols + c + 1]=sum;  // assuming 3x3 kernel
    }
  }

但是输出不是我们想要的(只有随机的黑白像素)。 但是,如果我以这种方式更改我的代码:

for (int r = 0; r < image.rows - krn.rows; ++r) {
    
            for (int c = 0; c < image.cols - krn.cols; ++c) {
    
            int sum = 0;
    
            for (int rs = 0; rs < krn.rows; ++rs) {
              for (int cs = 0; cs < krn.cols; ++cs) {
    
                sum += 0.11 * image.data[(r + rs) * image.cols + c + cs];           // CHANGE HERE
              }
            }
            output.data[(r+1)*src.cols + c + 1]=sum;  // assuming 3x3 kernel
        }
      }

使用0.11 代替内核值似乎可以提供正确的输出。 出于这个原因,我认为我在访问内核数据时做错了。

P.S:我不能使用krn.at&lt;float&gt;(rs,cs)

谢谢!

【问题讨论】:

  • krn.at(rs,cs) - 尝试以这种方式访问​​内核数据
  • 谢谢,我会添加到主帖中,但我不能使用它。
  • float* kernel_float_data = (float*)krn.data - 然后像你一样访问你的内核。
  • 很好,谢谢!在您看来,opencv convertTo() 函数还有其他方法吗?谢谢!
  • convertTo() 方法不影响“数据”字段的类型。

标签: c++ opencv mat


【解决方案1】:

您可以投射指针,而不是不必要地使用memcpy。我将使用 C 风格的演员表,因为为什么不呢。

cv::Mat krn = 1 / (cv::Mat_<float>(3,3) <<
    1, 2, 3,
    4, 5, 6,
    7, 8, 9);

for (int i = 0; i < krn.rows; i += 1)
{
    for (int j = 0; j < krn.cols; j += 1)
    {
        // to see clearly what's happening
        uint8_t *byteptr = krn.data + krn.step[0] * i + krn.step[1] * j;
        float *floatptr = (float*) byteptr;

        // or in one step:
        float *floatptr = (float*) (krn.data + krn.step[0] * i + krn.step[1] * j);

        cout << "krn.at<float>(" << i << "," << j << ") = " << (*floatptr) << endl;
endl;
    }
}
krn.at<float>(0,0) = 1
krn.at<float>(0,1) = 0.5
krn.at<float>(0,2) = 0.333333
krn.at<float>(1,0) = 0.25
krn.at<float>(1,1) = 0.2
krn.at<float>(1,2) = 0.166667
krn.at<float>(2,0) = 0.142857
krn.at<float>(2,1) = 0.125
krn.at<float>(2,2) = 0.111111

请注意,指针运算可能并不明显。如果你有一个uint8_t*,添加1 移动它一个uint8_t,如果你有一个float*,添加1 移动它一个浮动这是四个字节。 step[] 包含以字节表示的偏移量。

请咨询the documentation 了解详情,其中包括step[] 数组的信息,该数组包含在给定矩阵索引元组的情况下计算偏移量的步幅/步骤。

【讨论】:

  • 谢谢。与 memcpy 相比,我更喜欢这种方法。
  • 我能再问你一件事吗?我正在使用 5x5 内核和 filter2D() 函数比较我的结果。但是,我的结果似乎是错误的。查看代码,您知道我缺少什么吗?谢谢
  • 是的,在您的代码中,您正在从 uint8_t (uchar) 指针(image.datakrn.data)访问 float 数据。 ..那会给你垃圾。应用我展示的内容,问题就会解决。
  • 你应该找到 C++ 的学习资料。这是基本的 C++,甚至是基本的 C。*floatptr = something
【解决方案2】:

cv::Mat::datauchar 类型的指针。

通过data[y * cols + x],您可以访问krn 中存储的float 值的一些字节。要获得完整的浮点值,请使用 at 方法模板:

krn.at<float>(rs,cs)

考虑将sum 变量的类型更改为真实变量。没有这个,在计算卷积时可能会丢失部分结果。


所以,如果你不能使用at,只需从数据指针中读取4个字节:

float v = 0.0;
memcpy(&v, krn.data + (rs * krn.step + cs * sizeof(float)), 4);

step - 表示 mat 中一行占用的总字节数。

【讨论】:

  • 非常感谢您的回答。但是作为练习,我不能使用krn.at&lt;float&gt;。你会建议另一种方法吗?
  • 编辑了我的答案。
  • 再次感谢您的帮助。我正在使用 5x5 内核和 filter2D() 函数比较我的结果。但是,我的结果似乎是错误的。查看代码,您知道我缺少什么吗?再次感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-03
  • 2012-11-12
  • 1970-01-01
  • 2021-06-29
  • 2013-10-30
  • 2020-04-04
  • 1970-01-01
相关资源
最近更新 更多