视频叠加算法-白色素材叠加

相关

视频叠加算法-黑色素材叠加
视频叠加算法-彩色素材叠加
视频叠加算法-彩色加亮融合
视频叠加算法-彩色均值融合

引言

如果想在之上叠加一个静止图片很简单,像ffmpeg的滤镜、opencv等都能实现。但是假如文字拥有动画,而且文字出现比较频繁,全部使用序列的png图像会很大。例如如下的素材:

白色素材

这样一来,只能图片压缩成视频再往原视频上叠加。由于视频解码得来的是yuv格式,没有alpha通道,不能像常规图像叠加算法那样,将alpha通道值作为叠加权重进行叠加。
于是写了叠加白色内容的素材视频到另一个视频之上的算法(针对Ycbcr420p)。

算法实现

原视频:

input

基于ffmpeg框架,不过只是用到了部分ffmpeg的结构体和函数,算法主体还是用c语言自主实现的。代码中有注释,关键处也已经标注拿出来解释。
#include <stdio.h>
#include <math.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/frame.h>
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>
#include <libavutil/pixfmt.h>

#ifdef __cplusplus
};
#endif
int init_frame(AVFrame* frame,int width,int height,uint8_t* dst_buff);
int mergeyuv(char* file, char* light,char* lightout,int width,int height);
int write_yuvframe(AVFrame *pFrame,FILE *out);
int frame_cover_white( AVFrame* dst_frame, AVFrame* src_frame, AVFrame* cover_frame);
int main (char** args, int argv)
{
    char* file_in = "test.yuv";
    char* light = "light.yuv";
    char* file_out = "lightout.yuv";
    int width = 480;
    int height = 480;
    mergeyuv(file_in ,light,file_out,width,height);
    return 0;
}
//融合整个yuv文件
int mergeyuv(char* file, char* light,char* lightout,int width,int height)
{
    //初始化帧、buff以及文件
    AVFrame* readframe,*lightframe,*outframe;
    readframe = av_frame_alloc();
    lightframe = av_frame_alloc();
    outframe = av_frame_alloc();
    FILE* readfile = (FILE*)fopen(file,"rb");
    FILE* lightfile = (FILE*)fopen(light,"rb");
    FILE* outfile = (FILE*)fopen(lightout,"wb+");
    if(lightfile==NULL||readframe==NULL||outfile==NULL)
        return -1;
    int length = width*height*3/2;
    uint8_t* readbuff = (uint8_t*)malloc(length);
    uint8_t* lightbuff = (uint8_t*)malloc(length);
    uint8_t* outbuff = (uint8_t*)malloc(length);
    init_frame(readframe,width,height,readbuff);
    init_frame(lightframe,width,height,lightbuff);
    init_frame(outframe,width,height,outbuff);
    while(fread(readbuff,1,length,readfile))//读取原视频帧
    {
        if(fread(lightbuff,1,length,lightfile))//读取待叠加的帧
        {
            puts("mrege one frame");
            frame_cover_white(readframe,readframe,lightframe);//算法是原址的
            write_yuvframe(readframe,outfile);//将yuv数据写入文件
        }
        else
            break;
    }
    fclose(readfile);
    fclose(lightfile);
    fclose(outfile);
    free(readbuff);
    free(lightbuff);
    free(outbuff);
    av_frame_free(&readframe);
    av_frame_free(&lightframe);
    av_frame_free(&outframe);
    return 0;
}
//init 一帧
int init_frame(AVFrame* frame,int width,int height,uint8_t* dst_buff)
{

    if(!avpicture_fill((AVPicture *) frame, dst_buff, AV_PIX_FMT_YUV420P,width,height))
    {
        puts("init frame error");
        av_frame_free(&frame);
        return NULL;
    }
    frame->width=width;
    frame->height=height;
    frame->format = AV_PIX_FMT_YUV420P;
    return 0;
}
//叠加帧
int frame_cover_white( AVFrame* dst_frame, AVFrame* src_frame, AVFrame* cover_frame)
{
    if(dst_frame == NULL || src_frame == NULL || cover_frame == NULL)//检查合法性
    {
        puts("frame_cover_white input or output frame is NULL");
        return -1;
    }
    char* tempblack = (char*)malloc(sizeof(char) * cover_frame->linesize[0]);//参看算法讨论1
    memset(tempblack, 16, cover_frame->linesize[0]);

    int w2 = cover_frame->width;
    int h2 = cover_frame->height;

    int i = 0,j = 0;
    int temp,a,u,v,a2;
    float rat;
    int yindex = 0;
    int yindex2,uindex2;
    for(i = 0;i<h2;i++)
    {
        yindex = i*cover_frame->linesize[0];
        if(strncmp((char*)cover_frame->data[0]+yindex,tempblack,cover_frame->linesize[0])==0)//参看注1
        {
            continue;
        }
        yindex2 = i*src_frame->linesize[0];
        uindex2 = (i>>1)*src_frame->linesize[1];

        for(j=0;j<w2;j++)
        {

            a2 = cover_frame->data[0][yindex];
            if(a2 <= 40)//参看算法讨论2
            {
                yindex++;
                yindex2++;
                if(j%2!=0)
                    uindex2++;
                continue;
            }
            a = src_frame->data[0][yindex2];
            rat = a2*a2/40000.0;//参看算法讨论2
      
            if(rat > 1)
                rat = 1;

            temp = a+(255-a)*rat;

            dst_frame->data[0][yindex2] = (char)temp;
            u = src_frame->data[1][uindex2];
            v = src_frame->data[2][uindex2];
            dst_frame->data[1][uindex2]= u+(int)((128-u)*rat);//参看算法讨论3
            dst_frame->data[2][uindex2]= v+(int)((128-v)*rat);
            yindex++;
            yindex2++;
            if(j%2!=0)
                uindex2++;
        }
    }

    free(tempblack);
    return 0;
}
int write_yuvframe(AVFrame *pFrame,FILE *out)
{
    int height = pFrame->height,width = pFrame->width;
    if(pFrame==NULL)
    {
        puts("error:write frame is null");
        return -1;
    }
    if(out == NULL)
    {
        puts("give write file is null");
        return -1;
    }
    int j = 0;

    for (j = 0; j < height; j++)
        fwrite(pFrame->data[0] + j * pFrame->linesize[0], 1, width, out);//参看注4

    for (j = 0; j < height / 2; j++)
        fwrite(pFrame->data[1] + j * pFrame->linesize[1], 1, width / 2, out);

    for (j = 0; j < height / 2; j++)
        fwrite(pFrame->data[2] + j * pFrame->linesize[2], 1, width / 2,out);
    return 0;

}

输出效果:

output

算法讨论

1.截图一帧素材数据:

frame

观察可得,其实对于一帧文字叠加的素材视频,有大多区域是可以跳过的,因为都是纯黑色,也就是我们想跳过的全透明(因为其编码成了视频,并且选用的yuv的颜色空间,所以其实其y值是16,并非png中的透明),所以申请了一行数据的buff设置成为纯黑的y值,如果该行是纯黑色,就跳过该行。其实最好的处理方式是将文字的素材做成适当大小的视频,尽量将视频尺寸降低,然后在叠加时候通过目标坐标指定素材需要叠加的位置。从而减少历遍的次数,有效提升算法效率。

frame&data

选取文字边缘的色块(即图片中的红色方块区域),观察其y值发现,黑色区域y值都是16,当然通过计算公式也可知道。但是在白色边缘地带,非我们想要抠出的区域仍然有大于16的y值出现。其y值出现的频率图大致是:

概率曲线

选用16作拐点的话,会出现大量黑边,所以选用40作为拐点来分离出文字信息。但是也会引发边缘区域消失,粉末状的区域别忽视的问题。另外选用200作为最大值。其处理算法为:

if y< 40
忽视
else if y< 200
按比例趋近白色
else
完全替换原视频y值

  1. ycbcr计算公式为:

Y’ = 0.257R' + 0.504G' + 0.098B' + 16
Cb' = -0.148
R' - 0.291G' + 0.439B' + 128
Cr' = 0.439R' - 0.368G' - 0.071B' + 128
'R = 1.164
(Y’-16) + 1.596(Cr'-128)
B' = 1.164
(Y’-16) + 2.017(Cb'-128)
G' = 1.164
(Y’-16) - 0.813(Cr'-128) - 0.392(Cb'-128)

黑色和白色uv值应该是128,无色偏。所以素材视频中y值越大于16就使原视频中对应像素uv值越趋近128.

存在问题

  • 应该将素材视频生成的尺寸缩小,通过指定坐标的方法融合,从而提升算法效率。

  • 会忽略素材视频中的细节,最终视频中有锯齿。

  • 待叠加的只能有白色,如果其他颜色会根据颜色的Y值大小转换为白色,彩色素材视频的叠加参看。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • 一、实验目的 学习使用 weka 中的常用分类器,完成数据分类任务。 二、实验内容 了解 weka 中 explo...
    yigoh阅读 8,500评论 5 4
  • 相关 视频叠加算法-白色素材叠加视频叠加算法-黑色素材叠加视频叠加算法-彩色加亮融合视频叠加算法-彩色均值融合 引...
    Don_阅读 1,181评论 0 6
  • 相关 视频叠加算法-白色素材叠加视频叠加算法-彩色素材叠加视频叠加算法-彩色加亮融合视频叠加算法-彩色均值融合 引...
    Don_阅读 1,908评论 0 4
  • 六月很热 六月很忙 六月毕业 天各一方 太多的情感无处释放 只等默念回想 太多的记忆瞬间转移 只有孤单狂欢打烊 太...
    安嫚儿阅读 294评论 15 10
  • 闺蜜几个碰在一起,不知道怎么的就开始讨论感情问题。 女人么,在一起要是不八卦这些事情,那才是怪事儿。东拉西扯是女人...
    木黎阅读 21,308评论 76 319