| | import json |
| | import numpy as np |
| | import subprocess |
| | import os |
| | from collections import defaultdict |
| | import matplotlib.pyplot as plt |
| | import seaborn as sns |
| | from tqdm import tqdm |
| | import scipy.stats |
| |
|
| | jsonl_list = [ |
| | "./metadata_wan_fps24.jsonl" |
| | ] |
| |
|
| | def get_video_dimensions(video_path): |
| | """使用ffmpeg获取视频的宽度和高度""" |
| | try: |
| | |
| | cmd = [ |
| | 'ffprobe', |
| | '-v', 'quiet', |
| | '-print_format', 'json', |
| | '-show_streams', |
| | video_path |
| | ] |
| | |
| | result = subprocess.run(cmd, capture_output=True, text=True, check=True) |
| | video_info = json.loads(result.stdout) |
| | |
| | |
| | for stream in video_info['streams']: |
| | if stream['codec_type'] == 'video': |
| | width = int(stream['width']) |
| | height = int(stream['height']) |
| | return width, height |
| | |
| | except (subprocess.CalledProcessError, json.JSONDecodeError, KeyError) as e: |
| | print(f"获取视频尺寸失败 {video_path}: {e}") |
| | return None, None |
| | |
| | return None, None |
| |
|
| | def read_face_bbox( |
| | bboxs_path, |
| | h, |
| | w, |
| | video_length = None, |
| | start_idx = None, |
| | end_idx = None, |
| | bbox_type = "xywh", |
| | ): |
| | face_mask_start = None |
| | face_mask_end = None |
| | face_center = None |
| | bboxs = None |
| | bbox_infos = None |
| | if bboxs_path is not None: |
| | bboxs = np.load(bboxs_path) |
| | |
| | if start_idx is not None and end_idx is not None: |
| | |
| | video_frames = end_idx - start_idx |
| | |
| | |
| | if len(bboxs) == 1: |
| | |
| | bbox_start_idx = 0 |
| | bbox_end_idx = 0 |
| | else: |
| | |
| | bbox_start_idx = int(start_idx * (len(bboxs) - 1) / (video_length - 1)) if video_length > 1 else 0 |
| | bbox_end_idx = int(end_idx * (len(bboxs) - 1) / (video_length - 1)) if video_length > 1 else 0 |
| | bbox_start_idx = min(bbox_start_idx, len(bboxs) - 1) |
| | bbox_end_idx = min(bbox_end_idx, len(bboxs) - 1) |
| | |
| | |
| | relevant_start_idx = 0 |
| | relevant_end_idx = len(bboxs) - 1 |
| | |
| | relevant_bboxs = bboxs[relevant_start_idx:relevant_end_idx + 1] |
| | |
| | |
| | global_x_min = relevant_bboxs[:, 0].min() |
| | global_y_min = relevant_bboxs[:, 1].min() |
| | if bbox_type == "xywh": |
| | global_x_max = (relevant_bboxs[:, 2] + relevant_bboxs[:, 0]).max() |
| | global_y_max = (relevant_bboxs[:, 3] + relevant_bboxs[:, 1]).max() |
| | elif bbox_type == "xxyy": |
| | global_x_max = relevant_bboxs[:, 2].max() |
| | global_y_max = relevant_bboxs[:, 3].max() |
| | |
| | |
| | global_width = global_x_max - global_x_min |
| | global_height = global_y_max - global_y_min |
| | global_center_x = (global_x_min + global_x_max) / 2 |
| | global_center_y = (global_y_min + global_y_max) / 2 |
| | |
| | |
| | global_x_min = max(0, global_center_x - global_width / 2) |
| | global_x_max = min(w, global_center_x + global_width / 2) |
| | global_y_min = max(0, global_center_y - global_height / 2) |
| | global_y_max = min(h, global_center_y + global_height / 2) |
| | |
| | |
| | global_face_center = [(global_x_min + global_x_max)/2, (global_y_min + global_y_max)/2] |
| | global_bbox_info = { |
| | 'center': [global_face_center[0] / w, global_face_center[1] / h], |
| | 'width': (global_x_max - global_x_min) / w, |
| | 'height': (global_y_max - global_y_min) / h, |
| | 'bbox': [global_x_min/w, global_y_min/h, global_x_max/w, global_y_max/h] |
| | } |
| | |
| | return bboxs, bbox_infos |
| |
|
| | def plot_probability_density_distributions(all_widths, all_heights, all_areas, all_relative_widths, all_relative_heights, all_relative_areas): |
| | """Plot probability density distributions""" |
| | |
| | |
| | fig, axes = plt.subplots(2, 3, figsize=(18, 12)) |
| | fig.suptitle('BBox Probability Density Distribution Analysis', fontsize=16, fontweight='bold') |
| | |
| | |
| | |
| | axes[0, 0].hist(all_widths, bins=50, density=True, alpha=0.7, color='skyblue', edgecolor='black') |
| | kde_x = np.linspace(min(all_widths), max(all_widths), 1000) |
| | kde = scipy.stats.gaussian_kde(all_widths) |
| | axes[0, 0].plot(kde_x, kde(kde_x), 'r-', linewidth=2, label='KDE') |
| | axes[0, 0].set_title('Absolute Width Distribution') |
| | axes[0, 0].set_xlabel('Width (pixels)') |
| | axes[0, 0].set_ylabel('Probability Density') |
| | axes[0, 0].legend() |
| | axes[0, 0].grid(True, alpha=0.3) |
| | |
| | |
| | axes[0, 1].hist(all_heights, bins=50, density=True, alpha=0.7, color='lightgreen', edgecolor='black') |
| | kde_x = np.linspace(min(all_heights), max(all_heights), 1000) |
| | kde = scipy.stats.gaussian_kde(all_heights) |
| | axes[0, 1].plot(kde_x, kde(kde_x), 'r-', linewidth=2, label='KDE') |
| | axes[0, 1].set_title('Absolute Height Distribution') |
| | axes[0, 1].set_xlabel('Height (pixels)') |
| | axes[0, 1].set_ylabel('Probability Density') |
| | axes[0, 1].legend() |
| | axes[0, 1].grid(True, alpha=0.3) |
| | |
| | |
| | axes[0, 2].hist(all_areas, bins=50, density=True, alpha=0.7, color='orange', edgecolor='black') |
| | kde_x = np.linspace(min(all_areas), max(all_areas), 1000) |
| | kde = scipy.stats.gaussian_kde(all_areas) |
| | axes[0, 2].plot(kde_x, kde(kde_x), 'r-', linewidth=2, label='KDE') |
| | axes[0, 2].set_title('Absolute Area Distribution') |
| | axes[0, 2].set_xlabel('Area (pixels²)') |
| | axes[0, 2].set_ylabel('Probability Density') |
| | axes[0, 2].legend() |
| | axes[0, 2].grid(True, alpha=0.3) |
| | |
| | |
| | |
| | axes[1, 0].hist(all_relative_widths, bins=50, density=True, alpha=0.7, color='lightcoral', edgecolor='black') |
| | kde_x = np.linspace(min(all_relative_widths), max(all_relative_widths), 1000) |
| | kde = scipy.stats.gaussian_kde(all_relative_widths) |
| | axes[1, 0].plot(kde_x, kde(kde_x), 'r-', linewidth=2, label='KDE') |
| | axes[1, 0].set_title('Relative Width Distribution') |
| | axes[1, 0].set_xlabel('Relative Width (ratio)') |
| | axes[1, 0].set_ylabel('Probability Density') |
| | axes[1, 0].legend() |
| | axes[1, 0].grid(True, alpha=0.3) |
| | |
| | |
| | axes[1, 1].hist(all_relative_heights, bins=50, density=True, alpha=0.7, color='plum', edgecolor='black') |
| | kde_x = np.linspace(min(all_relative_heights), max(all_relative_heights), 1000) |
| | kde = scipy.stats.gaussian_kde(all_relative_heights) |
| | axes[1, 1].plot(kde_x, kde(kde_x), 'r-', linewidth=2, label='KDE') |
| | axes[1, 1].set_title('Relative Height Distribution') |
| | axes[1, 1].set_xlabel('Relative Height (ratio)') |
| | axes[1, 1].set_ylabel('Probability Density') |
| | axes[1, 1].legend() |
| | axes[1, 1].grid(True, alpha=0.3) |
| | |
| | |
| | axes[1, 2].hist(all_relative_areas, bins=50, density=True, alpha=0.7, color='gold', edgecolor='black') |
| | kde_x = np.linspace(min(all_relative_areas), max(all_relative_areas), 1000) |
| | kde = scipy.stats.gaussian_kde(all_relative_areas) |
| | axes[1, 2].plot(kde_x, kde(kde_x), 'r-', linewidth=2, label='KDE') |
| | axes[1, 2].set_title('Relative Area Distribution') |
| | axes[1, 2].set_xlabel('Relative Area (ratio)') |
| | axes[1, 2].set_ylabel('Probability Density') |
| | axes[1, 2].legend() |
| | axes[1, 2].grid(True, alpha=0.3) |
| | |
| | plt.tight_layout() |
| | plt.savefig('bbox_probability_density_distributions.png', dpi=300, bbox_inches='tight') |
| | plt.show() |
| |
|
| | def analyze_bbox_distribution(): |
| | """分析所有jsonl文件中bbox的分布情况""" |
| | all_widths = [] |
| | all_heights = [] |
| | all_areas = [] |
| | all_relative_widths = [] |
| | all_relative_heights = [] |
| | all_relative_areas = [] |
| | |
| | total_processed = 0 |
| | total_errors = 0 |
| | |
| | for jsonl_path in tqdm(jsonl_list, desc="处理数据集文件"): |
| | if not os.path.exists(jsonl_path): |
| | print(f"文件不存在: {jsonl_path}") |
| | continue |
| | |
| | |
| | with open(jsonl_path, 'r') as f: |
| | total_lines = sum(1 for _ in f) |
| | |
| | with open(jsonl_path, 'r') as f: |
| | for line_num, line in tqdm(enumerate(f, 1), total=total_lines, desc="处理行", leave=False): |
| | try: |
| | data = json.loads(line.strip()) |
| | |
| | |
| | video_path = data.get('video') |
| | bboxs_path = data.get('bboxs') |
| | width = data.get('width') |
| | height = data.get('height') |
| | |
| | if not all([video_path, bboxs_path]): |
| | continue |
| | |
| | |
| | if width is None or height is None: |
| | full_video_path = os.path.join(os.path.dirname(jsonl_path), video_path) |
| | width, height = get_video_dimensions(full_video_path) |
| | if width is None or height is None: |
| | print(f"无法获取视频尺寸: {full_video_path}") |
| | total_errors += 1 |
| | continue |
| | |
| | |
| | full_bbox_path = os.path.join(os.path.dirname(jsonl_path), bboxs_path) |
| | if not os.path.exists(full_bbox_path): |
| | print(f"bbox文件不存在: {full_bbox_path}") |
| | total_errors += 1 |
| | continue |
| | |
| | bboxs = np.load(full_bbox_path) |
| | |
| | |
| | for bbox in bboxs: |
| | if len(bbox) >= 4: |
| | x, y, w_bbox, h_bbox = bbox[:4] |
| | |
| | |
| | abs_width = w_bbox |
| | abs_height = h_bbox |
| | abs_area = abs_width * abs_height |
| | |
| | |
| | rel_width = abs_width / width |
| | rel_height = abs_height / height |
| | rel_area = rel_width * rel_height |
| | |
| | |
| | all_widths.append(abs_width) |
| | all_heights.append(abs_height) |
| | all_areas.append(abs_area) |
| | all_relative_widths.append(rel_width) |
| | all_relative_heights.append(rel_height) |
| | all_relative_areas.append(rel_area) |
| | |
| | total_processed += 1 |
| | except json.JSONDecodeError as e: |
| | print(f"JSON解析错误 {jsonl_path}:{line_num}: {e}") |
| | total_errors += 1 |
| | except Exception as e: |
| | print(f"处理错误 {jsonl_path}:{line_num}: {e}") |
| | total_errors += 1 |
| | |
| | |
| | print(f"\n=== 总体统计 ===") |
| | print(f"总处理样本数: {total_processed}") |
| | print(f"总错误数: {total_errors}") |
| | print(f"总bbox数: {len(all_widths)}") |
| | |
| | if all_widths: |
| | print(f"\n=== 绝对尺寸统计(像素) ===") |
| | print(f"宽度 - 均值: {np.mean(all_widths):.2f}, 中位数: {np.median(all_widths):.2f}, 标准差: {np.std(all_widths):.2f}") |
| | print(f"高度 - 均值: {np.mean(all_heights):.2f}, 中位数: {np.median(all_heights):.2f}, 标准差: {np.std(all_heights):.2f}") |
| | print(f"面积 - 均值: {np.mean(all_areas):.2f}, 中位数: {np.median(all_areas):.2f}, 标准差: {np.std(all_areas):.2f}") |
| | |
| | print(f"\n=== 相对尺寸统计(占图像比例) ===") |
| | print(f"相对宽度 - 均值: {np.mean(all_relative_widths):.4f}, 中位数: {np.median(all_relative_widths):.4f}, 标准差: {np.std(all_relative_widths):.4f}") |
| | print(f"相对高度 - 均值: {np.mean(all_relative_heights):.4f}, 中位数: {np.median(all_relative_heights):.4f}, 标准差: {np.std(all_relative_heights):.4f}") |
| | print(f"相对面积 - 均值: {np.mean(all_relative_areas):.6f}, 中位数: {np.median(all_relative_areas):.6f}, 标准差: {np.std(all_relative_areas):.6f}") |
| | |
| | |
| | print(f"\n=== 绘制概率密度分布图 ===") |
| | if all_widths: |
| | plot_probability_density_distributions(all_widths, all_heights, all_areas, all_relative_widths, all_relative_heights, all_relative_areas) |
| | |
| | |
| | results = { |
| | 'total_samples': total_processed, |
| | 'total_errors': total_errors, |
| | 'total_bboxes': len(all_widths), |
| | 'absolute_stats': { |
| | 'widths': {'mean': float(np.mean(all_widths)), 'median': float(np.median(all_widths)), 'std': float(np.std(all_widths))}, |
| | 'heights': {'mean': float(np.mean(all_heights)), 'median': float(np.median(all_heights)), 'std': float(np.std(all_heights))}, |
| | 'areas': {'mean': float(np.mean(all_areas)), 'median': float(np.median(all_areas)), 'std': float(np.std(all_areas))} |
| | }, |
| | 'relative_stats': { |
| | 'widths': {'mean': float(np.mean(all_relative_widths)), 'median': float(np.median(all_relative_widths)), 'std': float(np.std(all_relative_widths))}, |
| | 'heights': {'mean': float(np.mean(all_relative_heights)), 'median': float(np.median(all_relative_heights)), 'std': float(np.std(all_relative_heights))}, |
| | 'areas': {'mean': float(np.mean(all_relative_areas)), 'median': float(np.median(all_relative_areas)), 'std': float(np.std(all_relative_areas))} |
| | } |
| | } |
| | |
| | print(f"\n保存统计结果...") |
| | with open('bbox_distribution_stats.json', 'w', encoding='utf-8') as f: |
| | json.dump(results, f, indent=2, ensure_ascii=False) |
| | |
| | print(f"统计结果已保存到: bbox_distribution_stats.json") |
| | print(f"概率密度分布图已保存到: bbox_probability_density_distributions.png") |
| |
|
| | if __name__ == "__main__": |
| | |
| | analyze_bbox_distribution() |