Faster contrast algorithm for a bitmap

空扰寡人 提交于 2019-12-02 21:21:52

Depending on the machine you're running this on, your technique could be quite slow. If you're using an ARM system without an FPU, each of those operations would take quite a while. Since you're applying the same operation to every byte, a faster technique would be to create a 256-entry lookup table for the contrast level and then translate each image byte through the table. Your loop would then look like:

byte contrast_lookup[256];
double newValue = 0;
double c = (100.0 + contrast) / 100.0;

c *= c;

for (int i = 0; i < 256; i++)
{
    newValue = (double)i;
    newValue /= 255.0;
    newValue -= 0.5;
    newValue *= c;
    newValue += 0.5;
    newValue *= 255;

    if (newValue < 0)
        newValue = 0;
    if (newValue > 255)
        newValue = 255;
    contrast_lookup[i] = (byte)newValue;
}

for (int i = 0; i < sourcePixels.Length; i++)
{
    destPixels[i] = contrast_lookup[sourcePixels[i]];
}

@BitBank answers your question as asked, I wanted to add that if you're after performance you should consider your code that is getting the pixel data and setting it afterwards.

Full working code using pointers (props to @BitBank on the for loop code):

private unsafe void ApplyContrast(double contrast, Bitmap bmp)
{
    byte[] contrast_lookup = new byte[256];
    double newValue = 0;
    double c = (100.0 + contrast) / 100.0;

    c *= c;

    for (int i = 0; i < 256; i++)
    {
        newValue = (double)i;
        newValue /= 255.0;
        newValue -= 0.5;
        newValue *= c;
        newValue += 0.5;
        newValue *= 255;

        if (newValue < 0)
            newValue = 0;
        if (newValue > 255)
            newValue = 255;
        contrast_lookup[i] = (byte)newValue;
    }

    var bitmapdata = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), 
        System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

    int PixelSize = 4;

    for (int y = 0; y < bitmapdata.Height; y++)
    {
        byte* destPixels = (byte*)bitmapdata.Scan0 + (y * bitmapdata.Stride);
        for (int x = 0; x < bitmapdata.Width; x++)
        {
            destPixels[x * PixelSize] = contrast_lookup[destPixels[x * PixelSize]]; // B
            destPixels[x * PixelSize + 1] = contrast_lookup[destPixels[x * PixelSize + 1]]; // G
            destPixels[x * PixelSize + 2] = contrast_lookup[destPixels[x * PixelSize + 2]]; // R
            //destPixels[x * PixelSize + 3] = contrast_lookup[destPixels[x * PixelSize + 3]]; //A
        }
    }
    bmp.UnlockBits(bitmapdata);
}

If you're setting your image pixels data using Marshal.Copy you will find this performs better.

This should perform faster than your current code, and you also reduce the memory footprint which is good when dealing with very large images.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!