2011年4月8日金曜日

C# RGB ⇔ CIEXYZ ⇔ CIELAB 相互変換

RGB⇔CIEXYZ⇔CIELABの相互変換できる構造体を作成した

//RGBからL*a*b*へ
CIELAB Lab = new CIELAB(Color.Blue);
//L*a*b*からRGBへ
Color col = Lab.ToColor();
//RGBからCIEXYZへ
CIEXYZ xyz = new CIEXYZ(Color.Blue);
//CIEXYZからRGBへ
Color col = xyz.ToColor();
//L*a*b*からXYZへ
CIEXYZ xyz = new CIEXYZ(Lab);
//XYZからL*a*b*へ
CIELAB Lab = new CIELAB(xyz);

こんなかんじで。





//   
// CIELAB構造体   
// Hiroaki,Komori    
//   
using System;
using System.Drawing;
 
struct CIELAB
{
  private const double Xn = 0.950456;
  private const double Yn = 1.0;
  private const double Zn = 1.088754;
 
  private double l;
  private double a;
  private double b;
 
  public double L
  {
    get { return l; }
    set { l = value; }
  }
 
  public double A
  {
    get { return a; }
    set { a = value; }
  }
 
  public double B
  {
    get { return b; }
    set { b = value; }
  }
 
 
  public CIELAB(Double _L, Double _A, Double _B)
  {
    l = _L;
    a = _A;
    b = _B;
  }
 
  public CIELAB(Color rgb)
  {
    CIELAB _lab = CIELAB.Parse(rgb);
    l = _lab.L;
    a = _lab.A;
    b = _lab.B;
  }
 
  public CIELAB(CIEXYZ xyz)
  {
    CIELAB _lab = CIELAB.Parse(xyz);
    l = _lab.L;
    a = _lab.A;
    b = _lab.B;
  }
 
  ///
  /// Colorへ変換
  ///
  //////
  public Color ToColor()
  {
    return ToCIEXyz().ToColor();
  }
 
  ///
  /// CIEXyzへ変換
  ///
  //////
  public CIEXYZ ToCIEXyz()
  {
    double _delta = 6.0 / 29.0;
    double _fy = (l + 16.0) / 116.0;
    double _fx = _fy + a / 500.0;
    double _fz = _fy - b / 200.0;
 
    double _x, _y, _z;
 
    if (_fx > _delta)
    {
      _x = Xn * Math.Pow(_fx, 3);
    }
    else
    {
      _x = (_fx - 16.0 / 116.0) * 3 * Math.Pow(_delta, 2);
    }
 
    if (_fy > _delta)
    {
      _y = Yn * Math.Pow(_fy, 3);
    }
    else
    {
      _y = (_fy - 16.0 / 116.0) * 3 * Math.Pow(_delta, 2);
    }
 
    if (_fz > _delta)
    {
      _z = Zn * Math.Pow(_fz, 3);
    }
    else
    {
      _z = (_fz - 16.0 / 116.0) * 3 * Math.Pow(_delta, 2);
    }
 
    return new CIEXYZ(_x, _y, _z);
  }
 
  ///
  /// CIEXYZからCIELabへ変換
  ///
  public static CIELAB Parse(CIEXYZ xyz)
  {
    double _l = 116.0 * Fxyz(xyz.Y / Yn) - 16;
    double _a = 500.0 * (Fxyz(xyz.X / Xn) - Fxyz(xyz.Y / Yn));
    double _b = 200.0 * (Fxyz(xyz.Y / Yn) - Fxyz(xyz.Z / Zn));
 
    CIELAB _result = new CIELAB(_l, _a, _b);
 
    return _result;
  }
 
  ///
  /// XYZ to L*a*b* transformation function.
  ///
  private static double Fxyz(double t)
  {
    double _result;
    if (t > 0.008856)
    {
      _result = Math.Pow(t, (1.0 / 3.0));
    }
    else
    {
      _result = 7.787 * t + 16.0 / 116.0;
    }
 
    return _result;
  }
 
  ///
  /// CIEXYZからColorへ変換
  ///
  ///  ///
  public static CIELAB Parse(Color col)
  {
    CIEXYZ _xyz = CIEXYZ.Parse(col);
    return CIELAB.Parse(_xyz);
  }
 
  ///
  ///文字列に変換
  ///
  ///
  public override string ToString()
  {
    string _result = string.Format("CIELab [L*={0}, a*={1}, b*={2}", l.ToString("F"), a.ToString("F"), b.ToString("F"));
    return _result;
  }
}
 
//   
// CIEXYZ構造体   
// Hiroaki,Komori    
//   
struct CIEXYZ
{
    private double x;
    private double y;
    private double z;

    public double X
    {
        get { return x; }
        set { x = value; }
    }

    public double Y
    {
        get { return y; }
        set { y = value; }
    }

    public double Z
    {
        get { return z; }
        set { z = value; }
    }


    public CIEXYZ(Double _X, Double _Y, Double _Z)
    {
        x = _X;
        y = _Y;
        z = _Z;
    }

    public CIEXYZ(Color rgb)
    {
        CIEXYZ _xyz = Parse(rgb);

        x = _xyz.X;
        y = _xyz.Y;
        z = _xyz.Z;
    }

    ///
    /// CIELabからCIEXyzへ変換
    ///
    ///    public CIEXYZ(CIELAB Lab)
    {
        CIEXYZ _xyz = Lab.ToCIEXyz();
        x = _xyz.X;
        y = _xyz.Y;
        z = _xyz.Z;
    }

    ///
    /// ColorからXYZへ変換
    ///
    ///    ///
    public static CIEXYZ Parse(Color col)
    {
        double _RLinear = col.R / 255d;
        double _GLinear = col.G / 255d;
        double _BLinear = col.B / 255d;

        double _r, _g, _b, _x, _y, _z;

        if (_RLinear > 0.04045)
        {
            _r = Math.Pow((_RLinear + 0.055) / (1 + 0.055), 2.2);
        }
        else
        {
            _r = (_RLinear / 12.92);
        }

        if (_GLinear > 0.04045)
        {
            _g = Math.Pow((_GLinear + 0.055) / (1 + 0.055), 2.2);
        }
        else
        {
            _g = (_GLinear / 12.92);
        }

        if (_BLinear > 0.04045)
        {
            _b = Math.Pow((_BLinear + 0.055) / (1 + 0.055), 2.2);
        }
        else
        {
            _b = (_BLinear / 12.92);
        }

        _x = _r * 0.4124 + _g * 0.3576 + _b * 0.1805;
        _y = _r * 0.2126 + _g * 0.7152 + _b * 0.0722;
        _z = _r * 0.0193 + _g * 0.1192 + _b * 0.9505;
        CIEXYZ _result = new CIEXYZ(_x, _y, _z);

        return _result;
    }

    ///
    /// Colorへ変換
    ///
    ///    ///
    public Color ToColor()
    {
        double _r = 3.240479 * x - 1.53715 * y - 0.498535 * z;
        double _g = -0.969256 * x + 1.875991 * y + 0.041556 * z;
        double _b = 0.055648 * x - 0.204043 * y + 1.057311 * z;

        Color _result = Color.FromArgb(FromLinear(_r), FromLinear(_g), FromLinear(_b));
        return _result;
    }

    private static int FromLinear(double v)
    {
        int _result;

        if (v <= 0.0031308)
        {
            _result = (int)(Clamp(v * 12.92) * 255.0 + 0.5);
        }
        else
        {
            _result = (int)(Clamp(1.055 * Math.Pow(v, (1.0 / 2.4)) - 0.055) * 255.0 + 0.5);
        }

        return _result;
    }

    private static double Clamp(double v)
    {
        double _result = v;

        if (v < 0.0)
        {
            _result = 0.0;
        }
        else if (v > 1.0)
        {
            _result = 1.0;
        }

        return _result;
    }

    public CIELAB ToCIELab()
    {
        CIELAB _result = new CIELAB(new CIEXYZ(x, y, z));
        return _result;
    }

    ///
    ///文字列に変換
    ///
    ///
    public override string ToString()
    {
        string _result = string.Format("CIEXyz [X={0}, Y={1}, Z={2}", x.ToString("F"), y.ToString("F"), z.ToString("F"));
        return _result;
    }
}

0 件のコメント:

コメントを投稿