Add separate limb scaling controls

This commit is contained in:
grmchn
2026-05-08 18:53:13 +09:00
parent 227ddcd394
commit cd5af99868
4 changed files with 83 additions and 67 deletions
+1 -1
View File
@@ -14,7 +14,7 @@ Additionally, the Openpose Editor node from [toyxyz/ComfyUI-ultimate-openpose-ed
- **ProportionChanger Pose Detector**: Detects KeyPoints from images
- **ProportionChanger Reference**: Transforms proportions to reference poses
- **ProportionChanger Pose Render**: Converts KeyPoints to images
- **ProportionChanger Params**: Adjusts parameters for individual KeyPoint parts
- **ProportionChanger Params**: Adjusts parameters for individual KeyPoint parts, including separate upper/lower arm, thigh/lower-leg, and feet scaling
- **ProportionChanger Interpolator**: Interpolates KeyPoint videos with in-betweening
- **PoseData to pose_keypoint**: Converts WanAnimate `POSEDATA` into `POSE_KEYPOINT`
- **pose_keypoint resize**: Resizes `POSE_KEYPOINT` to a target size (pads then scales to avoid stretching when aspect differs)
+1 -1
View File
@@ -14,7 +14,7 @@
- **ProportionChanger Pose Detector**: 画像からKeyPointを検出する
- **ProportionChanger Reference**: 参照用ポーズにプロポーションを変換する
- **ProportionChanger Pose Render**: KeyPointを画像に変換する
- **ProportionChanger Params**: KeyPointの各パーツのパラメータを調整する
- **ProportionChanger Params**: KeyPointの各パーツのパラメータを調整する(上腕・下腕・太腿・下腿・足先の個別スケールを含む)
- **ProportionChanger Interpolator**: KeyPoint動画を中割りして補間する
- **PoseData to pose_keypoint**: WanAnimateの`POSEDATA`を`POSE_KEYPOINT`に変換する
- **pose_keypoint resize**: `POSE_KEYPOINT`を指定サイズにリサイズ(アスペクト比が違う場合はパディング→スケールで歪みを防ぐ)
+80 -64
View File
@@ -27,9 +27,14 @@ class ProportionChangerParams:
"neck_scale": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}),
"shoulder_scale": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}),
"arm_scale": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}),
"upper_arm_scale": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}),
"lower_arm_scale": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}),
"torso_scale": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}),
"pelvis_scale": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}),
"leg_scale": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}),
"thigh_scale": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}),
"lower_leg_scale": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}),
"feet_scale": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}),
# === FACE KEYPOINTS (face top to bottom order) ===
"face_shape_scale": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 5.0, "step": 0.01}),
@@ -76,7 +81,9 @@ class ProportionChangerParams:
left_eye_scale=1.0, right_eye_scale=1.0, left_eyebrow_scale=1.0,
right_eyebrow_scale=1.0, mouth_scale=1.0, nose_scale_face=1.0,
face_shape_scale=1.0, shoulder_scale=1.0, arm_scale=1.0,
leg_scale=1.0, hands_scale=1.0, overall_scale=1.0,
upper_arm_scale=1.0, lower_arm_scale=1.0, leg_scale=1.0,
thigh_scale=1.0, lower_leg_scale=1.0, feet_scale=1.0,
hands_scale=1.0, overall_scale=1.0,
rotate_angle=0.0, translate_x=0.0, translate_y=0.0):
"""
pose_keypointデータを各種パラメータで調整
@@ -106,7 +113,12 @@ class ProportionChangerParams:
"face_shape_scale": face_shape_scale,
"shoulder_scale": shoulder_scale,
"arm_scale": arm_scale,
"upper_arm_scale": upper_arm_scale,
"lower_arm_scale": lower_arm_scale,
"leg_scale": leg_scale,
"thigh_scale": thigh_scale,
"lower_leg_scale": lower_leg_scale,
"feet_scale": feet_scale,
"hands_scale": hands_scale,
"overall_scale": overall_scale,
"rotate_angle": rotate_angle,
@@ -144,7 +156,9 @@ class ProportionChangerParams:
"left_eye_scale": 1.0, "right_eye_scale": 1.0, "left_eyebrow_scale": 1.0,
"right_eyebrow_scale": 1.0, "mouth_scale": 1.0, "nose_scale_face": 1.0,
"face_shape_scale": 1.0, "shoulder_scale": 1.0, "arm_scale": 1.0,
"leg_scale": 1.0, "hands_scale": 1.0, "overall_scale": 1.0,
"upper_arm_scale": 1.0, "lower_arm_scale": 1.0, "leg_scale": 1.0,
"thigh_scale": 1.0, "lower_leg_scale": 1.0, "feet_scale": 1.0,
"hands_scale": 1.0, "overall_scale": 1.0,
"rotate_angle": 0.0, "translate_x": 0.0, "translate_y": 0.0
}
@@ -297,7 +311,12 @@ class ProportionChangerParams:
head_scale = params.get("head_scale", 1.0)
shoulder_scale = params.get("shoulder_scale", 1.0)
arm_scale = params.get("arm_scale", 1.0)
upper_arm_scale = params.get("upper_arm_scale", 1.0)
lower_arm_scale = params.get("lower_arm_scale", 1.0)
leg_scale = params.get("leg_scale", 1.0)
thigh_scale = params.get("thigh_scale", 1.0)
lower_leg_scale = params.get("lower_leg_scale", 1.0)
feet_scale = params.get("feet_scale", 1.0)
# Get original reference points (always from original keypoints)
orig_r_hip = get_point(original, KP["RHip"])
@@ -422,66 +441,71 @@ class ProportionChangerParams:
head_moved = [orig_head_point[0] + neck_movement[0], orig_head_point[1] + neck_movement[1]]
set_point(adjusted, KP[head_kp], head_moved)
# 5. Arm adjustment (from original arm joints, based on position after shoulder adjustment)
if arm_scale != 1.0 and current_r_shoulder and current_l_shoulder:
# 5. Arm adjustment. arm_scale remains the full-arm base scale;
# upper/lower arm scales additionally affect each segment.
if current_r_shoulder and current_l_shoulder:
for side_prefix, current_shoulder, orig_shoulder in [
("R", current_r_shoulder, orig_r_shoulder),
("L", current_l_shoulder, orig_l_shoulder)
]:
for joint in ["Elbow", "Wrist"]:
kp_name = f"{side_prefix}{joint}"
if kp_name in KP:
orig_joint = get_point(original, KP[kp_name])
if orig_joint and orig_shoulder:
new_joint = [
current_shoulder[0] + (orig_joint[0] - orig_shoulder[0]) * arm_scale,
current_shoulder[1] + (orig_joint[1] - orig_shoulder[1]) * arm_scale
]
set_point(adjusted, KP[kp_name], new_joint)
elif current_r_shoulder and current_l_shoulder:
# arm_scale=1.0の場合、shoulder移動の影響のみ適用
for side_prefix, current_shoulder, orig_shoulder in [
("R", current_r_shoulder, orig_r_shoulder),
("L", current_l_shoulder, orig_l_shoulder)
]:
if orig_shoulder:
shoulder_movement = [current_shoulder[0] - orig_shoulder[0], current_shoulder[1] - orig_shoulder[1]]
for joint in ["Elbow", "Wrist"]:
kp_name = f"{side_prefix}{joint}"
if kp_name in KP:
orig_joint = get_point(original, KP[kp_name])
if orig_joint:
new_joint = [orig_joint[0] + shoulder_movement[0], orig_joint[1] + shoulder_movement[1]]
set_point(adjusted, KP[kp_name], new_joint)
if not orig_shoulder:
continue
orig_elbow = get_point(original, KP[f"{side_prefix}Elbow"])
orig_wrist = get_point(original, KP[f"{side_prefix}Wrist"])
if orig_elbow:
new_elbow = [
current_shoulder[0] + (orig_elbow[0] - orig_shoulder[0]) * arm_scale * upper_arm_scale,
current_shoulder[1] + (orig_elbow[1] - orig_shoulder[1]) * arm_scale * upper_arm_scale
]
set_point(adjusted, KP[f"{side_prefix}Elbow"], new_elbow)
else:
new_elbow = None
if orig_wrist:
if orig_elbow and new_elbow:
new_wrist = [
new_elbow[0] + (orig_wrist[0] - orig_elbow[0]) * arm_scale * lower_arm_scale,
new_elbow[1] + (orig_wrist[1] - orig_elbow[1]) * arm_scale * lower_arm_scale
]
else:
new_wrist = [
current_shoulder[0] + (orig_wrist[0] - orig_shoulder[0]) * arm_scale * lower_arm_scale,
current_shoulder[1] + (orig_wrist[1] - orig_shoulder[1]) * arm_scale * lower_arm_scale
]
set_point(adjusted, KP[f"{side_prefix}Wrist"], new_wrist)
# 6. Leg adjustment (from original leg joints, based on position after pelvis adjustment)
current_r_hip = get_point(adjusted, KP["RHip"])
current_l_hip = get_point(adjusted, KP["LHip"])
if leg_scale != 1.0:
for side_prefix, current_hip, orig_hip in [("R", current_r_hip, orig_r_hip), ("L", current_l_hip, orig_l_hip)]:
for joint in ["Knee", "Ankle"]:
kp_name = f"{side_prefix}{joint}"
if kp_name in KP:
orig_joint = get_point(original, KP[kp_name])
if orig_joint and orig_hip:
new_joint = [
current_hip[0] + (orig_joint[0] - orig_hip[0]) * leg_scale,
current_hip[1] + (orig_joint[1] - orig_hip[1]) * leg_scale
]
set_point(adjusted, KP[kp_name], new_joint)
else:
# leg_scale=1.0の場合、pelvis移動の影響のみ適用
for side_prefix, current_hip, orig_hip in [("R", current_r_hip, orig_r_hip), ("L", current_l_hip, orig_l_hip)]:
if orig_hip:
hip_movement = [current_hip[0] - orig_hip[0], current_hip[1] - orig_hip[1]]
for joint in ["Knee", "Ankle"]:
kp_name = f"{side_prefix}{joint}"
if kp_name in KP:
orig_joint = get_point(original, KP[kp_name])
if orig_joint:
new_joint = [orig_joint[0] + hip_movement[0], orig_joint[1] + hip_movement[1]]
set_point(adjusted, KP[kp_name], new_joint)
for side_prefix, current_hip, orig_hip in [("R", current_r_hip, orig_r_hip), ("L", current_l_hip, orig_l_hip)]:
if not current_hip or not orig_hip:
continue
orig_knee = get_point(original, KP[f"{side_prefix}Knee"])
orig_ankle = get_point(original, KP[f"{side_prefix}Ankle"])
if orig_knee:
new_knee = [
current_hip[0] + (orig_knee[0] - orig_hip[0]) * leg_scale * thigh_scale,
current_hip[1] + (orig_knee[1] - orig_hip[1]) * leg_scale * thigh_scale
]
set_point(adjusted, KP[f"{side_prefix}Knee"], new_knee)
else:
new_knee = None
if orig_ankle:
if orig_knee and new_knee:
new_ankle = [
new_knee[0] + (orig_ankle[0] - orig_knee[0]) * leg_scale * lower_leg_scale,
new_knee[1] + (orig_ankle[1] - orig_knee[1]) * leg_scale * lower_leg_scale
]
else:
new_ankle = [
current_hip[0] + (orig_ankle[0] - orig_hip[0]) * leg_scale * lower_leg_scale,
current_hip[1] + (orig_ankle[1] - orig_hip[1]) * leg_scale * lower_leg_scale
]
set_point(adjusted, KP[f"{side_prefix}Ankle"], new_ankle)
# 7. Toe/heel adjustment (ankle-based leg_scale scaling)
current_l_ankle = get_point(adjusted, KP["LAnkle"])
@@ -503,17 +527,9 @@ class ProportionChangerParams:
current_ankle and orig_ankle): # Only if both ankle and toe exist
orig_toe_heel = [original[keypoint_start], original[keypoint_start + 1]]
confidence = original[keypoint_start + 2]
if leg_scale != 1.0:
# Maintain direction vector from ankle to toe, scale distance only
orig_relative = [orig_toe_heel[0] - orig_ankle[0], orig_toe_heel[1] - orig_ankle[1]]
scaled_relative = [orig_relative[0] * leg_scale, orig_relative[1] * leg_scale]
new_toe_heel = [current_ankle[0] + scaled_relative[0], current_ankle[1] + scaled_relative[1]]
else:
# leg_scale=1.0: follow ankle movement
ankle_movement = [current_ankle[0] - orig_ankle[0], current_ankle[1] - orig_ankle[1]]
new_toe_heel = [orig_toe_heel[0] + ankle_movement[0], orig_toe_heel[1] + ankle_movement[1]]
orig_relative = [orig_toe_heel[0] - orig_ankle[0], orig_toe_heel[1] - orig_ankle[1]]
scaled_relative = [orig_relative[0] * leg_scale * feet_scale, orig_relative[1] * leg_scale * feet_scale]
new_toe_heel = [current_ankle[0] + scaled_relative[0], current_ankle[1] + scaled_relative[1]]
# Update toe/heel position
adjusted[keypoint_start] = new_toe_heel[0]
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "ComfyUI-ProportionChanger"
description = "Advanced pose-based body proportion changer for ComfyUI"
version = "1.1.0"
version = "1.2.0"
license = {file = "LICENSE"}
dependencies = ["torch", "numpy", "opencv-python", "tqdm"]