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()19 VPMBrightnessDetection::VPMBrightnessDetection() {
20   Reset();
21 }
22 
~VPMBrightnessDetection()23 VPMBrightnessDetection::~VPMBrightnessDetection() {}
24 
Reset()25 void VPMBrightnessDetection::Reset() {
26   frame_cnt_bright_ = 0;
27   frame_cnt_dark_ = 0;
28 }
29 
ProcessFrame(const VideoFrame & frame,const VideoProcessing::FrameStats & stats)30 int32_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