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