Warp a Netpbm Image with pamrubber Control Points
pamrubber moves pixels towards new coordinates you give it, which is the fastest way to correct a skewed scan or pull a document's corners square. Expect about fifteen minutes to get a first transform out and verified. The examples use pamrubber from Netpbm 2:11.05.02-1.1build1, installed on this machine.
The route
Jump straight to the step you need, or tick off Done means at the end.
- You need: a readable PAM, PGM or other Netpbm image, its width and height (so you can pick sensible points), and a writable working directory.
- It will not touch: the input file. pamrubber writes the transformed image to standard output, so every example below ends in a shell redirection.
1. Check the installed command
Confirm which executable will run and skim the local manual before you commit points to a script. This is a read-only check, no privileges needed:
$ command -v pamrubber
/usr/bin/pamrubber
$ dpkg-query -W -f='${Package} ${Version}\n' netpbm
netpbm 2:11.05.02-1.1build1
$ man pamrubber
pamrubber needs exactly one of -tri or -quad, plus control-point coordinates and an optional input filename. Leave the filename out and it reads from standard input instead.
Checkpoint
If command -v points somewhere unexpected, or the package query does not describe your host, treat everything below as a starting point and check that installation's own manual first.
2. Understand the two coordinate lists
pamrubber wants one list of source points and one list of target points, each an x y pair, both lists the same length. Source coordinates describe the input image, target coordinates describe where those points end up in the output, and the output keeps the input's dimensions and format.
These four source points are the corners of a 4 by 4 image, in perimeter order. The target list pulls the top-right corner inwards:
source: 0 0 3 0 3 3 0 3
target: 0 0 2 0 3 3 0 3
- One point. pamrubber fills in the rest of the geometry differently depending on the mode.
- Two points. Used as opposite corners in quadrilateral mode.
- Three points. A fourth point gets constructed to make a parallelogram.
Those defaults are handy for a quick pull, but explicit points are far easier for the next person (or you, in six months) to read back out of a script.
3. Run a small triangle-mode transform
Triangle mode divides the image into corresponding triangular regions. This one-point example maps source point (0, 0) to target point (1, 1):
$ pamrubber -tri -randomseed=7 0 0 1 1 input.pam > output-tri.pam
$ pamfile output-tri.pam
output-tri.pam: PGM raw, 4 by 4 maxval 255
Swap in your own file for input.pam. The sample line came from a small PGM input, so your format, dimensions and maxval will likely differ; what matters is a zero exit status, a non-empty destination and a recognised Netpbm header.
-tri and -randomseed=7 are ordinary user commands, no sudo required. Keep the original input until you've inspected the result.
4. Use quadrilateral mode for four corners
Reach for -quad when both source and target are quadrilaterals, such as a photographed document whose corners need squaring up. All source coordinates come first, then all target coordinates:
$ pamrubber -quad -linear -randomseed=7 \
0 0 3 0 3 3 0 3 \
0 0 2 0 3 3 0 3 \
input.pam > output-quad.pam
$ pamfile output-quad.pam
output-quad.pam: PGM raw, 4 by 4 maxval 255
The four points should trace the corners in matching perimeter order; cross that order and you can get an invalid or just plain weird quadrilateral. Scale the example to your own image: for a WIDTH by HEIGHT image, the last corner is normally WIDTH-1 HEIGHT-1, not WIDTH HEIGHT.
-linear selects bilinear interpolation of four source pixels, which usually looks less blocky on a geometric transform. Leave it off for nearest-neighbour, which is preferable when exact source values must survive the trip.
5. Make runs reproducible
pamrubber randomises part of its output, and by default seeds from the time of day, so two runs of the same command can differ. Set -randomseed=N whenever a repeatable result matters:
$ pamrubber -tri -randomseed=7 0 0 1 1 input.pam > run-a.pam
$ pamrubber -tri -randomseed=7 0 0 1 1 input.pam > run-b.pam
$ cmp -- run-a.pam run-b.pam
$ echo $?
0
A zero status from cmp means the two files are byte-for-byte identical on this installation. Record the seed alongside the command whenever the output feeds a test, build or review.
Tip
Older Netpbm releases spelled this option -randseed. The installed manual documents -randomseed and says the old spelling still works, so you may meet either in the wild.
6. Add a diagnostic frame when checking geometry
-frame overlays the target image with the edges of the triangles or quadrilaterals used for the transform, handy for eyeballing point order. It changes the pixels, so it is a diagnostic tool, not the final image:
$ pamrubber -quad -frame -randomseed=7 \
0 0 3 0 3 3 0 3 0 0 3 0 3 3 0 3 \
input.pam > frame-check.pam
$ pamfile frame-check.pam
frame-check.pam: PGM raw, 4 by 4 maxval 255
Use identical source and target points to see the same overlay on the source geometry instead. Inspect it in your normal viewer, then rerun without -frame for the real output.
7. Protect an existing output
Warning
Shell redirection truncates its destination the moment pamrubber starts, before it can complain about anything. Never redirect straight over an image you care about. Write a temporary sibling, verify it, then replace the old file only when you're satisfied:
$ pamrubber -tri -randomseed=7 0 0 1 1 input.pam > output.pam.new
$ test -s output.pam.new
$ pamfile output.pam.new
$ mv -- output.pam.new output.pam
That final mv is the one state-changing step, and the one that can lose the old file. Back it up first if it matters:
$ cp --preserve=all -- output.pam output.pam.bak
Recovery
If pamrubber fails, do not move the incomplete file into place. To undo a completed replacement, restore the backup with mv -- output.pam.bak output.pam, and keep that backup until the new image has been checked.
Common traps
- "Specify -tri or -quad". Add exactly one mode option, not zero, not both.
- Complaint about control points. Count the coordinates: every point needs two numbers, and the source and target lists need equal counts.
- Warped-looking quad output. Check the four points trace corners in the same order rather than crossing lines.
A non-zero status from pamfile, an empty output or a corrupt-looking image means the transform is not verified. Check the input without changing it:
$ test -r input.pam && echo readable
$ pamfile input.pam
input.pam: PGM raw, 4 by 4 maxval 255
Remember a successful exit status only says pamrubber completed. It does not prove your chosen points describe the geometry you actually wanted, so verify dimensions and inspect the image before you ship it anywhere.
Done means
- Mode chosen. Exactly one of
-trior-quad. - Points matched. Source and target control-point lists have equal numbers of
x ypairs. - Output checked. The destination has the expected Netpbm format and dimensions.
- Seed pinned. You used
-randomseedwhenever repeatable bytes matter. - Frame used correctly.
-frametreated as a diagnostic overlay, never the final image. - Recovery path kept. The original input and any previous output stay recoverable until you've verified the new one.