【问题标题】:opencv multi channel element accessopencv多通道元素访问
【发布时间】:2010-12-21 22:33:42
【问题描述】:

我正在尝试学习如何使用 OpenCV 的新 C++ 接口。

如何访问多通道矩阵的元素?例如:

Mat myMat(size(3, 3), CV_32FC2);

for (int i = 0; i < 3; ++i)
{
    for (int j = 0; j < 3; ++j)
    {
        //myMat_at_(i,j) = (i,j);
    }
}

最简单的方法是什么?类似于旧界面的 cvSet2D。
最有效的方法是什么?类似于在旧接口中使用直接指针。

【问题讨论】:

    标签: c++ image image-processing opencv


    【解决方案1】:
    typedef struct elem_ {
            float f1;
            float f2;
    } elem;
    elem data[9] = { 0.0f };
    CvMat mat = cvMat(3, 3, CV_32FC2, data );
    
    float f1 = CV_MAT_ELEM(mat, elem, row, col).f1;
    float f2 = CV_MAT_ELEM(mat, elem, row, col).f2;
    
    CV_MAT_ELEM(mat, elem, row, col).f1 = 1212.0f;
    CV_MAT_ELEM(mat, elem, row, col).f2 = 326.0f;
    

    更新:适用于 OpenCV2.0

    1。选择一种类型来表示元素

    Mat(或 CvMat)有 3 个维度:行、列、通道。
    我们可以通过指定行和列来访问矩阵中的一个元素(或像素)。

    CV_32FC2 表示该元素是 2 通道的 32 位浮点值。
    所以上面代码中的 elem 是CV_32FC2 的一种可接受的表示形式。

    您可以使用您喜欢的其他表示。例如:

    typedef struct elem_ { float val[2];    } elem;
    typedef struct elem_ { float x;float y; } elem;
    

    OpenCV2.0 增加了一些新的类型来表示矩阵中的元素,比如:

    template<typename _Tp, int cn> class CV_EXPORTS Vec // cxcore.hpp (208)
    

    所以我们可以用Vec&lt;float,2&gt;来代表CV_32FC2,或者用:

    typedef Vec<float, 2> Vec2f; // cxcore.hpp (254)
    

    查看源代码以获取更多可以代表您的元素的类型。
    这里我们使用Vec2f

    2。访问元素

    访问 Mat 类中元素的最简单有效的方法是 Mat::at。
    它有 4 个重载:

    template<typename _Tp> _Tp& at(int y, int x);                // cxcore.hpp (868)
    template<typename _Tp> const _Tp& at(int y, int x) const;    // cxcore.hpp (870)
    template<typename _Tp> _Tp& at(Point pt);                    // cxcore.hpp (869)
    template<typename _Tp> const _Tp& at(Point pt) const;        // cxcore.hpp (871)
    // defineded in cxmat.hpp (454-468)
    
    // we can access the element like this :
    Mat m( Size(3,3) , CV_32FC2 );
    Vec2f& elem = m.at<Vec2f>( row , col ); // or m.at<Vec2f>( Point(col,row) );
    elem[0] = 1212.0f;
    elem[1] = 326.0f;
    float c1 = m.at<Vec2f>( row , col )[0]; // or m.at<Vec2f>( Point(col,row) );
    float c2 = m.at<Vec2f>( row , col )[1];
    m.at<Vec2f>( row, col )[0] = 1986.0f;
    m.at<Vec2f>( row, col )[1] = 326.0f;
    

    3。与旧界面交互

    Mat 提供 2 个转换函数:

    // converts header to CvMat; no data is copied     // cxcore.hpp (829)
    operator CvMat() const;                            // defined in cxmat.hpp
    // converts header to IplImage; no data is copied
    operator IplImage() const;
    
    // we can interact a Mat object with old interface :
    Mat new_matrix( ... );
    CvMat old_matrix = new_matrix;  // be careful about its lifetime
    CV_MAT_ELEM(old_mat, elem, row, col).f1 = 1212.0f;
    

    【讨论】:

    • 谢谢,但不是我想要的。您正在使用 CvMat - 旧的(1.1 版)c API。我想要使​​用 Mat 类的新 (2.0a) c++ API 的类似方法。 Mat 类有类似 CV_MAT_ELEM 的东西吗?
    • 对不起,我忘记OpenCV2.0已经发布了。我下载了 2.0 源代码并找到了一些接近您的目标的方法。请参阅更新的代码。
    • 有没有更好的方法来访问 CvMat 没有使用 CV_MAT_ELEM 像 CV_MAT_ELEM(old_mat, elem, row, col).f1 ?固定 f1 或 f2 后,我们无法以编程方式迭代矩阵,即 i,j 索引
    【解决方案2】:

    Vic 你必须使用 Vec3b 而不是 Vec3i:

    for (int i=0; i<image.rows; i++)
    {
        for (int j=0; j<image.cols; j++)
        {
            if (someArray[i][j] == 0)
            {
                image.at<Vec3b>(i,j)[0] = 0;
                image.at<Vec3b>(i,j)[1] = 0;
                image.at<Vec3b>(i,j)[2] = 0;
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

      可以直接访问底层数据数组:

      Mat myMat(size(3, 3), CV_32FC2);
      
      myMat.ptr<float>(y)[2*x]; // first channel
      myMat.ptr<float>(y)[2*x+1]; // second channel
      

      【讨论】:

      • 值得一提的是,y 是图像行,x 是图像列。您需要将 x 乘以 2,因为您有 2 个通道,并且在 OpenCV 中图像以行优先顺序表示为 HEIGHT x WIDTH x CHANNELS 矩阵。
      【解决方案4】:

      这取决于您使用的 Mat 的数据类型,如果它是像 CV_32FC1 这样的数字 你可以使用:

      myMat.at<float>(i, j)
      

      如果它是 uchar 类型,那么您可以使用访问元素

      (symb.at<Vec3b>(i, j)).val[k]
      

      其中 k 是通道,0 表示灰度图像,3 表示彩色图像

      【讨论】:

        【解决方案5】:

        使用 c++ api 访问多通道数组的最佳方法是使用 ptr 方法创建指向特定行的指针。

        例如;

        type elem = matrix.ptr&lt;type&gt;(i)[N~c~*j+c]

        在哪里

        • type:数据类型(float, int, char ect..)
        • i:您感兴趣的行
        • Nc:通道数
        • j:您感兴趣的列
        • c:您感兴趣的列(0-3)

        有关其他 c->c++ 转换的信息,请查看此链接:Source

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-08-07
          • 2011-09-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-02-01
          • 2014-05-13
          相关资源
          最近更新 更多