`
bcyy
  • 浏览: 1846211 次
文章分类
社区版块
存档分类
最新评论

【OpenCV】访问Mat图像中每个像素的值

 
阅读更多

今天百度搜资料还搜到了自己的。。。《访问图像中每个像素的值》,这是之前写的了,用的也是2.0的风格IplImage*格式,不太适用后来Mat的格式,特此重写一篇。

以下例子源自《The OpenCV Tutorials --Release 2.4.2》2.2 How to scan images, lookup tables and time measurement with OpenCV


图像容器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;
}
注意:书中这段代码是有问题的,前面写成了
int nRows = I.rows * channels;
int nCols = I.cols;
一般情况 isContinous为true,运行不会出错,但你可以注释掉那个if,会有访问越界的问题。
这种访问形式就是在每行定义一个指针,然后在内存上直接连续访问。如果整个数组在内存上都是连续存放的,那么只需要定义一个指针就可以访问所有的数据!如单通道的灰度图访问方式如下:
uchar* p = I.data;
for( unsigned int i =0; i < ncol*nrows; ++i)
	*p++ = table[*p];

安全的方法:迭代器iterator

相比用指针直接访问可能出现越界问题,迭代器绝对是非常安全的方法:
Mat& ScanImageAndReduceIterator(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:
		{
			MatIterator_<uchar> it, end;
			for( it = I.begin<uchar>(), end = I.end<uchar>(); it != end; ++it)
				*it = table[*it];
			break;
		}
	case 3:
		{
			MatIterator_<Vec3b> it, end;
			for( it = I.begin<Vec3b>(), end = I.end<Vec3b>(); it != end; ++it)
			{
				(*it)[0] = table[(*it)[0]];
				(*it)[1] = table[(*it)[1]];
				(*it)[2] = table[(*it)[2]];
			}
		}
	}
	return I;
}
这里我们只定义了一个迭代器,用了一个for循环,这是因为在OpenCV里迭代器会访问每一列然后自动跳到下一行,不用管在内存上是否isContinous。另外要注意的是在三通道图像中我们定义的是 <Vec3b>格式的迭代器,如果定义成uchar,则只能访问到B即蓝色通道的值。
这种方式虽然安全,但是挺慢的,一会儿就知道了。

更慢的方法:动态地址计算

这种方法在需要连续扫描所有点的应用时并不推荐,因为它更实用与随机访问。这种方法最基本的用途是访问任意的某一行某一列:
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 种情况。这个操作可以用一个简单的公式:

来实现,因为C++中int类型除法操作会自动截余。 类如 Iold=14; Inew=(Iold/10)*10=(14/10)*10=1*10=10;
在处理图像像素时,每个像素需要进行一遍上述计算也需要一定的时间花销。但我们注意到其实只有 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的像素减小颜色空间的结果,这样也就可以理解上述方法中的操作:
p[j] = table[p[j]];

LUT : Look up table

OpenCV 很聪明的有个 LUT 函数就是针对这种 Look up talbe 的操作:
Mat lookUpTable(1, 256, CV_8U);
uchar* p = lookUpTable.data;
for( int i = 0; i < 256; ++i)
	p[i] = table[i];
for (int i = 0; i < times; ++i)
	LUT(I, lookUpTable, J);

算法计时

为了验证几种方法的效率,可以用一个简单的计时和输出:
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图像中每个像素的值.docx

    【OpenCV】访问Mat图像中每个像素的值.docx

    访问Mat图像中每个像素的值

    三种方法访问图像中像素的值。 参考博文:http://blog.csdn.net/xiaowei_cqu/article/details/7771760

    OpenCvSharp实现Mat对象简单的像素操作

    1: 输出一个Mat对象的像素 自定义一个Mat 对象,然后输出像素值(像素值基本都在 0 – 255 之间 ,图像为三通道) ... * 小图像的每一个像素值我们都是知道的,可以输出查看,验证算法正确性,然后在ran大图 *

    OPENCV_Mat类存取方法

    * v.depth:深度,即每一个像素的位数(bits),在OpenCV的Mat.depth()中得到的是一个0–6的数字,分别代表不同的位数。 * vi.step:是一个数组,定义了矩阵的布局,具体见下面图片分析,另外注意step[k](step / ...

    opencv中对图像像素的访问

    //开始处理每个像素 (*it)[0] = (*it)[0] / div*div + div / 2; (*it)[1] = (*it)[1] / div*div + div / 2; (*it)[2] = (*it)[2] / div*div + div / 2; ++it; } } //动态地址计算像素 void atColorReduce(Mat&...

    c#计算机视觉库openCVSharp 计算机视觉.pdf

    在c++风格代码中,我们使用Mat类来读取图片,然后使用for循环来获取每个像素的值,并对其进行处理。我们可以使用指针来快速处理像素值。 openCVSharp提供了许多有用的功能,例如图像处理、视频分析、特征检测等。它...

    计算机视觉OpenCVAndroid图像操作之统计排序滤波、边缘保留滤波.pdf

    它的工作原理是,将图像分割成小窗口,然后对每个窗口内的像素值进行排序,取中间值作为输出。中值滤波的API函数位于Imgproc包中,函数名为medianBlur,函数原型为medianBlur(Mat src, Mat dst, int ksize)。其中,...

    Opencv图像处理:如何判断图片里某个颜色值占的比例

    一、功能 这里的需求是,判断摄像头有没有被物体遮挡。这里只考虑用手遮挡—-&gt;判断黑色颜色的范围。 二、使用OpenCV的Mat格式图片遍历图片 ... //遍历图片的每一个像素点 for(int i = 0; i &lt; im

    基于opencv3.1库的JAVA源码

    范例5-1-4改变影像的每1个像素调整影像明亮度 112 范例5-2-1全彩图转灰阶图 113 范例5-3-1影像颜色相反,使用Bitwise_xor 114 范例5-3-2影像颜色相反,使用subtract 115 范例5-3-3影像颜色相反,使用Bitwise_not 116 ...

    计算机视觉实验三图像线性滤波实验(附opencv代码) 计算机视觉.pdf

    这些滤波器都是线性滤波器,每个像素的输出值是一些输入像素的加权和。线性滤波器易于构造,并且易于从频率响应度来进行分析。 一、实验目的 * 通过实验掌握图像的框滤波原理和编程实现方法 * 通过实验掌握图像的...

    (一)OpenCV图像处理基础_15_自定义线性滤波

    卷积是图像处理中一个操作,是kernel在图像的每个像素上的操作。 Kernel本质上一个固定大小的矩阵数组,其中心点称为锚点(anchor point) 卷积过程:(模糊图像、提取边缘、图像锐化…) 把kernel放到像素数组之上,求...

    OpenCV识别图像上的线条轨迹

    (2)我的思路:根据图形中的每个像素点的差异去判断,对原图的灰度图做二值化处理,不是线条的区域像素置0,有线条的区域置为255,然后逐列进行像素求和,如果列的和大于0则是检测到了线条,此时结束该列的扫描,

    第八节 图像处理之模板匹配

    模板在待测图像上每次在横向或是纵向上移动一个像素,并作一次比较计算 我们可以通过cv.minMaxLoc函数来确定结果矩阵的最大值和最小值的位置。 2. cv.minMaxLoc(result) 返回result数值中最小值以及最小值...

    opencv3/C++ PHash算法图像检索详解

    将每个像素的灰度值与均值对比,大于均值记为1,小于均值记为0,得到64位哈希值。 PHash算法实现 将图片转为灰度值 将图片尺寸缩小为32*32 resize(src, src, Size(32, 32)); DCT变换 Mat srcDCT; dct(sr

Global site tag (gtag.js) - Google Analytics