Nodes/ComfyUI DocRes/DDC Rectify
ComfyUI Node

DDC Rectify

Flattens the page, and you don't get to pick the output size

By zjkhurry·Created 22 days ago·Updated 21 days ago· 1
DDC Rectify
  • image
  • points
  • image
  • preview

DDC Rectify is where the actual flattening happens. Everything before it - the network prediction, your dragging - has produced nothing but a grid of coordinates. This node takes that grid and warps the page through it, which is the only point in the DDC chain where pixels move.

It's also the node with the least to configure: two inputs, no widgets.

The mechanism, and why the output size is what it is

The interesting part is what happens between the drags and the warp. You only moved a handful of the 81 handles, but the warp is fitted to the full 31x31 grid. So the node lifts your edits back onto the fine grid by fitting a thin-plate spline displacement field: it matches your handles exactly, while every point you didn't touch acts as a weak prior pulling toward the network's original prediction. The result is a smooth mesh that follows your intent instead of a kinked surface with 80 spikes in it. The same spline then does the actual sampling.

Two consequences worth knowing before you blame the node:

The output size is a model decision, not a node setting. There's no width or height input, because DocRes's network predicts a segment head - a pair of numbers the network uses to say how big the flattened page should be. Rectify multiplies that out, rounds it, and uses it as the output resolution, mirroring the upstream project. So a page comes back at whatever size the net thinks a flat version of it is, and you resize downstream if you disagree.

The spline runs on the CPU, in float64, always. MPS has no float64 support, so this isn't a setting you've missed - it's a hard requirement of the solve. It's one solve per page, not per pixel, so it's fine in practice, but don't expect it to be instant on a very large scan.

Inputs and outputs

image - the clean canvas from DDC Edit Points' image output. Not preview. Wiring the preview is the classic mistake here: those dots are real pixels and they will be warped straight into your flattened page.

points (DDC_EDITED_POINTS) - from DDC Edit Points, edited or not. It's the only node that emits this type, so there's no way to jump straight from prediction to warp.

You get two outputs, and they're easy to tell apart once you know:

  • image - the rectified page. The one you save or chain on.
  • preview - the input canvas with the grid that was actually used for this warp drawn back over it. It's a QA output: it exists so you can see what produced the result and whether your handles landed where you thought.

Install

cd ComfyUI/custom_nodes
git clone https://github.com/zjkhurry/comfyui-docres.git
pip install -r comfyui-docres/requirements.txt

Restart, and the nodes appear under image/DocRes. Manager can install it too - search DocRes. Dependencies are einops, opencv-python, scikit-image and safetensors, with scikit-image the only one you probably don't already have. This node has no weights of its own; the 51 MB control-point model is fetched by DDC Predict Points, and the spline is pure maths.

Where people get burned

Feeding it the marked preview image. Repeated here because it's the one that actually ruins output. Dots in, dots out.

Expecting rectification to clean the page. It fixes geometry and nothing else. Shading, bleed-through, colour cast and blur all survive the warp untouched - chain a deshadowing or appearance pass from DocRes Restore after this node if the scan needs it. The two halves of the pack are independent, and stacking them is the intended workflow.

Wondering why the page looks squashed. The segment head is a quantised prediction. On an extreme page - a badly curled book shot from an angle - it can decide the flat page is a fairly modest size, and you'll notice the aspect. That's the model's estimate of the real page, not a crop bug.

A grid that didn't follow your edits. If the page comes back warped as if you'd never touched it, the edit data wasn't applied - usually because the image arriving at the editor is a different size from the one your drags were recorded against. Fix it upstream in DDC Edit Points: redo the drags on the current image and they'll stick.

Categoryimage/DocRes

Inputs (2)

NameTypeDefaultDescription
imageIMAGE—
pointsDDC_EDITED_POINTS—

Outputs (2)

NameTypeDescription
imageIMAGE—
previewIMAGE—