3

我正在尝试实现图像处理功能。这里是:

typedef void (*AgFilter)(int*, int*, int*, float*);

static void filter(AndroidBitmapInfo* info, void* pixels, AgFilter func, void* params){

    for(y = 0; y < height; y++){
        for(x = 0; x < width; x++){
            //initizalie r, g, b

            func(&r, &g, &b, params); //here is the problem
        }
    }
}

我将这个函数传递为func

static inline void brightness(int *r, int *g, int *b, float* param){
    float add = param[0];

    *r += add;
    *g += add;
    *b += add;
}

问题是它的工作速度非常慢。嗯,我可以理解。但是,如果不是通过引用传递函数,而是直接在filterfunc调用的入口)内编写函数,它的工作速度会快得多。哪里有问题?

PS注意不是c++

编辑

这个工作很快:

static void filter(AndroidBitmapInfo* info, void* pixels, int add){

    for(y = 0; y < height; y++){
        for(x = 0; x < width; x++){
            //initizalie r, g, b
            r += add;
            g += add;
            b += add;
        }
    }
}
4

3 回答 3

4

我认为问题在于您将函数作为指针传递。因为亮度()没有被编译器内联。

当您将亮度()的定义复制到过滤器()函数中时,您会得到您想要的结果 - 您内联该函数。

于 2012-08-28T07:39:11.710 回答
4

调用函数需要时间。通常,您不会注意到,但您会调用该函数一百万次(对于全高清 1920x1080 图像,大约需要两百万次)。现代相机创建 16 兆像素图像。如果每次调用耗时 1 us,则调用函数(不实际执行主体)的累计时间为 16

你怎样才能让它更快?一些建议:

  1. 不要传递四个参数,而是使用结构:

     struct data { int r,g,b; float* param; }
    

    分配一次并重用它。现在您可以func使用单个参数进行调用。

  2. 内存布局可能是个问题。param在记忆中的任何地方。将其复制到struct data

     struct data { int r,g,b, add; }
    

    原因是它param在内存中的任何地方,这意味着它可能在不同的缓存行中。如果您可以将所有数据放入单个 64 字节结构中,那么所有数据都将放入单个高速缓存行中,这可以极大地提高性能。

    但可能不是你的情况,因为你总是访问param[0]. 当您以随机方式访问数组时,这更成问题。

  3. 交换移位和位掩码操作:

     r = (int) ((line[x] & >> 16 ) & 0xFF);
    

    可以稍微提升一下,因为现在所有三种颜色都将被屏蔽,0xFF并且允许编译器将常量移动一次到 CPU 寄存器。

  4. 调用函数时,需要“保存/恢复”所有 CPU 寄存器。这需要时间。当函数被内联时,编译器知道哪些 CPU 寄存器被丢弃并可以相应地优化。

    实际上,CPU 寄存器并没有被保存(至少我很久没看到了)。现代编译器只是假设在调用函数之后,它们都已被更改。

  5. 请注意,这inline没有任何效果,因为您通过引用传递函数而不是直接调用它。

  6. 使用线程。这很容易并行化:在 1/N 的数据上运行函数 N 次(每个 CPU 内核一次)。这将为您提供大约 N 倍的性能提升。

于 2012-08-28T07:45:29.513 回答
1

到目前为止,您可以做出的最大改进是避免为每个像素调用一次函数。brightness在函数内移动循环很简单。

static inline void brightness(int *r, int *g, int *b, float* param){
    float add = param[0];

    for(y = 0; y < height; y++)
        for(x = 0; x < width; x++){
            //initialize r, g, b
            *r += add;
            *g += add;
            *b += add;
        }
}

现在,我知道你不想在你可能编写的每个不同的过滤器函数中复制循环迭代代码,所以这是使用宏可以真正发挥作用的情况之一。尝试这样的事情(未经测试)。

#define FOR_EACH_PIXEL for(y = 0; y < height; y++) \
                       for(x = 0; x < width;  x++)

static inline void brightness(int *r, int *g, int *b, float* param){
    float add = param[0];

    FOR_EACH_PIXEL 
    {
            //initialize r, g, b
            *r += add;
            *g += add;
            *b += add;
    }

}
于 2012-08-28T08:41:46.097 回答