Commit 0e67b25c authored by Debargha Mukherjee's avatar Debargha Mukherjee

Replace bilateral filter with domain transform RF

The main objective is to reduce computational complexity.
The domain transform filter has an effect of edge preserving smoothing
at a lower computational cost than the bilateral filter, and can be
readily paralelized.

A little drop in coding efficiency about 0.06% for lowres, 0.16% for
midres.

Change-Id: Id949406b7e5afe9b64588d130065c63a76e4f3f9
parent 705544c2
......@@ -90,8 +90,6 @@ void av1_free_ref_frame_buffers(BufferPool *pool) {
void av1_free_restoration_buffers(AV1_COMMON *cm) {
aom_free(cm->rst_info.restoration_type);
cm->rst_info.restoration_type = NULL;
aom_free(cm->rst_info.bilateral_info);
cm->rst_info.bilateral_info = NULL;
aom_free(cm->rst_info.wiener_info);
cm->rst_info.wiener_info = NULL;
aom_free(cm->rst_info.sgrproj_info);
......
......@@ -1204,20 +1204,13 @@ static const aom_prob default_tx_size_prob[MAX_TX_DEPTH][TX_SIZE_CONTEXTS]
#if CONFIG_LOOP_RESTORATION
const aom_tree_index av1_switchable_restore_tree[TREE_SIZE(
RESTORE_SWITCHABLE_TYPES)] = {
// -RESTORE_NONE, 2, -RESTORE_SGRPROJ, 4, -RESTORE_BILATERAL, -RESTORE_WIENER,
-RESTORE_NONE,
2,
4,
6,
-RESTORE_SGRPROJ,
-RESTORE_DOMAINTXFMRF,
-RESTORE_BILATERAL,
-RESTORE_WIENER,
-RESTORE_NONE, 2, -RESTORE_WIENER, 4, -RESTORE_SGRPROJ, -RESTORE_DOMAINTXFMRF,
};
static const aom_prob default_switchable_restore_prob[RESTORE_SWITCHABLE_TYPES -
1] = { 32, 128, 128,
128 };
static const aom_prob
default_switchable_restore_prob[RESTORE_SWITCHABLE_TYPES - 1] = {
32, 128, 128,
};
#endif // CONFIG_LOOP_RESTORATION
#if CONFIG_PALETTE
......@@ -2113,14 +2106,6 @@ void av1_setup_past_independence(AV1_COMMON *cm) {
// To force update of the sharpness
lf->last_sharpness_level = -1;
#if CONFIG_LOOP_RESTORATION
if (cm->rst_info.bilateral_info) {
int s;
for (i = 0; i < cm->rst_internal.ntiles; ++i)
for (s = 0; s < BILATERAL_SUBTILES; ++s)
cm->rst_info.bilateral_info[i].level[s] = -1;
}
#endif // CONFIG_LOOP_RESTORATION
av1_default_coef_probs(cm);
init_mode_probs(cm->fc);
......
......@@ -489,11 +489,10 @@ typedef uint8_t TXFM_CONTEXT;
#if CONFIG_LOOP_RESTORATION
typedef enum {
RESTORE_NONE = 0,
RESTORE_SGRPROJ = 1,
RESTORE_BILATERAL = 2,
RESTORE_WIENER = 3,
RESTORE_DOMAINTXFMRF = 4,
RESTORE_SWITCHABLE = 5,
RESTORE_WIENER = 1,
RESTORE_SGRPROJ = 2,
RESTORE_DOMAINTXFMRF = 3,
RESTORE_SWITCHABLE = 4,
RESTORE_SWITCHABLE_TYPES = RESTORE_SWITCHABLE,
RESTORE_TYPES,
} RestorationType;
......
This diff is collapsed.
......@@ -60,14 +60,6 @@ extern "C" {
#define SGRPROJ_BITS (SGRPROJ_PRJ_BITS * 2 + SGRPROJ_PARAMS_BITS)
#define BILATERAL_LEVEL_BITS_KF 4
#define BILATERAL_LEVELS_KF (1 << BILATERAL_LEVEL_BITS_KF)
#define BILATERAL_LEVEL_BITS 3
#define BILATERAL_LEVELS (1 << BILATERAL_LEVEL_BITS)
#define BILATERAL_SUBTILE_BITS 1
#define BILATERAL_SUBTILES (1 << (2 * BILATERAL_SUBTILE_BITS))
#define RESTORATION_HALFWIN 3
#define RESTORATION_HALFWIN1 (RESTORATION_HALFWIN + 1)
#define RESTORATION_WIN (2 * RESTORATION_HALFWIN + 1)
......@@ -94,8 +86,6 @@ extern "C" {
#define WIENER_FILT_TAP2_MAXV \
(WIENER_FILT_TAP2_MINV - 1 + (1 << WIENER_FILT_TAP2_BITS))
typedef struct { int level[BILATERAL_SUBTILES]; } BilateralInfo;
typedef struct {
int level;
int vfilter[RESTORATION_WIN], hfilter[RESTORATION_WIN];
......@@ -122,8 +112,6 @@ typedef struct {
typedef struct {
RestorationType frame_restoration_type;
RestorationType *restoration_type;
// Bilateral filter
BilateralInfo *bilateral_info;
// Wiener filter
WienerInfo *wiener_info;
// Selfguided proj filter
......@@ -210,7 +198,6 @@ void av1_domaintxfmrf_restoration_highbd(uint16_t *dgd, int width, int height,
int stride, int param, int bit_depth);
#endif // CONFIG_AOM_HIGHBITDEPTH
void decode_xq(int *xqd, int *xq);
int av1_bilateral_level_bits(const struct AV1Common *const cm);
void av1_loop_restoration_init(RestorationInternal *rst, RestorationInfo *rsi,
int kf, int width, int height);
void av1_loop_restoration_frame(YV12_BUFFER_CONFIG *frame, struct AV1Common *cm,
......
......@@ -2267,12 +2267,10 @@ static void decode_restoration_mode(AV1_COMMON *cm,
RestorationInfo *rsi = &cm->rst_info;
if (aom_rb_read_bit(rb)) {
if (aom_rb_read_bit(rb))
rsi->frame_restoration_type =
(aom_rb_read_bit(rb) ? RESTORE_WIENER : RESTORE_BILATERAL);
else
rsi->frame_restoration_type =
(aom_rb_read_bit(rb) ? RESTORE_DOMAINTXFMRF : RESTORE_SGRPROJ);
// rsi->frame_restoration_type = RESTORE_SGRPROJ;
else
rsi->frame_restoration_type = RESTORE_WIENER;
} else {
rsi->frame_restoration_type =
aom_rb_read_bit(rb) ? RESTORE_SWITCHABLE : RESTORE_NONE;
......@@ -2314,20 +2312,6 @@ static void read_domaintxfmrf_filter(DomaintxfmrfInfo *domaintxfmrf_info,
aom_read_literal(rb, DOMAINTXFMRF_PARAMS_BITS, ACCT_STR);
}
static void read_bilateral_filter(const AV1_COMMON *cm,
BilateralInfo *bilateral_info,
aom_reader *rb) {
int s;
for (s = 0; s < BILATERAL_SUBTILES; ++s) {
if (aom_read(rb, RESTORE_NONE_BILATERAL_PROB, ACCT_STR)) {
bilateral_info->level[s] =
aom_read_literal(rb, av1_bilateral_level_bits(cm), ACCT_STR);
} else {
bilateral_info->level[s] = -1;
}
}
}
static void decode_restoration(AV1_COMMON *cm, aom_reader *rb) {
int i;
RestorationInfo *rsi = &cm->rst_info;
......@@ -2337,9 +2321,6 @@ static void decode_restoration(AV1_COMMON *cm, aom_reader *rb) {
rsi->restoration_type = (RestorationType *)aom_realloc(
rsi->restoration_type, sizeof(*rsi->restoration_type) * ntiles);
if (rsi->frame_restoration_type == RESTORE_SWITCHABLE) {
rsi->bilateral_info = (BilateralInfo *)aom_realloc(
rsi->bilateral_info, sizeof(*rsi->bilateral_info) * ntiles);
assert(rsi->bilateral_info != NULL);
rsi->wiener_info = (WienerInfo *)aom_realloc(
rsi->wiener_info, sizeof(*rsi->wiener_info) * ntiles);
assert(rsi->wiener_info != NULL);
......@@ -2356,13 +2337,6 @@ static void decode_restoration(AV1_COMMON *cm, aom_reader *rb) {
if (rsi->restoration_type[i] == RESTORE_WIENER) {
rsi->wiener_info[i].level = 1;
read_wiener_filter(&rsi->wiener_info[i], rb);
} else if (rsi->restoration_type[i] == RESTORE_BILATERAL) {
#if BILATERAL_SUBTILES == 0
rsi->bilateral_info[i].level[0] =
aom_read_literal(rb, av1_bilateral_level_bits(cm), ACCT_STR);
#else
read_bilateral_filter(cm, &rsi->bilateral_info[i], rb);
#endif
} else if (rsi->restoration_type[i] == RESTORE_SGRPROJ) {
rsi->sgrproj_info[i].level = 1;
read_sgrproj_filter(&rsi->sgrproj_info[i], rb);
......@@ -2385,14 +2359,6 @@ static void decode_restoration(AV1_COMMON *cm, aom_reader *rb) {
rsi->restoration_type[i] = RESTORE_NONE;
}
}
} else if (rsi->frame_restoration_type == RESTORE_BILATERAL) {
rsi->bilateral_info = (BilateralInfo *)aom_realloc(
rsi->bilateral_info, sizeof(*rsi->bilateral_info) * ntiles);
assert(rsi->bilateral_info != NULL);
for (i = 0; i < ntiles; ++i) {
rsi->restoration_type[i] = RESTORE_BILATERAL;
read_bilateral_filter(cm, &rsi->bilateral_info[i], rb);
}
} else if (rsi->frame_restoration_type == RESTORE_SGRPROJ) {
rsi->sgrproj_info = (SgrprojInfo *)aom_realloc(
rsi->sgrproj_info, sizeof(*rsi->sgrproj_info) * ntiles);
......
......@@ -2991,34 +2991,22 @@ static void encode_restoration_mode(AV1_COMMON *cm,
aom_wb_write_bit(wb, 0);
aom_wb_write_bit(wb, 0);
break;
case RESTORE_SWITCHABLE:
aom_wb_write_bit(wb, 0);
case RESTORE_WIENER:
aom_wb_write_bit(wb, 1);
aom_wb_write_bit(wb, 0);
break;
/*
case RESTORE_SGRPROJ:
aom_wb_write_bit(wb, 1);
aom_wb_write_bit(wb, 0);
break;
*/
case RESTORE_SGRPROJ:
aom_wb_write_bit(wb, 1);
aom_wb_write_bit(wb, 0);
aom_wb_write_bit(wb, 1);
aom_wb_write_bit(wb, 0);
break;
case RESTORE_DOMAINTXFMRF:
aom_wb_write_bit(wb, 1);
aom_wb_write_bit(wb, 0);
aom_wb_write_bit(wb, 1);
break;
case RESTORE_BILATERAL:
aom_wb_write_bit(wb, 1);
aom_wb_write_bit(wb, 1);
aom_wb_write_bit(wb, 0);
break;
case RESTORE_WIENER:
aom_wb_write_bit(wb, 1);
aom_wb_write_bit(wb, 1);
case RESTORE_SWITCHABLE:
aom_wb_write_bit(wb, 0);
aom_wb_write_bit(wb, 1);
break;
default: assert(0);
......@@ -3053,19 +3041,6 @@ static void write_domaintxfmrf_filter(DomaintxfmrfInfo *domaintxfmrf_info,
aom_write_literal(wb, domaintxfmrf_info->sigma_r, DOMAINTXFMRF_PARAMS_BITS);
}
static void write_bilateral_filter(const AV1_COMMON *cm,
BilateralInfo *bilateral_info,
aom_writer *wb) {
int s;
for (s = 0; s < BILATERAL_SUBTILES; ++s) {
aom_write(wb, bilateral_info->level[s] >= 0, RESTORE_NONE_BILATERAL_PROB);
if (bilateral_info->level[s] >= 0) {
aom_write_literal(wb, bilateral_info->level[s],
av1_bilateral_level_bits(cm));
}
}
}
static void encode_restoration(AV1_COMMON *cm, aom_writer *wb) {
int i;
RestorationInfo *rsi = &cm->rst_info;
......@@ -3076,14 +3051,7 @@ static void encode_restoration(AV1_COMMON *cm, aom_writer *wb) {
av1_write_token(
wb, av1_switchable_restore_tree, cm->fc->switchable_restore_prob,
&switchable_restore_encodings[rsi->restoration_type[i]]);
if (rsi->restoration_type[i] == RESTORE_BILATERAL) {
#if BILATERAL_SUBTILES == 0
aom_write_literal(wb, rsi->bilateral_info[i].level[0],
av1_bilateral_level_bits(cm));
#else
write_bilateral_filter(cm, &rsi->bilateral_info[i], wb);
#endif
} else if (rsi->restoration_type[i] == RESTORE_WIENER) {
if (rsi->restoration_type[i] == RESTORE_WIENER) {
write_wiener_filter(&rsi->wiener_info[i], wb);
} else if (rsi->restoration_type[i] == RESTORE_SGRPROJ) {
write_sgrproj_filter(&rsi->sgrproj_info[i], wb);
......@@ -3091,10 +3059,6 @@ static void encode_restoration(AV1_COMMON *cm, aom_writer *wb) {
write_domaintxfmrf_filter(&rsi->domaintxfmrf_info[i], wb);
}
}
} else if (rsi->frame_restoration_type == RESTORE_BILATERAL) {
for (i = 0; i < cm->rst_internal.ntiles; ++i) {
write_bilateral_filter(cm, &rsi->bilateral_info[i], wb);
}
} else if (rsi->frame_restoration_type == RESTORE_WIENER) {
for (i = 0; i < cm->rst_internal.ntiles; ++i) {
aom_write(wb, rsi->wiener_info[i].level != 0, RESTORE_NONE_WIENER_PROB);
......
......@@ -34,8 +34,7 @@ typedef double (*search_restore_type)(const YV12_BUFFER_CONFIG *src,
int partial_frame, RestorationInfo *info,
double *best_tile_cost);
// const int frame_level_restore_bits[RESTORE_TYPES] = { 2, 2, 3, 3, 2 };
const int frame_level_restore_bits[RESTORE_TYPES] = { 2, 3, 3, 3, 3, 2 };
const int frame_level_restore_bits[RESTORE_TYPES] = { 2, 2, 3, 3, 2 };
static int64_t sse_restoration_tile(const YV12_BUFFER_CONFIG *src,
AV1_COMMON *const cm, int h_start,
......@@ -476,7 +475,8 @@ static double search_domaintxfmrf(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
RestorationInfo *info,
double *best_tile_cost) {
DomaintxfmrfInfo *domaintxfmrf_info = info->domaintxfmrf_info;
double err, cost_norestore, cost_domaintxfmrf;
double cost_norestore, cost_domaintxfmrf;
int64_t err;
int bits;
MACROBLOCK *x = &cpi->td.mb;
AV1_COMMON *const cm = &cpi->common;
......@@ -561,116 +561,6 @@ static double search_domaintxfmrf(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
return cost_domaintxfmrf;
}
static double search_bilateral(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
int filter_level, int partial_frame,
RestorationInfo *info, double *best_tile_cost) {
BilateralInfo *bilateral_info = info->bilateral_info;
AV1_COMMON *const cm = &cpi->common;
int i, tile_idx, subtile_idx;
int64_t err;
int bits;
double cost, best_cost, cost_bilateral, cost_norestore_subtile;
const int bilateral_level_bits = av1_bilateral_level_bits(&cpi->common);
const int bilateral_levels = 1 << bilateral_level_bits;
MACROBLOCK *x = &cpi->td.mb;
RestorationInfo rsi;
int tile_width, tile_height, nhtiles, nvtiles;
int h_start, h_end, v_start, v_end;
const int ntiles = av1_get_rest_ntiles(cm->width, cm->height, &tile_width,
&tile_height, &nhtiles, &nvtiles);
// Make a copy of the unfiltered / processed recon buffer
aom_yv12_copy_y(cm->frame_to_show, &cpi->last_frame_uf);
av1_loop_filter_frame(cm->frame_to_show, cm, &cpi->td.mb.e_mbd, filter_level,
1, partial_frame);
aom_yv12_copy_y(cm->frame_to_show, &cpi->last_frame_db);
rsi.frame_restoration_type = RESTORE_BILATERAL;
rsi.bilateral_info =
(BilateralInfo *)aom_malloc(sizeof(*rsi.bilateral_info) * ntiles);
assert(rsi.bilateral_info != NULL);
for (tile_idx = 0; tile_idx < ntiles; ++tile_idx)
for (subtile_idx = 0; subtile_idx < BILATERAL_SUBTILES; ++subtile_idx)
bilateral_info[tile_idx].level[subtile_idx] =
rsi.bilateral_info[tile_idx].level[subtile_idx] = -1;
// Find best filter for each tile
for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
for (subtile_idx = 0; subtile_idx < BILATERAL_SUBTILES; ++subtile_idx) {
av1_get_rest_tile_limits(tile_idx, subtile_idx, BILATERAL_SUBTILE_BITS,
nhtiles, nvtiles, tile_width, tile_height,
cm->width, cm->height, 0, 0, &h_start, &h_end,
&v_start, &v_end);
err = sse_restoration_tile(src, cm, h_start, h_end - h_start, v_start,
v_end - v_start);
#if BILATERAL_SUBTILES
// #bits when a subtile is not restored
bits = av1_cost_bit(RESTORE_NONE_BILATERAL_PROB, 0);
#else
bits = 0;
#endif
cost_norestore_subtile =
RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
best_cost = cost_norestore_subtile;
for (i = 0; i < bilateral_levels; ++i) {
rsi.bilateral_info[tile_idx].level[subtile_idx] = i;
err = try_restoration_tile(src, cpi, &rsi, partial_frame, tile_idx,
subtile_idx, BILATERAL_SUBTILE_BITS);
bits = bilateral_level_bits << AV1_PROB_COST_SHIFT;
bits += av1_cost_bit(RESTORE_NONE_BILATERAL_PROB, 1);
cost = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
if (cost < best_cost) {
bilateral_info[tile_idx].level[subtile_idx] = i;
best_cost = cost;
}
rsi.bilateral_info[tile_idx].level[subtile_idx] = -1;
}
}
bits = 0;
for (subtile_idx = 0; subtile_idx < BILATERAL_SUBTILES; ++subtile_idx) {
rsi.bilateral_info[tile_idx].level[subtile_idx] =
bilateral_info[tile_idx].level[subtile_idx];
if (rsi.bilateral_info[tile_idx].level[subtile_idx] >= 0)
bits += bilateral_level_bits << AV1_PROB_COST_SHIFT;
#if BILATERAL_SUBTILES
bits +=
av1_cost_bit(RESTORE_NONE_BILATERAL_PROB,
rsi.bilateral_info[tile_idx].level[subtile_idx] >= 0);
#endif
}
err = try_restoration_tile(src, cpi, &rsi, partial_frame, tile_idx, 0, 0);
best_tile_cost[tile_idx] = RDCOST_DBL(
x->rdmult, x->rddiv,
(bits + cpi->switchable_restore_cost[RESTORE_BILATERAL]) >> 4, err);
}
// Find cost for combined configuration
bits = frame_level_restore_bits[rsi.frame_restoration_type]
<< AV1_PROB_COST_SHIFT;
for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
for (subtile_idx = 0; subtile_idx < BILATERAL_SUBTILES; ++subtile_idx) {
rsi.bilateral_info[tile_idx].level[subtile_idx] =
bilateral_info[tile_idx].level[subtile_idx];
if (rsi.bilateral_info[tile_idx].level[subtile_idx] >= 0) {
bits += bilateral_level_bits << AV1_PROB_COST_SHIFT;
}
#if BILATERAL_SUBTILES
bits +=
av1_cost_bit(RESTORE_NONE_BILATERAL_PROB,
rsi.bilateral_info[tile_idx].level[subtile_idx] >= 0);
#endif
}
}
err = try_restoration_frame(src, cpi, &rsi, partial_frame);
cost_bilateral = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
aom_free(rsi.bilateral_info);
aom_yv12_copy_y(&cpi->last_frame_uf, cm->frame_to_show);
return cost_bilateral;
}
static double find_average(uint8_t *src, int h_start, int h_end, int v_start,
int v_end, int stride) {
uint64_t sum = 0;
......@@ -1173,8 +1063,7 @@ static double search_switchable_restoration(
void av1_pick_filter_restoration(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
LPF_PICK_METHOD method) {
static search_restore_type search_restore_fun[RESTORE_SWITCHABLE_TYPES] = {
search_norestore, search_sgrproj, search_bilateral,
search_wiener, search_domaintxfmrf,
search_norestore, search_wiener, search_sgrproj, search_domaintxfmrf,
};
AV1_COMMON *const cm = &cpi->common;
struct loopfilter *const lf = &cm->lf;
......@@ -1188,10 +1077,6 @@ void av1_pick_filter_restoration(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
cm->rst_info.restoration_type = (RestorationType *)aom_realloc(
cm->rst_info.restoration_type,
sizeof(*cm->rst_info.restoration_type) * ntiles);
cm->rst_info.bilateral_info = (BilateralInfo *)aom_realloc(
cm->rst_info.bilateral_info,
sizeof(*cm->rst_info.bilateral_info) * ntiles);
assert(cm->rst_info.bilateral_info != NULL);
cm->rst_info.wiener_info = (WienerInfo *)aom_realloc(
cm->rst_info.wiener_info, sizeof(*cm->rst_info.wiener_info) * ntiles);
assert(cm->rst_info.wiener_info != NULL);
......@@ -1264,10 +1149,10 @@ void av1_pick_filter_restoration(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
}
cm->rst_info.frame_restoration_type = best_restore;
/*
printf("Frame %d/%d frame_restore_type %d : %f %f %f %f %f %f\n",
printf("Frame %d/%d frame_restore_type %d : %f %f %f %f %f\n",
cm->current_video_frame, cm->show_frame,
cm->rst_info.frame_restoration_type, cost_restore[0], cost_restore[1],
cost_restore[2], cost_restore[3], cost_restore[4], cost_restore[5]);
cost_restore[2], cost_restore[3], cost_restore[4]);
*/
for (r = 0; r < RESTORE_SWITCHABLE_TYPES; r++) aom_free(tile_cost[r]);
}
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