HEIC-Fotos annehmen und den Ausschnitt weiter fassen

iPhones fotografieren HEIC; ohne pillow-heif wies die Bildpruefung jedes
Foto ab. Dazu: ein erkannter Vogel ohne bestimmbare Art wird nicht mehr als
"kein Vogel" gemeldet, und der Ausschnitt fuer die Sammlung ist quadratisch.
This commit is contained in:
christian committed 2026-10-14 18:16:08 +00:00
1 parent dbec78aa7a
commit f572c20080
9 files changed
+285 -8

No files matched your search

+31 -4
View File
@@ -88,17 +88,41 @@ class Warteschlange:
# -- Bearbeiten -------------------------------------------------------
def _melden(self, foto_id: int, ausschnitt, result) -> None:
def _melden(self, foto_id: int, ausschnitt, result, box=None) -> None:
import requests
# ⚠️ ``Result.best`` ist eine Property, kein Aufruf — ``result.best()``
# scheitert erst zur Laufzeit und genau dann, wenn ein Vogel
# erkannt wurde.
bester = result.best if result else None
# 🔴 **„Vogel ja, Art nein" ist etwas anderes als „kein Vogel" — und
# ging hier verloren.**
#
# ``Pipeline.run`` gibt in DREI Fällen ``result = None`` zurück: kein
# Fund, Beinahe-Treffer unter der Schwelle, und — der interessante —
# ein sicher erkannter Vogel, dessen Art keine heimische ist. Die Box
# unterscheidet die Fälle, nur hat sie vorher niemand angesehen.
#
# Folge am 14.10.2026: Ein Foto mit einer Meise im Gegenlicht wurde
# mit 93 % als Vogel erkannt und kam in der App als „Kein Vogel
# erkannt. Auf dem Foto war nichts zu finden" an. Christian hat
# daraufhin zugeschnitten — gegen ein Problem, das nie der Zuschnitt
# war. **Eine falsche Auskunft ist teurer als keine.**
#
# ``box.score`` ist genau die Zahl, die „da ist ein Vogel" bedeutet;
# sie gehört in ``mean_bird_score``, dessen Sinn der Server selbst so
# beschreibt: Vogelwert 0 heißt „auf keinem Bild war ein Vogel".
vogelwert = 0.0
if result is not None:
vogelwert = result.bird_score
elif box is not None and self.pipeline.zaehlt_als_vogel(box):
vogelwert = box.score
nutzlast = {
"species": bester.species.slug if bester else None,
"confidence": round(bester.confidence, 4) if bester else 0.0,
"mean_bird_score": round(result.bird_score, 4) if result else 0.0,
"mean_bird_score": round(vogelwert, 4),
"votes": {g.species.slug: round(g.confidence, 4)
for g in (result.guesses[:5] if result else [])},
}
@@ -161,8 +185,11 @@ class Warteschlange:
box, result = self.pipeline.run(bild)
# Den Ausschnitt mitschicken, damit die Sammlung dasselbe Bild
# zeigt wie bei einer Sichtung von der Kamera.
ausschnitt = box.crop(bild) if box is not None else None
self._melden(foto["id"], ausschnitt, result)
# ⚠️ `anzeige_ausschnitt`, nicht `crop`: Der enge Schnitt ist
# fuer den Klassifikator gedacht; in der fast quadratischen
# Kachel der Sammlung bleibt davon nur die Bauchmitte uebrig.
ausschnitt = box.anzeige_ausschnitt(bild) if box is not None else None
self._melden(foto["id"], ausschnitt, result, box)
fertig += 1
except Exception as exc: # absichtlich breit, siehe Docstring
print(f"[warteschlange] Foto {foto['id']} übersprungen: {exc}")