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中像素数据读取并转化再输出即可,只是获取指针方式不同而已。

  • 6
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值