Nodes/ComfyUI-NKD-VFX-Tools/😺NKD fSpy Camera
ComfyUI Node

😺NKD fSpy Camera

Find the Camera That Took the Photo, From Two Pairs of Vanishing Lines

By Nekodificador·Created 6 months ago·Updated a day ago· 155
😺NKD fSpy Camera
  • image
  • camera_info
  • image
  • fov_vertical
  • focal_length_mm
  • width
  • height
â—„fspy_state{"mode": "2point", "vp1": [[0.15, 0.35], [0.45, 0.3], [0.15, 0.65], [0.45, 0.7]], "vp2": [[0.55, 0.3], [0.85, 0.35], [0.55, 0.7], [0.85, 0.65]], "principalPoint": {"mode": "center"}, "vp1Axis": "x+", "vp2Axis": "z+", "origin": [0.5, 0.5], "distance": 5.0}â–º

A generated object floating on top of a photo instead of standing in it is usually a camera problem, not a model problem. If you want something added to a shot to share its perspective, you need the shot's lens. That's what fSpy Camera is for: you drag two pairs of vanishing lines over a photo and it solves the camera that took it. It's the fSpy workflow - the open-source camera-matching app and its Blender importer - brought inside ComfyUI so you never have to leave the graph to do it.

How it works

The 2-point vanishing-point solve is a classic. Each pair of lines you draw (along floorboards, table edges, a building's roofline) intersects at a vanishing point. Two vanishing points give you the focal length - the constraint is f² = -(Fu − P)·(Fv − P), the dot product of the two VP directions from the principal point - and the camera's orientation. The node carries the name as credit and implements the same solve; the package is GPL-3.0 like fSpy itself.

One honest limit: it solves orientation and FOV only. There's no absolute camera position, because fSpy can't know scene scale without a reference distance. The camera is placed at a nominal distance looking at the origin, which is all you need for matching perspective.

What you set and what you get

  • image - the reference photo, from a Load Image node. It also passes through unchanged, so you don't need a second copy to feed downstream.
  • fspy_state - the JSON of your line placements. You won't type this; you drag the vanishing lines on the node's viewport, and this widget just stores the result (which is how the state survives a workflow save).

Outputs are the useful part:

  • camera_info (LOAD3D_CAMERA) - wire this into NKD Preview 3D so your model sits in the photo's real perspective.
  • focal_length_mm - wire this into NKD Perspective Unwarp's Metric mode and the flattened aspect ratio comes out true instead of estimated.
  • fov_vertical, plus width and height - handy scalars if anything else in your graph wants the lens numbers.

Install and troubleshooting

Same as the whole pack: ComfyUI Manager → search "NKD VFX Tools" → install → restart. No models to download.

Practical advice from the mechanism: pick lines that are actually parallel in the real world, and place each pair far enough apart that they intersect cleanly. Near-parallel lines make the solve fragile or fail outright, and if both vanishing points get assigned to the same axis the solve returns nothing - the third axis is derived from the two you pick. Don't expect a full 3D tracker out of this; it's a lens and an orientation, which is exactly the right tool for making added objects sit in the shot rather than on top of it.

Category😺NKD Nodes/3D

Inputs (2)

NameTypeDefaultDescription
imageIMAGEReference photo (e.g. from a Load Image node). Also passed through to Preview3D's bg_image.
fspy_stateSTRING{"mode": "2point", "vp1": [[0.15, 0.35], [0.45, 0.3], [0.15, 0.65], [0.45, 0.7]], "vp2": [[0.55, 0.3], [0.85, 0.35], [0.55, 0.7], [0.85, 0.65]], "principalPoint": {"mode": "center"}, "vp1Axis": "x+", "vp2Axis": "z+", "origin": [0.5, 0.5], "distance": 5.0}—

Outputs (6)

NameTypeDescription
camera_infoLOAD3D_CAMERA—
imageIMAGE—
fov_verticalFLOAT—
focal_length_mmFLOAT—
widthINT—
heightINT—