1. 程式人生 > >各個顏色空間的轉換

各個顏色空間的轉換

// 沒有驗證過

// RGB<->YUV
// RGB<->XYZ
// RGB<->LAB
// RGB<->HSV
// RGB<->CMY

// XYZ<->LAB
// YUV ->XYZ
// LAB ->HSV
// XYZ ->HSV
// RGB ->CMYK
// CMYK->CMY

// http://www.cnblogs.com/phinecos/archive/2009/05/03/1448121.html
// http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
// http://www.programmershare.com/1288015/
// http://blog.sina.com.cn/s/blog_6806030c0101ei9z.html

#include <math.h>

template <class T>
const T& HYMin(const T& refT1, const T& refT2)
{
	return (refT1 < refT2) ? refT1 : refT2;
}

template <class T>
const T& HYMax(const T& refT1, const T& refT2)
{
	return (refT1 > refT2) ? refT1 : refT2;
}

// RGB轉換為YUV
void RGB2YUV(double dR, double dG, double dB, double &dY, double &dU, double &dV)
{
    dY = 0.257 * dR + 0.504 * dG + 0.098 * dB + 16;		// y
    dU = -0.148 * dR - 0.291 * dG + 0.439 * dB + 128;	// u
    dV = 0.439 * dR - 0.368 * dG - 0.071 * dB + 128;	// v
}

// YUV轉換為RGB
void YUV2RGB(double dY, double dU, double dV, double &dR, double &dG, double &dB)
{
    dR = 1.0 * dY + 8 + 1.402 * (dV - 128);
    dG = 1.0 * dY - 0.34413 * (dU - 128) - 0.71414 * (dV - 128); 
    dB = 1.0 * dY + 1.772 * (dU - 128) + 0;
}

// RGB轉換為XYZ
void RGB2XYZ(double dR, double dG, double dB, double &dX, double &dY, double &dZ)
{
    double dTempR = (dR / 255.0);
    double dTempG = (dG / 255.0);
    double dTempB = (dB / 255.0);

    if(0.04045 < dTempR)
    {
        dTempR = pow((dTempR + 0.055) / 1.055, 2.4);
    }
    else
    {
        dTempR /= 12.92;
    }

    if(0.04045 < dTempG)
    {
        dTempG = pow((dTempG + 0.055) / 1.055, 2.4);
    }
    else
    {
        dTempG /= 12.92;
    }

    if(0.04045 < dTempB)
    {
        dTempB = pow((dTempB + 0.055) / 1.055, 2.4);
    }
    else
    {
        dTempB /= 12.92;
    }         

    dTempR *= 100.0;
    dTempG *= 100.0;
    dTempB *= 100.0;

    //Observer. = 2°, Illuminant = D65
    dX = 0.4124564 * dTempR + 0.3575761 * dTempG + 0.1804375 * dTempB;
    dY = 0.2126729 * dTempR + 0.7151522 * dTempG + 0.0721750 * dTempB;
    dZ = 0.0193339 * dTempR + 0.1191920 * dTempG + 0.9503041 * dTempB;
}

// XYZ轉換為LAB
void XYZ2LAB(double dX, double dY, double dZ, double &dL, double &dA ,double &dB)
{
    double dTempX = dX / 95.047;
    double dTempY = dY / 100.000;
    double dTempZ = dZ / 108.883;

    if(0.008856 < dTempX)
    {
        dTempX = pow((float)dTempX, 1.0f / 3.0f);
    }
    else
    {
        dTempX = ( 7.787 * dTempX ) + (16.0 / 116.0);
    }
	
    if(0.008856 < dTempY)
    {
        dTempY = pow((float)dTempY, 1.0f / 3.0f);
    }
    else
    {
        dTempY = (7.787 * dTempY) + (16.0 / 116.0);
    }

    if(0.008856 < dTempZ)
    {
        dTempZ = pow((float)dTempZ, 1.0f / 3.0f);
    }
    else
    {
        dTempZ = (7.787 * dTempZ) + (16.0 / 116.0);
    }

    dL = (116 * dTempY) - 16;
    dA = 500 * (dTempX - dTempY);
    dB = 200 * (dTempY - dTempZ);
}

// RGB轉換為LAB
void RGB2LAB(double dR, double dG, double dB, double &dLAB_L, double &dLAB_A, double &dLAB_B)
{
    double dX, dY, dZ;
    RGB2XYZ(dR, dG, dB, dX, dY, dZ);
	XYZ2LAB(dX, dY, dZ, dLAB_L, dLAB_A, dLAB_B);
}

// LAB轉換為XYZ
void LAB2XYZ(double dLAB_L, double dLAB_A, double dLAB_B, double &dX, double &dY, double &dZ)
{
    double dTempY = (dLAB_L + 16) / 116;
    double dTempX = dLAB_A / 500 + dTempY;
    double dTempZ = dTempY - dLAB_B / 200;

    if(pow((double)dTempY, 3) > 0.008856)
	{
        dTempY = pow((double)dTempY, 3);
	}
    else
	{
		dTempY = (dTempY - 16 / 116) / 7.787;
	}

    if(pow((double)dTempX, 3) > 0.008856)
	{
        dTempX = pow((double)dTempX, 3);
	}
    else
	{
        dTempX = (dTempX - 16 / 116) / 7.787;
	}

    if(pow((double)dTempZ, 3) > 0.008856)
	{
        dTempZ = pow((double)dTempZ, 3);
	}
    else
	{
        dTempZ = (dTempZ - 16.0 / 116.0) / 7.787;
	}

	dX = 95.047 * dTempX;
	dY = 100.000 * dTempY;
    dZ = 108.883 * dTempZ;
}

// XYZ轉換為RGB
void XYZ2RGB(double dX, double dY, double dZ, double &dR, double &dG, double &dB)
{
    double dTempX = dX / 100.0f;        // X from 0 to  95.047      (Observer = 2°, Illuminant = D65)
    double dTempY = dY / 100.0f;        // Y from 0 to 100.000
    double dTempZ = dZ / 100.0f;        // Z from 0 to 108.883

    double dTempR = dTempX * 3.2404542 + dTempY * -1.5371385 + dTempZ * -0.4985314;
    double dTempG = dTempX * -0.9692660 + dTempY * 1.8760108 + dTempZ * 0.0415560;
    double dTempB = dTempX * 0.0556434 + dTempY * -0.2040259 + dTempZ * 1.0572252;

    if(0.0031308 < dTempR)
	{
        dTempR = 1.055 * (pow(dTempR, (1 / 2.4))) - 0.055;
	}
    else
	{
        dTempR *= 12.92;
	}
	
    if(0.0031308 < dTempG)
	{
        dTempG = 1.055 * (pow(dTempG, (1 / 2.4))) - 0.055;
	}
    else
	{
        dTempG *= 12.92;
	}
	
    if(0.0031308 < dTempB)
	{
        dTempB = 1.055 * (pow(dTempB, (1 / 2.4))) - 0.055;
	}
    else
	{
        dTempB *= 12.92;
	}
	
    dR = 255.0f * dTempR;
    dG = 255.0f * dTempG;
    dB = 255.0f * dTempB;
}

// LAB轉換為RGB
void LAB2RGB(double dLAB_L, double dLAB_A, double dLAB_B, double &dR, double &dG, double &dB)
{
    double dX, dY, dZ;
    LAB2XYZ(dLAB_L, dLAB_A, dLAB_B, dX, dY, dZ);
    XYZ2RGB(dX, dY, dZ, dR, dG, dB);
}

// RGB轉換為HSV
void RGB2HSV(double dR, double dG, double dB, double &dH, double &dS, double& dV)
{
    double dTempR = (dR / 255);			// RGB from 0 to 255
    double dTempG = (dG / 255);
    double dTempB = (dB / 255);

    double dMin, dMax, dDelMax;
    dMin = HYMin(HYMin(dTempR, dTempG), dTempB);
    dMax = HYMax(HYMax(dTempR, dTempG), dTempB);
    dDelMax = dMax - dMin;				// Delta RGB value 

    dV = dMax;

    if(0 == dMax)			// This is a gray, no chroma
    {
        dH = 0.0;				// HSV results from 0 to 1
        dS = 0.0;
    }
    else					// Chromatic data
    {
        dS = dDelMax / dMax;        

        double dDelR = (((dMax - dTempR) / 6) + (dDelMax / 2)) / dDelMax;
        double dDelG = (((dMax - dTempG) / 6) + (dDelMax / 2)) / dDelMax;
        double dDelB = (((dMax - dTempB) / 6) + (dDelMax / 2)) / dDelMax;

        if(dTempR == dMax)
		{
            dH = dDelB - dDelG;
		}
        else if(dTempG == dMax)
		{
            dH = (1.0 / 3.0) + dDelR - dDelB;
		}
        else if(dTempB == dMax)
		{
            dH = (2.0 / 3.0) + dDelG - dDelR;
		}			

        if(0 > dH)
		{
            dH += 1.0;
		}
		
        if(1 < dH)
		{
            dH -= 1.0;
		}
    }
}

// HSV轉換為RGB
void HSV2RGB(double dH, double dS, double dV, double &dR, double &dG, double &dB)
{
    if(dS == 0)                       // HSV from 0 to 1
    {
        dR = 255.0f * dV;
        dG = 255.0f * dV;
        dB = 255.0f * dV;
    }
    else
    {
		// 86912219
        double dTempH, dTempI, dTemp1, dTemp2, dTemp3;

        dTempH = 6.0f * dH;
        if(6 == dTempH)
		{
            dTempH = 0.0;     // H must be < 1
		}
		
        dTempI = int(dTempH);            //Or  var_i = floor( var_h )
        dTemp1 = dV * (1 - dS);
        dTemp2 = dV * (1 - dS * (dTempH - dTempI));
        dTemp3 = dV * (1 - dS * (1 - (dTempH - dTempI)));

        double dTempR, dTempG, dTempB;
		
        if(0 == dTempI)
        {
            dTempR = dV; 
            dTempG = dTemp3 ;
            dTempB = dTemp1;
        }
        else if(1 == dTempI) 
        {
            dTempR = dTemp2 ;
            dTempG = dV;
            dTempB = dTemp1;
        }
        else if(2 == dTempI)
		{
            dTempR = dTemp1;
            dTempG = dV;
            dTempB = dTemp3;
        }
        else if (3 == dTempI)
        {
            dTempR = dTemp1 ;
            dTempG = dTemp2 ;
            dTempB = dV;
        }
        else if(4 == dTempI)
        {
            dTempR = dTemp3;
            dTempG = dTemp1; 
            dTempB = dV;
        }
        else
        {
            dTempR = dV;
            dTempG = dTemp1;
            dTempB = dTemp2;
        }

        dR = 255.0f * dTempR;	// RGB results from 0 to 255
        dG = 255.0f * dTempR;
        dB = 255.0f * dTempR;
    }
}

// YUV轉換為XYZ
void YUV2XYZ(double dL, double dU, double dV, double &dX, double &dY, double &dZ)
{
    double dTempY, dRefX, dRefY, dRefZ, dRefU, dRefV, dTempU, dTempV;
	
    dTempY = (dL + 16) / 116;
    if(pow(dTempY, 3) > 0.008856)
	{
        dTempY = pow(dTempY, 3);
	}
    else
	{
        dTempY = (dTempY - 16.0 / 116.0) / 7.787;
	}

    dRefX =  95.047;      //Observer= 2°, Illuminant= D65
    dRefY = 100.000;
    dRefZ = 108.883;

    dRefU = (4 * dRefX ) / (dRefX + (15 * dRefY) + (3 * dRefZ));
    dRefV = (9 * dRefY ) / (dRefX + (15 * dRefY) + (3 * dRefZ));

    dTempU = dU / (13 * dL) + dRefU;
    dTempV = dV / (13 * dL) + dRefV;

    dY = dTempY * 100;
    dX = -(9 * dY * dTempU) / ((dTempU - 4) * dTempV  - dTempU * dTempV);
    dZ = (9 * dY - (15 * dTempV * dY) - (dTempV * dX)) / (3 * dTempV);
}

// XYZ轉換為HSV
void XYZ2HSV(double dX, double dY, double dZ,double &dH, double &dS, double &dV)
{
    double dR, dG, dB;
    XYZ2RGB(dX, dY, dZ, dR, dG, dB);
    RGB2HSV(dR, dG, dB, dH, dS, dV);
}

// LAB轉換為HSV
void LAB2HSV(double dL, double dA, double dB, double &dH, double &dS, double &dV)
{
    double dX, dY, dZ;
    LAB2XYZ(dL, dA, dB, dX, dY, dZ);
    XYZ2HSV(dX, dY, dZ, dH, dS, dV);
}


// RGB轉換為CMY
void RGB2CMY(double dR, double dG, double dB, double &dC, double &dM, double dY)
{
    dC = 1.0 - (dR / 255.0f);
    dM = 1.0 - (dG / 255.0f);
    dY = 1.0 - (dB / 255.0f);
}

//CMY轉換為RGB
void CMY2RGB(double dC, double dM, double dY, double &dR, double &dG, double &dB)
{
    dR = (1.0f - dC) * 255.0f;
    dG = (1.0f - dM) * 255.0f;
    dB = (1.0f - dY) * 255.0f;
}

//RGB轉換為CMYK
void RGB2CMYK(double dR, double dG, double dB, double &dC, double &dM, double dY, double &dK)
{
    // RGB2CMY
    RGB2CMY(dR, dG, dB, dC, dM, dY);
	
    //CMYK and CMY values from 0 to 1
    double dTempK = 1.0;

    if(dC < dTempK)
	{
        dTempK = dC;
	}
	
    if(dM < dTempK)
	{
        dTempK = dM;
	}

    if(dY < dTempK)
	{
        dTempK = dY;
	}
	
    if(1 == dTempK)
    { //Black
        dC = 0;
        dM = 0;
        dY = 0;
    }
    else 
    {
        dC = (dC - dTempK) / (1 - dTempK);
        dM = (dM - dTempK) / (1 - dTempK);
        dY = (dY - dTempK) / (1 - dTempK);
    }
	
    dK = dTempK;
}

// CMYK轉換為CMY
void CMYK2CMY(double dC1, double dM1, double dY1, double dK1, double &dC2, double &dM2, double dY2)
{
    dC2 = (dC1 * (1 - dK1) + dK1);
    dM2 = (dM1 * (1 - dK1) + dK1);
    dY2 = (dY1 * (1 - dK1) + dK1);
}

// RGB<-->HSL互轉描述, 我已驗證, 這個就是Windows顏色選擇對話方塊的顏色選擇轉換演算法

http://www.cnblogs.com/daiguagua/p/3311756.html