|
|
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() |