wip
This commit is contained in:
@@ -27,8 +27,6 @@ class OpenPoseRotator:
|
||||
"optional": {
|
||||
"pose_keypoint": ("POSE_KEYPOINT",),
|
||||
"debug": ("BOOLEAN", {"default": False}),
|
||||
"perspective": ("FLOAT", {"default": 0.0, "min": -0.5, "max": 0.5, "step": 0.01}),
|
||||
"focal_length": ("FLOAT", {"default": 800.0, "min": 100.0, "max": 5000.0, "step": 50.0}),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -40,11 +38,11 @@ class OpenPoseRotator:
|
||||
mode: str,
|
||||
pose_keypoint: list | None = None,
|
||||
debug: bool = False,
|
||||
perspective: float = 0.0,
|
||||
focal_length: float = 800.0,
|
||||
) -> tuple[torch.Tensor, list]:
|
||||
"""
|
||||
Rotate OpenPose figure(s) around torso. Processes batch of images.
|
||||
Advanced mode uses a fixed 35° camera elevation and ~90% figure fill to
|
||||
automatically derive perspective and focal-length — no manual tuning needed.
|
||||
Returns (image_tensor, rotated_pose_keypoints_list).
|
||||
"""
|
||||
batch_size = image.shape[0]
|
||||
@@ -72,8 +70,6 @@ class OpenPoseRotator:
|
||||
image_index=i,
|
||||
debug=debug,
|
||||
mode=mode,
|
||||
perspective=perspective,
|
||||
focal_length=focal_length,
|
||||
)
|
||||
|
||||
if not success:
|
||||
|
||||
+43
-7
@@ -405,11 +405,17 @@ def _compute_adaptive_depth_scale(
|
||||
return 0.4 * (120.0 / shoulder_width)
|
||||
|
||||
|
||||
# Perspective scale_y: (cy - y) is in pixels; this scales the term so perspective has visible effect.
|
||||
# At 0.3, perspective=0.5 with a point 200px above pivot contributes 30 z-units, shifting x by
|
||||
# ~5px at 10° and ~21px at 45° — clearly perceptible without being overwhelming.
|
||||
# Perspective scale_y: bridges the raw (cy - y) pixel value to z-units.
|
||||
# In advanced mode the coefficient is derived geometrically from ADVANCED_CAMERA_ELEVATION_DEG;
|
||||
# this constant keeps the formula consistent: z += perspective * (cy - y) * PERSPECTIVE_SCALE_Y.
|
||||
PERSPECTIVE_SCALE_Y = 0.3
|
||||
|
||||
# Advanced mode: fixed physical camera / figure assumptions.
|
||||
# Camera is elevated 35° above horizontal, looking at a standing figure that fills
|
||||
# roughly 80-100% (average ~90%) of the image height.
|
||||
ADVANCED_CAMERA_ELEVATION_DEG = 35.0
|
||||
ADVANCED_FIGURE_FILL = 0.90
|
||||
|
||||
# Ankle y-parity threshold: fraction of figure height (neck→lower ankle) within which both ankles
|
||||
# are considered to be at the same elevation (standing upright on flat ground).
|
||||
UPRIGHT_ANKLE_THRESHOLD = 0.08
|
||||
@@ -455,6 +461,28 @@ def _detect_upright_figure(
|
||||
return True, neck, ankle_mid
|
||||
|
||||
|
||||
def _compute_advanced_params(image_height: int) -> tuple[float, float]:
|
||||
"""
|
||||
Derive perspective and focal_length for advanced mode from fixed camera/figure assumptions.
|
||||
|
||||
Camera elevation θ = ADVANCED_CAMERA_ELEVATION_DEG (35°) above horizontal.
|
||||
Figure fills ADVANCED_FIGURE_FILL (~90%) of image height.
|
||||
|
||||
perspective: maps vertical pixel distance from pivot to depth.
|
||||
Formula: z += perspective * (cy - y) * PERSPECTIVE_SCALE_Y
|
||||
For geometric accuracy: perspective * PERSPECTIVE_SCALE_Y = tan(θ)
|
||||
→ perspective = tan(35°) / 0.3 ≈ 2.33
|
||||
|
||||
focal_length: perspective projection strength, scaled to image resolution.
|
||||
From pinhole geometry: focal_length = image_height * fill / tan(θ)
|
||||
At 35° with 90% fill → focal_length ≈ 1.29 × image_height
|
||||
"""
|
||||
tan_elev = math.tan(math.radians(ADVANCED_CAMERA_ELEVATION_DEG))
|
||||
perspective = tan_elev / PERSPECTIVE_SCALE_Y
|
||||
focal_length = image_height * ADVANCED_FIGURE_FILL / tan_elev
|
||||
return perspective, focal_length
|
||||
|
||||
|
||||
def rotate_keypoints_3d(
|
||||
keypoints: dict[str, list[tuple[float, float, float]]],
|
||||
pivot: tuple[float, float],
|
||||
@@ -834,19 +862,27 @@ def rotate_openpose(
|
||||
image_index: int = 0,
|
||||
debug: bool = False,
|
||||
mode: str = "simple",
|
||||
perspective: float = 0.0,
|
||||
focal_length: float = 800.0,
|
||||
) -> tuple[np.ndarray, bool, dict[str, list[tuple[float, float, float]]] | None]:
|
||||
"""
|
||||
Main pipeline: extract/parse keypoints, detect torso, rotate, render.
|
||||
Returns (output_image, success, rotated_keypoints). On failure, returns (input_image, False, None).
|
||||
rotated_keypoints is internal format: {"body": [(x,y,c),...], "hand_left": [...], ...}
|
||||
image_index: used for console logging when processing batches.
|
||||
mode: "simple" or "advanced". perspective: 0=eye level, >0=camera above, <0=camera below.
|
||||
focal_length: (advanced only) perspective strength; higher=flatter.
|
||||
|
||||
mode: "simple" uses orthographic projection at eye level (perspective=0).
|
||||
"advanced" uses perspective projection with camera parameters derived from
|
||||
ADVANCED_CAMERA_ELEVATION_DEG (35°) and ADVANCED_FIGURE_FILL (90%), which
|
||||
gives geometrically correct depth inference and focal length for the assumed pose.
|
||||
"""
|
||||
h, w = image.shape[:2]
|
||||
|
||||
# Derive camera parameters from mode and fixed assumptions
|
||||
if mode == "advanced":
|
||||
perspective, focal_length = _compute_advanced_params(h)
|
||||
else:
|
||||
perspective = 0.0
|
||||
focal_length = 800.0 # unused in simple (orthographic) mode
|
||||
|
||||
# Get keypoints
|
||||
if pose_keypoint is not None:
|
||||
keypoints = parse_pose_keypoint(pose_keypoint)
|
||||
|
||||
Reference in New Issue
Block a user