X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavfilter%2Fvf_nlmeans.c;h=dcb5a0395334565e798d730eebb1b932846df246;hb=0fef412dffb74fef3494f7fae0c138c32a444484;hp=547cb80acddff9a1ae8ddf2a5f297bb0df72ba0e;hpb=4278f79ef61058e3133214253a636113c18fb90a;p=ffmpeg diff --git a/libavfilter/vf_nlmeans.c b/libavfilter/vf_nlmeans.c index 547cb80acdd..dcb5a039533 100644 --- a/libavfilter/vf_nlmeans.c +++ b/libavfilter/vf_nlmeans.c @@ -43,9 +43,6 @@ struct weighted_avg { float sum; }; -#define WEIGHT_LUT_NBITS 9 -#define WEIGHT_LUT_SIZE (1<research_hsize, s->research_hsize_uv) + FFMAX(s->patch_hsize, s->patch_hsize_uv); - s->chroma_w = FF_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w); - s->chroma_h = FF_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h); + s->chroma_w = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w); + s->chroma_h = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h); s->nb_planes = av_pix_fmt_count_planes(inlink->format); /* Allocate the integral image with extra edges of thickness "e" @@ -393,19 +351,58 @@ static int nlmeans_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs const int slice_end = (process_h * (jobnr+1)) / nb_jobs; const int starty = td->starty + slice_start; const int endy = td->starty + slice_end; + const int p = td->p; + const uint32_t *ii = td->ii_start + (starty - p - 1) * s->ii_lz_32 - p - 1; + const int dist_b = 2*p + 1; + const int dist_d = dist_b * s->ii_lz_32; + const int dist_e = dist_d + dist_b; for (y = starty; y < endy; y++) { const uint8_t *src = td->src + y*src_linesize; struct weighted_avg *wa = s->wa + y*s->wa_linesize; for (x = td->startx; x < td->endx; x++) { - const uint32_t patch_diff_sq = get_integral_patch_value(td->ii_start, s->ii_lz_32, x, y, td->p); + /* + * M is a discrete map where every entry contains the sum of all the entries + * in the rectangle from the top-left origin of M to its coordinate. In the + * following schema, "i" contains the sum of the whole map: + * + * M = +----------+-----------------+----+ + * | | | | + * | | | | + * | a| b| c| + * +----------+-----------------+----+ + * | | | | + * | | | | + * | | X | | + * | | | | + * | d| e| f| + * +----------+-----------------+----+ + * | | | | + * | g| h| i| + * +----------+-----------------+----+ + * + * The sum of the X box can be calculated with: + * X = e-d-b+a + * + * See https://en.wikipedia.org/wiki/Summed_area_table + * + * The compute*_ssd functions compute the integral image M where every entry + * contains the sum of the squared difference of every corresponding pixels of + * two input planes of the same size as M. + */ + const uint32_t a = ii[x]; + const uint32_t b = ii[x + dist_b]; + const uint32_t d = ii[x + dist_d]; + const uint32_t e = ii[x + dist_e]; + const uint32_t patch_diff_sq = e - d - b + a; + if (patch_diff_sq < s->max_meaningful_diff) { - const unsigned weight_lut_idx = patch_diff_sq * s->pdiff_lut_scale; - const float weight = s->weight_lut[weight_lut_idx]; // exp(-patch_diff_sq * s->pdiff_scale) + const float weight = s->weight_lut[patch_diff_sq]; // exp(-patch_diff_sq * s->pdiff_scale) wa[x].total_weight += weight; wa[x].sum += weight * src[x]; } } + ii += s->ii_lz_32; } return 0; } @@ -524,11 +521,12 @@ static av_cold int init(AVFilterContext *ctx) const double h = s->sigma * 10.; s->pdiff_scale = 1. / (h * h); - s->max_meaningful_diff = -log(1/255.) / s->pdiff_scale; - s->pdiff_lut_scale = 1./s->max_meaningful_diff * WEIGHT_LUT_SIZE; - av_assert0((s->max_meaningful_diff - 1) * s->pdiff_lut_scale < FF_ARRAY_ELEMS(s->weight_lut)); - for (i = 0; i < WEIGHT_LUT_SIZE; i++) - s->weight_lut[i] = exp(-i / s->pdiff_lut_scale * s->pdiff_scale); + s->max_meaningful_diff = log(255.) / s->pdiff_scale; + s->weight_lut = av_calloc(s->max_meaningful_diff, sizeof(*s->weight_lut)); + if (!s->weight_lut) + return AVERROR(ENOMEM); + for (i = 0; i < s->max_meaningful_diff; i++) + s->weight_lut[i] = exp(-i * s->pdiff_scale); CHECK_ODD_FIELD(research_size, "Luma research window"); CHECK_ODD_FIELD(patch_size, "Luma patch"); @@ -556,6 +554,7 @@ static av_cold int init(AVFilterContext *ctx) static av_cold void uninit(AVFilterContext *ctx) { NLMeansContext *s = ctx->priv; + av_freep(&s->weight_lut); av_freep(&s->ii_orig); av_freep(&s->wa); }