www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁 > 公眾號(hào)精選 > 嵌入式IoT

1.文章簡(jiǎn)述2. YUV轉(zhuǎn)RGB的代碼優(yōu)化問題2.1 浮點(diǎn)轉(zhuǎn)換2.2 浮點(diǎn)轉(zhuǎn)整形2.3 浮點(diǎn)運(yùn)算和整數(shù)運(yùn)算在PC上模擬的效果3. x1000上進(jìn)行對(duì)比測(cè)試3.1 使用軟浮點(diǎn)測(cè)試一幀圖像轉(zhuǎn)換時(shí)間3.2 開啟FPU后轉(zhuǎn)換圖像3.3 開啟FPU進(jìn)行測(cè)試3.3.1 基本思路3.3.2 程序設(shè)計(jì)4. 總結(jié)

1.文章簡(jiǎn)述

攝像輸出的圖像一般都是YUV格式的圖像,本文主要從攝像頭輸出的YUV格式圖像的角度出發(fā),對(duì)圖像格式的轉(zhuǎn)換進(jìn)行設(shè)計(jì)。同時(shí)對(duì)代碼的優(yōu)化進(jìn)行總結(jié)與整理。下面來詳細(xì)講述這些問題。

2. YUV轉(zhuǎn)RGB的代碼優(yōu)化問題

從原理上來說,對(duì)于一個(gè)YUV轉(zhuǎn)RGB的代碼,可以從浮點(diǎn)和浮點(diǎn)轉(zhuǎn)整形這兩種方式進(jìn)行轉(zhuǎn)換,而轉(zhuǎn)成整數(shù)后又可以利用MXU進(jìn)行計(jì)算,應(yīng)該可以加快運(yùn)算速度。

在編寫代碼時(shí),最開始的解決辦法都是從網(wǎng)上查找的資料,感覺可以實(shí)現(xiàn)基本的功能,但是對(duì)代碼沒有進(jìn)行任何的優(yōu)化,甚至還降低代碼的可讀性。這是我以前寫代碼時(shí)沒有認(rèn)真總結(jié)的問題,經(jīng)過夏總的指導(dǎo),確實(shí)在這個(gè)上面需要認(rèn)真的下點(diǎn)功夫。

2.1 浮點(diǎn)轉(zhuǎn)換

原始的代碼如下

y = 0.299*r + 0.587*g + 0.114*b;
u = -0.1687*r - 0.3313*g + 0.5*b + 128;
v = 0.5*r - 0.4187*g - 0.0813*b + 128;

y1 = 0.299*r1 + 0.587*g1 + 0.114*b1;
u1 = -0.1687*r1 - 0.3313*g1 + 0.5*b1 + 128;
v1 = 0.5*r1 - 0.4187*g1 - 0.0813*b1 + 128;

這樣寫法邏輯上沒有什么問題,但是細(xì)節(jié)上存在問題。首先是代碼的對(duì)稱性上來說,取的變量名應(yīng)該是y0,u0,v0,y1,u1,v1這樣才能保證對(duì)稱性。第二可以將這些參數(shù)替代成宏,這樣的代碼更加整齊,閱讀性更好。

優(yōu)化后

頭文件定義:

/******************************************
*  YUV轉(zhuǎn)RGB公式:
*    [ 1      0        1.402 ]  [ Y ]    [ R ]
*    [ 1    -0.34414  -0.71414] * [ U ]  =  [ G ]
*    [ 1    1.1772      0  ]  [ V ]    [ B ]
******************************************/ //浮點(diǎn) #define YUV2RGB_COEF00_FLOAT (1) #define YUV2RGB_COEF01_FLOAT (0) #define YUV2RGB_COEF02_FLOAT (1.402f) #define YUV2RGB_COEF10_FLOAT (1) #define YUV2RGB_COEF11_FLOAT (-0.34414f) #define YUV2RGB_COEF12_FLOAT (-0.71414f) #define YUV2RGB_COEF20_FLOAT (1) #define YUV2RGB_COEF21_FLOAT (1.1772f) #define YUV2RGB_COEF22_FLOAT (0) 

代碼

/*********************************************************************************
*  YUV2轉(zhuǎn)RGB格式(浮點(diǎn)計(jì)算),兩個(gè)rgb像素轉(zhuǎn)換一個(gè)yuv2像素
*  r = y1 + 1.4075*(v - 128);
*  g = y - 0.3455*(u - 128) - 0.7169*(v - 128);
*  b = y + 1.779*(u - 128);
**********************************************************************************/ int yuv2rgb_native(unsigned char *rgb, unsigned char *yuv, unsigned int width, unsigned int height) { if (width < 1 || height < 1 || rgb == NULL || yuv == NULL)
 { return 0;
 } unsigned char y0, u, v, y1; int r0, g0, b0, r1, g1, b1; unsigned int i; int loop = (width*height) >> 1; for (i = 0; i < loop; i++)
 {
 y0 = yuv[0];
 u = yuv[1];
 y1 = yuv[2];
 v = yuv[3];
 yuv += 4;
 r0 = YUV2RGB_COEF00_FLOAT*y1 + YUV2RGB_COEF01_FLOAT*u + YUV2RGB_COEF02_FLOAT*(v - 128);
 g0 = YUV2RGB_COEF10_FLOAT*y0 + YUV2RGB_COEF11_FLOAT*(u - 128) + YUV2RGB_COEF12_FLOAT*(v - 128);
 b0 = YUV2RGB_COEF20_FLOAT*y0 + YUV2RGB_COEF21_FLOAT*(u - 128) + YUV2RGB_COEF22_FLOAT*v;
 r1 = YUV2RGB_COEF00_FLOAT*y1 + YUV2RGB_COEF01_FLOAT*u + YUV2RGB_COEF02_FLOAT*(v - 128);
 g1 = YUV2RGB_COEF10_FLOAT*y1 + YUV2RGB_COEF11_FLOAT*(u - 128) + YUV2RGB_COEF12_FLOAT*(v - 128);
 b1 = YUV2RGB_COEF20_FLOAT*y1 + YUV2RGB_COEF21_FLOAT*(u - 128) + YUV2RGB_COEF22_FLOAT*v; /*
 rgb[0] = (((TUNE(g0) & 0x1C) << 3) | (TUNE(b0) >> 3));
 rgb[1] = ((TUNE(r0) & 0xF8) | (TUNE(g0) >> 5));
 rgb[2] = (((TUNE(g1) & 0x1C) << 3) | (TUNE(b1) >> 3));
 rgb[3] = ((TUNE(r1) & 0xF8) | (TUNE(g1) >> 5));
 rgb += 4;
 */ rgb[0] = TUNE(r0);
 rgb[1] = TUNE(g0);
 rgb[2] = TUNE(b0);
 rgb[3] = TUNE(r1);
 rgb[4] = TUNE(g1);
 rgb[5] = TUNE(b1);
 rgb += 6;

 } return 1;
}

從整體的代碼風(fēng)格上來說,一定要確保代碼盡可能的簡(jiǎn)潔優(yōu)美,代碼中用的比較多的常數(shù)可以用宏來進(jìn)行表示。往往這些細(xì)節(jié)問題,容易忽視的問題,一定要重視。

2.2 浮點(diǎn)轉(zhuǎn)整形

在前面的文檔中,已經(jīng)詳細(xì)描述了浮點(diǎn)轉(zhuǎn)整形的原理,現(xiàn)在只是做一些細(xì)節(jié)上的優(yōu)化和敘述。

定義轉(zhuǎn)換精度:

//定義轉(zhuǎn)換精度 #define YUV2RGB_COEF_SHIFT (8) 

定義系數(shù)宏:

#define YUV2RGB_COEF00_INT (1) #define YUV2RGB_COEF01_INT (1) #define YUV2RGB_COEF02_INT ((int)((YUV2RGB_FLOAT_COEF02 - 1) * (1< #define YUV2RGB_COEF10_INT (1) #define YUV2RGB_COEF11_INT ((int)((YUV2RGB_FLOAT_COEF11) * (1< #define YUV2RGB_COEF12_INT ((int)((YUV2RGB_FLOAT_COEF12) * (1< #define YUV2RGB_COEF20_INT (1) #define YUV2RGB_COEF21_INT (1) #define YUV2RGB_COEF22_INT ((int)((YUV2RGB_FLOAT_COEF21 - 1) * (1<

轉(zhuǎn)換函數(shù)

/*********************************************************************************
*  YUV2轉(zhuǎn)RGB格式(浮點(diǎn)轉(zhuǎn)整形計(jì)算),兩個(gè)rgb像素轉(zhuǎn)換一個(gè)yuv2像素
*  r = y1 + 1.4075*(v - 128);
*  g = y - 0.3455*(u - 128) - 0.7169*(v - 128);
*  b = y + 1.779*(u - 128);
*
*  YUV轉(zhuǎn)RGB公式:
*    [ 1      0        1.402 ]  [ Y ]    [ R ]
*    [ 1    -0.34414  -0.71414] * [ U ]  =  [ G ]
*    [ 1    1.1772      0  ]  [ V ]    [ B ]
*
*  r = y1 + v + ((104*v)>>8) -180
*  g = y - ((89*u)>>8) -((183*v)>>8) + 135
*  b = y + u + ((199*u)<<8) -227
**********************************************************************************/ int yuv2rgb(unsigned char *rgb, unsigned char *yuv, unsigned int width, unsigned int height) { unsigned char y0, u, v, y1; int r0, g0, b0, r1, g1, b1; unsigned int i; int loop = (width*height) >> 1;//yuv圖像大小是 for (i = 0; i < loop; i++)
 {
 y0 = yuv[0];
 u = yuv[1];
 y1 = yuv[2];
 v = yuv[3];
 yuv += 4; //簡(jiǎn)化 r0 = y1 + v + ((YUV2RGB_INT_COEF02*v) >> YUV2RGB_COEF_SHIFT) - 179;
 g0 = y0 + ((YUV2RGB_INT_COEF11* u) >> YUV2RGB_COEF_SHIFT) + ((YUV2RGB_INT_COEF12*v) >> YUV2RGB_COEF_SHIFT) + 135;
 b0 = y0 + u + ((YUV2RGB_INT_COEF22*u) >> YUV2RGB_COEF_SHIFT) - 150;
 r1 = y1 + v + ((YUV2RGB_INT_COEF02*v) >> YUV2RGB_COEF_SHIFT) - 179;
 g1 = y1 + ((YUV2RGB_INT_COEF11* u) >> YUV2RGB_COEF_SHIFT) + ((YUV2RGB_INT_COEF12*v) >> YUV2RGB_COEF_SHIFT) + 135;
 b1 = y1 + u + ((YUV2RGB_INT_COEF22*u) >> YUV2RGB_COEF_SHIFT) - 150;

 rgb[0] = TUNE(r0);
 rgb[1] = TUNE(g0);
 rgb[2] = TUNE(b0);
 rgb[3] = TUNE(r1);
 rgb[4] = TUNE(g1);
 rgb[5] = TUNE(b1);
 rgb += 6; /*
 rgb[0] = (((TUNE(g0) & 0x1C) << 3) | (TUNE(b0) >> 3));
 rgb[1] = ((TUNE(r0) & 0xF8) | (TUNE(g0) >> 5));
 rgb[2] = (((TUNE(g1) & 0x1C) << 3) | (TUNE(b1) >> 3));
 rgb[3] = ((TUNE(r1) & 0xF8) | (TUNE(g1) >> 5));
 rgb += 4;
 */ } return 1;
}

在這個(gè)代碼中主要注意將函數(shù)展開,這樣就是讓復(fù)雜的運(yùn)算變成乘法或者加法運(yùn)算,因?yàn)镸XU有相關(guān)的乘法加法和移位運(yùn)算。

2.3 浮點(diǎn)運(yùn)算和整數(shù)運(yùn)算在PC上模擬的效果

在PC機(jī)上模擬時(shí)間測(cè)試

可以看到Y(jié)UV2RGB_Native函數(shù)運(yùn)行時(shí)間11158us,也就是浮點(diǎn)轉(zhuǎn)換的時(shí)間為11158us。

而轉(zhuǎn)換成整形后需要7444us。明顯轉(zhuǎn)換成整數(shù)后效率要高。

圖像質(zhì)量比較:

原圖:

浮點(diǎn)轉(zhuǎn)換:

經(jīng)過整形轉(zhuǎn)換后的圖

從上面的效果上可以看出,基本上圖形效果比較好。

3. x1000上進(jìn)行對(duì)比測(cè)試

在開發(fā)板上進(jìn)行測(cè)試主要從以下幾個(gè)方面進(jìn)行:

  • 不開啟FPU的情況下測(cè)試浮點(diǎn)和整形一幀圖像轉(zhuǎn)換時(shí)間

  • 開啟FPU的情況下測(cè)試浮點(diǎn)和整形一幀圖像轉(zhuǎn)換時(shí)間

  • 在利用MXU進(jìn)行優(yōu)化后的一幀圖像轉(zhuǎn)換時(shí)間

3.1 使用軟浮點(diǎn)測(cè)試一幀圖像轉(zhuǎn)換時(shí)間

開啟軟浮點(diǎn)需要在編譯選項(xiàng)中添加

-msoft-float 

然后找到

ingenic-linux-kernel3.10.14-x1000-v5.0-20161213\prebuilts\toolchains\mips-gcc472-glibc216\lib\gcc\mips-linux-gnu\4.7.2\soft-float\libgcc.a 

文件添加到到application目錄下。

然后編輯application目錄中的SConsript

from building import *

cwd = GetCurrentDir()
src = Glob('*.c') + Glob('*.cpp')+ Glob('*.a')

CPPPATH = [cwd, str(Dir('#'))]

group = DefineGroup('Applications', src, depend = [''],CPPPATH = CPPPATH)

Return('group')

浮點(diǎn)運(yùn)算時(shí)間

轉(zhuǎn)換一幀圖像需要的時(shí)間是137ms

浮點(diǎn)轉(zhuǎn)整形運(yùn)算時(shí)間

經(jīng)過轉(zhuǎn)換只需要9ms。也就是說,將浮點(diǎn)轉(zhuǎn)換成整形后,效率提高了15倍。

3.2 開啟FPU后轉(zhuǎn)換圖像

在linux系統(tǒng)下編譯,并利用君正提供的gcc。默認(rèn)情況下是支持FPU的,所以首先需要將編譯選項(xiàng)中的-msoft-float去掉。

浮點(diǎn)運(yùn)算時(shí)間


可見轉(zhuǎn)換一幀圖像后運(yùn)算時(shí)間為12ms。

浮點(diǎn)轉(zhuǎn)整形運(yùn)算時(shí)間

浮點(diǎn)轉(zhuǎn)整形后速度還是要快一些。

3.3 開啟FPU進(jìn)行測(cè)試

3.3.1 基本思路

總體的代碼如下

r0 = y1 + v + a1 - 179;
g0 = y0 + b1 + c1 + 135;
b0 = y0 + u + d1 - 150;
r1 = y1 + v + a1 - 179;
g1 = y1 + b1 + c1 + 135;
b1 = y1 + u + d1 - 150;

上面簡(jiǎn)化其實(shí)就是

a1:((YUV2RGB_INT_COEF02*v) >> YUV2RGB_COEF_SHIFT)

b1:((YUV2RGB_INT_COEF11* u) >> YUV2RGB_COEF_SHIFT)

c1:((YUV2RGB_INT_COEF12*v) >> YUV2RGB_COEF_SHIFT)

d1:((YUV2RGB_INT_COEF22*u) >> YUV2RGB_COEF_SHIFT)

實(shí)際上這就是一個(gè)乘法,加法,移位運(yùn)算。考慮到乘法和移位比較消耗時(shí)間,可以在代碼中只做加減操作,乘法和移位用MXU來進(jìn)行。

主要用到的指令

而在MXU中有一個(gè)8位的乘法指令

也就是說可以將四個(gè)char類型的數(shù)填充到32位的寄存器中,得到的數(shù)據(jù)是4個(gè)16位的short型數(shù)據(jù)。

所以得到xra,xrd后然后將這兩個(gè)寄存器的值移位

所以這四個(gè)乘法和移位計(jì)算由兩條MXU指令即可完成

3.3.2 程序設(shè)計(jì)

將四個(gè)char類型系數(shù)放在src1中,將四個(gè)char類型的u,v分量放在src2中

int yuv2rgb(unsigned char *rgb, unsigned char *yuv, unsigned int width, unsigned int height) { // if (width < 1 || height < 1 || rgb == NULL || yuv == NULL) // { //    return 0; // } unsigned char src1[4]; unsigned char src2[4]; unsigned short dst1[2]; unsigned short dst2[2]; unsigned char y0, u, v, y1; int r0, g0, b0, r1, g1, b1;
 src1[0] = YUV2RGB_INT_COEF02 ;
 src1[1] = -YUV2RGB_INT_COEF11;//變成正數(shù) src1[2] = -YUV2RGB_INT_COEF12;//變成正數(shù) src1[3] = YUV2RGB_INT_COEF22 ; unsigned int i; int loop = (width*height) >> 1; for (i = 0; i < loop; i++)
 {
 y0 = yuv[0];
 u = yuv[1];
 y1 = yuv[2];
 v = yuv[3];
 yuv += 4;

 src2[0] = v;
 src2[1] = u;
 src2[2] = v;
 src2[3] = u;

 S32LDDR(xr1, src1, 0);//將src1的數(shù)據(jù)放在xr1中 S32LDDR(xr2, src2, 0);//將src2的數(shù)據(jù)放在xr2中 Q8MUL(xr3, xr1, xr2, xr4);//將xr1與xr2每八位相乘,得到高位放xr3,低位放xr4 Q16SLR(xr5, xr3, xr4, xr6, YUV2RGB_COEF_SHIFT);//將xr3與xr4進(jìn)行移位 S32STD(xr5, dst1, 0);// dst1[1] Short3 dst1[0] Short2 S32STD(xr6, dst2, 0);// dst2[1] Short1 dst2[0] Short0 r0 = y1 + v + dst1[1] - 179;
 g0 = y0 - dst1[0] - dst2[1]  + 135;
 b0 = y0 + u + dst2[0] - 150;
 r1 = y1 + v + dst1[1]- 179;
 g1 = y1 - dst1[0] - dst2[1] + 135;
 b1 = y1 + u + dst2[0] - 150;

 rgb[0] = (((TUNE(g0) & 0x1C) << 3) | (TUNE(b0) >> 3));
 rgb[1] = ((TUNE(r0) & 0xF8) | (TUNE(g0) >> 5));
 rgb[2] = (((TUNE(g1) & 0x1C) << 3) | (TUNE(b1) >> 3));
 rgb[3] = ((TUNE(r1) & 0xF8) | (TUNE(g1) >> 5));
 rgb += 4;
 } return 1;
}

經(jīng)過測(cè)試,效果如下

發(fā)現(xiàn)效果并沒有預(yù)想中的那么明顯。依然和整形轉(zhuǎn)換一幀圖像時(shí)間差不多。和之前的猜想不相符,如果將幾條乘法指令并行執(zhí)行,可能會(huì)效果好很多,但實(shí)際測(cè)試發(fā)現(xiàn)優(yōu)化好不了多少。后面再將加減法進(jìn)行一下MXU的優(yōu)化,看一下能不能有更好的優(yōu)化方案。

4. 總結(jié)

本文主要測(cè)試YUV轉(zhuǎn)RGB的幾種方法的效率問題,得到的結(jié)論是定點(diǎn)化處理更加的高效。如果用浮點(diǎn)運(yùn)算,會(huì)消耗大量的硬件資源。


本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
關(guān)閉