Files
grmchnandClaude c059e7896f Fix ProportionChanger Reference rendering to show black screen when pose detection fails
- Remove debug colored dots (red, green, blue) from DWPose render when no valid keypoints
- Remove debug white circle when no valid keypoints detected
- Failed pose detection now properly displays black screen instead of test markers
- Affects ProportionChanger DWPose Render node when reference pose detection fails

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-03 16:48:57 +09:00

338 lines
14 KiB
Python

"""
DWPose rendering utilities for drawing poses on canvas
Handles body, hand, and face keypoint visualization with DWPose styling
"""
import cv2
import math
import numpy as np
import colorsys
import os
import logging
# Debug mode control via environment variable (local implementation to avoid imports)
DEBUG_MODE = os.getenv('PROPORTION_CHANGER_DEBUG', 'false').lower() in ('true', '1', 'yes')
log = logging.getLogger(__name__)
def debug_log(message):
"""Conditional debug logging - only outputs if DEBUG_MODE is enabled"""
if DEBUG_MODE:
log.debug(f"🔍 {message}")
def draw_dwpose_render(pose_keypoint, resolution_x, show_body, show_face, show_hands, show_feet,
pose_marker_size, face_marker_size, hand_marker_size):
"""
Render POSE_KEYPOINT data using DWPose style with 25-point support including toe keypoints
Compatible with ultimate-openpose-render parameters but using DWPose rendering algorithms
"""
if not pose_keypoint or len(pose_keypoint) == 0:
return []
pose_imgs = []
# Handle single frame vs multi-frame input
if isinstance(pose_keypoint, dict):
frames = [pose_keypoint]
else:
frames = pose_keypoint
for frame_data in frames:
if 'people' not in frame_data or len(frame_data['people']) == 0:
# Create empty image for frames with no people
H = frame_data.get('canvas_height', 768)
W = frame_data.get('canvas_width', 512)
if resolution_x > 0:
W = resolution_x
H = int(frame_data.get('canvas_height', 768) * (W / frame_data.get('canvas_width', 512)))
pose_imgs.append(np.zeros((H, W, 3), dtype=np.uint8))
continue
# Get canvas dimensions
H = frame_data.get('canvas_height', 768)
W = frame_data.get('canvas_width', 512)
# Apply resolution scaling
if resolution_x > 0:
W_scaled = resolution_x
H_scaled = int(H * (W_scaled / W))
else:
W_scaled, H_scaled = W, H
# Create canvas
canvas = np.zeros((H_scaled, W_scaled, 3), dtype=np.uint8)
# Process each person in the frame
for person in frame_data['people']:
# Draw body keypoints
if show_body and 'pose_keypoints_2d' in person:
canvas = draw_dwpose_body_and_foot(canvas, person['pose_keypoints_2d'],
W_scaled, H_scaled, pose_marker_size, show_feet)
# Draw hand keypoints
if show_hands:
if 'hand_left_keypoints_2d' in person:
canvas = draw_dwpose_handpose(canvas, person['hand_left_keypoints_2d'],
W_scaled, H_scaled, hand_marker_size)
if 'hand_right_keypoints_2d' in person:
canvas = draw_dwpose_handpose(canvas, person['hand_right_keypoints_2d'],
W_scaled, H_scaled, hand_marker_size)
# Draw face keypoints
if show_face and 'face_keypoints_2d' in person:
canvas = draw_dwpose_facepose(canvas, person['face_keypoints_2d'],
W_scaled, H_scaled, face_marker_size)
pose_imgs.append(canvas)
return pose_imgs
def draw_dwpose_body_and_foot(canvas, body_keypoints, W, H, pose_marker_size, show_feet):
"""
Draw body and foot keypoints using DWPose style (25-point support)
Based on WanVideo DWPose draw_body_and_foot function
"""
if not body_keypoints or len(body_keypoints) < 54: # At least 18 points * 3
return canvas
# Define limb connections (bone structure)
if show_feet and len(body_keypoints) >= 75: # 25 points * 3
# DWPose 25-point with toe connections
limbSeq = [[2, 3], [2, 6], [3, 4], [4, 5], [6, 7], [7, 8], [2, 9], [9, 10],
[10, 11], [2, 12], [12, 13], [13, 14], [2, 1], [1, 15], [15, 17],
[1, 16], [16, 18], [14, 19], [11, 20]] # Added toe connections
else:
# Standard 18-point OpenPose
limbSeq = [[2, 3], [2, 6], [3, 4], [4, 5], [6, 7], [7, 8], [2, 9], [9, 10],
[10, 11], [2, 12], [12, 13], [13, 14], [2, 1], [1, 15], [15, 17],
[1, 16], [16, 18]]
# Color palette for bones
colors = [[255, 0, 0], [255, 85, 0], [255, 170, 0], [255, 255, 0], [170, 255, 0], [85, 255, 0], [0, 255, 0],
[0, 255, 85], [0, 255, 170], [0, 255, 255], [0, 170, 255], [0, 85, 255], [0, 0, 255], [85, 0, 255],
[170, 0, 255], [255, 0, 255], [255, 0, 170], [255, 0, 85], [170, 255, 255], [255, 255, 0]]
# First pass: determine coordinate system by checking all coordinates
max_coord = 0
for i in range(0, len(body_keypoints), 3):
if i + 2 < len(body_keypoints):
x_raw = body_keypoints[i]
y_raw = body_keypoints[i + 1]
if x_raw > 0 and y_raw > 0:
max_coord = max(max_coord, x_raw, y_raw)
# Determine if coordinates are normalized or already in pixel space
is_normalized = max_coord <= 2.0
# Convert keypoints to coordinate pairs with consistent coordinate system
keypoints = []
confidences = []
for i in range(0, len(body_keypoints), 3):
if i + 2 < len(body_keypoints):
x_raw = body_keypoints[i]
y_raw = body_keypoints[i + 1]
conf = body_keypoints[i + 2]
# Apply consistent coordinate transformation
if is_normalized:
# Data is normalized (0-1), convert to pixel coordinates
x = x_raw * W
y = y_raw * H
else:
# Data is already in pixel coordinates, use as-is
x = x_raw
y = y_raw
keypoints.append([x, y])
confidences.append(conf)
# Debug: check if we have valid keypoints
valid_keypoints = sum(1 for conf in confidences if conf > 0.0)
debug_log(f"Body Debug - Canvas size: {W}x{H}, Max coord: {max_coord:.4f}, Normalized: {is_normalized}")
debug_log(f"Body Debug - Valid keypoints: {valid_keypoints}/{len(confidences)}")
debug_log(f"Body Debug - First 3 keypoints: {[(i, f'{keypoints[i][0]:.1f}, {keypoints[i][1]:.1f}', f'{confidences[i]:.3f}') for i in range(min(3, len(keypoints)))]}")
if valid_keypoints == 0:
debug_log("Body Debug - No valid keypoints, returning black screen")
# Return black screen for failed pose detection
return canvas
# Draw limb connections (bones)
bones_drawn = 0
for i, limb in enumerate(limbSeq):
if len(keypoints) >= max(limb[0], limb[1]):
pt1_idx, pt2_idx = limb[0] - 1, limb[1] - 1 # Convert to 0-based indexing
# Use more lenient confidence threshold
if (pt1_idx < len(confidences) and pt2_idx < len(confidences) and
confidences[pt1_idx] > 0.0 and confidences[pt2_idx] > 0.0):
x1, y1 = keypoints[pt1_idx]
x2, y2 = keypoints[pt2_idx]
# More lenient coordinate check
if x1 >= 0 and y1 >= 0 and x2 >= 0 and y2 >= 0:
# Calculate bone properties (following WanVideo DWPose convention)
# Note: WanVideo uses X=height, Y=width convention
X1, Y1 = y1, x1 # Convert to WanVideo coordinate convention
X2, Y2 = y2, x2
mX = (X1 + X2) / 2 # Mean height coordinate
mY = (Y1 + Y2) / 2 # Mean width coordinate
length = ((X1 - X2) ** 2 + (Y1 - Y2) ** 2) ** 0.5
if length > 1: # Only draw if bone has reasonable length
# Use WanVideo's angle calculation
angle = math.degrees(math.atan2(X1 - X2, Y1 - Y2))
# Draw bone as ellipse polygon (note coordinate order: Y, X)
stick_width = max(1, pose_marker_size)
polygon = cv2.ellipse2Poly((int(mY), int(mX)),
(int(length / 2), stick_width),
int(angle), 0, 360, 1)
color_idx = min(i, len(colors) - 1)
cv2.fillConvexPoly(canvas, polygon, colors[color_idx])
bones_drawn += 1
# Apply transparency to bones only if bones were drawn
if bones_drawn > 0:
canvas = (canvas * 0.6).astype(np.uint8)
# Draw keypoint markers
if pose_marker_size > 0:
max_points = min(len(keypoints), 25 if show_feet else 18)
points_drawn = 0
for i in range(max_points):
if i < len(confidences) and confidences[i] > 0.0:
x, y = keypoints[i]
if x >= 0 and y >= 0 and x < W and y < H:
color_idx = min(i, len(colors) - 1)
cv2.circle(canvas, (int(x), int(y)), pose_marker_size, colors[color_idx], thickness=-1)
points_drawn += 1
# No debug points - let failed poses show as black screen
return canvas
def draw_dwpose_handpose(canvas, hand_keypoints, W, H, hand_marker_size):
"""
Draw hand keypoints using DWPose style
Based on WanVideo DWPose draw_handpose function
"""
if not hand_keypoints or len(hand_keypoints) < 63: # 21 points * 3
return canvas
# Hand bone connections
edges = [[0, 1], [1, 2], [2, 3], [3, 4], [0, 5], [5, 6], [6, 7], [7, 8], [0, 9], [9, 10],
[10, 11], [11, 12], [0, 13], [13, 14], [14, 15], [15, 16], [0, 17], [17, 18], [18, 19], [19, 20]]
# First pass: determine coordinate system
max_coord = 0
for i in range(0, len(hand_keypoints), 3):
if i + 2 < len(hand_keypoints):
x_raw = hand_keypoints[i]
y_raw = hand_keypoints[i + 1]
if x_raw > 0 and y_raw > 0:
max_coord = max(max_coord, x_raw, y_raw)
is_normalized = max_coord <= 2.0
# Convert keypoints to coordinate pairs with consistent coordinate system
keypoints = []
confidences = []
for i in range(0, len(hand_keypoints), 3):
if i + 2 < len(hand_keypoints):
x_raw = hand_keypoints[i]
y_raw = hand_keypoints[i + 1]
conf = hand_keypoints[i + 2]
# Apply consistent coordinate transformation
if is_normalized:
x = x_raw * W
y = y_raw * H
else:
x = x_raw
y = y_raw
keypoints.append([x, y])
confidences.append(conf)
# Draw hand connections
if hand_marker_size > 0:
for ie, edge in enumerate(edges):
if (len(keypoints) > max(edge) and
confidences[edge[0]] > 0.0 and confidences[edge[1]] > 0.0):
x1, y1 = keypoints[edge[0]]
x2, y2 = keypoints[edge[1]]
if x1 >= 0 and y1 >= 0 and x2 >= 0 and y2 >= 0:
# Generate color using HSV
h = (ie / float(len(edges))) % 1.0
r, g, b = colorsys.hsv_to_rgb(h, 1.0, 1.0)
color = (int(255 * r), int(255 * g), int(255 * b))
cv2.line(canvas, (int(x1), int(y1)), (int(x2), int(y2)), color, thickness=2)
# Draw hand keypoints
if hand_marker_size > 0:
for i, (x, y) in enumerate(keypoints):
if i < len(confidences) and confidences[i] > 0.0 and x >= 0 and y >= 0:
cv2.circle(canvas, (int(x), int(y)), hand_marker_size, (0, 0, 255), thickness=-1)
return canvas
def draw_dwpose_facepose(canvas, face_keypoints, W, H, face_marker_size):
"""
Draw face keypoints using DWPose style
Based on WanVideo DWPose draw_facepose function
"""
if not face_keypoints or len(face_keypoints) < 210: # 70 points * 3
return canvas
# First pass: determine coordinate system
max_coord = 0
for i in range(0, len(face_keypoints), 3):
if i + 2 < len(face_keypoints):
x_raw = face_keypoints[i]
y_raw = face_keypoints[i + 1]
if x_raw > 0 and y_raw > 0:
max_coord = max(max_coord, x_raw, y_raw)
is_normalized = max_coord <= 2.0
# Convert keypoints to coordinate pairs with consistent coordinate system
keypoints = []
confidences = []
for i in range(0, len(face_keypoints), 3):
if i + 2 < len(face_keypoints):
x_raw = face_keypoints[i]
y_raw = face_keypoints[i + 1]
conf = face_keypoints[i + 2]
# Apply consistent coordinate transformation
if is_normalized:
x = x_raw * W
y = y_raw * H
else:
x = x_raw
y = y_raw
keypoints.append([x, y])
confidences.append(conf)
# Draw face keypoints
if face_marker_size > 0:
for i, (x, y) in enumerate(keypoints):
if i < len(confidences) and confidences[i] > 0.0 and x >= 0 and y >= 0:
cv2.circle(canvas, (int(x), int(y)), face_marker_size, (255, 255, 255), thickness=-1)
return canvas