```python
import cv2
import numpy as np
import time
def calculate_frame_luminance(frame):
"""
计算帧的相对亮度(感知亮度)
使用加权公式: Y = 0.299*R + 0.587*G + 0.114*B
"""
转换为灰度图(标准亮度公式)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
或者使用RGB加权计算
luminance = 0.299 * frame:,:,2 + 0.587 * frame:,:,1 + 0.114 * frame:,:,0
返回平均亮度和最大亮度
avg_luminance = np.mean(gray)
max_luminance = np.max(gray)
min_luminance = np.min(gray)
return {
'average': avg_luminance,
'max': max_luminance,
'min': min_luminance,
'std': np.std(gray)
}
def calculate_relative_brightness(frame, reference_frame=None):
"""
计算相对亮度
如果提供参考帧,返回相对于参考帧的亮度比
"""
current = calculate_frame_luminance(frame)
if reference_frame is not None:
ref = calculate_frame_luminance(reference_frame)
relative = {
'average_ratio': current'average' / ref'average' if ref'average' > 0 else 0,
'max_ratio': current'max' / ref'max' if ref'max' > 0 else 0,
'min_ratio': current'min' / ref'min' if ref'min' > 0 else 0,
'current': current,
'reference': ref
}
return relative
else:
归一化亮度(0-255映射到0-1)
normalized = {
'average': current'average' / 255.0,
'max': current'max' / 255.0,
'min': current'min' / 255.0,
'std': current'std' / 255.0,
'raw': current
}
return normalized
def detect_video_luminance(video_path, sample_interval=30, reference_frame_index=0):
"""
检测视频的相对亮度变化
"""
cap = cv2.VideoCapture(video_path)
if not cap.isOpened():
print("Error: Could not open video.")
return None
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
fps = cap.get(cv2.CAP_PROP_FPS)
print(f"视频信息: {total_frames} 帧, {fps:.2f} FPS")
获取参考帧(第一帧或指定帧)
cap.set(cv2.CAP_PROP_POS_FRAMES, reference_frame_index)
ret, reference_frame = cap.read()
if not ret:
print("Error: Could not read reference frame.")
cap.release()
return None
重置到开始
cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
luminance_data = \[\]
frame_count = 0
print("开始处理...")
start_time = time.time()
while True:
ret, frame = cap.read()
if not ret:
break
按间隔采样
if frame_count % sample_interval == 0:
计算相对亮度
relative = calculate_relative_brightness(frame, reference_frame)
data_point = {
'frame': frame_count,
'timestamp': frame_count / fps,
'relative_avg': relative'average_ratio' if isinstance(relative, dict) else relative'average',
'absolute_avg': relative'current''average' if isinstance(relative, dict) else relative'raw''average' * 255,
'brightness_level': 'bright' if relative'average_ratio' > 1.2 else 'normal' if relative'average_ratio' > 0.8 else 'dark'
}
luminance_data.append(data_point)
进度显示
if len(luminance_data) % 10 == 0:
progress = (frame_count / total_frames) * 100
print(f"进度: {progress:.1f}%")
frame_count += 1
cap.release()
elapsed_time = time.time() - start_time
print(f"处理完成! 耗时: {elapsed_time:.2f}秒")
return {
'data': luminance_data,
'total_frames': total_frames,
'fps': fps,
'sample_interval': sample_interval
}
def analyze_luminance_stats(luminance_result):
"""
分析亮度统计数据
"""
data = luminance_result'data'
if not data:
print("无数据")
return None
relative_values = d\['relative_avg' for d in data]
stats = {
'mean_relative': np.mean(relative_values),
'max_relative': np.max(relative_values),
'min_relative': np.min(relative_values),
'std_relative': np.std(relative_values),
'total_samples': len(data),
'bright_segments': sum(1 for d in data if d'brightness_level' == 'bright'),
'normal_segments': sum(1 for d in data if d'brightness_level' == 'normal'),
'dark_segments': sum(1 for d in data if d'brightness_level' == 'dark')
}
return stats
def visualize_luminance(luminance_result, output_path='luminance_plot.png'):
"""
可视化亮度变化
"""
import matplotlib.pyplot as plt
data = luminance_result'data'
times = d\['timestamp' for d in data]
relative_values = d\['relative_avg' for d in data]
absolute_values = d\['absolute_avg' for d in data]
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8))
相对亮度图
ax1.plot(times, relative_values, 'b-', linewidth=1.5)
ax1.axhline(y=1.0, color='r', linestyle='--', alpha=0.5, label='参考亮度')
ax1.axhline(y=1.2, color='g', linestyle=':', alpha=0.5, label='亮阈值')
ax1.axhline(y=0.8, color='orange', linestyle=':', alpha=0.5, label='暗阈值')
ax1.set_xlabel('时间 (秒)')
ax1.set_ylabel('相对亮度 (参考帧=1.0)')
ax1.set_title('视频相对亮度变化')
ax1.grid(True, alpha=0.3)
ax1.legend()
绝对亮度图
ax2.plot(times, absolute_values, 'g-', linewidth=1.5)
ax2.set_xlabel('时间 (秒)')
ax2.set_ylabel('绝对亮度 (0-255)')
ax2.set_title('视频绝对亮度变化')
ax2.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig(output_path, dpi=150)
plt.show()
print(f"可视化图表已保存到: {output_path}")
def get_luminance_summary(luminance_result, stats):
"""
生成亮度检测摘要
"""
summary = f"""
========== 视频亮度检测摘要 ==========
总帧数: {luminance_result'total_frames'}
FPS: {luminance_result'fps':.2f}
采样间隔: {luminance_result'sample_interval'} 帧
亮度统计:
-
平均相对亮度: {stats'mean_relative':.3f}
-
最大相对亮度: {stats'max_relative':.3f}
-
最小相对亮度: {stats'min_relative':.3f}
-
标准差: {stats'std_relative':.3f}
亮度分布:
-
亮段 (>1.2): {stats'bright_segments'} 个样本
-
正常段 (0.8-1.2): {stats'normal_segments'} 个样本
-
暗段 (<0.8): {stats'dark_segments'} 个样本
总体评价:
-
平均亮度 {'偏亮' if stats'mean_relative' > 1.1 else '正常' if stats'mean_relative' > 0.9 else '偏暗'}
-
亮度变化 {'较大' if stats'std_relative' > 0.2 else '平稳'}
=====================================
"""
return summary
========== 使用示例 ==========
if name == "main":
示例1: 检测视频文件
video_path = "your_video.mp4" # 替换为你的视频路径
try:
进行亮度检测
result = detect_video_luminance(video_path, sample_interval=15, reference_frame_index=0)
if result:
分析统计数据
stats = analyze_luminance_stats(result)
打印摘要
summary = get_luminance_summary(result, stats)
print(summary)
可视化
visualize_luminance(result)
except FileNotFoundError:
print("视频文件未找到,请检查路径")
except Exception as e:
print(f"处理过程中出错: {e}")
```
使用说明
主要功能
-
calculate_frame_luminance(): 计算单帧的亮度统计(平均值、最大值、最小值、标准差)
-
calculate_relative_brightness(): 计算相对于参考帧的亮度比
-
detect_video_luminance(): 检测整个视频的亮度变化
-
visualize_luminance(): 生成亮度变化曲线图
快速使用
```python
基本使用
result = detect_video_luminance("your_video.mp4")
分析并可视化
stats = analyze_luminance_stats(result)
visualize_luminance(result)
print(get_luminance_summary(result, stats))
```
说明
· sample_interval: 采样间隔(帧),默认30帧采样一次
· reference_frame_index: 参考帧索引,默认使用第0帧
· 相对亮度 > 1.2 判定为偏亮,< 0.8 判定为偏暗