初学OpenCV学习记录(二)

以下内容摘自OpenCV2 计算机视觉编程手册
大多数图像处理中,我们需要遍历图像的所有像素,接下来介绍遍历循环的方式(以三通道的彩色图像为例)

存储方式

在一个彩色图像中,图像数据缓冲区的前三个字节对应图像左上角像素的三个通道值,接下来三个字节对应第一行的第二个像素块,以此类推,出于效率考虑,有些图像每行会填补一些额外像素方便一些多媒体芯片处理数据,如果没有填补像素,则图像的有效宽度等于真实宽度。

本节用到的相关参数

成员变量:

  • rows 图像的高度(像素的行数)
  • cols 图像的宽度(像素的列数)
  • step 图像的有效宽度(一行像素包含的字节数)

成员函数:

  • elemSize():返回像素的大小(字节数)
  • channels():返回图像的通道数,比如RGB图像的通道数为3
  • total():返回矩阵的像素个数

遍历图像的方法

(1)指针遍历图像

ptr()模板函数获取图像任意行的地址
代码如下:

int row=image.rows;
int col=image.cols*image.channels();
for(int i=0;i<row;++i){
    
    
	uchar* data=image.ptr<uchar>(i);     //获得第i行的首地址
	for(int j=0;j<cols;j++){
    
    
		//在这里处理每一个像素data[j]或*data
	}
}

如果图像没有进行填补时,那么每一行的像素在内存中都是连续的,则可以仅使用一个循环就完成遍历。
代码如下:

if(image.isContinuous()) //判断图像是否有填补
{
    
    
	image.reshape(1,1);
}
int row=image.rows;
int col=image.cols*image.channels();
for(int i=0;i<row;++i){
    
    
	uchar* data=image.ptr<uchar>(i);     //获得第i行的首地址
	for(int j=0;j<cols;j++){
    
    
		//在这里处理每一个像素data[j]或*data
	}
}

reshape函数在不改变内存的情况下改变矩阵的维度,参数分别为新的通道数和行数,列数会根据设置值自适应。
还有一种不推荐使用的方式代码如下:

int row=image.rows;
int col=image.cols*image.channels();
for(int i=0;i<row;++i){
    
    
	for(int j=0;j<cols;j++){
    
    
		uchar *data=image.data+i*image.step+j*image.elemSize();
		//在这里处理每一个像素*data
	}
}

(2)使用迭代器遍历图像

OpenCv为cv::Mat提供了与STL迭代器兼容的迭代器:
cv::Mat_< xxx >::iterator 或 cv::Mat_< xxx >::const_iterator
代码如下:

cv::Mat_<cv::Vec3b>::iterator it=image.begin<cv::Vec3b>();
cv::Mat_<cv::Vec3b>::iterator itend=image.end<cv::Vec3b>();
for(;it!=itend;it++){
    
    
	//在这里处理每一个像素的三个通道分别是(*it)[0] (*it)[1] (*it)[2]
}
//如果想从任意位置开始,则迭代器初始化为image.begin<cv::Vec3b>()+x x为要跳过的像素个数

说明:使用指针遍历的运行速度更快,使用迭代器遍历代码更加清晰简洁,各有好处,根据具体项目进行取舍即可。

猜你喜欢

转载自blog.csdn.net/weixin_42411702/article/details/123819895
今日推荐