1 /* 2 * Copyright (c) 2011 The WebRTC 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 "webrtc/modules/video_processing/brightness_detection.h" 12 13 #include <math.h> 14 15 #include "webrtc/modules/video_processing/include/video_processing.h" 16 17 namespace webrtc { 18 VPMBrightnessDetection()19VPMBrightnessDetection::VPMBrightnessDetection() { 20 Reset(); 21 } 22 ~VPMBrightnessDetection()23VPMBrightnessDetection::~VPMBrightnessDetection() {} 24 Reset()25void VPMBrightnessDetection::Reset() { 26 frame_cnt_bright_ = 0; 27 frame_cnt_dark_ = 0; 28 } 29 ProcessFrame(const VideoFrame & frame,const VideoProcessing::FrameStats & stats)30int32_t VPMBrightnessDetection::ProcessFrame( 31 const VideoFrame& frame, 32 const VideoProcessing::FrameStats& stats) { 33 if (frame.IsZeroSize()) { 34 return VPM_PARAMETER_ERROR; 35 } 36 int width = frame.width(); 37 int height = frame.height(); 38 39 if (!VideoProcessing::ValidFrameStats(stats)) { 40 return VPM_PARAMETER_ERROR; 41 } 42 43 const uint8_t frame_cnt_alarm = 2; 44 45 // Get proportion in lowest bins. 46 uint8_t low_th = 20; 47 float prop_low = 0; 48 for (uint32_t i = 0; i < low_th; i++) { 49 prop_low += stats.hist[i]; 50 } 51 prop_low /= stats.num_pixels; 52 53 // Get proportion in highest bins. 54 unsigned char high_th = 230; 55 float prop_high = 0; 56 for (uint32_t i = high_th; i < 256; i++) { 57 prop_high += stats.hist[i]; 58 } 59 prop_high /= stats.num_pixels; 60 61 if (prop_high < 0.4) { 62 if (stats.mean < 90 || stats.mean > 170) { 63 // Standard deviation of Y 64 const uint8_t* buffer = frame.buffer(kYPlane); 65 float std_y = 0; 66 for (int h = 0; h < height; h += (1 << stats.sub_sampling_factor)) { 67 int row = h * width; 68 for (int w = 0; w < width; w += (1 << stats.sub_sampling_factor)) { 69 std_y += 70 (buffer[w + row] - stats.mean) * (buffer[w + row] - stats.mean); 71 } 72 } 73 std_y = sqrt(std_y / stats.num_pixels); 74 75 // Get percentiles. 76 uint32_t sum = 0; 77 uint32_t median_y = 140; 78 uint32_t perc05 = 0; 79 uint32_t perc95 = 255; 80 float pos_perc05 = stats.num_pixels * 0.05f; 81 float pos_median = stats.num_pixels * 0.5f; 82 float posPerc95 = stats.num_pixels * 0.95f; 83 for (uint32_t i = 0; i < 256; i++) { 84 sum += stats.hist[i]; 85 if (sum < pos_perc05) 86 perc05 = i; // 5th perc. 87 if (sum < pos_median) 88 median_y = i; // 50th perc. 89 if (sum < posPerc95) 90 perc95 = i; // 95th perc. 91 else 92 break; 93 } 94 95 // Check if image is too dark 96 if ((std_y < 55) && (perc05 < 50)) { 97 if (median_y < 60 || stats.mean < 80 || perc95 < 130 || 98 prop_low > 0.20) { 99 frame_cnt_dark_++; 100 } else { 101 frame_cnt_dark_ = 0; 102 } 103 } else { 104 frame_cnt_dark_ = 0; 105 } 106 107 // Check if image is too bright 108 if ((std_y < 52) && (perc95 > 200) && (median_y > 160)) { 109 if (median_y > 185 || stats.mean > 185 || perc05 > 140 || 110 prop_high > 0.25) { 111 frame_cnt_bright_++; 112 } else { 113 frame_cnt_bright_ = 0; 114 } 115 } else { 116 frame_cnt_bright_ = 0; 117 } 118 } else { 119 frame_cnt_dark_ = 0; 120 frame_cnt_bright_ = 0; 121 } 122 } else { 123 frame_cnt_bright_++; 124 frame_cnt_dark_ = 0; 125 } 126 127 if (frame_cnt_dark_ > frame_cnt_alarm) { 128 return VideoProcessing::kDarkWarning; 129 } else if (frame_cnt_bright_ > frame_cnt_alarm) { 130 return VideoProcessing::kBrightWarning; 131 } else { 132 return VideoProcessing::kNoWarning; 133 } 134 } 135 136 } // namespace webrtc 137