zoukankan      html  css  js  c++  java
  • rgb2yuv

    1.rgb2yuv422p

    代码的运算速度取决于以下几个方面

    1、 算法本身的复杂度,比如MPEG比JPEG复杂,JPEG比BMP图片的编码复杂。

    2、 CPU自身的速度和设计架构

    3、 CPU的总线带宽

    4、 您自己代码的写法

    将RGB格式的彩色图像先转换成YUV图像。

    图像转换的公式如下:

    Y = 0.299 * R + 0.587 * G + 0.114 * B;

    图像尺寸640*480*24bit,RGB图像已经按照RGBRGB顺序排列的格式,放在内存里面了。

    以下是输入和输出的定义:

    #define XSIZE 640

    #define YSIZE 480

    #define IMGSIZE XSIZE * YSIZE

    typedef struct RGB

    {

    unsigned char R;

    unsigned char G;

    unsigned char B;

    }RGB;

    struct RGB in[IMGSIZE]; //需要计算的原始数据

    unsigned char out[IMGSIZE]; //计算后的结果

    第一个优化

    优化原则:图像是一个2D数组,我用一个一维数组来存储。编译器处理一维数组的效率要高过二维数组。

    先写一个代码:

    Y = 0.299 * R + 0.587 * G + 0.114 * B;

    void calc_lum()

    {

    int i;

    for(i = 0; i < IMGSIZE; i++)

    {

    double r,g,b,y;

    unsigned char yy;

    r = in[i].r;

    g = in[i].g;

    b = in[i].b;

    y = 0.299 * r + 0.587 * g + 0.114 * b;

    yy = y;

    out[i] = yy;

    }

    }

    这大概是能想得出来的最简单的写法了,实在看不出有什么毛病,好了,编译一下跑一跑吧。

    第一次试跑

    这个代码分别用vc6.0和gcc编译,生成2个版本,分别在pc上和我的embedded system上面跑。

    速度多少?

    在PC上,由于存在硬件浮点处理器,CPU频率也够高,计算速度为20秒。

    我的embedded system,没有以上2个优势,浮点操作被编译器分解成了整数运算,运算速度为120秒左右。

    去掉浮点运算

    上面这个代码还没有跑,我已经知道会很慢了,因为这其中有大量的浮点运算。只要能不用浮点运算,一定能快很多。

    Y = 0.299 * R + 0.587 * G + 0.114 * B;

    这个公式怎么能用定点的整数运算替代呢?

    0.299 * R可以如何化简?

    Y = 0.299 * R + 0.587 * G + 0.114 * B;

    Y = D + E + F;

    D = 0.299 * R;

    E = 0.587 * G;

    F = 0.114 * B;

    我们就先简化算式D吧!

    RGB的取值范围都是0~255,都是整数,只是这个系数比较麻烦,不过这个系数可以表示为:0.299 = 299 / 1000;

    所以 D = ( R * 299) / 1000;

    Y = (R * 299 + G * 587 + B * 114) / 1000;

    这一下,能快多少呢?

    Embedded system上的速度为45秒;

    PC上的速度为2秒;

    0.299 * R可以如何化简

    Y = 0.299 * R + 0.587 * G + 0.114 * B;

    Y = (R * 299 + G * 587 + B * 114) / 1000;

    这个式子好像还有点复杂,可以再砍掉一个除法运算。

    前面的算式D可以这样写:

    0.299=299/1000=1224/4096

    所以 D = (R * 1224) / 4096

    Y=(R*1224)/4096+(G*2404)/4096+(B*467)/4096

    再简化为:

    Y=(R*1224+G*2404+B*467)/4096

    这里的/4096除法,因为它是2的N次方,所以可以用移位操作替代,往右移位12bit就是把某个数除以4096了。

    void calc_lum()

    {

    int i;

    for(i = 0; i < IMGSIZE; i++)

    {

    int r,g,b,y;

    r = 1224 * in[i].r;

    g = 2404 * in[i].g;

    b = 467 * in[i].b;

    y = r + g + b;

    y = y >> 12; //这里去掉了除法运算

    out[i] = y;

    }

    }

    这个代码编译后,又快了20%。

    虽然快了不少,还是太慢了一些,20秒处理一幅图像,地球人都不能接受。

    仔细端详一下这个式子!

    Y = 0.299 * R + 0.587 * G + 0.114 * B;

    Y=D+E+F;

    D=0.299*R;

    E=0.587*G;

    F=0.114*B;

    RGB的取值有文章可做,RGB的取值永远都大于等于0,小于等于255,我们能不能将D,E,F都预先计算好呢?然后用查表算法计算呢?

    我们使用3个数组分别存放DEF的256种可能的取值,然后。。。

    查表数组初始化

    int D[256],F[256],E[256];

    void table_init()

    {

    int i;

    for(i=0;i<256;i++)

    {

    D[i]=i*1224;

    D[i]=D[i]>>12;

    E[i]=i*2404;

    E[i]=E[i]>>12;

    F[i]=i*467;

    F[i]=F[i]>>12;

    }

    }

    void calc_lum()

    {

    int i;

    for(i = 0; i < IMGSIZE; i++)

    {

    int r,g,b,y;

    r = D[in[i].r];//查表

    g = E[in[i].g];

    b = F[in[i].b];

    y = r + g + b;

    out[i] = y;

    }

    }

    这一次的成绩把我吓出一身冷汗,执行时间居然从30秒一下提高到了2秒!在PC上测试这段代码,眼皮还没眨一下,代码就执行完了。一下提高15倍,爽不爽?

    继续优化
    很多embedded system的32bit CPU,都至少有2个ALU,能不能让2个ALU都跑起来?

    void calc_lum()

    {

    int i;

    for(i = 0; i < IMGSIZE; i += 2) //一次并行处理2个数据

    {

    int r,g,b,y,r1,g1,b1,y1;

    r = D[in[i].r];//查表 //这里给第一个ALU执行

    g = E[in[i].g];

    b = F[in[i].b];

    y = r + g + b;

    out[i] = y;

    r1 = D[in[i + 1].r];//查表 //这里给第二个ALU执行

    g1 = E[in[i + 1].g];

    b1 = F[in[i + 1].b];

    y = r1 + g1 + b1;

    out[i + 1] = y;

    }

    }

    2个ALU处理的数据不能有数据依赖,也就是说:某个ALU的输入条件不能是别的ALU的输出,这样才可以并行。

    这次成绩是1秒。

    查看这个代码

    int D[256],F[256],E[256]; //查表数组

    void table_init()

    {

    int i;

    for(i=0;i<256;i++)

    {

    D[i]=i*1224;

    D[i]=D[i]>>12;

    E[i]=i*2404;

    E[i]=E[i]>>12;

    F[i]=i*467;

    F[i]=F[i]>>12;

    }

    }

    到这里,似乎已经足够快了,但是我们反复实验,发现,还有办法再快!

    可以将int D[256],F[256],E[256]; //查表数组

    更改为

    unsigned short D[256],F[256],E[256]; //查表数组

    这是因为编译器处理int类型和处理unsigned short类型的效率不一样。

    再改动

    inline void calc_lum()

    {

    int i;

    for(i = 0; i < IMGSIZE; i += 2) //一次并行处理2个数据

    {

    int r,g,b,y,r1,g1,b1,y1;

    r = D[in[i].r];//查表 //这里给第一个ALU执行

    g = E[in[i].g];

    b = F[in[i].b];

    y = r + g + b;

    out[i] = y;

    r1 = D[in[i + 1].r];//查表 //这里给第二个ALU执行

    g1 = E[in[i + 1].g];

    b1 = F[in[i + 1].b];

    y = r1 + g1 + b1;

    out[i + 1] = y;

    }

    }

    将函数声明为inline,这样编译器就会将其嵌入到母函数中,可以减少CPU调用子函数所产生的开销。

    这次速度:0.5秒。

    其实,我们还可以飞出地球的!

    如果加上以下措施,应该还可以更快:

    1、 把查表的数据放置在CPU的高速数据CACHE里面;

    2、 把函数calc_lum()用汇编语言来写

    其实,CPU的潜力是很大的

    1、 不要抱怨你的CPU,记住一句话:“只要功率足够,砖头都能飞!”

    2、 同样的需求,写法不一样,速度可以从120秒变化为0.5秒,说明CPU的潜能是很大的!看你如何去挖掘。

    3、 我想:要是Microsoft的工程师都像我这样优化代码,我大概就可以用489跑windows XP了!

    以上就是对《让你的软件飞起来》的摘录,下面,我将按照这位牛人的介绍,对RGB到YCbCr的转换算法做以总结。

    Y = 0.299R + 0.587G + 0.114B
    U = -0.147R - 0.289G + 0.436B
    V = 0.615R - 0.515G - 0.100B

    #deinfe SIZE 256

    #define XSIZE 640

    #define YSIZE 480

    #define IMGSIZE XSIZE * YSIZE

    typedef struct RGB

    {

    unsigned char r;

    unsigned char g;

    unsigned char b;

    }RGB;

    struct RGB in[IMGSIZE]; //需要计算的原始数据

    unsigned char out[IMGSIZE * 3]; //计算后的结果

    unsigned short Y_R[SIZE],Y_G[SIZE],Y_B[SIZE],U_R[SIZE],U_G[SIZE],U_B[SIZE],V_R[SIZE],V_G[SIZE],V_B[SIZE]; //查表数组

    void table_init()

    {

    int i;

    for(i = 0; i < SIZE; i++)

    {

    Y_R[i] = (i * 1224) >> 12; //Y对应的查表数组

    Y_G[i] = (i * 2404) >> 12;

    Y_B[i] = (i * 467) >> 12;

    U_R[i] = (i * 602) >> 12; //U对应的查表数组

    U_G[i] = (i * 1183) >> 12;

    U_B[i] = (i * 1785) >> 12;

    V_R[i] = (i * 2519) >> 12; //V对应的查表数组

    V_G[i] = (i * 2109) >> 12;

    V_B[i] = (i * 409) >> 12;

    }

    }

    inline void calc_lum()

    {

    int i;

    for(i = 0; i < IMGSIZE; i += 2) //一次并行处理2个数据

    {

    out[i] = Y_R[in[i].r] + Y_G[in[i].g] + Y_B[in[i].b]; //Y

    out[i + IMGSIZE] = U_B[in[i].b] - U_R[in[i].r] - U_G[in[i].g]; //U

    out[i + 2 * IMGSIZE] = V_R[in[i].r] - V_G[in[i].g] - V_B[in[i].b]; //V

    out[i + 1] = Y_R[in[i + 1].r] + Y_G[in[i + 1].g] + Y_B[in[i + 1].b]; //Y

    out[i + 1 + IMGSIZE] = U_B[in[i + 1].b] - U_R[in[i + 1].r] - U_G[in[i + 1].g]; //U

    out[i + 1 + 2 * IMGSIZE] = V_R[in[i + 1].r] - V_G[in[i + 1].g] - V_B[in[i + 1].b]; //V

    }

    }

    从公式中,我们关键要理解的一点是,UV / CbCr信号实际上就是蓝色差信号和红色差信号,进而言之,实际上一定程度上间接的代表了蓝色和红色的强度,理解这一点对于我们理解各种颜色变换处理的过程会有很大的帮助。

            我们在数字电子多媒体领域所谈到的YUV格式,实际上准确的说,是以YcrCb色彩空间模型为基础的具有多种存储格式的一类颜色模型的家族(包括 YUV444 / YUV422 / YUV420 / YUV420P等等)。并不是传统意义上用于PAL制模拟电视的YUV模型。这些YUV模型的区别主要在于UV数据的采样方式和存储方式,这里就不详述。

            而在Camera Sensor中,最常用的YUV模型是 YUV422格式,因为它采用4个字节描述两个像素,能和RGB565模型比较好的兼容。有利于Camera Sensor和Camera controller的软硬件接口设计。

    http://blog.csdn.net/frankiewang008/article/details/6854616

    http://hi.baidu.com/zymill/item/b09445aa563d02796cd4558b

    http://wenku.baidu.com/link?url=j97XMVF-UMfdNgt8c4KM3J1lUe0beWdno23c10MJzS8AEImRtJTBo7ZHj2Zx6GAwwYNKAbN0pDNs_Nd_McNCaIK00NiQUTSZypxVHqfc5KO百度文库位图信息

  • 相关阅读:
    git init 后关联github仓库是发生错误:
    node mysql模块写入中文字符时的乱码问题
    Error: ER_BAD_FIELD_ERROR: Unknown column 'xxx' in 'where clause'
    安装MariaDB
    yum命令无效
    文档管理系统介绍
    RichTextBox文字处理控件属性介绍
    Android调用相册拍照控件实现系统控件缩放切割图片
    苹果5S指纹扫描识别传感器Touch ID有利于iPhone的安全性
    在服务器端将XML转换成HTML
  • 原文地址:https://www.cnblogs.com/pengkunfan/p/3798414.html
Copyright © 2011-2022 走看看