多视频叠加-黑色素材叠加

相关

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

引言

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

黑色素材

虽然与白色素材叠加算法中所用素材相同,但目的不同,以下demo将素材以“黑色部分叠加,白色区域透明”的效果叠加到视频之上。

算法实现

原视频:

input
#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 frame_cover_black( AVFrame* dst_frame, AVFrame* src_frame, AVFrame* cover_frame);
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 main (char** args, int argv)
{
    char* file = "test.yuv";
    char* light = "light.yuv";
    char* lightout = "lightout.yuv";
    int width = 480;
    int height = 480;
    mergeyuv(file,light,lightout,width,height);
    return 0;
}
int mergeyuv(char* file, char* light,char* lightout,int width,int height)
{
    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_black(readframe,readframe,lightframe);
            write_yuvframe(readframe,outfile);
        }
        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;
}
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_black( AVFrame* dst_frame, AVFrame* src_frame, AVFrame* cover_frame)
{
    if(dst_frame == NULL || src_frame == NULL || cover_frame == NULL)
    {
        puts("frame_cover_black input or output frame is NULL");
        return -1;
    }
    int w2 = cover_frame->width;
    int h2 = cover_frame->height;
    int i = 0, j = 0;
    int a, a2;
    float rat;
    for(i = 0; i < h2; i++)
    {
        for(j = 0; j < w2; j++)
        {
            a2 = cover_frame->data[0][i * cover_frame->linesize[0] + j];
            a2 = a2 >= 0 ? a2 : 256 + a2;
            if(a2 <= 32)
            {
                dst_frame->data[1][(j >> 1) + (int)(i >> 1) * (dst_frame->linesize[1])] = cover_frame->data[1][(j >> 1) + (int)(i >> 1) * (cover_frame->linesize[1])];
                dst_frame->data[2][(j >> 1) + (int)(i >> 1) * (dst_frame->linesize[2])] = cover_frame->data[2][(j >> 1) + (int)(i >> 1) * (cover_frame->linesize[2])];
                dst_frame->data[0][i * dst_frame->linesize[0] + j] = 16;
                continue;
            }
            a = src_frame->data[0][i * src_frame->linesize[0] + j];
            a  = a >= 0 ? a : 256 + a;
            rat = (double)a2 / 256;
            rat = rat > 1 ? 1 : rat;
            dst_frame->data[0][i * dst_frame->linesize[0] + j] = a * rat;
        }
    }
    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);
    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

注:

选用16作拐点的话,会出现大量泛白区域,所以选用32作为拐点来分离出黑色区域。但是同样会忽视某些细节。当然,很可能这些细节是由于编码的“有损”而产生的。使用200 作为全透明峰值。
y为素材视频对应点的Y值,d(包含uv)为输出帧的数据
if y< 32
d设置为黑色
else if y< 200
d按比例趋近黑色
else
忽视素材叠加,取原帧对应点数据
具体解释参看视频叠加算法-白色素材叠加

三 待改进

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

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

3 对于半透明处,也就是算法中 d按比例趋近黑色处,该计算方法会使得输出视频透明略显生硬,梯度并不明显,该处计算方法待改进。

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

推荐阅读更多精彩内容

  • 相关 视频叠加算法-黑色素材叠加视频叠加算法-彩色素材叠加视频叠加算法-彩色加亮融合视频叠加算法-彩色均值融合 引...
    Don_阅读 3,113评论 3 10
  • 相关 视频叠加算法-白色素材叠加视频叠加算法-黑色素材叠加视频叠加算法-彩色加亮融合视频叠加算法-彩色均值融合 引...
    Don_阅读 1,147评论 0 6
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,471评论 25 707
  • 文/唐朝 期待着 那一场下在三月的白雪 所有的灵动都是为了走向远方 云朵遮掩不了太阳 挂一张牌 身份 昭然若揭 ...
    绽放唐朝阅读 459评论 2 1
  • 三十六岁了,即将到来的却是我的第四个清明节。 从小没有见过奶奶。爷爷离世时,我才九岁。幼时迟钝,对生死的概念不太清...
    赵都四哥阅读 385评论 2 4