- Rename nodes/ directory to proportion_changer/ following ComfyUI conventions - Update __init__.py to use simple relative imports instead of importlib.util - Fix nodes.py imports to reference .proportion_changer instead of .nodes - Resolve ImportError caused by Python module vs package name collision - Follow established ComfyUI custom node patterns (similar to adv_control/) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
190 lines
7.3 KiB
Python
190 lines
7.3 KiB
Python
"""
|
|
Pose data processing and conversion utilities
|
|
Handles conversion between POSE_KEYPOINT format and DWPose internal format
|
|
"""
|
|
|
|
import numpy as np
|
|
import copy
|
|
|
|
|
|
def pose_keypoint_to_dwpose_format(pose_keypoint, canvas_width, canvas_height):
|
|
"""
|
|
Convert POSE_KEYPOINT format to DWPose internal format
|
|
|
|
Args:
|
|
pose_keypoint: POSE_KEYPOINT data (list of dicts)
|
|
canvas_width: Canvas width for coordinate conversion
|
|
canvas_height: Canvas height for coordinate conversion
|
|
|
|
Returns:
|
|
dict: DWPose format with 'bodies', 'faces', 'hands' keys
|
|
"""
|
|
|
|
if not pose_keypoint or len(pose_keypoint) == 0:
|
|
return {'bodies': {'candidate': np.array([]), 'subset': np.array([])}, 'faces': np.array([]), 'hands': np.array([])}
|
|
|
|
frame_data = pose_keypoint[0] # Use first frame
|
|
people = frame_data.get('people', [])
|
|
|
|
if len(people) == 0:
|
|
return {'bodies': {'candidate': np.array([]), 'subset': np.array([])}, 'faces': np.array([]), 'hands': np.array([])}
|
|
|
|
person = people[0] # Use first person
|
|
|
|
# Extract keypoints
|
|
body_kpts = person.get('pose_keypoints_2d', [])
|
|
face_kpts = person.get('face_keypoints_2d', [])
|
|
lhand_kpts = person.get('hand_left_keypoints_2d', [])
|
|
rhand_kpts = person.get('hand_right_keypoints_2d', [])
|
|
|
|
# Convert body keypoints to candidate format
|
|
candidates = []
|
|
subset = []
|
|
|
|
if body_kpts and len(body_kpts) >= 75: # 25 points * 3 (x,y,conf)
|
|
for i in range(25): # Support full 25 points including toes
|
|
x = body_kpts[i*3] / canvas_width if canvas_width > 0 else body_kpts[i*3]
|
|
y = body_kpts[i*3+1] / canvas_height if canvas_height > 0 else body_kpts[i*3+1]
|
|
conf = body_kpts[i*3+2]
|
|
candidates.append([x, y, conf])
|
|
|
|
# Create subset (which keypoints are valid)
|
|
subset_row = []
|
|
for i in range(25):
|
|
if body_kpts[i*3+2] > 0: # confidence > 0
|
|
subset_row.append(i)
|
|
else:
|
|
subset_row.append(-1)
|
|
subset.append(subset_row)
|
|
|
|
candidate_array = np.array(candidates) if candidates else np.array([])
|
|
subset_array = np.array(subset) if subset else np.array([])
|
|
|
|
# Convert face keypoints
|
|
faces = []
|
|
if face_kpts and len(face_kpts) >= 210: # 70 points * 3
|
|
face_points = []
|
|
for i in range(70):
|
|
x = face_kpts[i*3] / canvas_width if canvas_width > 0 else face_kpts[i*3]
|
|
y = face_kpts[i*3+1] / canvas_height if canvas_height > 0 else face_kpts[i*3+1]
|
|
conf = face_kpts[i*3+2]
|
|
face_points.append([x, y, conf])
|
|
faces.append(face_points)
|
|
|
|
# Convert hand keypoints
|
|
hands = []
|
|
if lhand_kpts and len(lhand_kpts) >= 63: # 21 points * 3
|
|
lhand_points = []
|
|
for i in range(21):
|
|
x = lhand_kpts[i*3] / canvas_width if canvas_width > 0 else lhand_kpts[i*3]
|
|
y = lhand_kpts[i*3+1] / canvas_height if canvas_height > 0 else lhand_kpts[i*3+1]
|
|
conf = lhand_kpts[i*3+2]
|
|
lhand_points.append([x, y, conf])
|
|
hands.append(lhand_points)
|
|
|
|
if rhand_kpts and len(rhand_kpts) >= 63: # 21 points * 3
|
|
rhand_points = []
|
|
for i in range(21):
|
|
x = rhand_kpts[i*3] / canvas_width if canvas_width > 0 else rhand_kpts[i*3]
|
|
y = rhand_kpts[i*3+1] / canvas_height if canvas_height > 0 else rhand_kpts[i*3+1]
|
|
conf = rhand_kpts[i*3+2]
|
|
rhand_points.append([x, y, conf])
|
|
hands.append(rhand_points)
|
|
|
|
faces_array = np.array(faces) if faces else np.array([])
|
|
hands_array = np.array(hands) if hands else np.array([])
|
|
|
|
return {
|
|
'bodies': {
|
|
'candidate': candidate_array,
|
|
'subset': subset_array
|
|
},
|
|
'faces': faces_array,
|
|
'hands': hands_array
|
|
}
|
|
|
|
|
|
def dwpose_format_to_pose_keypoint(candidate, faces, hands, canvas_width, canvas_height):
|
|
"""
|
|
Convert DWPose internal format back to POSE_KEYPOINT format
|
|
|
|
Args:
|
|
candidate: Body keypoints in DWPose format
|
|
faces: Face keypoints in DWPose format
|
|
hands: Hand keypoints in DWPose format
|
|
canvas_width: Canvas width for coordinate conversion
|
|
canvas_height: Canvas height for coordinate conversion
|
|
|
|
Returns:
|
|
list: POSE_KEYPOINT format data
|
|
"""
|
|
|
|
# Convert body keypoints
|
|
body_keypoints = []
|
|
if len(candidate) > 0:
|
|
for i in range(min(25, len(candidate))): # Support up to 25 points including toes
|
|
x = candidate[i][0] * canvas_width if canvas_width > 0 else candidate[i][0]
|
|
y = candidate[i][1] * canvas_height if canvas_height > 0 else candidate[i][1]
|
|
conf = candidate[i][2] if len(candidate[i]) > 2 else 1.0 # Use 1.0 instead of 0.0 for missing confidence
|
|
body_keypoints.extend([x, y, conf])
|
|
|
|
# Pad to 25 points if needed
|
|
while len(body_keypoints) < 75: # 25 * 3
|
|
body_keypoints.extend([0.0, 0.0, 0.0])
|
|
|
|
# Convert face keypoints
|
|
face_keypoints = []
|
|
if len(faces) > 0 and len(faces[0]) > 0:
|
|
for i in range(min(70, len(faces[0]))):
|
|
x = faces[0][i][0] * canvas_width if canvas_width > 0 else faces[0][i][0]
|
|
y = faces[0][i][1] * canvas_height if canvas_height > 0 else faces[0][i][1]
|
|
conf = faces[0][i][2] if len(faces[0][i]) > 2 else 1.0 # Use 1.0 instead of 0.0 for missing confidence
|
|
face_keypoints.extend([x, y, conf])
|
|
|
|
# Pad to 70 points if needed
|
|
while len(face_keypoints) < 210: # 70 * 3
|
|
face_keypoints.extend([0.0, 0.0, 0.0])
|
|
|
|
# Convert hand keypoints
|
|
lhand_keypoints = []
|
|
rhand_keypoints = []
|
|
|
|
if len(hands) > 0:
|
|
# Left hand
|
|
if len(hands[0]) > 0:
|
|
for i in range(min(21, len(hands[0]))):
|
|
x = hands[0][i][0] * canvas_width if canvas_width > 0 else hands[0][i][0]
|
|
y = hands[0][i][1] * canvas_height if canvas_height > 0 else hands[0][i][1]
|
|
conf = hands[0][i][2] if len(hands[0][i]) > 2 else 1.0 # Use 1.0 instead of 0.0 for missing confidence
|
|
lhand_keypoints.extend([x, y, conf])
|
|
|
|
# Right hand
|
|
if len(hands) > 1 and len(hands[1]) > 0:
|
|
for i in range(min(21, len(hands[1]))):
|
|
x = hands[1][i][0] * canvas_width if canvas_width > 0 else hands[1][i][0]
|
|
y = hands[1][i][1] * canvas_height if canvas_height > 0 else hands[1][i][1]
|
|
conf = hands[1][i][2] if len(hands[1][i]) > 2 else 1.0 # Use 1.0 instead of 0.0 for missing confidence
|
|
rhand_keypoints.extend([x, y, conf])
|
|
|
|
# Pad hand keypoints to 21 points if needed
|
|
while len(lhand_keypoints) < 63: # 21 * 3
|
|
lhand_keypoints.extend([0.0, 0.0, 0.0])
|
|
while len(rhand_keypoints) < 63: # 21 * 3
|
|
rhand_keypoints.extend([0.0, 0.0, 0.0])
|
|
|
|
# Create POSE_KEYPOINT structure
|
|
person_data = {
|
|
"pose_keypoints_2d": body_keypoints,
|
|
"face_keypoints_2d": face_keypoints,
|
|
"hand_left_keypoints_2d": lhand_keypoints,
|
|
"hand_right_keypoints_2d": rhand_keypoints
|
|
}
|
|
|
|
frame_data = {
|
|
"version": "1.0",
|
|
"people": [person_data] if len(candidate) > 0 else [],
|
|
"canvas_width": canvas_width,
|
|
"canvas_height": canvas_height
|
|
}
|
|
|
|
return frame_data |