RGB与Lab颜色空间互相转换

一、RGB与Lab的区别

  RGB的是由红色通道(R)、绿色通道(G)、蓝色通道(B)组成的,最亮的红色+最亮的绿色+最亮的蓝色=白色;最暗的红色+最暗的绿色+最暗的蓝色=黑色;而在最亮和最暗之间,相同明暗度的红色+相同明暗度的绿色+相同明暗度的蓝色=灰色。在RGB的任意一个通道内,白和黑表示这个颜色的明暗度。所以,有白色或者灰白色的地方,R、G、B三个通道都不可能是黑色的,因为必须要有R、G、B三个通道来构成这些颜色。
  而LAB不一样,LAB中的明度通道(L)专门负责整张图的明暗度,简单的说就是整幅图的黑白版。a通道和b通道只负责颜色的多少。a通道表示从洋红色(通道里的白色)至深绿色(通道里的黑色)的范围;b表示从焦黄色(通道里的白色)至袅蓝色(通道里的黑色)的范围;a、b通道里的50%中性灰色表示没有颜色,所以越接近灰色说明颜色越少,而且a通道和b通道的颜色没有亮度。这就说明了为什么在a、b通道中红色T恤的轮廓是那么的清晰!因为红色是洋红色+焦黄色组成的。
总的来说:

  1. 适合RGB通道抠的图大部分LAB模式能完成,反之不成立。
  2. 任何单一色调背景下,用通道抠有明显颜色区别的部分,用LAB模式很快能完成
  3. LAB模式下对明度(L)通道做任何操作(如锐化、模糊等)不会影响到色相。

二、RGB转Lab颜色空间

RGB颜色空间不能直接转换为Lab颜色空间,需要借助XYZ颜色空间,把RGB颜色空间转换到XYZ颜色空间,之后再把XYZ颜色空间转换到Lab颜色空间。
在这里插入图片描述
仔细观察式(1),其中 X = 0.412453 * R + 0.357580 * G+ 0.180423 * B ; 各系数相加之和为0.950456,非常接近于1,我们知道R/G/B的取值范围为[ 0,255 ],如果系数和等于1,则X的取值范围也必然在[ 0,255 ]之间,因此我们可以考虑等比修改各系数,使其之和等于1,这样就做到了XYZ和RGB在同等范围的映射。这也就是为什么代码里X,Y,Z会分别除以0.950456、1.0、1.088754。
在这里插入图片描述

RGB2Lab关键代码实现:

//RGB2Lab Lab2RGB
const float param_13 = 1.0f / 3.0f;
const float param_16116 = 16.0f / 116.0f;
const float Xn = 0.950456f;
const float Yn = 1.0f;
const float Zn = 1.088754f;
 
 float gamma(float x)
  {
    
    
	  return x>0.04045?powf((x+0.055f)/1.055f,2.4f):(x/12.92);
  }; 
 
 void RGB2XYZ(T_U8 R, T_U8 G, T_U8 B, float *X, float *Y, float *Z)  
    {
    
      
	float RR = gamma(R/255.0);
	float GG = gamma(G/255.0);
	float BB = gamma(B/255.0);
 
        *X = 0.4124564f * RR + 0.3575761f * GG + 0.1804375f * BB;  
        *Y = 0.2126729f * RR + 0.7151522f * GG + 0.0721750f * BB;  
        *Z = 0.0193339f * RR + 0.1191920f * GG + 0.9503041f * BB;  
    }  
  
 
 
  void XYZ2Lab(float X, float Y, float Z, float *L, float *a, float *b)  
    {
    
      
        float fX, fY, fZ;  
      
        X /= (Xn);  
        Y /= (Yn);  
        Z /= (Zn);  
      
        if (Y > 0.008856f)  
	    fY = pow(Y, param_13);  	
        else  
	    fY = 7.787f * Y + param_16116;  
   
        if (X > 0.008856f)  
            fX = pow(X, param_13);  
        else  
            fX = 7.787f * X + param_16116;  
      
        if (Z > 0.008856)  
            fZ = pow(Z, param_13);  
        else  
            fZ = 7.787f * Z + param_16116;  
 
        *L = 116.0f * fY - 16.0f;
	*L = *L > 0.0f ? *L : 0.0f;   
        *a = 500.0f * (fX - fY);  
        *b = 200.0f * (fY - fZ);  
    }  
 
int RGB2Lab(IMAGE_TYPE *bmp_img,float *lab_img)
{
    
    
	DWORD width,height,index;
	WORD  biBitCount;
	T_U8 *dst,*bmp,R,G,B;
	float X,Y,Z,L,a,b;
	
	T_U32 line_byte;
	T_U16 i,j;
	
	BITMAPFILEHEADER bf;
	BITMAPINFOHEADER bi;
	
	memset(&bf, 0, sizeof(bf));
	memset(&bi, 0, sizeof(bi));
	
	bmp = bmp_img;
	memcpy(&bf,bmp,14);
	memcpy(&bi,&bmp[14],40);
	
	height = bi.biHeight;
	width  = bi.biWidth;
	biBitCount = bi.biBitCount;//每一个像素由24 bits表示,即RGB分量每一个分量用8 bits表示
	line_byte = WIDTHBYTES(width*bi.biBitCount);
 
	dst = bmp_img+BMPHEADSIZE;
	
	for (i = 0; i <height;i++)
	{
    
    
		for (j = 0;j < width;j++)
		{
    
    
			index = i*line_byte+3*j;
			B = dst[index];
			G = dst[index+1];
			R = dst[index+2];
 
			RGB2XYZ(R,G,B,&X,&Y,&Z);
			XYZ2Lab(X,Y,Z,&L,&a,&b);
 
			lab_img[index] = L;
			lab_img[index+1] = a;
			lab_img[index+2] = b;
		}
	}
    
	return 0;
 
}

三、Lab转RGB颜色空间

在这里插入图片描述
在这里插入图片描述

Lab2RGB关键代码实现:

extern const float param_13;
extern const float param_16116;
extern const float Xn;
extern const float Yn;
extern const float Zn;
 
 float gamma_XYZ2RGB(float x)
  {
    
    
	  return x>0.0031308?(1.055f*powf(x,(1/2.4f))-0.055):(x*12.92);
  };
 
void XYZ2RGB(float X, float Y, float Z, unsigned char*R, unsigned char*G, unsigned char*B)  
    {
    
           
	float RR , GG, BB ;
        RR =  3.2404542f * X - 1.5371385f * Y - 0.4985314f * Z;  
        GG = -0.9692660f * X + 1.8760108f * Y + 0.0415560f * Z;  
        BB =  0.0556434f * X - 0.2040259f * Y + 1.0572252f * Z;  
 
	RR = gamma_XYZ2RGB(RR);
	GG = gamma_XYZ2RGB(GG);
	BB = gamma_XYZ2RGB(BB);
 
        RR = CLIP255(RR*255.0+0.5);
        GG = CLIP255(GG*255.0+0.5);
        BB = CLIP255(BB*255.0+0.5);
 
        *R = (unsigned char)RR;  
        *G = (unsigned char)GG;  
        *B = (unsigned char)BB;  
    }  
      
  void Lab2XYZ(float L, float a, float b, float *X, float *Y, float *Z)  
    {
    
      
	float fX, fY, fZ;  
      
        fY = (L + 16.0f) / 116.0; 
	fX = a / 500.0f + fY;
	fZ = fY - b / 200.0f; 
 
	if(powf(fY,3.0)>0.008856)
	    *Y =powf(fY,3.0);
	else
	    *Y = (fY-param_16116)/7.787f;
		
        if (powf(fX,3) > 0.008856)  
            *X = fX * fX * fX;  
        else  
            *X = (fX - param_16116) / 7.787f;  
      
        if (powf(fZ,3.0) > 0.008856)  
            *Z = fZ * fZ * fZ;  
        else  
            *Z = (fZ - param_16116) / 7.787f;  
      
        (*X) *= (Xn);  
        (*Y) *= (Yn);  
        (*Z) *= (Zn); 
    }  
 
 
int Lab2RGB(IMAGE_TYPE *bmp_img,float *lab_img)
{
    
    
	DWORD width,height,index;
	WORD  biBitCount;
	T_U8 *bmp,R,G,B,*Lab2BMP;
	float X,Y,Z,L,a,b;
	
	T_U32 line_byte;
	T_U16 i,j;
	
	BITMAPFILEHEADER bf;
	BITMAPINFOHEADER bi;
 
	FILE *Lab2BMP_fp = fopen("Lab2BMP.bmp","wb");
	
	if(NULL == Lab2BMP_fp)
	{
    
    
		printf("Can't open Lab2BMP.bmp\n");
		return -1;
	}
	
	memset(&bf, 0, sizeof(bf));
	memset(&bi, 0, sizeof(bi));
 
	bmp = bmp_img;
	memcpy(&bf,bmp,14);
	memcpy(&bi,&bmp[14],40);
 
	height = bi.biHeight;
	width  = bi.biWidth;
	biBitCount = bi.biBitCount;//每一个像素由24 bits表示,即RGB分量每一个分量用8 bits表示
	line_byte = WIDTHBYTES(width*bi.biBitCount);
	
	fwrite(&bf,sizeof(BITMAPFILEHEADER),1,Lab2BMP_fp);
	fwrite(&bi,sizeof(BITMAPINFOHEADER),1,Lab2BMP_fp);
 
 
	Lab2BMP = (T_U8*)malloc(height*line_byte);
	if (Lab2BMP == NULL)
	{
    
    
		printf("Can't malloc LabBMP image.\n");
		return 0;
	}
	memset(Lab2BMP,0,height*line_byte);
 
	
	for (i = 0; i <height;i++)
	{
    
    
		for (j = 0;j < width;j++)
		{
    
    
			index = i*line_byte+3*j;
			L = lab_img[index];
			a = lab_img[index+1];
			b = lab_img[index+2];
 
			Lab2XYZ(L,a,b,&X,&Y,&Z);
			XYZ2RGB(X,Y,Z,&R,&G,&B);
		
 
			Lab2BMP[index] = B;
			Lab2BMP[index+1] = G;
			Lab2BMP[index+2] = R;
		}
	}
 
	fwrite(Lab2BMP, line_byte*height, 1, Lab2BMP_fp);
	fclose(Lab2BMP_fp);  
    free(Lab2BMP);
    
	return 0;
 
}

四、效果图

在这里插入图片描述

左侧图像是原始图像,右侧图像经过RGB->XYZ->LAB->XYZ->RGB的转换结果图。

猜你喜欢

转载自blog.csdn.net/qq_41731507/article/details/113871296