You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Python Katna包自定义关键帧命名关联视频帧时间

解决Katna关键帧命名关联视频时间的问题

问题背景

使用Katna提取视频关键帧时,希望自定义文件名,让每个关键帧名称包含对应帧在视频中的精确时间戳。尝试修改Katna源码未成功,单独用OpenCV提取时间戳效率太低,需要高效的集成方案。

可行实现方案

方案一:扩展Katna组件(无需修改核心源码,推荐)

通过扩展FrameExtractor和自定义KeyFrameDiskWriter,让提取过程同时记录帧时间戳,并在保存时生成带时间的文件名。

1. 修改FrameExtractor类,添加时间戳记录

修改Katna的frame_extractor.py中的对应方法,让提取帧时同时保存时间戳:

# 修改__extract_all_frames_from_video__方法
def __extract_all_frames_from_video__(self, videopath):
    cap = cv2.VideoCapture(str(videopath))
    ret, frame = cap.read()
    i = 1
    chunk_no = 0
    
    while ret:
        curr_frame = None
        prev_frame = None
        frame_diffs = []
        frames = []
        timestamps = []  # 新增:存储帧时间戳
        for _ in range(0, self.max_frames_in_chunk):
            if ret:
                # 获取当前帧的时间戳(单位:毫秒)
                timestamp = cap.get(cv2.CAP_PROP_POS_MSEC)
                prev_frame, curr_frame = self.__process_frame(frame, prev_frame, frame_diffs, frames)
                timestamps.append(timestamp)  # 保存时间戳
                i = i + 1
                ret, frame = cap.read()
            else:
                cap.release()
                break
        chunk_no = chunk_no + 1
        yield frames, frame_diffs, timestamps  # 修改返回值,加入时间戳
    cap.release()

# 修改__get_frames_in_local_maxima__方法,返回帧和对应时间戳
def __get_frames_in_local_maxima__(self, frames, frame_diffs, timestamps):
    extracted_key_frames = []
    extracted_timestamps = []
    diff_array = np.array(frame_diffs)
    sm_diff_array = self.__smooth__(diff_array, self.len_window)
    frame_indexes = np.asarray(argrelextrema(sm_diff_array, np.greater))[0]

    for frame_index in frame_indexes:
        extracted_key_frames.append(frames[frame_index - 1])
        extracted_timestamps.append(timestamps[frame_index - 1])  # 对应时间戳
    del frames[:]
    del sm_diff_array
    del diff_array
    del frame_diffs[:]
    del timestamps[:]
    return extracted_key_frames, extracted_timestamps  # 修改返回值

# 修改extract_candidate_frames方法,返回带时间戳的列表
def extract_candidate_frames(self, videopath):
    extracted_candidate_key_frames = []
    extracted_candidate_timestamps = []
    frame_extractor_from_video_generator = self.__extract_all_frames_from_video__(videopath)

    for frames, frame_diffs, timestamps in frame_extractor_from_video_generator:
        if self.USE_LOCAL_MAXIMA:
            frames_chunk, timestamps_chunk = self.__get_frames_in_local_maxima__(frames, frame_diffs, timestamps)
            extracted_candidate_key_frames.extend(frames_chunk)
            extracted_candidate_timestamps.extend(timestamps_chunk)
    return extracted_candidate_key_frames, extracted_candidate_timestamps  # 修改返回值

2. 自定义Writer类,支持时间戳命名

创建自定义的Writer,替代默认的KeyFrameDiskWriter:

from Katna.writer import KeyFrameWriter
import cv2
import os
import datetime

class TimestampKeyFrameWriter(KeyFrameWriter):
    def __init__(self, location):
        super().__init__()
        self.location = location
        os.makedirs(self.location, exist_ok=True)

    def write(self, frames, timestamps):
        for idx, (frame, ts) in enumerate(zip(frames, timestamps)):
            # 将毫秒时间戳转为HH_MM_SS_sss格式(避免文件名含冒号)
            dt = datetime.datetime.fromtimestamp(ts/1000)
            time_str = dt.strftime("%H_%M_%S_%f")[:-3]  # 保留三位毫秒
            filename = f"keyframe_{time_str}.jpg"
            file_path = os.path.join(self.location, filename)
            cv2.imwrite(file_path, frame)

3. 修改调用代码

from Katna.video import Video
import os

if __name__ == "__main__":
    vd = Video()
    no_of_frames_to_returned = 96
    # 使用自定义Writer
    diskwriter = TimestampKeyFrameWriter(location="selectedframes")
    video_file_path = os.path.join("/home/plumpi/Desktop/test_katna", "exp.mp4")

    print(f"Input video file path = {video_file_path}")
    # 需要同步修改Video类的extract_video_keyframes方法:
    # 找到调用frame_extractor.extract_candidate_frames的地方,改为接收帧和时间戳
    # 筛选出最终关键帧后,调用writer.write(selected_frames, selected_timestamps)
    vd.extract_video_keyframes(
         no_of_frames=no_of_frames_to_returned, file_path=video_file_path,
         writer=diskwriter
    )

方案二:直接修改Katna核心Writer(快速实现)

如果愿意修改Katna的KeyFrameDiskWriter,可以在获取关键帧时同步传递时间戳,修改writer.py中的write方法:

# 修改Katna/writer.py的KeyFrameDiskWriter
def write(self, frames, timestamps):  # 添加timestamps参数
    for idx, (frame, ts) in enumerate(zip(frames, timestamps)):
        dt = datetime.datetime.fromtimestamp(ts/1000)
        time_str = dt.strftime("%H_%M_%S_%f")[:-3]
        filename = f"keyframe_{time_str}.jpg"
        file_path = os.path.join(self.location, filename)
        cv2.imwrite(file_path, frame)

同时需要修改Video类中调用Writer的逻辑,传递时间戳参数。

注意事项

  • 时间戳格式可根据需求调整,比如用秒数(保留两位小数)命名,避免特殊字符
  • 修改Katna源码后,确保本地环境引用的是修改后的版本,而非pip安装的原始版本
  • 若不想修改源码,也可以在提取关键帧后,通过帧索引和视频帧率计算时间戳:时间戳 = 帧索引 / 帧率,但效率略低于集成方案

内容的提问来源于stack exchange,提问作者ali noori

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 03:23:09