Need raw RGB565 file format spec for Arducam Mega on Arduino Uno

Hi everyone,

I’m working on an application that examines raw pixel data from an Arducam Mega (SKU B0401) on an Arduino Uno, with the OV5642 sensor. I need to read the raw RGB565 bytes directly — I’m not trying to convert RGB565 into an image.

What I can’t figure out is the exact layout of the raw .raw file the camera writes. Specifically:

  • Does the Arducam put any formatting/header data inside the .raw file?
  • Where does the actual pixel data start?
  • How is the color encoded in the bytes? My understanding is RGB565 means each pair of bytes contains 5 bits of Red, 6 bits of Blue, and 5 bits of Green.
  • Where are the image width and height stored in the file?
  • Are there any bytes that represent a new line or end of file?

Honestly a file format spec for the raw image would be ideal.

I’ve gone through all the Arducam docs I can find, the OV5642 datasheet, forum posts, and a bunch of YouTube videos. The closest thing I found is this Python snippet that converts RGB565 to an image:

# Convert RGB565 format to an image
def RGB565ToMat(self, data, Width, Height):
    arr = np.frombuffer(data, dtype='<u2').astype(np.uint32)
    arr = ((arr & 0xFF00) >> 8) + ((arr & 0x00FF) << 8)
    arr = 0xFF000000 + ((arr & 0xF800) << 8) + ((arr & 0x07E0) << 5) + ((arr & 0x001F) << 3)
    arr.dtype = np.uint8
    image = arr.reshape(Height, Width, 4)
    return image

But that assumes I already have clean pixel data and just converts it. It doesn’t tell me what’s in the file before that.

Thanks for the details. One thing that matters a lot here: are you reading the raw data returned directly by the SDK, or are you using the full_featured demo sketch? The full_featured demo packs the data before sending it over the serial port, so in that case the bytes you get are not just plain pixel data.

I’m mostly working with the SDK’s raw capture output — I assumed that would be the actual .raw file. But I’ve also looked at the full_featured sketch. Either way, what I really need is the raw RGB file format itself: where pixel data starts, how the RGB565 bytes are encoded, where width/height live, and whether there’s any header or newline/EOF bytes mixed in. All I keep finding is that conversion example.

The RGB565 encoding itself is straightforward: 2 bytes per pixel. In case it helps, here’s the standard conversion used to turn that buffer into an image:

# Convert RGB565 format to an image
def RGB565ToMat(self, data, Width, Height):
    arr = np.frombuffer(data, dtype='<u2').astype(np.uint32)
    arr = ((arr & 0xFF00) >> 8) + ((arr & 0x00FF) << 8)
    arr = 0xFF000000 + ((arr & 0xF800) << 8) + ((arr & 0x07E0) << 5) + ((arr & 0x001F) << 3)
    arr.dtype = np.uint8
    image = arr.reshape(Height, Width, 4)
    return image

The important part for your byte question: the buffer is read as little-endian uint16, then byte-swapped, so each 2-byte pixel is interpreted as 5 bits R, 6 bits G, 5 bits B. That’s where 0xF800 (red), 0x07E0 (green) and 0x001F (blue) come from.

Right, I already had that snippet — it’s the conversion I keep seeing everywhere. My issue isn’t converting RGB565 into an image. I need to know the file format before conversion: is there a header, where does pixel data actually start, and where are width/height stored? The conversion code just assumes I already know Width and Height and have a clean data buffer.

Fair point. Let me lay out the byte-level part of that code more clearly, because it does describe the pixel layout inside the buffer:

# Convert RGB565 format to an image
def RGB565ToMat(self, data, Width, Height):
    arr = np.frombuffer(data, dtype='<u2').astype(np.uint32)
    arr = ((arr & 0xFF00) >> 8) + ((arr & 0x00FF) << 8)
    arr = 0xFF000000 + ((arr & 0xF800) << 8) + ((arr & 0x07E0) << 5) + ((arr & 0x001F) << 3)
    arr.dtype = np.uint8
    image = arr.reshape(Height, Width, 4)
    return image

Each pixel is one 16-bit word, little-endian on the wire. The swap is needed because the bytes arrive in the opposite order. After the swap, red is the top 5 bits, green the middle 6, blue the low 5. But you’re right that this still assumes a clean buffer.

That helps for the encoding part, thanks. But I still don’t know whether the .raw file from the SDK has a header before the pixels, or where width/height are stored. Does the file have any structure other than the pixel bytes?

The raw data read out by the SDK is just that — raw pixel data, no header. For example, if you select 96x96 resolution, the buffer is 96962 bytes total (2 bytes per RGB565 pixel). Width and height are not stored in the file; they come from the resolution you configured in the sketch/SDK.

If you use the full_featured example instead, note that the data is packed before being sent over the serial port, so it isn’t plain raw pixels anymore. To parse the packed full_featured data, check the Renesas example in the docs:

https://www.arducam.com/docs/arducam-mega/arducam-mega-getting-started/packs/example/renesas.html

So in short: SDK raw = widthheight2 bytes with no header and no newline/EOF markers. full_featured = packed serial data that needs to be unpacked first.