Spaces:
Running
Running
Upload 2 files
Browse files- noinstance_copy_script.py +63 -0
- noinstance_v2i.py +110 -0
noinstance_copy_script.py
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'''
|
2 |
+
|
3 |
+
'''
|
4 |
+
|
5 |
+
import os
|
6 |
+
import cv2
|
7 |
+
import argparse
|
8 |
+
import shutil
|
9 |
+
from pathlib import Path
|
10 |
+
from tqdm import tqdm
|
11 |
+
|
12 |
+
from animeinsseg import AnimeInsSeg
|
13 |
+
|
14 |
+
# 设置模型路径
|
15 |
+
ckpt = r'models/AnimeInstanceSegmentation/rtmdetl_e60.ckpt'
|
16 |
+
mask_thres = 0.3
|
17 |
+
instance_thres = 0.3
|
18 |
+
refine_kwargs = {'refine_method': 'refinenet_isnet'} # 如果不使用 refinenet,设置为 None
|
19 |
+
# refine_kwargs = None
|
20 |
+
|
21 |
+
# 初始化模型
|
22 |
+
net = AnimeInsSeg(ckpt, mask_thr=mask_thres, refine_kwargs=refine_kwargs)
|
23 |
+
|
24 |
+
def has_instances(image_path):
|
25 |
+
# 读取图像
|
26 |
+
img = cv2.imread(image_path)
|
27 |
+
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
|
28 |
+
|
29 |
+
# 推理
|
30 |
+
instances = net.infer(
|
31 |
+
img,
|
32 |
+
output_type='numpy',
|
33 |
+
pred_score_thr=instance_thres
|
34 |
+
)
|
35 |
+
|
36 |
+
# 如果没有检测到对象,返回 False
|
37 |
+
if instances.bboxes is None:
|
38 |
+
return False
|
39 |
+
return True
|
40 |
+
|
41 |
+
def copy_images_without_instances(input_path, output_dir):
|
42 |
+
input_path = Path(input_path)
|
43 |
+
output_dir = Path(output_dir)
|
44 |
+
|
45 |
+
if not output_dir.exists():
|
46 |
+
output_dir.mkdir(parents=True)
|
47 |
+
|
48 |
+
image_paths = list(input_path.rglob("*.png")) + list(input_path.rglob("*.jpg"))
|
49 |
+
for image_path in tqdm(image_paths, desc="Processing images"):
|
50 |
+
if not has_instances(image_path):
|
51 |
+
# 拷贝不包含实例的图片到目标文件夹
|
52 |
+
shutil.copy(image_path, output_dir / image_path.name)
|
53 |
+
|
54 |
+
def main():
|
55 |
+
parser = argparse.ArgumentParser(description="Copy images without instances to a target directory")
|
56 |
+
parser.add_argument("input_path", type=str, help="Path to the input image or folder")
|
57 |
+
parser.add_argument("output_dir", type=str, help="Path to the output directory")
|
58 |
+
args = parser.parse_args()
|
59 |
+
|
60 |
+
copy_images_without_instances(args.input_path, args.output_dir)
|
61 |
+
|
62 |
+
if __name__ == "__main__":
|
63 |
+
main()
|
noinstance_v2i.py
ADDED
@@ -0,0 +1,110 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#### pip install imagehash
|
2 |
+
#### python noinstance_v2i.py 翠星测试.mp4 翠星图片
|
3 |
+
#### python noinstance_v2i.py 翠星测试.mp4 翠星图片25_0_1
|
4 |
+
|
5 |
+
import os
|
6 |
+
import cv2
|
7 |
+
import argparse
|
8 |
+
import shutil
|
9 |
+
import imagehash
|
10 |
+
from pathlib import Path
|
11 |
+
from tqdm import tqdm
|
12 |
+
from moviepy.editor import VideoFileClip
|
13 |
+
from collections import deque
|
14 |
+
from PIL import Image
|
15 |
+
|
16 |
+
from animeinsseg import AnimeInsSeg
|
17 |
+
|
18 |
+
# 配置参数
|
19 |
+
CKPT_PATH = "models/AnimeInstanceSegmentation/rtmdetl_e60.ckpt"
|
20 |
+
DOWNSAMPLE_SIZE = (320, 180) # 下采样尺寸提升处理速度
|
21 |
+
MIN_SCENE_CHANGE = 0.3 # 场景变化阈值 (0-1)
|
22 |
+
HASH_THRESHOLD = 25 # 哈希相似度阈值
|
23 |
+
FRAME_BUFFER = 10 # 连续帧缓冲区
|
24 |
+
|
25 |
+
class VideoProcessor:
|
26 |
+
def __init__(self):
|
27 |
+
self.net = AnimeInsSeg(
|
28 |
+
CKPT_PATH,
|
29 |
+
mask_thr=0.1,
|
30 |
+
refine_kwargs={'refine_method': 'refinenet_isnet'}
|
31 |
+
)
|
32 |
+
self.hash_dict = {}
|
33 |
+
self.last_saved_hash = None
|
34 |
+
|
35 |
+
def _preprocess_frame(self, frame):
|
36 |
+
"""预处理帧:下采样 + 灰度化"""
|
37 |
+
small_frame = cv2.resize(frame, DOWNSAMPLE_SIZE)
|
38 |
+
return cv2.cvtColor(small_frame, cv2.COLOR_BGR2GRAY)
|
39 |
+
|
40 |
+
def _has_human(self, frame):
|
41 |
+
"""快速人物检测"""
|
42 |
+
instances = self.net.infer(
|
43 |
+
cv2.cvtColor(frame, cv2.COLOR_BGR2RGB),
|
44 |
+
output_type='numpy',
|
45 |
+
pred_score_thr=0.5 # 适当提高置信度阈值加速判断
|
46 |
+
)
|
47 |
+
return instances.bboxes is not None
|
48 |
+
|
49 |
+
def _is_duplicate(self, frame):
|
50 |
+
"""基于感知哈希的去重检测"""
|
51 |
+
current_hash = imagehash.dhash(Image.fromarray(frame))
|
52 |
+
for existing_hash in self.hash_dict.values():
|
53 |
+
if current_hash - existing_hash < HASH_THRESHOLD:
|
54 |
+
return True
|
55 |
+
return False
|
56 |
+
|
57 |
+
def process_video(self, video_path, output_dir):
|
58 |
+
"""核心处理流程"""
|
59 |
+
clip = VideoFileClip(str(video_path))
|
60 |
+
output_path = Path(output_dir)
|
61 |
+
output_path.mkdir(parents=True, exist_ok=True)
|
62 |
+
|
63 |
+
# 初始化场景检测
|
64 |
+
prev_frame = None
|
65 |
+
frame_buffer = deque(maxlen=FRAME_BUFFER)
|
66 |
+
|
67 |
+
for i, frame in enumerate(clip.iter_frames()):
|
68 |
+
# 转换为OpenCV格式
|
69 |
+
cv_frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
|
70 |
+
|
71 |
+
# 动态抽帧策略
|
72 |
+
processed_frame = self._preprocess_frame(cv_frame)
|
73 |
+
if prev_frame is not None:
|
74 |
+
# 使用结构相似性检测场景变化
|
75 |
+
similarity = cv2.compareHist(
|
76 |
+
cv2.calcHist([processed_frame], [0], None, [256], [0, 256]),
|
77 |
+
cv2.calcHist([prev_frame], [0], None, [256], [0, 256]),
|
78 |
+
cv2.HISTCMP_CORREL
|
79 |
+
)
|
80 |
+
if similarity > (1 - MIN_SCENE_CHANGE):
|
81 |
+
continue
|
82 |
+
|
83 |
+
prev_frame = processed_frame
|
84 |
+
|
85 |
+
# 缓冲区去重检测
|
86 |
+
if any(cv2.absdiff(processed_frame, f).sum() < 1000 for f in frame_buffer):
|
87 |
+
continue
|
88 |
+
frame_buffer.append(processed_frame)
|
89 |
+
|
90 |
+
# 执行人物检测
|
91 |
+
if not self._has_human(cv_frame):
|
92 |
+
# 哈希去重检查
|
93 |
+
if not self._is_duplicate(frame):
|
94 |
+
frame_hash = imagehash.dhash(Image.fromarray(frame))
|
95 |
+
self.hash_dict[i] = frame_hash
|
96 |
+
cv2.imwrite(str(output_path / f"frame_{i:06d}.jpg"), cv_frame)
|
97 |
+
|
98 |
+
clip.close()
|
99 |
+
|
100 |
+
def main():
|
101 |
+
parser = argparse.ArgumentParser(description="提取视频中无人物出现的帧")
|
102 |
+
parser.add_argument("video_path", type=str, help="输入视频路径")
|
103 |
+
parser.add_argument("output_dir", type=str, help="输出目录路径")
|
104 |
+
args = parser.parse_args()
|
105 |
+
|
106 |
+
processor = VideoProcessor()
|
107 |
+
processor.process_video(args.video_path, args.output_dir)
|
108 |
+
|
109 |
+
if __name__ == "__main__":
|
110 |
+
main()
|