如何裁剪YUV420圖像,抓取指定區(qū)域,制作方形視頻,模仿Instagram

I420格式介紹

在webrtc中android和ios系統(tǒng)采集攝像頭獲取到原始數(shù)據(jù)后,
一幀原始圖像會(huì)被轉(zhuǎn)化為標(biāo)準(zhǔn)的YUV420P格式,也就是I420格式,
轉(zhuǎn)換的函數(shù)使用的是libyuv中的ConvertToI420()函數(shù)

YUV格式詳細(xì)講解

進(jìn)行裁剪操作需要對(duì)I420格式的內(nèi)存分布有深入的了解,推薦大家看這篇文章:
http://blog.csdn.net/jefry_xdz/article/details/7931018 
其中I420就是YUV420P格式

裁剪圖像的含義

裁剪就是去掉某些區(qū)域,剩下指定的區(qū)域,
本文所講的裁剪就是摳圖,摳去出原圖像的某個(gè)內(nèi)部區(qū)域

裁剪的用途

我們可以將裁剪后的視頻傳遞給h264編碼器,然后將輸出保存成MP4文件(還需要加上聲音),即可模仿Instagram軟件中拍攝方形視頻的功能。

代碼如下:

代碼中假設(shè)視頻寬度和“Image Stride”相同
什么是stride? 參考這篇文章:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa473780(v=vs.85).aspx

這里使用到了webrtc中的部分代碼其中I420VideoFrame格式定義為
https://code.google.com/p/webrtc/source/browse/trunk/webrtc/video_frame.h?r=8434
所以dst_frame是這樣生成的:
  dst_frame->CreateEmptyFrame(dst_width_, dst_height_,
                              dst_width_, (dst_width_ + 1) / 2,
                              (dst_width_ + 1) / 2);
int zp_getImageBlock(const I420VideoFrame& src_frame, I420VideoFrame& dst_frame,int start_w,int start_h)
    {

        //I420格式說(shuō)明參考的這個(gè)博客 http://blog.csdn.net/jefry_xdz/article/details/7931018
        
        assert(start_w >= 0 && start_h >= 0);
        //start_w 開(kāi)始點(diǎn)距離左邊的距離
        //start_h 開(kāi)始點(diǎn)距離上邊的距離
        //起始點(diǎn)可以決定裁剪視頻的哪個(gè)區(qū)域,不一定是中心區(qū)域
        
        int src_width = src_frame.width();
        int src_height = src_frame.height();
        int dst_width = dst_frame.width();
        int dst_height = dst_frame.height();
        
        if (start_w + dst_width > src_width ||
            start_h + dst_height > src_height) {
            //區(qū)域設(shè)置不合理,已經(jīng)超出原始視頻范圍
            return -1;
        }
        if(dst_height > src_height || dst_width > src_width)
        {
            //只能縮小,不能擴(kuò)大,擴(kuò)大使用libyuv的scale函數(shù)
            return -1;
        }
        
        int w_cut = start_w;
        int h_cut = start_h;
        
        //切除的部分必須是偶數(shù),因?yàn)槊克膫€(gè)像素對(duì)應(yīng)一個(gè)u,v
        assert(w_cut%2==0);
        assert(h_cut%2==0);
        
        const uint8* src_y = src_frame.buffer(kYPlane);
        uint8* dst_y = dst_frame.buffer(kYPlane);
        const uint8* src_u = src_frame.buffer(kUPlane);
        uint8* dst_u = dst_frame.buffer(kUPlane);
        const uint8* src_v = src_frame.buffer(kVPlane);
        uint8* dst_v = dst_frame.buffer(kVPlane);
        
        //取Y
        for (int row = 0; row < dst_height; ++row) {
            for (int col = 0; col < dst_width; ++col) {
                //計(jì)算目標(biāo)區(qū)域的下標(biāo)對(duì)應(yīng)于源數(shù)據(jù)的哪個(gè)下標(biāo)
                //目標(biāo)區(qū)域的下表row*dst_width+col
                //(h_cut+row)*src_width+(w_cut+col)
                dst_y[row*dst_width+col] = src_y[(h_cut+row)*src_width+(w_cut+col)];
            }
        }
        
        //取U,V
        int k = 0;
        for (int row = 0; row < dst_height; row+=2) {
            for (int col = 0; col < dst_width; col+=2) {
                int old_index = (h_cut+row)*src_width/4+(w_cut+col)/2;
                dst_u[k] = src_u[old_index];
                dst_v[k] = src_v[old_index];
                k++;
            }
        }
        return 0;
    }
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容