更快的算法改变色相/饱和度/亮度在一个位图

本文关键字:位图 一个 亮度 饱和度 算法 改变 | 更新日期: 2023-09-27 17:53:36

我正在尝试过滤位图图像以增加或减少色相,饱和度和亮度值。

我的代码工作得很好,但是它很慢

我正在内存中锁定两个位图,原始源和当前目的地。用户可以移动各种trackbar控件来修改每个值,然后将其转换为HSL值。例如,trackbar上的值对应于-1.0到1.0的范围。

每次触发轨迹条值发生变化的事件时,我运行一个函数,该函数锁定目标位图并将HSL值与源位图应用,然后将结果存储在目标位图中。完成后,我解锁目标位图并在屏幕上绘制图像。

以前我使用了查找表作为我的其他过滤器,因为我做的是每字节操作。然而,我不知道如何使用HSL来应用。下面是我使用的代码:

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;
}
这是我的ModifyBrightness函数:
public static Color ModifyBrightness(Color color, double brightness)
{
    HSL hsl = FromRGB(color);
    hsl.L *= brightness;
    return hsl.ToRGB();
}

所以基本上如果它们的亮度滑块在中间,它的值将是0,当我把它传递给函数时,我将把它转换为"1.0",所以它将亮度乘以1.0,这意味着它不会改变。如果他们把滑块一直拖到右边,它的值将是100,这将导致修改器为2.0,所以我将亮度值乘以2.0,使其翻倍。

更快的算法改变色相/饱和度/亮度在一个位图

我最终研究了ImageAttributes和ColorMatrix,发现它们的性能非常出色。

下面是我如何实现饱和度和亮度滤镜:

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

你需要分析你的应用程序,看看问题在哪里。

随机建议:

  • 使用32位/像素格式来避免未对齐的读取。(并读取整个32作为单次操作)
  • 避免多次RGB <-> HSL转换