Files
yichengup-ComfyUI_SwiftCut/py/utils.py
T
2025-09-02 14:51:51 +00:00

142 lines
4.7 KiB
Python

import torch
from torch import Tensor
import re
from typing import Union, List, Tuple
# 定义常量
BIGMIN = -(2**53-1)
BIGMAX = 2**53-1
def convert_str_to_indexes(text: str, total_frames: int) -> List[int]:
"""将字符串转换为索引列表
支持格式:
- 单个索引: "5"
- 多个索引: "1,3,5"
- 范围: "3-10"
- 混合: "1,3-5,8,10-15"
- 负索引: "-1" (最后一帧)
- 步长: "0-10:2" (0到10每隔2帧)
"""
if not text.strip():
return []
indexes = []
parts = text.split(',')
for part in parts:
part = part.strip()
if not part:
continue
# 处理范围格式 "start-end" 或 "start-end:step"
if '-' in part and not part.startswith('-'):
# 检查是否有步长
if ':' in part:
range_part, step_str = part.split(':', 1)
try:
step = int(step_str)
except ValueError:
step = 1
else:
range_part = part
step = 1
# 解析范围
try:
start_str, end_str = range_part.split('-', 1)
start = int(start_str)
end = int(end_str)
# 处理负索引
if start < 0:
start = total_frames + start
if end < 0:
end = total_frames + end
# 确保范围有效
start = max(0, min(start, total_frames - 1))
end = max(0, min(end, total_frames - 1))
# 生成范围内的索引
if start <= end:
indexes.extend(range(start, end + 1, step))
else:
indexes.extend(range(start, end - 1, -step))
except ValueError:
# 如果解析失败,尝试作为单个索引处理
try:
idx = int(part)
if idx < 0:
idx = total_frames + idx
if 0 <= idx < total_frames:
indexes.append(idx)
except ValueError:
pass
else:
# 处理单个索引
try:
idx = int(part)
if idx < 0:
idx = total_frames + idx
if 0 <= idx < total_frames:
indexes.append(idx)
except ValueError:
pass
# 去重并排序
indexes = sorted(list(set(indexes)))
return indexes
def select_indexes(input_obj: Tensor, indexes: List[int]) -> Tensor:
"""根据索引列表选择tensor中的数据"""
if not indexes:
return input_obj[:0] # 返回空tensor,保持维度结构
# 确保索引在有效范围内
valid_indexes = [idx for idx in indexes if 0 <= idx < input_obj.shape[0]]
if not valid_indexes:
return input_obj[:0] # 返回空tensor
return input_obj[valid_indexes]
def select_indexes_from_str(input_obj: Tensor, indexes: str,
err_if_missing: bool = True,
err_if_empty: bool = True) -> Tensor:
"""从字符串索引选择tensor数据"""
total_frames = input_obj.shape[0]
# 转换字符串为索引列表
index_list = convert_str_to_indexes(indexes, total_frames)
# 检查错误条件
if err_if_empty and not index_list:
raise ValueError(f"没有有效的索引被选择。输入: '{indexes}', 总帧数: {total_frames}")
if err_if_missing:
# 检查是否有索引超出范围
invalid_indexes = [idx for idx in index_list if idx >= total_frames or idx < 0]
if invalid_indexes:
raise ValueError(f"索引超出范围: {invalid_indexes}, 总帧数: {total_frames}")
# 选择数据
return select_indexes(input_obj, index_list)
# 描述文本
select_description = """
Image Index Selection Node
Supported Index Formats:
- Single Index: "5" (Selects the 6th image, counting from 0)
- Multiple Indexes: "1,3,5" (Selects the 2nd, 4th, and 6th images)
- Range Selection: "3-10" (Selects the 4th to 11th images)
- Range with Step: "0-10:2" (Selects the 1st, 3rd, 5th, 7th, 9th, and 11th images)
- Mixed Format: "1,3-5,8,10-15" (Selects the 1st, 3rd, 4th, 5th, 8th, 10th, 11th, 12th, 13th, 14th, and 15th images)
- Negative Index: "-1" (Selects the last image), "-3--1" (Selects the last 3 images)
Parameter Description:
- err_if_missing: Whether to report an error if the index is out of range
- err_if_empty: Whether to report an error if no images are selected
"""