視頻疊加算法-白色素材疊加

相關(guān)

視頻疊加算法-黑色素材疊加
視頻疊加算法-彩色素材疊加
視頻疊加算法-彩色加亮融合
視頻疊加算法-彩色均值融合

引言

如果想在之上疊加一個靜止圖片很簡單,像ffmpeg的濾鏡、opencv等都能實現(xiàn)。但是假如文字擁有動畫,而且文字出現(xiàn)比較頻繁,全部使用序列的png圖像會很大。例如如下的素材:

白色素材

這樣一來,只能圖片壓縮成視頻再往原視頻上疊加。由于視頻解碼得來的是yuv格式,沒有alpha通道,不能像常規(guī)圖像疊加算法那樣,將alpha通道值作為疊加權(quán)重進行疊加。
于是寫了疊加白色內(nèi)容的素材視頻到另一個視頻之上的算法(針對Ycbcr420p)。

算法實現(xiàn)

原視頻:

input

基于ffmpeg框架,不過只是用到了部分ffmpeg的結(jié)構(gòu)體和函數(shù),算法主體還是用c語言自主實現(xiàn)的。代碼中有注釋,關(guān)鍵處也已經(jīng)標注拿出來解釋。
#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數(shù)據(jù)寫入文件
        }
        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.截圖一幀素材數(shù)據(jù):

frame

觀察可得,其實對于一幀文字疊加的素材視頻,有大多區(qū)域是可以跳過的,因為都是純黑色,也就是我們想跳過的全透明(因為其編碼成了視頻,并且選用的yuv的顏色空間,所以其實其y值是16,并非png中的透明),所以申請了一行數(shù)據(jù)的buff設(shè)置成為純黑的y值,如果該行是純黑色,就跳過該行。其實最好的處理方式是將文字的素材做成適當大小的視頻,盡量將視頻尺寸降低,然后在疊加時候通過目標坐標指定素材需要疊加的位置。從而減少歷遍的次數(shù),有效提升算法效率。

frame&data

選取文字邊緣的色塊(即圖片中的紅色方塊區(qū)域),觀察其y值發(fā)現(xiàn),黑色區(qū)域y值都是16,當然通過計算公式也可知道。但是在白色邊緣地帶,非我們想要摳出的區(qū)域仍然有大于16的y值出現(xiàn)。其y值出現(xiàn)的頻率圖大致是:

概率曲線

選用16作拐點的話,會出現(xiàn)大量黑邊,所以選用40作為拐點來分離出文字信息。但是也會引發(fā)邊緣區(qū)域消失,粉末狀的區(qū)域別忽視的問題。另外選用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值應(yīng)該是128,無色偏。所以素材視頻中y值越大于16就使原視頻中對應(yīng)像素uv值越趨近128.

存在問題

  • 應(yīng)該將素材視頻生成的尺寸縮小,通過指定坐標的方法融合,從而提升算法效率。

  • 會忽略素材視頻中的細節(jié),最終視頻中有鋸齒。

  • 待疊加的只能有白色,如果其他顏色會根據(jù)顏色的Y值大小轉(zhuǎn)換為白色,彩色素材視頻的疊加參看。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

  • 一、實驗?zāi)康?學習使用 weka 中的常用分類器,完成數(shù)據(jù)分類任務(wù)。 二、實驗內(nèi)容 了解 weka 中 explo...
    yigoh閱讀 8,844評論 5 4
  • 相關(guān) 視頻疊加算法-白色素材疊加視頻疊加算法-黑色素材疊加視頻疊加算法-彩色加亮融合視頻疊加算法-彩色均值融合 引...
    Don_閱讀 1,221評論 0 6
  • 相關(guān) 視頻疊加算法-白色素材疊加視頻疊加算法-彩色素材疊加視頻疊加算法-彩色加亮融合視頻疊加算法-彩色均值融合 引...
    Don_閱讀 2,095評論 0 4
  • 六月很熱 六月很忙 六月畢業(yè) 天各一方 太多的情感無處釋放 只等默念回想 太多的記憶瞬間轉(zhuǎn)移 只有孤單狂歡打烊 太...
    安嫚兒閱讀 346評論 15 10
  • 閨蜜幾個碰在一起,不知道怎么的就開始討論感情問題。 女人么,在一起要是不八卦這些事情,那才是怪事兒。東拉西扯是女人...
    木黎閱讀 21,392評論 76 319

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