Faster algorithm to change Hue/Saturation/Lightness in a bitmap

这一生的挚爱 提交于 2019-12-18 18:26:11

问题


I am trying to filter a Bitmap image to increase or decrease Hue, Saturation, and Lightness values.

My code is working perfectly, but it is slow.

I am locking two bitmaps in memory, the original source and the current destination. The user can move various trackbar controls to modify each value which is then converted to an HSL value. For example, the values on the trackbar correspond to a range of -1.0 to 1.0.

Each time an event is thrown that the trackbar value changed, I run a function which locks the destination bitmap and applies the HSL values with the source bitmap and then stores the result in the destination bitmap. Once finished, I unlock the destination bitmap and paint the image on the screen.

Previously I used a lookup table for my other filters since I was doing per-byte operations. However I do not know how to apply that using HSL instead. Here is the code I am using:

byte red, green, blue;

for (int i = 0; i < sourceBytes.Length; i += 3)
{
    blue = sourceBytes[i];
    green = sourceBytes[i + 1];
    red = sourceBytes[i + 2];

    Color newColor = Color.FromArgb(red, green, blue);

    if (ModifyHue)
        newColor = HSL.ModifyHue(newColor, Hue);

    if (ModifySaturation)
        newColor = HSL.ModifySaturation(newColor, Saturation);

    if (ModifyLightness)
        newColor = HSL.ModifyBrightness(newColor, Lightness);

    destBytes[i] = newColor.B;
    destBytes[i + 1] = newColor.G;
    destBytes[i + 2] = newColor.R;
}

And here's my ModifyBrightness function:

public static Color ModifyBrightness(Color color, double brightness)
{
    HSL hsl = FromRGB(color);
    hsl.L *= brightness;
    return hsl.ToRGB();
}

So basically if their brightness slider is in the very middle, its value will be 0 which I will convert to "1.0" when I pass it in to the function, so it multiplies the brightness by 1.0 which means it won't change. If they drag the slider all the way to the right it will have a value of 100 which will result in a modifier of 2.0, so I'll multiply the lightness value by 2.0 to double it.


回答1:


I ended up researching ImageAttributes and ColorMatrix and found the performance was excellent.

Here is how I implemented it for a Saturation and Brightness filter:

// Luminance vector for linear RGB
const float rwgt = 0.3086f;
const float gwgt = 0.6094f;
const float bwgt = 0.0820f;

private ImageAttributes imageAttributes = new ImageAttributes();
private ColorMatrix colorMatrix = new ColorMatrix();
private float saturation = 1.0f;
private float brightness = 1.0f;

protected override void OnPaint(object sender, PaintEventArgs e)
{
    base.OnPaint(sender, e);

    e.Graphics.DrawImage(_bitmap, BitmapRect, BitmapRect.X, BitmapRect.Y, BitmapRect.Width, BitmapRect.Height, GraphicsUnit.Pixel, imageAttributes);
}

private void saturationTrackBar_ValueChanged(object sender, EventArgs e)
{
    saturation = 1f - (saturationTrackBar.Value / 100f);

    float baseSat = 1.0f - saturation;

    colorMatrix[0, 0] = baseSat * rwgt + saturation;
    colorMatrix[0, 1] = baseSat * rwgt;
    colorMatrix[0, 2] = baseSat * rwgt;
    colorMatrix[1, 0] = baseSat * gwgt;
    colorMatrix[1, 1] = baseSat * gwgt + saturation;
    colorMatrix[1, 2] = baseSat * gwgt;
    colorMatrix[2, 0] = baseSat * bwgt;
    colorMatrix[2, 1] = baseSat * bwgt;
    colorMatrix[2, 2] = baseSat * bwgt + saturation;

    imageAttributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);

    Invalidate();
}

private void brightnessTrackBar_ValueChanged(object sender, EventArgs e)
{
    brightness = 1f + (brightnessTrackBar.Value / 100f);

    float adjustedBrightness = brightness - 1f;

    colorMatrix[4, 0] = adjustedBrightness;
    colorMatrix[4, 1] = adjustedBrightness;
    colorMatrix[4, 2] = adjustedBrightness;

    imageAttributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);

    Invalidate();
}



回答2:


You need to profile you app and see where problems are.

Random suggestions:

  • use 32 bit-per-pixel format to avoid unaligned reads. (and read whole 32 as single operation)
  • avoid multiple RGB <-> HSL conversions


来源:https://stackoverflow.com/questions/14364716/faster-algorithm-to-change-hue-saturation-lightness-in-a-bitmap

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