OpenCV学习笔记二:操作像素

    xiaoxiao2021-03-25  122

    一、存取像素值

    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 = 1type():矩阵的数据类型,比如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 = 6ptr(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,05,image1,0.7,0,imageROI); //imageROI = 0.5*imageROI + 0.7 * image1;

    转载请注明原文地址: https://ju.6miu.com/read-5193.html

    最新回复(0)