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:
detectChart() reports a chart where there is none, with corners outside the frame.
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.
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:
detectChart()reports a chart where there is none, with corners outside the frame.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 callsmeasureChart()makes:engine.open(dng),detectChart(),patchCentres(corners),samplePatch()for each cell, thensolveFromPatches(patches, {clipped, colorMatrices}). The input is a/image.dngfrom a gk7205v200 + IMX307 camera looking at a plain, red-lit wall with no chart.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.colorMatrixaccepts them too.Posting the first and third matrices with
POST /api/v1/config {"isp":{"colorMatrix": …}}, the same callraw-calibrate.jsmakes, 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.The camera-side guard is tracked separately in majestic: rows summing to 1 is not enough to reject a matrix like these.