2 * Copyright (c) 2015 The WebM project authors. All Rights Reserved.
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.
14 #include "vp9/common/vp9_blockd.h"
15 #include "vp9/encoder/vp9_encoder.h"
16 #include "vp9/encoder/vp9_skin_detection.h"
18 // Fixed-point skin color model parameters.
19 static const int skin_mean
[2] = {7463, 9614}; // q6
20 static const int skin_inv_cov
[4] = {4107, 1663, 1663, 2157}; // q16
21 static const int skin_threshold
= 1570636; // q18
23 // Thresholds on luminance.
24 static const int y_low
= 20;
25 static const int y_high
= 220;
27 // Evaluates the Mahalanobis distance measure for the input CbCr values.
28 static int evaluate_skin_color_difference(int cb
, int cr
) {
29 const int cb_q6
= cb
<< 6;
30 const int cr_q6
= cr
<< 6;
31 const int cb_diff_q12
= (cb_q6
- skin_mean
[0]) * (cb_q6
- skin_mean
[0]);
32 const int cbcr_diff_q12
= (cb_q6
- skin_mean
[0]) * (cr_q6
- skin_mean
[1]);
33 const int cr_diff_q12
= (cr_q6
- skin_mean
[1]) * (cr_q6
- skin_mean
[1]);
34 const int cb_diff_q2
= (cb_diff_q12
+ (1 << 9)) >> 10;
35 const int cbcr_diff_q2
= (cbcr_diff_q12
+ (1 << 9)) >> 10;
36 const int cr_diff_q2
= (cr_diff_q12
+ (1 << 9)) >> 10;
37 const int skin_diff
= skin_inv_cov
[0] * cb_diff_q2
+
38 skin_inv_cov
[1] * cbcr_diff_q2
+
39 skin_inv_cov
[2] * cbcr_diff_q2
+
40 skin_inv_cov
[3] * cr_diff_q2
;
44 int vp9_skin_pixel(const uint8_t y
, const uint8_t cb
, const uint8_t cr
) {
45 if (y
< y_low
|| y
> y_high
)
48 return (evaluate_skin_color_difference(cb
, cr
) < skin_threshold
);
51 #ifdef OUTPUT_YUV_SKINMAP
52 // For viewing skin map on input source.
53 void vp9_compute_skin_map(VP9_COMP
*const cpi
, FILE *yuv_skinmap_file
) {
54 int i
, j
, mi_row
, mi_col
;
55 VP9_COMMON
*const cm
= &cpi
->common
;
57 const uint8_t *src_y
= cpi
->Source
->y_buffer
;
58 const uint8_t *src_u
= cpi
->Source
->u_buffer
;
59 const uint8_t *src_v
= cpi
->Source
->v_buffer
;
60 const int src_ystride
= cpi
->Source
->y_stride
;
61 const int src_uvstride
= cpi
->Source
->uv_stride
;
62 YV12_BUFFER_CONFIG skinmap
;
63 memset(&skinmap
, 0, sizeof(YV12_BUFFER_CONFIG
));
64 if (vp9_alloc_frame_buffer(&skinmap
, cm
->width
, cm
->height
,
65 cm
->subsampling_x
, cm
->subsampling_y
,
66 VP9_ENC_BORDER_IN_PIXELS
, cm
->byte_alignment
)) {
67 vp9_free_frame_buffer(&skinmap
);
70 memset(skinmap
.buffer_alloc
, 128, skinmap
.frame_size
);
72 // Loop through 8x8 blocks and set skin map based on center pixel of block.
73 // Set y to white for skin block, otherwise set to source with gray scale.
74 // Ignore rightmost/bottom boundary blocks.
75 for (mi_row
= 0; mi_row
< cm
->mi_rows
- 1; ++mi_row
) {
76 for (mi_col
= 0; mi_col
< cm
->mi_cols
- 1; ++mi_col
) {
77 // Use middle pixel for each 8x8 block for skin detection.
78 // If middle pixel is skin, assign whole 8x8 block to skin.
79 const uint8_t ysource
= src_y
[4 * src_ystride
+ 4];
80 const uint8_t usource
= src_u
[2 * src_uvstride
+ 2];
81 const uint8_t vsource
= src_v
[2 * src_uvstride
+ 2];
82 const int is_skin
= vp9_skin_pixel(ysource
, usource
, vsource
);
83 for (i
= 0; i
< 8; i
++) {
84 for (j
= 0; j
< 8; j
++) {
86 y
[i
* src_ystride
+ j
] = 255;
88 y
[i
* src_ystride
+ j
] = src_y
[i
* src_ystride
+ j
];
96 y
+= (src_ystride
<< 3) - ((cm
->mi_cols
- 1) << 3);
97 src_y
+= (src_ystride
<< 3) - ((cm
->mi_cols
- 1) << 3);
98 src_u
+= (src_uvstride
<< 2) - ((cm
->mi_cols
- 1) << 2);
99 src_v
+= (src_uvstride
<< 2) - ((cm
->mi_cols
- 1) << 2);
101 vp9_write_yuv_frame_420(&skinmap
, yuv_skinmap_file
);
102 vp9_free_frame_buffer(&skinmap
);