Spaces:
Runtime error
Runtime error
| #### 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() | |