1 CSC基本实现

根据前一篇CSC转换的文档了解到,RGB与YUV的变换公式如下:

YCbCr(256 级别) 可以从8位 RGB 直接计算,计算公式如下:

Y = 0.299 R + 0.587 G + 0.114 B

Cb = - 0.1687 R - 0.3313 G + 0.5 B + 128

Cr = 0.5 R - 0.4187 G - 0.0813 B + 128

反过来,RGB 也可以直接从YUV (256级别) 计算:

R = Y + 1.402 (Cr-128)

G = Y - 0.34414 (Cb-128) - 0.71414 (Cr-128)

B = Y + 1.772 (Cb-128)

YUV格式比较多,下面以YV12格式为例,说明YV12格式转化成RGB24格式的方法。其基本思路:按照RGB与YUV的变换公式进行逐像素的计算,但具体实现过程中,优化方法和技巧影响最终的转换效率。说明:为了方便查看转换后的结果,在实现过程中,是BGR24格式代替RGB24格式,其转换过程是不变。具体实现如下:

 bool YV12ToBGR24_Native(unsigned char* pYUV,unsigned char* pBGR24,int width,int height)
{
if (width < || height < || pYUV == NULL || pBGR24 == NULL)
return false;
const long len = width * height;
unsigned char* yData = pYUV;
unsigned char* vData = &yData[len];
unsigned char* uData = &vData[len >> ]; int bgr[];
int yIdx,uIdx,vIdx,idx;
for (int i = ;i < height;i++){
for (int j = ;j < width;j++){
yIdx = i * width + j;
vIdx = (i/) * (width/) + (j/);
uIdx = vIdx; bgr[] = (int)(yData[yIdx] + 1.732446 * (uData[vIdx] - )); // b分量
bgr[] = (int)(yData[yIdx] - 0.698001 * (uData[uIdx] - ) - 0.703125 * (vData[vIdx] - )); // g分量
bgr[] = (int)(yData[yIdx] + 1.370705 * (vData[uIdx] - )); // r分量 for (int k = ;k < ;k++){
idx = (i * width + j) * + k;
if(bgr[k] >= && bgr[k] <= )
pBGR24[idx] = bgr[k];
else
pBGR24[idx] = (bgr[k] < )?:;
}
}
}
return true;
}

2 基于查表法优化

逐一访问像素,进行浮点运算,比较耗时,因而利用空间换时间思路,以查找表来替代转换过程中的一些计算。具体实现如下:

 static int Table_fv1[] = { -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -,  -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -,  -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -,-, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -,  -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,  , , , , , , , , , , , , , , , , , , , ,  };
static int Table_fv2[] = { -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , };
static int Table_fu1[] = { -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , };
static int Table_fu2[] = { -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, -, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }; bool YV12ToBGR24_Table(unsigned char* pYUV,unsigned char* pBGR24,int width,int height)
{
if (width < || height < || pYUV == NULL || pBGR24 == NULL)
return false;
const long len = width * height;
unsigned char* yData = pYUV;
unsigned char* vData = &yData[len];
unsigned char* uData = &vData[len >> ]; int bgr[];
int yIdx,uIdx,vIdx,idx;
int rdif,invgdif,bdif;
for (int i = ;i < height;i++){
for (int j = ;j < width;j++){
yIdx = i * width + j;
vIdx = (i/) * (width/) + (j/);
uIdx = vIdx; rdif = Table_fv1[vData[vIdx]];
invgdif = Table_fu1[uData[uIdx]] + Table_fv2[vData[vIdx]];
bdif = Table_fu2[uData[uIdx]]; bgr[] = yData[yIdx] + bdif;
bgr[] = yData[yIdx] - invgdif;
bgr[] = yData[yIdx] + rdif; for (int k = ;k < ;k++){
idx = (i * width + j) * + k;
if(bgr[k] >= && bgr[k] <= )
pBGR24[idx] = bgr[k];
else
pBGR24[idx] = (bgr[k] < )?:;
}
}
}
return true;
}

3 基于opencv优化

利用OpenCV提供的转换函数实现YUV到RGB的转换,实现简单方便。实现过程,只需要合理构造包含YUV数据的Mat,具体实现方法如下:

 bool YV12ToBGR24_OpenCV(unsigned char* pYUV,unsigned char* pBGR24,int width,int height)
{
if (width < || height < || pYUV == NULL || pBGR24 == NULL)
return false;
Mat dst(height,width,CV_8UC3,pBGR24);
Mat src(height + height/,width,CV_8UC1,pYUV);
cvtColor(src,dst,CV_YUV2BGR_YV12);
return true;
}

4 基于FFmpeg优化

利用FFmpeg中swscale实现YUV到RGB的转换,实现过程中,需要构造AVPicture结构,具体实现方法如下:

 bool YV12ToBGR24_FFmpeg(unsigned char* pYUV,unsigned char* pBGR24,int width,int height)
{
if (width < || height < || pYUV == NULL || pBGR24 == NULL)
return false;
//int srcNumBytes,dstNumBytes;
//uint8_t *pSrc,*pDst;
AVPicture pFrameYUV,pFrameBGR; //pFrameYUV = avpicture_alloc();
//srcNumBytes = avpicture_get_size(PIX_FMT_YUV420P,width,height);
//pSrc = (uint8_t *)malloc(sizeof(uint8_t) * srcNumBytes);
avpicture_fill(&pFrameYUV,pYUV,PIX_FMT_YUV420P,width,height); //U,V互换
uint8_t * ptmp=pFrameYUV.data[];
pFrameYUV.data[]=pFrameYUV.data[];
pFrameYUV.data []=ptmp; //pFrameBGR = avcodec_alloc_frame();
//dstNumBytes = avpicture_get_size(PIX_FMT_BGR24,width,height);
//pDst = (uint8_t *)malloc(sizeof(uint8_t) * dstNumBytes);
avpicture_fill(&pFrameBGR,pBGR24,PIX_FMT_BGR24,width,height); struct SwsContext* imgCtx = NULL;
imgCtx = sws_getContext(width,height,PIX_FMT_YUV420P,width,height,PIX_FMT_BGR24,SWS_BILINEAR,,,); if (imgCtx != NULL){
sws_scale(imgCtx,pFrameYUV.data,pFrameYUV.linesize,,height,pFrameBGR.data,pFrameBGR.linesize);
if(imgCtx){
sws_freeContext(imgCtx);
imgCtx = NULL;
}
return true;
}
else{
sws_freeContext(imgCtx);
imgCtx = NULL;
return false;
}
}

5 基于Pinknoise实现

下载上述网站提供的yuv2rgb代码,利用yuv420_2_rgb888函数即可实现YUV到RGB的转换

 bool YV12ToBGR24_Pinknoise(unsigned char* pYUV,unsigned char* pBGR24,int width,int height)
{
if (width < || height < || pYUV == NULL || pBGR24 == NULL)
return false;
unsigned char *yData = pYUV;
unsigned char *vData = &pYUV[width * height];
unsigned char *uData = &vData[width * height >> ];
yuv420_2_rgb888(pBGR24,yData,uData,vData,width,height,width,width>>,width*,yuv2rgb565_table,);
return true;
}

6 基于移位操作实现

在牺牲一定精度前提下,RGB2YUV和YUV2RGB的转换如下:

RGB转YUV:

Y = ((R << 6) + (R << 3) + (R << 2) + R + (G << 7) + (G << 4) + (G << 2) + (G << 1) + (B << 4) + (B << 3) + (B << 2) + B) >> 8;

U = (-((R << 5) + (R << 2) + (R << 1)) - ((G << 6) + (G << 3) + (G << 1)) + ((B << 6) + (B << 5) + (B << 4))) >> 8;

V = ((R << 7) + (R << 4) + (R << 3) + (R << 2) + (R << 1) - ((G << 7) + (G << 2)) - ((B << 4) + (B << 3) + (B << 1))) >> 8;

YUV转RGB:

R   = ((Y << 8) + ((V << 8) + (V << 5) + (V << 2))) >> 8;
G = ((Y << 8) - ((U << 6) + (U << 5) + (U << 2)) - ((V << 7) + (V << 4) + (V << 2) + V)) >> 8;

B = ((Y << 8) + (U << 9) + (U << 3)) >> 8;

根据上述公式,具体实现如下:

static void RGBToYUV(int Red, int Green, int Blue, int* Y,int* U,int* V)
{
    *Y = ((Red << 6) + (Red << 3) + (Red << 2) + Red + (Green << 7) + (Green << 4) + (Green << 2) + (Green << 1) + (Blue << 4) + (Blue << 3) + (Blue << 2) + Blue) >> 8;
    *U = (-((Red << 5) + (Red << 2) + (Red << 1)) - ((Green << 6) + (Green << 3) + (Green << 1)) + ((Blue << 6) + (Blue << 5) + (Blue << 4))) >> 8;
    *V = ((Red << 7) + (Red << 4) + (Red << 3) + (Red << 2) + (Red << 1) - ((Green << 7) + (Green << 2)) - ((Blue << 4) + (Blue << 3) + (Blue << 1))) >> 8;
};
static void YUVToRGB(int Y, int U, int V, int* Red, int* Green, int* Blue)
{
    *Red   = ((Y << 8) + ((V << 8) + (V << 5) + (V << 2))) >> 8;
    *Green = ((Y << 8) - ((U << 6) + (U << 5) + (U << 2)) - ((V << 7) + (V << 4) + (V << 2) + V)) >> 8;  
    *Blue = ((Y << 8) + (U << 9) + (U << 3)) >> 8;
};

7 各版本性能分析

测试序列:1920*1080(基于移位操作实现不参与对比)

测试环境:OpenCV2.4.8, FFmpeg2.0, YUV2RGB v0.03

由上述表格可以看出,基于FFmpeg的格式转换效率最高,利用查找表法可以提高转换效率,但基于查找表法的转换效率有待进一步优化提升。

后续应关注于FFmpeg其格式转换的算法实现,抽取其实现代码,使格式转换不依赖于FFmpeg库。

9 参考链接

(1) http://www.cnblogs.com/dwdxdy/p/3713990.html

(2) http://www.cnblogs.com/qiqibaby/p/8608893.html

(3) http://blog.csdn.net/Trent1985/article/details/52053397

图像处理之CSC性能优化(源码)的更多相关文章

  1. JDK1.7中HashMap死环问题及JDK1.8中对HashMap的优化源码详解

    一.JDK1.7中HashMap扩容死锁问题 我们首先来看一下JDK1.7中put方法的源码 我们打开addEntry方法如下,它会判断数组当前容量是否已经超过的阈值,例如假设当前的数组容量是16,加 ...

  2. 红外图像处理之直方图均衡的matlab源码与效果验证

    红外图像是热辐射成像,由于场景中的目标与背景的温差相对较小,红外图像的动态范围大.对比度 低, 信噪比也较可见光图像的低.为了能够从红外图像中正确地识别出目标,必须对红外图像进行增强处理.一般红外探测 ...

  3. JVM性能优化--字节码技术

    一.字节码技术应用场景 AOP技术.Lombok去除重复代码插件.动态修改class文件等 二.字节技术优势 Java字节码增强指的是在Java字节码生成之后,对其进行修改,增强其功能,这种方式相当于 ...

  4. Node 进阶:express 默认日志组件 morgan 从入门使用到源码剖析

    本文摘录自个人总结<Nodejs学习笔记>,更多章节及更新,请访问 github主页地址.欢迎加群交流,群号 197339705. 章节概览 morgan是express默认的日志中间件, ...

  5. Session获取不到的情况及解决办法(源码解析)

    本博客是自己在学习和工作途中的积累与总结,仅供自己参考,也欢迎大家转载,转载时请注明出处,请尊重他人努力成果,谢谢. 1. 当有连个sessionFactory时,容易产生获取不到session的情况 ...

  6. 将AOSP源码导入到Android Studio进行查看

    生成iml和ipr文件 source build/envsetup.sh lunch aosp_x86-eng # 或者直接输入lunch,然后选择对应的target make idegen deve ...

  7. LRU工程实现源码(一):Redis 内存淘汰策略

    目录 内存淘汰是什么?什么时候内存淘汰 内存淘汰策略 Redis中的LRU淘汰算法 源码剖析 第一步:什么时候开始淘汰key 配置读取 检查时机 getMaxmemoryState 第二步:淘汰哪些k ...

  8. Android布局性能优化—从源码角度看ViewStub延迟加载技术

    在项目中,难免会遇到这种需求,在程序运行时需要动态根据条件来决定显示哪个View或某个布局,最通常的想法就是把需要动态显示的View都先写在布局中,然后把它们的可见性设为View.GONE,最后在代码 ...

  9. Java开源生鲜电商平台-性能优化以及服务器优化的设计与架构(源码可下载)

    Java开源生鲜电商平台-性能优化以及服务器优化的设计与架构(源码可下载) 说明:Java开源生鲜电商平台-性能优化以及服务器优化的设计与架构,我采用以下三种维度来讲解 1.  代码层面. 2.  数 ...

随机推荐

  1. JDK8 metaspace调优

    从JDK8开始,永久代(PermGen)的概念被废弃掉了,取而代之的是一个称为Metaspace的存储空间.Metaspace使用的是本地内存,而不是堆内存,也就是说在默认情况下Metaspace的大 ...

  2. 王者荣耀交流协会PSP Daily项目Postmortem结果

    王者荣耀交流协会PSP Daily项目Postmortem结果 整理:王超 设想和目标 1.       我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? PSP D ...

  3. 第二阶段Sprint冲刺会议10

    进展:把所有功能整合到主界面,结果导致视频只能播放不能录制,闹钟加不进去,导致闹钟功能差点不能用,放弃整合.

  4. 冲刺One之站立会议5 /2015-5-18

    2015-5-18 服务器部分大体已经完工,现在我们主要是在把登陆界面和服务器组装起来,这个过程是很让人头痛的,以为其中涉及到了很多网络协议.网络编程的知识,由于之前我们没有接触过所以实现起来会觉得很 ...

  5. css布局 弹性布局 和 网格布局

    这里就不写这两种布局的内容了 弹性布局链接:http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html 网格布局链接:https://www.ji ...

  6. js 杂项(一)函数篇

    你还应该知道箭头函数( => )可以用来保留上下文.这个方法也可以:

  7. iOS成长之路-使用系统默认声音、震动

    导入框架 代码片段 apple系统默认声音名称说明: 1.声音格式是MP3或m4r的需要转成caf格式(可先转成aif , aiff,然后修改后缀) 2.路径在/System/Library/Audi ...

  8. cobbler技术详解(是PXE二次详解)

    Cobbler是PXE的二次封装,使用Python语言开发, 可以用来快速建立 Linux 网络安装环境,它已将 Linux 网络安装的技术门槛,从大专以上文化水平,成功降低到初中以下,连补鞋匠都能学 ...

  9. Gulp插件笔记

    初次接触Gulp是出于网页模块化的需要,用过之后发现这个任务管理工具有很多实用的插件,意外地好用,于是打算写下这篇笔记把用到的Gulp插件记录一下.至于想了解Gulp基本用法的同学可以去Gulp官网查 ...

  10. 使用GatewayWorker 开发个即时聊天demo

    前言: 上手册以示尊重:https://www.kancloud.cn/walkor/gateway-worker/326138: https://www.cnblogs.com/fuqiang88/ ...