时序动作定位任务thumos14数据集标注文件处理

166 阅读5分钟
  • 时序动作定位任务取 thumos 14 官方数据集的验证集当训练集,测试集当验证集
  • 各有21个标注文件,Ambiguous_val.txt 文件记录了难以判断是否为动作的时间段,这些片段不参与评估。
oqbab4el.pngnc2rwwwo.png

根据标签文件把时序动作任务用到的视频移到同一个文件夹里(两个,一个val,一个test)

import shutil
from pathlib import Path

# 标注文件夹路径
annotations_dir = Path('/hy-tmp/mmaction2-main/data/thumos14/annotations_val')
# 所有视频所在目录
video_dir = Path('/hy-tmp/123/validation')  # 请根据实际情况修改
# 目标目录
target_dir = Path('/hy-tmp/val_videos')
target_dir.mkdir(exist_ok=True)

# 1. 解析所有标注文件,收集用到的视频名(去重)
video_names = set()
for txt in annotations_dir.glob('*.txt'):
    with open(txt, 'r') as f:
        for line in f:
            if line.strip():
                video_names.add(line.strip().split()[0])

# 2. 批量移动视频文件到目标目录,并统计
moved_count = 0
not_found_count = 0

for v in sorted(video_names):
    src = video_dir / f'{v}.mp4'
    dst = target_dir / f'{v}.mp4'
    if src.exists():
        shutil.move(str(src), str(dst))  # 如需复制请改为 shutil.copy
        print(f'已移动: {src} -> {dst}')
        moved_count += 1
    else:
        print(f'未找到视频文件: {src}')
        not_found_count += 1

print(f'\n共移动视频数: {moved_count}')
print(f'共未找到视频数: {not_found_count}')

将thumos14的标注文件处理成时序动作定位可使用的标注格式

import json
import os
from pathlib import Path
import cv2 # opencv-python 库

def get_video_duration_and_fps(video_path):
    """
    使用 OpenCV 获取视频时长和FPS。
    你需要根据实际视频文件路径来调用此函数。
    这是一个示例,实际使用时可能需要更健壮的错误处理。
    """
    try:
        cap = cv2.VideoCapture(str(video_path))
        if not cap.isOpened():
            print(f"错误:无法打开视频 {video_path}")
            return None, None
        
        fps = cap.get(cv2.CAP_PROP_FPS)
        frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
        
        if fps > 0:
            duration_second = frame_count / fps
        else:
            print(f"错误:视频 {video_path} 的FPS为 {fps}。无法计算时长。")
            cap.release()
            return None, None
            
        cap.release()
        return duration_second, fps
    except Exception as e:
        print(f"使用OpenCV处理视频 {video_path} 时出错: {e}")
        if 'cap' in locals() and cap.isOpened():
            cap.release()
        return None, None

def convert_thumos_to_hacs(thumos_ann_dir, output_json_path, thumos_video_dir=None):
    """
    将 THUMOS14 格式的标注文件转换为 HACS JSON 格式。

    Args:
        thumos_ann_dir (str): THUMOS14 标注文件所在目录 (e.g., '.../annotations_val/').
        output_json_path (str): 输出的 HACS 格式 JSON 文件路径。
        thumos_video_dir (str, optional): THUMOS14 视频文件所在目录。
                                         如果提供,会尝试读取视频真实时长和FPS。
    """
    hacs_data = {}
    thumos_ann_path = Path(thumos_ann_dir)

    if not thumos_ann_path.is_dir():
        print(f"错误:找不到标注目录 '{thumos_ann_dir}'。")
        return

    for ann_file in thumos_ann_path.glob('*.txt'):
        action_label = ann_file.stem.replace('_val', '').replace('_test', '') # 从文件名提取类别
        print(f"正在处理类别: {action_label},来自文件: {ann_file.name}")

        with open(ann_file, 'r') as f:
            for line in f:
                parts = line.strip().split()
                if len(parts) != 3:
                    print(f"警告:跳过 {ann_file.name} 中的格式错误行: {line.strip()}")
                    continue

                video_name = parts[0]
                try:
                    start_time = float(parts[1])
                    end_time = float(parts[2])
                except ValueError:
                    print(f"警告:跳过 {ann_file.name} 中时间无效的行: {line.strip()}")
                    continue

                if video_name not in hacs_data:
                    actual_duration_s = None
                    current_video_fps = None # 初始化为 None

                    if thumos_video_dir:
                        potential_video_path = Path(thumos_video_dir) / f"{video_name}.mp4" # 假设文件扩展名为 .mp4
                        if potential_video_path.exists():
                            res_duration, res_fps = get_video_duration_and_fps(potential_video_path)
                            if res_duration is not None and res_fps is not None and res_fps > 0:
                                actual_duration_s = res_duration
                                current_video_fps = res_fps # 如果有效,则使用实际的FPS
                            else:
                                print(f"警告:无法从视频文件 {potential_video_path} 获取 {video_name} 的有效元数据(时长或FPS)。帧数相关字段将为0。")
                        else:
                            print(f"警告:在 {potential_video_path} 未找到 {video_name} 的视频文件。无法确定FPS,帧数相关字段将为0。")
                    else:
                        print(f"警告:未提供视频目录,无法获取 {video_name} 的FPS。帧数相关字段将为0。")
                    
                    hacs_data[video_name] = {
                        "duration_second": actual_duration_s if actual_duration_s is not None else 0.0,
                        "duration_frame": 0, # 稍后计算或保持为0
                        "feature_frame": 0,  # 稍后计算或保持为0
                        "_fps_temp": current_video_fps, # 临时存储FPS, 可能为 None
                        "annotations": []
                    }
                
                # 添加标注
                annotation_entry = {
                    "label": action_label,
                    "segment": [start_time, end_time]
                }
                hacs_data[video_name]["annotations"].append(annotation_entry)

                # 如果未读取到实际时长或时长无效,则更新估算视频时长
                # 当 actual_duration_s 为 None 时,hacs_data[video_name]["duration_second"] 会以 0.0 开始,此时会发生这种情况
                if hacs_data[video_name]["duration_second"] == 0.0:
                    hacs_data[video_name]["duration_second"] = max(
                        hacs_data[video_name].get("duration_second", 0.0), # 确保键存在,以防万一丢失
                        end_time
                    )

    # 第二遍:计算 duration_frame、feature_frame 并移除临时fps
    for video_name in hacs_data:
        video_info = hacs_data[video_name]
        temp_fps = video_info.get("_fps_temp") # 可能为 None

        if video_info["duration_second"] > 0 and temp_fps is not None and temp_fps > 0:
            video_info["duration_frame"] = int(video_info["duration_second"] * temp_fps)
        else:
            video_info["duration_frame"] = 0 # 默认情况或错误情况
            if temp_fps is None or temp_fps <= 0:
                 print(f"错误:视频 {video_name} 的FPS未知或无效 (读取到的FPS: {temp_fps})。duration_frame 和 feature_frame 将设置为0。")

        video_info["feature_frame"] = video_info["duration_frame"] # 根据 HACS 结构

        if "_fps_temp" in video_info:
            del video_info["_fps_temp"] # 移除临时键

    # 保存为 JSON
    with open(output_json_path, 'w') as f:
        json.dump(hacs_data, f, indent=4)
    print(f"转换完成。输出已保存到 {output_json_path}")


if __name__ == '__main__':
    # --- 配置参数 ---
    # THUMOS14 验证集标注文件目录
    thumos_annotations_dir = r'/hy-tmp/mmaction2-main/data/thumos14/annotations_test' # 原始字符串适用于Windows路径,但Path对象也能处理
    # THUMOS14 视频文件目录 (可选, 用于获取精确时长和FPS)
    thumos_videos_base_dir = r'/hy-tmp/test_videos' # 已修改:指向实际的示例视频文件夹
    # 输出的 HACS 格式 JSON 文件
    output_hacs_json = r'/hy-tmp/annotations_test.json' # 输出路径
    # 确保输出目录存在
    Path(output_hacs_json).parent.mkdir(parents=True, exist_ok=True)

    # --- 执行转换 ---
    convert_thumos_to_hacs(
        thumos_annotations_dir,
        output_hacs_json,
        thumos_video_dir=thumos_videos_base_dir # 已修改:传递视频目录
    )