Производительность алгоритма обработки изображений Android - PullRequest
2 голосов
/ 15 декабря 2011

Я создал метод, который выполняет определение края sobel.Я использую байтовый массив Camera yuv для выполнения обнаружения.Теперь моя проблема в том, что я получаю только 5 кадров в секунду или что-то, что очень мало.Я знаю, что это можно сделать быстрее, потому что на рынке есть другие приложения, которые могут делать это с хорошей скоростью и хорошим качеством.Я передаю изображения в разрешении 800х400.Кто-нибудь может проверить, можно ли сделать мой алгоритм более коротким или более производительным?Я уже поместил алгоритм в нативный код, но, похоже, нет разницы в fps.привет

Ответы [ 2 ]

2 голосов
/ 15 декабря 2011
  • Если вы используете свой алгоритм в режиме реального времени, вызывайте его реже, возможно, каждые ~ 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) {

}

Обратите внимание, что приведенный выше код не был протестирован, он был написан внутри окна браузера и может содержать синтаксические ошибки.

РЕДАКТИРОВАТЬ Вы можете попробовать использовать функцию быстрого целочисленного квадратного корня, чтобы избежать Math.sqrt.http://atoms.alife.co.uk/sqrt/index.html

2 голосов
/ 15 декабря 2011

Итак, у меня есть две вещи:

  1. Я бы посоветовал потерять выражение Math.sqrt (): если вас интересует только обнаружение краев, я не вижу в этом необходимости, так как sqrtФункция является монотонной, и ее вычисление действительно затратно.
  2. Я бы рассмотрел другой алгоритм, особенно у меня были хорошие результаты при использовании отдельного фильтра свертки: http://www.songho.ca/dsp/convolution/convolution.html#separable_convolution, так как это могло бы снизить числоарифметические операции с плавающей точкой (что, вероятно, является вашим узким местом).

Я надеюсь, что это помогает или, по крайней мере, вызывает некоторое вдохновение.Удачи.

...