Character recognition: build your own library

Recognize one symbol at a time — drawn or photographed. Name your symbols, draw or upload a handful of samples each, test it live, and download a self-contained zip to host on your own site. No accounts — save gives you a resumable URL. For plain capital letters A–Z, the three ready-made recognizers are smaller and already measured; the home page runs one live.

1 · Library type: characters (words, sentences and the page cleaner later)

2 · Classes & training data

Each class is a symbol your library recognizes. Draw at least 5 samples per class (more = better). Click a thumbnail to delete it.

quick add:
Train from a zip of character images

Upload one or more .zips of individual character images plus a manifest.json that labels each image and gives its baseline. Most samples train; the last few per character measure accuracy. Height is meaningful — measured from the baseline up (descenders below the baseline don't add to it). Select several zips at once, or add more later — they combine into one training set (a same-named zip replaces its earlier version). This builds a photo-input character library. See the format doc.

manifest.json: { "version":1, "xHeight":52, "characters":[ {"file":"a1.png","char":"a","baselineY":140}, … ] } — xHeight optional (auto-derived from x-height letters if omitted); add "split":"test" to force a sample into the test set.

Whitespace + dark-pixel combination — experiment

A second recognizer that scores the white space, not the ink: for every background pixel it measures the distance to the nearest dark pixel and, casting rays, how far each travels before hitting ink (an angular arm signature that separates * / x / +), binned into a per-cell spatial-grid histogram and matched by chi-square. Its per-class probabilities are then blended with the main dark-pixel matcher in log-probability space — (1−blend)·log Pdark + blend·log Pwhite. Loads the same character zips above; run once, then slide blend d↔w to remix the two instantly and find the best mix. A standalone experiment (not part of the downloaded library).

Leave-one-out cross-validation — per-variant accuracy

Runs many training passes over the same character zips above: each time a different drawn variant of a character is held out of the bank and recognized against the rest, repeated until every variant has been the held-out one exactly once. Reports the overall accuracy and, for each variant, its result — the confidence when the correct character ranks #1, otherwise the top-3 guesses with each one's confidence. Uses the matcher's built-in self-exclusion, so one recognizer is built and reused across all hold-outs.

recognizer:
Pair-discrimination heatmaps (baseline frame) — experiment

Which parts of a character carry the evidence that separates it from one specific confusable rival (O vs Q, P vs R)? Pick a good letter and a bad (rival) letter. For every variant of the good letter, its most similar other good variant and most similar bad variant are found (production matcher score, baseline-anchored frame: height above the baseline + distance from the left edge). Then each point is colored by comparing its best point-match into each: dark blue = matches the good template well and the bad one poorly (evidence for the good letter); dark red = the reverse (evidence for the rival); white = matches both or neither (uninformative). Continuous in between. A consistent blue region across variants = exploitable signal for a pair-specific discriminator.

good bad
Advanced matcher parameters

Defaults are the swept optima — change only if you know why. Applies to stroke matching; photo matching uses its own tuned set.

3 · Test it

This pad runs the exact runtime + training that ships in your zip.

4 · Save & download

stock word = drawn strokes, pure JS, 62-class bank, 5,459 words (~230 KB).
photo-word = reads PHOTOGRAPHS via the WASM matcher + CC lattice, 73 classes (incl. punctuation), 28,770 words with contractions (~0.9 MB, ~2–4 s/word).
page cleaner = the other half of the problem and NO recognition: a photo of a page in, clean ink and word boxes out (dewarp, illumination flatten, ruling removal, segmentation; ~170 KB). Detects what kind of paper it is — ruled, plain, graph, dot grid — or you pick. Ready-made; the button above builds a library tuned to your data.