LCOV - code coverage report
Current view: top level - media/libvpx/libvpx/vp9/encoder - vp9_skin_detection.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 47 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 3 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  *  Copyright (c) 2015 The WebM project authors. All Rights Reserved.
       3             :  *
       4             :  *  Use of this source code is governed by a BSD-style license
       5             :  *  that can be found in the LICENSE file in the root of the source
       6             :  *  tree. An additional intellectual property rights grant can be found
       7             :  *  in the file PATENTS.  All contributing project authors may
       8             :  *  be found in the AUTHORS file in the root of the source tree.
       9             :  */
      10             : 
      11             : #include <limits.h>
      12             : #include <math.h>
      13             : 
      14             : #include "vp9/common/vp9_blockd.h"
      15             : #include "vp9/encoder/vp9_encoder.h"
      16             : #include "vp9/encoder/vp9_skin_detection.h"
      17             : 
      18             : #define MODEL_MODE 1
      19             : 
      20             : // Fixed-point skin color model parameters.
      21             : static const int skin_mean[5][2] = { { 7463, 9614 },
      22             :                                      { 6400, 10240 },
      23             :                                      { 7040, 10240 },
      24             :                                      { 8320, 9280 },
      25             :                                      { 6800, 9614 } };
      26             : static const int skin_inv_cov[4] = { 4107, 1663, 1663, 2157 };  // q16
      27             : static const int skin_threshold[6] = { 1570636, 1400000, 800000,
      28             :                                        800000,  800000,  800000 };  // q18
      29             : 
      30             : // Thresholds on luminance.
      31             : static const int y_low = 40;
      32             : static const int y_high = 220;
      33             : 
      34             : // Evaluates the Mahalanobis distance measure for the input CbCr values.
      35           0 : static int evaluate_skin_color_difference(int cb, int cr, int idx) {
      36           0 :   const int cb_q6 = cb << 6;
      37           0 :   const int cr_q6 = cr << 6;
      38           0 :   const int cb_diff_q12 =
      39           0 :       (cb_q6 - skin_mean[idx][0]) * (cb_q6 - skin_mean[idx][0]);
      40           0 :   const int cbcr_diff_q12 =
      41           0 :       (cb_q6 - skin_mean[idx][0]) * (cr_q6 - skin_mean[idx][1]);
      42           0 :   const int cr_diff_q12 =
      43           0 :       (cr_q6 - skin_mean[idx][1]) * (cr_q6 - skin_mean[idx][1]);
      44           0 :   const int cb_diff_q2 = (cb_diff_q12 + (1 << 9)) >> 10;
      45           0 :   const int cbcr_diff_q2 = (cbcr_diff_q12 + (1 << 9)) >> 10;
      46           0 :   const int cr_diff_q2 = (cr_diff_q12 + (1 << 9)) >> 10;
      47           0 :   const int skin_diff =
      48           0 :       skin_inv_cov[0] * cb_diff_q2 + skin_inv_cov[1] * cbcr_diff_q2 +
      49           0 :       skin_inv_cov[2] * cbcr_diff_q2 + skin_inv_cov[3] * cr_diff_q2;
      50           0 :   return skin_diff;
      51             : }
      52             : 
      53           0 : int vp9_skin_pixel(const uint8_t y, const uint8_t cb, const uint8_t cr,
      54             :                    int motion) {
      55           0 :   if (y < y_low || y > y_high) {
      56           0 :     return 0;
      57             :   } else {
      58             :     if (MODEL_MODE == 0) {
      59             :       return (evaluate_skin_color_difference(cb, cr, 0) < skin_threshold[0]);
      60             :     } else {
      61           0 :       int i = 0;
      62             :       // Exit on grey.
      63           0 :       if (cb == 128 && cr == 128) return 0;
      64             :       // Exit on very strong cb.
      65           0 :       if (cb > 150 && cr < 110) return 0;
      66           0 :       for (; i < 5; i++) {
      67           0 :         int skin_color_diff = evaluate_skin_color_difference(cb, cr, i);
      68           0 :         if (skin_color_diff < skin_threshold[i + 1]) {
      69           0 :           if (y < 60 && skin_color_diff > 3 * (skin_threshold[i + 1] >> 2))
      70           0 :             return 0;
      71           0 :           else if (motion == 0 &&
      72           0 :                    skin_color_diff > (skin_threshold[i + 1] >> 1))
      73           0 :             return 0;
      74             :           else
      75           0 :             return 1;
      76             :         }
      77             :         // Exit if difference is much large than the threshold.
      78           0 :         if (skin_color_diff > (skin_threshold[i + 1] << 3)) {
      79           0 :           return 0;
      80             :         }
      81             :       }
      82           0 :       return 0;
      83             :     }
      84             :   }
      85             : }
      86             : 
      87           0 : int vp9_compute_skin_block(const uint8_t *y, const uint8_t *u, const uint8_t *v,
      88             :                            int stride, int strideuv, int bsize,
      89             :                            int consec_zeromv, int curr_motion_magn) {
      90             :   // No skin if block has been zero/small motion for long consecutive time.
      91           0 :   if (consec_zeromv > 60 && curr_motion_magn == 0) {
      92           0 :     return 0;
      93             :   } else {
      94           0 :     int motion = 1;
      95             :     // Take center pixel in block to determine is_skin.
      96           0 :     const int y_width_shift = (4 << b_width_log2_lookup[bsize]) >> 1;
      97           0 :     const int y_height_shift = (4 << b_height_log2_lookup[bsize]) >> 1;
      98           0 :     const int uv_width_shift = y_width_shift >> 1;
      99           0 :     const int uv_height_shift = y_height_shift >> 1;
     100           0 :     const uint8_t ysource = y[y_height_shift * stride + y_width_shift];
     101           0 :     const uint8_t usource = u[uv_height_shift * strideuv + uv_width_shift];
     102           0 :     const uint8_t vsource = v[uv_height_shift * strideuv + uv_width_shift];
     103           0 :     if (consec_zeromv > 25 && curr_motion_magn == 0) motion = 0;
     104           0 :     return vp9_skin_pixel(ysource, usource, vsource, motion);
     105             :   }
     106             : }
     107             : 
     108             : #ifdef OUTPUT_YUV_SKINMAP
     109             : // For viewing skin map on input source.
     110             : void vp9_compute_skin_map(VP9_COMP *const cpi, FILE *yuv_skinmap_file) {
     111             :   int i, j, mi_row, mi_col, num_bl;
     112             :   VP9_COMMON *const cm = &cpi->common;
     113             :   uint8_t *y;
     114             :   const uint8_t *src_y = cpi->Source->y_buffer;
     115             :   const uint8_t *src_u = cpi->Source->u_buffer;
     116             :   const uint8_t *src_v = cpi->Source->v_buffer;
     117             :   const int src_ystride = cpi->Source->y_stride;
     118             :   const int src_uvstride = cpi->Source->uv_stride;
     119             :   int y_bsize = 16;  // Use 8x8 or 16x16.
     120             :   int uv_bsize = y_bsize >> 1;
     121             :   int ypos = y_bsize >> 1;
     122             :   int uvpos = uv_bsize >> 1;
     123             :   int shy = (y_bsize == 8) ? 3 : 4;
     124             :   int shuv = shy - 1;
     125             :   int fac = y_bsize / 8;
     126             :   // Use center pixel or average of center 2x2 pixels.
     127             :   int mode_filter = 0;
     128             :   YV12_BUFFER_CONFIG skinmap;
     129             :   memset(&skinmap, 0, sizeof(YV12_BUFFER_CONFIG));
     130             :   if (vpx_alloc_frame_buffer(&skinmap, cm->width, cm->height, cm->subsampling_x,
     131             :                              cm->subsampling_y, VP9_ENC_BORDER_IN_PIXELS,
     132             :                              cm->byte_alignment)) {
     133             :     vpx_free_frame_buffer(&skinmap);
     134             :     return;
     135             :   }
     136             :   memset(skinmap.buffer_alloc, 128, skinmap.frame_size);
     137             :   y = skinmap.y_buffer;
     138             :   // Loop through blocks and set skin map based on center pixel of block.
     139             :   // Set y to white for skin block, otherwise set to source with gray scale.
     140             :   // Ignore rightmost/bottom boundary blocks.
     141             :   for (mi_row = 0; mi_row < cm->mi_rows - 1; mi_row += fac) {
     142             :     num_bl = 0;
     143             :     for (mi_col = 0; mi_col < cm->mi_cols - 1; mi_col += fac) {
     144             :       int is_skin = 0;
     145             :       if (mode_filter == 1) {
     146             :         // Use 2x2 average at center.
     147             :         uint8_t ysource = src_y[ypos * src_ystride + ypos];
     148             :         uint8_t usource = src_u[uvpos * src_uvstride + uvpos];
     149             :         uint8_t vsource = src_v[uvpos * src_uvstride + uvpos];
     150             :         uint8_t ysource2 = src_y[(ypos + 1) * src_ystride + ypos];
     151             :         uint8_t usource2 = src_u[(uvpos + 1) * src_uvstride + uvpos];
     152             :         uint8_t vsource2 = src_v[(uvpos + 1) * src_uvstride + uvpos];
     153             :         uint8_t ysource3 = src_y[ypos * src_ystride + (ypos + 1)];
     154             :         uint8_t usource3 = src_u[uvpos * src_uvstride + (uvpos + 1)];
     155             :         uint8_t vsource3 = src_v[uvpos * src_uvstride + (uvpos + 1)];
     156             :         uint8_t ysource4 = src_y[(ypos + 1) * src_ystride + (ypos + 1)];
     157             :         uint8_t usource4 = src_u[(uvpos + 1) * src_uvstride + (uvpos + 1)];
     158             :         uint8_t vsource4 = src_v[(uvpos + 1) * src_uvstride + (uvpos + 1)];
     159             :         ysource = (ysource + ysource2 + ysource3 + ysource4) >> 2;
     160             :         usource = (usource + usource2 + usource3 + usource4) >> 2;
     161             :         vsource = (vsource + vsource2 + vsource3 + vsource4) >> 2;
     162             :         is_skin = vp9_skin_pixel(ysource, usource, vsource, 1);
     163             :       } else {
     164             :         int block_size = BLOCK_8X8;
     165             :         int consec_zeromv = 0;
     166             :         int bl_index = mi_row * cm->mi_cols + mi_col;
     167             :         int bl_index1 = bl_index + 1;
     168             :         int bl_index2 = bl_index + cm->mi_cols;
     169             :         int bl_index3 = bl_index2 + 1;
     170             :         if (y_bsize == 8)
     171             :           consec_zeromv = cpi->consec_zero_mv[bl_index];
     172             :         else
     173             :           consec_zeromv =
     174             :               VPXMIN(cpi->consec_zero_mv[bl_index],
     175             :                      VPXMIN(cpi->consec_zero_mv[bl_index1],
     176             :                             VPXMIN(cpi->consec_zero_mv[bl_index2],
     177             :                                    cpi->consec_zero_mv[bl_index3])));
     178             :         if (y_bsize == 16) block_size = BLOCK_16X16;
     179             :         is_skin =
     180             :             vp9_compute_skin_block(src_y, src_u, src_v, src_ystride,
     181             :                                    src_uvstride, block_size, consec_zeromv, 0);
     182             :       }
     183             :       for (i = 0; i < y_bsize; i++) {
     184             :         for (j = 0; j < y_bsize; j++) {
     185             :           if (is_skin)
     186             :             y[i * src_ystride + j] = 255;
     187             :           else
     188             :             y[i * src_ystride + j] = src_y[i * src_ystride + j];
     189             :         }
     190             :       }
     191             :       num_bl++;
     192             :       y += y_bsize;
     193             :       src_y += y_bsize;
     194             :       src_u += uv_bsize;
     195             :       src_v += uv_bsize;
     196             :     }
     197             :     y += (src_ystride << shy) - (num_bl << shy);
     198             :     src_y += (src_ystride << shy) - (num_bl << shy);
     199             :     src_u += (src_uvstride << shuv) - (num_bl << shuv);
     200             :     src_v += (src_uvstride << shuv) - (num_bl << shuv);
     201             :   }
     202             :   vp9_write_yuv_frame_420(&skinmap, yuv_skinmap_file);
     203             :   vpx_free_frame_buffer(&skinmap);
     204             : }
     205             : #endif

Generated by: LCOV version 1.13