| /* |
| * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include "video_processing.h" |
| #include "brightness_detection.h" |
| #include "trace.h" |
| |
| #include <math.h> |
| |
| namespace webrtc { |
| |
| VPMBrightnessDetection::VPMBrightnessDetection() : |
| _id(0) |
| { |
| Reset(); |
| } |
| |
| VPMBrightnessDetection::~VPMBrightnessDetection() |
| { |
| } |
| |
| WebRtc_Word32 |
| VPMBrightnessDetection::ChangeUniqueId(const WebRtc_Word32 id) |
| { |
| _id = id; |
| return VPM_OK; |
| } |
| |
| void |
| VPMBrightnessDetection::Reset() |
| { |
| _frameCntBright = 0; |
| _frameCntDark = 0; |
| } |
| |
| WebRtc_Word32 |
| VPMBrightnessDetection::ProcessFrame(const WebRtc_UWord8* frame, |
| const WebRtc_UWord32 width, |
| const WebRtc_UWord32 height, |
| const VideoProcessingModule::FrameStats& stats) |
| { |
| if (frame == NULL) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, _id, "Null frame pointer"); |
| return VPM_PARAMETER_ERROR; |
| } |
| |
| if (width == 0 || height == 0) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, _id, "Invalid frame size"); |
| return VPM_PARAMETER_ERROR; |
| } |
| |
| if (!VideoProcessingModule::ValidFrameStats(stats)) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, _id, "Invalid frame stats"); |
| return VPM_PARAMETER_ERROR; |
| } |
| |
| const WebRtc_UWord8 frameCntAlarm = 2; |
| |
| // Get proportion in lowest bins |
| WebRtc_UWord8 lowTh = 20; |
| float propLow = 0; |
| for (WebRtc_UWord32 i = 0; i < lowTh; i++) |
| { |
| propLow += stats.hist[i]; |
| } |
| propLow /= stats.numPixels; |
| |
| // Get proportion in highest bins |
| unsigned char highTh = 230; |
| float propHigh = 0; |
| for (WebRtc_UWord32 i = highTh; i < 256; i++) |
| { |
| propHigh += stats.hist[i]; |
| } |
| propHigh /= stats.numPixels; |
| |
| if(propHigh < 0.4) |
| { |
| if (stats.mean < 90 || stats.mean > 170) |
| { |
| // Standard deviation of Y |
| float stdY = 0; |
| for (WebRtc_UWord32 h = 0; h < height; h += (1 << stats.subSamplHeight)) |
| { |
| WebRtc_UWord32 row = h*width; |
| for (WebRtc_UWord32 w = 0; w < width; w += (1 << stats.subSamplWidth)) |
| { |
| stdY += (frame[w + row] - stats.mean) * (frame[w + row] - stats.mean); |
| } |
| } |
| stdY = sqrt(stdY / stats.numPixels); |
| |
| // Get percentiles |
| WebRtc_UWord32 sum = 0; |
| WebRtc_UWord32 medianY = 140; |
| WebRtc_UWord32 perc05 = 0; |
| WebRtc_UWord32 perc95 = 255; |
| float posPerc05 = stats.numPixels * 0.05f; |
| float posMedian = stats.numPixels * 0.5f; |
| float posPerc95 = stats.numPixels * 0.95f; |
| for (WebRtc_UWord32 i = 0; i < 256; i++) |
| { |
| sum += stats.hist[i]; |
| |
| if (sum < posPerc05) |
| { |
| perc05 = i; // 5th perc |
| } |
| if (sum < posMedian) |
| { |
| medianY = i; // 50th perc |
| } |
| if (sum < posPerc95) |
| { |
| perc95 = i; // 95th perc |
| } |
| else |
| { |
| break; |
| } |
| } |
| |
| // Check if image is too dark |
| if ((stdY < 55) && (perc05 < 50)) |
| { |
| if (medianY < 60 || stats.mean < 80 || perc95 < 130 || propLow > 0.20) |
| { |
| _frameCntDark++; |
| } |
| else |
| { |
| _frameCntDark = 0; |
| } |
| } |
| else |
| { |
| _frameCntDark = 0; |
| } |
| |
| // Check if image is too bright |
| if ((stdY < 52) && (perc95 > 200) && (medianY > 160)) |
| { |
| if (medianY > 185 || stats.mean > 185 || perc05 > 140 || propHigh > 0.25) |
| { |
| _frameCntBright++; |
| } |
| else |
| { |
| _frameCntBright = 0; |
| } |
| } |
| else |
| { |
| _frameCntBright = 0; |
| } |
| |
| } |
| else |
| { |
| _frameCntDark = 0; |
| _frameCntBright = 0; |
| } |
| |
| } |
| else |
| { |
| _frameCntBright++; |
| _frameCntDark = 0; |
| } |
| |
| if (_frameCntDark > frameCntAlarm) |
| { |
| return VideoProcessingModule::kDarkWarning; |
| } |
| else if (_frameCntBright > frameCntAlarm) |
| { |
| return VideoProcessingModule::kBrightWarning; |
| } |
| else |
| { |
| return VideoProcessingModule::kNoWarning; |
| } |
| } |
| |
| } //namespace |