You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中使用颜色矩阵实时重绘高清图像的亮度异常问题

颜色矩阵实时重绘图像的亮度问题

我正在做一个运行时实时重绘高清图像、延迟极低的类,最终选了颜色矩阵方案——因为逐像素查找表的颜色替换方法既受限又计算成本太高。拼了多篇资料的代码,但现在效果拉胯:色调转换看起来正常,但重绘后的图像总是褪色、亮度被压缩,靠肉眼根本找不到问题根源,调试起来头大。

以下是我的Recolorer类代码:

public class Recolorer
{    
    const float LumR = 0.2126f;
    const float LumG = 0.7152f;
    const float LumB = 0.0722f;
    
    public bool UseSat = true;
    public bool UseLum = false;
    public bool UseBri = true;
    
    public Bitmap Recolor(Bitmap bm, Color BaseColor, Color NewColor)
    {
        float r = 1;
        float d = 0;
        d = BrightnessDelta(BaseColor, NewColor);
        
        float[][] H = HueMatrix(NewColor, BaseColor.GetHue());
        float[][] S = SaturationMatrix(NewColor);
        float[][] L = LuminosityMatrix();
        float[][] B = LightnessMatrix(r, d);
        float[][] T = H;
        if (UseSat)
            T = Multiply(S, T);
        if (UseLum)
            T = Multiply(L, T);
        if (UseBri)
            T = Multiply(B, T);
        
        ColorMatrix cm = new ColorMatrix(T);
        ImageAttributes ia = new ImageAttributes();
        ia.SetColorMatrix(cm);
        Rectangle rect = new Rectangle(0, 0, bm.Width, bm.Height);
        Bitmap temp = new Bitmap(bm.Width, bm.Height);
        Graphics g = Graphics.FromImage(temp);
        g.DrawImage(bm, rect, 0, 0, bm.Width, bm.Height, GraphicsUnit.Pixel, ia);
        return temp;
    }
    
    public float[][] LuminosityMatrix(float B = 1f)
    {
        return new float[][] {
            new float[] {LumR * B, LumR * B, LumR * B, 0, 0},
            new float[] {LumG * B, LumG * B, LumG * B, 0, 0},
            new float[] {LumB * B, LumB * B, LumB * B, 0, 0},
            new float[] {0, 0, 0, 1, 0},
            new float[] {0, 0, 0, 0, 1}
        };
    }
    
    public float[][] SaturationMatrix(Color c)
    {
        float s = c.GetSaturation();
        float sr = (1f - s) * LumR;
        float sg = (1f - s) * LumG;
        float sb = (1f - s) * LumB;
        
        return new float[][] {
            new float[] {sr+s, sr, sr, 0, 0},
            new float[] {sg, sg+s, sg, 0, 0},
            new float[] {sb, sb, sb+s, 0, 0},
            new float[] {0, 0, 0, 1, 0},
            new float[] {0, 0, 0, 0, 1}
        };
    }
    
    public float[][] HueMatrix(Color c, float x = 0)
    {
        float angle = c.GetHue() - x;
        angle /= 180f;
        float cos = (float)Math.Cos(angle * Math.PI);
        float sin = (float)Math.Sin(angle * Math.PI);
        
        float A00 = LumR + (1 - LumR) * cos - LumR * sin;
        float A01 = LumR - LumR * cos + 0.413f * sin;
        float A02 = LumR - LumR * cos - (1 - LumR) * sin;
        
        float A10 = LumG - LumG * cos - LumG * sin;
        float A11 = LumG + (1 - LumG) * cos + 0.140f * sin;
        float A12 = LumG - LumG * cos + LumG * sin;
        
        float A20 = LumB - LumB * cos + (1 - LumB) * sin;
        float A21 = LumB - LumB * cos - 0.283f * sin;
        float A22 = LumB + (1 - LumB) * cos + LumB * sin;
        
        return new float[][] {
            new float[] { A00, A01, A02,  0,  0 },
            new float[] { A10, A11, A12,  0,  0 },
            new float[] { A20, A21, A22,  0,  0 },
            new float[] {   0,   0,   0,  1,  0 },
            new float[] {   0,   0,   0,  0,  1 }
        };
    }
    
    public float GetBrightness(Color c)
    {
        return (((float)c.R * LumR / 255f) + ((float)c.G * LumG / 255f) + ((float)c.B * LumB / 255f));
    }
    
    public float BrightnessRatio(Color From, Color To)
    {
        return (GetBrightness(To) / GetBrightness(From));
    }
    
    public float BrightnessDelta(Color From, Color To)
    {
        return ((GetBrightness(To) - GetBrightness(From)) / 2f);
    }
    
    public float[][] LightnessMatrix(float f = 1, float l = 0)
    {
        return new float[][] {
            new float[] { f, 0, 0, 0, 0 },
            new float[] { 0, f, 0, 0, 0 },
            new float[] { 0, 0, f, 0, 0 },
            new float[] { 0, 0, 0, 1, 0 },
            new float[] { l, l, l, 0, 1 }
        };
    }
            
    public float[][] Multiply(float[][] A, float[][] B)
    {
        const int size = 5;
        float temp = 0;
        
        float[][] C = new float[size][];
        for (int sigh = 0; sigh<size; sigh++)
            C[sigh] = new float[size];
        
        for (int i = 0; i < size; i++)
        {
            for (int j = 0; j < size; j++)
            {
                temp = 0;
                for (int k = 0; k < size; k++)
                {
                    temp += A[i][k] * B[k][j];
                }
                C[i][j] = temp;
            }
        }
        return C;
    }
}

我搞不清brightness/lightness/luminosity/luminance这些概念的区别,不知道该用哪个、怎么用,试了各种方式都没法得到正确的亮度表现。举几个例子(裙子原始颜色是蓝色):

  • 亮红色与暗红色效果对比
  • 亮绿色与暗绿色效果对比
  • 色调转换正常的示例

内容的提问来源于stack exchange,提问作者goodri63

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 01:59:49