画中画 视频合成

原文说转 没有具体的转链接 我转备用。 具体验证还未完成。

转: https://blog.csdn.net/zwz1984/article/details/50403150

YUV图像合成原理

引言:在视频监控中最常用的就是图像拼接和字符叠加,25FPS的视频流,如果每隔40MS就从各个通道中取一幅图像来合成,则可以看到一个实时的合成视频。合成的过程也就是原始图像的拼接、缩放的过程,本文主要阐述UV分开存储的YUV420图像拼接的过程,实现下图的效果。

一、原图图像格式

1、图像常用的格式有两种RGB和YUV

(1)YUV是被欧洲电视系统所采用的一种颜色编码方法(属于PAL),是PAL和SECAM模拟彩色电视制式采用的颜色空间。在现代彩色电视系统中,通常采用三管彩色摄影机或彩色CCD摄影机进行取像,然后把取得的彩色图像信号经分色、分别放大校正后得到RGB,再经过矩阵变换电路得到亮度信号Y和两个色差信号R-Y(即U)、B-Y(即V),最后发送端将亮度和色差三个信号分别进行编码,用同一信道发送出去。这种色彩的表示方法就是所谓的YUV色彩空间表示。采用YUV色彩空间的重要性是它的亮度信号Y和色度信号U、V是分离的。

(2)RGB色彩模式是工业界的一种颜色标准,是通过对红(R)、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB即是代表红、绿、蓝三个通道的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是目前运用最广的颜色系统之一。

2、两者在存储上的区别

(1)YUV按照内存消耗量总体上分为YUV420、YUV422两种

YUV420-----其Y:U:V或者Y:UV或者Y:V:U的总量为4:2:0

YUV422-----其Y:U:V比例为4:2:2

(2)RGB内存比例为1:1:1

则可以看出 显示一个像素点 需要的内存字节数

YUV420=(4+2+0)/4=3/2BYTE

YUV422=(4+2+2)/4=2 BYTE

RGB=(1+1+1)/1=3 BYTE

现在有一副图像,宽W高H,那么显示一副图像所需内存

YUV420=W*H*3/2 BYTE

YUV422=W*H*2 BYTE

RGB=W*H*3 BYTE

3、YUV数据格式YUV420-UV分开存储

X代表Y分量 0代表U/V分量 420的常规打包格式如下:

也就是说在水平方向和锤子4个像素点Y分量公用一组U/V分量

在内存结构上U/V分量水平和垂直分量均为1/2 U=w/2*h/2  V=w/2*h/2

用表格数据得出来就是

二、图像合成过程

合成前的图像和需要合成到的目的图像如下图所示

需要进行采样缩放、贴图后就能实现图像合成

1、采样

这里不做详细介绍 只看采样后效果

2、贴图

贴图原理-采样后图像的Y分量直接memcpy到合成图像的对应区域,Y/V分量则需要注意下

U/V水平和垂直均1/2采样

隔行拷贝,每次拷贝采样后w/2长度。由于合成图像的U/V数据已经隔行-存储的时候是连续的,所以UV拷贝的时候连续拷贝采样后长度/2然后进入合成图像下一行的U/V然后再拷贝,拷贝的高度为采样后图像高度h/2

上代码

  1. //图像类型枚举

  2.  

    typedef enum IMAGE_TYPE

  3.  

    {

  4.  

    IMAGE_YUV420,

  5.  

    IMAGE_YUV422

  6.  

    };

  7.  

  8.  

    //YUV图像结构体

  9.  

    typedef struct YUV_IMAGE

  10.  

    {

  11.  

    YUV_IMAGE(){ y = NULL; u = NULL; v = NULL; w = 0; h = 0; }

  12.  

    ~YUV_IMAGE(){ y = NULL; u = NULL; v = NULL; w = 0; h = 0; }

  13.  

    UCHAR *y;

  14.  

    UCHAR *u;

  15.  

    UCHAR *v;

  16.  

    UINT w;

  17.  

    UINT h;

  18.  

    IMAGE_TYPE t;

  19.  

    };

  1. /*从各个通道获取图像并缩放到合成图像上*/

  2.  

    BOOL CDigitalCourt::GetMergeImg()

  3.  

    {

  4.  

    DWORD dwTimeBegin = GetTickCount();

  5.  

    BOOL bRet = FALSE;

  6.  

    YUV_IMAGE *pImg = NULL;

  7.  

  8.  

    for (int i = 0; i < MAX_CHANNEL_CNT; i++)

  9.  

    {

  10.  

    if (m_pChannel[i])

  11.  

    {

  12.  

    //将YUV图像进行拷贝

  13.  

    if (m_pChannel[i]->GetYUVImage(&pImg))

  14.  

    {

  15.  

    //将拷贝后的YUV图像缩放到合成图像上

  16.  

    MergeImage(pImg, &m_MergeImg, i);

  17.  

  18.  

    bRet = TRUE;

  19.  

    }

  20.  

    }

  21.  

    }

  22.  

    //memcpy(m_MergeImg.y, src->y, 1920 * 1080 * 3 / 2);

  23.  

    /*memset(m_MergeImg.y, m_nMergeFrmCnt % 255, m_MergeImg.w*m_MergeImg.h);

  24.  

    memset(m_MergeImg.u, m_nMergeFrmCnt % 255 + 100, m_MergeImg.w*m_MergeImg.h / 2);

  25.  

    */

  26.  

    return bRet;

  27.  

    }

  28.  

  29.  

  30.  

  31.  

    //创建采样器

  32.  

    SwsContext * CDigitalCourt::CreateSws(YUV_IMAGE *src, UINT nOrder, UINT w, UINT h)

  33.  

    {

  34.  

    if (NULL == src || nOrder >= MAX_CHANNEL_CNT || 0 == w || 0 == h)

  35.  

    return NULL;

  36.  

  37.  

    if (NULL == m_pSubSws[nOrder])

  38.  

    {

  39.  

    m_pSubSws[nOrder] = sws_getContext(src->w,

  40.  

    src->h,

  41.  

    AV_PIX_FMT_YUV420P,

  42.  

    w,

  43.  

    h,

  44.  

    AV_PIX_FMT_YUV420P,

  45.  

    SWS_BICUBIC,

  46.  

    NULL,

  47.  

    NULL,

  48.  

    NULL);

  49.  

    if (NULL == m_pSubSws)

  50.  

    {

  51.  

    LOG(LOG_ERROR, "CDigitalCourt::Create sws failed index=%d,w=%d,h=%d,mergeW=%d,mergeH=%d!", nOrder, src->w, src->h, m_nMergeW, m_nMergeH);

  52.  

    return FALSE;

  53.  

    }

  54.  

    }

  55.  

    return m_pSubSws[nOrder];

  56.  

    }

  57.  

  58.  

  59.  

    //图像缩放--从源图像缩放到另外一个图像空间中去

  60.  

    void CDigitalCourt::Scale(YUV_IMAGE *src, YUV_IMAGE *dst, SwsContext *pSws)

  61.  

    {

  62.  

    AVPicture pictsrc;

  63.  

    AVPicture pictdst;

  64.  

  65.  

    if (NULL == src || NULL == dst || NULL == pSws) return;

  66.  

  67.  

    pictsrc.data[0] = src->y;

  68.  

    pictsrc.data[1] = src->u;

  69.  

    pictsrc.data[2] = src->v;

  70.  

    pictsrc.linesize[0] = src->w;

  71.  

    pictsrc.linesize[1] = src->w / 2;

  72.  

    pictsrc.linesize[2] = src->w / 2;

  73.  

  74.  

    pictdst.data[0] = dst->y;

  75.  

    pictdst.data[1] = dst->u;

  76.  

    pictdst.data[2] = dst->v;

  77.  

    pictdst.linesize[0] = dst->w;

  78.  

    pictdst.linesize[1] = dst->w / 2;

  79.  

    pictdst.linesize[2] = dst->w / 2;

  80.  

  81.  

    sws_scale(pSws, pictsrc.data, pictsrc.linesize, 0, src->h, pictdst.data, pictdst.linesize);

  82.  

  83.  

    }

  84.  

  85.  

    //将图像缩放到合成图像上 nOrder--图像位置0~5 对应于合成图像s1-s6

  86.  

    //这里用了两个变量来存储缩放后的图像 m_mainMerge--位置0 m_subMerge--其它位置

  87.  

    void CDigitalCourt::MergeImage(YUV_IMAGE *src, YUV_IMAGE *dst, UINT nOrder)

  88.  

    {

  89.  

  90.  

    UINT nOffY = 0, nOffx = 0,w=0,h=0;

  91.  

    SwsContext *pSws = NULL;

  92.  

    YUV_IMAGE *pImgSmall = NULL;

  93.  

  94.  

    if (NULL == src || NULL == dst || nOrder < 0 || nOrder >= MAX_CHANNEL_CNT)

  95.  

    {

  96.  

    return;

  97.  

    }

  98.  

    //根据位置找出图像Y偏移量

  99.  

    switch (nOrder)

  100.  

    {

  101.  

    case 0:

  102.  

    nOffx = 0;

  103.  

    nOffY = 0;

  104.  

    w = dst->w * 2 / 3;

  105.  

    h = dst->h * 2 / 3;

  106.  

    pImgSmall = &m_mainMerge;

  107.  

    break;

  108.  

    case 1:

  109.  

    nOffx = dst->w * 2 / 3;

  110.  

    nOffY = 0;

  111.  

    w = dst->w / 3;

  112.  

    h = dst->h / 3;

  113.  

    pImgSmall = &m_subMerge;

  114.  

    break;

  115.  

    case 2:

  116.  

    nOffx = dst->w * 2 / 3;

  117.  

    nOffY = dst->h / 3;

  118.  

    w = dst->w / 3;

  119.  

    h = dst->h / 3;

  120.  

    pImgSmall = &m_subMerge;

  121.  

    break;

  122.  

    case 3:

  123.  

    nOffx = dst->w * 2 / 3;

  124.  

    nOffY = dst->h * 2 / 3;

  125.  

    w = dst->w / 3;

  126.  

    h = dst->h / 3;

  127.  

    pImgSmall = &m_subMerge;

  128.  

    break;

  129.  

    case 4:

  130.  

    nOffx = dst->w / 3;

  131.  

    nOffY = dst->h * 2 / 3;

  132.  

    w = dst->w / 3;

  133.  

    h = dst->h / 3;

  134.  

    pImgSmall = &m_subMerge;

  135.  

    break;

  136.  

    case 5:

  137.  

    nOffx = 0;

  138.  

    nOffY = dst->h * 2 / 3;

  139.  

    w = dst->w / 3;

  140.  

    h = dst->h / 3;

  141.  

    pImgSmall = &m_subMerge;

  142.  

    break;

  143.  

    default:

  144.  

    LOG(LOG_ERROR, "CDigitalCourt::MergeImage failed of image order error!");

  145.  

    return;

  146.  

    }

  147.  

    //创建缩放器

  148.  

    pSws = CreateSws(src, nOrder, w, h);

  149.  

    //缩放

  150.  

    Scale(src, pImgSmall, pSws);

  151.  

    //图像粘贴

  152.  

    MapImage(pImgSmall, &m_MergeImg, nOffx, nOffY);

  153.  

    }

  154.  

    //图像黏贴

  155.  

    void MapImage(YUV_IMAGE *src, YUV_IMAGE *dst, UINT nOffX, UINT nOffY)

  156.  

    {

  157.  

    if (NULL == src || NULL == dst) return;

  158.  

    if (src->w > dst->w || src->h > dst->h) return;

  159.  

    if (NULL == src->y || NULL == src->u || NULL == src->v) return;

  160.  

    if (NULL == dst->y || NULL == dst->u || NULL == dst->v) return;

  161.  

  162.  

    UINT nOff = 0;

  163.  

    for (int i = 0; i < src->h; i++)

  164.  

    {

  165.  

    nOff = dst->w*(nOffY + i) + nOffX;

  166.  

    //逐行拷贝

  167.  

    memcpy(dst->y + nOff, src->y + src->w*i, src->w);

  168.  

    }

  169.  

    UINT nUVOffX = nOffX / 2, nUVOffY = nOffY / 2;

  170.  

    UINT nUVSrcW = src->w / 2, nUVSrcH = src->h / 2;

  171.  

    UINT nUVDstW = dst->w / 2, nUVDstH = dst->h / 2;

  172.  

  173.  

    for (int j = 0; j < nUVSrcH; j++)

  174.  

    {

  175.  

    nOff = nUVDstW*(nUVOffY + j) + nUVOffX;

  176.  

    memcpy(dst->u + nOff, src->u + nUVSrcW*j, nUVSrcW);

  177.  

    memcpy(dst->v + nOff, src->v + nUVSrcW*j, nUVSrcW);

  178.  

    }

  179.  

    }

原文地址:https://www.cnblogs.com/swing07/p/9710599.html

时间: 2024-10-12 07:36:21

画中画 视频合成的相关文章

FFmpeg+NeroAacEnc多音轨音频与视频合成

工欲善其事必先利其器,工具是必须先准备滴: FFmpeg:http://ffmpeg.zeranoe.com/builds/ ,选最新Static版本下载,exe程序在bin文件夹下,其他是开发者用的 NeroAacEnc:http://www.nero.com/eng/downloads-nerodigital-nero-aac-codec.php ,需填写邮箱地址才能下载. 下面开始吧 方法1 使用ffmpeg实现合并多个音频为一个音频的方法: http://blog.chinaunix.n

转载:ffmpeg 音视频合成分割

http://blog.csdn.net/jixiuffff/article/details/5709976 当然先安装了 gentoo 下一条命令搞定 emerge  ffmpeg 格式转换 (将file.avi 转换成output.flv) ffmpeg -i  file.avi   output.flv -i 表示输入文件 :现在有个视频video.avi,有个音频 audio.mp3,将其合并成output.avi 两个命令                     ( video2.av

如何使用ffmpeg进行音视频裁剪命令和音视频合成命令

音视频剪裁命令 ffmpeg -i input.mp4 -ss 00:00:00 -t 10 out.ts -i : 指定视频 -ss : 开始时间 -t : 指定裁剪的秒数 音视频合并的命令 ffmpeg -f concat -i inputs.txt out.flv -f concat : 指定为合并的指令 -i : 指定需要操作的命令 inputs.txt: 指定合并的文件,文件格式 file "文件名称" 举例inputs.txt file “1.ts” file “2.ts”

即时通讯工具的音视频本地合成录制

现在网上的一般音视频工具具有基本的视频.音频的即时通讯,但是能够实现中心录像的功能比较少,网上的AnyChat音视频互动平台,自AnyChat r4027版本开始,Windows平台(含Web平台)本地视频录制支持并列模式录制. Windows平台本地视频录制支持单用户录制.合成录制(画中画模式).并列录制,其中: 1.单用户录制是指整个录像文件只有一个用户的视频信息: 2.合成录制是指整个录像文件包括通话双方的视频信息,其中视频以画面迭加的形式展现: 3.并列录制是指整个录像文件包括通话双方的

音视频转码后合成的一些例子

1.android上录音AAC/MP3格式,未成功https://github.com/turkeyzhu/AACEncoder_Android2.通过mp4parser将AAC.h264.mp4格式合成MP4https://code.google.com/p/mp4parser/(mp4parser源码)https://github.com/sannies/mp4parser(使用mp4parser合成.转码MP4例子,该代码添加了其他东西,需要添加很多依赖库(主要是aspectjrt.jar

多个视频怎么合成一个,什么合并视频软件好用

视频的剪辑和合成是使用较多的一个功能,平时自己录制视频可能都会分享到社交平台上,然而在分享之前,我们必然会做很多的处理,比如滤镜,美颜,分割,合成等等的操作,前两者很简单,那怎么将录制的几个视频合成一个呢?可能很多朋友都还不知道该怎么解决这一问题,一起来看看多个视频怎么合成一个,什么合并视频软件好用吧!1.第一步,电脑上安装迅捷视频合并分割工具,打开这样一个集视频分割和合并的软件,左侧的第一个是分割功能,第二个就是合并功能:2.第二步,点击合并小按钮,在右侧可以看到操作步骤,首先要先添加视频内容

跨平台的即时通讯音视频解决方案

改变你视界的AnyChat,通过封装音视频编解码.流媒体处理以及P2P等专业复杂技术,为上层应用提供简单的API控制接口,实现一对一.一对多的实时音视频交互.文件传输.透明通道.音视频录制等功能.在移动互联网.物联网.在线教育.远程医疗.视频客服以及智能家居等业务领域拥有广泛的应用空间. 产品核心竞争力 一.音视频通信 承载数千客户的多形态音视频通信应用,近十年技术积累值得信赖,AnyChat将为您提供专业卓越的跨平台音视频通信服务体验.采用和优化H.264视频编解码,AAC音频编码标准与P2P

iOS 9 分屏多任务(3):画中画(PiP)快速入门

原文出处: @钢铁侠般的卿哥   欢迎分享原创到伯乐头条 该文档包含: 第一部分:iOS 9 分屏多任务–入门 第二部分:iOS 9 分屏多任务–Slide Over & Split View快速入门 第三部分:iOS 9 分屏多任务–画中画(PiP)快速入门 依据本章的指南在所支持的iPad上使用画中画(PiP). 想要让视频播放支持画中画模式,确保你Xcode项目和App配置如下: 设置Base SDK为“Latest iOS”,请参阅 App Distribution Guide 的 Se

即时通讯 音视频录制技术

音视频录制是音视频解决方案中最重要的功能特性之一,特别是一些行业应用中音视频录制是最基本的功能需求,AnyChat作为业界一流的跨平台音视频解决方案,在音视频录制方面也提供了非常完善的整体解决方案,概括起来有如下特点: 1.   可针对单个用户的音频.视频进行录制: 2.   可针对通话双方的音频.视频合成录制,支持画中画.并列模式等多种合成方式: 3.   可以自定义录制参数,包括录制码率.视频分辩率等: 4.   录制的视频格式可自定义,支持MP4(默认).WMV.FLV.MP3等: 5.