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

求可仅用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 13:05:59