Skip to content

Instantly share code, notes, and snippets.

@NotSoIntelligent
Created April 16, 2025 07:35
Show Gist options
  • Select an option

  • Save NotSoIntelligent/5770a7a199309cd1d8a1418cc9f70695 to your computer and use it in GitHub Desktop.

Select an option

Save NotSoIntelligent/5770a7a199309cd1d8a1418cc9f70695 to your computer and use it in GitHub Desktop.
Python script to Convert Bayer Mipi packed Raw image to Unpacked 16 bit RAW

MIPI RAW Image Unpacker

This Python script unpacks RAW Bayer MIPI-packed images (RAW10 or RAW12) into 16-bit RAW format.


🔧 Features

  • Supports RAW10 (4 pixels in 5 bytes) and RAW12 (2 pixels in 3 bytes) formats.
  • Converts packed MIPI RAW to 16-bit little-endian format for easier processing and analysis.
  • CLI-based, fast, and portable.

🧰 Prerequisites

  • Python 3.6+
  • No external libraries required (only standard Python libraries)

▶️ Usage

python3 mipi_unpack.py <input_file.raw> <bit_depth> [-o <output_file.raw>]

Arguments:

Argument Description
<input_file.raw> Path to the MIPI packed RAW image
<bit_depth> Bit depth: 10 for RAW10 or 12 for RAW12
-o, --output (Optional) Output filename

🧪 Examples

Unpack RAW10 image:

python3 mipi_unpack.py image_raw10.raw 10

Unpack RAW12 image with custom output filename:

python3 mipi_unpack.py image_raw12.raw 12 -o image_unpacked.raw

📂 Output

  • The output is a raw binary file where each pixel is stored as a 16-bit unsigned integer (little endian).
  • You can load this in tools like ImageJ, MATLAB, OpenCV, or any image viewer that supports raw 16-bit input.

🚫 Limitations

  • Only supports MIPI packed RAW10 and RAW12 formats.
  • Assumes byte-aligned data with no frame headers or footers.

import argparse
import os
import sys
import struct
def unpack_mipi_raw(data: bytes, bpp: int) -> bytearray:
"""
Unpacks MIPI RAW10 or RAW12 packed data into 16-bit pixels.
Returns: bytearray of unpacked 16-bit pixel values.
"""
unpacked = bytearray()
if bpp == 10:
# RAW10: 4 pixels = 5 bytes
if len(data) % 5 != 0:
raise ValueError("Invalid RAW10 data size.")
for i in range(0, len(data), 5):
b0, b1, b2, b3, b4 = data[i:i+5]
p0 = ((b0 << 2) | ((b4 >> 0) & 0x03))
p1 = ((b1 << 2) | ((b4 >> 2) & 0x03))
p2 = ((b2 << 2) | ((b4 >> 4) & 0x03))
p3 = ((b3 << 2) | ((b4 >> 6) & 0x03))
unpacked += struct.pack('<HHHH', p0, p1, p2, p3)
elif bpp == 12:
# RAW12: 2 pixels = 3 bytes
if len(data) % 3 != 0:
raise ValueError("Invalid RAW12 data size.")
for i in range(0, len(data), 3):
b0, b1, b2 = data[i:i+3]
p0 = ((b0 << 4) | ((b2 >> 0) & 0x0F))
p1 = ((b1 << 4) | ((b2 >> 4) & 0x0F))
unpacked += struct.pack('<HH', p0, p1)
else:
raise ValueError("Only 10bpp or 12bpp supported.")
return unpacked
def main():
parser = argparse.ArgumentParser(description="Unpack MIPI RAW10/RAW12 image to 16-bit format")
parser.add_argument("input_file", help="Path to the MIPI packed RAW image")
parser.add_argument("bpp", type=int, choices=[10, 12], help="Bit depth of packed RAW image (10 or 12)")
parser.add_argument("-o", "--output", help="Output file name (default: <input>_unpacked.raw)")
args = parser.parse_args()
# Read input
try:
with open(args.input_file, "rb") as f:
packed_data = f.read()
except Exception as e:
print(f"Error reading input file: {e}")
sys.exit(1)
# Unpack
try:
unpacked_data = unpack_mipi_raw(packed_data, args.bpp)
except Exception as e:
print(f"Error unpacking image: {e}")
sys.exit(2)
# Write output
output_file = args.output or f"{os.path.splitext(args.input_file)[0]}_unpacked.raw"
try:
with open(output_file, "wb") as f:
f.write(unpacked_data)
print(f"Unpacked image written to: {output_file}")
except Exception as e:
print(f"Error writing output file: {e}")
sys.exit(3)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment