]> granicus.if.org Git - libvpx/commitdiff
Enable 8x8 skin detection for vp8.
authorJerome Jiang <jianj@google.com>
Wed, 14 Jun 2017 00:22:26 +0000 (17:22 -0700)
committerJerome Jiang <jianj@google.com>
Fri, 16 Jun 2017 03:53:03 +0000 (20:53 -0700)
If 2 or more 8x8 blocks are identified as skin, the macroblock will be
labeled as skin.

Change-Id: I596542c81a2df9e96270cab39d920bbfeb02bc6e

vp8/common/vp8_skin_detection.c
vp8/common/vp8_skin_detection.h
vp8/encoder/pickinter.c

index 495366dc849b4184e1f8242a1d2e6ee5b3fc5d97..2c0237087ee858eef7f4d156bf36e8e748a89f16 100644 (file)
 #include "vpx_mem/vpx_mem.h"
 #include "vpx_util/vpx_write_yuv_frame.h"
 
+static int avg_2x2(const uint8_t *s, int p) {
+  int i, j;
+  int sum = 0;
+  for (i = 0; i < 2; ++i, s += p) {
+    for (j = 0; j < 2; ++j) {
+      sum += s[j];
+    }
+  }
+  return (sum + 2) >> 2;
+}
+
 int vp8_compute_skin_block(const uint8_t *y, const uint8_t *u, const uint8_t *v,
-                           int stride, int strideuv, int consec_zeromv,
+                           int stride, int strideuv,
+                           SKIN_DETECTION_BLOCK_SIZE bsize, int consec_zeromv,
                            int curr_motion_magn) {
   // No skin if block has been zero/small motion for long consecutive time.
   if (consec_zeromv > 60 && curr_motion_magn == 0) {
     return 0;
   } else {
     int motion = 1;
-    // Take the average of center 2x2 pixels.
-    const int ysource = (y[7 * stride + 7] + y[7 * stride + 8] +
-                         y[8 * stride + 7] + y[8 * stride + 8]) >>
-                        2;
-    const int usource = (u[3 * strideuv + 3] + u[3 * strideuv + 4] +
-                         u[4 * strideuv + 3] + u[4 * strideuv + 4]) >>
-                        2;
-    const int vsource = (v[3 * strideuv + 3] + v[3 * strideuv + 4] +
-                         v[4 * strideuv + 3] + v[4 * strideuv + 4]) >>
-                        2;
     if (consec_zeromv > 25 && curr_motion_magn == 0) motion = 0;
-    return vpx_skin_pixel(ysource, usource, vsource, motion);
+    if (bsize == SKIN_16X16) {
+      // Take the average of center 2x2 pixels.
+      const int ysource = avg_2x2(y + 7 * stride + 7, stride);
+      const int usource = avg_2x2(u + 3 * strideuv + 3, strideuv);
+      const int vsource = avg_2x2(v + 3 * strideuv + 3, strideuv);
+      return vpx_skin_pixel(ysource, usource, vsource, motion);
+    } else {
+      int num_skin = 0;
+      int i, j;
+      for (i = 0; i < 2; i++) {
+        for (j = 0; j < 2; j++) {
+          // Take the average of center 2x2 pixels.
+          const int ysource = avg_2x2(y + 3 * stride + 3, stride);
+          const int usource = avg_2x2(u + strideuv + 1, strideuv);
+          const int vsource = avg_2x2(v + strideuv + 1, strideuv);
+          num_skin += vpx_skin_pixel(ysource, usource, vsource, motion);
+          if (num_skin >= 2) return 1;
+          y += 8;
+          u += 4;
+          v += 4;
+        }
+        y += (stride << 3) - 16;
+        u += (strideuv << 2) - 8;
+        v += (strideuv << 2) - 8;
+      }
+
+      return 0;
+    }
   }
 }
 
@@ -74,8 +103,9 @@ void vp8_compute_skin_map(VP8_COMP *const cpi, FILE *yuv_skinmap_file) {
                              VPXMIN(cpi->consec_zero_last[bl_index1],
                                     VPXMIN(cpi->consec_zero_last[bl_index2],
                                            cpi->consec_zero_last[bl_index3])));
-      is_skin = vp8_compute_skin_block(src_y, src_u, src_v, src_ystride,
-                                       src_uvstride, consec_zeromv, 0);
+      is_skin =
+          vp8_compute_skin_block(src_y, src_u, src_v, src_ystride, src_uvstride,
+                                 SKIN_8X8, consec_zeromv, 0);
       for (i = 0; i < 16; i++) {
         for (j = 0; j < 16; j++) {
           if (is_skin)
index 3d0a9f45f0fb2f13d0abf53442b7ac50536d3f9e..4d27f5eb2ea6a6feaebd20ada4d842de052bc6b8 100644 (file)
@@ -22,8 +22,17 @@ extern "C" {
 
 struct VP8_COMP;
 
+typedef enum {
+  // Skin detection based on 8x8 block. If two of them are identified as skin,
+  // the macroblock is marked as skin.
+  SKIN_8X8,
+  // Skin detection based on 16x16 block.
+  SKIN_16X16
+} SKIN_DETECTION_BLOCK_SIZE;
+
 int vp8_compute_skin_block(const uint8_t *y, const uint8_t *u, const uint8_t *v,
-                           int stride, int strideuv, int consec_zeromv,
+                           int stride, int strideuv,
+                           SKIN_DETECTION_BLOCK_SIZE bsize, int consec_zeromv,
                            int curr_motion_magn);
 
 #ifdef OUTPUT_YUV_SKINMAP
index 74f9def69fde74c7e3545937d63266dabf707f62..d399839ddf6b5d64a3f8f7663987af217e4cd555 100644 (file)
@@ -693,7 +693,7 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
     int block_index = mb_row * cpi->common.mb_cols + mb_col;
     x->is_skin = vp8_compute_skin_block(
         x->src.y_buffer, x->src.u_buffer, x->src.v_buffer, x->src.y_stride,
-        x->src.uv_stride, cpi->consec_zero_last[block_index], 0);
+        x->src.uv_stride, SKIN_16X16, cpi->consec_zero_last[block_index], 0);
   }
 #if CONFIG_TEMPORAL_DENOISING
   if (cpi->oxcf.noise_sensitivity) {