求可仅用x、y色度坐标计算主波长的C#函数或库
C#实现色度坐标转主波长
针对你的需求,目前没有现成的C#库能直接输入x、y色度坐标就输出主波长,但可以通过自定义代码实现完整逻辑——包含从白点到目标点的直线计算、光谱轨迹/紫边交点判定,以及主波长插值计算。以下是可直接使用的实现:
完整代码实现
public static class ColorWavelengthCalculator { // CIE 1931光谱轨迹关键波长对应的色度坐标(x,y) private static readonly Dictionary<double, (double x, double y)> SpectralLocus = new Dictionary<double, (double x, double y)> { {380, (0.1741, 0.0050)}, {400, (0.1731, 0.0049)}, {420, (0.1681, 0.0040)}, {440, (0.1448, 0.0031)}, {460, (0.1048, 0.0088)}, {480, (0.0606, 0.1377)}, {500, (0.0210, 0.3230)}, {520, (0.0782, 0.7190)}, {540, (0.2034, 0.7710)}, {560, (0.3768, 0.6067)}, {580, (0.5386, 0.4544)}, {600, (0.6548, 0.3387)}, {620, (0.7390, 0.2599)}, {640, (0.7920, 0.2079)}, {660, (0.8230, 0.1770)}, {680, (0.8425, 0.1575)}, {700, (0.8544, 0.1456)}, {780, (0.8683, 0.1317)} }; // 计算白点到目标点的直线与光谱轨迹/紫边的交点 private static (double x, double y, bool isPurpleEdge) FindIntersection(double targetX, double targetY) { // 直线方程:y = m*(x - 0.33) + 0.33 double m = (targetY - 0.33) / (targetX - 0.33); double b = 0.33 - m * 0.33; // 先检查是否与紫边(380nm-780nm连线)相交 var (x380, y380) = SpectralLocus[380]; var (x780, y780) = SpectralLocus[780]; double mPurple = (y780 - y380) / (x780 - x380); double bPurple = y380 - mPurple * x380; // 求两条直线交点 double intersectX = (bPurple - b) / (m - mPurple); double intersectY = m * intersectX + b; // 验证交点是否在紫边线段上,且方向符合(目标点在白点与交点之间) if (intersectX >= Math.Min(x380, x780) && intersectX <= Math.Max(x380, x780) && intersectY >= Math.Min(y380, y780) && intersectY <= Math.Max(y380, y780)) { double tTarget = (targetX - 0.33) / (intersectX - 0.33); if (tTarget > 0) { return (intersectX, intersectY, true); } } // 遍历光谱轨迹线段,找与目标直线的交点 double prevWave = 380; var prevPoint = SpectralLocus[prevWave]; foreach (var (wave, point) in SpectralLocus.Skip(1)) { double x1 = prevPoint.x, y1 = prevPoint.y; double x2 = point.x, y2 = point.y; // 解联立方程求线段与直线的交点 double denominator = (y2 - y1) - m * (x2 - x1); if (Math.Abs(denominator) < 1e-9) { prevPoint = point; prevWave = wave; continue; } double intersectXSeg = ((y2 - y1)*x1 - (x2 - x1)*y1 + (x2 - x1)*b) / denominator; double intersectYSeg = m * intersectXSeg + b; // 验证交点在线段上且方向正确 if (intersectXSeg >= Math.Min(x1, x2) && intersectXSeg <= Math.Max(x1, x2) && intersectYSeg >= Math.Min(y1, y2) && intersectYSeg <= Math.Max(y1, y2)) { double t = (intersectXSeg - 0.33) / (targetX - 0.33); if (t > 0) { return (intersectXSeg, intersectYSeg, false); } } prevPoint = point; prevWave = wave; } throw new ArgumentException("输入的色度坐标超出可见色域范围"); } // 主计算函数:输入x,y返回主波长(紫区返回补色波长) public static double CalculateDominantWavelength(double x, double y) { // 白点无主波长 if (Math.Abs(x - 0.33) < 1e-9 && Math.Abs(y - 0.33) < 1e-9) { throw new ArgumentException("白点不存在主波长"); } var (intersectX, intersectY, isPurpleEdge) = FindIntersection(x, y); if (isPurpleEdge) { // 紫区计算补色波长:反向延长线到光谱轨迹的交点 double m = (y - 0.33) / (x - 0.33); double b = 0.33 - m * 0.33; double prevWave = 380; var prevPoint = SpectralLocus[prevWave]; foreach (var (wave, point) in SpectralLocus.Skip(1)) { double x1 = prevPoint.x, y1 = prevPoint.y; double x2 = point.x, y2 = point.y; double denominator = (y2 - y1) - m * (x2 - x1); if (Math.Abs(denominator) < 1e-9) { prevPoint = point; prevWave = wave; continue; } double intersectXSeg = ((y2 - y1)*x1 - (x2 - x1)*y1 + (x2 - x1)*b) / denominator; double intersectYSeg = m * intersectXSeg + b; // 检查反向延长线的交点 double t = (intersectXSeg - 0.33) / (x - 0.33); if (t < 0 && intersectXSeg >= Math.Min(x1, x2) && intersectXSeg <= Math.Max(x1, x2) && intersectYSeg >= Math.Min(y1, y2) && intersectYSeg <= Math.Max(y1, y2)) { // 线性插值得到精确波长 double ratio = (intersectXSeg - x1) / (x2 - x1); return prevWave + ratio * (wave - prevWave); } prevPoint = point; prevWave = wave; } throw new ArgumentException("无法计算紫区补色波长"); } else { // 线性插值计算主波长 double wave1 = 0, wave2 = 0; (double x, double y) p1 = (0,0), p2 = (0,0); foreach (var (wave, point) in SpectralLocus) { if (point.x >= intersectX) { wave2 = wave; p2 = point; break; } wave1 = wave; p1 = point; } double ratio = (intersectX - p1.x) / (p2.x - p1.x); return wave1 + ratio * (wave2 - wave1); } } }
使用示例
// 测试色度坐标(0.6, 0.35) double targetX = 0.6; double targetY = 0.35; try { double dominantWave = ColorWavelengthCalculator.CalculateDominantWavelength(targetX, targetY); Console.WriteLine($"主波长:{dominantWave:F1} nm"); } catch (ArgumentException ex) { Console.WriteLine(ex.Message); }
可选库参考
如果不想自己维护代码,可参考ColorMine库——它提供了CIE色度坐标的基础处理工具,你可以基于其现有模块扩展上述交点计算逻辑,不过自定义代码的可控性更强,无需依赖第三方库的版本更新。
内容的提问来源于stack exchange,提问作者methsound
相关产品推荐
相关产品推荐

