OpenCV遍历和输出Mat矩阵中数据方法总结

一、Mat中图像像素的访问方式

1.ptr操作和指针-高效的方式

这种方式基于.ptr的操作,也是比较推荐的遍历图像的方式。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 /** @Method 1: the efficient method   accept grayscale image and RGB image */ int  ScanImageEfficiet(Mat & image) {      // channels of the image      int  iChannels = image.channels();      // rows(height) of the image      int  iRows = image.rows;      // cols(width) of the image      int  iCols = image.cols * iChannels;        // check if the image data is stored continuous      if  (image.isContinuous())      {          iCols *= iRows;          iRows = 1;      }        uchar* p;      for  ( int  i = 0; i < iRows; i++)      {          // get the pointer to the ith row          p = image.ptr<uchar>(i);          // operates on each pixel          for  ( int  j = 0; j < iCols; j++)          {              // assigns new value              p[j] = table[p[j]];          }      }        return  0; }

这里获取一个指向每一行的指针,然后遍历这一行所有的数据。当图像数据是连续存储的时候,只需要取一次指针,然后就可以遍历整个图像数据。

2.迭代器-比较安全的方式

相较于高效的方式需要自己来计算需要遍历的数据量,以及当图像的行与行之间数据不连续的时候需要跳过一些间隙。迭代器(iterator)方式提供了一个更安全的访问图像像素的方式。你只需要做的就是声明两个MatIterator_变量,一个指向图像开始,一个指向图像结束,然后迭代。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 /** @Method 2: the iterator(safe) method   accept grayscale image and RGB image */ int  ScanImageIterator(Mat & image) {      // channels of the image      int  iChannels = image.channels();        switch  (iChannels)      {      case  1:      {          MatIterator_<uchar> it, end;          for  (it = image.begin<uchar>(), end = image.end<uchar>(); it != end; it++)          {              *it = table[*it];          }          break ;      }      case  3:      {          MatIterator_<Vec3b> it, end;          for  (it = image.begin<Vec3b>(), end = image.end<Vec3b>(); it != end; it++)          {              (*it)[0] = table[(*it)[0]];              (*it)[1] = table[(*it)[1]];              (*it)[2] = table[(*it)[2]];          }          break ;      }      }        return  0; }

彩色图像的话,由于是三个通道的向量,OpenCV提供了Vec3b的数据类型来存储。

3.动态地址计算-更适合随机访问的方式

这种方式不推荐用来遍历图像,一般用在要随机访问很少量的图像数据的时候。基本用法就是指定行列号,返回该位置的像素值。不过需要你事先知道返回的数据类型是uchar还是Vec3b或者其他的。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 /** @Method 3: random access method   accept grayscale image and RGB image */ int  ScanImageRandomAccess(Mat & image) {      // channels of the image      int  iChannels = image.channels();      // rows(height) of the image      int  iRows = image.rows;      // cols(width) of the image      int  iCols = image.cols;            switch  (iChannels)      {      // grayscale      case  1:      {          for  ( int  i = 0; i < iRows; i++)          {              for  ( int  j = 0; j < iCols; j++)              {                  image.at<uchar>(i, j) = table[image.at<uchar>(i, j)];              }          }          break ;      }      // RGB      case  3:      {          Mat_<Vec3b> _image = image;          for  ( int  i = 0; i < iRows; i++)          {              for  ( int  j = 0; j < iCols; j++)              {                  _image(i, j)[0] = table[_image(i, j)[0]];                  _image(i, j)[1] = table[_image(i, j)[1]];                  _image(i, j)[2] = table[_image(i, j)[2]];              }          }          image = _image;          break ;      }      }        return  0; }

4.查找表-一颗赛艇的方式

OpenCV大概也考虑到了有很多这种需要改变单个像素值的场合(比如基于单个像素值的亮度变换,gamma矫正等),因此在core模块提供了一个更加高效很一颗赛艇的LUT()函数来进行这种操作而且不需要遍历整个图像。
首先建个映射查找表:

1 2 3 4 5 6 7 // build a Mat type of the lookup table Mat lookupTable(1, 256, CV_8U); uchar* p = lookupTable.data; for  ( int  i = 0; i < 256; i++) {      p[i] = table[i]; }

然后调用LUT()函数:

1 2 // call the function LUT(image, lookupTable, matout);

image是输入图像,matout是输出图像。

二、Mat图像像素的输出方式

1.最简单直接输出方式

(1)直接通过cout<<mat<<endl;语句将所需输出的Mat矩阵输出到窗口;

(2)将mat中数据输出到xml文件中

FileStorage fs(“./mat.xml”,FileStorage::WRITE);
fs<<“mat”<<mat;
fs.release();

2.通过ptr操作和指针输出Mat图像像素

通过指针遍历mat中图像像素地址,依次输出

uchar * pdata=mat.ptr<uchar>(i);
for (int i=0;i<mat.rows;i++)
{

for (int j=0;j<mat.cols*mat.channels();j++)
{
cout<<padata[j]<<endl;
}
}

注意:由于mat中存储的像素数据是uchar或vec3d格式,直接通过cout<<padata[j]<<endl输出的话,将其数据对应的ASCII码进行输出,而有的数据ASCII码是隐藏的不对窗口显示,所以需要将数据类型进行转换再输出即可,如下:

int img_pixel=(int)padata[j];//像素中数据为0-255,所以使用int类型即可

cout<<padata[j]<<endl;

3.其余输出方式

其余输出方式都是通过指针将mat中像素数据读取并转化再输出即可,只是获取指针方式不同而已。

    原文作者:小伟锅
    原文地址: https://blog.csdn.net/u011028345/article/details/74852501
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞