Home > Blockchain >  How to use cv::Mat::at<double>(i,j,k) (to access a multi channel matrix)?
How to use cv::Mat::at<double>(i,j,k) (to access a multi channel matrix)?

Time:07-30

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

int main()
{
    double m[1][4][3] =
        {
            {{1.0, 2.0, 3.0}, {4.0, 5.0, 6.0}, {7.0, 8.0, 9.0}, {10.0, 11.0, 12.0}}};

    cv::Mat M(1, 4, CV_64FC3, m);

    for (int i = 0; i < 1;   i)
        for (int j = 0; j < 4;   j)
            for (int k = 0; k < 3;   k)
                std::cout << M.at<double>(i, j, k) << std::endl;

    

    cv::namedWindow("Input", cv::WINDOW_NORMAL);
    cv::imshow("Input", M);
    cv::waitKey();

    return 0;
}

Expected Output

1.0
2.0
3.0
4.0
5.0
6.0
7.0
8.0
9.0
10.0
11.0
12.0

Current Output

1
8.10465e-320
5.31665e-315
4
8.11058e-320
2.122e-314  
7
8.11355e-320
-9.44163e 21
10
7.16685e-308
0

CodePudding user response:

opencv treats the number of channels in each element of a cv::Mat as separate from the number of dimensions.

In your case cv::Mat M(1, 4, CV_64FC3, m) is a 2 dimentional array where each element has 3 channels.

cv::Mat::at returns an element in the cv::Mat.
In order to use it in your case you need to:

  1. Pass 2 indices for the 2 dimensions.
  2. Get a cv::Vec3d value which holds an element with 3 channels of doubles .
  3. Iterate over the channels using operator[] of cv::Vec3d.

Complete example:

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

int main()
{
    double m[1][4][3] = {{{1.0, 2.0, 3.0}, {4.0, 5.0, 6.0}, {7.0, 8.0, 9.0}, {10.0, 11.0, 12.0}} };
    cv::Mat M(1, 4, CV_64FC3, m);

    for (int i = 0; i < M.rows;   i)
    {
        for (int j = 0; j < M.cols;   j)
        {
            cv::Vec3d const& elem = M.at<cv::Vec3d>(i, j);
            for (int k = 0; k < 3;   k)
            {
                std::cout << elem[k] << std::endl;
            }
        }
    }

    return 0;
}

Output:

1
2
3
4
5
6
7
8
9
10
11
12

Note:

Using cv::Mat::at for traversing a big matrix is not the most efficient way (and in debug builds it also incurs expensive validity checks).
A more efficient way it to use cv::Mat::ptr, which gives you direct access to row data.

Usage in your case (yields the same output):

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

int main()
{
    double m[1][4][3] = { {{1.0, 2.0, 3.0}, {4.0, 5.0, 6.0}, {7.0, 8.0, 9.0}, {10.0, 11.0, 12.0}} };
    cv::Mat M(1, 4, CV_64FC3, m);

    for (int i = 0; i < M.rows;   i)
    {
    //----------------------------vvv---------------
        cv::Vec3d const* pRow = M.ptr<cv::Vec3d>(i);
        for (int j = 0; j < M.cols;   j)
        {
            cv::Vec3d const& elem = pRow[j];
            for (int k = 0; k < 3;   k)
            {
                std::cout << elem[k] << std::endl;
            }
        }
    }

    return 0;
}
  • Related