简体   繁体   English

如何加快这个计算

[英]How to speed up this calculation

Given two ARGB colors represented as integers, 8 bit/channel (alpha, red, green, blue), I need to compute a value that represents a sort of distance (also integer) between them. 鉴于两个ARGB颜色表示为整数,8位/通道(alpha,红色,绿色,蓝色),我需要计算一个值,表示它们之间的一种距离(也是整数)。

So the formula for the distance is: Delta=|R1-R2|+|G1-G2|+|B1-B2| 因此距离的公式为: Delta=|R1-R2|+|G1-G2|+|B1-B2| where Rx, Gx and Bx are the values of the channles of color 1 and 2. Alpha channel is always ignored. 其中Rx,Gx和Bx是颜色1和2的通道值.Alpha通道始终被忽略。

I need to speed up this calculation because is done a lot of times on a slow machine. 我需要加快这个计算速度,因为在慢速机器上进行了很多次。 What is the 'geekies' way to calculate this on a single thread given the two integers. 在给定两个整数的情况下,在单个线程上计算这个的'geekies'方法是什么。

My best so far is but I guess this can be improved further: 到目前为止,我最好的是,但我想这可以进一步改进:

    //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;
    }

Long Answer: 答案很长:

How many is "a lot" 有多少是“很多”

I have a fast machine I guess, but I wrote this little script: 我想有一台快速的机器,但我写了这个小脚本:

 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();
        }

And the output is: 6878 输出是:6878

So 7 seconds for 100 million times seems pretty good. 所以7亿次1亿次看起来相当不错。

We can definitely speed this up though. 我们绝对可以加快速度。 I changed your function to look like this: 我改变你的功能看起来像这样:

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

With that change, the output was: 5546. So, we managed to get a 1 second performance gain over 100 million iterations by returning a constant. 随着这一变化,输出为:5546。因此,通过返回常量,我们设法获得超过1亿次迭代的1秒性能增益。 ;) ;)

Short answer: this function is not your bottleneck. 简短回答:这个功能不是你的瓶颈。 :) :)

I'm trying to let runtime to make calculation for me. 我正试图让运行时为我计算。

First of all I define struct with explicit field offset 首先,我使用显式字段偏移定义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;
}

the calculation function will be: 计算功能将是:

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;
}

And the usage 和用法

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();
}

One idea would be to use the same code you already have, but in a different order: apply the mask, take the difference, then shift. 一个想法是使用您已有的相同代码,但顺序不同:应用掩码,取差异,然后移动。

Another modification that might help is to inline this function: that is, instead of calling it for each pair of colors, just compute the difference directly, inside whatever loop executes this code. 可能有帮助的另一个修改是内联这个函数:也就是说,不是为每对颜色调用它,而是直接计算差异,在任何循环中执行此代码。 I assume it is inside a tight loop, because otherwise its cost would be negligible. 我认为它是在一个紧凑的循环内,因为否则它的成本可以忽略不计。

Lastly, since you're probably getting image pixel data, you'd save a lot by going the unsafe route: make your bitmaps like this EditableBitmap , then grab the byte* and read the image data out of it. 最后,由于您可能正在获取图像像素数据,因此通过使用unsafe路径可以节省很多:使您的位图像这个EditableBitmap ,然后获取字节*并从中读取图像数据。

You can do this in order to reduce the AND operations: 您可以这样做以减少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;
}

not much but something... 不多但是......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM