Android图像处理算法性能



我已经创建了一个方法来执行一个标签边缘检测。我使用Camera yuv字节数组来执行检测。现在我的问题是我只能得到5帧左右的效果,这真的很低。我知道它可以更快完成,因为市场上有其他应用能够以高质量的fps完成它。我传递800x400分辨率的图像。谁能检查一下我的算法是否可以更短或更高效?我已经把算法放在本机代码中,但fps似乎没有区别。

public void process() {
        progress=0;
        index = 0;
        // calculate size
        // pixel index
        size = width*(height-2) - 2;
        // pixel loop
        while (size>0)
        {
            // get Y matrix values from YUV
            ay = input[index];
            by = input[index+1];
            cy = input[index+2];
            gy = input[index+doubleWidth];
            hy = input[index+doubleWidth+1];
            iy = input[index+doubleWidth+2];
            // get X matrix values from YUV
            ax = input[index];
            cx = input[index+2];
            dx = input[index+width];
            fx = input[index+width+2];
            gx = input[index+doubleWidth];
            ix = input[index+doubleWidth+2];
            //  1  2  1
            //  0  0  0
            // -1 -2 -1
            sumy = ay + (by*2) + cy - gy - (2*hy) - iy;
            // -1  0  1
            // -2  0  2
            // -1  0  1  
            sumx = -ax + cx -(2*dx) + (2*fx) - gx + ix;
            total[index] =  (int) Math.sqrt(sumx*sumx+sumy*sumy);
           // Math.atan2(sumx,sumy);
            if(max < total[index])
                max = total[index];
          //  sum = - a -(2*b) - c + g + (2*h) + i;
            if (total[index] <0) 
                total[index] = 0;
            // clamp to 255
            if (total[index] >255) 
                total[index] = 0;
            sum = (int) (total[index]);
            output[index] = 0xff000000 | (sum << 16) | (sum << 8) | sum;
            size--;
            // next
            index++;
        }
        //ratio = max/255;
}

提前感谢!问候

我有两件事:

  1. 我会考虑失去Math.sqrt()表达式:如果你只对边缘检测感兴趣,我看不需要这个,因为SQRT函数是单调的,而且非常昂贵计算。
  2. 我会考虑另一种算法,特别是我有一个分离的卷积过滤器的良好结果:http://www.songho.ca/dsp/convolution/convolution.html#separable_convolution,因为这可能会降低算术浮点操作的数量(这可能是你的瓶颈)。

我希望这有助于,或者至少激发一些灵感。好运。

  • 如果你是实时使用你的算法,少调用一次,也许每~20帧而不是每帧调用一次。
  • 每次迭代做更多的工作,800x400在你的算法中是318,398次迭代。每次迭代都以随机的方式(对处理器)从输入数组中提取数据,这会导致缓存问题。尝试拉出ay, ay2, by, by2, cy, cy2,并在每个循环中进行两次计算,您会注意到下一次迭代中的变量将与前一次迭代相关。ay现在是ay2等等…

这是你的算法的重写,每次迭代做两倍的工作。它节省了一些冗余内存访问,并且忽略了另一个答案中提到的平方根。

public void process() {
    progress=0;
    index = 0;
    // calculate size
    // pixel index
    size = width*(height-2) - 2;
    // do FIRST iteration outside of loop
        // grab input avoid redundant memory accesses
        ay = ax = input[index];
        by = ay2 = ax2 = input[index+1];
        cy = by2 = cx = input[index+2];
        cy2 = cx2 = input[index+3];
        gy = gx = input[index+doubleWidth];
        hy = gy2 = gx2 = input[index+doubleWidth+1];
        iy = hy2 = ix = input[index+doubleWidth+2];
        iy2 = ix2 = input[index+doubleWidth+3];
        dx = input[index+width];
        dx2 = input[index+width+1];
        fx = input[index+width+2];
        fx2 = input[index+width+3];
        //
        sumy = ay + (by*2) + cy - gy - (2*hy) - iy;
        sumy2 = ay2 + (by2*2) + cy2 - gy2 - (2*hy2) - iy2;
        sumx = -ax + cx -(2*dx) + (2*fx) - gx + ix;
        sumx2 = -ax2 + cx2 -(2*dx2) + (2*fx2) - gx2 + ix2;
        // ignore the square root
        total[index] = fastSqrt(sumx*sumx+sumy*sumy);
        total[index+1] = fastSqrt(sumx2*sumx2+sumy2*sumy2);
        max = Math.max(max, Math.max(total[index], total[index+1]));
        // skip the test for negative value it can never happen
        if(total[index] > 255) total[index] = 0;
        if(total[index+1] > 255) total[index+1] = 0;
        sum = (int) (total[index]);
        sum2 = (int) (total[index+1]);
        output[index] = 0xff000000 | (sum << 16) | (sum << 8) | sum;
        output[index+1] = 0xff000000 | (sum2 << 16) | (sum2 << 8) | sum2;
        size -= 2;
        index += 2;
    while (size>0)
    {
        // grab input avoid redundant memory accesses
        ay = ax = cy;
        by = ay2 = ax2 = cy2;
        cy = by2 = cs = input[index+2];
        cy2 = cx2 = input[index+3];
        gy = gx = iy;
        hy = gy2 = gx2 = iy2;
        iy = hy2 = ix = input[index+doubleWidth+2];
        iy2 = ix2 = input[index+doubleWidth+3];
        dx = fx;
        dx2 = fx2;
        fx = input[index+width+2];
        fx2 = input[index+width+3];
        //
        sumy = ay + (by*2) + cy - gy - (2*hy) - iy;
        sumy2 = ay2 + (by2*2) + cy2 - gy2 - (2*hy2) - iy2;
        sumx = -ax + cx -(2*dx) + (2*fx) - gx + ix;
        sumx2 = -ax2 + cx2 -(2*dx2) + (2*fx2) - gx2 + ix2;
        // ignore the square root
        total[index] = fastSqrt(sumx*sumx+sumy*sumy);
        total[index+1] = fastSqrt(sumx2*sumx2+sumy2*sumy2);
        max = Math.max(max, Math.max(total[index], total[index+1]));
        // skip the test for negative value it can never happen
        if(total[index] >= 65536) total[index] = 0;
        if(total[index+1] >= 65536) total[index+1] = 0;
        sum = (int) (total[index]);
        sum2 = (int) (total[index+1]);
        output[index] = 0xff000000 | (sum << 16) | (sum << 8) | sum;
        output[index+1] = 0xff000000 | (sum2 << 16) | (sum2 << 8) | sum2;
        size -= 2;
        index += 2;
    }
}
// some faster integer only implementation of square root.
public static int fastSqrt(int x) {
}

请注意,上面的代码没有经过测试,它是在浏览器窗口内编写的,可能包含语法错误。

EDIT您可以尝试使用快速整数平方根函数来避免Math.sqrt。http://atoms.alife.co.uk/sqrt/index.html

最新更新