提高OpenCV中Mat像素访问的性能

时间:2014-03-04 17:41:54

标签: c++ performance opencv image-processing profiling

我的程序中有以下代码功能

template <typename _Tp>
void lbp::OLBP_(const Mat& src, Mat& dst) {
    assert(src.rows > 3);
    dst = Mat::zeros(src.rows-2, src.cols-2, CV_8UC1);

    _Tp
        *row_m1,
        *row = (_Tp*)src.ptr<_Tp>(0),
        *row_p1 = (_Tp*)src.ptr<_Tp>(1);

    for(int i=1; i<src.rows-1; i++) {
        unsigned char *dst_row = dst.ptr<unsigned char>(i-1);
        row_m1 = row;
        row = row_p1;
        row_p1 = (_Tp*)src.ptr<_Tp>(i+1);

        for(int j=1;j<src.cols-1;j++) {
            _Tp center = row[j];
            unsigned char code = 0;
            code |= (row_m1 [j-1] > center) << 7;
            code |= (row_m1 [j]   > center) << 6;
            code |= (row_m1 [j+1] > center) << 5;
            code |= (row    [j+1] > center) << 4;
            code |= (row_p1 [j+1] > center) << 3;
            code |= (row_p1 [j]   > center) << 2;
            code |= (row_p1 [j-1] > center) << 1;
            code |= (row    [j-1] > center) << 0;
            dst_row[j-1] = code;
        }
    }
}

基本上它的作用是,src中的每个像素都会在dst中生成代码。该“代码”是二进制数,其中8位中的每一位对应于8个像素的邻居中的每一个,如果邻居大于中心的像素,则为1,否则为0。 (参见维基百科中的Local Binary Patterns

代码工作正常,并且会被调用很多次。运行一个分析器我发现大部分执行时间花在这个特定的函数上,特别是在我访问像素值的行上:

//The code is templated but it should compile to something similar to this
unsigned char *pointer = src.ptr<unsigned char>(row); // THIS CONSUMES MOST OF THE TIME!
pointer[column]; // get the actual pixel value

像素的访问方式还有改进的余地吗? 我对这样的场景特别感兴趣,其中函数需要随机访问图像而不是连续的情况。

1 个答案:

答案 0 :(得分:1)

事实上,。将数据写入Mat::ptr图像时,您可以避免调用dst

...
for(int i=1; i<src.rows-1; i++) {
  unsigned char *dst_row = dst.ptr<unsigned char>(i-1); << THIS CAN BE AVOIDED      
...

您可以在创建数据缓冲区之后简单地初始化指向数据缓冲区的指针,然后在不调用dst的情况下填充它,即:

ptr

如果dst = Mat::zeros(src.rows-2, src.cols-2, CV_8UC1); unsigned char *dst_data = dst.data; int pix_ctr = 0; // .. and then, inside the `for` loop, after calculating the LBP code. dst_data[pix_ctr++] = code; 中存储的数据连续,则可以 (在这种情况下,您知道它,因为您刚刚通过调用{{}来初始化它1}})。您可以致电dst来查看。

(事实上,如果Mat::zeros中的输入数据是连续的,你可以摆脱循环中的{strong>全部 dst.isContinuous()。在这种情况下,推进你的像素指针没有Mat::ptr使用图片尺寸。)