Home | History | Annotate | Download | only in video_processing
      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 
     19 VPMBrightnessDetection::VPMBrightnessDetection() {
     20   Reset();
     21 }
     22 
     23 VPMBrightnessDetection::~VPMBrightnessDetection() {}
     24 
     25 void VPMBrightnessDetection::Reset() {
     26   frame_cnt_bright_ = 0;
     27   frame_cnt_dark_ = 0;
     28 }
     29 
     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