OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include <limits.h> | 11 #include <limits.h> |
12 #include <math.h> | 12 #include <math.h> |
13 | 13 |
14 #include "webrtc/modules/video_processing/util/skin_detection.h" | 14 #include "webrtc/modules/video_processing/util/skin_detection.h" |
15 | 15 |
16 namespace webrtc { | 16 namespace webrtc { |
17 | 17 |
18 // Fixed-point skin color model parameters. | 18 // Fixed-point skin color model parameters. |
19 static const int skin_mean[2] = {7463, 9614}; // q6 | 19 static const int skin_mean[5][2] = { |
| 20 {7463, 9614}, {6400, 10240}, {7040, 10240}, {8320, 9280}, {6800, 9614}}; |
20 static const int skin_inv_cov[4] = {4107, 1663, 1663, 2157}; // q16 | 21 static const int skin_inv_cov[4] = {4107, 1663, 1663, 2157}; // q16 |
21 static const int skin_threshold = 1570636; // q18 | 22 static const int skin_threshold[6] = {1570636, 1400000, 800000, 800000, 800000, |
| 23 800000}; // q18 |
22 | 24 |
23 // Thresholds on luminance. | 25 // Thresholds on luminance. |
24 static const int y_low = 20; | 26 static const int y_low = 40; |
25 static const int y_high = 220; | 27 static const int y_high = 220; |
26 | 28 |
27 // Evaluates the Mahalanobis distance measure for the input CbCr values. | 29 // Evaluates the Mahalanobis distance measure for the input CbCr values. |
28 static int EvaluateSkinColorDifference(int cb, int cr) { | 30 static int EvaluateSkinColorDifference(int cb, int cr, int idx) { |
29 const int cb_q6 = cb << 6; | 31 const int cb_q6 = cb << 6; |
30 const int cr_q6 = cr << 6; | 32 const int cr_q6 = cr << 6; |
31 const int cb_diff_q12 = (cb_q6 - skin_mean[0]) * (cb_q6 - skin_mean[0]); | 33 const int cb_diff_q12 = |
32 const int cbcr_diff_q12 = (cb_q6 - skin_mean[0]) * (cr_q6 - skin_mean[1]); | 34 (cb_q6 - skin_mean[idx][0]) * (cb_q6 - skin_mean[idx][0]); |
33 const int cr_diff_q12 = (cr_q6 - skin_mean[1]) * (cr_q6 - skin_mean[1]); | 35 const int cbcr_diff_q12 = |
| 36 (cb_q6 - skin_mean[idx][0]) * (cr_q6 - skin_mean[idx][1]); |
| 37 const int cr_diff_q12 = |
| 38 (cr_q6 - skin_mean[idx][1]) * (cr_q6 - skin_mean[idx][1]); |
34 const int cb_diff_q2 = (cb_diff_q12 + (1 << 9)) >> 10; | 39 const int cb_diff_q2 = (cb_diff_q12 + (1 << 9)) >> 10; |
35 const int cbcr_diff_q2 = (cbcr_diff_q12 + (1 << 9)) >> 10; | 40 const int cbcr_diff_q2 = (cbcr_diff_q12 + (1 << 9)) >> 10; |
36 const int cr_diff_q2 = (cr_diff_q12 + (1 << 9)) >> 10; | 41 const int cr_diff_q2 = (cr_diff_q12 + (1 << 9)) >> 10; |
37 const int skin_diff = | 42 const int skin_diff = skin_inv_cov[0] * cb_diff_q2 + |
38 skin_inv_cov[0] * cb_diff_q2 + skin_inv_cov[1] * cbcr_diff_q2 + | 43 skin_inv_cov[1] * cbcr_diff_q2 + |
39 skin_inv_cov[2] * cbcr_diff_q2 + skin_inv_cov[3] * cr_diff_q2; | 44 skin_inv_cov[2] * cbcr_diff_q2 + |
| 45 skin_inv_cov[3] * cr_diff_q2; |
40 return skin_diff; | 46 return skin_diff; |
41 } | 47 } |
42 | 48 |
| 49 static int SkinPixel(const uint8_t y, const uint8_t cb, const uint8_t cr) { |
| 50 if (y < y_low || y > y_high) { |
| 51 return 0; |
| 52 } else { |
| 53 if (MODEL_MODE == 0) { |
| 54 return (EvaluateSkinColorDifference(cb, cr, 0) < skin_threshold[0]); |
| 55 } else { |
| 56 // Exit on grey. |
| 57 if (cb == 128 && cr == 128) |
| 58 return 0; |
| 59 // Exit on very strong cb. |
| 60 if (cb > 150 && cr < 110) |
| 61 return 0; |
| 62 // Exit on (another) low luminance threshold if either color is high. |
| 63 if (y < 50 && (cb > 140 || cr > 140)) |
| 64 return 0; |
| 65 for (int i = 0; i < 5; i++) { |
| 66 int diff = EvaluateSkinColorDifference(cb, cr, i); |
| 67 if (diff < skin_threshold[i + 1]) { |
| 68 return 1; |
| 69 } else if (diff > (skin_threshold[i + 1] << 3)) { |
| 70 // Exit if difference is much large than the threshold. |
| 71 return 0; |
| 72 } |
| 73 } |
| 74 return 0; |
| 75 } |
| 76 } |
| 77 } |
| 78 |
43 bool MbHasSkinColor(const uint8_t* y_src, | 79 bool MbHasSkinColor(const uint8_t* y_src, |
44 const uint8_t* u_src, | 80 const uint8_t* u_src, |
45 const uint8_t* v_src, | 81 const uint8_t* v_src, |
46 const int stride_y, | 82 const int stride_y, |
47 const int stride_u, | 83 const int stride_u, |
48 const int stride_v, | 84 const int stride_v, |
49 const int mb_row, | 85 const int mb_row, |
50 const int mb_col) { | 86 const int mb_col) { |
51 const uint8_t* y = y_src + ((mb_row << 4) + 8) * stride_y + (mb_col << 4) + 8; | 87 const uint8_t* y = y_src + ((mb_row << 4) + 8) * stride_y + (mb_col << 4) + 8; |
52 const uint8_t* u = u_src + ((mb_row << 3) + 4) * stride_u + (mb_col << 3) + 4; | 88 const uint8_t* u = u_src + ((mb_row << 3) + 4) * stride_u + (mb_col << 3) + 4; |
53 const uint8_t* v = v_src + ((mb_row << 3) + 4) * stride_v + (mb_col << 3) + 4; | 89 const uint8_t* v = v_src + ((mb_row << 3) + 4) * stride_v + (mb_col << 3) + 4; |
54 // Use 2x2 average of center pixel to compute skin area. | 90 // Use 2x2 average of center pixel to compute skin area. |
55 uint8_t y_avg = (*y + *(y + 1) + *(y + stride_y) + *(y + stride_y + 1)) >> 2; | 91 uint8_t y_avg = (*y + *(y + 1) + *(y + stride_y) + *(y + stride_y + 1)) >> 2; |
56 uint8_t u_avg = (*u + *(u + 1) + *(u + stride_u) + *(u + stride_u + 1)) >> 2; | 92 uint8_t u_avg = (*u + *(u + 1) + *(u + stride_u) + *(u + stride_u + 1)) >> 2; |
57 uint8_t v_avg = (*v + *(v + 1) + *(v + stride_v) + *(v + stride_v + 1)) >> 2; | 93 uint8_t v_avg = (*v + *(v + 1) + *(v + stride_v) + *(v + stride_v + 1)) >> 2; |
58 // Ignore MB with too high or low brightness. | 94 return SkinPixel(y_avg, u_avg, v_avg) == 1; |
59 if (y_avg < y_low || y_avg > y_high) | |
60 return false; | |
61 else | |
62 return (EvaluateSkinColorDifference(u_avg, v_avg) < skin_threshold); | |
63 } | 95 } |
64 | 96 |
65 } // namespace webrtc | 97 } // namespace webrtc |
OLD | NEW |