OpenCV学习之二: 使用指针遍历图像

来源:互联网 发布:php json encode 编辑:程序博客网 时间:2024/04/23 18:14

图像矩阵是如何存储在内存之中的?

图像矩阵的大小取决于我们所用的颜色模型,确切地说,取决于所用通道数。
如果是灰度图像,矩阵就会像这样:

而对多通道图像来说,矩阵中的列会包含多个子列,其子列个数与通道数相等。
例如,RGB颜色模型的矩阵:

注意到,子列的通道顺序是反过来的:BGR而不是RGB。很多情况下,因为内存足够大,可实现连续存储,因此,图像中的各行就能一行一行地连接起来,形成一个长行。连续存储有助于提升图像扫描速度,我们可以使用 isContinuous() 来去判断矩阵是否是连续存储的. 相关示例会在接下来的内容中提供。

1.高效的方法 Efficient Way

说到性能,经典的C风格运算符[](指针)访问要更胜一筹. 因此,我们推荐的效率最高的查找表赋值方法,还是下面的这种:

Mat& ScanImageAndReduceC(Mat& I, const uchar* const table){    // 只接受8位深度的图像    CV_Assert(I.depth() != sizeof(uchar));         int channels = I.channels();//返回图像I的通道数    int nRows = I.rows * channels;      int nCols = I.cols;//图像矩阵的行数    if (I.isContinuous())//判断图像数据是否连续存放在内存中    {        nCols *= nRows;        nRows = 1;             }    int i,j;    uchar* p;     for( i = 0; i < nRows; ++i)    {        p = I.ptr<uchar>(i);  //指向I矩阵第i行的头指针        for ( j = 0; j < nCols; ++j)        {            p[j] = table[p[j]];   //p[j]表示I矩阵第i行第j列的指针                  }    }    return I; }

这里,我们获取了每一行开始处的指针,然后遍历至该行末尾。如果矩阵是以连续方式存储的,我们只需请求一次指针、然后一路遍历下去就行。彩色图像的情况有必要加以注意:因为三个通道的原因,我们需要遍历的元素数目也是3倍。

    这里有另外一种方法来实现遍历功能,就是使用 data , data会从 Mat 中返回指向矩阵第一行第一列的指针。注意如果该指针为NULL则表明对象里面无输入,所以这是一种简单的检查图像是否被成功读入的方法。当矩阵是连续存储时,我们就可以通过遍历 data 来扫描整个图像。例如,一个灰度图像,其操作如下:

uchar* p = I.data;for( unsigned int i =0; i < ncol*nrows; ++i)    *p++ = table[*p];

这回得出和前面相同的结果。但是这种方法编写的代码可读性方面差,并且进一步操作困难。同时,我发现在实际应用中,该方法的性能表现上并不明显优于前一种(因为现在大多数编译器都会对这类操作做出优化)。


0 0
原创粉丝点击