C语言实现RGB565转LAB色彩空间(RT1064 + 凌瞳)

前言

生活中我们使用RGB颜色空间更多一些,但在计算机视觉中,尤其颜色识别相关的算法设计中,rgb,hsv,lab颜色空间混用是常用的方法。由于本人去年用过OPENMV,其IDE里有着极为方便使用的LAB阈值编辑器,所以选择将RGB565格式的图片转成LAB,再进行后续的处理。

关于凌瞳

15届全国大学生智能车竞赛即将到来,逐飞新出品了一款名为“凌瞳”的彩色摄像头,分辨率最高可达VGA(480*640),使用RT1064的CSI接口采集图像,帧率最高可达60。它支持RGB565,YUV422的图像格式。它的sensor型号成谜,逐飞的店主曾经委婉提及他们试用了十多款sensor才选定的这个scc8660。以我的好奇心当然是要搜一下的,不过百度谷歌都无果,在逐飞群里问了一下,没一个人理。时隔多日有人在群里问,这是逐飞自己编出来的名字吗?我随即附和,却没想到二石不能激起一层浪,罢了。

RGB转Lab颜色空间

RGB颜色空间不能直接转换为Lab颜色空间,需要借助XYZ颜色空间,把RGB颜色空间转换到XYZ颜色空间,之后再把XYZ颜色空间转换到Lab颜色空间。

关于RGB565

RGB565,顾名思义,16位数据,分别5,6,5位是R,G,B分量。

获取R,G,B

img_show[i][j]=scc8660_csi_image[i][j];
      r=(img_show[i][j]&0Xf800)>>11;
      g=(img_show[i][j]&0X07e0)>>5;
      b=(img_show[i][j]&0X001f);

按理说数据高八位应该在数据低八位,上面的代码却没有执行高低八位换位的操作,是因为在摄像头的配置文件中,有这样一个数据,默认0改为1即可。

{SCC8660_DATA_FORMAT,1}//输出数据格式 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY)

RGB->XYZ

此处参考handspeaker的博客


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

XYZ->LAB

L = 116 f ( Y 1 ) 16 L = 116 * f(Y1) - 16
A = 500 ( f ( X / X n ) f ( Y / Y n ) ) A = 500 * (f(X/Xn) - f(Y/Yn))
B = 200 ( f ( Y 1 ) f ( Z 1 ) ) B = 200 * (f(Y1) - f(Z1))

Xn,Yn,Zn一般默认是95.047,100.0,108.883。

代码实现

无任何优化的代码

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[0]/255.0f);
    float G=gamma(rgbImg[1]/255.0f);
    float R=gamma(rgbImg[2]/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[0] = Y > 0.008856f ? (116.0f * FY - 16.0f) : (903.3f * Y);
    labImg[1] = 500.f * (FX - FY);
    labImg[2] = 200.f * (FY - FZ);
}

移植、优化和修改

可以看出handspeaker的代码是基于RGB888格式的,而凌瞳是RGB565,需要做一定的修改。另一方面,将gama和f(t)运算简化为查表运算,将浮点数转换为大整形,将乘除法转换为移位操作。具体代码如下:

static int LabTable[1024];
static int GamaTable1[32];
static int GamaTable2[64];//B有6位,特殊对待
void CreateTable()//建表
{
  for (int I = 0; I < 1024; I++)
  {
    if (I > 9)
      LabTable[I] = (int)(pow((float)I / 1024, 1.0F / 3.0F) * 1024 );
    else
      LabTable[I] = (int)(7.787F * I + 141.2 );
  }
  for (int J = 0; J < 32; J++)
  {
    float x = J/32.0F;
    x = x>0.04045?pow((x+0.055f)/1.055f,2.4f):x/12.92;
    GamaTable1[J] = (int)(x*1024);
  }
  for (int K = 0; K < 64; K++)
  {
    float y = K/64.0F;
    y = y>0.04045?pow((y+0.055f)/1.055f,2.4f):y/12.92;
    GamaTable2[K] = (int)(y*1024);
  }
}
x=(455026*GamaTable1[r]+394489*GamaTable2[g]+199046*GamaTable1[b])>>20;
y=(223002*GamaTable1[r]+749900*GamaTable2[g]+75675*GamaTable1[b])>>20;
z=(18619*GamaTable1[r]+114786*GamaTable2[g]+915097*GamaTable1[b])>>20;
L = y > 9 ? (116 * LabTable[y] - 16384)>> 10: (903 * LabTable[y])>> 10;
A = (500 * (LabTable[x] - LabTable[y]))>> 10;
B = (200 * (LabTable[y] - LabTable[z]))>> 10;

总结

前期利用image2lcd软件进行图片的取模和显示,在dev c++上调试代码 ,可以一步步看到结果。调好的代码再移植到RT1064上,效率很高,一次成功。
优化部分已经做到了最佳,比未优化算法快上百倍,运行时间可以说是忽略不计,非常满意。

发布了1 篇原创文章 · 获赞 0 · 访问量 123

猜你喜欢

转载自blog.csdn.net/weixin_44349732/article/details/104062757