From d1e3d0467c7efbc6eeddefc9d568cf928110e8fb Mon Sep 17 00:00:00 2001 From: JackyChen Date: Tue, 26 Jan 2016 18:01:10 +0800 Subject: [PATCH] VPX skin map improvement. Use multiple clusters instead of one and decrease the distance thresholds. Add a define to switch between models. Default is set to existing (1 cluster) model. Change-Id: I802cd9bb565437ae8983ef39453939f5d5073bb1 --- vp8/encoder/pickinter.c | 57 ++++++++++++++++++++++---------- vp9/encoder/vp9_skin_detection.c | 35 +++++++++++++++----- 2 files changed, 66 insertions(+), 26 deletions(-) diff --git a/vp8/encoder/pickinter.c b/vp8/encoder/pickinter.c index d0fff3f04..0ea063291 100644 --- a/vp8/encoder/pickinter.c +++ b/vp8/encoder/pickinter.c @@ -36,6 +36,8 @@ extern unsigned int cnt_pm; #endif +#define MODEL_MODE 0 + extern const int vp8_ref_frame_order[MAX_MODES]; extern const MB_PREDICTION_MODE vp8_mode_order[MAX_MODES]; @@ -45,18 +47,21 @@ extern const MB_PREDICTION_MODE vp8_mode_order[MAX_MODES]; // skin color classifier is defined. // Fixed-point skin color model parameters. -static const int skin_mean[2] = {7463, 9614}; // q6 +static const int skin_mean[5][2] = + {{7463, 9614}, {6400, 10240}, {7040, 10240}, {8320, 9280}, {6800, 9614}}; static const int skin_inv_cov[4] = {4107, 1663, 1663, 2157}; // q16 -static const int skin_threshold = 1570636; // q18 +static const int skin_threshold[2] = {1570636, 800000}; // q18 // Evaluates the Mahalanobis distance measure for the input CbCr values. -static int evaluate_skin_color_difference(int cb, int cr) -{ +static int evaluate_skin_color_difference(int cb, int cr, int idx) { const int cb_q6 = cb << 6; const int cr_q6 = cr << 6; - const int cb_diff_q12 = (cb_q6 - skin_mean[0]) * (cb_q6 - skin_mean[0]); - const int cbcr_diff_q12 = (cb_q6 - skin_mean[0]) * (cr_q6 - skin_mean[1]); - const int cr_diff_q12 = (cr_q6 - skin_mean[1]) * (cr_q6 - skin_mean[1]); + const int cb_diff_q12 = + (cb_q6 - skin_mean[idx][0]) * (cb_q6 - skin_mean[idx][0]); + const int cbcr_diff_q12 = + (cb_q6 - skin_mean[idx][0]) * (cr_q6 - skin_mean[idx][1]); + const int cr_diff_q12 = + (cr_q6 - skin_mean[idx][1]) * (cr_q6 - skin_mean[idx][1]); const int cb_diff_q2 = (cb_diff_q12 + (1 << 9)) >> 10; const int cbcr_diff_q2 = (cbcr_diff_q12 + (1 << 9)) >> 10; const int cr_diff_q2 = (cr_diff_q12 + (1 << 9)) >> 10; @@ -67,6 +72,34 @@ static int evaluate_skin_color_difference(int cb, int cr) return skin_diff; } +// Checks if the input yCbCr values corresponds to skin color. +static int is_skin_color(int y, int cb, int cr) +{ + if (y < 40 || y > 220) + { + return 0; + } + else + { + if (MODEL_MODE == 0) + { + return (evaluate_skin_color_difference(cb, cr, 0) < skin_threshold[0]); + } + else + { + int i = 0; + for (; i < 5; i++) + { + if (evaluate_skin_color_difference(cb, cr, i) < skin_threshold[1]) + { + return 1; + } + } + return 0; + } + } +} + static int macroblock_corner_grad(unsigned char* signal, int stride, int offsetx, int offsety, int sgnx, int sgny) { @@ -157,16 +190,6 @@ static int check_dot_artifact_candidate(VP8_COMP *cpi, return 0; } -// Checks if the input yCbCr values corresponds to skin color. -static int is_skin_color(int y, int cb, int cr) -{ - if (y < 40 || y > 220) - { - return 0; - } - return (evaluate_skin_color_difference(cb, cr) < skin_threshold); -} - int vp8_skip_fractional_mv_step(MACROBLOCK *mb, BLOCK *b, BLOCKD *d, int_mv *bestmv, int_mv *ref_mv, int error_per_bit, diff --git a/vp9/encoder/vp9_skin_detection.c b/vp9/encoder/vp9_skin_detection.c index 0ca166536..54cc0828b 100644 --- a/vp9/encoder/vp9_skin_detection.c +++ b/vp9/encoder/vp9_skin_detection.c @@ -15,22 +15,28 @@ #include "vp9/encoder/vp9_encoder.h" #include "vp9/encoder/vp9_skin_detection.h" +#define MODEL_MODE 0 + // Fixed-point skin color model parameters. -static const int skin_mean[2] = {7463, 9614}; // q6 +static const int skin_mean[5][2] = { + {7463, 9614}, {6400, 10240}, {7040, 10240}, {8320, 9280}, {6800, 9614}}; static const int skin_inv_cov[4] = {4107, 1663, 1663, 2157}; // q16 -static const int skin_threshold = 1570636; // q18 +static const int skin_threshold[2] = {1570636, 800000}; // q18 // Thresholds on luminance. static const int y_low = 20; static const int y_high = 220; // Evaluates the Mahalanobis distance measure for the input CbCr values. -static int evaluate_skin_color_difference(int cb, int cr) { +static int evaluate_skin_color_difference(int cb, int cr, int idx) { const int cb_q6 = cb << 6; const int cr_q6 = cr << 6; - const int cb_diff_q12 = (cb_q6 - skin_mean[0]) * (cb_q6 - skin_mean[0]); - const int cbcr_diff_q12 = (cb_q6 - skin_mean[0]) * (cr_q6 - skin_mean[1]); - const int cr_diff_q12 = (cr_q6 - skin_mean[1]) * (cr_q6 - skin_mean[1]); + const int cb_diff_q12 = + (cb_q6 - skin_mean[idx][0]) * (cb_q6 - skin_mean[idx][0]); + const int cbcr_diff_q12 = + (cb_q6 - skin_mean[idx][0]) * (cr_q6 - skin_mean[idx][1]); + const int cr_diff_q12 = + (cr_q6 - skin_mean[idx][1]) * (cr_q6 - skin_mean[idx][1]); const int cb_diff_q2 = (cb_diff_q12 + (1 << 9)) >> 10; const int cbcr_diff_q2 = (cbcr_diff_q12 + (1 << 9)) >> 10; const int cr_diff_q2 = (cr_diff_q12 + (1 << 9)) >> 10; @@ -42,10 +48,21 @@ static int evaluate_skin_color_difference(int cb, int cr) { } int vp9_skin_pixel(const uint8_t y, const uint8_t cb, const uint8_t cr) { - if (y < y_low || y > y_high) + if (y < y_low || y > y_high) { return 0; - else - return (evaluate_skin_color_difference(cb, cr) < skin_threshold); + } else { + if (MODEL_MODE == 0) { + return (evaluate_skin_color_difference(cb, cr, 0) < skin_threshold[0]); + } else { + int i = 0; + for (; i < 5; i++) { + if (evaluate_skin_color_difference(cb, cr, i) < skin_threshold[1]) { + return 1; + } + } + return 0; + } + } } int vp9_compute_skin_block(const uint8_t *y, const uint8_t *u, const uint8_t *v,