Как ускорить этот расчет - PullRequest
       3

Как ускорить этот расчет

3 голосов
/ 05 сентября 2011

Учитывая два цвета ARGB, представленные в виде целых чисел, 8 бит / канал (альфа, красный, зеленый, синий), мне нужно вычислить значение, которое представляет собой своего рода расстояние (также целое) между ними.

Итак, формула для расстояния: Delta=|R1-R2|+|G1-G2|+|B1-B2| где Rx, Gx и Bx - значения каналов цвета 1 и 2. Альфа-канал всегда игнорируется.

Мне нужноускорить этот расчет, потому что это делается много раз на медленной машине.Какой способ вычислить это «вундеркинды» в одном потоке с учетом двух целых чисел.

Пока что лучше всего, но я думаю, что это можно еще улучшить:

    //Used for color conversion from/to int
    private const int ChannelMask = 0xFF;
    private const int GreenShift = 8;
    private const int RedShift = 16;

    public int ComputeColorDelta(int color1, int color2)
    {
        int rDelta = Math.Abs(((color1 >> RedShift) & ChannelMask) - ((color2 >> RedShift) & ChannelMask));
        int gDelta = Math.Abs(((color1 >> GreenShift) & ChannelMask) - ((color2 >> GreenShift) & ChannelMask));
        int bDelta = Math.Abs((color1 & ChannelMask) - (color2 & ChannelMask));

        return rDelta + gDelta + bDelta;
    }

Ответы [ 4 ]

3 голосов
/ 05 сентября 2011

Длинный ответ:

Сколько стоит "много"

Думаю, у меня есть быстрая машина, но я написал этот небольшой сценарий:

 public static void Main() {
            var s = Stopwatch.StartNew();
            Random r = new Random();
            for (int i = 0; i < 100000000; i++) {
                int compute = ComputeColorDelta(r.Next(255), r.Next(255));
            }
            Console.WriteLine(s.ElapsedMilliseconds);
            Console.ReadLine();
        }

Ивывод: 6878

Таким образом, 7 секунд для 100 миллионов раз кажутся довольно хорошими.

Мы можем определенно ускорить это, хотя.Я изменил вашу функцию так, чтобы она выглядела следующим образом:

public static int ComputeColorDelta(int color1, int color2) {
  return 1;
}

После этого изменения получилось: 5546. Таким образом, нам удалось получить прирост производительности за 1 секунду за 100 миллионов итераций, возвращая константу.;)

Краткий ответ: эта функция не является вашим узким местом.:)

2 голосов
/ 06 сентября 2011

Я пытаюсь позволить среде выполнения производить для меня вычисления.

Прежде всего я определяю struct с явным смещением поля

[StructLayout(LayoutKind.Explicit)]
public struct Color
{
    [FieldOffset(0)] public int Raw;
    [FieldOffset(0)] public byte Blue;
    [FieldOffset(8)] public byte Green;
    [FieldOffset(16)] public byte Red;
    [FieldOffset(24)] public byte Alpha;
}

функция вычисления будет:

public int ComputeColorDeltaOptimized(Color color1, Color color2)
{
    int rDelta = Math.Abs(color1.Red - color2.Red);
    int gDelta = Math.Abs(color1.Green - color2.Green);
    int bDelta = Math.Abs(color1.Blue - color2.Blue);

    return rDelta + gDelta + bDelta;
}

И использование

public void FactMethodName2()
{
    var s = Stopwatch.StartNew();
    var color1 = new Color(); // This is a structs, so I can define they out of loop and gain some performance
    var color2 = new Color(); 
    for (int i = 0; i < 100000000; i++)
    {
        color1.Raw = i;
        color2.Raw = 100000000 - i;
        int compute = ComputeColorDeltaOptimized(color1, color2);
    }
    Console.WriteLine(s.ElapsedMilliseconds); //5393 vs 7472 of original 
    Console.ReadLine();
}
1 голос
/ 05 сентября 2011

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

Другая модификация, которая может помочь, - встроить эту функцию:то есть вместо того, чтобы вызывать его для каждой пары цветов, просто вычислите разницу напрямую внутри цикла, выполняющего этот код.Я предполагаю, что он находится в узком цикле, потому что в противном случае его стоимость была бы незначительной.

Наконец, поскольку вы, вероятно, получаете данные пикселей изображения, вы бы много сэкономили, пройдя по маршруту unsafe: makeваши растровые изображения, как это EditableBitmap , затем захватите байт * и прочитайте из него данные изображения.

0 голосов
/ 05 сентября 2011

Вы можете сделать это для уменьшения операций AND:

public int ComputeColorDelta(int color1, int color2)
{
    int rDelta = Math.Abs((((color1  >> RedShift) - (color2  >> RedShift))) & ChannelMask)));
    // same for other color channels

    return rDelta + gDelta + bDelta;
}

не много, а что-то ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...