vp8_skin_detection.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  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. #include "vp8/common/alloccommon.h"
  11. #include "vp8/common/vp8_skin_detection.h"
  12. #include "vpx_dsp/vpx_dsp_common.h"
  13. #include "vpx_mem/vpx_mem.h"
  14. #include "vpx_util/vpx_write_yuv_frame.h"
  15. static int avg_2x2(const uint8_t *s, int p) {
  16. int i, j;
  17. int sum = 0;
  18. for (i = 0; i < 2; ++i, s += p) {
  19. for (j = 0; j < 2; ++j) {
  20. sum += s[j];
  21. }
  22. }
  23. return (sum + 2) >> 2;
  24. }
  25. int vp8_compute_skin_block(const uint8_t *y, const uint8_t *u, const uint8_t *v,
  26. int stride, int strideuv,
  27. SKIN_DETECTION_BLOCK_SIZE bsize, int consec_zeromv,
  28. int curr_motion_magn) {
  29. // No skin if block has been zero/small motion for long consecutive time.
  30. if (consec_zeromv > 60 && curr_motion_magn == 0) {
  31. return 0;
  32. } else {
  33. int motion = 1;
  34. if (consec_zeromv > 25 && curr_motion_magn == 0) motion = 0;
  35. if (bsize == SKIN_16X16) {
  36. // Take the average of center 2x2 pixels.
  37. const int ysource = avg_2x2(y + 7 * stride + 7, stride);
  38. const int usource = avg_2x2(u + 3 * strideuv + 3, strideuv);
  39. const int vsource = avg_2x2(v + 3 * strideuv + 3, strideuv);
  40. return vpx_skin_pixel(ysource, usource, vsource, motion);
  41. } else {
  42. int num_skin = 0;
  43. int i, j;
  44. for (i = 0; i < 2; i++) {
  45. for (j = 0; j < 2; j++) {
  46. // Take the average of center 2x2 pixels.
  47. const int ysource = avg_2x2(y + 3 * stride + 3, stride);
  48. const int usource = avg_2x2(u + strideuv + 1, strideuv);
  49. const int vsource = avg_2x2(v + strideuv + 1, strideuv);
  50. num_skin += vpx_skin_pixel(ysource, usource, vsource, motion);
  51. if (num_skin >= 2) return 1;
  52. y += 8;
  53. u += 4;
  54. v += 4;
  55. }
  56. y += (stride << 3) - 16;
  57. u += (strideuv << 2) - 8;
  58. v += (strideuv << 2) - 8;
  59. }
  60. return 0;
  61. }
  62. }
  63. }
  64. #ifdef OUTPUT_YUV_SKINMAP
  65. // For viewing skin map on input source.
  66. void vp8_compute_skin_map(VP8_COMP *const cpi, FILE *yuv_skinmap_file) {
  67. int i, j, mb_row, mb_col, num_bl;
  68. VP8_COMMON *const cm = &cpi->common;
  69. uint8_t *y;
  70. const uint8_t *src_y = cpi->Source->y_buffer;
  71. const int src_ystride = cpi->Source->y_stride;
  72. int offset = 0;
  73. YV12_BUFFER_CONFIG skinmap;
  74. memset(&skinmap, 0, sizeof(skinmap));
  75. if (vp8_yv12_alloc_frame_buffer(&skinmap, cm->Width, cm->Height,
  76. VP8BORDERINPIXELS) < 0) {
  77. vpx_free_frame_buffer(&skinmap);
  78. return;
  79. }
  80. memset(skinmap.buffer_alloc, 128, skinmap.frame_size);
  81. y = skinmap.y_buffer;
  82. // Loop through blocks and set skin map based on center pixel of block.
  83. // Set y to white for skin block, otherwise set to source with gray scale.
  84. for (mb_row = 0; mb_row < cm->mb_rows; mb_row += 1) {
  85. num_bl = 0;
  86. for (mb_col = 0; mb_col < cm->mb_cols; mb_col += 1) {
  87. const int is_skin = cpi->skin_map[offset++];
  88. for (i = 0; i < 16; i++) {
  89. for (j = 0; j < 16; j++) {
  90. y[i * src_ystride + j] = is_skin ? 255 : src_y[i * src_ystride + j];
  91. }
  92. }
  93. num_bl++;
  94. y += 16;
  95. src_y += 16;
  96. }
  97. y += (src_ystride << 4) - (num_bl << 4);
  98. src_y += (src_ystride << 4) - (num_bl << 4);
  99. }
  100. vpx_write_yuv_frame(yuv_skinmap_file, &skinmap);
  101. vpx_free_frame_buffer(&skinmap);
  102. }
  103. #endif // OUTPUT_YUV_SKINMAP