是否可以使用单个 ColorMatrix 更改位图的色调、饱和度、亮度和透明度?

问题描述 投票:0回答:1

我希望能够通过一次位图重绘来更改色调、饱和度、亮度和透明度。我目前有这个函数(改编自这个答案:https://stackoverflow.com/a/14384449/9852011),它可以调整传递到其中的图像的饱和度、亮度和透明度,并且它可以工作。:

public static void AdjustImageAttributes(Image image, float brightness, float saturation, float transparency)
{
    //adapted from https://stackoverflow.com/a/14384449/9852011
    // Luminance vector for linear RGB
    const float rwgt = 0.3086f;
    const float gwgt = 0.6094f;
    const float bwgt = 0.0820f;

    // Create a new color matrix
    ColorMatrix colorMatrix = new ColorMatrix();

    // Adjust saturation
    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;

    // Adjust brightness
    float adjustedBrightness = brightness - 1f;
    colorMatrix[4, 0] = adjustedBrightness;
    colorMatrix[4, 1] = adjustedBrightness;
    colorMatrix[4, 2] = adjustedBrightness;

    colorMatrix[3, 3] = transparency;

    // Create image attributes
    ImageAttributes imageAttributes = new ImageAttributes();
    imageAttributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);

    // Draw the image with the new color matrix
    using (Graphics g = Graphics.FromImage(image))
    {
        g.DrawImage(image, new Rectangle(0, 0, image.Width, image.Height),
        0, 0, image.Width, image.Height,
        GraphicsUnit.Pixel, imageAttributes);
    }
}

我还在这里找到了这个函数:https://stackoverflow.com/a/37995434/9852011
它返回具有所需色调旋转的 ColorMatrix。

ColorMatrix GetHueShiftColorMax(Single hueShiftDegrees)
{
    /* Return the matrix
    
        A00  A01  A02  0  0
        A10  A11  A12  0  0
        A20  A21  A22  0  0
          0    0    0  1  0
          0    0    0  0  1
    */
    Single theta = hueShiftDegrees/360 * 2*pi; //Degrees --> Radians
    Single c = cos(theta);
    Single s = sin(theta);

    Single A00 = 0.213 + 0.787*c - 0.213*s;
    Single A01 = 0.213 - 0.213*c + 0.413*s;
    Single A02 = 0.213 - 0.213*c - 0.787*s;

    Single A10 = 0.715 - 0.715*c - 0.715*s;
    Single A11 = 0.715 + 0.285*c + 0.140*s;
    Single A12 = 0.715 - 0.715*c + 0.715*s;

    Single A20 = 0.072 - 0.072*c + 0.928*s;
    Single A21 = 0.072 - 0.072*c - 0.283*s;
    Single A22 = 0.072 + 0.928*c + 0.072*s;

    ColorMatrix cm = new ColorMatrix(
          ( A00, A01, A02,  0,  0 ),
          ( A10, A11, A12,  0,  0 ),
          ( A20, A21, A22,  0,  0 ),
          (   0,   0,   0,  0,  0 ),
          (   0,   0,   0,  0,  1 )
    )

    return cm;
}

所以现在我基本上有两个颜色矩阵。我能做的就是使用第一个函数重绘图像,然后为色调创建另一个类似的函数并再次重绘。然而,这对我来说似乎没有必要。我觉得应该有一种方法可以将 2 个矩阵合并为 1 个矩阵,并且只需一次重绘即可完成所有操作。不幸的是,这些函数中的数学超出了我的能力范围,所以我不知道从哪里开始。

c# graphics colormatrix
1个回答
0
投票

感谢@JonasH 为我指明了正确的方向。答案确实是简单地将矩阵相乘。使用这些信息,我能够创建这个类,它完全符合我的要求:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BIUK9000
{
    public class HSBTAdjuster
    {
        //Hue 0 - 360, 0 is no change
        //Saturation 1 is no change, <1 for decrease, >1 for increase
        //Brightness 1 is no change, <1 for decrease, >1 for increase
        //Transparency 1 is fully opaque, <1 for transparency
        public static Bitmap HSBTAdjustedBitmap(Bitmap bitmap, float hue, float saturation, float brightness, float transparency)
        {
            ImageAttributes imageAttributes = HSBTAdjustedImageAttributes(hue, saturation, brightness, transparency);

            Bitmap result = new Bitmap(bitmap.Width, bitmap.Height);
            using Graphics g = Graphics.FromImage(result);
            g.DrawImage(bitmap,
                new Rectangle(0,0, bitmap.Width, bitmap.Height),
                0, 0, bitmap.Width, bitmap.Height,
                GraphicsUnit.Pixel, imageAttributes);
            return result;
        }

        public static ImageAttributes HSBTAdjustedImageAttributes(float hue, float saturation, float brightness, float transparency)
        {
            ImageAttributes ia = new ImageAttributes();
            ia.SetColorMatrix(
                MultipliedColorMatrix(
                    SBTShiftedColorMatrix(saturation, brightness, transparency),
                    HueRotatedColorMatrix(hue)),
                ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
            return ia;
        }

        private static ColorMatrix MultipliedColorMatrix(ColorMatrix sbtCm, ColorMatrix hCm)
        {
            ColorMatrix result = new ColorMatrix();
            for (int i = 0; i < 5; i++)
            {
                for (int j = 0; j < 5; j++)
                {
                    result[i, j] = sbtCm[i, 0] * hCm[0, j];
                    result[i, j] += sbtCm[i, 1] * hCm[1, j];
                    result[i, j] += sbtCm[i, 2] * hCm[2, j];
                    result[i, j] += sbtCm[i, 3] * hCm[3, j];
                    result[i, j] += sbtCm[i, 4] * hCm[4, j];
                }
            }
            return result;
        }
        private static ColorMatrix SBTShiftedColorMatrix(float saturation, float brightness, float transparency)
        {
            //adapted from https://stackoverflow.com/a/14384449/9852011
            // Luminance vector for linear RGB
            const float rwgt = 0.3086f;
            const float gwgt = 0.6094f;
            const float bwgt = 0.0820f;

            // Create a new color matrix
            ColorMatrix colorMatrix = new ColorMatrix();

            // Adjust saturation
            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;

            // Adjust brightness
            float adjustedBrightness = brightness - 1f;
            colorMatrix[4, 0] = adjustedBrightness;
            colorMatrix[4, 1] = adjustedBrightness;
            colorMatrix[4, 2] = adjustedBrightness;

            colorMatrix[3, 3] = transparency;

            return colorMatrix;
        }
        private static ColorMatrix HueRotatedColorMatrix(float hueShiftDegrees)
        {
            float theta = (float)(hueShiftDegrees / 360 * 2 * Math.PI); //Degrees --> Radians
            float c = (float)Math.Cos(theta);
            float s = (float)Math.Sin(theta);

            float A00 = (float)(0.213 + 0.787 * c - 0.213 * s);
            float A01 = (float)(0.213 - 0.213 * c + 0.413 * s);
            float A02 = (float)(0.213 - 0.213 * c - 0.787 * s);

            float A10 = (float)(0.715 - 0.715 * c - 0.715 * s);
            float A11 = (float)(0.715 + 0.285 * c + 0.140 * s);
            float A12 = (float)(0.715 - 0.715 * c + 0.715 * s);

            float A20 = (float)(0.072 - 0.072 * c + 0.928 * s);
            float A21 = (float)(0.072 - 0.072 * c - 0.283 * s);
            float A22 = (float)(0.072 + 0.928 * c + 0.072 * s);

            ColorMatrix cm = new ColorMatrix();
            cm.Matrix00 = A00;
            cm.Matrix01 = A01;
            cm.Matrix02 = A02;
            cm.Matrix10 = A10;
            cm.Matrix11 = A11;
            cm.Matrix12 = A12;
            cm.Matrix20 = A20;
            cm.Matrix21 = A21;
            cm.Matrix22 = A22;
            
            cm.Matrix44 = 1;
            cm.Matrix33 = 1;
            return cm;
        }
    }
}

HSBTAdjustedBitmap
方法返回传递给它的位图,并通过传递的参数调整色调、饱和度、亮度和透明度。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.