如何使用滑块控件调整位图的亮度?

How to use a slider control to adjust the brightness of a Bitmap?

我正在尝试调整 RGB 值以使我的图像处理器项目中的图片变暗或变亮。最好在一个 TrackBar 控件上结合变暗和变亮,当滑块在中间设置为 0 时,中性的、不变的图像。
但是,我目前仍在尝试弄清楚如何在一个 TrackBar 上只执行一项功能,例如变暗。

将 TrackBar 控件 (Min 0, Max 10) 放入我的项目后,我使用 trackbar_scroll 事件检测 TrackBar 何时滚动。
我还对其进行了编码,通过从图像每个像素的 RGB 中减去某个字节值来使图像变暗。
当您向右滑动滚动条时,滚动条成功地使图像变暗,但是当您将 TrackBar 向左滑动回到其原始位置时,我也想取消它的变暗。

private void trbBrightness_Scroll(object sender, EventArgs e)
{
    if (bitmapImage == null) return; 

    Byte Red, Green, Blue;
    int iWidth = 320;
    int iHeight = 240;

    for (int i = 0; i < iWidth; i++)
    {
        for (int j = 0; j < iHeight; j++)
        {
            Color pixel = ImageArray[i, j];

            Red = pixel.R;
            Green = pixel.G;
            Blue = pixel.B;

            Color newColor = 
                Color.FromArgb(255, 
                               Red - Convert.ToByte(Red * (trbBrightness.Value * 0.1)), 
                               Green - Convert.ToByte(Green * (trbBrightness.Value * 0.1)), 
                               Blue - Convert.ToByte(Blue * (trbBrightness.Value * 0.1)));
            ImageArray[i, j] = newColor;

现在它只是像我想要的那样使图像变暗,但是我希望,当向左滑动时,滑块向右滑动时基本上可以取消变暗。

有没有办法检测滑块的值何时增加,执行此操作,以及滑块值何时减少,执行此操作?
我假设我必须以某种方式存储旧的 trackbar 值,以便我可以将它与新的进行比较?


我在哪里可以得到:

if (trackbar value is increasing) 
{

} 
else if (trackbar value is decreasing)
{

}

您只需要保证原始位图的安全并在调整值时应用 ColorMatrix to the original bitmap ImageAttributes
当然,您不能调整已经调整过的内容,否则,您将永远无法恢复到源位图的原始 Brightness/Contrast 值。
将新值设置为原始位图,然后仅显示结果,保留原始值。

对比度组件的设置范围为 -1.00f2.00f
当对比度值低于 0 时,您正在反转颜色以制作 负片 图像。您需要决定是否允许这种行为。否则,您可以将对比度限制为最小 0.00f:应用于所有颜色分量,生成灰色 blob(完全没有对比度)。

亮度组件的值可以设置在-1.00f+1.00f的范围内。上面和下面你有全白和全黑的结果。

使用恒等矩阵作为参考:

C = Contrast = 1 : B = Brightness = 0

    C, 0, 0, 0, 0        1, 0, 0, 0, 0
    0, C, 0, 0, 0        0, 1, 0, 0, 0
    0, 0, C, 0, 0        0, 0, 1, 0, 0
    0, 0, 0, 1, 0        0, 0, 0, 1, 0
    B, B, B, 1, 1        0, 0, 0, 1, 1

(如果你习惯了Matrix的math定义或者其他平台定义它的方式,你可能会认为这是错误的。这只是ColorMatrix的定义方式在.Net/GDI 方言).

调整位图亮度和对比度所需的代码示例,使用 ColorMatrix 和标准 PictureBox 控件来显示结果。

样本结果:

程序:
将 Image 分配给 PictureBox 控件,然后将相同的 Image 分配给 Bitmap 对象,这里是一个名为 adjustBitmap:

的字段
Bitmap adjustBitmap = null; 

在某处(Form.Load(),也许),将图像分配给 PicureBox,并将同一图像的副本分配给 adjustBitmap 字段,这将保留原始图像颜色值。
注意Dispose()adjustBitmap对象当Form关闭(Form.FormClosed)事件。

添加 2 个 TrackBar 控件,一个用于调整亮度,一个用于对比度(名为 trkContrasttrkBrightness 这里).

亮度 轨迹栏将具有:Minimum = -100, Maximum = 100, Value = 0
对比度 轨迹栏将具有:Minimum = -100, Maximum = 200, Value = 100

订阅并分配给 Scroll 事件的同一事件处理程序。
处理程序代码调用负责调整位图亮度和对比度的方法,使用 2 个 TrackBar 控件的当前值和原始位图的引用:

// Somewhere... assign the Bitmap to be altered to the Field
adjustBitmap = [Some Bitmap];
// Use a copy of the above as the PictureBox image
pictureBox1.Image = [A copy of the above];

private void trackBar_Scroll(object sender, EventArgs e)
{
    pictureBox1.Image?.Dispose();
    pictureBox1.Image = AdjustBrightnessContrast(adjustBitmap, trkContrast.Value, trkBrightness.Value);
}

主要方法将 TrackBars 的 int 值转换为前面描述的范围内的浮点数,然后分配给矩阵数组:
新的 ColorMatrix 被分配给一个 ImageAttribute class,它在Graphics.DrawImage 接受 ImageAttribute.

的方法重载
using System.Drawing;
using System.Drawing.Imaging;

public Bitmap AdjustBrightnessContrast(Image image, int contrastValue, int brightnessValue)
{
    float brightness = -(brightnessValue / 100.0f);
    float contrast = contrastValue / 100.0f;
    var bitmap = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppArgb));

    using (var g = Graphics.FromImage(bitmap))
    using (var attributes = new ImageAttributes())
    {
        float[][] matrix = {
            new float[] { contrast, 0, 0, 0, 0},
            new float[] {0, contrast, 0, 0, 0},
            new float[] {0, 0, contrast, 0, 0},
            new float[] {0, 0, 0, 1, 0},
            new float[] {brightness, brightness, brightness, 1, 1}
        };

        ColorMatrix colorMatrix = new ColorMatrix(matrix);
        attributes.SetColorMatrix(colorMatrix);
        g.DrawImage(image, new Rectangle(0, 0, bitmap.Width, bitmap.Height),
            0, 0, bitmap.Width, bitmap.Height, GraphicsUnit.Pixel, attributes);
        return bitmap;
    }
}