Browse Source

Images : les traces d'un trou après réduction ne comptent plus comme des mesures

- 7bb4e8a avait monté le seuil des trous de 1e20 à 1e30, en supposant que
  les traces laissées par la réduction LANCZOS restaient au-dessus de 1e35.
  C'est faux : au bout d'une fine bande de trous (quelques lignes de haut),
  les lobes du noyau se compensent et la trace descend jusqu'à 1,3e26
  (13 440 cas essayés). Prise pour une mesure, elle devenait le maximum de
  l'échelle : sur 60 cartes à trous tirées au hasard, 2 arrivaient délavées
  ou toutes noires.
- Retour à 1e20, qui garde six ordres de grandeur de marge. Les vraies
  valeurs au-dessus de 1e20 sont de nouveau des trous : rares dans un PNG
  ou un TIFF, quand les « sans donnée » à -3,4e38 sont courants.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Johnounet 1 ngày trước cách đây
mục cha
commit
d69d5a01d0
2 tập tin đã thay đổi với 15 bổ sung và 8 xóa
  1. 3 4
      bot/images.py
  2. 12 4
      tests/test_attachments_prep.py

+ 3 - 4
bot/images.py

@@ -31,10 +31,9 @@ _DIRECT_FORMATS = {"JPEG": "image/jpeg", "PNG": "image/png", "GIF": "image/gif",
 _LOSSLESS_FORMATS = {"PNG", "GIF", "BMP", "TIFF"}
 _PNG_MODES = ("L", "RGB")  # modes sans transparence enregistrables tels quels en PNG
 # Image en flottants : une valeur infinie, NaN ou plus grande que ceci (en valeur absolue) n'est pas une
-# mesure mais un trou (zone « sans donnée » d'une carte, souvent ±3,4e38) ou sa trace après la réduction
-# (mesurée au-dessus de 1e35). Assez haut pour garder les vraies valeurs géantes (densités de colonne en
-# astronomie, autour de 1e21).
-_FLOAT_HOLE = 1e30
+# mesure mais un trou (zone « sans donnée » d'une carte, souvent ±3,4e38) ou sa trace après la réduction.
+# Ces traces descendent vers 1e26 au bout d'une fine bande de trous : le seuil garde de la marge en dessous.
+_FLOAT_HOLE = 1e20
 _FLOAT32_MAX = 3.4e38
 
 

+ 12 - 4
tests/test_attachments_prep.py

@@ -115,14 +115,22 @@ class PrepareImageTest(unittest.TestCase):
         self.assertEqual(result.getextrema(), (0, 0))
 
     def test_huge_float_values_not_holes(self):
-        # Densités de colonne en astronomie : de vraies mesures de 1e21 à 5e21, pas des trous à noircir.
-        img = Image.new("F", (300, 100), 1e21)
-        img.paste(3e21, (100, 0, 200, 100))
-        img.paste(5e21, (200, 0, 300, 100))
+        # De très grandes mesures, sous le seuil des trous : étalées comme les autres, pas noircies.
+        img = Image.new("F", (300, 100), 1e18)
+        img.paste(3e18, (100, 0, 200, 100))
+        img.paste(5e18, (200, 0, 300, 100))
         result = opened(prepare_image(encode(img, "TIFF")).data).convert("L")
         for x, expected in ((50, 0), (150, 128), (250, 255)):
             self.assertAlmostEqual(result.getpixel((x, 0)), expected, delta=2)
 
+    def test_float_hole_trace_not_a_measure(self):
+        # Au bout d'une fine bande de trous, la réduction laisse des traces bien plus petites que le trou
+        # (vers 1e26 ici) : elles ne doivent pas compter comme des mesures et écraser les gris du reste.
+        img = Image.new("F", (5003, 60), 0.5)
+        img.paste(3.4e38, (33, 10, 800, 18))
+        result = opened(prepare_image(encode(img, "TIFF")).data).convert("L")
+        self.assertEqual(result.getpixel((1000, 15)), 128)
+
     def test_uniform_out_of_range_grey(self):
         # Image uniforme hors des plages connues : rien à voir, mais un gris moyen plutôt qu'un noir de trou.
         for img in (Image.new("I", (200, 100), 100000), Image.new("F", (200, 100), -5.0)):