You ask an embedded camera module for an uncompressed frame, and the demo tool that ships with it returns only JPEG. You write your own reader, and the saved image comes out covered in black spots and repeating stripes. Before touching the decoder again, run the checks in the order that finds the cause fastest: confirm the module can output raw at all, inspect the bytes you actually received, and compute whether the link can carry a raw frame inside your cycle time. In most cases the spots are not the sensor and not dirt. They are a decoder reading a byte stream that was never raw pixels, and the fix is either a different command or different hardware.
What the black spots are telling you
Artifacts that repeat are parsing faults, not imaging faults. Stripes with a constant period come from a byte offset or a row-stride error in the reader. Block-shaped garbage that changes with the scene is compressed data being decoded as pixels. Periodicity is the tell: measure the distance between repeats and compare it with your row stride or your packet size.
- Stripes at a fixed period: a byte offset or stride error in your reader
- Block garbage that follows the scene: JPEG bytes decoded as pixels
- One spot, same position, every frame: contamination or a dead pixel
- Grey noise across the whole frame: the resolution or bit-depth field set wrong for the requested mode
A single spot that never moves is the exception — it sits on the sensor, and isolating a persistent black spot has its own procedure.
Cause 1: the module's firmware has no raw mode
Most serial camera modules are JPEG engines. The sensor is read inside the module, compressed in firmware, and only the compressed bytes reach the host. The bundled demo tool mirrors that: it sends a snapshot command and displays a JPEG because that is the only mode the firmware implements. Confirm it from the manual's command table: the output modes are listed there, and a raw snapshot usually gets its own resolution field, kept separate from the JPEG resolution field.
Send the raw-snapshot command exactly as the table prints it: full command length, every fixed and reserved field set, resolution field pointed at the raw option. A command one byte short is answered with a NAK and an error code, not with an image, so log every ACK and NAK. If the module acknowledges the JPEG snapshot but rejects every raw request with an unsupported-mode code, the capability is not in the firmware, and no reader code will change that.
The fix is hardware, not code — the section near the end covers the camera class to move to. The same discipline applies to any module-host pairing: interface, format and protocol must agree before you stream.
Cause 2: JPEG bytes decoded as pixels
If the module does send JPEG, reading those bytes as raw pixels produces exactly the artifact in your saved images, because the decoder assigns compressed byte values to pixel coordinates. Two checks settle it in minutes.
Dump the received bytes to a file instead of a decoded image. A JPEG stream begins with the byte pair FF D8 and ends with FF D9, the JPEG standard's SOI and EOI markers. Finding them proves the stream is compressed.
Compare byte counts. A raw frame is always exactly width × height × bytes per pixel — 640 × 480 × 1 = 307 200 B for an 8-bit VGA frame. JPEG length varies frame to frame even for a static scene. Capture the same scene twice: identical counts point to raw, different counts point to JPEG.
Two guides cover the decode side: what raw sensor output means on a module without an ISP, and how to know you have a true Bayer raw stream. The reverse mistake — raw bytes handed to a JPEG decoder — is why JPEG decode hangs on raw pixel data.
Cause 3: packet reassembly drops or shifts bytes
Serial JPEG travels in fixed-size packets. Each packet carries a small header — image identifier and packet index — plus a checksum, and the module announces how many packets make up the image. The exact header and checksum sizes are printed in the module's protocol document; do not infer them from sniffed traffic.
Reassemble packets in index order, verify each checksum, and count the packets against the announced total before writing the buffer. A packet lost mid-image shifts every byte after it by the payload length, which prints as stripes with a period equal to that length — the symmetric pattern from the symptom list. On a checksum mismatch, discard the image and restart the transfer instead of appending a partial frame: the decoder needs a contiguous stream from SOI to EOI.
When corruption survives every packet check, the format-and-wiring checklist for a corrupted camera image is the next stop.
Worked example: one 640 × 480 raw frame over a 115 200 baud serial link
The decision between raw and JPEG is a byte budget. Inputs for a typical serial camera module: VGA resolution, 640 × 480 pixels; 8 bits per pixel for mono or Bayer raw, so 1 B per pixel; a UART link at 115 200 baud with 8N1 framing — 1 start bit, 8 data bits, 1 stop bit, so 10 bits per byte; and a typical 25 kB JPEG snapshot of the same scene, that is 25 600 B.
Frame size: 640 × 480 × 1 B = 307 200 B. Link rate at 115 200 baud: 115 200 ÷ 10 = 11 520 B/s. Raw transfer time: 307 200 ÷ 11 520 = 26.7 s. The JPEG frame: 25 600 ÷ 11 520 = 2.2 s. Raise the UART to 921 600 baud and the link carries 92 160 B/s: raw falls to 307 200 ÷ 92 160 = 3.3 s, JPEG to 25 600 ÷ 92 160 = 0.28 s.
| Link setting | Link rate | 307 200 B raw frame | 25 600 B JPEG frame |
|---|---|---|---|
| 115 200 baud, 8N1 | 11 520 B/s | 26.7 s | 2.2 s |
| 921 600 baud, 8N1 | 92 160 B/s | 3.3 s | 0.28 s |
Decision for this frame and link class: if the inspection cycle needs an image faster than about every 3 s, raw over UART fails at both common baud rates. JPEG fits cycles down to roughly 0.3 s, and only at the high-baud end. That budget is why serial-module firmware implements JPEG only. Raw pixels need a link that moves megabytes per second — USB3, GigE, or a camera bus that writes to memory directly — and that is where the module class changes.
Choosing a board camera that streams raw by default
Machine-vision board cameras work the other way round: uncompressed frames are the normal output, and the SDK hands your code Bayer or mono pixels directly, with the pixel format as a setting you select. You choose sensor, shutter and mount instead of a compression mode. The cards below cover USB3 and GigE, global and rolling shutter:
- Sensor format
- 1/1.8"
- Lens mount
- C-mount
- Sensor format
- 1/1.8"
- Interface
- USB3
- Sensor format
- 1/2.9"
- Lens mount
- M12
The LS-BCM-0003 pairs a 3.1 MP global-shutter sensor with USB3 and a C-mount, the fit for motion on a short cable. The MV-CB060-10UM-B is a bare 6 MP mono board on USB3 for building into confined housings. The MV-CB016-10GM-M-W takes the same uncompressed path over GigE, with a 1.6 MP global-shutter sensor behind an M12 mount for longer runs. For more resolution on GigE, the LS-BCM-0056 pairs a 12 MP sensor with 1.6 μm × 1.6 μm pixels on a C-mount.
- Sensor format
- 1/2"
- Lens mount
- C-mount
- Interface
- GigE
- Resolution
- 12 MP
Pick the rest from the board-level cameras range or the camera finder. Global shutter for moving parts, rolling for static scenes: the board-level camera selection guide carries the full trade list, the board camera evaluation checklist covers what to test before committing a design, and the replacement guide maps sensor and format onto a new part when a module dies mid-life. If a USB3 bridge board sits between camera and host, match the two before you stream.
Verify before you code: five checks
- Read the command table first. Note whether an uncompressed mode exists at all, and treat the raw-resolution field as separate from the JPEG-resolution field.
- Send the raw-snapshot command with the exact length and reserved fields the table prints, and log every ACK and NAK with its error code.
- Capture to a byte file and run the two tests above: marker search, then byte count against width × height × bytes per pixel.
- Do the bandwidth arithmetic before writing the decoder: frame bytes ÷ (baud ÷ bits per byte) against your cycle time.
- Only then write the Bayer or mono decode, and validate it on a printed static target where every expected pixel is known.
Pick the sensor and mount in the camera finder above, then step through the configurator; the free expert support that comes with every order covers checking the pixel format against your capture stack. More format-and-stream guides sit on the cameras topic page, and if a build question survives every check above, the contact page reaches the applications team.
Questions
How do I tell JPEG bytes from raw pixel data in a capture?
Look at the first bytes in a hex view: JPEG starts with FF D8 and ends with FF D9, the standard's markers. Raw has none, and its length is fixed at width × height × bytes per pixel every frame. A second test: force the capture open as an image. Bayer raw opened as color shows a strongly green, maze-patterned picture; JPEG opened in any viewer shows the scene correctly.
Can a UART link carry raw frames at inspection rates?
Only at small sizes and slow cycles. A 320 × 240, 8-bit frame is 76 800 bytes; on a 921 600 baud link moving 92 160 bytes per second, it arrives in about 0.83 s — roughly one frame per second. A VGA raw frame needs about 3.3 s on the same link. Cycles faster than one frame per second need USB3, GigE or a camera bus that writes to memory directly.
What does a NAK from a serial camera module mean?
The module refused the last command instead of running it. The NAK carries an error code that names the failing check — unsupported mode, wrong parameter value, or a command length that does not match the table in the manual. Log the code on every attempt. A NAK raised only by the raw-snapshot command, while the JPEG snapshot is acknowledged, is the signature of firmware that has no uncompressed mode.
Do black spots that stay in place come from the sensor?
Yes. A spot fixed at the same pixel position in every frame — while the scene moves — is contamination on the sensor or cover glass, or a damaged pixel. Spots that move with the scene are image content; spots that jump when a byte offset changes are parsing faults. Clean the cover glass first, then map dead pixels; persistent defects have their own isolation procedure on this site.
Is raw always better than JPEG for machine vision?
For measurement and defect detection, yes: compression discards gray-level detail and can raise block artifacts that imitate defects, so a dimensional check or a surface inspection wants uncompressed pixels. JPEG remains reasonable for preview, archiving and links that cannot carry raw inside the cycle time. Match the choice to the algorithm: a presence check tolerates compression, a tolerance check does not.



