Răsfoiți Sursa

varvusensor/nutikodu-web: varvi valge tasakaal (valge -> D65)

- color.py: XYZ skaleeritakse nii, et uhtlased kanalid = D65 (eemaldab roosa/red nihke; R=1 -> #FFFFFF)

- nutikodu-web: toores varv arvutatakse kanalitest (valge-tasakaalustatud), mitte salvestatud rgb_hex-ist
ardo 1 săptămână în urmă
părinte
comite
9c81c5e297
3 a modificat fișierele cu 63 adăugiri și 10 ștergeri
  1. 7 6
      dev/nutikodu-web/app.py
  2. 28 2
      dev/nutikodu-web/color.py
  3. 28 2
      dev/varvusensor/collector/color.py

+ 7 - 6
dev/nutikodu-web/app.py

@@ -594,15 +594,16 @@ async def varv_latest(limit: int = Query(60, ge=1, le=300)) -> dict:
     out = []
     for r in rows:
         bands = {b: r.get(b) for b in VARV_BANDS}
+        raw = color.analyze(bands)
         item = {
             "ts": r["ts"],
             "t": int(r["t"]),
-            "rgb_hex": r.get("rgb_hex") or "#000000",
-            "r": int(r.get("r") or 0),
-            "g": int(r.get("g") or 0),
-            "b": int(r.get("b") or 0),
-            "x_chrom": r.get("x_chrom"),
-            "y_chrom": r.get("y_chrom"),
+            "rgb_hex": raw["rgb_hex"],
+            "r": raw["r"],
+            "g": raw["g"],
+            "b": raw["b"],
+            "x_chrom": raw["x_chrom"],
+            "y_chrom": raw["y_chrom"],
             "bands": bands,
             "clear": r.get("clear"),
             "nir": r.get("nir"),

+ 28 - 2
dev/nutikodu-web/color.py

@@ -86,9 +86,35 @@ def chromaticity_xy(x: float, y: float, z: float) -> tuple[float, float]:
     return x / total, y / total
 
 
-def analyze(channels: dict[str, float]) -> dict:
-    """Tagastab tuletatud värviväljad ClickHouse'i rea jaoks."""
+# D65 valgepunkt (CIE XYZ)
+D65_WHITE = (0.95047, 1.0, 1.08883)
+
+
+def _white_reference_xyz() -> tuple[float, float, float]:
+    """XYZ, kui kõik kanalid = 1 (st ühtlane/valge spekter)."""
+    x = y = z = 0.0
+    for wavelength in CHANNEL_WAVELENGTHS.values():
+        cx, cy, cz = cie_xyz_cmf(wavelength)
+        x += cx
+        y += cy
+        z += cz
+    return x, y, z
+
+
+_WHITE_XYZ = _white_reference_xyz()
+
+
+def analyze(channels: dict[str, float], white_balance: bool = True) -> dict:
+    """Tagastab tuletatud värviväljad ClickHouse'i rea jaoks.
+
+    white_balance=True korral skaleeritakse XYZ nii, et ühtlased kanalid
+    (valge) vastavad D65 valgele — muidu annab mudel kerge roosa nihke.
+    """
     x, y, z = channels_to_xyz(channels)
+    if white_balance and _WHITE_XYZ[0] > 0 and _WHITE_XYZ[1] > 0 and _WHITE_XYZ[2] > 0:
+        x *= D65_WHITE[0] / _WHITE_XYZ[0]
+        y *= D65_WHITE[1] / _WHITE_XYZ[1]
+        z *= D65_WHITE[2] / _WHITE_XYZ[2]
     cx, cy = chromaticity_xy(x, y, z)
     r, g, b = xyz_to_srgb(x, y, z)
     return {

+ 28 - 2
dev/varvusensor/collector/color.py

@@ -86,9 +86,35 @@ def chromaticity_xy(x: float, y: float, z: float) -> tuple[float, float]:
     return x / total, y / total
 
 
-def analyze(channels: dict[str, float]) -> dict:
-    """Tagastab tuletatud värviväljad ClickHouse'i rea jaoks."""
+# D65 valgepunkt (CIE XYZ)
+D65_WHITE = (0.95047, 1.0, 1.08883)
+
+
+def _white_reference_xyz() -> tuple[float, float, float]:
+    """XYZ, kui kõik kanalid = 1 (st ühtlane/valge spekter)."""
+    x = y = z = 0.0
+    for wavelength in CHANNEL_WAVELENGTHS.values():
+        cx, cy, cz = cie_xyz_cmf(wavelength)
+        x += cx
+        y += cy
+        z += cz
+    return x, y, z
+
+
+_WHITE_XYZ = _white_reference_xyz()
+
+
+def analyze(channels: dict[str, float], white_balance: bool = True) -> dict:
+    """Tagastab tuletatud värviväljad ClickHouse'i rea jaoks.
+
+    white_balance=True korral skaleeritakse XYZ nii, et ühtlased kanalid
+    (valge) vastavad D65 valgele — muidu annab mudel kerge roosa nihke.
+    """
     x, y, z = channels_to_xyz(channels)
+    if white_balance and _WHITE_XYZ[0] > 0 and _WHITE_XYZ[1] > 0 and _WHITE_XYZ[2] > 0:
+        x *= D65_WHITE[0] / _WHITE_XYZ[0]
+        y *= D65_WHITE[1] / _WHITE_XYZ[1]
+        z *= D65_WHITE[2] / _WHITE_XYZ[2]
     cx, cy = chromaticity_xy(x, y, z)
     r, g, b = xyz_to_srgb(x, y, z)
     return {