• ffmpeg抠图


    1.不用png,用AVFrame
    2.合流
    3.图片抠图透明 (1.)mp4扣yuv图,(2)用1.把一张yuv标记为透明然后av_hwframe_transfer_data到GPU (3)用抠图算法函数对yuv进行处理 (4)
    qsv的h264_qsv只支持nv12和qsv,但qsv本身并不限制像素格式,比如在qsv里可以用vpp_qsv=format输出各种像素格式。因此以上第二种方法可能可行。
    av_hwframe_transfer_data转换不了可能是硬件帧函数配置的像素格式出的问题。

    ffmpeg -y   -i TJTV.png -vf  colorkey=0x0000FF:0.5:0.0    -c:v png t.png
    
    • 1

    0x0000FF:六位每两位分别表示红绿蓝,因此它是对rgb像素进行透明标记。
    0.5表示蓝色的范围容差值,范围为0.01-1,数值越大,容错越大。
    0.0是alpha通道的阀值,为0表示完全透明,实测这个值作用不明显。
    对于TJTV.png,可以看到它的编码和封装方式都是png,它的像素格式为rgba。

    Stream #0:0: Video: png, rgba(pc), 280x279 [SAR 2835:2835 DAR
    280:279], 25 fps, 25 tbr, 25 tbn

    这个命令只能对rgb的像素格式进行透明标记,但是对yuv得不能,会导致花屏。只有argb、rgba等带透明度格式的像素格式才能进行抠图透明标记。
    透明的原理是对rgb数据逐个像素处理,修改rgb值,达到对特定的像素进行透明标记。
    透明的原理是对rgb或yuv增加第四个Alpha通道,这个通道的值由一个byte表示,不同的值表示透明程度不同,Alpha的值与其他yuv、rgb值作用来改变灰阶度来达到透明效果。
    chromakey与colorkey的区别,官网给了这四个例子

    ffmpeg -i input.png -vf colorkey=green out.png
    
    • 1
    ffmpeg -i background.png -i video.mp4 -filter_complex "[1:v]colorkey=0x3BBD1E:0.3:0.2[ckout];[0:v][ckout]overlay[out]" -map "[out]" output.flv
    
    • 1
    ffmpeg -i input.png -vf chromakey=green out.png
    
    • 1
    ffmpeg -f lavfi -i color=c=black:s=1280x720 -i video.mp4 -shortest -filter_complex "[1:v]chromakey=0x70de77:0.1:0.2[ckout];[0:v][ckout]overlay[out]" -map "[out]" output.mkv
    
    • 1

    clolorkey是对yuv数据进行处理,但它的三个参数值依然和colorkey同样的用法。对yuv进行透明标记后,如果再次编码,那么标记就会失效。同时如果对rtb图像进行标记后,如果转为yuv,则标记同样失效并且花屏。
    以下是去除绿色背景。

    在这里插入图片描述

    
    ffmpeg -h filter=colorkey
    
    Filter colorkey
      Turns a certain color into transparency. Operates on RGB colors.
        slice threading supported
        Inputs:
           #0: default (video)
        Outputs:
           #0: default (video)
    colorkey AVOptions:
       color             <color>      ..FV.....T. set the colorkey key color (default "black")
       similarity        <float>      ..FV.....T. set the colorkey similarity value (from 1e-05 to 1) (default 0.01)
       blend             <float>      ..FV.....T. set the colorkey key blend value (from 0 to 1) (default 0)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    ffmpeg -h filter=chromakey
    
    Filter chromakey
      Turns a certain color into transparency. Operates on YUV colors.
        slice threading supported
        Inputs:
           #0: default (video)
        Outputs:
           #0: default (video)
    chromakey AVOptions:
       color             <color>      ..FV.....T. set the chromakey key color (default "black")
       similarity        <float>      ..FV.....T. set the chromakey similarity value (from 1e-05 to 1) (default 0.01)
       blend             <float>      ..FV.....T. set the chromakey key blend value (from 0 to 1) (default 0)
       yuv               <boolean>    ..FV.....T. color parameter is in yuv instead of rgb (default false)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    第四个参数默认为false,也就是前面传递的是grb信号值,如果为true的话,颜色传递的信号已经是YUV而不是RGB。像"green"或"red"这样的字面颜色不再有意义了。 这可以用于将精确的YUV值作为十六进制数传递。

    附录:
    1.ffmpeg滤镜chromakey针对yuv处理,将对应像素点标记透明。

    typedef struct ColorkeyContext {
        const AVClass *class;
     
        /* color offsets rgba */
        int co[4];
     
        uint8_t colorkey_rgba[4];
        float similarity;
        float blend;
    } ColorkeyContext;
     
    static uint8_t do_chromakey_pixel(ChromakeyContext *ctx, uint8_t u[9], uint8_t v[9])
    {
        double diff = 0.0;
        int du, dv, i;
    
        for (i = 0; i < 9; ++i) {
            du = (int)u[i] - ctx->chromakey_uv[0];
            dv = (int)v[i] - ctx->chromakey_uv[1];
    
            diff += sqrt((du * du + dv * dv) / (255.0 * 255.0 * 2));
        }
    
        diff /= 9.0;
    
        if (ctx->blend > 0.0001) {
            return av_clipd((diff - ctx->similarity) / ctx->blend, 0.0, 1.0) * 255.0;
        } else {
            return (diff > ctx->similarity) ? 255 : 0;
        }
    }
    static int do_chromakey_slice(AVFilterContext *avctx, void *arg, int jobnr, int nb_jobs)
    {
        AVFrame *frame = arg;
    
        const int slice_start = (frame->height * jobnr) / nb_jobs;
        const int slice_end = (frame->height * (jobnr + 1)) / nb_jobs;
    
        ChromakeyContext *ctx = avctx->priv;
    
        int x, y, xo, yo;
        uint8_t u[9], v[9];
    
        memset(u, ctx->chromakey_uv[0], sizeof(u));
        memset(v, ctx->chromakey_uv[1], sizeof(v));
    
        for (y = slice_start; y < slice_end; ++y) 
        {
            for (x = 0; x < frame->width; ++x) 
            {
                for (yo = 0; yo < 3; ++yo) 
                {
                    for (xo = 0; xo < 3; ++xo) 
                    {
                        get_pixel_uv(frame, ctx->hsub_log2, ctx->vsub_log2, x + xo - 1, y + yo - 1, &u[yo * 3 + xo], &v[yo * 3 + xo]);
                    }
                }
    
                frame->data[3][frame->linesize[3] * y + x] = do_chromakey_pixel(ctx, u, v);
            }
        }
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    2.ffmpeg滤镜colorkey针对rgb处理,将目标像素点设置为透明。

    static uint8_t do_colorkey_pixel(ColorkeyContext *ctx, uint8_t r, uint8_t g, uint8_t b)
    {
        int dr = (int)r - ctx->colorkey_rgba[0];
        int dg = (int)g - ctx->colorkey_rgba[1];
        int db = (int)b - ctx->colorkey_rgba[2];
    
    	//计算相似度
        double diff = sqrt((dr * dr + dg * dg + db * db) / (255.0 * 255.0 * 3.0));
    
        if (ctx->blend > 0.0001) {
            return av_clipd((diff - ctx->similarity) / ctx->blend, 0.0, 1.0) * 255.0;
        } else {
            return (diff > ctx->similarity) ? 255 : 0;
        }
    }
    static int do_colorkey_slice(AVFilterContext *avctx, void *arg, int jobnr, int nb_jobs)
    {
        AVFrame *frame = arg;
    
        const int slice_start = (frame->height * jobnr) / nb_jobs;
        const int slice_end = (frame->height * (jobnr + 1)) / nb_jobs;
    
        ColorkeyContext *ctx = avctx->priv;
    
        int o, x, y;
    
        for (y = slice_start; y < slice_end; ++y) {
            for (x = 0; x < frame->width; ++x) {
                o = frame->linesize[0] * y + x * 4;
    			// 修改rgba a数据
                frame->data[0][o + ctx->co[3]] =
                    do_colorkey_pixel(ctx,
                                      frame->data[0][o + ctx->co[0]],
                                      frame->data[0][o + ctx->co[1]],
                                      frame->data[0][o + ctx->co[2]]);
            }
        }
    
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    参考:
    http://ffmpeg.org/ffmpeg-filters.html#colorkey
    ffmpeg绿幕抠图原理解析

    ffmpeg是音视频必备,但即使从业数年,它似乎依然有无穷的秘密,感兴趣添加笔者微信:YQW1163720468,加入ffmpeg微信群讨论。但记得备注:ffmpeg爱好者

    colorkey抠一下 效果不一定好,边框可能有细微问题,可以先hsv处理一下在抠
    《深入理解FFmpeg》

    ffmpeg -i 20190323162628578.png -i juren-30s.mp4 -filter_complex “[0:v]colorkey=0x00FF00:0.1:0[out];[1:v][out]overlay[re]” -map [re] -c:v h264_qsv re.mp4

    转成yuv就会花屏
    ffmpeg -i 20190323162628578.png  -vf  "colorkey=0x00FF00:0.5:0"      -pix_fmt yuv420p t.yuv
    ffplay -video_size 146x60 -pixel_format yuv420p -i t.yuv
    
    • 1
    • 2
    • 3
    这样OK
    ffmpeg -i 20190323162628578.png  -vf  "colorkey=0x00FF00:0.5:0"     t.png
    ffplay t.png
    
    • 1
    • 2
    • 3
    这样OK
    ffmpeg -i 20190323162628578.png  -vf  "colorkey=0x00FF00:0.5:0"      -pix_fmt yuva420p t.yuv
    ffplay -video_size 146x60 -pixel_format yuva420p -i t.yuv
    
    • 1
    • 2
    • 3
    palettegen滤镜也可以设置透明度
    ffmpeg -i "./了不起\3D%02d.png" -filter_complex "[0:v]scale=700:700:force_original_aspect_ratio=decrease,format=rgba,fps=25,split[v0][v1];[v0]palettegen=reserve_transparent=on:transparency_color=00000000[v];[v1][v]paletteuse" -y 了不起.gif
    
    • 1
    • 2
  • 相关阅读:
    mysql -mmm
    一幅长文细学node.js——一幅长文系列
    QCC51XX---BLE_生活中的实例_医院的结构
    【Proteus仿真】【Arduino单片机】DS18B20温度计
    服务器抓包简介
    2022年全球市场胃管泵总体规模、主要生产商、主要地区、产品和应用细分研究报告
    在VS Code 中调试远程服务器的PHP代码
    冒泡排序及其优化
    【网络八股】TCP八股
    内网安全-内网穿透
  • 原文地址:https://blog.csdn.net/weixin_43466192/article/details/133020957