opencv中访问图像像素方式
2015-03-20 22:37
169 查看
opencv中图像是存储在Mat类的对象中,Mat称为基本图像容器。图像矩阵的大小取决于图像的大小和所使用的颜色模型,确切的说应该是图像的通道数。对于灰度图像只有一个通道,彩色图像则会有多个通道。对于多通道图像来说,矩阵中会有多个子列,其子列的个数等于图像的通道数。
注意,在opencv中子列的通道顺序是反过来的:BGR而不是RGB。如果内存足够大,图像就能够实现连续存储,各行连接起来组成一个长行,有助于提升图像的扫描速度。在opencv中可以利用函数iscontinuous()来判断图像是否连续存储。
下面主要总结访问图像像素的不同方法。
1、高效的方法(efficient way)
效率最高的访问方式是经典的C风格运算符[](指针)。程序示例如下:
另外,也可以使用data来实现遍历。data会从Mat中返回指向第一行第一列的指针。若这个指针为空,说明没有数据,常用来检验图像是否读入。当图像是连续存储的时候,可以直接使用data来遍历整幅图像。对于一幅灰度图像,具体实现过程如下:
2、使用迭代器访问图像中的像素
迭代器是一种更为安全的图像像素访问方法,在利用迭代器访问图像的像素时只需要获得图像矩阵的begin和end,然后增加迭代直至从begin到end。将*操作符添加在迭代指针的前面,即可获得当前指针指向的内容。具体实现如下:
3.通过动态的获取图像像素的地址来遍历图像
这种方法一般不推荐用来对图像进行扫描,它本来是用于获取或者改变图像中随机像素的值。基本方法是要首先确定你所访问图像像素的行和列,同时确定图像像素的数据类型。主要使用at()函数实现,下面是访问一个灰度图像的代码示例:
4、核心函数LUT
opencv提供了一个函数LUT来实现批量图像元素查找和更改操作图像的方法。图像处理中,最常见的操作是将某个给定的值替换成其它值,opencv提供的LUT函数直接实现该类操作,不需要自己扫描图像。示例如下:
首先建立一个mat型查找表:
效率对比:使用opencv的内置函数,调用LUT函数可以获得更快的速度,是因为opencv内部可以通过英特尔线程构架启用多线程。采用指针的算法来扫描图像,迭代法是一个不错的选择,不过效率较低。在debug模式下,动态访问是最浪费资源的一种扫描方式,在release模式下它和迭代法相差无几。从安全角度来说,迭代法更好。
5.opencv中计算程序运行的时间
在opencv中提供了两个函数:getTickCount()函数和getTickFrequency()函数;
getTickCount()函数:这个函数返回CPU自某个事件(比如电脑启动)以来走过的时钟周期数;
getTickFrequency()函数:返回CPU一秒内走过的时钟周期数。
计算一段程序运行的时间可以按照如下方式实现:
注意,在opencv中子列的通道顺序是反过来的:BGR而不是RGB。如果内存足够大,图像就能够实现连续存储,各行连接起来组成一个长行,有助于提升图像的扫描速度。在opencv中可以利用函数iscontinuous()来判断图像是否连续存储。
下面主要总结访问图像像素的不同方法。
1、高效的方法(efficient way)
效率最高的访问方式是经典的C风格运算符[](指针)。程序示例如下:
Mat& ScanImageAndReduceC(Mat& I,const uchar* const table) { 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; for( i = 0; i < nRows ; i++) { uchar* p = I.ptr<uchar>(i); for(j = 0; j < nCols ; j++) { p[j] = table[p[j]]; } } return I; }获取每一行开始出的指针,然后遍历至该行末尾。如果矩阵元素是连续方式存储的,只请求一次指针,然后一直遍历下去即可。彩色的图像需要注意:因为每个像素有三个通道,所以遍历的元素的数目也需要乘以3。
另外,也可以使用data来实现遍历。data会从Mat中返回指向第一行第一列的指针。若这个指针为空,说明没有数据,常用来检验图像是否读入。当图像是连续存储的时候,可以直接使用data来遍历整幅图像。对于一幅灰度图像,具体实现过程如下:
uchar* p = I.data; for(int i = 0; i < nCols*nRows; i++) { *p++ = table[*p];}
2、使用迭代器访问图像中的像素
迭代器是一种更为安全的图像像素访问方法,在利用迭代器访问图像的像素时只需要获得图像矩阵的begin和end,然后增加迭代直至从begin到end。将*操作符添加在迭代指针的前面,即可获得当前指针指向的内容。具体实现如下:
Mat& ScanImageAndReduceC(Mat& I,const uchar* const table) { CV_Assert(I.depth() != sizeof(uchar)); //Mat I = Mat::zeros(I.size(),CV_8UC3); const int channels = I.channels(); switch(channels) { case 1: { MatIterator_<uchar> it = I.begin<uchar>(); MatIterator_<uchar> end = I.end<uchar>(); for(;it != end; it++) *it = table[*it]; break; } case 3: { Mat_<Vec3b>::iterator 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]]; } break; } default: break; } return I; }对于彩色图像中的一行,每一列有三个uchar类型的元素,可以看做是包含uchar类型元素的一个三维的vector,在opencv中用Vec3b来表示。如果要访问第n个子列,只需要用[]来操作即可。opencv中的迭代在扫描完一行中所有的列后,会自动跳到下一行;所以说如果在彩色图像中只是用简单的uchar而不是Vec3b迭代的话,就只能获得B通道。
3.通过动态的获取图像像素的地址来遍历图像
这种方法一般不推荐用来对图像进行扫描,它本来是用于获取或者改变图像中随机像素的值。基本方法是要首先确定你所访问图像像素的行和列,同时确定图像像素的数据类型。主要使用at()函数实现,下面是访问一个灰度图像的代码示例:
Mat& ScanImageAndReduceIterator(Mat& I, const uchar* const table) { CV_Assert(I.depth() != I.channels()); 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; } default: break; } }
4、核心函数LUT
opencv提供了一个函数LUT来实现批量图像元素查找和更改操作图像的方法。图像处理中,最常见的操作是将某个给定的值替换成其它值,opencv提供的LUT函数直接实现该类操作,不需要自己扫描图像。示例如下:
首先建立一个mat型查找表:
Mat lookUpTable(1,256,CV_8U); uchar* p = lookUpTable.data; for(int i = 0; i < 256 ; i++) p[i] = table[i];然后直接调用函数(I是输入,J是输出):
LUT(I,lookUpTable ,J);
效率对比:使用opencv的内置函数,调用LUT函数可以获得更快的速度,是因为opencv内部可以通过英特尔线程构架启用多线程。采用指针的算法来扫描图像,迭代法是一个不错的选择,不过效率较低。在debug模式下,动态访问是最浪费资源的一种扫描方式,在release模式下它和迭代法相差无几。从安全角度来说,迭代法更好。
5.opencv中计算程序运行的时间
在opencv中提供了两个函数:getTickCount()函数和getTickFrequency()函数;
getTickCount()函数:这个函数返回CPU自某个事件(比如电脑启动)以来走过的时钟周期数;
getTickFrequency()函数:返回CPU一秒内走过的时钟周期数。
计算一段程序运行的时间可以按照如下方式实现:
double t = (double)getTickCount(); //deal with sth... t = ((double)getTickCount() - t)/getTickFrequency(); cout<<" Time passed in seconds:"<<t<<endl;
相关文章推荐
- OpenCV访问图像像素值的若干种方式
- opencv 使用Mat 矩阵进行图像的降采样,像素的访问方式
- OpenCV访问图像像素值的若干种方式
- opencv 访问图像像素的三种方式
- 【OpenCV学习笔记】【函数学习】二十(访问图像像素)
- 【OpenCV】访问Mat图像中每个像素的值
- OpenCV的图像像素访问[转]
- OpenCV访问图像像素的方法收集以及自己实践中得体会
- opencv OpenCV访问图像像素, 数组元素等方法收集
- 【OpenCV】访问Mat图像中每个像素的值
- python OpenCV 图像像素访问 (三)
- 【OpenCV】访问Mat图像中每个像素的值
- OpenCV 访问图像像素点
- OpenCV: cv::Mat图像像素值访问及其坐标系问题
- 【OpenCV】访问图像中每个像素的值
- 【OpenCV】访问Mat图像中每个像素的值
- 【OpenCV】访问Mat图像中每个像素的值
- opencv里常用的访问图像像素数据方法
- 【OpenCV】访问Mat图像中每个像素的值
- 访问图像像素信息方式的优化