You trained the characters, and the OCR training tool reads them every time. You build the inspection job on the same image and the same ROI, and the runtime draws its box around the character — then returns nothing. On smart cameras and code readers this failure almost never means the training was wrong. It means the training environment and the deployed read are two programs with two sets of defaults, and every setting you did not set explicitly can differ between them. This guide covers the mechanism, a five-minute test that isolates the cause, the pixel check that rules out resolution, every setting to pin, and the cases where the image rather than the settings is the real problem.
The symptom: found, boxed, not named
The pattern is distinctive. The same character on the same ROI reads in the training tool and no-reads in the deployed program, yet the runtime still locates the glyph: the character report shows a found region with no classification. Localization works; classification does not.
That points at the input to the classifier — the binarized glyph. Threshold mode, threshold range, read resolution, erosions and character spacing all decide which pixels reach the classifier, and the glyph the runtime builds is not the glyph you trained against. When only some positions fail — three of eight on a curved part, for example — the differing settings are everywhere, but only the positions with thinner strokes or weaker contrast cross the line where it shows. Train each position separately when the curve changes the stroke geometry; training a custom OCR font for curved inner-cap text works through that case. If your misses are absent digits rather than found-but-unnamed glyphs, start instead from numeric OCR missing digits: diagnose incomplete results.
Two environments, two sets of defaults
The training tool is an interactive program: it recomputes its threshold on each image and shows you the result on screen. The deployed job executes the parameter set stored with the job, and anything the job does not store falls back to that environment's library defaults. Those defaults are not shared between the two programs, and nothing warns you when they differ. The job looks identical to the training session and behaves differently.
A non-linear thresholding mode widens the gap. The runtime derives the threshold from each image's local histogram, so the values in use belong to the image in front of the camera at that moment — not to the values the training tool displayed while you built the font. Polarity is the same trap in miniature: whether characters are read light-on-dark or dark-on-light must be pinned, not inherited, and the polarity you train should match the polarity you read. The light-on-dark versus dark-on-light polarity choice in OCR training covers which way round to train.
One distinction saves hours: the font file stores the trained glyphs and nothing else. Threshold mode, threshold range, read resolution, read strategy, erosions and character spacing live in the job, and each one has to be written there.
The five-minute test that isolates the cause
Work from a saved image, not a live view. Save the exact frame the runtime failed on, load that file into the training tool, and confirm the miss reproduces there with the job's settings. Then:
- Open the character report in the deployed program and note the threshold values the runtime printed for the failing read.
- Enter those values as a fixed-range threshold in the training tool and re-read the saved image.
- If the glyph highlights in the overlay and reads, thresholding is the divergence: pin that mode and that range in the deployed job.
- If it still fails, change one setting at a time in both environments — read resolution first, then erosions, then strategy — until training and runtime agree.
If training reads the saved image with identical settings while the live station still misses, the settings are equal and the images are not: exposure drift, part presentation, lighting. That branch is the last section of this guide. The same polarity trap in blob analysis is covered in skeletonize line patterns: fix threshold polarity first.
Worked example: ruling out resolution on a curved part
Before pinning anything, prove the pixels are sufficient — otherwise you tune thresholds against a stroke that is barely two pixels wide. Take a curved part carrying eight copies of a 2.5 mm character with roughly 0.4 mm strokes, spread over a 24 × 18 mm region; those are this example's inputs, measured off the part. The camera is a 5 MP class reader: the LS-CRD-0028 prints 2560 × 2048 pixels on a 1/1.7-inch sensor behind an 8 mm lens.
- Interface
- Fast Ethernet
- Resolution
- 5 MP
- Sensor format
- 1/1.7"
- Shutter
- Global
A type-1/1.7-inch sensor measures about 7.5 × 5.6 mm, so the pixel pitch is 7.5 mm ÷ 2560 px = 2.9 µm. The limits to check: a character wants 10 to 16 pixels of height — take 12 px as the working minimum — and a stroke at least 2 px wide, or the binarized glyph loses the features the classifier matches.
Across the 18 mm field height: 2048 px ÷ 18 mm = 114 px/mm. Character height on the object: 2.5 mm × 114 px/mm = 285 px. Stroke width: 0.4 mm × 114 px/mm = 46 px. Magnification is m = 7.5 mm ÷ 24 mm = 0.31, so the 8 mm lens sits at a working distance of WD = f × (1 + m) ÷ m = 8 mm × 1.31 ÷ 0.31 = 34 mm.
Decision: 285 px of character height against the 12 px minimum is a margin of about 24 times, and 46 px of stroke against the 2 px floor. Resolution is not why this runtime no-reads. For contrast, stretch the same camera over a 300 mm field: 2560 px ÷ 300 mm = 8.5 px/mm, so the character drops to 21 px and the stroke to 3.4 px — readable, but one halving of the field from the floor. Below about 12 px of height or 2 px of stroke, fix the optics before touching a threshold; the camera resolution calculator runs this arithmetic on your own numbers.
Every setting to pin in the deployed job
Write the same value on both sides of every row — the training session and the deployed job — and leave nothing on default.
| Setting | What it does | What to set |
|---|---|---|
| Threshold mode | Fixed range, global, or non-linear adaptive thresholding per image | The mode that read in training; if the runtime's reported values worked, fixed range with those values |
| Threshold range | Minimum and maximum gray levels accepted as character pixels | The runtime report's values, as constants — never left on auto |
| Read resolution | Downsampling applied before the read | The same factor on both sides; an unset value halves stroke widths silently |
| Read strategy | How glyphs are segmented and matched | Conservative or aggressive, but explicit |
| Erosions | Morphology passes; each pass strips a pixel layer from every stroke | Same count on both sides; on a 3 px stroke one pass erases the character |
| Character spacing | How gaps split adjacent glyphs | An explicit value, in pixels or as a character-width ratio |
| Polarity | Light-on-dark or dark-on-light | Pinned, matching the trained font |
| Character set | The font file the job loads | The same file as training, confirmed loaded at start-up |
Read resolution and erosions interact: downsample by two and every stroke is half as many pixels thick, then a single erosion pass removes what is left. That pair explains most remaining cases where the threshold values already match between training and runtime.
The fix, step by step
- Save a failing frame from the runtime and reproduce the miss in the training tool with the job's settings.
- Copy the threshold values from the runtime character report into training as a fixed range, and confirm the glyph reads.
- Set all eight properties from the table explicitly in the deployed job — including the ones you never changed.
- Lock exposure and gain to fixed values at fixed light output; a drifting histogram defeats a pinned threshold range. Runtime camera parameter control covers setting exposure and white balance once, and auto-exposure ROI instability covers the feedback loop that silently moves them.
- Run 100 consecutive parts and log every no-read with its image; a change that survives 100 parts holds.
- Record the settings with the station documentation — an export, a screenshot, a filled-in table — so the next migration cannot revert to defaults unseen.
Run the job on hardware with room for eight ROIs and the logging: the LS-SMC-0017 is an x86 smart camera with 8.8 MP, a global shutter and a C mount, so the OCR job runs with pixels and processing to spare.
- Interface
- USB 2.0
- Resolution
- 6-10 MP
- Sensor format
- 1"
- Shutter
- Global
When the settings match and it still fails
Glare sweeping a curved, shiny surface as the part presents is the first suspect. Fix it with light, not software: a dome light floods the curve with diffuse illumination, and a semi-polarizing cover kills the specular bounce. The MV-SC3050XC-16M-ATN-H is a 5 MP color vision sensor with a global shutter and an M12 mount, and the MV-SC3000-C-HP is a square semi-polarizing lens cover for smart cameras; reading QR codes on reflective and curved surfaces covers the geometry of the bounce.
- Interface
- Fast Ethernet
- Resolution
- 5 MP
Focus falling off across the arc comes second: flank characters sit millimetres from the crown characters, and a lens focused on one misses the other. Stopping down one or two f-stops deepens the field at the cost of light — pay for that with light output, not exposure, or a moving part blurs.
Presentation drift is third: the part sits a few millimetres off, the ROI clips the glyph, contrast collapses. Size the ROI to the worst-case position rather than the nominal one — setting an ROI for inline code reading gives the speed and reliability trade-off.
Checklist before you reopen the training tool
- The miss reproduces in training on a saved runtime image with the job's settings.
- The runtime's threshold values, entered as a fixed range, read in training.
- All eight properties set explicitly in the deployed job; none left on default.
- Exposure, gain and light output locked at fixed values.
- At least 12 px of character height and 2 px of stroke at the worst-case position.
- A 100-part run logged clean after the change.
- The settings recorded with the station documentation.
If the part itself is the problem — small characters, a tight curve, a glossy finish — start again from the camera configurator, or browse smart cameras and fixed code readers; covers and light boards sit in code reader accessories. More set-up guides are on the code reading topic page, and a station that still misses after all of this deserves a second opinion: contact the applications team.
The configurator matches a camera, lens, light, light controller and cables to each other, step by step, and lists only parts that fit what you already picked.
Questions
Why does the training tool read a character the deployed program cannot classify?
Because they are separate programs. The font file stores the trained glyphs; the read settings — threshold mode and range, read resolution, strategy, erosions, spacing, polarity — live in the job. Any setting left unset falls back to that environment's default, and the defaults are not shared. The character is found because localization works; classification fails because the binarized glyph reaching the classifier differs from the one you trained against.
How do I prove the threshold is the divergent setting?
Pull the gray-level numbers the runtime actually used from the deployed program's character report for a failing read, then apply them in training as a fixed range on the saved frame. A glyph that now highlights and decodes tells you binarization alone caused the miss, so pin that mode and range in the deployed job. If the read still fails, work down the list one change at a time: read resolution, then erosions, then strategy.
Should I train each position on a curved part separately?
Yes, when the curve changes the stroke geometry or the lighting between positions — a 5 at the crown of the arc can render with thinner strokes than one on the flank. Give each position its own ROI and its own trained characters, but keep the read settings and the character set identical across all of them, so a no-read at one station always means image quality, not configuration drift between positions.
How many pixels does a character need for reliable OCR?
Plan for 10 to 16 pixels of character height and at least 2 pixels of stroke width; 12 pixels of height is a good working minimum. Below that, classification errors appear even when the image looks acceptable on screen, because the binarized glyph loses the features the classifier matches. Compute it directly: pixels per millimetre across the field, multiplied by character height in millimetres.
When should I stop adjusting settings and fix the image instead?
When pinned settings read a saved runtime image in training but the live station still misses — the difference is then the image, not the configuration. Look for glare moving across the curved surface, focus falling off across the arc (stop the lens down to deepen the field), and exposure drifting part to part. A semi-polarizing cover, a diffuse light and a locked exposure clear most of these.



