0

I am unable to access a Mat of type 16UC(6). Below is the code used to iterate over the Mat.

//6 channel Mat
int cols=1280, rows=720;
Mat mat1=Mat(cols, rows, CV_16UC(6), Scalar::all(0));
Mat grid(Size(cols, rows), CV_16UC2, Scalar::all(0));   
//create a grid of numbers - the value of each pixel in the grid 
contains the coordinate of the pixel
for (int i = 0; i < grid.rows; ++i) {
    for (int j = 0; j < grid.cols; ++j) {
        grid.at<Vec2s>(i, j)[0] = (ushort)j;
        grid.at<Vec2s>(i, j)[1] = (ushort)i;
    }
}
vector<Mat> imgs(2); //create copies of the grid for each image
for(int i=0;i<2;i++){
    imgs[i] = grid.clone();
}
//Values in Mat1 are filled with values of imgs[0] and imgs[1] using 
// some logic.
int rows=mat1.rows;
int channels=mat1.channels();
int cols=mat1.cols * channels;
uchar* p;
for(int i=0;i<rows;i++){
   p=mat1.ptr<uchar>(i);
   for(int j=0;j<cols;j+=6){
      cout<<"Value 0 :"<<p[j]<<endl;
      cout<<"Value 1 :"<<p[j+1]<<endl;
      cout<<"Value 2 :"<<p[j+2]<<endl;
      cout<<"Value 3 :"<<p[j+3]<<endl;
      cout<<"Value 4 :"<<p[j+4]<<endl;
      cout<<"Value 5 :"<<p[j+5]<<endl;
   }
 }

But im getting ^E and ^@ as values. When tried casting to (int) I am getting all zeros. I am able to access the Mat properly using MatIterator. I am not sure where I went wrong, there must be some issue with the Mat ype and the way I am trying to access the value.Can anyone help me in solving the issue.

Gayathri
  • 5
  • 3

1 Answers1

0

You have:

grid.at<Vec2s>(i, j)[0] = (ushort)j;

Vec2s is for shorts, but you have Unsigned Short matrix. You should use Vec2w (not sure who came with the w... or why) that is for unsigned short.

This can be rewritten as:

grid.at<cv::Vec2w>(i, j)[0] = static_cast<ushort>(j);

Then, you show uchar values from the 16U matrix... each uchar is 8bit and each pixel is 16bit...

Here is an example of how you can access each pixel with iterators in a CV_16UC(6) matrix.

  // create dummy 3x3 matrix
  cv::Mat b(3,3,CV_16UC(6));
  // use the templated functions begin and end (you may templated with <ushort> 
  // directly and it will represent the value of each channel of each pixel)
  for (auto it = b.begin<cv::Vec<ushort, 6>>(); it != b.end<cv::Vec<ushort, 6>>(); ++it)
  {
    // assign some values (this part can be skipped if it is already filled)
    (*it)[0] = 5;
    (*it)[1] = 7;
    (*it)[2] = 8;
    (*it)[3] = 9;
    (*it)[4] = 1;
    (*it)[5] = 2;
    // Print the Vec<ushort, 6>, OpenCV already has a way to print it
    std::cout << *it << std::endl;
  }

And the result of this small code is:

[5, 7, 8, 9, 1, 2]
[5, 7, 8, 9, 1, 2]
[5, 7, 8, 9, 1, 2]
[5, 7, 8, 9, 1, 2]
[5, 7, 8, 9, 1, 2]
[5, 7, 8, 9, 1, 2]
[5, 7, 8, 9, 1, 2]
[5, 7, 8, 9, 1, 2]
[5, 7, 8, 9, 1, 2]

Which is what we expect. You may have notice that I used cv::Vec<ushort, 6>, cv::Vec can be templated with any number of channels (probably there is a limit) and any type (I have only tested it with native numeric types). Actually cv::Vec2w or cv::Vec2s are just typedef of cv::Vec and cv::Vec respectively, and you can also create your typedef if you use it all over the code.

using Vec6w = cv::Vec<ushort, 6>;

and then you can replace it in the for loop:

...
for (auto it = b.begin<Vec6w>(); it != b.end<Vec6w>(); ++it)
...

and achieve the same result

api55
  • 11,070
  • 4
  • 41
  • 57