針對(duì)移動(dòng)端攝像頭yuv旋轉(zhuǎn)、裁剪卧蜓、鏡像帐要、格式轉(zhuǎn)換算法的實(shí)現(xiàn)

存在問(wèn)題

移動(dòng)端錄像在yuv數(shù)據(jù)上存在如下問(wèn)題:

  1. 無(wú)論android還是ios都不能直接從攝像頭取出顏色空間為i420的數(shù)據(jù),所以在編碼前需要進(jìn)行格式轉(zhuǎn)換弥奸。
  2. 而且由于所取圖像得分辨率必須是攝像頭所提供分辨率中得一組榨惠,所以有可能需要裁剪。
  3. 另外由于
    (1)想讓無(wú)論用戶哪個(gè)方向拿手機(jī)所錄的視頻內(nèi)容永遠(yuǎn)“頭朝上”
    ( 2)攝像頭默認(rèn)返回圖像為橫屏圖像(寬大于長(zhǎng))
    所以需要旋轉(zhuǎn)。
  4. 前置攝像頭需要鏡像赠橙。

算法實(shí)現(xiàn)

1.格式轉(zhuǎn)換
nv21轉(zhuǎn)成i420耽装。可以通過(guò)攝像頭設(shè)置將所采集數(shù)據(jù)設(shè)置為YUVNV21格式期揪。
void NV21ToI420(uint8_t* dstyuv,uint8_t* data, int imageWidth, int imageHeight) { int Ustart =imageWidth*imageHeight; int i,j; int uWidth = imageWidth/2; int uHeight = imageWidth/2; //y memcpy(dstyuv,data,imageWidth*imageHeight); int tempindex = 0 ; int srcindex= 0; //u for(i= 0 ;i <uHeight;i++) { for(j = 0;j <uWidth ;j++ ) { dstyuv[Ustart+tempindex+j]= data[Ustart+(srcindex<<1)+1]; srcindex++; } tempindex+= uWidth; } //v for (i = 0; i < uHeight;i++) { for (j = 0; j < uWidth;j++) { dstyuv[Ustart+tempindex + j] = data[Ustart + (srcindex << 1 )]; srcindex++; } tempindex+= uWidth; } }

其實(shí)就是改變了uv的位置掉奄。
I420: YYYYYYYY UU VV
NV21: YYYYYYYY VUVU

2.裁剪
//crop yuv data int crop_yuv (char* data, char*dst, intwidth, intheight, int goalwidth, int goalheight) { int i, j; int h_div = 0, w_div = 0; w_div= (width - goalwidth) / 2; if (w_div % 2) w_div--; h_div= (height - goalheight) / 2; if (h_div % 2) h_div--; //u_div = (height-goalheight)/4; int src_y_length = width *height; int dst_y_length =goalwidth * goalheight; for (i = 0; i <goalheight; i++) for (j = 0; j <goalwidth; j++) { dst[i* goalwidth + j] = data[(i + h_div) * width + j + w_div]; } int index = dst_y_length; int src_begin =src_y_length + h_div * width / 4; int src_u_length =src_y_length / 4; int dst_u_length =dst_y_length / 4; for (i = 0; i <goalheight / 2; i++) for (j = 0; j <goalwidth / 2; j++) { int p = src_begin + i *(width >> 1) + (w_div >> 1) + j; dst[index]= data[p]; dst[dst_u_length+ index++] = data[p + src_u_length]; } return 0; }

3.** 旋轉(zhuǎn)**
分為四個(gè)方向 。以順時(shí)針270度為例作圖横侦。
旋轉(zhuǎn)前:


旋轉(zhuǎn)后:

u值的第i 行j列 對(duì)應(yīng)原 數(shù)據(jù)的下標(biāo)為:ustart+uw*j-i;
去除index的乘除法運(yùn)算后算法:
(1) i420 順時(shí)針 270度
int rotateYUV420Degree270(uint8_t* dstyuv,uint8_t* srcdata, int imageWidth, int imageHeight) { int i = 0, j = 0; int index = 0; int tempindex = 0; int div = 0; for (i = 0; i <imageHeight; i++) { div= i +1; tempindex= 0; for (j = 0; j <imageWidth; j++) { tempindex+= imageWidth; dstyuv[index++]= srcdata[tempindex-div]; } } int start =imageWidth*imageHeight; int udiv = imageWidth *imageHeight / 4; int uWidth = imageWidth /2; int uHeight = imageHeight /2; index= start; for (i = 0; i < uHeight;i++) { div= i +1; tempindex= start; for (j = 0; j < uWidth;j++) { tempindex += uWidth; dstyuv[index]= srcdata[tempindex-div]; dstyuv[index+udiv]= srcdata[tempindex-div+udiv]; index++; } } return 0; }
(2)i420 順時(shí)針旋轉(zhuǎn) 180
int rotateYUV420Degree180(uint8_t* dstyuv,uint8_t* srcdata, int imageWidth, int imageHeight) { int i = 0, j = 0; int index = 0; int tempindex = 0; int ustart = imageWidth \*imageHeight; tempindex= ustart; for (i = 0; i <imageHeight; i++) { tempindex-= imageWidth; for (j = 0; j <imageWidth; j++) { dstyuv[index++] = srcdata[tempindex + j]; } } int udiv = imageWidth *imageHeight / 4; int uWidth = imageWidth /2; int uHeight = imageHeight /2; index= ustart; tempindex= ustart+udiv; for (i = 0; i < uHeight;i++) { tempindex-= uWidth; for (j = 0; j < uWidth;j++) { dstyuv[index]= srcdata[tempindex + j]; dstyuv[index+ udiv] = srcdata[tempindex + j + udiv]; index++; } } return 0; }
(3)順時(shí)針 90度
int rotateYUV420Degree90(uint8_t* dstyuv,uint8_t* srcdata, int imageWidth, int imageHeight) { int i = 0, j = 0; int index = 0; int tempindex = 0; int div = 0; int ustart = imageWidth *imageHeight; for (i = 0; i <imageHeight; i++) { div= i; tempindex= ustart; for (j = 0; j <imageHeight; j++) { tempindex-= imageWidth; dstyuv[index++]= srcdata[tempindex + div]; } } int udiv = imageWidth *imageHeight / 4; int uWidth = imageWidth /2; int uHeight = imageHeight /2; index= ustart; for (i = 0; i < uHeight;i++) { div= i ; tempindex= ustart+udiv; for (j = 0; j < uWidth;j++) { tempindex-= uWidth; dstyuv[index]= srcdata[tempindex + div]; dstyuv[index+ udiv] = srcdata[tempindex + div + udiv]; index++; } } return 0; }
4.** 鏡像**
//mirro 原址的 void Mirror(uint8_t\* yuv_temp, int nw, int nh, int w, int h) { int deleteW = (nw - h) / 2; int deleteH = (nh - w) / 2; int i, j; int a, b; uint8_ttemp; //mirror y for (i = 0; i < h; i++){ a= i \* w; b= (i + 1) \* w - 1; while (a < b) { temp= yuv_temp[a]; yuv_temp[a]= yuv_temp[b]; yuv_temp[b]= temp; a++; b--; } } //mirror u int uindex = w * h; for (i = 0; i < h / 2;i++) { a = i\ * w / 2; b= (i + 1) \* w / 2 - 1; while (a < b) { temp= yuv_temp[a + uindex]; yuv_temp[a+ uindex] = yuv_temp[b + uindex]; yuv_temp[b+ uindex] = temp; a++; b--; } } //mirror v uindex= w * h / 4 * 5; for (i = 0; i < h / 2;i++) { a= i\* w / 2; b= (i + 1) \* w / 2 - 1; while (a < b) { temp= yuv_temp[a + uindex]; yuv_temp[a+ uindex] = yuv_temp[b + uindex]; yuv_temp[b+ uindex] = temp; a++; b--; } } }

算法優(yōu)化

如果從攝像頭取出數(shù)據(jù)挥萌,這樣一步步的歷遍,在低配手機(jī)上是滿足不了需求的枉侧。其實(shí)這三個(gè)步驟中有很多中間步驟是可以省去的引瀑,比如:將a放到b 位置,再將b位置上的數(shù)據(jù)取出放到c位置榨馁,那么可以直接將a放到c位置憨栽。
所以將旋轉(zhuǎn)、裁剪翼虫、格式轉(zhuǎn)換三個(gè)問(wèn)題所用的算法整合(未整合進(jìn)去鏡像)屑柔。結(jié)果如下:
**(1)處理不用旋轉(zhuǎn)的圖像,格式轉(zhuǎn)換加裁剪
void detailPic0(uint8_t\* d, uint8_t\* yuv_temp, int nw, int nh, int w, int h) { int deleteW = (nw - w) / 2; int deleteH = (nh - h) / 2; //處理y 旋轉(zhuǎn)加裁剪 int i, j; int index = 0; for (j = deleteH; j < nh- deleteH; j++) { for (i = deleteW; i < nw- deleteW; i++) yuv_temp[index++]= d[j \* nw + i]; } //處理u index= w \* h; for (i = nh + deleteH / 2;i < nh / 2 \* 3 - deleteH / 2; i++) for (j = deleteW + 1; j< nw - deleteW; j += 2) yuv_temp[index++]= d[i \* nw + j]; //處理v 旋轉(zhuǎn)裁剪加格式轉(zhuǎn)換 for (i = nh + deleteH / 2;i < nh / 2 \* 3 - deleteH / 2; i++) for (j = deleteW; j < nw- deleteW; j += 2) yuv_temp[index++]= d[i \* nw + j]; }

**(2)格式轉(zhuǎn)換珍剑、裁剪加旋轉(zhuǎn)90度
void detailPic90(uint8_t\* d, uint8_t\* yuv_temp, int nw, int nh, int w, int h) { int deleteW = (nw - h) / 2; int deleteH = (nh - w) / 2; int i, j; for (i = 0; i < h; i++){ for (j = 0; j < w; j++){ yuv_temp[(h- i) \* w - 1 - j] = d[nw \* (deleteH + j) + nw - deleteW -i]; } } int index = w \* h; for (i = deleteW + 1; i< nw - deleteW; i += 2) for (j = nh / 2 \* 3 -deleteH / 2; j > nh + deleteH / 2; j--) yuv_temp[index++]= d[(j - 1) \* nw + i]; for (i = deleteW; i < nw- deleteW; i += 2) for (j = nh / 2 \* 3 -deleteH / 2; j > nh + deleteH / 2; j--) yuv_temp[index++]= d[(j - 1) \* nw + i]; }

(3)格式轉(zhuǎn)換掸宛、裁剪加旋轉(zhuǎn)180度
void detailPic180(uint8_t\* d, uint8_t\* yuv_temp, int nw, int nh, int w, int h) { int deleteW = (nw - w) / 2; int deleteH = (nh - h) / 2; //處理y 旋轉(zhuǎn)加裁剪 int i, j; int index = w \* h; for (j = deleteH; j < nh- deleteH; j++) { for (i = deleteW; i < nw- deleteW; i++) yuv_temp[--index]= d[j \* nw + i]; } //處理u index= w \* h \* 5 / 4; for (i = nh + deleteH / 2;i < nh / 2 \* 3 - deleteH / 2; i++) for (j = deleteW + 1; j< nw - deleteW; j += 2) yuv_temp[--index]= d[i \* nw + j]; //處理v index= w \* h \* 3 / 2; for (i = nh + deleteH / 2;i < nh / 2 \* 3 - deleteH / 2; i++) for (j = deleteW; j < nw- deleteW; j += 2) yuv_temp[--index]= d[i \* nw + j]; }

(4)格式轉(zhuǎn)換、裁剪加旋轉(zhuǎn)270度
void detailPic270(uint8_t\* d, uint8_t\* yuv_temp, int nw, int nh, int w, int h) { int deleteW = (nw - h) / 2; int deleteH = (nh - w) / 2; int i, j; //處理y 旋轉(zhuǎn)加裁剪 for (i = 0; i < h; i++){ for (j = 0; j < w; j++){ yuv_temp[i\* w + j] = d[nw \* (deleteH + j) + nw - deleteW - i]; } } //處理u 旋轉(zhuǎn)裁剪加格式轉(zhuǎn)換 int index = w \* h; for (i = nw - deleteW - 1;i > deleteW; i -= 2) for (j = nh + deleteH / 2;j < nh / 2 \* 3 - deleteH / 2; j++) yuv_temp[index++]= d[(j) \* nw + i]; //處理v 旋轉(zhuǎn)裁剪加格式轉(zhuǎn)換 for (i = nw - deleteW - 2;i >= deleteW; i -= 2) for (j = nh + deleteH / 2;j < nh / 2 \* 3 - deleteH / 2; j++) yuv_temp[index++]= d[(j) \* nw + i]; }

注:以上算法消除index的乘法后效果肯定會(huì)更好招拙。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末唧瘾,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子别凤,更是在濱河造成了極大的恐慌饰序,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件规哪,死亡現(xiàn)場(chǎng)離奇詭異求豫,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)诉稍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門蝠嘉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人杯巨,你說(shuō)我怎么就攤上這事蚤告。” “怎么了舔箭?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵罩缴,是天一觀的道長(zhǎng)蚊逢。 經(jīng)常有香客問(wèn)我,道長(zhǎng)箫章,這世上最難降的妖魔是什么烙荷? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮檬寂,結(jié)果婚禮上终抽,老公的妹妹穿的比我還像新娘。我一直安慰自己桶至,他們只是感情好昼伴,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著镣屹,像睡著了一般圃郊。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上女蜈,一...
    開(kāi)封第一講書(shū)人閱讀 49,950評(píng)論 1 291
  • 那天持舆,我揣著相機(jī)與錄音,去河邊找鬼伪窖。 笑死逸寓,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的覆山。 我是一名探鬼主播竹伸,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼簇宽!你這毒婦竟也來(lái)了勋篓?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤晦毙,失蹤者是張志新(化名)和其女友劉穎生巡,沒(méi)想到半個(gè)月后耙蔑,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體见妒,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年甸陌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了须揣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡钱豁,死狀恐怖耻卡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情牲尺,我是刑警寧澤卵酪,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布幌蚊,位于F島的核電站,受9級(jí)特大地震影響溃卡,放射性物質(zhì)發(fā)生泄漏溢豆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一瘸羡、第九天 我趴在偏房一處隱蔽的房頂上張望漩仙。 院中可真熱鬧,春花似錦犹赖、人聲如沸队他。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)麸折。三九已至,卻和暖如春粘昨,著一層夾襖步出監(jiān)牢的瞬間磕谅,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工雾棺, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留膊夹,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓捌浩,卻偏偏與公主長(zhǎng)得像放刨,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子尸饺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容