```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}")

```

 

使用说明

 

主要功能

 

1. calculate_frame_luminance(): 计算单帧的亮度统计(平均值、最大值、最小值、标准差)

2. calculate_relative_brightness(): 计算相对于参考帧的亮度比

3. detect_video_luminance(): 检测整个视频的亮度变化

4. 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 判定为偏暗

 

 

 

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐