Skip to content

Calibrate applies a garbage colour matrix from a frame with no chart (false detectChart, no fit-quality gate) #42

Description

@widgetii

Summary

On a frame with no colour chart in it, Calibrate produces a colour matrix that makes the camera's live picture unwatchable, and offers to apply it. Two separate defects combine to cause this:

  1. detectChart() reports a chart where there is none, with corners outside the frame.
  2. solveFromPatches() has no check on how good the fit is. A fit with a mean ΔE2000 around 24, where the panel itself calls under 2 good, still gets Apply to the camera.

A user who opens the editor on an ordinary scene sees a "found" chart, clicks Measure, then Apply, and the stream turns into a noisy mosaic. That is what the reporter describes at OpenIPC/firmware#2234 (comment): "I used 'automatic' functions … after that I got mosaic black and white tiled image. To revert, I did rm /etc/majestic.yaml".

Reproduction

This uses raw-editor at 71040d9, run headlessly with the same calls measureChart() makes: engine.open(dng), detectChart(), patchCentres(corners), samplePatch() for each cell, then solveFromPatches(patches, {clipped, colorMatrices}). The input is a /image.dng from a gk7205v200 + IMX307 camera looking at a plain, red-lit wall with no chart.

frame 1920 x 1080 cfa 0 black 240 white 4095
detectChart: {"corners":[[945.9,230.1],[1845.7,230.8],[2170.0,1985.8],[634.0,1095.3]],"cells":19}

== detected corners: patches 20, mean dE2000 24.10, worst 37.32
      2.9713  -15.0481   13.0769  rowsum 1.000
      7.4899  -13.9628    7.4729  rowsum 1.000
      2.7751   -4.9203    3.1451  rowsum 1.000

== default corners (middle third): patches 24, mean dE2000 24.36, worst 32.70
     -1.0112   -0.5553    2.5664  rowsum 1.000
     -0.6399   -1.0803    2.7202  rowsum 1.000
      7.2588   -9.3362    3.0774  rowsum 1.000

== a user-dragged area, bottom middle: patches 24, mean dE2000 24.65, worst 48.40
      8.6385  -10.6353    2.9968  rowsum 1.000
     14.8869  -16.2932    2.4062  rowsum 1.000
     18.8230  -19.8783    2.0554  rowsum 1.000

Every result passes the solver's own refusals (at least 12 usable patches, at least 2 greys, not singular), and every row sums to exactly 1. So majestic's only check on isp.colorMatrix accepts them too.

Posting the first and third matrices with POST /api/v1/config {"isp":{"colorMatrix": …}}, the same call raw-calibrate.js makes, turned the live JPEG from a normal red wall into sensor noise amplified into a coarse speckle, with garbage colours: saturated green and white for one, flat yellow for the other. Posting {"isp":{"colorMatrix":null}} put the picture back exactly; it matched a fresh majestic start.

What should change

  • detectChart(): do not return corners outside the frame. More generally, a quad whose 24 cells are not distinct patches is not a chart. Here, 19 "cells" on a uniform wall.
  • solveFromPatches() / the Calibrate panel: refuse, or at least withhold Apply to the camera, when the fit is far outside what a chart produces. A mean ΔE2000 in the 20s means the patches were not the chart. The panel already prints the number; it just never acts on it.
  • Worth checking: the 30 s hold asks the user to confirm the picture still looks right. If the image on screen during the hold is the editor's rendering of the RAW frame rather than the live stream, the user cannot see the damage they are being asked to confirm. The reporter still ended up with the matrix persisted.

The camera-side guard is tracked separately in majestic: rows summing to 1 is not enough to reject a matrix like these.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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