File size: 3,935 Bytes
1fec9bd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#### 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()