| | import os |
| | import json |
| | import numpy as np |
| | from nuscenes.nuscenes import NuScenes |
| | import multiprocessing as mp |
| | from tqdm import tqdm |
| | import cv2 |
| | from PIL import Image |
| |
|
| | |
| | VERSION = 'v1.0-trainval' |
| | DATA_ROOT = '/share_zhuyixuan05/public_datasets/nuscenes/nuscenes-download/data' |
| | OUTPUT_DIR = '/share_zhuyixuan05/zhuyixuan05/nuscenes_video_generation_dynamic' |
| | NUM_PROCESSES = 30 |
| | PROCESSED_SCENES_FILE = os.path.join(OUTPUT_DIR, 'processed_scenes_dynamic.txt') |
| | CAMERA_CHANNELS = ['CAM_FRONT'] |
| |
|
| | def calculate_relative_pose(pose_current, pose_reference): |
| | """计算相对于参考pose的相对位置和旋转""" |
| | trans_ref = np.array(pose_reference['translation']) |
| | trans_cur = np.array(pose_current['translation']) |
| | |
| | |
| | relative_translation = trans_cur - trans_ref |
| | |
| | relative_pose = { |
| | 'relative_translation': relative_translation.tolist(), |
| | 'current_rotation': pose_current['rotation'], |
| | 'reference_rotation': pose_reference['rotation'], |
| | 'timestamp': pose_current['timestamp'] |
| | } |
| | |
| | return relative_pose |
| |
|
| | def extract_full_scene_with_keyframes(nusc, scene_token, scene_name, output_dir, channel): |
| | """提取完整场景并记录关键帧位置""" |
| | scene_record = nusc.get('scene', scene_token) |
| | current_sample_token = scene_record['first_sample_token'] |
| | |
| | |
| | all_sd_tokens = [] |
| | all_ego_poses = [] |
| | keyframe_indices = [] |
| | frame_index = 0 |
| | |
| | while current_sample_token: |
| | sample_record = nusc.get('sample', current_sample_token) |
| | |
| | if channel in sample_record['data']: |
| | current_sd_token = sample_record['data'][channel] |
| | |
| | |
| | while current_sd_token: |
| | sd_record = nusc.get('sample_data', current_sd_token) |
| | all_sd_tokens.append(current_sd_token) |
| | |
| | |
| | if sd_record['is_key_frame']: |
| | ego_pose_record = nusc.get('ego_pose', sd_record['ego_pose_token']) |
| | all_ego_poses.append(ego_pose_record) |
| | keyframe_indices.append(frame_index) |
| | else: |
| | all_ego_poses.append(None) |
| | |
| | frame_index += 1 |
| | current_sd_token = sd_record['next'] if sd_record['next'] != '' else None |
| | |
| | break |
| | |
| | current_sample_token = sample_record['next'] if sample_record['next'] != '' else None |
| | |
| | |
| | total_frames = len(all_sd_tokens) |
| | num_keyframes = len(keyframe_indices) |
| | |
| | if total_frames < 30 or num_keyframes < 3: |
| | print(f"Scene {scene_name}: Insufficient frames ({total_frames}) or keyframes ({num_keyframes}), skipping...") |
| | return 0 |
| | |
| | |
| | scene_dir = os.path.join(output_dir, 'scenes', f"{scene_name}_{channel}") |
| | os.makedirs(scene_dir, exist_ok=True) |
| | |
| | |
| | video_path = os.path.join(scene_dir, 'full_video.mp4') |
| | success = render_full_video(nusc, all_sd_tokens, video_path) |
| | |
| | if not success: |
| | print(f"Failed to render video for {scene_name}") |
| | return 0 |
| | |
| | |
| | keyframe_poses = [] |
| | valid_keyframes = [] |
| | |
| | for i, frame_idx in enumerate(keyframe_indices): |
| | pose = all_ego_poses[frame_idx] |
| | if pose is not None: |
| | keyframe_poses.append(pose) |
| | valid_keyframes.append(frame_idx) |
| | |
| | |
| | scene_info = { |
| | 'scene_name': scene_name, |
| | 'channel': channel, |
| | 'total_frames': total_frames, |
| | 'keyframe_indices': valid_keyframes, |
| | 'keyframe_poses': keyframe_poses, |
| | 'sample_data_tokens': all_sd_tokens, |
| | 'video_path': 'full_video.mp4' |
| | } |
| | |
| | with open(os.path.join(scene_dir, 'scene_info.json'), 'w') as f: |
| | json.dump(scene_info, f, indent=2) |
| | |
| | print(f"Processed scene {scene_name}: {total_frames} frames, {len(valid_keyframes)} keyframes") |
| | return 1 |
| |
|
| | def render_full_video(nusc, sd_tokens, output_path): |
| | """渲染完整视频序列""" |
| | if not sd_tokens: |
| | return False |
| | |
| | try: |
| | |
| | first_sd = nusc.get('sample_data', sd_tokens[0]) |
| | first_image_path = os.path.join(nusc.dataroot, first_sd['filename']) |
| | first_image = Image.open(first_image_path) |
| | width, height = first_image.size |
| | |
| | |
| | fourcc = cv2.VideoWriter_fourcc(*'mp4v') |
| | out = cv2.VideoWriter(output_path, fourcc, 10.0, (width, height)) |
| | |
| | for sd_token in sd_tokens: |
| | sd_record = nusc.get('sample_data', sd_token) |
| | image_path = os.path.join(nusc.dataroot, sd_record['filename']) |
| | |
| | if os.path.exists(image_path): |
| | image = cv2.imread(image_path) |
| | if image is not None: |
| | out.write(image) |
| | |
| | out.release() |
| | return True |
| | |
| | except Exception as e: |
| | print(f"Error rendering video to {output_path}: {str(e)}") |
| | return False |
| |
|
| | def process_scene_dynamic(args): |
| | """处理单个场景,生成动态长度数据""" |
| | scene_token, channels = args |
| | nusc = NuScenes(version=VERSION, dataroot=DATA_ROOT, verbose=False) |
| | scene_record = nusc.get('scene', scene_token) |
| | scene_name = scene_record['name'] |
| | |
| | success_channels = [] |
| | total_scenes = 0 |
| | |
| | try: |
| | for channel in channels: |
| | |
| | scene_dir = os.path.join(OUTPUT_DIR, 'scenes', f"{scene_name}_{channel}") |
| | if os.path.exists(os.path.join(scene_dir, 'scene_info.json')): |
| | print(f"Scene {scene_name} {channel} already processed, skipping...") |
| | success_channels.append(channel) |
| | continue |
| | |
| | |
| | scenes_count = extract_full_scene_with_keyframes(nusc, scene_token, scene_name, OUTPUT_DIR, channel) |
| | |
| | if scenes_count > 0: |
| | success_channels.append(channel) |
| | total_scenes += scenes_count |
| | else: |
| | print(f"Failed to process scene {scene_name} {channel}") |
| | |
| | except Exception as e: |
| | print(f"Error processing {scene_name} ({scene_token}): {str(e)}") |
| | |
| | return scene_token, success_channels, total_scenes |
| |
|
| | def get_processed_scenes(): |
| | """读取处理记录""" |
| | processed = {} |
| | if os.path.exists(PROCESSED_SCENES_FILE): |
| | with open(PROCESSED_SCENES_FILE, 'r') as f: |
| | for line in f: |
| | line = line.strip() |
| | if not line or ':' not in line: |
| | continue |
| | token, channels_str = line.split(':', 1) |
| | processed[token] = set(channels_str.split(',')) |
| | return processed |
| |
|
| | def main(): |
| | |
| | os.makedirs(OUTPUT_DIR, exist_ok=True) |
| | os.makedirs(os.path.join(OUTPUT_DIR, 'scenes'), exist_ok=True) |
| | |
| | |
| | nusc = NuScenes(version=VERSION, dataroot=DATA_ROOT, verbose=True) |
| | all_scenes = {s['token']: s for s in nusc.scene} |
| | |
| | |
| | processed = get_processed_scenes() |
| | |
| | |
| | tasks = [] |
| | for scene_token in all_scenes: |
| | processed_channels = processed.get(scene_token, set()) |
| | remaining = [ch for ch in CAMERA_CHANNELS if ch not in processed_channels] |
| | if remaining: |
| | tasks.append((scene_token, remaining)) |
| | |
| | print(f"Total scenes: {len(all_scenes)}") |
| | print(f"Pending tasks: {len(tasks)}") |
| | print("Processing full scenes with keyframe tracking...") |
| | |
| | if not tasks: |
| | print("All scenes already processed!") |
| | return |
| | |
| | |
| | total_scenes_created = 0 |
| | with mp.Pool(processes=NUM_PROCESSES) as pool: |
| | results = [] |
| | for res in tqdm(pool.imap_unordered(process_scene_dynamic, tasks), |
| | total=len(tasks), |
| | desc="Processing Scenes"): |
| | results.append(res) |
| | |
| | |
| | updated = get_processed_scenes() |
| | for scene_token, success_chs, scenes_count in results: |
| | if scene_token not in updated: |
| | updated[scene_token] = set() |
| | updated[scene_token].update(success_chs) |
| | total_scenes_created += scenes_count |
| | |
| | |
| | with open(PROCESSED_SCENES_FILE, 'w') as f: |
| | for token, chs in updated.items(): |
| | f.write(f"{token}:{','.join(sorted(chs))}\n") |
| | |
| | print(f"\nProcessing completed!") |
| | print(f"Total scenes created: {total_scenes_created}") |
| | print(f"Output directory: {OUTPUT_DIR}") |
| |
|
| | if __name__ == '__main__': |
| | main() |