You enabled a deeper pixel format — the data sheet says 12-bit, or you asked for Mono14 — and the frame that lands in memory is labeled Mono16. The histogram looks broken: values spaced 16 apart, nothing above 65520, and a threshold tuned for 8-bit images now passes the whole scene. Nothing is wrong with the camera. Mono16 names the container the camera packs pixels into, and a 12-bit sensor's counts sit left-aligned inside it. This guide gives you the shift arithmetic, a worked threshold conversion, the bandwidth comparison, and the bench checks that tell you how many bits your camera really sends.
The pixel format names the container, not the sensor
A pixel format answers one question: how many bits each pixel occupies in the frame buffer, and how many of those bits carry sensor data. It does not tell you the depth of the sensor's analog-to-digital converter. Machine-vision sensors most often digitize to 10, 12 or 14 bits; true 16-bit converters stay rare in area scan cameras. In the unpacked GenICam SFNC formats — the naming that GigE Vision and USB3 Vision cameras use — Mono10, Mono12, Mono14 and Mono16 all occupy the same two-byte container and differ only in how many bits are significant.
The camera's own enumeration of supported pixel formats is the contract. If the list shows Mono16 and the packed variants but not Mono14, then Mono14 cannot be selected, whatever an older manual says. Depth choice is a separate decision: choosing 8, 10 or 12 bits covers the image-quality side. The container idea explains errors in both directions — the mirror case, a 10-bit converter shipping in 8-bit containers, is why 10-bit sensors ship 8-bit images.
Left-aligned: the padding bits sit at the bottom
Container formats are left-aligned: the sensor count's most significant bit lands in the container's most significant bit, and the unused low bits stay zero. One formula covers every case:
| Pixel format | ADC bits | Zero bits at the bottom | Value step | Saturated value |
|---|---|---|---|---|
| Mono16 | 16 | 0 | 1 | 65535 |
| Mono14 | 14 | 2 | 4 | 65532 |
| Mono12 | 12 | 4 | 16 | 65520 |
| Mono10 | 10 | 6 | 64 | 65472 |
Read the last column as clipping, not brightness. A 12-bit converter that saturates reports 65520 forever; it never emits 65535, and its four lowest bits are always zero. The same arithmetic, met from the Linux capture side, is why 12-bit data in a 16-bit V4L2 frame tops out near 65520.
Worked example: thresholding a 12-bit frame delivered as Mono16
Inputs, and where each comes from:
- ADC depth 12 bits — the sensor digitizes to 12 bits, so counts run 0 to 4095.
- Negotiated pixel format Mono16 — a 16-bit container, so shift = 16 - 12 = 4.
- Threshold 200 on an 8-bit scale — the value your previous tool used; this is the example's illustrative input, so substitute your own.
Rule in words: the buffer value is the sensor count shifted left by four bit positions, so multiply sensor counts by 16 to work in buffer values, and divide buffer values by 16 to get back.
Arithmetic:
- 8-bit threshold to sensor counts: 200 ÷ 255 × 4095 = 3211.8 ≈ 3212 counts.
- Threshold in buffer values: 3212 × 16 = 51392.
- Saturation check: 4095 × 16 = 65520, which is why no histogram bin exists above it.
Result: pass pixels at or above 51392 buffer counts, and treat any pixel sitting at 65520 as clipped, not bright.
Decision: convert the threshold once, multiply by 16, or right-shift the whole frame by 4 and keep every tool in 0 to 4095. Pick one convention per project. The old 200 applied literally sits near the black level of shifted 12-bit data and admits nearly every pixel on the sensor.
Why a Mono14 request can arrive as Mono16
This is normal, and the data is fine. Cameras move pixel data in whole 16-bit words because the sensor interface, the transfer engine and host memory all handle 16-bit words efficiently. Firmware therefore exposes Mono16 as the container for everything above 8 bits and offers the packed variants — Mono10p, Mono12p, Mono12Packed — for the bandwidth you get back. A camera documented as 14-bit may list only Mono16 in its current firmware; documentation lags the enumeration, and the enumeration is what the camera honors.
Reproducing the check takes any camera whose format list you can read: the LS-CMR-0166 — a 12 MP USB3 camera with a 4000 × 3000 sensor at 30 fps — is a compact bench camera for exactly this.
- Sensor format
- 1/1.7"
- Interface
- USB3
- Resolution
- 12 MP
- Shutter
- Rolling
One more distinction prevents confusion: current cameras implement the GenICam SFNC naming used above, while legacy device-specific interface layouts named and sometimes aligned the same data differently. And when two formats are both left-aligned, their bytes are identical — a Mono16 frame from a 14-bit-capable camera runs in your pipeline because only the claimed significance differs, so the swap passes unnoticed until a threshold lands between steps.
What this changes in your image processing
Four effects, all arithmetic:
- Histograms. Only every 16th bin is populated on 12-bit data (every 4th on 14-bit, every 64th on 10-bit). The gaps are padding, not a broken grab.
- Normalization. Divide by the real maximum — 65520 for 12-bit data in 16 bits, 65532 for 14-bit — not by 65535. The error is about 0.02 %, but a saturation detector keyed to 65535 never fires.
- Off-grid values. Counts that are not multiples of 16 mean the camera altered data after the converter: digital gain, a lookup table or noise dithering.
- One conversion, in one place:
adc_bits: int = 12 # sensor digitizer depth in bits
shift: int = 16 - adc_bits # 4 zero bits at the bottom
saturation: int = (2**adc_bits - 1) << shift # 65520
threshold_adu: int = 3212 # from the worked example, in counts
threshold_buffer: int = threshold_adu << shift # 51392
assert saturation == 65520 and threshold_buffer == 51392
The variables are illustrative and the assert is the test: it proves the shift is applied the same way in both places. If buffer sizes also look wrong — half the elements you expected per frame — that is the same two-byte container at work, and the fix is in Mono16 buffer size and payload errors.
Packed formats when bandwidth is tight
Mono12p stores a 12-bit pixel in 12 bits: 1.5 bytes instead of 2, a 25 % smaller frame with identical values once unpacked. The legacy Mono12Packed variant packs two pixels into three bytes; unpack either into a 16-bit container before processing.
The arithmetic on a 4000 × 3000 sensor: a Mono16 frame is 4000 × 3000 × 2 bytes = 24 MB. GigE carries roughly 118 MB/s of image payload (1 Gbit/s of wire rate minus protocol overhead), so one frame takes 24 ÷ 118 ≈ 0.20 s, about 5 fps. Mono12p cuts the frame to 18 MB and the frame time to 0.15 s, about 6.6 fps — a third more frames for the same image content. On USB3, with roughly 400 MB/s usable from 5 Gbit/s, the unpacked frame still runs at about 16 fps, so packed formats earn their keep mostly on GigE and multi-camera links.
When a format change drags the frame rate down, the usual cause is a linked attribute such as packet size, not the packing itself.
Checks before you trust the format name
Five bench checks, in order:
- Read the enumeration. List the pixel formats the camera offers in its current firmware; that list, not the manual, is the contract.
- Set, then read back. An unsupported value fails, and the read-back tells you what the camera will send.
- Cover the lens. Values should pin at zero plus the camera's black-level offset.
- Saturate. Aim at a bright lamp and raise exposure until nothing gets brighter. The plateau reads the depth: 65520 means 12-bit data in a 16-bit container, 65532 means 14-bit, 65535 means true 16-bit.
- Check the histogram spacing. Populated bins every 16 counts confirm the 4-bit shift with no tools at all.
The saturation test needs only a mono camera and a desk lamp. The MV-CS200-10UM is a 20 MP mono USB3 camera with a 1" sensor in C-mount.
- Sensor format
- 1"
- Lens mount
- C-mount
- Interface
- USB3
- Resolution
- 16-25 MP
When the usual answer is wrong
Left-aligned 16-bit containers cover most cameras, but three cases break the pattern:
- Post-converter processing. Firmware gain or a lookup table produces values off the 16-count grid, so the data is no longer raw converter output.
- True 16-bit converters. Some cooled and scientific sensors digitize deeper; their Mono16 frames use the full 0 to 65535 range and saturate at 65535.
- Legacy layouts. A device configured in a device-specific interface layout instead of the GenICam SFNC one may name or align formats differently; confirm the layout before porting thresholds between cameras.
The decision, case by case
- Thresholding 12-bit data in Mono16: multiply thresholds by 16, or shift the frame right by 4; saturation sits at 65520; expect histogram steps of 16.
- Asked for Mono14: read the enumeration. If only Mono16 appears, take it — same left-aligned container — and confirm the depth with the saturation plateau.
- Bandwidth-bound on GigE: move to Mono12p for 1.5 bytes per pixel and about a third more frames per second; unpack before processing.
- Values off the 16-count grid: look for firmware gain or a lookup table before blaming the converter.
To shortlist cameras for a build that depends on converter depth, start in the camera configurator or the camera finder, browse the area scan cameras category, or contact us with your sensor and pixel-format questions. More explainers like this one sit on the cameras topic page.
Questions
Does Mono16 mean the camera has a 16-bit sensor?
No. Mono16 describes the container: each pixel occupies two bytes. The sensor behind it usually digitizes to 10, 12 or 14 bits, and those counts are stored left-aligned in the container. Read the histogram or the saturation plateau to see how many bits are real: steps of 16 with a 65520 ceiling indicate 12-bit data, while a 65535 ceiling indicates a true 16-bit pipeline.
How do I convert Mono16 values back to 12-bit sensor counts?
Right-shift by the gap between container and converter depth. For 12-bit data in 16 bits, shift right by 4, or divide by 16: a buffer value of 51392 becomes 3212 sensor counts. For 14-bit data shift by 2, for 10-bit data by 6. Shift once, at acquisition, and keep every downstream tool in sensor counts.
Why do saturated pixels read 65520 instead of 65535?
A 12-bit converter clips at 4095 counts. Left-aligned in a 16-bit container, that is 4095 × 16 = 65520, with the four low bits held at zero. The 15 counts between 65520 and 65535 are padding, not lost signal. Key saturation detection at 65520; a detector waiting for 65535 never fires on 12-bit data.
What is the difference between Mono12 and Mono12p?
The values are identical once decoded; the packing differs. Mono12 stores each pixel in a 16-bit container at 2 bytes per pixel. Mono12p packs the bits tightly at 1.5 bytes per pixel: 25 % less bandwidth and about a third more frames per second on a GigE link. Unpack into a 16-bit container before processing.
How much more dynamic range does 14-bit give over 12-bit?
Ideally, each added converter bit doubles the measurable range: 12 bits span 4096 levels, about 72 dB, while 14 bits span 16384 levels, about 84 dB — a two-stop gain. Real cameras gain less because sensor noise, not the converter, sets the effective floor. In a Mono16 container both store left-aligned, stepping by 16 and by 4.

