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
相关产品推荐
相关产品推荐




