Forms still arrive at inspection stations carrying a handwritten signature where a machine-readable code should be. The question the line asks is not what the letters spell but whether the right person signed. This guide gives you the working pipeline: size the camera to the thinnest pen stroke, binarize and close the image with a kernel tuned to the pen width, describe each signature by normalized stroke features, and match it against trained samples per writer. Train three writers or thirty - the pipeline stays the same; more writers need more samples, not a new design.
Why whole-signature classification beats character OCR
Printed-character OCR starts by segmenting glyphs, and cursive defeats that at the first step: strokes connect, loops overlap, and the same writer produces a different shape every time they sign. The working decision is to stop segmenting and classify the whole signature region as one object, described by a fixed-length feature vector and compared against vectors stored from genuine samples of each writer. That turns the task into nearest-neighbor matching, which is stable, explainable and runs in microseconds.
Two limits to accept up front. The system tells you which trained writer produced the signature and reads none of the text. And it is a process check, not a forensic one: it catches the wrong signer, a missing signature and crude imitations, while a practiced forgery is out of scope. Inside those limits it answers the line's question - right signer, wrong signer, or nobody the system knows. Character-level fixes remain the right toolbox for print, as in the segmentation approach for touching digits before OCR.
What you need
- A camera and lens sized to the stroke (Step 1) and a rigid holder that keeps the form flat.
- Diffuse white light. Plain paper forgives a point source; laminated or glossy forms glare, so spread the illumination.
- A processor for the matcher: a line-side PC, or a smart camera with an x86 platform that runs your own code.
- Training samples: 15-20 genuine signatures per writer, collected over at least three sessions with at least two pens.
- Standard image-processing functions only: threshold, morphology, skeleton, distance transform and a nearest-neighbor distance. No deep-learning toolchain is needed for the core pipeline.
The pipeline in six moves:
- Size the capture to the thinnest stroke.
- Binarize and close pen skips.
- Normalize the signature region.
- Extract the stroke feature vector.
- Train per writer.
- Classify with an accept window.
Step 1: size the capture to the thinnest stroke
Decide the smallest feature you must resolve. A fine ballpoint lays down a line of about 0.3 mm; broader 0.5-0.7 mm pens only add pixels at the same scale, so the fine line is the binding case. Budget 3 pixels across it - enough for a stable skeleton and a stroke-width measurement:
A 0.3 mm stroke therefore needs 0.1 mm per pixel or finer. This is the same pixels-per-feature budget that sets the minimum font size for OCR.
Worked example. The signature box is 60 mm wide; add 5 mm of margin per side for locating marks and skew, so the field of view is 70 mm. At 0.1 mm per pixel the sensor needs 70 / 0.1 = 700 pixels across, which any sensor of 1.2 MP or more exceeds. What each class delivers at this field:
- 1280 pixels across (1.2 MP class): 70 / 1280 = 0.0547 mm per pixel, so the stroke spans 0.3 / 0.0547 ≈ 5.5 pixels.
- 2592 pixels across (5 MP class): 70 / 2592 = 0.0270 mm per pixel, so the stroke spans about 11 pixels.
Both read the stroke. The finer scale steadies the feature values and gives the closing kernel room to work before it starts merging strokes. Scale linearly with the field: a 140 mm field at 0.1 mm per pixel needs 1400 pixels across.
Working distance from the lens you have
Magnification falls out of the sensor and the field; working distance follows from the lens:
Take a 1/2.4" sensor, about 5.6 mm wide, with an 8 mm lens at the 70 mm field: m = 5.6 / 70 = 0.08, so WD ≈ 8 × 1.08 / 0.08 = 108 mm. Halve the field to 35 mm and m doubles to 0.16, pulling the camera in to 8 × 1.16 / 0.16 = 58 mm. The form is flat and static, so depth of field does not constrain the choice.
Step 2: binarize, then close pen skips
Threshold the cropped region so ink becomes foreground. Under controlled light, a global Otsu threshold on the gray image is enough - the Lab-color Otsu segmentation walkthrough covers the setup - while drifting ambient light calls for a local adaptive threshold.
Then close the binary image with a small rectangular structuring element. Closing heals pen skips, the faint gaps a fast ballpoint leaves, but it welds neighboring strokes together once the kernel grows past their separation. Two bounds fix the kernel size k:
At the 0.0547 mm-per-pixel scale of Step 1, a 0.3 mm stroke is about 5.5 pixels wide. Skips of 0.10-0.15 mm measure 2-3 pixels, and the tightest gaps in connected cursive run 0.30-0.35 mm, or 5-6 pixels. A kernel between 3 and 5 pixels satisfies both bounds: start at 3 × 3 and step up to 5 × 5 only if skips still show in hold-out images. Stay below 7 × 7, which reaches the 5-6 pixel gaps and fuses loops. If the skips you must heal ever outgrow the gaps you must keep, no kernel works at that pixel scale - buy resolution, not kernel size.
Step 3: normalize the signature region
Locate the box and crop to the ink. A fixture fixes the box; loose forms need the printed frame found by pattern match and a deskew to it, because the slant feature in Step 4 assumes a repeatable rotation. Crop to the ink bounding box, pad it by 2 pixels, then resize the long side to 192 pixels and pad the short side to 96. Do not stretch to a fixed rectangle: the distortion corrupts the aspect ratio you are about to measure as a feature. Keep the pre-resize width and height, because their ratio is the first feature.
Step 4: extract the stroke feature vector
A fixed set of global numbers describes the signature well enough to tell writers apart:
| Feature | Count | How it is computed |
|---|---|---|
| Ink-box aspect ratio | 1 | bounding-box width / height, before resize |
| Ink density | 1 | foreground pixels / box area |
| Horizontal projection profile | 16 | ink sum per row, normalized to sum 1 |
| Vertical projection profile | 16 | ink sum per column, normalized to sum 1 |
| Mean stroke width | 1 | 2 × mean of the distance transform |
| Slant | 1 | dominant orientation from the second-order central moments |
| Skeleton endpoints and junctions | 2 | counts after thinning |
| Hu moments 1-4 | 4 | log-scaled, sign preserved |
That totals 42 numbers per signature. Normalize each to [0, 1] with the minimum and maximum from the training set, so every feature carries equal weight in the distance. The projection profiles do most of the discrimination because they encode where the ink sits; the endpoint and junction counts separate writers who loop their letters from writers who print them.
Step 5: train on genuine samples per writer
Collect 15-20 genuine samples per writer, across at least three sessions and two pens. Signature shape drifts with speed, posture and pen, and the set must span that drift or every real signature looks like a stranger. Extract the 42-feature vector from each sample and store the vectors per writer: 30 writers at 20 samples each is 600 × 42 ≈ 25,200 floats, about 100 KB, with the min-max bounds recomputed once per training run.
Effort scales in one place: writers whose signatures resemble each other. Watch the hold-out confusion matrix, and when writer A's samples land nearer writer B's templates than their own, add five more A samples and retrain. The pipeline never changes, only the sample count does. Past a few dozen look-alike writers, hand-picked features stop separating people - that is where learned embeddings take over, the trade-off set out in the rule-based versus AI inspection comparison.
Step 6: classify with an accept window
Runtime is one pass: threshold, close, resize, extract 42 features, then compute the normalized Euclidean distance from that vector to every stored sample. Let d1 be the distance to the nearest sample and d2 the nearest distance among any other writer's samples. Start the window at:
- Accept the writer when d1 ≤ 0.30 and d2 - d1 ≥ 0.08.
- Flag for review when d1 ≤ 0.30 but the margin falls short, meaning the signature sits between two trained writers.
- Return unknown signer when d1 > 0.30.
These are starting values anchored to the [0, 1] feature scaling; the hold-out set fixes the final ones. Push the d1 threshold down until false accepts on 10 unseen samples per writer reach zero, then weigh the false rejects against your review capacity. Closeness plus margin is the same trust discipline as judging barcode read confidence. The matcher is a light load: 600 stored vectors × 42 features ≈ 25,000 multiply-adds, well under a millisecond on a PC-class processor.
Verify the set-up before it goes live
- Zero false accepts on a hold-out of 10 unseen samples per writer. A signature check that waves the wrong writer through is worse than no check.
- False rejects below 5% on the same set. Above that, add samples for the rejected writers before loosening d1.
- Parameter parity: runtime runs the same threshold, kernel, resize and normalization bounds as training. A matcher trained one way and run another fails silently, the OCR trains but fails at runtime failure, unchanged here.
- Condition tests: the same writer signs with a gel pen, the form stock changes, the room lights change. Retest the hold-out after each; if d1 drifts upward, add the new condition to the training set.
- Rotation: forms skewed a few degrees shift slant and projections. Deskew to the printed frame in Step 3 before extracting features.
Where the classifier runs
The matcher is ordinary code over 42-number vectors, so the capture device decides the architecture. To keep the whole inspection on one device, use a smart camera with an x86 platform that executes your own program beside the image pipeline. The LS-SMC-0017 pairs its x86 platform with an 8.8 MP, 1" global-shutter sensor behind a C-mount.
- Interface
- USB 2.0
- Resolution
- 6-10 MP
- Sensor format
- 1"
- Shutter
- Global
If classification runs on a line-side PC instead, the camera only has to deliver pixels, and a fanless industrial mini PC keeps paper dust out of the electronics. Mono sensors keep the pipeline lean because binarization discards color anyway. Two capture options at this field size: the MV-SC5060XM-08M-WBN pairs a 6 MP mono sensor with a fixed 8 mm M12-mount lens, while the MV-SCB007EC-12S-WBN offers 1.6 MP color with a 12 mm manual-focus M12 lens.
- Interface
- GigE
- Resolution
- 6-10 MP
- Interface
- Fast Ethernet
- Resolution
- Up to 3 MP
One boundary worth knowing: a fixed code reader decodes printed 1D and 2D symbologies and will not classify free-form handwriting, so the reader already on your line is the wrong tool for this job. The smart cameras page and the camera finder filter by resolution and mount, the configurator walks the full chain, and the code-reading topic page collects the reading guides.
Decisions per case: a few dozen writers with distinct signatures - this pipeline with 15-20 samples each. Look-alike writers beyond that - same capture, learned embeddings for the match. Laminated forms - diffuse the light before touching anything else. Pen skips fighting stroke gaps at your pixel scale - buy pixels first; it is the only move that widens both kernel bounds at once.
Questions
How many training samples does each writer need?
Start at 15-20 genuine samples per writer, taken over at least three sessions with at least two pens. If the hold-out confusion matrix shows one writer landing nearer another writer's templates than their own, add five samples at a time for the confused writer only, and recompute the min-max normalization bounds each round, because the feature scales move as the set grows.
Can signature classification run on the camera instead of a PC?
Only on an x86-platform smart camera that executes your own program. Fixed-function vision sensors can capture the image and run preset checks, but a custom nearest-neighbor matcher will not run on them. The matcher itself is light, about 25,000 multiply-adds for 30 writers, so any x86-class processor handles it inside the cycle time.
Does this pipeline detect forged signatures?
It catches a missing signature, a different signer and a crude imitation, because those move the stroke features well outside a writer's spread. A practiced forgery that copies slant, spacing and pressure can fall inside that spread; stopping those is document forensics, not a line-side check. Treat the result as a process gate and pair it with access and audit controls if fraud is the concern.
What camera resolution do I need for a 0.3 mm pen line?
At least 3 pixels across the stroke, so 0.1 mm per pixel or finer. A 60 mm signature box with registration margins needs 700 pixels across the 70 mm field, which a 1.2 MP sensor already exceeds; a 5 MP sensor gives about 11 pixels per stroke and steadier feature values.
Why does my closing operation weld neighboring strokes together?
The structuring element is wider than the gap between them. Closing heals any gap up to about the kernel size, so set the kernel to at most the smallest gap you must preserve minus one pixel. If genuine pen skips need a larger kernel than that rule allows, the fix is more image resolution, not a bigger kernel.
Should I segment a signature into individual letters first?
No. Cursive strokes connect and overlap, so character segmentation fails exactly where signatures are hardest, and whole-region features sidestep it entirely. Reserve per-character OCR for the printed block letters elsewhere on the same form, where the character-level toolbox works.


