Add files via upload

improved method for pose inter, so make a V2 node.  Add new function: pose modify node,
This commit is contained in:
YangJX
2025-05-27 14:58:57 +08:00
committed by GitHub
parent f5d79bf0ac
commit a3fadc2053
3 changed files with 724 additions and 5 deletions
+724 -5
View File
@@ -6,7 +6,7 @@ import cv2
import numpy as np
import folder_paths
import os
import math
connect_color = [
[ 0, 0, 255],
@@ -42,8 +42,489 @@ skeleton = [
[12, 13], [14, 0], [14, 16], [15, 0],
[15, 17]
]
bonesPoints = [
[1,0],# neck
[0,14 ],#right eye
[0,15 ],#left eye
[14,16 ],# right ear
[15,17 ],# left ear
[1,2 ],#right shoulder
[1,5 ],#left shoulder
[2,3 ],#right elbow
[5,6 ],#left elbow
[3,4 ],#right wrist
[6,7 ],#left wrist
[1,8 ],#right hip
[1,11 ],#left hip
[8,9 ],#right knee
[11,12 ],# left knee
[9,10 ],#right ankle
[12,13 ] # left ankle
]
def gen_skeleton(pose_keypoints_2d, canvas_width, canvas_height,landmarkType):
class HumanPart:
def __init__(self, index):
self.index = index
self.abs_x = 0.0 #绝对坐标
self.abs_y = 0.0 # 绝对坐标
self.length = 0.0 #长度
self.score=1.0 #置信度
self.abs_angle=0.0 #绝对角度
self.ref_angle=0.0 #相对角度
self.children = [] #子物体
self.ref_scale=1.0
self.abs_scale=1.0
self.parent = None #父物体
def SetParent(self, parent):
self.parent = parent
parent.children.append(self)
#根据相对角度和长度计算绝对坐标
def Update(self):
# 如果有父节点,则更新绝对位置和角度
if self.parent is not None:
if self.score > 0.0:
# 更新绝对缩放
self.abs_scale = self.parent.abs_scale * self.ref_scale
# 更新绝对角度
self.abs_angle = self.parent.abs_angle + self.ref_angle
# 更新绝对x坐标
self.abs_x = self.parent.abs_x + self.length * math.cos(self.abs_angle)* self.abs_scale
# 更新绝对y坐标
self.abs_y = self.parent.abs_y + self.length * math.sin(self.abs_angle)* self.abs_scale
else:
# 如果没有父节点,则绝对角度和缩放等于参考角度和缩放
self.abs_angle = self.ref_angle
self.abs_scale = self.ref_scale
#self.score=1.0
# 遍历子节点,递归调用Update方法
for child in self.children:
child.Update()
#根据绝对位置,计算角度、相对位置和相对角度
def CalculateRef(self):
# 如果有父节点,则更新相对位置和角度
if self.parent is not None:
if self.score > 0.0:
self.length = math.sqrt((self.abs_x - self.parent.abs_x)**2 + (self.abs_y - self.parent.abs_y)**2)
self.abs_angle =math.atan2(self.abs_y - self.parent.abs_y, self.abs_x - self.parent.abs_x)
self.ref_angle = self.abs_angle - self.parent.abs_angle
self.ref_scale = self.abs_scale / self.parent.abs_scale
#如果父节点score为0,而本节点score为1,那么这个节点就只有abs_x,abs_y是可靠的,其他都是不可靠的
#除非使用IK算法,否则无法计算可靠的角度和长度。超出了这个插件编写的本意。留着以后优化吧。
#openpose的线条,在两个端点都可靠的情况下才会绘制。因此本插件即使不计算这个骨骼,也不影响绘制。
#本插件还有猜测不可靠节点的位置的功能,不放在这个函数里处理,是因为这个函数是递归调用的,放在这里的话,猜测的位置会不断被覆盖。
#猜测功能用在pose interpolation里,因为设计本意里,pose interpolation的输入来自两张不同的图片,里面的可靠节点数量不一致,所以需要猜测不可靠节点的位置。
else:
self.length = 0.0
self.ref_angle = 0.0
self.abs_angle= 0.0
# 遍历子节点,递归调用Update方法
for child in self.children:
child.CalculateRef()
class HumanDoll:
def __init__(self, canvas_width, canvas_height):
self.canvas_width = canvas_width
self.canvas_height = canvas_height
self.parts = [None] * (len(bonesPoints) + 1)
self.keyPoints=[]
self.RootPart = HumanPart(1) # 根部 固定长度为0,对应keypoints[1]的位置
self.abs_x = canvas_width / 2
self.abs_y = canvas_height / 3
self.RootPart.abs_x = canvas_width / 2
self.RootPart.abs_y = canvas_height / 3
self.RootPart.ref_angle = 0.0
self.RootPart.score = 1.0
self.parts[1] = self.RootPart
for (p,c) in bonesPoints: # p为父节点,c为子节点
child = HumanPart(c)
child.SetParent(self.parts[p])
self.parts[c] = child
def UpdateByKeypoints(self, keypoints):
self.keyPoints = keypoints
for i, keypoint in enumerate(keypoints):
if keypoint is not None:
self.parts[i].abs_x = keypoint[0]
self.parts[i].abs_y = keypoint[1]
self.parts[i].score = keypoint[2]
else:
self.parts[i].score = 0.0
self.RootPart.CalculateRef()
def UpdateByParts(self):
self.RootPart.Update()
for i in range(len(self.keyPoints)):
self.keyPoints[i] = (self.parts[i].abs_x, self.parts[i].abs_y, self.parts[i].score)
def Draw(self, width, height,draw_all=False):
# 在这里实现绘制函数
return keyPoints_2_image(self.keyPoints, width, height,draw_all)
def guessMissingParts(self):
# 在这里实现猜测缺失部分的功能。用于pose interpolation
doll_T_Pose = HumanDoll(self.canvas_width,self.canvas_height)
keyPoints = gen_t_pose_keypoints(self.canvas_width,self.canvas_height)
doll_T_Pose.UpdateByKeypoints(keyPoints)
# 定义各部位缺失时的参考顺序数组
# 格式为:(目标部位索引, [参考部位列表按优先级排序])
reference_order = [
(0, [2,5,8,11]), # 补充头部(部位0)时参考的顺序
(2, [5,8,11,0]), # 补充右肩(部位2)时参考的顺序
(5, [2,8,11,0]), # 补充左肩(部位5)时参考的顺序
(8, [11,2,5,0]), # 补充右髋(部位8)时参考的顺序
(11, [8,2,5,0]), # 补充左髋(部位11)时参考的顺序
(3, [6,2,8,11,0]), # 补充右上臂(部位3)时参考的顺序
(6, [3,2,11,8,0]), # 补充左上臂(部位6)时参考的顺序
(4, [3,7,2,5,8,11,0]), # 补充右前臂(部位4)时参考的顺序
(7, [4,6,5,3,2,8,11,0]), # 补充左前臂(部位7)时参考的顺序
(9, [12,8,11,2,5,0]), # 补充右大腿(部位9)时参考的顺序
(12, [9,11,8,5,2,0]), # 补充左大腿(部位12)时参考的顺序
(10, [13,9,12,8,11,2,5,0]), # 补充右小腿(部位10)时参考的顺序
(13, [10,12,9,11,8,2,5,0]), # 补充左小腿(部位13)时参考的顺序
#以上都是以父节点长度参考缺失节点长度,而角度则从t-pose中复制
#但是脸上的部位,需要另外的算法。实际运行中出现过耳朵可靠而眼睛不可靠的情况,因此需要另外的算法
# (14, [15,0]), # 补充右眼睛(部位14)时参考的顺序
# (15, [14,0]), # 补充左眼睛(部位15)时参考的顺序
# (16, [17,14,15,0]), # 补充右耳朵(部位16)时参考的顺序
# (17, [16,15,14,0]), # 补充左耳朵(部位17)时参考的顺序
# 其他部位的参考规则可以继续添加
# ...
]
# 遍历所有定义好的参考规则
for target_part, reference_parts in reference_order:
# 跳过1号部位(根据需求描述1号部位不会缺失)
if target_part == 1:
continue
# 如果目标部位缺失(分数为0)
if self.parts[target_part].score == 0.0:
# 标记为已尝试修复
self.parts[target_part].score = 1.0
# 复制T姿态下的参考角度
self.parts[target_part].ref_angle = doll_T_Pose.parts[target_part].ref_angle
# 遍历参考部位列表,按优先级尝试补充数据
for ref_part in reference_parts:
if self.parts[ref_part].score > 0.0:
# 使用参考部位数据补充目标部位长度
# 比例因子:目标部位在T姿态下的长度 / 参考部位在T姿态下的长度
ratio = doll_T_Pose.parts[target_part].length / doll_T_Pose.parts[ref_part].length
#if target_part == 16 or target_part == 17:
self.parts[target_part].length = self.parts[ref_part].length * ratio
#print(f"[{target_part}]-[{ref_part}]-ratio:{ratio}- self.parts[ref_part].length:{self.parts[ref_part].length} - result_length:{self.parts[target_part].length}")
break # 找到第一个有效参考后退出循环
else:
# 如果所有参考部位都无效,重置分数
self.parts[target_part].score = 0.0
#现在处理右眼。如果右眼缺失,则根据左耳朵和鼻子的位置计算
if self.parts[14].score == 0.0:
self.parts[14].score=1.0
if self.parts[16].score > 0.0 and self.parts[0].score > 0.0:
self.parts[14].abs_x = (self.parts[16].abs_x + self.parts[0].abs_x)/2
self.parts[14].abs_y = (self.parts[16].abs_y + self.parts[0].abs_y)/2
self.parts[14].CalculateRef()
elif self.parts[0].score > 0.0:
ratio = doll_T_Pose.parts[14].length / doll_T_Pose.parts[0].length
self.parts[14].length = self.parts[0].length * ratio
else:
self.parts[14].score = 0.0
#现在处理左眼。如果左眼缺失,则根据右耳朵和鼻子的位置计算
if self.parts[15].score == 0.0:
self.parts[15].score=1.0
if self.parts[17].score > 0.0 and self.parts[0].score > 0.0:
self.parts[15].abs_x = (self.parts[17].abs_x + self.parts[0].abs_x)/2
self.parts[15].abs_y = (self.parts[17].abs_y + self.parts[0].abs_y)/2
self.parts[15].CalculateRef()
elif self.parts[0].score > 0.0:
ratio = doll_T_Pose.parts[15].length / doll_T_Pose.parts[0].length
self.parts[15].length = self.parts[0].length * ratio
else:
self.parts[15].score = 0.0
reference_order_part2 = [
(16, [17,14,15,0]), # 补充右耳朵(部位16)时参考的顺序
(17, [16,15,14,0]), # 补充左耳朵(部位17)时参考的顺序
]
for target_part, reference_parts in reference_order_part2:
# 跳过1号部位(根据需求描述1号部位不会缺失)
if target_part == 1:
continue
# 如果目标部位缺失(分数为0)
if self.parts[target_part].score == 0.0:
# 标记为已尝试修复
self.parts[target_part].score = 1.0
# 复制T姿态下的参考角度
self.parts[target_part].ref_angle = doll_T_Pose.parts[target_part].ref_angle
# 遍历参考部位列表,按优先级尝试补充数据
for ref_part in reference_parts:
if self.parts[ref_part].score > 0.0:
# 使用参考部位数据补充目标部位长度
# 比例因子:目标部位在T姿态下的长度 / 参考部位在T姿态下的长度
ratio = doll_T_Pose.parts[target_part].length / doll_T_Pose.parts[ref_part].length
#if target_part == 16 or target_part == 17:
self.parts[target_part].length = self.parts[ref_part].length * ratio
#print(f"[{target_part}]-[{ref_part}]-ratio:{ratio}- self.parts[ref_part].length:{self.parts[ref_part].length} - result_length:{self.parts[target_part].length}")
break # 找到第一个有效参考后退出循环
else:
# 如果所有参考部位都无效,重置分数
self.parts[target_part].score = 0.0
#现在处理右眼。如果右眼缺失,则根据左耳朵和鼻子的位置计算
print("修复完成")
def gen_t_pose_keypoints(canvas_width, canvas_height):
# 初始化关键点数组
keyPoints = [None] * (len(bonesPoints) + 1)
# 定义起始点(1号关键点,颈部)的位置
start_x = canvas_width / 2
start_y = canvas_height / 4
keyPoints[1] = (start_x, start_y, 1.0)
# 定义骨骼长度
neck_length = canvas_height / 10
shoulder_length = canvas_width / 8
arm_length = canvas_width / 6
hip_width = shoulder_length
hip_height = canvas_height / 4
leg_length = canvas_height / 5
head_radius = canvas_height / 15 # 头部半径
eye_distance = canvas_width / 10 # 眼睛间距
ear_distance = canvas_width / 10 # 耳朵间距
# 计算0号关键点(头部中心)的位置
head_center_x = start_x
head_center_y = start_y - neck_length
keyPoints[0] = (head_center_x, head_center_y, 1.0)
# 计算右肩(2号关键点)的位置
right_shoulder_x = start_x - shoulder_length
right_shoulder_y = start_y
keyPoints[2] = (right_shoulder_x, right_shoulder_y, 1.0)
# 计算左肩(5号关键点)的位置
left_shoulder_x = start_x + shoulder_length
left_shoulder_y = start_y
keyPoints[5] = (left_shoulder_x, left_shoulder_y, 1.0)
# 计算右肘(3号关键点)的位置
right_elbow_x = right_shoulder_x - arm_length
right_elbow_y = right_shoulder_y
keyPoints[3] = (right_elbow_x, right_elbow_y, 1.0)
# 计算左肘(6号关键点)的位置
left_elbow_x = left_shoulder_x + arm_length
left_elbow_y = left_shoulder_y
keyPoints[6] = (left_elbow_x, left_elbow_y, 1.0)
# 计算右手腕(4号关键点)的位置
right_wrist_x = right_elbow_x - arm_length
right_wrist_y = right_elbow_y
keyPoints[4] = (right_wrist_x, right_wrist_y, 1.0)
# 计算左手腕(7号关键点)的位置
left_wrist_x = left_elbow_x+ arm_length
left_wrist_y = left_elbow_y
keyPoints[7] = (left_wrist_x, left_wrist_y, 1.0)
# 计算右髋(8号关键点)的位置
right_hip_x = start_x - hip_width
right_hip_y = start_y + hip_height
keyPoints[8] = (right_hip_x, right_hip_y, 1.0)
# 计算左髋(11号关键点)的位置
left_hip_x = start_x + hip_width
left_hip_y = start_y + hip_height
keyPoints[11] = (left_hip_x, left_hip_y, 1.0)
# 计算右膝(9号关键点)的位置
right_knee_x = right_hip_x
right_knee_y = right_hip_y + leg_length
keyPoints[9] = (right_knee_x, right_knee_y, 1.0)
# 计算左膝(12号关键点)的位置
left_knee_x = left_hip_x
left_knee_y = left_hip_y + leg_length
keyPoints[12] = (left_knee_x, left_knee_y, 1.0)
# 计算右脚踝(10号关键点)的位置
right_ankle_x = right_knee_x
right_ankle_y = right_knee_y + leg_length
keyPoints[10] = (right_ankle_x, right_ankle_y, 1.0)
# 计算左脚踝(13号关键点)的位置
left_ankle_x = left_knee_x
left_ankle_y = left_knee_y + leg_length
keyPoints[13] = (left_ankle_x, left_ankle_y, 1.0)
# 计算右眼(14号关键点)的位置
right_eye_x = head_center_x - eye_distance / 2
right_eye_y = head_center_y- eye_distance / 2
keyPoints[14] = (right_eye_x, right_eye_y, 1.0)
# 计算左眼(15号关键点)的位置
left_eye_x = head_center_x + eye_distance / 2
left_eye_y = head_center_y- eye_distance / 2
keyPoints[15] = (left_eye_x, left_eye_y, 1.0)
# 计算右耳(16号关键点)的位置
right_ear_x = head_center_x - ear_distance
right_ear_y = head_center_y
keyPoints[16] = (right_ear_x, right_ear_y, 1.0)
# 计算左耳(17号关键点)的位置
left_ear_x = head_center_x + ear_distance
left_ear_y = head_center_y
keyPoints[17] = (left_ear_x, left_ear_y, 1.0)
return keyPoints
def poseKeypoints2D_2_keypoints(pose_keypoints_2d, canvas_width, canvas_height,landmarkType):
keyPoints = [pose_keypoints_2d[i:i + 3] for i in range(0, len(pose_keypoints_2d), 3)]
if landmarkType == "DWPose":
canvas_height=1
canvas_width=1
for i in range(len(keyPoints)):
x, y, z = keyPoints[i]
keyPoints[i] = (x * canvas_width, y * canvas_height, z)
return keyPoints
def keypoints_2_bones(keyPoints):
bones=[]
for i, (a, b) in enumerate(bonesPoints):
a_x, a_y, a_z = keyPoints[a]
b_x, b_y, b_z = keyPoints[b]
# 现在 (a_x,a_y) 是骨骼起点的坐标,(b_x,b_y) 是骨骼终点的坐标
# 然后计算骨骼的长度和角度,连同坐标一起生成一个骨骼对象,放入bones数组
# 如果a_z=0或者b_z=0,则忽略这个骨骼,放入一个空对象
if a_z == 0 or b_z == 0:
bone = {
'start': (a_x, a_y),
'end': (b_x, b_y),
'length': -1,
'angle': 0
}
bones.append(bone)
continue
# 计算骨骼的长度
bone_length = math.sqrt((b_x - a_x) ** 2 + (b_y - a_y) ** 2)
# 计算骨骼的角度
bone_angle = math.atan2(b_y - a_y, b_x - a_x)
# 生成骨骼对象
bone = {
'start': (a_x, a_y),
'end': (b_x, b_y),
'length': bone_length,
'angle': bone_angle
}
bones.append(bone)
return bones
def bones_2_keypoints(bones):
keyPoints = [None] * 18
# 从1号关键点开始
start_bone = bones[0]
start_x, start_y = start_bone['start']
neck_length = start_bone['length']
neck_angle = start_bone['angle']
keyPoints[1] = (start_x ,start_y,1.0)
# 计算新的0号关键点的位置
new_x = start_x + neck_length * math.cos(neck_angle)
new_y = start_y + neck_length * math.sin(neck_angle)
keyPoints[0] = (new_x ,new_y,1.0)
# 依次计算后续关键点的位置
for i, (a, b) in enumerate(bonesPoints):
if i == 0:
continue # 跳过第一个骨骼,因为它已经处理过了
# 获取前一个关键点的位置
prev_x,prev_y,score = keyPoints[a]
# 获取当前骨骼的信息
bone = bones[i]
bone_length = bone['length']
bone_angle = bone['angle']
if bone_length == -1:
keyPoints[b]=(0,0,0)
continue
# 计算新的关键点位置
new_x = prev_x + bone_length * math.cos(bone_angle)
new_y = prev_y + bone_length * math.sin(bone_angle)
# 将新的关键点位置存入数组
keyPoints[b]=(new_x ,new_y,1.0)
return keyPoints
def keyPoints_2_image(keyPoints, canvas_width, canvas_height ,draw_all=False):
image = np.zeros((canvas_height, canvas_width, 3), dtype=np.uint8)
# 绘制骨架
for i, (a, b) in enumerate(skeleton):
a_x, a_y, a_z = keyPoints[a]
b_x, b_y, b_z = keyPoints[b]
if draw_all:
if a_z != 0 and b_z != 0:
cv2.line(image, (int(a_x), int(a_y)), (int(b_x), int(b_y)), connect_color[i] + [0], 4)
else:
cv2.line(image, (int(a_x), int(a_y)), (int(b_x), int(b_y)), (255,255,255), 4)
else:
# 检查是否在画面内(假设a_z和b_z为0表示不在画面内)
a_in_canvas = a_z != 0 and 0 <= a_x < canvas_width and 0 <= a_y < canvas_height
b_in_canvas = b_z != 0 and 0 <= b_x < canvas_width and 0 <= b_y < canvas_height
if a_in_canvas and b_in_canvas:
cv2.line(image, (int(a_x), int(a_y)), (int(b_x), int(b_y)), connect_color[i] + [0], 4)
# 绘制关键点
for i, (x, y, z) in enumerate(keyPoints):
if z!=0:
try:
cv2.circle(image, (int(x), int(y)), int(canvas_width/100), connect_color[i], -1)
except:
pass
# cv2.putText(image, str(i), (int(x), int(y)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
return image
def draw_skeleton(pose_keypoints_2d, canvas_width, canvas_height,landmarkType):
# 加载背景图片或创建一个空白画布
image = None #cv2.imread('background.jpg') # 使用实际的背景图片路径
if image is None:
@@ -137,7 +618,7 @@ class Pose_Inter:
for i, keypoints in enumerate(keypoints_array):
# 显示图像
image = gen_skeleton(
image = draw_skeleton(
keypoints,
openpose_dict_2["canvas_width"],
openpose_dict_2["canvas_height"],
@@ -150,14 +631,252 @@ class Pose_Inter:
#print("shape of tensor_stacked")
#print(tensor_stacked.shape)
return (tensor_stacked,)
class PoseModify:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"pose_keypoint": ("POSE_KEYPOINT", ),
"landmarkType": (["OpenPose","DWPose"], ),
"globalScale": ("FLOAT", {"default": 1.0, "min": 0.1, "max": 10.0}),
"head": ("FLOAT", {"default": 1.0, "min": 0.1, "max": 10.0,"step":0.1}),
"neck": ("FLOAT", {"default": 1.0, "min": 0.1, "max": 10.0,"step":0.1}),
"neck": ("FLOAT", {"default": 1.0, "min": 0.1, "max": 10.0,"step":0.1}),
"torsoWidth": ("FLOAT", {"default": 1.0, "min": 0.1, "max": 10.0,"step":0.1}),
"torsoHeight": ("FLOAT", {"default": 1.0, "min": 0.1, "max": 10.0,"step":0.1}),
"upperArmLength": ("FLOAT", {"default": 1.0, "min": 0.1, "max": 10.0,"step":0.1}),
"lowerArmLength": ("FLOAT", {"default": 1.0, "min": 0.1, "max": 10.0,"step":0.1}),
"upperLegLength": ("FLOAT", {"default": 1.0, "min": 0.1, "max": 10.0,"step":0.1}),
"lowerLegLength": ("FLOAT", {"default": 1.0, "min": 0.1, "max": 10.0,"step":0.1}),
},
}
RETURN_TYPES = ("IMAGE",)
FUNCTION = "run"
CATEGORY = "Pose Interpolation"
def run(self,pose_keypoint,landmarkType,globalScale,head,neck,torsoWidth,torsoHeight,upperArmLength,lowerArmLength,upperLegLength,lowerLegLength):
# if head==1.0 & neck==1.0 & torsoWidth==1.0 & torsoHeight==1.0 & upperArmLength==1.0 & lowerArmLength==1.0 & upperLegLength==1.0 & lowerLegLength==1.0:
# lengthFactors = [1.0] * 18
# else:
lengthFactors = [neck,1.0,
torsoWidth,
upperArmLength,
lowerArmLength,
torsoWidth,
upperArmLength,
lowerArmLength,
torsoHeight,
upperLegLength,
lowerLegLength,
torsoHeight,
upperLegLength,
lowerLegLength,
head,
head,
head,
head]
openpose_dict_2 = pose_keypoint[0]
width = openpose_dict_2["canvas_width"]
height = openpose_dict_2["canvas_height"]
output=[]
openpose_dict_2 = pose_keypoint[0]
width = openpose_dict_2["canvas_width"]
height = openpose_dict_2["canvas_height"]
keyPoints = gen_t_pose_keypoints(width,height)
doll = HumanDoll(width,height)
doll.UpdateByKeypoints(keyPoints)
for openpose_dict_2 in pose_keypoint:
human1Keypoints = poseKeypoints2D_2_keypoints(
openpose_dict_2["people"][0]["pose_keypoints_2d"],
width,
height,
landmarkType
)
doll.UpdateByKeypoints(human1Keypoints)
doll.RootPart.ref_scale = globalScale
for i in range(len(doll.parts)):
if doll.parts[i].score > 0.0:
doll.parts[i].length *= lengthFactors[i]
doll.UpdateByParts()
image=doll.Draw(width,height)
image = torch.from_numpy(image.astype(np.float32) / 255.0)#.unsqueeze(0)
output.append(image)
tensor_stacked = torch.stack(output)
#print("shape of tensor_stacked")
#print(tensor_stacked.shape)
return (tensor_stacked,)
class GenTPose:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"width": ("INT", {"default": 480, "min": 2, "max": 1024, "step": 1}),
"height": ("INT", {"default": 640, "min": 2, "max": 1024, "step": 1}),
},
}
RETURN_TYPES = ("IMAGE",)
FUNCTION = "run"
CATEGORY = "Pose Interpolation"
def run(self,width,height):
keyPoints = gen_t_pose_keypoints(width,height)
doll = HumanDoll(width, height)
doll.UpdateByKeypoints(keyPoints)
doll.UpdateByParts()
image=doll.Draw(width, height)
output=[]
image = torch.from_numpy(image.astype(np.float32) / 255.0)#.unsqueeze(0)
output.append(image)
tensor_stacked = torch.stack(output)
#print("shape of tensor_stacked")
#print(tensor_stacked.shape)
return (tensor_stacked,)
class Pose_Inter_V2:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"pose_from": ("POSE_KEYPOINT", ),
"pose_to": ("POSE_KEYPOINT", ),
"interpolate_frames": ("INT", {"default": 10, "min": 2, "max": 100, "step": 1}),
"landmarkType": (["OpenPose","DWPose"], ),
"draw_all": ("BOOLEAN", {"default": False}),
},
}
RETURN_TYPES = ("IMAGE",)
FUNCTION = "run"
CATEGORY = "Pose Interpolation"
def run(self,pose_from,pose_to,interpolate_frames,landmarkType,draw_all):
output=[]
openpose_dict = pose_from[0]
openpose_dict_2 = pose_to[0]
width = openpose_dict_2["canvas_width"]
height = openpose_dict_2["canvas_height"]
dollFrom = HumanDoll(width,height)
fromKeys = poseKeypoints2D_2_keypoints(openpose_dict["people"][0]["pose_keypoints_2d"],width,height,landmarkType)
dollFrom.UpdateByKeypoints(fromKeys)
dollTo = HumanDoll(width,height)
toKeys = poseKeypoints2D_2_keypoints(openpose_dict_2["people"][0]["pose_keypoints_2d"],width,height,landmarkType)
dollTo.UpdateByKeypoints(toKeys)
dollFrom.guessMissingParts()
dollTo.guessMissingParts()
image=dollFrom.Draw(width,height,draw_all)
image = torch.from_numpy(image.astype(np.float32) / 255.0)
output.append(image)
position_x_arr = np.full(interpolate_frames+2, -1.0, dtype=np.float32)
position_y_arr = np.full(interpolate_frames+2,-1.0, dtype=np.float32)
position_x_arr[0] = dollFrom.RootPart.abs_x
position_y_arr[0] = dollFrom.RootPart.abs_y
position_x_arr[interpolate_frames+1] = dollTo.RootPart.abs_x
position_y_arr[interpolate_frames+1] = dollTo.RootPart.abs_y
for i in range(1, interpolate_frames+1):
position_x_arr[i] = position_x_arr[0] + (position_x_arr[interpolate_frames+1] - position_x_arr[0]) * (i - 1) / interpolate_frames
position_y_arr[i] = position_y_arr[0] + (position_y_arr[interpolate_frames+1] - position_y_arr[0]) * (i - 1) / interpolate_frames
#18个骨骼,每个骨骼2个数组,每个数组有interpolate_frames+2个元素表示骨骼每一帧的长度和角度
curveDatas = np.full((18, 2, interpolate_frames+2), -1.0, dtype=np.float32)
for i in range(len(dollFrom.parts)):
if dollFrom.parts[i].score > 0.0:
curveDatas[i][0][0] = dollFrom.parts[i].length
curveDatas[i][1][0] = dollFrom.parts[i].ref_angle
dollFrom.parts[i].score=1.0
for i in range(len(dollTo.parts)):
if dollTo.parts[i].score > 0.0:
curveDatas[i][0][interpolate_frames+1] = dollTo.parts[i].length
curveDatas[i][1][interpolate_frames+1] = dollTo.parts[i].ref_angle
dollTo.parts[i].score=1.0
for i in range(18):
j=0
#骨骼长度,线性插值
for k in range(1, interpolate_frames+1):
curveDatas[i][j][k] = curveDatas[i][j][0] + (curveDatas[i][j][interpolate_frames+1] - curveDatas[i][j][0]) * (k) / (interpolate_frames+1)
for i in range(18):
j=1
a = curveDatas[i][j][0]
b = curveDatas[i][j][interpolate_frames+1]
# 将 b 调整到与 a 变化量最小的等效弧度值
b_adjusted = b - 2 * np.pi * np.round((b - a) / (2 * np.pi))
curveDatas[i][j][interpolate_frames+1] = b_adjusted
for k in range(1, interpolate_frames+1):
curveDatas[i][j][k] = a + (b_adjusted - a) * (k) / (interpolate_frames+1)
curveDatas[i][j] = np.mod(curveDatas[i][j], 2 * np.pi)
for i in range(1,interpolate_frames+1):
dollFrom.RootPart.abs_x = position_x_arr[i]
dollFrom.RootPart.abs_y = position_y_arr[i]
for k in range(18):
dollFrom.parts[k].length = curveDatas[k][0][i]
dollFrom.parts[k].ref_angle = curveDatas[k][1][i]
dollFrom.UpdateByParts()
image=dollFrom.Draw(width,height,draw_all)
image = torch.from_numpy(image.astype(np.float32) / 255.0)#.unsqueeze(0)
output.append(image)
image=dollTo.Draw(width,height,draw_all)
image = torch.from_numpy(image.astype(np.float32) / 255.0)#.unsqueeze(0)
output.append(image)
tensor_stacked = torch.stack(output)
return (tensor_stacked,)
# A dictionary that contains all nodes you want to export with their names
# NOTE: names should be globally unique
NODE_CLASS_MAPPINGS = {
"Pose_Inter": Pose_Inter
"Pose_Inter": Pose_Inter,
"Pose_Inter_V2": Pose_Inter_V2,
"PoseModify": PoseModify,
"GenTPose":GenTPose
}
# A dictionary that contains the friendly/humanly readable titles for the nodes
NODE_DISPLAY_NAME_MAPPINGS = {
"Pose_Inter": "Pose Interpolation"
"Pose_Inter": "Pose Interpolation",
"Pose_Inter_V2": "Pose Interpolation_V2",
"PoseModify": "Pose Modify by factor",
"GenTPose": "GenTPose"
}
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB