Arducam Mega 5MP camera YUV data format: Is the first byte luma?

Hey folks, I’m trying to get image data out of an Arducam Mega 5MP over SPI and everything is coming out blue. Like, various shades of blue, but nothing resembling a real color image.

I’m not using the PC GUI tool — I’m reading the FIFO directly from the sensor and trying to interpret the pixels as RGB565. The camera’s output format isn’t really documented anywhere I can find, so I’m kind of guessing here.

Anyone know what format this camera actually spits out? Or has anyone else seen this blue-tint issue with raw captures?

Can you share a bit more about your setup? Specifically — what resolution are you running, and how many bytes are you pulling from the FIFO per frame? That’ll help narrow down whether the pixel format assumption is correct.

Sure. I’m running at 96x96 for testing purposes. Each frame I’m reading 18,432 bytes from the FIFO, which works out to 96 × 96 × 2 bytes per pixel, so 2 bytes per pixel. That part checks out for RGB565 at least.

Interface is SPI, camera is the Arducam Mega 5MP.

Yeah, that math lines up — 96 × 96 × 2 = 18,432 bytes, which is exactly right for RGB565. So the pixel format should indeed be RGB565.

The “all blue” thing is unusual though. Would you be able to capture a test frame and save two things for me?

  1. The raw FIFO data — just dump the entire 18,432-byte buffer straight to a binary file (.bin or .dat), no processing at all.
  2. The rendered image your code produces from that same data — save it as a BMP or PNG so I can see what “shades of blue” actually looks like.

That way I can compare what the sensor is sending versus what your code is rendering and figure out where the disconnect is.

Before sending data, I started doing some more systematic testing on my end. I tested all the likely RGB formats — RGB444, RGB555, RGB565 — and even tried interpreting it as raw Bayer. Nothing looked right.

But… I think I found the bug. And it’s embarrassingly simple.

Here’s what I was doing to assemble each 16-bit pixel from two bytes:

uint16_t pixel = byte1 + byte2;

Yeah, I was just adding them. Instead of:

uint16_t pixel = (byte1 << 8) | byte2;

That’s why everything was blue — the addition was basically crushing all the color channels and the blue channel was dominating in whatever was left. There was a tiny bit of green in there too, but mostly just blue.

Ha, that’ll do it. Classic — and honestly easy to miss when you’re neck-deep in getting the SPI reads working. Adding the bytes instead of shifting and OR-ing means the MSB never gets into the right position, so the red channel (which sits in the upper 5 bits of the 16-bit word) gets completely scrambled.

So just to confirm — you swapped in (byte1 << 8) | byte2 and things look normal now?

Yep, that fixed it. The corrected code produces a proper RGB color image now. I compared it against the reference JPG output and it matches. So confirmed: the Arducam Mega 5MP outputs standard RGB565 over the FIFO — 5 bits red, 6 bits green, 5 bits blue across two consecutive bytes. No surprises in the format itself, it was my pixel assembly that was broken.

Glad you sorted it out before I even got to look at the sample data! And good to have confirmation on the RGB565 format for anyone else who finds this thread.

To summarize the root cause for posterity: the sensor output was fine, the issue was assembling the 16-bit pixel value. Using byte1 + byte2 instead of (byte1 << 8) | byte2 corrupts the bit layout — the upper byte (which carries the red channel and part of green) never gets shifted into position, so you end up with a blue-dominated mess.

Thanks. Now that RGB565 is sorted, I have a follow-up question about this camera’s YUV mode.

I’m working on a robot vision project and I’d like to use YUV output so I can grab just the luma channel directly as grayscale. In my testing, if I take the 1st byte of each 16-bit word, it seems to give me reasonable grayscale output. But I haven’t found any documentation confirming the byte layout.

Does anyone know the exact YUV format this camera uses? Is it really YUYV? And is that first byte actually Y (luminance)?

Good question. The Arducam Mega 5MP outputs YUV 4:2:2, and the byte ordering is YUYV.

Here’s the layout — for every two pixels, you get a 4-byte sequence:

  • Byte 0: Y0 (luminance for pixel 0)
  • Byte 1: U (chrominance, shared between pixel 0 and 1)
  • Byte 2: Y1 (luminance for pixel 1)
  • Byte 3: V (chrominance, shared between pixel 0 and 1)

So to answer your question directly: yes, the first byte is indeed Y (greyscale/luma) for the first pixel. And the third byte (offset 2 in each 4-byte block) is Y for the second pixel. If you’re just pulling every other byte starting from byte 0, you’re getting the Y values and that’s valid grayscale data.

So your approach of using the 1st byte as Y is correct — you’ll get proper luminance without needing to do any color space conversion.