如何裁剪YUV420图像,抓取指定区域,制作方形视频,模仿Instagram

###I420格式介绍
在webrtc中android和ios系统采集摄像头获取到原始数据后,
一帧原始图像会被转化为标准的YUV420P格式,也就是I420格式,
转换的函数使用的是libyuv中的ConvertToI420()函数
###YUV格式详细讲解
进行裁剪操作需要对I420格式的内存分布有深入的了解,推荐大家看这篇文章:
http://blog.csdn.net/jefry_xdz/article/details/7931018
其中I420就是YUV420P格式

###裁剪图像的含义
裁剪就是去掉某些区域,剩下指定的区域,
本文所讲的裁剪就是抠图,抠去出原图像的某个内部区域
###裁剪的用途
我们可以将裁剪后的视频传递给h264编码器,然后将输出保存成MP4文件(还需要加上声音),即可模仿Instagram软件中拍摄方形视频的功能。

###代码如下:
代码中假设视频宽度和“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格式说明参考的这个博客 http://blog.csdn.net/jefry_xdz/article/details/7931018
        
        assert(start_w >= 0 && start_h >= 0);
        //start_w 开始点距离左边的距离
        //start_h 开始点距离上边的距离
        //起始点可以决定裁剪视频的哪个区域,不一定是中心区域
        
        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) {
            //区域设置不合理,已经超出原始视频范围
            return -1;
        }
        if(dst_height > src_height || dst_width > src_width)
        {
            //只能缩小,不能扩大,扩大使用libyuv的scale函数
            return -1;
        }
        
        int w_cut = start_w;
        int h_cut = start_h;
        
        //切除的部分必须是偶数,因为每四个像素对应一个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) {
                //计算目标区域的下标对应于源数据的哪个下标
                //目标区域的下表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;
    }
    
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值