Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/heroku/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 更改位图中色调/饱和度/亮度的更快算法_C#_.net_Bitmap_Hsl - Fatal编程技术网

C# 更改位图中色调/饱和度/亮度的更快算法

C# 更改位图中色调/饱和度/亮度的更快算法,c#,.net,bitmap,hsl,C#,.net,Bitmap,Hsl,我试图过滤位图图像以增加或减少色调、饱和度和亮度值 我的代码运行得很好,但速度很慢 我在内存中锁定了两个位图,原始源和当前目标。用户可以移动各种轨迹栏控件来修改每个值,然后将其转换为HSL值。例如,轨迹栏上的值对应于-1.0到1.0的范围 每次抛出轨迹栏值更改的事件时,我都会运行一个函数,该函数锁定目标位图,并将HSL值应用于源位图,然后将结果存储在目标位图中。完成后,我解锁目标位图并在屏幕上绘制图像 以前,我对我的其他过滤器使用了查找表,因为我是在进行每字节操作。然而,我不知道如何使用HSL来

我试图过滤位图图像以增加或减少色调、饱和度和亮度值

我的代码运行得很好,但速度很慢

我在内存中锁定了两个位图,原始源和当前目标。用户可以移动各种轨迹栏控件来修改每个值,然后将其转换为HSL值。例如,轨迹栏上的值对应于-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;
}

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

您需要分析应用程序并查看问题所在

随机建议:

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

我最终研究了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();
}

我要做的第一件事是缓存结果,并使用不安全的代码更快地访问阵列。+1。有了这样的微码,阵列访问就完全毁了你。每次访问都是对最小/最大值的检查。请输入不安全的指针代码。并从字节移动到同时具有所有值的结构。你们有任何关于这方面的文档参考吗?当数组是指针时,Afaik数组语法等于指针语法,不是吗?无论如何都没有最小/最大限制。@OP如果您只需要修改HSL,您也可以将ImageAttributes与ColorMatrix一起使用,它的执行速度将比您当前的代码快得多。我对亮度、对比度、gamma、反转和灰度过滤器使用相同的精确代码结构,它们使用查找表时速度非常快。我尝试过使用指针,但实际上我注意到性能下降了。数组索引不是这里的瓶颈,而是RGB到HSL的转换。正如我在问题中所说,我想使用类似于查找表的东西,但我不知道如何将其应用于HSL,因为你不能为每个可能的双精度值创建一个查找表,它与256个不同的字节值不同。我对对比度、RGB亮度、gamma、反转等使用相同的代码,而且速度非常快。因此,RGB/HSL转换是主要的瓶颈。也许你可以详细说明我如何避免多次转换。我曾想过使用查找表,但如何使用LUT来表示双精度值?使用字节值很容易,因为只有256种可能性。@Moozhe,您的代码从最多2个无用的转换开始(如果您需要更改所有3个H/s/L)。否则-从RGB查看
代码并进行优化。在最坏的情况下,预计算表的16M整数值并不是世界末日…@AlexeiLevenkov它实际上是167M颜色*4字节=67MB,不太可行。更不用说这些值可能比图像中实际存在的值还要多,这使得LUT的生成速度比计算速度慢。@Rotem 67Mb大约相当于现代相机拍摄的一幅图像的大小,因此每个项目的内存量并非前所未闻。OP应该能够测量并查看CPU和内存在这种情况下是否适用于特定情况。我应该只将其转换为HSL一次,而不是3次。实际上,在我的测试中,我只做了亮度过滤器,速度非常慢。其他过滤器已关闭。所以我可以解决这个问题,但我仍然需要通过其他方式提高性能。有趣的是,你可以使用单个矩阵计算许多不同的效果,然后乘以矩阵来组合效果。
// 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();
}