float threshold;
float percent;
int method;
+ int type;
int nsteps;
int planes;
void (*thresholding)(float *block, const int width, const int height,
const int stride, const float threshold,
- const float percent, const int nsteps);
+ const float percent);
} VagueDenoiserContext;
#define OFFSET(x) offsetof(VagueDenoiserContext, x)
{ "method", "set filtering method", OFFSET(method), AV_OPT_TYPE_INT, {.i64=2 }, 0, 2, FLAGS, "method" },
{ "hard", "hard thresholding", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "method" },
{ "soft", "soft thresholding", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "method" },
- { "garrote", "garotte thresholding", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "method" },
+ { "garrote", "garrote thresholding", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "method" },
{ "nsteps", "set number of steps", OFFSET(nsteps), AV_OPT_TYPE_INT, {.i64=6 }, 1, 32, FLAGS },
{ "percent", "set percent of full denoising", OFFSET(percent),AV_OPT_TYPE_FLOAT, {.dbl=85}, 0,100, FLAGS },
{ "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=15 }, 0, 15, FLAGS },
+ { "type", "set threshold type", OFFSET(type), AV_OPT_TYPE_INT, {.i64=0 }, 0, 1, FLAGS, "type" },
+ { "universal", "universal (VisuShrink)", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "type" },
+ { "bayes", "bayes (BayesShrink)", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "type" },
{ NULL }
};
static int query_formats(AVFilterContext *ctx)
{
static const enum AVPixelFormat pix_fmts[] = {
- AV_PIX_FMT_GRAY8,
- AV_PIX_FMT_GRAY16,
+ AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10,
+ AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16,
AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P,
AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P,
AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P,
AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16,
AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10,
AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16,
+ AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P,
+ AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA444P12, AV_PIX_FMT_YUVA444P16,
+ AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA422P12, AV_PIX_FMT_YUVA422P16,
+ AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA420P16,
+ AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16,
AV_PIX_FMT_NONE
};
AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
static void hard_thresholding(float *block, const int width, const int height,
const int stride, const float threshold,
- const float percent, const int unused)
+ const float percent)
{
const float frac = 1.f - percent * 0.01f;
int y, x;
}
static void soft_thresholding(float *block, const int width, const int height, const int stride,
- const float threshold, const float percent, const int nsteps)
+ const float threshold, const float percent)
{
const float frac = 1.f - percent * 0.01f;
const float shift = threshold * 0.01f * percent;
- int w = width;
- int h = height;
- int y, x, l;
-
- for (l = 0; l < nsteps; l++) {
- w = (w + 1) >> 1;
- h = (h + 1) >> 1;
- }
+ int y, x;
for (y = 0; y < height; y++) {
- const int x0 = (y < h) ? w : 0;
- for (x = x0; x < width; x++) {
+ for (x = 0; x < width; x++) {
const float temp = FFABS(block[x]);
if (temp <= threshold)
block[x] *= frac;
static void qian_thresholding(float *block, const int width, const int height,
const int stride, const float threshold,
- const float percent, const int unused)
+ const float percent)
{
const float percent01 = percent * 0.01f;
const float tr2 = threshold * threshold * percent01;
}
}
+static float bayes_threshold(float *block, const int width, const int height,
+ const int stride, const float threshold)
+{
+ float mean = 0.f;
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ mean += block[x] * block[x];
+ }
+ block += stride;
+ }
+
+ mean /= width * height;
+
+ return threshold * threshold / (FFMAX(sqrtf(mean - threshold), FLT_EPSILON));
+}
+
static void filter(VagueDenoiserContext *s, AVFrame *in, AVFrame *out)
{
int p, y, x, i, j;
v_low_size0 = (v_low_size0 + 1) >> 1;
}
- s->thresholding(s->block, width, height, width, s->threshold, s->percent, s->nsteps);
+ if (s->type == 0) {
+ s->thresholding(s->block, width, height, width, s->threshold, s->percent);
+ } else {
+ for (int n = 0; n < s->nsteps; n++) {
+ float threshold;
+ float *block;
+
+ if (n == s->nsteps - 1) {
+ threshold = bayes_threshold(s->block, s->hlowsize[p][n], s->vlowsize[p][n], width, s->threshold);
+ s->thresholding(s->block, s->hlowsize[p][n], s->vlowsize[p][n], width, threshold, s->percent);
+ }
+ block = s->block + s->hlowsize[p][n];
+ threshold = bayes_threshold(block, s->hhighsize[p][n], s->vlowsize[p][n], width, s->threshold);
+ s->thresholding(block, s->hhighsize[p][n], s->vlowsize[p][n], width, threshold, s->percent);
+ block = s->block + s->vlowsize[p][n] * width;
+ threshold = bayes_threshold(block, s->hlowsize[p][n], s->vhighsize[p][n], width, s->threshold);
+ s->thresholding(block, s->hlowsize[p][n], s->vhighsize[p][n], width, threshold, s->percent);
+ block = s->block + s->hlowsize[p][n] + s->vlowsize[p][n] * width;
+ threshold = bayes_threshold(block, s->hhighsize[p][n], s->vhighsize[p][n], width, s->threshold);
+ s->thresholding(block, s->hhighsize[p][n], s->vhighsize[p][n], width, threshold, s->percent);
+ }
+ }
while (nsteps_invert--) {
const int idx = s->vlowsize[p][nsteps_invert] + s->vhighsize[p][nsteps_invert];
{ NULL }
};
-AVFilter ff_vf_vaguedenoiser = {
+const AVFilter ff_vf_vaguedenoiser = {
.name = "vaguedenoiser",
.description = NULL_IF_CONFIG_SMALL("Apply a Wavelet based Denoiser."),
.priv_size = sizeof(VagueDenoiserContext),