Commit 99d9a8fe authored by Aamir Anis's avatar Aamir Anis
Browse files

Updated loop restoration

1. Wiener restoration filter now has normalization and evaluation of
quantization procedure.
2. Corrected scaling of bits in RD cost computation.
3. Changed dynamic range and number of bits for Wiener filter.
Observed gains: Overall 0.58% for low_res, 0.7% for mid_res sequences.

Change-Id: I8928b3ea493bfe1790926b00388d6c4bafc08e19
parent 17c4f1c7
......@@ -34,13 +34,13 @@ extern "C" {
#define RESTORATION_FILT_BITS 7
#define RESTORATION_FILT_STEP (1 << RESTORATION_FILT_BITS)
#define WIENER_FILT_TAP0_MINV 3
#define WIENER_FILT_TAP0_MINV -5
#define WIENER_FILT_TAP1_MINV (-23)
#define WIENER_FILT_TAP2_MINV 5
#define WIENER_FILT_TAP2_MINV -20
#define WIENER_FILT_TAP0_BITS 2
#define WIENER_FILT_TAP1_BITS 4
#define WIENER_FILT_TAP2_BITS 5
#define WIENER_FILT_TAP0_BITS 4
#define WIENER_FILT_TAP1_BITS 5
#define WIENER_FILT_TAP2_BITS 6
#define WIENER_FILT_BITS \
((WIENER_FILT_TAP0_BITS + WIENER_FILT_TAP1_BITS + WIENER_FILT_TAP2_BITS) * 2)
......
......@@ -76,7 +76,8 @@ static int search_bilateral_level(const YV12_BUFFER_CONFIG *sd,
rsi.restoration_type = RESTORE_NONE;
err = try_restoration_frame(sd, cpi, &rsi, partial_frame);
bits = 0;
best_cost = RDCOST_DBL(x->rdmult, x->rddiv, (bits << 2), err);
best_cost = RDCOST_DBL(x->rdmult, x->rddiv,
(bits << (VP9_PROB_COST_SHIFT - 6)), err);
for (i = 0; i < restoration_levels; ++i) {
rsi.restoration_type = RESTORE_BILATERAL;
rsi.restoration_level = i;
......@@ -85,7 +86,8 @@ static int search_bilateral_level(const YV12_BUFFER_CONFIG *sd,
// when RDCOST is used. However below we just scale both in the correct
// ratios appropriately but not exactly by these values.
bits = restoration_level_bits;
cost = RDCOST_DBL(x->rdmult, x->rddiv, (bits << 2), err);
cost = RDCOST_DBL(x->rdmult, x->rddiv,
(bits << (VP9_PROB_COST_SHIFT - 6)), err);
if (cost < best_cost) {
restoration_best = i;
best_cost = cost;
......@@ -321,20 +323,12 @@ static INLINE int wrap_index(int i) {
return (i >= RESTORATION_HALFWIN1 ? RESTORATION_WIN - 1 - i : i);
}
static void normalize_copy(double *v, int n) {
double s = 0.0;
int i;
for (i = 0; i < n; ++i)
s += v[i];
s = 1.0 / s;
for (i = 0; i < n; ++i) v[i] *= s;
}
// Fix vector b, update vector a
static void update_a_sep_sym(double **Mc, double **Hc, double *a, double *b) {
int i, j;
double S[RESTORATION_WIN];
double A[RESTORATION_WIN], B[RESTORATION_WIN2];
int w, w2;
memset(A, 0, sizeof(A));
memset(B, 0, sizeof(B));
for (i = 0; i < RESTORATION_WIN; i ++) {
......@@ -344,7 +338,6 @@ static void update_a_sep_sym(double **Mc, double **Hc, double *a, double *b) {
A[jj] += Mc[i][j] * b[i];
}
}
for (i = 0; i < RESTORATION_WIN; i ++) {
for (j = 0; j < RESTORATION_WIN; j ++) {
int k, l;
......@@ -358,12 +351,23 @@ static void update_a_sep_sym(double **Mc, double **Hc, double *a, double *b) {
}
}
}
if (linsolve(RESTORATION_HALFWIN1, B, RESTORATION_HALFWIN1, A, S)) {
for (i = 0; i < RESTORATION_WIN; ++i) {
const int ii = wrap_index(i);
a[i] = S[ii];
// Normalization enforcement in the system of equations itself
w = RESTORATION_WIN;
w2 = (w >> 1) + 1;
for (i = 0; i < w2 - 1; ++i)
A[i] -= A[w2 - 1] * 2 + B[i * w2 + w2 - 1]
- 2 * B[(w2 - 1) * w2 + (w2 - 1)];
for (i = 0; i < w2 - 1; ++i)
for (j = 0; j < w2 - 1; ++j)
B[i * w2 + j] -= 2 * (B[i * w2 + (w2 - 1)] + B[(w2 - 1) * w2 + j] -
2 * B[(w2 - 1) * w2 + (w2 - 1)]);
if (linsolve(w2 - 1, B, w2, A, S)) {
S[w2 - 1] = 1.0;
for (i = w2; i < w; ++i) {
S[i] = S[w - 1 - i];
S[w2 - 1] -= 2 * S[i];
}
normalize_copy(a, RESTORATION_WIN);
memcpy(a, S, w * sizeof(*a));
}
}
......@@ -372,6 +376,7 @@ static void update_b_sep_sym(double **Mc, double **Hc, double *a, double *b) {
int i, j;
double S[RESTORATION_WIN];
double A[RESTORATION_WIN], B[RESTORATION_WIN2];
int w, w2;
memset(A, 0, sizeof(A));
memset(B, 0, sizeof(B));
for (i = 0; i < RESTORATION_WIN; i ++) {
......@@ -393,12 +398,23 @@ static void update_b_sep_sym(double **Mc, double **Hc, double *a, double *b) {
a[k] * a[l];
}
}
if (linsolve(RESTORATION_HALFWIN1, B, RESTORATION_HALFWIN1, A, S)) {
for (i = 0; i < RESTORATION_WIN; ++i) {
const int ii = wrap_index(i);
b[i] = S[ii];
// Normalization enforcement in the system of equations itself
w = RESTORATION_WIN;
w2 = RESTORATION_HALFWIN1;
for (i = 0; i < w2 - 1; ++i)
A[i] -= A[w2 - 1] * 2 + B[i * w2 + w2 - 1]
- 2 * B[(w2 - 1) * w2 + (w2 - 1)];
for (i = 0; i < w2 - 1; ++i)
for (j = 0; j < w2 - 1; ++j)
B[i * w2 + j] -= 2 * (B[i * w2 + (w2 - 1)] + B[(w2 - 1) * w2 + j] -
2 * B[(w2 - 1) * w2 + (w2 - 1)]);
if (linsolve(w2 - 1, B, w2, A, S)) {
S[w2 - 1] = 1.0;
for (i = w2; i < w; ++i) {
S[i] = S[w - 1 - i];
S[w2 - 1] -= 2 * S[i];
}
normalize_copy(b, RESTORATION_WIN);
memcpy(b, S, w * sizeof(*b));
}
}
......@@ -429,6 +445,46 @@ static int wiener_decompose_sep_sym(double *M, double *H,
return 1;
}
// Computes the function x'*A*x - x'*b for the learned filters, and compares
// against identity filters; Final score is defined as the difference between
// the function values
static double compute_score(double *M, double *H, int *vfilt, int *hfilt) {
double ab[RESTORATION_WIN * RESTORATION_WIN];
int i, k, l;
double P = 0, Q = 0;
double iP = 0, iQ = 0;
double Score, iScore;
int w;
double a[RESTORATION_WIN], b[RESTORATION_WIN];
w = RESTORATION_WIN;
a[RESTORATION_HALFWIN] = b[RESTORATION_HALFWIN] = 1.0;
for (i = 0; i < RESTORATION_HALFWIN; ++i) {
a[i] = a[RESTORATION_WIN - i - 1 ] =
(double) vfilt[i] / RESTORATION_FILT_STEP;
b[i] = b[RESTORATION_WIN - i - 1 ] =
(double) hfilt[i] / RESTORATION_FILT_STEP;
a[RESTORATION_HALFWIN] -= 2 * a[i];
b[RESTORATION_HALFWIN] -= 2 * b[i];
}
for (k = 0; k < w; ++k) {
for (l = 0; l < w; ++l) {
ab[k * w + l] = a[l] * b[k];
}
}
for (k = 0; k < w * w; ++k) {
P += ab[k] * M[k];
for (l = 0; l < w * w; ++l)
Q += ab[k] * H[k * w * w + l] * ab[l];
}
Score = Q - 2 * P;
iP = M[(w * w) >> 1];
iQ = H[((w * w) >> 1) * w * w + ((w * w) >> 1)];
iScore = iQ - 2 * iP;
return Score - iScore;
}
#define CLIP(x, lo, hi) ((x) < (lo) ? (lo) : (x) > (hi) ? (hi) : (x))
#define RINT(x) ((x) < 0 ? (int)((x) - 0.5) : (int)((x) + 0.5))
......@@ -463,6 +519,7 @@ static int search_wiener_filter(const YV12_BUFFER_CONFIG *src,
const int height = cm->height;
const int src_stride = src->y_stride;
const int dgd_stride = dgd->y_stride;
double score;
assert(width == dgd->y_crop_width);
assert(height == dgd->y_crop_height);
......@@ -478,7 +535,8 @@ static int search_wiener_filter(const YV12_BUFFER_CONFIG *src,
rsi.restoration_type = RESTORE_NONE;
err = try_restoration_frame(src, cpi, &rsi, partial_frame);
bits = 0;
cost_norestore = RDCOST_DBL(x->rdmult, x->rddiv, (bits << 2), err);
cost_norestore = RDCOST_DBL(x->rdmult, x->rddiv,
(bits << (VP9_PROB_COST_SHIFT - 6)), err);
#if CONFIG_VP9_HIGHBITDEPTH
if (cm->use_highbitdepth)
......@@ -496,12 +554,27 @@ static int search_wiener_filter(const YV12_BUFFER_CONFIG *src,
quantize_sym_filter(vfilterd, vfilter);
quantize_sym_filter(hfilterd, hfilter);
// Filter score computes the value of the function x'*A*x - x'*b for the
// learned filter and compares it against identity filer. If there is no
// reduction in the function, the filter is reverted back to identity
score = compute_score(M, H, vfilter, hfilter);
if (score > 0.0) {
int i;
for (i = 0; i < RESTORATION_HALFWIN; ++i)
vfilter[i] = hfilter[i] = 0;
rsi.restoration_type = RESTORE_NONE;
if (best_cost_ret) *best_cost_ret = cost_norestore;
vpx_yv12_copy_y(&cpi->last_frame_uf, cm->frame_to_show);
return 0;
}
rsi.restoration_type = RESTORE_WIENER;
memcpy(rsi.vfilter, vfilter, sizeof(rsi.vfilter));
memcpy(rsi.hfilter, hfilter, sizeof(rsi.hfilter));
err = try_restoration_frame(src, cpi, &rsi, partial_frame);
bits = WIENER_FILT_BITS;
cost_wiener = RDCOST_DBL(x->rdmult, x->rddiv, (bits << 2), err);
cost_wiener = RDCOST_DBL(x->rdmult, x->rddiv,
(bits << (VP9_PROB_COST_SHIFT - 6)), err);
vpx_yv12_copy_y(&cpi->last_frame_uf, cm->frame_to_show);
......@@ -597,7 +670,7 @@ void vp10_pick_filter_restoration(
cm->rst_info.restoration_type = RESTORE_NONE;
}
// printf("[%d] Costs %g %g (%d) %g (%d)\n", cm->rst_info.restoration_type,
// cost_norestore, cost_bilateral, lf->filter_level, cost_wiener,
// wiener_success);
// cost_norestore, cost_bilateral, lf->filter_level, cost_wiener,
// wiener_success);
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment