Naming and tooltip adjustments

This commit is contained in:
kijai 2026-06-11 16:52:48 +03:00
parent 0d0b008b83
commit 3fe0a695b1

View File

@ -54,10 +54,10 @@ class SAM3DBody_Loader(io.ComfyNode):
io.Combo.Input( io.Combo.Input(
"model_file", "model_file",
options=folder_paths.get_filename_list("detection"), options=folder_paths.get_filename_list("detection"),
tooltip="SAM 3D Body weights (.safetensors) in the 'detection' folder",
), ),
], ],
outputs=[SAM3DBodyModel.Output("model", display_name="sam3d_body_model")], outputs=[SAM3DBodyModel.Output(display_name="sam3d_body_model")],
) )
@ -126,40 +126,35 @@ class SAM3DBody_Predict(io.ComfyNode):
def define_schema(cls): def define_schema(cls):
return io.Schema( return io.Schema(
node_id="SAM3DBody_Predict", node_id="SAM3DBody_Predict",
display_name="Predict SAM3D Body", display_name="Run SAM3D Body Prediction",
category="image/detection/sam3dbody/", category="image/detection",
inputs=[ inputs=[
SAM3DBodyModel.Input("sam3d_body_model"), SAM3DBodyModel.Input("sam3d_body_model"),
io.Image.Input("image"), io.Image.Input("image"),
SAM3TrackData.Input( SAM3TrackData.Input(
"sam3_track_data", optional=True, "track_data", optional=True,
tooltip=("Output of SAM3 Video Track, required for multi-person detection"), tooltip=("Tracking data from SAM3 Video Track, required for multi-person detection"),
), ),
io.BoundingBox.Input( io.BoundingBox.Input(
"bboxes", optional=True, force_input=True, "bboxes", optional=True, force_input=True,
tooltip=( tooltip=(
"Per-frame person boxes (e.g. RT-DETR Detect with class_name='person'). " "Per-frame bounding boxes used for better detection. Can be used as an alternative to tracking data. "
"Use for better detection as alternative to SAM3 tracks."
), ),
), ),
io.Boolean.Input( io.Boolean.Input(
"run_hand_refinement", default=True, "run_hand_refinement", default=True,
tooltip="Improves hand pose at the cost of extra inference time and memory use"), tooltip="Improves hand pose at the cost of extra inference time and memory use"),
io.Float.Input( io.Float.Input(
"fov_degrees", "fov",
default=0.0, min=0.0, max=170.0, step=0.5,
tooltip=( tooltip=(
"Vertical FOV in degrees. Affects predicted depth (cam_t.z) and " "Vertical FoV in degrees. Affects predicted depth and absolute scale. 0 = fall back to ~53° (16:9)."
"absolute scale. 0 = fall back to ~53° (16:9). Feed MoGeGeometryToFOV "
"here to derive it from a MoGe estimate."
), ),
), ),
io.Int.Input( io.Int.Input(
"chunk_size", #TODO: automate? "chunk_size", #TODO: automate?
default=64, min=1, max=512, step=1, advanced=True, default=64, min=1, max=512, step=1, advanced=True,
tooltip=( tooltip=(
"Max person-crops per forward. Higher = throughput + VRAM; " "Max frames to process as a batch. Larger values utilize more VRAM for faster inference."
"per-chunk frame count is chunk_size / persons_per_frame."
), ),
), ),
], ],
@ -167,7 +162,7 @@ class SAM3DBody_Predict(io.ComfyNode):
) )
@classmethod @classmethod
def execute(cls, sam3d_body_model, image, sam3_track_data=None, bboxes=None, run_hand_refinement=True, fov_degrees=0.0, chunk_size=64) -> io.NodeOutput: def execute(cls, sam3d_body_model, image, sam3_track_data=None, bboxes=None, run_hand_refinement=True, fov=0.0, chunk_size=64) -> io.NodeOutput:
comfy.model_management.load_model_gpu(sam3d_body_model) comfy.model_management.load_model_gpu(sam3d_body_model)
inner: SAM3DBody = sam3d_body_model.model inner: SAM3DBody = sam3d_body_model.model
@ -187,8 +182,8 @@ class SAM3DBody_Predict(io.ComfyNode):
per_frame_bboxes = [full_frame_bbox.clone() for _ in range(B)] per_frame_bboxes = [full_frame_bbox.clone() for _ in range(B)]
per_frame_masks = None per_frame_masks = None
inference_type = "full" if run_hand_refinement else "body" inference_type = "full" if run_hand_refinement else "body"
# fov_degrees > 0 sets intrinsics; else None falls back to prepare_batch's diagonal default. # fov > 0 sets intrinsics; else None falls back to prepare_batch's diagonal default.
cam_int = cam_int_from_fov(int(H), int(W), float(fov_degrees)) cam_int = cam_int_from_fov(int(H), int(W), float(fov))
frames_rgb: List[Optional[torch.Tensor]] = [] frames_rgb: List[Optional[torch.Tensor]] = []
for f in range(B): for f in range(B):
@ -259,8 +254,8 @@ class SAM3DBody_FaceExpression(io.ComfyNode):
display_name="Face Expression to SAM3D Body", #TODO: better name? display_name="Face Expression to SAM3D Body", #TODO: better name?
category="image/detection/sam3dbody/", category="image/detection/sam3dbody/",
inputs=[ inputs=[
MHRPoseData.Input("mhr_pose_data"),
SAM3DBodyModel.Input("sam3d_body_model"), SAM3DBodyModel.Input("sam3d_body_model"),
MHRPoseData.Input("mhr_pose_data"),
io.Image.Input("image"), io.Image.Input("image"),
io.Float.Input( io.Float.Input(
"strength", default=1.0, min=0.0, max=4.0, step=0.05, "strength", default=1.0, min=0.0, max=4.0, step=0.05,
@ -268,17 +263,17 @@ class SAM3DBody_FaceExpression(io.ComfyNode):
), ),
io.Float.Input( io.Float.Input(
"mouth_strength", default=1.0, min=0.0, max=4.0, step=0.05, "mouth_strength", default=1.0, min=0.0, max=4.0, step=0.05,
tooltip="Multiplier on mouth/jaw shapes. MP's jawOpen saturates near 1.0.", tooltip="Multiplier on mouth/jaw shapes. MediaPipe's jawOpen saturates near 1.0.",
advanced=True, advanced=True,
), ),
io.Float.Input( io.Float.Input(
"eye_strength", default=2.0, min=0.0, max=4.0, step=0.05, "eye_strength", default=2.0, min=0.0, max=4.0, step=0.05,
tooltip="Multiplier on eye shapes. MP rarely exceeds 0.5; 2-3x often needed.", tooltip="Multiplier on eye shapes. MediaPipe rarely exceeds 0.5; 2-3x often needed.",
advanced=True, advanced=True,
), ),
io.Float.Input( io.Float.Input(
"brow_strength", default=2.0, min=0.0, max=4.0, step=0.05, "brow_strength", default=2.0, min=0.0, max=4.0, step=0.05,
tooltip="Multiplier on brow/cheek/sneer shapes. MP outputs ~0.1-0.3; 2-3x.", tooltip="Multiplier on brow/cheek/sneer shapes. MediaPipe outputs ~0.1-0.3; 2-3x.",
advanced=True, advanced=True,
), ),
io.Float.Input( io.Float.Input(
@ -451,23 +446,23 @@ class SAM3DBody_Smooth(io.ComfyNode):
def define_schema(cls): def define_schema(cls):
return io.Schema( return io.Schema(
node_id="SAM3DBody_Smooth", node_id="SAM3DBody_Smooth",
description="Reduce frame-to-frame jitter via vertex-space temporal averaging", description="Reduce frame-to-frame jitter via temporal smoothing.",
display_name="Smooth SAM3D Body Pose Frames", display_name="Smooth SAM3D Body Pose Data",
category="image/detection/sam3dbody/", category="image/detection/sam3dbody/",
inputs=[ inputs=[
MHRPoseData.Input("mhr_pose_data"), MHRPoseData.Input("mhr_pose_data"),
io.Float.Input( io.Float.Input(
"strength", "strength",
default=1.0, min=0.0, max=1.0, step=0.05, default=1.0, min=0.0, max=1.0, step=0.05,
tooltip="Blend raw (0) → smoothed (1).", tooltip="Smoothing strength. 0 = raw, 1 = smoothed.",
), ),
io.Combo.Input( io.Combo.Input(
"method", "method",
options=["gaussian", "savgol"], options=["gaussian", "savgol"],
default="gaussian", advanced=True, default="gaussian", advanced=True,
tooltip=( tooltip=(
"'gaussian': symmetric weighted average, best general-purpose smoother. " "gaussian: symmetric weighted average, best general-purpose smoother./n"
"'savgol': sliding polynomial fit, preserves sharp peaks." "savgol: sliding polynomial fit, preserves sharp peaks."
), ),
), ),
io.Int.Input( io.Int.Input(
@ -477,11 +472,11 @@ class SAM3DBody_Smooth(io.ComfyNode):
), ),
io.Float.Input( io.Float.Input(
"rotation_threshold_deg", "rotation_threshold_deg",
default=15.0, min=0.0, max=45.0, step=1.0, advanced=True, default=30.0, min=0.0, max=90.0, step=1.0, advanced=True,
tooltip=( tooltip=(
"Disables smoothing for this root-rotation rate (deg/frame) to preserve fast spins. " "Disables smoothing for this root rotation rate (degree/frame) to preserve fast spins. "
"15° suits most content, low values trigger on ordinary jitter and " "30° suits most content, low values might disable smoothing on ordinary jitter and "
"silently sabotage smoothing. 0 = disable." "silently impacts quality. 0 = disable."
), ),
), ),
], ],
@ -870,11 +865,9 @@ class SAM3DBody_Render(io.ComfyNode):
), ),
), ),
io.Float.Input( io.Float.Input(
"camera_fov", default=0.0, min=0.0, max=170.0, step=0.5, advanced=True, "fov", default=0.0, min=0.0, max=170.0, step=0.5, advanced=True,
tooltip=( tooltip=(
"Vertical FOV for the camera_info override. 0 = keep the SAM3D " "Override the vertical FoV of the camera_info. Ignored when camera_info is empty. 0 = keep the FoV of the camera_info."
"predicted camera's FOV (only the viewpoint changes). Any non-zero "
"value overrides the lens. Ignored when camera_info is unwired."
), ),
), ),
io.DynamicCombo.Input( io.DynamicCombo.Input(
@ -900,7 +893,7 @@ class SAM3DBody_Render(io.ComfyNode):
@classmethod @classmethod
def execute(cls, mhr_pose_data, background=None, width=0, height=0, camera_info=None, camera_fov=0.0, render_style=None) -> io.NodeOutput: def execute(cls, mhr_pose_data, background=None, width=0, height=0, camera_info=None, fov=0.0, render_style=None) -> io.NodeOutput:
render_style = render_style or {"render_style": "mesh"} render_style = render_style or {"render_style": "mesh"}
mode_key = render_style.get("render_style", "mesh") mode_key = render_style.get("render_style", "mesh")
@ -919,7 +912,7 @@ class SAM3DBody_Render(io.ComfyNode):
px_scale = min(new_W / native_W, new_H / native_H) px_scale = min(new_W / native_W, new_H / native_H)
if camera_info is not None: if camera_info is not None:
mhr_pose_data = apply_camera_override(mhr_pose_data, camera_info, H, W, fov_deg=float(camera_fov)) mhr_pose_data = apply_camera_override(mhr_pose_data, camera_info, H, W, fov_deg=float(fov))
B = len(mhr_pose_data["frames"]) B = len(mhr_pose_data["frames"])
if B == 0: if B == 0: