1.原理

RGB无法直接转换成LAB,需要先转换成XYZ再转换成LAB,即:RGB——XYZ——LAB

因此转换公式分两部分:

(1)RGB转XYZ

假设r,g,b为像素三个通道,取值范围均为[0,255],转换公式如下:

    (1)

    (2)

    (3)

M=

0.4124,0.3576,0.1805

0.2126,0.7152,0.0722

0.0193,0.1192,0.9505

等同于如下公式:

X = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805
Y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722
Z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505

上面的gamma函数,是用来对图象进行非线性色调编辑的,目的是提高图像对比度。这个函数不是唯一的,但是我在网上查到的基本都使用上式。

(2)XYZ转LAB

    (5)

    (6)

上面两个公式中,L*,a*,b*是最终的LAB色彩空间三个通道的值。X,Y,Z是RGB转XYZ后计算出来的值,Xn,Yn,Zn一般默认是95.047,100.0,108.883。

 

2.代码实现

(1)完全按照算法无优化实现(经@竹子小蜻蜓指正,原来代码有误,现已改正--206.04.12)

inline float gamma(float x)
{return x>0.04045?pow((x+0.055f)/1.055f,2.4f):x/12.92;}; void RGBToLab(unsigned char*rgbImg,float*labImg)
{
float B=gamma(rgbImg[]/255.0f);
float G=gamma(rgbImg[]/255.0f);
float R=gamma(rgbImg[]/255.0f);
float X=0.412453*R+0.357580*G+0.180423*B;
float Y=0.212671*R+0.715160*G+0.072169*B;
float Z=0.019334*R+0.119193*G+0.950227*B;   float X/=0.95047;
  float Y/=1.0;
  float Z/=1.08883;
float FX = X > 0.008856f ? pow(X,1.0f/3.0f) : (7.787f * X +0.137931f);
float FY = Y > 0.008856f ? pow(Y,1.0f/3.0f) : (7.787f * Y +0.137931f);
float FZ = Z > 0.008856f ? pow(Z,1.0f/3.0f) : (7.787f * Z +0.137931f);
labImg[] = Y > 0.008856f ? (116.0f * FY - 16.0f) : (903.3f * Y);
labImg[] = .f * (FX - FY);
labImg[] = .f * (FY - FZ);
}

上面是完全按照转换算法做的无优化的实现,里面涉及了大量的浮点运算,在PC上可能没什么问题,但是如果是在Android操作系统的移动端上,即使利用JNI,把转换算法写成C++版本进行加速,速度也不理想,因为这个操作时逐像素的,每个像素做几十次浮点运算,耗时还是十分巨大的。

(2)牺牲一些精度的快速实现

首先可以把gamma函数去掉,因为经过我的测试,这个函数带来的影响很小。

其次,M矩阵中的值都为小数,可以通过放大变成整数,接下来的计算就可以变成整数计算(在手机上浮点计算一般耗时是整形计算的几倍)。在这里,可以把M矩阵的值都扩大2^20倍变为整数,在计算得到X,Y,Z分量时再缩小回来。但是,XYZ的小数部分会消失,会引入误差,而在公式(5)(6)中(尤其是(6),涉及到指数运算和阈值运算,之前XYZ的误差在这里会被放大),这种误差还会继续传递给最终的L,a,b值。那怎么才能保证一定的准确率呢?

在这里我的方法是引入了一个查表机制。过程如下:

A.在计算XYZ的时候,参数扩大2^20倍,但最后缩小时只缩小2^18,这样计算出来的XYZ值范围是[0,1023]

B.建立一个table,用于将取值为[0,1023]的XYZ通过f(t)函数映射到中间结果,记为:LabTable(m)

C.将LabTable(m)代入公式(5)计算最终的Lab分量值

代码如下:

const static int big_shift=;
const static int HalfShiftValue=;
const static int shift=;
const static int offset=<<shift;
const static int ScaleLC = ( * ( << shift));
const static int ScaleLT = ;
const static int ScaleY= ;
const static int para1=;
const static int para2=;
const static int ThPara=9; void RGBToLab(unsigned char*rgbImg,int*labImg)
{
long long X=(rgbImg[] * + rgbImg[] * + rgbImg[] * + )>> (big_shift);
long long Y=(rgbImg[] * + rgbImg[] * + rgbImg[] * + ) >> (big_shift);
long long Z=(rgbImg[] * + rgbImg[] * + rgbImg[] * + ) >> (big_shift); labImg[] = Y>ThPara?((ScaleLT * LabTable[Y] - ScaleLC + HalfShiftValue)>>shift):((ScaleY* Y)>>shift);
labImg[] = (para1*(LabTable[X] - LabTable[Y])+HalfShiftValue+offset)>>shift;
labImg[] = (para2*(LabTable[Y] - LabTable[Z])+HalfShiftValue+offset)>>shift;
}

建立LabTable的代码如下:

int LabTable[];
for (int I = ; I < ; I++)
{
if (I > )
LabTable[I] = (int)(pow((float)I / , 1.0F / ) * ( << ) + 0.5 );
else
LabTable[I] = (int)(( * 29.0 * I / ( * * * ) + 4.0 / ) * ( << ) + 0.5 );
printf("%d,",LabTable[I]);
}

参考文章:

http://www.easyrgb.com/index.php?X=MATH&H=07#text7

http://vcsos.com/Article/pageSource/120314/20120314114422.shtml

http://www.cnblogs.com/Imageshop/archive/2013/01/31/2888097.html

http://www.cnblogs.com/Imageshop/archive/2013/02/02/2889897.html

RGB转LAB色彩空间的更多相关文章

  1. RGB转为Lab空间

    虽然若干年前就看过了关于色彩空间的介绍,但是直到今天才自己动手写代码做这件事情.虽然网络上已经有很多现成的例子,但是一则仅仅适用于浮点型的数据,另一方面,在实现上也有一些尚可优化之处. 色彩模型除了最 ...

  2. 基于MATLAB的RGB转YCBCR色彩空间转换

    使用MATLAB进行图片的处理十分方便,看它的名字就知道了,矩阵实验室(matrix laboratory).一副图片的像素数据可以看成是一个二维数组一个大矩阵,MTABLAB就是为矩阵运算而生. M ...

  3. OpenCV源码分析:RGB到其他色彩空间的转换

    1.流程调用图 2.部分代码分析 //模板函数进行颜色空间的转换 template <typename Cvt> void CvtColorLoop(const Mat& src, ...

  4. lab 颜色模式的生理原因 黄色, 洋红色 刺眼。 绿色,蓝色,不刺眼。

    hsb 颜色模式理解了. lab 颜色模式,都说是生理原因.没说是啥生理原因. 猜测:黄色, 洋红色 刺眼.   绿色,蓝色,不刺眼. https://blog.csdn.net/self_mind/ ...

  5. KVO 进阶

    Key-value coding (KVC) 和 key-value observing (KVO) 是两种能让我们驾驭 Objective-C 动态特性并简化代码的机制.在这篇文章里,我们将接触一些 ...

  6. 视觉显著性简介 Saliency Detection

    内容转移到博客文章系列:显著性检测 1.简介 视觉显著性包括从下而上和从上往下两种机制.从下而上也可以认为是数据驱动,即图像本身对人的吸引,从上而下则是在人意识控制下对图像进行注意.科研主要做的是从下 ...

  7. 人脸检测(1)——HOG特征

    一.概述 前面一个系列,我们对车牌识别的相关技术进行了研究,但是车牌识别相对来说还是比较简单的,后续本人会对人脸检测.人脸识别,人脸姿态估计和人眼识别做一定的学习和研究.其中人脸检测相对来说比较简单, ...

  8. Atitit  rgb yuv  hsv HSL 模式和 HSV(HSB) 图像色彩空间的区别

    Atitit  rgb yuv  hsv HSL 模式和 HSV(HSB) 图像色彩空间的区别 1.1. 色彩的三要素 -- 色相.明度.纯度1 1.2. YUV三个字母中,其中"Y&quo ...

  9. 颜色空间模型(HSV\LAB\RGB\CMYK)

    通过Photoshop的拾色器,我们知道表征颜色的模型的不止一种,本文将系统并且详细讨论这四种模型(HSV.LAB.RGB和CMYK)之间的联系以及应用.本文部分章节整合了多位优秀博主的博客(链接见本 ...

随机推荐

  1. S3C2440的七种模式之——未定义模式(去掉bl print1 bug解决)

    现在做第一个实验,模拟未定义模式. 未定义模式,是cpu遇到自己不能识别的指令时候做出的异常处理. arm指令的机器码一定是按照某种规范要求的,不然你随意写一条指令,cpu不是都可以执行吗?在cpu没 ...

  2. Git pull error: Your local changes to the following files would be overwritten by merge:

    联合开发,遇上的一个问题,果然,在此验证了百度的不靠谱,是谷歌出的答案...... stackoverflow上有解决方案,链接:http://stackoverflow.com/questions/ ...

  3. 基于jQuery仿QQ音乐播放器网页版代码

    基于jQuery仿QQ音乐播放器网页版代码是一款黑色样式风格的网页QQ音乐播放器样式代码.效果图如下: 在线预览   源码下载 实现的代码. html代码: <div class="m ...

  4. J.U.C--locks--AQS分析

    看一下AbstractQueuedSynchronizer(下面简称AQS)的子类就行知道,J.U.C中宣传的封装良好的同步工具类Semaphore.CountDownLatch.ReentrantL ...

  5. Docker之宿主机ssh至docker容器

    下载docker: https://www.docker.com/products/overview 下载镜像: docker pull centos 查看镜像:docker images 创建镜像对 ...

  6. layer.open如何关闭自身弹出窗口

    1. 弹出窗口中本身可以添加按钮事件如下: layer.open({ title: '打印' ,type: 2 ,content: [ctx + '/saleOrder/eorderEdit?orde ...

  7. hbase1.4.0安装和使用

    jia下载地址:  http://mirrors.shuosc.org/apache/hbase/1.4.0/ 解压 tar -zxvf hbase-1.4.0-bin.tar.gz 修改环境变量 [ ...

  8. AD集成库元件简写中英文对照表

    序号 英文简写 元件英文名 元件中文名 1 Res semi Semiconductor Resistor 半导体电阻 2 Cap semi Semiconductor Capacitor 半导体电容 ...

  9. Error:不能将"char*"类型的值分配到"LPSTR"类型的实体 也许 "char*"类型的实参与"LPCWSTR"类型的形参不兼容

    http://www.myexception.cn/ruby-rails/1876106.html 选择“XXX项目”->“属性”->“配置属性”->“常规”选项中,把“使用 Uni ...

  10. PHP数组缓存:三种方式JSON、序列化和var_export的比较

    使用PHP的站点系统,在面对大数据量的时候不得不引入缓存机制.有一种简单有效的办法是将PHP的对象缓存到文件里.下面我来对这3种缓存方法进行说明和比较. 第一种方法:JSONJSON缓存变量的方式主要 ...