在c#中将double值转换为RGB Color
我试图将double值(介于0和1之间)转换为RGB Color.在下面的代码中,您可以看到我尝试做什么,但我觉得这个算法有问题.我没有得到所有的颜色.当我从double转换为int或者我不确定时,可能有松散的信息……但是请看看它,如果你有任何建议或任何其他方法(经过验证的方法),请告诉我:
private Color generateRGB(double X) { Color color; if (X >= 0.5) //red and half of green colors { int Red = (int)((2 * X - 1) * 255); int Green = (int)((2 - 2 * X) * 255); int Blue = 0; color = Color.FromArgb(Red,Green,Blue); } else // blue and half of green colors { int Red = 0; int Green = (int)((2 * X) * 255); int Blue = (int)((1 - 2 * X) * 255); color = Color.FromArgb(Red,Blue); } return color; } 这是表达我想要做的最好的图像. https://www.dropbox.com/s/bvs3a9m9nc0rk5e/20131121_143044%20%281%29.jpg [更新] 这就是我的方式,这似乎是一个很好的解决方案.请看看它,并告诉我天气这是更好的表示与否(也许那些对Color Spaces有更好了解的人可以给出反馈) 我从这里使用了HSVtoRGB转换算法:http://www.splinter.com.au/converting-hsv-to-rgb-colour-using-c/. private Color generateRGB(double X) { Color color; int red; int green; int blue; HsvToRgb(X*360,1,out red,out green,out blue); color = Color.FromArgb(red,green,blue); return color; } 解决方法
在你的一条评论中,你说:“不,我的目的是包括所有颜色,我不想赞成其中任何一种颜色.简单地说,我希望将双重值转换为RGB颜色的最佳方法”
因此,您不关心double和Color之间的实际关系,并且您不希望以某种方式对Double值进行操作. 我可能会提醒你RGB颜色由3个字节组成,但是出于组合的原因,.NET BCL类Color将3个组件作为int值提供. 所以你有3个字节! 足够的聊天,对实际问题. 您是否听说过StructLayoutAttribute属性及其随行人员,FieldOffsetAttribute属性? 假设你有一个结构,我们称之为CommonDenominatorBetweenColoursAndDoubles. public struct CommonDenominatorBetweenColoursAndDoubles { public byte R; public byte G; public byte B; public double AsDouble; } 现在,假设您想以这样的方式编排编译器和即将运行的运行符,以便R,G和B字段(每个占用1个字节)连续布局,并且AsDouble字段在它的前3个重叠它们字节并继续使用它自己的,专门保留5个字节.你是怎样做的 ? 您可以使用上述属性指定: >你正在控制结构的布局这一事实(小心,强大的力量带来了很大的责任) 这些属性位于System.Runtime.InteropServices命名空间下的mscorlib.dll中,您可以在这里阅读它们StructLayout和这里FieldOffset. 所以你可以实现所有这些: [StructLayout(LayoutKind.Explicit)] public struct CommonDenominatorBetweenColoursAndDoubles { [FieldOffset(0)] public byte R; [FieldOffset(1)] public byte G; [FieldOffset(2)] public byte B; [FieldOffset(0)] public double AsDouble; } 这是struct(kinda)实例中的内存如下所示: 还有什么比一些扩展方法更好的方式来包装它: public static double ToDouble(this Color @this) { CommonDenominatorBetweenColoursAndDoubles denom = new CommonDenominatorBetweenColoursAndDoubles (); denom.R = (byte)@this.R; denom.G = (byte)@this.G; denom.B = (byte)@this.B; double result = denom.AsDouble; return result; } public static Color ToColor(this double @this) { CommonDenominatorBetweenColoursAndDoubles denom = new CommonDenominatorBetweenColoursAndDoubles (); denom.AsDouble = @this; Color color = Color.FromArgb ( red: denom.R,green: denom.G,blue: denom.B ); return color; } 我也对此进行了测试,以确保它是防弹的,据我所知,你不必担心一件事: for (int x = 0; x < 255; x++) { for (int y = 0; y < 255; y++) { for (int z = 0; z < 255; z++) { var c1 = Color.FromArgb (x,y,z); var d1 = c1.ToDouble (); var c2 = d1.ToColor (); var x2 = c2.R; var y2 = c2.G; var z2 = c2.B; if ((x != x2) || (y != y2) || (z != z2)) Console.Write ("1 error"); } } } 完成后不会产生任何错误. 编辑 在我开始编辑之前:如果你研究 如果已经不清楚了,double.Epsilon *(256 * 3 – 1)是一个令人难以置信的小数字,人们甚至无法发音. 在该范围内,你会发现你有精确的256 * 3,这是2“连续”的双倍值,从0开始,以最小的双倍距离分开. 通过数学(逻辑值)操作(不通过直接存储器寻址),您可以轻松地将原始0 … double.Epsilon *(22? – 1)的22?数字范围扩展到0 .. 1. 这就是我所说的: 不要将double.Epsilon(或ε)误认为是指数字母e. 所以,为了确保我们为编码做好准备,让我们回顾一下这里发生的事情: 我们有N(N为22?)双数,以ε*(N-1)结束(其中ε或double.Epsilon是大于0的最小双数). 从某种意义上说,我们创建的结构实际上只是帮助我们做到这一点: double[] allDoubles = new double[256 * 256 * 256]; double cursor = 0; int index = 0; for (int r = 0; r < 256; r++) for (int g = 0; g < 256; g++) for (int b = 0; b < 256; b++) { allDoubles[index] = cursor; index++; cursor += double.Epsilon; } 那么,为什么我们经历了结构的所有麻烦? 现在,转到线性变换位. 我们现在要做的只是一些数学运算(计算需要更长的时间,因为它涉及浮点运算,但会成功地将我们的双精度范围扩展到0到1之间的均匀分布): 在我们之前创建的结构中,我们将重命名AsDouble字段,将其设为私有并创建一个名为AsDouble的新属性来处理转换(两种方式): [StructLayout(LayoutKind.Explicit)] public struct CommonDenominatorBetweenColoursAndDoubles { [FieldOffset(0)] public byte R; [FieldOffset(1)] public byte G; [FieldOffset(2)] public byte B; // we renamed this field in order to avoid simple breaks in the consumer code [FieldOffset(0)] private double _AsDouble; // now,a little helper const private const int N_MINUS_1 = 256 * 256 * 256 - 1; // and maybe a precomputed raw range length private static readonly double RAW_RANGE_LENGTH = double.Epsilon * N_MINUS_1; // and now we're adding a property called AsDouble public double AsDouble { get { return this._AsDouble / RAW_RANGE_LENGTH; } set { this._AsDouble = value * RAW_RANGE_LENGTH; } } } 你会惊喜地发现我在编辑之前提出的测试仍然可以正常使用这个新增功能,所以你有0%的信息丢失,现在双倍范围同样在0 .. 1之间拉伸. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |