如何优化简单高斯滤波器的性能? 我正在尝试编写一个Android应用程序,需要为多个全分辨率图像计算高斯和拉普拉斯金字塔,我用NDK在C++上写了这个代码,代码的最关键部分是将高斯滤波器应用到图像ABD中,我是水平和垂直地应用这个滤波器。p>

如何优化简单高斯滤波器的性能? 我正在尝试编写一个Android应用程序,需要为多个全分辨率图像计算高斯和拉普拉斯金字塔,我用NDK在C++上写了这个代码,代码的最关键部分是将高斯滤波器应用到图像ABD中,我是水平和垂直地应用这个滤波器。p>,c++,c,performance,optimization,C++,C,Performance,Optimization,过滤器为(0.0625,0.25,0.375,0.25,0.0625) 因为我在研究整数,所以我在计算(1,4,6,4,1)/16 我做了一些简单的优化,但它仍然比预期的慢,我想知道是否有任何其他优化选项,我错过了 PS:我应该提到的是,我曾经尝试用内嵌的arm组件编写这个过滤器部件,但是它给出的结果慢了2倍 //horizontal filter for(unsigned y = 0; y < height; y++) { for(unsigned x = 2; x <

过滤器为(0.0625,0.25,0.375,0.25,0.0625) 因为我在研究整数,所以我在计算(1,4,6,4,1)/16

我做了一些简单的优化,但它仍然比预期的慢,我想知道是否有任何其他优化选项,我错过了

PS:我应该提到的是,我曾经尝试用内嵌的arm组件编写这个过滤器部件,但是它给出的结果慢了2倍

//horizontal  filter
for(unsigned y = 0; y < height;  y++) {
    for(unsigned x = 2; x < width-2;  x++) {
        int index = y*width+x;
            dst[index].r = (src[index-2].r+ src[index+2].r + (src[index-1].r + src[index+1].r)*4 + src[index].r*6)>>4;
            dst[index].g = (src[index-2].g+ src[index+2].g + (src[index-1].g + src[index+1].g)*4 + src[index].g*6)>>4;
            dst[index].b = (src[index-2].b+ src[index+2].b + (src[index-1].b + src[index+1].b)*4 + src[index].b*6)>>4;                
     }
}
//vertical filter
for(unsigned y = 2;  y < height-2;  y++) {
    for(unsigned x = 0;  x < width;  x++) {
        int index = y*width+x;
            dst[index].r = (src[index-2*width].r + src[index+2*width].r  + (src[index-width].r + src[index+width].r)*4 + src[index].r*6)>>4;
            dst[index].g = (src[index-2*width].g + src[index+2*width].g  + (src[index-width].g + src[index+width].g)*4 + src[index].g*6)>>4;
            dst[index].b = (src[index-2*width].b + src[index+2*width].b  + (src[index-width].b + src[index+width].b)*4 + src[index].b*6)>>4;
     }
}
//水平过滤器
对于(无符号y=0;y>4;
dst[index].g=(src[index-2].g+src[index+2].g+(src[index-1].g+src[index+1].g)*4+src[index.g*6)>>4;
dst[index].b=(src[index-2].b+src[index+2].b+(src[index-1].b+src[index+1].b)*4+src[index.b*6)>>4;
}
}
//垂直过滤器
for(无符号y=2;y>4;
dst[index].g=(src[index-2*width].g+src[index+2*width].g+(src[index-width].g+src[index+width].g)*4+src[index].g*6>>4;
dst[index].b=(src[index-2*width].b+src[index+2*width].b+(src[index-width].b+src[index+width].b)*4+src[index].b*6>>4;
}
}

我不确定编译器将如何优化所有这些,但我倾向于使用指针。假设您的结构是3个字节。。。您可以从正确位置的指针开始(源过滤器的边缘,目标过滤器的目标),然后使用恒定的数组偏移量将它们移动。我还在外循环中加入了一个可选的OpenMP指令,因为这也可以改善情况

#pragma omp parallel for
for(unsigned y = 0; y < height;  y++) {
    const int rowindex = y * width;
    char * dpos = (char*)&dest[rowindex+2];
    char * spos = (char*)&src[rowindex];
    const char *end = (char*)&src[rowindex+width-2];

    for( ; spos != end;  spos++, dpos++) {
        *dpos = (spos[0] + spos[4] + ((spos[1] + src[3])<<2) + spos[2]*6) >> 4;
    }
}
#pragma omp parallel for
对于(无符号y=0;y
对于垂直循环也是如此

const int scanwidth = width * 3;
const int row1 = scanwidth;
const int row2 = row1+scanwidth;
const int row3 = row2+scanwidth;
const int row4 = row3+scanwidth;

#pragma omp parallel for
for(unsigned y = 2;  y < height-2;  y++) {
    const int rowindex = y * width;
    char * dpos = (char*)&dest[rowindex];
    char * spos = (char*)&src[rowindex-row2];
    const char *end = spos + scanwidth;

    for( ; spos != end;  spos++, dpos++) {
        *dpos = (spos[0] + spos[row4] + ((spos[row1] + src[row3])<<2) + spos[row2]*6) >> 4;
    }
}
const int scanwidth=width*3;
const int row1=扫描宽度;
const int row2=行1+扫描宽度;
const int row3=第2行+扫描宽度;
const int row4=第3行+扫描宽度;
#pragma-omp并行
for(无符号y=2;y
不管怎样,这就是我做卷积的方式。它牺牲了一点可读性,而且我从来没有尝试过测量差异。我只是从一开始就倾向于这样写。看看这是否会给你一个加速。如果你有一台多核机器,OpenMP肯定会,指针的东西可能会


我喜欢关于将SSE用于这些操作的评论。

我不确定编译器将如何优化所有这些操作,但我倾向于使用指针。假设您的结构是3个字节……您可以从正确位置的指针开始(源过滤器的边缘,目标的目标),并使用恒定的数组偏移量将它们移动。我还在外部循环中加入了可选的OpenMP指令,因为这也可以改善情况

#pragma omp parallel for
for(unsigned y = 0; y < height;  y++) {
    const int rowindex = y * width;
    char * dpos = (char*)&dest[rowindex+2];
    char * spos = (char*)&src[rowindex];
    const char *end = (char*)&src[rowindex+width-2];

    for( ; spos != end;  spos++, dpos++) {
        *dpos = (spos[0] + spos[4] + ((spos[1] + src[3])<<2) + spos[2]*6) >> 4;
    }
}
#pragma omp parallel for
对于(无符号y=0;y
对于垂直循环也是如此

const int scanwidth = width * 3;
const int row1 = scanwidth;
const int row2 = row1+scanwidth;
const int row3 = row2+scanwidth;
const int row4 = row3+scanwidth;

#pragma omp parallel for
for(unsigned y = 2;  y < height-2;  y++) {
    const int rowindex = y * width;
    char * dpos = (char*)&dest[rowindex];
    char * spos = (char*)&src[rowindex-row2];
    const char *end = spos + scanwidth;

    for( ; spos != end;  spos++, dpos++) {
        *dpos = (spos[0] + spos[row4] + ((spos[row1] + src[row3])<<2) + spos[row2]*6) >> 4;
    }
}
const int scanwidth=width*3;
const int row1=扫描宽度;
const int row2=行1+扫描宽度;
const int row3=第2行+扫描宽度;
const int row4=第3行+扫描宽度;
#pragma-omp并行
for(无符号y=2;y
不管怎样,这就是我做卷积的方式。它牺牲了一点可读性,而且我从来没有尝试过测量差异。我只是从一开始就倾向于这样写。看看这是否会给你一个加速。如果你有一台多核机器,OpenMP肯定会,指针的东西可能会


我喜欢关于使用SSE进行这些操作的评论。

可以将
索引
乘法从内部循环中分解出来,因为只有在
y
发生更改时才会发生乘法:

for (unsigned y ...
{
    int index = y * width;
    for (unsigned int x...  
通过在使用变量之前加载变量,可以获得一定的速度。这将使处理器在缓存中加载变量:

for (unsigned x = ...  
{  
    register YOUR_DATA_TYPE a, b, c, d, e;
    a = src[index - 2].r;
    b = src[index - 1].r;
    c = src[index + 0].r; // The " + 0" is to show a pattern.
    d = src[index + 1].r;
    e = src[index + 2].r;
    dest[index].r = (a + e + (b + d) * 4 + c * 6) >> 4;
    // ...  
另一个技巧是“缓存”src的值,以便每次只添加一个新值,因为
src[index+2]
中的值最多可使用5次

下面是一个概念示例:

//horizontal  filter
for(unsigned y = 0; y < height;  y++)
{
    int index = y*width + 2;
    register YOUR_DATA_TYPE a, b, c, d, e;
    a = src[index - 2].r;
    b = src[index - 1].r;
    c = src[index + 0].r; // The " + 0" is to show a pattern.
    d = src[index + 1].r;
    e = src[index + 2].r;
    for(unsigned x = 2; x < width-2;  x++)
    {
        dest[index - 2 + x].r = (a + e + (b + d) * 4 + c * 6) >> 4;
        a = b;
        b = c;
        c = d;
        d = e;
        e = src[index + x].r;
//水平过滤器
对于(无符号y=0;ya=  0x[0011][0034]  <-- split to two 
b=  0x[0031][008a]
----------------------
sum    0042  00b0
>>4    0004  200b0  <-- mask off
mask   00ff  00ff   
-------------------
       0004  000b   <-- result 
#define MASK (255+(255<<10)+(255<<20))
#define KERNEL(a,b,c,d,e) { \
 a=((a+e+(c<<1))>>2) & MASK; a=(a+b+c+d)>>2 & MASK; *DATA++ = a; a=DATA[4]; }

void calc_5_rgbs(unsigned int *DATA)
{
   register unsigned int a = DATA[0], b=DATA[1], c=DATA[2], d=DATA[3], e=DATA[4];
   KERNEL(a,b,c,d,e);
   KERNEL(b,c,d,e,a);
   KERNEL(c,d,e,a,b);
   KERNEL(d,e,a,b,c);
   KERNEL(e,a,b,c,d);
}
 unsigned char *s=(unsigned char *) source_array; 
 unsigned char *d=(unsigned char *) dest_array; 
 for (j=0;j<3*N;j++) d[j]=(s[j]+s[j+16]+s[j+8]*6+s[j+4]*4+s[j+12]*4)>>4;