您的位置:首页 > 运维架构

OpenCV学习笔记二:操作像素

2017-03-08 19:26 232 查看

一、存取像素值

Mat的成员函数at(int x,int y)用于存取第x行,第y例的像素值。存取像素值时必须知道图像的数据类型,因此at函数实现为模板函数,调用时需指定类型,例如对单通道图和彩色图:

//注:指定的数据类型一定要与图像的实际类型吻合
//单通道
image.at< uchar >(x,y) = 255;
//双通道
image.at<Vec3b>(x,y)[channel] = 255;


如果嫌调用函数时指定模板参数麻烦,可以使用Mat的模板子类Mat_,其重载了()操作符,可以直接存取像素值,像这样:

Mat_<uchar> image;
image(x,y) = 255;


二、图像遍历

遍历图像前最好先了解Mat的一些成员的意义

data:Mat中的一个指针,指向存放图像数据的内存

channels():图像的通道数,比如灰度图channels = 1

type():矩阵的数据类型,比如CV_8U,CV_8UC3等

depth():图像的深度,可以理解为矩阵中元素的一个通道的数据类型,这个值和type是相关的。例如 type为 CV_16SC2,一个2通道的16位的有符号整数。那么,depth则是CV_16S。Mat.depth()中得到的是一个 0 – 6 的数字,分别代表不同的位数:enum { CV_8U=0, CV_8S=1, CV_16U=2, CV_16S=3, CV_32S=4, CV_32F=5, CV_64F=6 }; 可见 0和1都代表8位, 2和3都代表16位,4和5代表32位,6代表64位;

rows:图像矩阵的行数

cols:图像矩阵的列数

step:每行的字节数

elemSize:每个像素的大小,对于short型三通道矩阵(CV_16SC3),elemSize = 6

ptr(int x):返回第x行的首地址

1、通过指针遍历图像

对于三通道的彩色图像,内存中前三个字节对左上角像素的三个通道值,接下来的三个字节对应第一行第二个像素(OpenCV采用BGR通道顺序)。因此可以以如下方式遍历图像:

int nl = image.rows;//行数
int nc = image.cols * image.channels();
for(int j=0;j<nl;j++)
{
//得到第j行首地址
uchar *data = image.ptr<uchar>(j);
for(int i=0;i<nc;i++)
{
data[i] = 255;//处理每一个通道值
}
}


2使用迭代器遍历图像

OpenCV为Mat提供了与STL迭代器兼容的迭代器。一个Mat实例的迭代器可以通过创建MatIterator_实例来得到。类似于Mat_,下划线表明其是一个模板类。

MatIterator_<Vec3b> it;
MatConstIterator_<Vec3b> itc;
//也可以使用定义在Mat_内部的迭代器类型
Mat_<Vec3b>::iterator it;
Mat_<Vec3b>::const_iterator itc;


然后,可以像这样遍历图像:

Mat_<Vec3b>::iterator it = image.begin<Vec3b>();
Mat_<Vec3b>::iterator itend = image.end<Vec3b>();
//遍历
for(;it != itend;++it)
{
(*it)[channel] = 255;//处理每个channel
}


*图像遍历的一些建议

图像原地处理更快

指针处理更快,但迭代器更简单

at方法适合随机存取,不适合遍历

如果要对一个像素进行N种运算,那么在一次循环内完成要比分别用N个循环,每次循环只作一种运算高效得多

图像行与行之间往往存储是不连续的,但是有些图像可以是连续的,Mat提供了一个检测图像是否连续的函数isContinuous()。当图像连通时,我们就可以把图像完全展开,看成是一行。1中的两重循环可以简化为一层。

待补充

3、简单的图像运算

图像可以以不同的方式组合。因为它们只是一般的矩阵,所以它们可以做各种矩阵运算:加、减、乘、除、转置等。

以图像相加为例,当我们需要将一些图像叠加在一起时,就需要用到图像加法。通过调用add,更准确地说是addWeighted来完成。

addWeighted(image1,0.7,image2,0.9,0,result);
//OpenCV重载了大多数算术操作符,因此上式也等价于
//result = 0.7*image1 + 0.9*image2 + 0;


图像加法只能用于两张图像大小一致的情况,对于大小不一致的情况,则需要定义感兴趣区域(ROI)。

//定义ROI为image1的大小,这样就可以用图像加法了
Mat imageROI = image(Rect(100,100,image1.cols,image1.rows);
imageROI = addWeighted(imageROI,0。5,image1,0.7,0,imageROI);
//imageROI = 0.5*imageROI + 0.7 * image1;


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: