UI拡充
This commit is contained in:
@@ -2,13 +2,16 @@
|
||||
|
||||
from . import generate_mask
|
||||
from . import apply_blur
|
||||
from . import clear_cache
|
||||
|
||||
|
||||
def register():
|
||||
generate_mask.register()
|
||||
apply_blur.register()
|
||||
clear_cache.register()
|
||||
|
||||
|
||||
def unregister():
|
||||
clear_cache.unregister()
|
||||
apply_blur.unregister()
|
||||
generate_mask.unregister()
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
"""
|
||||
Clear Cache Operator.
|
||||
|
||||
Provides operators to clear mask cache directories.
|
||||
"""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import bpy
|
||||
from bpy.types import Operator
|
||||
from bpy.props import BoolProperty
|
||||
|
||||
|
||||
class SEQUENCER_OT_clear_mask_cache(Operator):
|
||||
"""Clear mask cache directories."""
|
||||
|
||||
bl_idname = "sequencer.clear_mask_cache"
|
||||
bl_label = "Clear Mask Cache"
|
||||
bl_description = "Delete cached mask images"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
all_strips: BoolProperty(
|
||||
name="All Strips",
|
||||
description="Clear cache for all strips (otherwise only current strip)",
|
||||
default=False,
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
import tempfile
|
||||
|
||||
blend_file = bpy.data.filepath
|
||||
total_size = 0
|
||||
cleared_count = 0
|
||||
|
||||
if self.all_strips:
|
||||
# Clear all cache directories
|
||||
if blend_file:
|
||||
# Project cache
|
||||
project_dir = os.path.dirname(blend_file)
|
||||
cache_root = os.path.join(project_dir, ".mask_cache")
|
||||
else:
|
||||
# Temp cache
|
||||
cache_root = os.path.join(tempfile.gettempdir(), "blender_mask_cache")
|
||||
|
||||
if os.path.exists(cache_root):
|
||||
# Calculate size before deletion
|
||||
for root, dirs, files in os.walk(cache_root):
|
||||
for file in files:
|
||||
file_path = os.path.join(root, file)
|
||||
try:
|
||||
total_size += os.path.getsize(file_path)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
# Delete cache directory
|
||||
try:
|
||||
shutil.rmtree(cache_root)
|
||||
cleared_count = len(os.listdir(cache_root)) if os.path.exists(cache_root) else 0
|
||||
self.report({'INFO'}, f"Cleared all cache ({self._format_size(total_size)})")
|
||||
except Exception as e:
|
||||
self.report({'ERROR'}, f"Failed to clear cache: {e}")
|
||||
return {'CANCELLED'}
|
||||
else:
|
||||
self.report({'INFO'}, "No cache to clear")
|
||||
return {'FINISHED'}
|
||||
|
||||
else:
|
||||
# Clear cache for active strip only
|
||||
seq_editor = context.scene.sequence_editor
|
||||
if not seq_editor or not seq_editor.active_strip:
|
||||
self.report({'WARNING'}, "No strip selected")
|
||||
return {'CANCELLED'}
|
||||
|
||||
strip = seq_editor.active_strip
|
||||
if blend_file:
|
||||
project_dir = os.path.dirname(blend_file)
|
||||
cache_dir = os.path.join(project_dir, ".mask_cache", strip.name)
|
||||
else:
|
||||
cache_dir = os.path.join(tempfile.gettempdir(), "blender_mask_cache", strip.name)
|
||||
|
||||
if os.path.exists(cache_dir):
|
||||
# Calculate size
|
||||
for root, dirs, files in os.walk(cache_dir):
|
||||
for file in files:
|
||||
file_path = os.path.join(root, file)
|
||||
try:
|
||||
total_size += os.path.getsize(file_path)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
# Delete
|
||||
try:
|
||||
shutil.rmtree(cache_dir)
|
||||
self.report({'INFO'}, f"Cleared cache for {strip.name} ({self._format_size(total_size)})")
|
||||
except Exception as e:
|
||||
self.report({'ERROR'}, f"Failed to clear cache: {e}")
|
||||
return {'CANCELLED'}
|
||||
else:
|
||||
self.report({'INFO'}, f"No cache for {strip.name}")
|
||||
return {'FINISHED'}
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def _format_size(self, size_bytes):
|
||||
"""Format bytes to human-readable size."""
|
||||
for unit in ['B', 'KB', 'MB', 'GB']:
|
||||
if size_bytes < 1024.0:
|
||||
return f"{size_bytes:.1f} {unit}"
|
||||
size_bytes /= 1024.0
|
||||
return f"{size_bytes:.1f} TB"
|
||||
|
||||
|
||||
# Registration
|
||||
classes = [
|
||||
SEQUENCER_OT_clear_mask_cache,
|
||||
]
|
||||
|
||||
|
||||
def register():
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
|
||||
|
||||
def unregister():
|
||||
for cls in reversed(classes):
|
||||
bpy.utils.unregister_class(cls)
|
||||
+10
-30
@@ -7,7 +7,7 @@ from video strips in the Video Sequence Editor.
|
||||
|
||||
import os
|
||||
import bpy
|
||||
from bpy.props import FloatProperty, IntProperty
|
||||
from bpy.props import IntProperty
|
||||
from bpy.types import Operator
|
||||
|
||||
from ..core.async_generator import get_generator
|
||||
@@ -15,37 +15,12 @@ from ..core.async_generator import get_generator
|
||||
|
||||
class SEQUENCER_OT_generate_face_mask(Operator):
|
||||
"""Generate face mask image sequence from video strip."""
|
||||
|
||||
|
||||
bl_idname = "sequencer.generate_face_mask"
|
||||
bl_label = "Generate Face Mask"
|
||||
bl_description = "Detect faces and generate mask image sequence"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
# YOLO Detection parameters
|
||||
conf_threshold: FloatProperty(
|
||||
name="Confidence",
|
||||
description="YOLO confidence threshold (higher = fewer false positives)",
|
||||
default=0.25,
|
||||
min=0.1,
|
||||
max=1.0,
|
||||
)
|
||||
|
||||
iou_threshold: FloatProperty(
|
||||
name="IOU Threshold",
|
||||
description="Non-maximum suppression IOU threshold",
|
||||
default=0.45,
|
||||
min=0.1,
|
||||
max=1.0,
|
||||
)
|
||||
|
||||
mask_scale: FloatProperty(
|
||||
name="Mask Scale",
|
||||
description="Scale factor for mask region (1.0 = exact face size)",
|
||||
default=1.5,
|
||||
min=1.0,
|
||||
max=3.0,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
"""Check if operator can run."""
|
||||
@@ -126,6 +101,11 @@ class SEQUENCER_OT_generate_face_mask(Operator):
|
||||
wm.mask_progress = 0
|
||||
wm.mask_total = end_frame - start_frame + 1
|
||||
|
||||
# Get parameters from scene properties
|
||||
conf_threshold = scene.facemask_conf_threshold
|
||||
iou_threshold = scene.facemask_iou_threshold
|
||||
mask_scale = scene.facemask_mask_scale
|
||||
|
||||
# Start generation
|
||||
generator.start(
|
||||
video_path=video_path,
|
||||
@@ -133,9 +113,9 @@ class SEQUENCER_OT_generate_face_mask(Operator):
|
||||
start_frame=0, # Frame indices in video
|
||||
end_frame=end_frame - start_frame,
|
||||
fps=fps,
|
||||
conf_threshold=self.conf_threshold,
|
||||
iou_threshold=self.iou_threshold,
|
||||
mask_scale=self.mask_scale,
|
||||
conf_threshold=conf_threshold,
|
||||
iou_threshold=iou_threshold,
|
||||
mask_scale=mask_scale,
|
||||
on_complete=on_complete,
|
||||
on_progress=on_progress,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user