Skip to content

Document: Grayscale/desaturated colors on libcamera devices with uncalibrated sensors #185

@FreddyFunk

Description

@FreddyFunk

Problem

When using the camera app on devices with libcamera and uncalibrated or minimally-tuned sensors, captured images appear grayscale or severely desaturated despite being stored as color images.

Observed Behavior

  • Captured images appear monochrome/grayscale
  • RGB channel values are nearly identical (e.g., R=0.031, G=0.032, B=0.031)
  • Images are technically color (3 channels, sRGB colorspace) but visually grayscale
  • Preview also appears desaturated

Expected Behavior

Images should have proper color reproduction.

Root Cause

This is not a bug in the camera app but rather a limitation of libcamera's "simple" IPA (Image Processing Algorithm) pipeline when used with uncalibrated sensors.

The libcamera simple pipeline tuning files for many sensors have the Color Correction Matrix (CCM) algorithm disabled:

imx371.yaml (front camera tuning)

# SPDX-License-Identifier: CC0-1.0
%YAML 1.1
---
version: 1
algorithms:
  - BlackLevel:
      blackLevel: 4096
  - Awb:
  - Adjust:
  - Agc:
...

uncalibrated.yaml (reference)

# SPDX-License-Identifier: CC0-1.0
%YAML 1.1
---
version: 1
algorithms:
  - BlackLevel:
  - Awb:
  # Color correction matrices can be defined here. The CCM algorithm
  # has a significant performance impact, and should only be enabled
  # if tuned.
  # - Ccm:
  #     ccms:
  #       - ct: 6500
  #         ccm: [ 1, 0, 0,
  #                0, 1, 0,
  #                0, 0, 1]
  - Adjust:
  - Agc:
...

The CCM (Color Correction Matrix) is explicitly commented out with the note: "has a significant performance impact, and should only be enabled if tuned."

Without CCM, the raw Bayer sensor data is debayered but not color-corrected, resulting in grayscale or heavily desaturated output.

Technical Details

Device Information

  • Device: OnePlus 6T (oneplus-fajita)
  • OS: postmarketOS edge
  • Kernel: 6.16.7-sdm845
  • Architecture: aarch64
  • Cameras: imx371 (front), imx376 (back)
  • libcamera pipeline: simple

Image Analysis

$ exiftool IMG_20260201_002850.jpg
File Size                       : 5.3 MB
Image Width                     : 3840
Image Height                    : 2160
Color Components                : 3
Y Cb Cr Sub Sampling            : YCbCr4:4:4 (1 1)

$ identify -verbose IMG_20260201_002850.jpg | grep -E '(Colorspace|Type)'
  Colorspace: sRGB
  Type: TrueColor

$ convert IMG_20260201_002850.jpg -colorspace RGB -format "%[fx:mean.r] %[fx:mean.g] %[fx:mean.b]" info:
0.0316212 0.0321284 0.0316602

The image is stored as TrueColor sRGB with 3 color channels, but the RGB means are nearly identical, confirming the visual grayscale appearance.

libcamera Tuning Files Location

/usr/share/libcamera/ipa/simple/imx371.yaml  (145 bytes - minimal)
/usr/share/libcamera/ipa/simple/imx376.yaml  (145 bytes - minimal)
/usr/share/libcamera/ipa/simple/uncalibrated.yaml  (404 bytes - reference)

This is NOT Fixable by the Camera App

The color correction happens at the libcamera/kernel level before frames reach our application. The camera app receives already-processed (but poorly color-corrected) frames from PipeWire/libcamera.

Possible solutions outside this project:

  1. postmarketOS: Create properly calibrated CCM tuning files for imx371/imx376 sensors
  2. libcamera upstream: Improve the simple pipeline's default color handling
  3. Kernel/Device Tree: Some SoCs may support hardware ISP that could handle color correction

Workarounds

Users experiencing this issue on postmarketOS or similar libcamera-based systems can:

  1. Report to postmarketOS: File an issue requesting proper sensor tuning for their device
  2. Manual tuning: Advanced users can create custom tuning files with CCM enabled:
    algorithms:
      - BlackLevel:
          blackLevel: 4096
      - Awb:
      - Ccm:
          ccms:
            - ct: 6500
              ccm: [ 1.5, -0.3, -0.2,
                    -0.2,  1.4, -0.2,
                    -0.1, -0.3,  1.4]
      - Adjust:
      - Agc:
    Note: CCM values need to be calibrated for each sensor.

Documentation

This issue should be documented in the postmarketOS development guide as a known limitation.

Affected Devices

Any device using libcamera's "simple" pipeline with uncalibrated sensors:

  • OnePlus 6/6T (sdm845)
  • PinePhone (various)
  • Librem 5
  • Other mobile Linux devices with libcamera

References

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions