如题,我也找到了一个这样的算法(如下),但是与photoshop中的相差甚远
RGB=>Lab
|X|   |0.433910  0.376220  0.189860| |R/255|
|Y| = |0.212649  0.715169  0.072182|*|G/255|
|Z|   |0.017756  0.109478  0.872915| |B/255|L = 116*Y^1/3      for Y>0.008856
L = 903.3*Y      for Y<=0.008856a = 500*(f(X)-f(Y))
b = 200*(f(Y)-f(Z))
其中  f(t)=t^1/3              for t>0.008856
      f(t)=7.787*t+16/116    for t<=0.008856

解决方案 »

  1.   

    unit uLabRgb;interfacetype
      TVector3 = array[1..3] of Double;function LabToRgb(Lab: TVector3): TVector3;
    function RgbToLab(Rgb: TVector3): TVector3;implementationtype
      TMatrix3 = array[1..3, 1..3] of Double;const
      RgbXyz: TMatrix3 = ((1, 0, 0), (0, 1, 0), (0, 0, 1));
      XyzRgb: TMatrix3 = ((1, 0, 0), (0, 1, 0), (0, 0, 1));  { CCIR recommended values }
      PhosphorX: TVector3 = (0.64, 0.30, 0.15);
      PhosphorY: TVector3 = (0.33, 0.60, 0.06);
      WhitePoint: TVector3 = (0.95, 1.0000, 1.09);
      Gamma: Double = 1 / 0.45;function MultiplyMatrix3ByVector3(const M: TMatrix3;
      const V: TVector3): TVector3;
      var
        I: Integer;
        J: Integer;
      begin
      for I := 1 to 3 do begin
        Result[I] := 0.0;
        for J := 1 to 3 do
          Result[I] := Result[I] + M[I, J] * V[J] end end;function MultiplyMatrix3ByMatrix3(const M1, M2: TMatrix3): TMatrix3;
      var
        I: Integer;
        J: Integer;
        K: Integer;
      begin
      for I := 1 to 3 do
        for J := 1 to 3 do begin
          Result[I, J] := 0.0;
          for K := 1 to 3 do
            Result[I, J] := Result[I, J] + M1[I, K] * M2[K, J] end end;function InvertMatrix3(const M: TMatrix3): TMatrix3;
      var
        I: Integer;
        J: Integer;
        D: Double;  function Next(I: Integer): Integer;
        begin
        Result := I + 1;
        if Result > 3 then
          Result := Result - 3 end;  function Prev(I: Integer): Integer;
        begin
        Result := I - 1;
        if Result < 1 then
          Result := Result + 3 end;  begin
      D := 0;
      for I := 1 to 3 do
        D := D + M[1, I] * (M[2, Next(I)] * M[3, Prev(I)] -
          M[2, Prev(I)] * M[3, Next(I)]);
      FillChar(Result, SizeOf(Result), 0);
      for I := 1 to 3
        do for J := 1 to 3 do
          Result[J, I] := (M[Next(I), Next(J)] * M[Prev(I), Prev(J)] -
            M[Next(I), Prev(J)] * M[Prev(I), Next(J)]) / D end;function LabToXyz(const Lab: TVector3): TVector3;
      var
        LL: Double;  function Cube(X: Double): Double;
        begin
        if X >= (6 / 29) then
          Result := X * X * X
        else
          Result := (108 / 841) * (X - (4 / 29)) end;  begin
      LL := (Lab[1] + 16) / 116;
      Result[1] := WhitePoint[1] * Cube(LL + Lab[2] / 500);
      Result[2] := WhitePoint[2] * Cube(LL);
      Result[3] := WhitePoint[3] * Cube(LL - Lab[3] / 200) end;function XyzToRgb(const Xyz: TVector3): TVector3;
      var
        I: Integer;
      begin
      Result := MultiplyMatrix3ByVector3(XyzRgb, Xyz);
      for I := 1 to 3 do
        if Result[I] <= 0.0 then
          Result[I] := 0
        else Result[I] := Exp(Ln(Result[I]) / Gamma) end;function LabToRgb(Lab: TVector3): TVector3;
      begin
      Result := XyzToRgb(LabToXyz(Lab)) end;function RgbToXyz(const Rgb: TVector3): TVector3;
      var
        I: Integer;
      begin
      Result := Rgb;
      for I := 1 to 3 do
        if Result[I] <= 0.0 then
          Result[I] := 0
        else Result[I] := Exp(Ln(Result[I]) * Gamma);
      Result := MultiplyMatrix3ByVector3(RgbXyz, Result) end;function XyzToLab(const Xyz: TVector3): TVector3;
      var
        YY: Double;  function CubeRoot(X: Double): Double;
        begin
        if X >= (216 / 24389) then
          Result := Exp(Ln(X) / 3)
        else
          Result := (841 / 108) * X + (4 / 29) end;  begin
      YY := CubeRoot(Xyz[2] / WhitePoint[2]);
      Result[1] := 116 * YY - 16;
      Result[2] := 500 * (CubeRoot(Xyz[1] / WhitePoint[1]) - YY);
      Result[3] := 200 * (YY - CubeRoot(Xyz[3] / WhitePoint[3])) end;
      

  2.   

    function RgbToLab(Rgb: TVector3): TVector3;
      begin
      Result := XyzToLab(RgbToXyz(Rgb)) end;procedure InitTransformationMatrices;
      var
        I: Integer;
        J: Integer;
        PhosphorZ: TVector3;
        C: TVector3;
        CToXyz: TMatrix3;
        XyzToC: TMatrix3;
      begin
      for I := 1 to 3 do begin
        CToXyz[1, I] := PhosphorX[I];
        CToXyz[2, I] := PhosphorY[I];
        CToXyz[3, I] := 1 - PhosphorX[I] - PhosphorY[I] end;
      XyzToC := InvertMatrix3(CToXyz);
      C := MultiplyMatrix3ByVector3(XyzToC, WhitePoint);
      for I := 1 to 3 do
        for J := 1 to 3 do
          RgbXyz[I, J] := CToXyz[I, J] * C[J];
      XyzRgb := InvertMatrix3(RgbXyz) end;initialization
      InitTransformationMatrices end.
      

  3.   

    The HSL system that Windows uses is imperfect in that different colors
    having the same L value aren't all of the same perceived brightness.
    This makes it difficult to do brightness matching.  I've put together
    some code that uses the CIE's L*,a*,b* system to provide a color
    coordinate system that does a much better job of matching the response
    of the human visual system.To use the code, take your original RGB value, then divide each value
    by 255 so that the resulting numbers range from 0.0 to 1.0. Now feed
    these values to the RgbToLab function. This converts the RGB
    coordinates to LAB coordinates, where the first coordinate (L) is
    scaled from 0 to 100. So now you can modify that L value to change the
    brightness of the color, then feed the new LAB values to LabToRgb to
    convert back to RGB. Finally, multiply each of the final result values
    by 255 and round to the nearest integer.
      

  4.   

    To: aiirii
    你说的这个我也试过了,但比那个差得更远,简单算得上离谱
      

  5.   

    {********************************************************************
    *
    * =-----------------------------------------------------------------=
    * =                          ____          _________                =
    * =                         / _  \         \___  __/                =
    * =                        / /_/ /     ____   / /                   =
    * =                       /  _   \ ● / _  \ / /                    =
    * =                      /  /_/  // // / / // /                     =
    * =                      \______//_//_/ /_//_/                      =
    * =                                                                 =
    * =             Copyright (c) BIN Technology studio,2004            =
    * =                           LET'Z BT                              =
    * =-----------------------------------------------------------------=

    * Author : 周蔚
    * Create : 2004-10-14
    * LastChange : 2004-10-14 23:40
    * History : 
    *
    * Description : RGB=>CIELab  
    *
    ********************************************************************}procedure RGB2CIELab(R, G, B: Integer; var L, aa, bb: Integer);
    var
      X, Y, Z, FL, Fa, Fb: Extended;
    begin
      X :=  0.412453 * R + 0.357580 * G + 0.180423 * B;
      Y :=  0.212671 * R + 0.715160 * G + 0.072169 * B;
      Z :=  0.019334 * R + 0.119193 * G + 0.950227 * B;
      X := X / 255 / 0.950456;
      Y := Y / 255;
      Z := Z / 255 / 1.088754;
      if Y > 0.008856 then
        FL := 116.0 * Power(Y, 1 / 3) - 16
      else
        FL := 903.3 * Y;
      L := Round(FL);  if X > 0.008856 then
        Fa := Power(X, 1 / 3)
      else
        Fa := (7.787 * X) + 16 / 116;  if Y > 0.008856 then
        Fa := Fa - Power(Y, 1 / 3)
      else
        Fa := Fa - ((7.787 * Y) + 16 / 116);  aa := Round(Fa * 500) + 128;  if Y > 0.008856 then
        Fb := Power(Y, 1 / 3)
      else
        Fb := (7.787 * Y) + 16 / 116;  if Z > 0.008856 then
        Fb := Fb - Power(Z, 1 / 3)
      else
        Fb := Fb - ((7.787 * Z) + 16 / 116);  bb := Round(Fb * 200) + 128;
    end;
      

  6.   

    function getCieL(Y:single):single;
    var tmp:single;
    begin
      tmp:=Y/CieY0;//ciey0=100
      result:=iif(tmp>CieK1,116*power(tmp,1/3)-16,
                    903.3*tmp);              //ciek1=8.856E-3   当TEP在0-100之间的时候 cieL=
      if result<0 then
        result:=0
      else if result>100 then
        result:=100;
    end;
    function getCieA(X,Y:single):single;
    begin
      result:=500*(FX(X)-FY(Y));
      if result<-86 then
        result:=-86
      else if result>100 then
        result:=100;
    end;function getCieB(Z,Y:single):single;
    begin
      result:=200*(FY(Y)-FZ(Z));
      if result<-108 then
        result:=-108
      else if result>94 then
        result:=94;
    end;
    function FX(X:single):single;
    var tmp:single;
    begin
      tmp:=X/CieX0;  //ciexo=95
      result:=iif(tmp>CieK1,power(tmp,1/3),
                    7.787*tmp+16/116);
    end;function FY(Y:single):single;
    var tmp:single;
    begin
      tmp:=Y/CieY0; //ciey0=100
      result:=iif(tmp>CieK1,power(tmp,1/3),
                    7.787*tmp+16/116);
    end;function FZ(Z:single):single;
    var tmp:single;
    begin
      tmp:=Z/CieZ0;     //ciez0=109
      -
      result:=iif(tmp>CieK1,power(tmp,1/3),
                    7.787*tmp+16/116);
    end;
      

  7.   

    To: ehom(?!)
      你的这个得出的结果和photoshop中的结果也差得很远呀,
    To:  johnneng(阿能) 
      你这个是XYZ-->Lab吧,好像也不太对还是多谢两位,还有其它的人有和Photoshop中的结果差不多的算法吗?
      

  8.   

    我这个已经非常接近了,在RGB的颜色边界都作了修正,中间区域一般也就1-3的误差,如果这也觉得大,还是自己推导吧,要做的和PS一模一样,最好对PS进行逆向工作,取出里面的运算数据和算法
      

  9.   

    周老大,我找这个算法找得好辛苦!Lab颜色空间比HSI好到哪去了,可惜我就是以前用不了,谢了先!