《OpenCV:访问Mat图像中每个像素值》
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《OpenCV:访问Mat图像中每个像素值》相关的知识,希望对你有一定的参考价值。
图像容器Mat
还是先看Mat的存储形式。Mat和Matlab里的数组格式有点像,但一般是二维向量,如果是灰度图,一般存放<uchar>类型;如果是RGB彩色图,存放<Vec3b>类型。
单通道灰度图数据存放格式:
多通道的图像中,每列并列存放通道数量的子列,如RGB三通道彩色图:
注意通道的顺序反转了:BGR。通常情况内存足够大的话图像的每一行是连续存放的,也就是在内存上图像的所有数据存放成一行,这中情况在访问时可以提供很大方便。可以用 isContinuous()函数来判断图像数组是否为连续的。
访问图像中的像素
高效的方法:C操作符[ ]
最快的是直接用C风格的内存访问操作符[]来访问:
-
Mat& ScanImageAndReduceC(Mat& I, const uchar* const table) { // accept only char type matrices CV_Assert(I.depth() != sizeof(uchar)); int channels = I.channels(); int nRows = I.rows ; int nCols = I.cols* channels; if (I.isContinuous()) { nCols *= nRows; nRows = 1; } int i,j; uchar* p; for( i = 0; i < nRows; ++i) { p = I.ptr<uchar>(i); for ( j = 0; j < nCols; ++j) { p[j] = table[p[j]]; } } return I; }
一般情况 isContinous为true,运行不会出错,但你可以注释掉那个if,会有访问越界的问题。
这种访问形式就是在每行定义一个指针,然后在内存上直接连续访问。如果整个数组在内存上都是连续存放的,那么只需要定义一个指针就可以访问所有的数据!如单通道的灰度图访问方式如下:
uchar* p = I.data; for( unsigned int i =0; i < ncol*nrows; ++i) *p++ = table[*p];
这种方式虽然安全,但是挺慢的,一会儿就知道了。
更慢的方法:动态地址计算
这种方法在需要连续扫描所有点的应用时并不推荐,因为它更实用与随机访问。这种方法最基本的用途是访问任意的某一行某一列:
Mat& ScanImageAndReduceRandomAccess(Mat& I, const uchar* const table) { // accept only char type matrices CV_Assert(I.depth() != sizeof(uchar)); const int channels = I.channels(); switch(channels) { case 1: { for( int i = 0; i < I.rows; ++i) for( int j = 0; j < I.cols; ++j ) I.at<uchar>(i,j) = table[I.at<uchar>(i,j)]; break; } case 3: { Mat_<Vec3b> _I = I; for( int i = 0; i < I.rows; ++i) for( int j = 0; j < I.cols; ++j ) { _I(i,j)[0] = table[_I(i,j)[0]]; _I(i,j)[1] = table[_I(i,j)[1]]; _I(i,j)[2] = table[_I(i,j)[2]]; } I = _I; break; } } return I; }
减小颜色空间 color space reduction
现在来介绍下上述函数对每个元素的操作,也就是用table更改像素值。这里其实是做了个减小颜色空间的操作,这在一些识别之类的应用中会大大降低运算复杂度。类如uchar类型的三通道图像,每个通道取值可以是0~255,于是就有 256*256个不同的值。我们可以通过定义:
0~9 范围的像素值为 0
10~19 范围的像素值 为 10
20~29 范围的像素值为 20
。。。。。。
着这样的操作将颜色取值降低为 26*26*26 种情况。这个操作可以用一个简单的公式:
0~9 范围的像素值为 0
10~19 范围的像素值 为 10
20~29 范围的像素值为 20
。。。。。。
着这样的操作将颜色取值降低为 26*26*26 种情况。这个操作可以用一个简单的公式:
来实现,因为C++中int类型除法操作会自动截余。 类如 Iold=14; Inew=(Iold/10)*10=(14/10)*10=1*10=10;
在处理图像像素时,每个像素需要进行一遍上述计算也需要一定的时间花销。但我们注意到其实只有 0~255 种像素,即只有256种情况。进一步可以把256种计算好的结果提前存在表中 table 中,这样每种情况不需计算直接从 table 中取结果即可。
在处理图像像素时,每个像素需要进行一遍上述计算也需要一定的时间花销。但我们注意到其实只有 0~255 种像素,即只有256种情况。进一步可以把256种计算好的结果提前存在表中 table 中,这样每种情况不需计算直接从 table 中取结果即可。
int divideWith=10; uchar table[256]; for (int i = 0; i < 256; ++i) table[i] = divideWith* (i/divideWith);
于是table[i]存放的是值为i的像素减小颜色空间的结果,这样也就可以理解上述方法中的操作:
LUT : Look up table
OpenCV 很聪明的有个 LUT 函数就是针对这种 Look up talbe 的操作:算法计时
为了验证几种方法的效率,可以用一个简单的计时和输出:
double t; t = (double)getTickCount(); t = 1000*((double)getTickCount() - t)/getTickFrequency(); t /= times;
原图:
降低颜色空间结果:
算法时间:
更清楚的时间对比表:
转载请注明出处:http://blog.csdn.net/xiaowei_cqu/article/details/7771760
实验代码下载:http://download.csdn.net/detail/xiaowei_cqu/4443761
以上是关于《OpenCV:访问Mat图像中每个像素值》的主要内容,如果未能解决你的问题,请参考以下文章