ffmpeg中的gblur实现

一 glur是高斯blur的缩写

简单来说就是通过周围的像素点计算得到中间像素点的值,ffmpeg中gblur滤镜只考虑了上下左右四个点,然后有一个强度系数sigma。

二 代码走读

2.1 整体流程

把原画copy到申请的buffer -> 在buffer中完成gblur模糊,行上和列上面是分开做的->把buffer中blur好的画面copy到out帧中

     if (s->depth == 8) {
            for (y = 0; y < height; y++) {
                for (x = 0; x < width; x++) {
                    bptr[x] = src[x];//先循环吧数据copy到buffer里面
                }
                bptr += width;
                src += in->linesize[plane];
            }
        } else {
            for (y = 0; y < height; y++) {
                for (x = 0; x < width; x++) {
                    bptr[x] = src16[x];
                }
                bptr += width;
                src16 += in->linesize[plane] / 2;
            }
        }

        gaussianiir2d(ctx, plane);

        bptr = s->buffer;
        if (s->depth == 8) {
            for (y = 0; y < height; y++) {
                for (x = 0; x < width; x++) {
                    dst[x] = bptr[x];//吧数据从buffer里面copy到目标帧里面
                }
                bptr += width;
                dst += out->linesize[plane];
            }
        } else {
            for (y = 0; y < height; y++) {
                for (x = 0; x < width; x++) {
                    dst16[x] = bptr[x];
                }
                bptr += width;
                dst16 += out->linesize[plane] / 2;
            }
        }

三 行列上的blur

列上的blur,地址不是连续的不能使用SIMD

static int filter_vertically(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
{
    GBlurContext *s = ctx->priv; //参数数据
    ThreadData *td = arg; //线程上下文
    const int height = td->height; //高度
    const int width = td->width; //宽度
    const int slice_start = (width *  jobnr   ) / nb_jobs; //起始列
    const int slice_end   = (width * (jobnr+1)) / nb_jobs;//结束lie 
    const float boundaryscale = s->boundaryscaleV;//输入参数
    const int steps = s->steps;//步长
    const float nu = s->nuV; //列强度
    float *buffer = s->buffer;//缓存buffer
    int aligned_end; //对其

    aligned_end = slice_start + (((slice_end - slice_start) >> 3) << 3);
    /* Filter vertically along columns (process 8 columns in each step)  对齐的列*/
    do_vertical_columns(buffer, width, height, slice_start, aligned_end,
                        steps, nu, boundaryscale, 8); // 8列一组

    /* Filter un-aligned columns one by one 对齐的列 */
    do_vertical_columns(buffer, width, height, aligned_end, slice_end,
                        steps, nu, boundaryscale, 1); //一列一组
    return 0;
}
static void do_vertical_columns(
float *buffer, // 缓存buffer,一个像素一个值
int width, //宽
int height, //高
int column_begin, //起始列 
int column_end,  //结束列
int steps, //窗口size
float nu,  //nu系数
float boundaryscale,  //强度scale
int column_step) //列step
{
    const int numpixels = width * height; //像素树木
    int i, x, k, step;
    float *ptr;
    for (x = column_begin; x < column_end;) { //从起始列循环到结束列
        for (step = 0; step < steps; step++) { //循环遍历窗口
            ptr = buffer + x;// 缓存地址起点
            for (k = 0; k < column_step; k++) { //每间隔step 乘以系数boundaryscale ,step 每次8个一组
                ptr[k] *= boundaryscale;
            }
            /* Filter downwards */
            for (i = width; i < numpixels; i += width) { //滤波每一列,遍历每一个像素
                for (k = 0; k < column_step; k++) {
                    ptr[i + k] += nu * ptr[i - width + k]; //周围点的带权求和
                    /*
                    
                    * (参考点)    
                    *(当前点)
                    
                    当前点的值 = 上一个点 * 一定的系数
                    */
                }
            }
            i = numpixels - width; //最后一行

            for (k = 0; k < column_step; k++)  //column_step = 8
                ptr[i + k] *= boundaryscale; //

            /* Filter upwards 下一行的系数*/
            for (; i > 0; i -= width) {
                for (k = 0; k < column_step; k++)
                    ptr[i - width + k] += nu * ptr[i + k]; //当前点,下一个点
            }
        }
        x += column_step;
    }
}

行上的blur

static void horiz_slice_c(float *buffer, int width, int height, int steps,
                          float nu, float bscale)
{ //行上blur C语言版本
//还有intrisic版本
    int step, x, y;
    float *ptr;
    for (y = 0; y < height; y++) {
        for (step = 0; step < steps; step++) {
            ptr = buffer + width * y; //先取到这一行的内存
            ptr[0] *= bscale;

            /* Filter rightwards */
            for (x = 1; x < width; x++)
                ptr[x] += nu * ptr[x - 1]; //行上当前点和前一个点,向右考虑
            ptr[x = width - 1] *= bscale;

            /* Filter leftwards */
            for (; x > 0; x--) //循环,向左考虑
                ptr[x - 1] += nu * ptr[x];//当前点的位置前一个点。
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值