System designTroubleshooting

Camera image encoding falls back to mono8: request Bayer instead

Why a color camera falls back to mono8 when you request rgb8, which Bayer pixel format to set in image_encoding, and why binning_x 2 fails on Bayer sensors.

LumaSpec Vision10 min read Share on LinkedIn

On this page 9 sections
  1. 01Why does image_encoding rgb8 come back as mono8 at startup?
  2. 02Which pixel format should I request from a color camera?
  3. 03How do I list the pixel formats my camera really supports?
  4. 04Why does my color camera refuse 2×2 binning?
  5. 05Where should the Bayer-to-rgb8 conversion happen?
  6. 06What does rgb8 cost in bandwidth?
  7. 07When is mono8 the right format after all?
  8. 08What checks stop a silent fallback at the next commissioning?
  9. 09Questions

You asked a color camera for rgb8 and it started at mono8 anyway. The startup log reads back encoding = 'mono8', binning = [1, 1], exposure = 43000, gain = 0.45 — every value you tried to change is still sitting at its default. The camera is not faulty and the cable is not the cause: the values you wrote are not members of the camera's PixelFormat and binning enumerations, so the firmware rejected them and the wrapper carried on with what the sensor already had.

This guide walks that chain from wrapper parameter to sensor: which pixel format a Bayer color camera can actually send, how to read back what the camera accepted, why 2×2 binning is refused on color sensors, and where the demosaic belongs. You will finish with a startup check that catches a silent fallback before it costs you a shift of grayscale-only data.

Why does image_encoding rgb8 come back as mono8 at startup?

Because the camera's PixelFormat enumeration does not contain RGB8: the sensor outputs a Bayer mosaic, the wrapper's write is rejected, and the node falls back to its mono8 default, which the startup line then reports.

A color machine-vision sensor is a monochrome chip behind a mosaic of red, green and blue filters — one value per pixel, half of them green. rgb8 means three interleaved bytes per pixel, and only a converter can produce that. When the wrapper applies your parameters, it maps image_encoding: "rgb8" to the GenICam symbol RGB8 and writes it to PixelFormat. The camera accepts enum members only; the write fails; the wrapper keeps the sensor's current format, Mono8, and prints it. The same sequence explains the other half of your log: binning_x: 2 and binning_y: 2 map to BinningHorizontal and BinningVertical, and on this camera those enums offer only 1.

The contrast with a USB camera that accepts rgb8 is expected, not a contradiction: consumer UVC devices deliver converted RGB or YUV from the device, so rgb8 is available to ask for. An industrial Bayer camera sends what the sensor made.

The readback is the proof. The startup settings line prints state after configuration, not your request:

Startup settings: encoding = 'mono8', binning = [1, 1], exposure = 43000, gain = 0.45

The check, in illustrative form for any SDK:

# Illustrative readback check; substitute your SDK's feature calls
requested = "RGB8"                       # str: the symbol you wrote
accepted = read_feature("PixelFormat")   # str: what the camera reports back
assert accepted == requested, f"camera kept {accepted}"

If the symptom is color missing in your stack while the manufacturer's viewer shows color, the same enum mismatch is the usual cause — GigE camera shows no color image: fix the pixel format default covers that variant, and camera pixel format not changing: why formats are fixed and how to set them explains why you cannot add a format the firmware does not list.

Which pixel format should I request from a color camera?

Request the Bayer format that matches the sensor's filter layout — on a typical RGGB sensor that is bayer_rggb8, mapping to the GenICam symbol BayerRG8 — and demosaic to rgb8 on the host.

The wrapper names and the symbols behind them:

Wrapper value GenICam symbol Bytes per pixel What the camera sends
mono8 Mono8 1 one brightness value per pixel
bayer_rggb8 BayerRG8 1 raw mosaic, first row starts RG
bayer_grbg8 BayerGR8 1 raw mosaic, first row starts GR
rgb8 RGB8 3 three bytes per pixel, only if the camera converts

Start with bayer_rggb8. If the PixelFormat enum answers with a different Bayer member, request that one: the layout is fixed by the filter on the sensor, and demosaicing with the wrong pattern swaps colors instead of degrading quietly. When a task needs true per-pixel RGB rather than interpolated color, that is a three-sensor prism camera decision, not a format decision — prism 3-sensor color cameras vs Bayer: when true RGB matters.

The MV-CU020-90GC is a 2.5 MP color GigE camera with a global shutter.

Area scan camerasHikrobot MV-CU020-90GC 2.5 MP Area Scan Camera, GigE, GMAX4002, ColorMV-CU020-90GC
Sensor format
1/1.7"
Lens mount
C-mount
Interface
GigE
Resolution
Up to 3 MP
$309.00View partBuild a system with it

How do I list the pixel formats my camera really supports?

Read the PixelFormat enumeration from the camera over GenICam: it lists every symbolic value the firmware accepts — typically Mono8, the four Bayer variants and sometimes a packed YUV mode — so you pick a member that exists.

Three ways, fastest first:

  1. The manufacturer's viewer application shows the full feature tree; the PixelFormat dropdown is the enum.
  2. Any GenICam-compliant tool enumerates the feature and its entries over GigE Vision or USB3 Vision — the enum travels with the camera, not with the SDK.
  3. Your wrapper's startup log prints the current value; pair it with one enum read before the first write and the pair becomes your regression test.

Under each symbol sits the integer the register takes; you set the name, never the number. BinningHorizontal and BinningVertical are enums of the same kind, which is why a log reading binning = [1, 1] is a statement about the camera, not about your parameter file.

Why does my color camera refuse 2×2 binning?

Because 2×2 binning would merge one red, two green and one blue photosite into a single value and destroy the Bayer mosaic, most color cameras do not expose binning at all — binning_x: 2 fails and the readback stays [1, 1].

Mono sensors bin freely: summing neighbors of the same kind is safe when there is no mosaic. Color sensors built for binned readout do exist — quad-Bayer parts group four same-color pixels so a 2×2 merge leaves a valid pattern; quad Bayer 4-cell sensors: binning, remosaic and full resolution covers them. A conventional Bayer camera is not one of them, so:

  • Delete binning_x and binning_y from the parameter file; they cannot take on this sensor.
  • If binning was for frame rate, mono8 or a Bayer format already gives the smallest frame the camera can send.
  • If binning was for resolution, crop a region of interest instead, which Bayer cameras do support.

If the goal was really having enough pixels for the part, do that arithmetic directly: 3 pixels across a 0.3 mm feature is 3 / 0.3 = 10 px/mm, and a 200 mm field of view then needs 10 × 200 = 2,000 pixels across — a 3 MP sensor at 2,048 pixels across clears it, no binning required.

Camera resolution for the smallest feature
Units
Pixels needed
–
Sensor size
– MP
Smallest sensor that fits
–
Pixel on the part
– mm
Pixels across the feature, that sensor
–

Pixels needed = field / feature × pixels per feature on each axis (field incl. margin). The lens must resolve the pixels too: Nyquist = 1000 / (2 × pixel µm) lp/mm.

Find cameras with enough pixels Open the full calculator

Where should the Bayer-to-rgb8 conversion happen?

On the host: keep one byte per pixel on the wire, capture bayer_rggb8, and demosaic in the driver or the consumer — a camera-side conversion triples the bytes and adds no information.

The three placements, with the decision:

  • Camera side, writing RGB8 from the device: accept it only when one legacy consumer demands rgb8 frames and the link has headroom to spare.
  • Driver side, converting before publishing: every subscriber gets rgb8, and every subscriber pays for it.
  • Consumer side, converting at the point of use: the transport stays at one byte per pixel, and tools that only measure or read codes consume the raw frame as brightness.

After any conversion, confirm the output object carries the format you assume — converted image object pixel format: verify before processing. And if a preview window goes dark the moment you switch to Bayer, that viewer cannot decode the mosaic: unsupported Bayer pixel format: diagnose a blank preview.

What does rgb8 cost in bandwidth?

Three bytes per pixel instead of one: rgb8 triples the data rate of the same frame, and on a GigE link that usually decides the frame rate you can reach.

bytes_per_frame = pixel_count × bytes_per_pixel data_rate = bytes_per_frame × frame_rate

The LS-CMR-0166 is a 12 MP USB3 camera running 4000 × 3000 at 30 fps.

Area scan cameras12 MP USB3 area scan camera, IMX226, 1/1.7" rolling shutter, 30 fps, 4000 × 3000 resolution (LS-CMR-0166)LS-CMR-0166
Sensor format
1/1.7"
Interface
USB3
Resolution
12 MP
Shutter
Rolling
$560.00View partBuild a system with it

One frame is 4,000 × 3,000 = 12,000,000 pixels:

  • mono8 or bayer_rggb8: 12,000,000 × 1 B = 12 MB per frame. At 30 fps, 12 MB × 30 = 360 MB/s, about 2.9 Gbit/s — inside USB3 camera throughput of roughly 350–450 MB/s.
  • rgb8: 12,000,000 × 3 B = 36 MB per frame. At 30 fps, 36 MB × 30 = 1,080 MB/s — beyond any USB3 camera link, and 10GigE at about 1 GB/s would sit at its ceiling.

The same arithmetic is why high-resolution color cameras on GigE ship Bayer rather than RGB. Twenty megapixels at three bytes is about 60 MB per frame; even 5 fps of that is 300 MB/s against a GigE link's practical 100–125 MB/s. Frame rate also interacts with exposure time, not only with bytes: RGB camera frame rate limits: pixel format and exposure works that coupling through.

The MV-CS200-10GC is a 20 MP color GigE camera with a 1-inch sensor.

Area scan camerasHikrobot MV-CS200-10GC 20 MP Area Scan Camera, GigE, IMX183, Color, BasicMV-CS200-10GC
Sensor format
1"
Lens mount
C-mount
Interface
GigE
Resolution
16-25 MP
$739.00View partBuild a system with it

When a link runs near its ceiling, the interface choice and the camera data cable matter as much as the format; 5GBASE-T camera interface: bandwidth, cables and distance gives the numbers for the middle-ground option.

When is mono8 the right format after all?

When no downstream task uses color: presence checks, edge and dimension measurement, OCR on neutral parts and most bar-code reading gain nothing from RGB, and mono8 gives the smallest frame and the highest frame rate.

The rule: configure for color only when a color feature decides pass or fail — an insulation tint, a ripeness index, a color-coded cap. Two consequences follow:

  • A mono camera is the better mono tool. Its sensor usually offers real 2×2 binning, so binning_x: 2 takes and quarter-resolution readout works.
  • mono8 from a color camera is a one-way door. The mosaic leaves as brightness; the color information is gone from that stream, and nothing downstream recovers it.

What checks stop a silent fallback at the next commissioning?

A five-line startup check: log the requested and the accepted value for PixelFormat, binning, exposure and gain, and stop before the first image when the two differ.

The list, in order:

  1. Enumerate before you write. Read PixelFormat's entries and pick a member you have seen listed.
  2. Write, read back, compare. The snippet in the first section is the pattern; apply it to binning as well.
  3. Expect no binning on Bayer. If BinningHorizontal lists only 1, delete the parameters instead of shipping a request that always fails.
  4. Budget the link. Pixels × bytes per pixel × fps against a practical rate: 100–125 MB/s on GigE, 350–450 MB/s on USB3, about 1 GB/s on 10GigE.
  5. Persist what worked. Save the verified settings to a user set so a power cycle cannot lose them: save camera parameters as a user set that loads on startup. Frame rate deserves the same readback habit — camera startup frame rate: verify saved settings and readback.
  6. Order the color variant deliberately. Mono and color versions of one sensor line differ in exactly these two behaviors, formats and binning, so filter the area scan cameras finder by Colour and Shutter before you commit.

From here: run the camera finder with your format and frame-rate budget, or start at the camera step of the system configurator. If the chain still falls back, bring the startup log to us through the contact page and we will read it with you.

Questions

Is bayer_rggb8 lower quality than rgb8?

No. Both carry the same 8-bit sensor values; rgb8 is manufactured from them by interpolation. Demosaicing once on the host gives the same color a camera-side conversion would, keeps one byte per pixel on the cable, and lets you choose the interpolation method. Convert after capture, then confirm the output container really holds three channels before your processing runs.

Why does mono8 from a color camera look green-tinged?

Because mono8 from a Bayer sensor is the raw mosaic read as brightness: half the photosites sit behind green filters, a quarter behind red and a quarter behind blue, so green dominates the gray image. Color cannot be recovered from that stream later. If any current or future task needs color, capture bayer_rggb8 and demosaic; keep mono8 only when color decides nothing.

Will a quad-Bayer sensor give me working 2×2 binning?

Yes, that is what it is built for. A quad-Bayer sensor groups four same-color pixels in each 2×2 block, so summing a block leaves a valid mosaic and true 2×2 binning with roughly four times the collected light per output pixel. Full-resolution readout from the same sensor needs a remosaic step, which is the trade you accept. Conventional Bayer sensors offer no binning at all.

Which format should I log to disk when storage is the limit?

Log the raw Bayer frame. At 12 MP a frame is about 12 MB in bayer_rggb8 and about 36 MB in rgb8, so a 30-minute capture at 10 fps is 18,000 frames: roughly 216 GB raw against 648 GB converted. Demosaic offline, on demand, with the method you choose. The same one-byte-per-pixel logic applies to mono8 logs from mono cameras.

What does the wrong Bayer pattern do to the image?

It swaps channels rather than blurring anything: requesting the pattern of a different sensor layout exchanges red and blue, because green occupies the same positions in every 2×2 block of the common layouts. Blues render as red, skin tones go wrong, and edge-based measurements keep working. Check against a known color patch after the first color capture.