#### pip install imagehash #### python noinstance_v2i.py 翠星测试.mp4 翠星图片 #### python noinstance_v2i.py 翠星测试.mp4 翠星图片25_0_1 import os import cv2 import argparse import shutil import imagehash from pathlib import Path from tqdm import tqdm from moviepy.editor import VideoFileClip from collections import deque from PIL import Image from animeinsseg import AnimeInsSeg # 配置参数 CKPT_PATH = "models/AnimeInstanceSegmentation/rtmdetl_e60.ckpt" DOWNSAMPLE_SIZE = (320, 180) # 下采样尺寸提升处理速度 MIN_SCENE_CHANGE = 0.3 # 场景变化阈值 (0-1) HASH_THRESHOLD = 25 # 哈希相似度阈值 FRAME_BUFFER = 10 # 连续帧缓冲区 class VideoProcessor: def __init__(self): self.net = AnimeInsSeg( CKPT_PATH, mask_thr=0.1, refine_kwargs={'refine_method': 'refinenet_isnet'} ) self.hash_dict = {} self.last_saved_hash = None def _preprocess_frame(self, frame): """预处理帧:下采样 + 灰度化""" small_frame = cv2.resize(frame, DOWNSAMPLE_SIZE) return cv2.cvtColor(small_frame, cv2.COLOR_BGR2GRAY) def _has_human(self, frame): """快速人物检测""" instances = self.net.infer( cv2.cvtColor(frame, cv2.COLOR_BGR2RGB), output_type='numpy', pred_score_thr=0.5 # 适当提高置信度阈值加速判断 ) return instances.bboxes is not None def _is_duplicate(self, frame): """基于感知哈希的去重检测""" current_hash = imagehash.dhash(Image.fromarray(frame)) for existing_hash in self.hash_dict.values(): if current_hash - existing_hash < HASH_THRESHOLD: return True return False def process_video(self, video_path, output_dir): """核心处理流程""" clip = VideoFileClip(str(video_path)) output_path = Path(output_dir) output_path.mkdir(parents=True, exist_ok=True) # 初始化场景检测 prev_frame = None frame_buffer = deque(maxlen=FRAME_BUFFER) for i, frame in enumerate(clip.iter_frames()): # 转换为OpenCV格式 cv_frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR) # 动态抽帧策略 processed_frame = self._preprocess_frame(cv_frame) if prev_frame is not None: # 使用结构相似性检测场景变化 similarity = cv2.compareHist( cv2.calcHist([processed_frame], [0], None, [256], [0, 256]), cv2.calcHist([prev_frame], [0], None, [256], [0, 256]), cv2.HISTCMP_CORREL ) if similarity > (1 - MIN_SCENE_CHANGE): continue prev_frame = processed_frame # 缓冲区去重检测 if any(cv2.absdiff(processed_frame, f).sum() < 1000 for f in frame_buffer): continue frame_buffer.append(processed_frame) # 执行人物检测 if not self._has_human(cv_frame): # 哈希去重检查 if not self._is_duplicate(frame): frame_hash = imagehash.dhash(Image.fromarray(frame)) self.hash_dict[i] = frame_hash cv2.imwrite(str(output_path / f"frame_{i:06d}.jpg"), cv_frame) clip.close() def main(): parser = argparse.ArgumentParser(description="提取视频中无人物出现的帧") parser.add_argument("video_path", type=str, help="输入视频路径") parser.add_argument("output_dir", type=str, help="输出目录路径") args = parser.parse_args() processor = VideoProcessor() processor.process_video(args.video_path, args.output_dir) if __name__ == "__main__": main()