提高OpenCV中Mat像素访问性能

3
我在我的程序中有以下代码函数:

我有以下程序中的代码函数

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。(请参阅维基百科中的局部二值模式)。该代码可以正常工作,并且将被调用非常多次。运行分析器后,我发现大部分执行时间都花费在这个特定函数上,特别是在访问像素值的行上:
//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

像素访问的方式有改进的空间吗? 我特别关注这样的情况,其中函数需要对图像进行随机访问,而不是顺序访问。


ptr<>可能不是最有效的像素访问方式,但它是相当有效的。而且每行只调用一次。极不可能它会消耗任何值得注意的运行时间。更有可能的是分析器正在归咎于错误的行。 - user2983637
1个回答

1
事实上,是的。在向dst图像写入数据时,您可以避免调用Mat::ptr:
...
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;

这只有在存储在 dst 中的数据是连续的情况下才可能发生(在这种情况下,您之前调用了 Mat::zeros 进行初始化,因此您知道它是连续的)。您可以通过调用 dst.isContinuous() 来检查它。
(实际上,如果 src 中的输入数据是连续的,则可以在循环内部摆脱所有的 Mat::ptr。在这种情况下,通过使用图像尺寸来推进像素指针而不需要使用 ptr。)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接