Files
business-card-scanner/tests/test_segment.py
Lucas Orth ab993e98e1 Visitenkarten-Scanner: Stapelscan, Extraktion, Übersicht, vCard-Export
Selbst gehostete PWA, die Visitenkarten von einem Foto freistellt, ausliest
und als Kontakt bereitstellt.

- Stapelscan: OpenCV findet die Kartenrechtecke über mehrere Binärmasken,
  entzerrt sie perspektivisch und schneidet sie einzeln aus. Ohne Fund gilt
  das ganze Foto als eine Karte.
- Extraktion: ein Aufruf je Zuschnitt an das Vision-Modell mit
  JSON-Schema. Kein vorgeschaltetes OCR - das würde Layout und
  Schriftgrößen wegwerfen, aus denen die Feldzuordnung entsteht.
- Metadaten: Aufnahmezeit und GPS aus den EXIF-Daten des Fotos, Ortsname
  über Nominatim, Browserstandort nur als Rückfallebene.
- Übersicht mit Volltextsuche und Filtern, Detailansicht mit Korrekturmaske.
- Notizfeld je Karte, Erinnerungen per Mail inklusive Nachholen verpasster
  Termine nach einem Neustart.
- vCard 3.0 einzeln und als Sammeldatei, Karte gilt danach als exportiert.
- Anmeldung über ein Passwort, Sitzung als signiertes Cookie.
- Deployment per Tag-Push nach den Konventionen in DEPLOY.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 11:45:56 +02:00

46 lines
1.2 KiB
Python

import numpy as np
from app import segment
from tests.helpers import photo_with_cards
def test_findet_alle_karten_im_stapel():
photo = photo_with_cards(count=6)
crops, fallback = segment.segment(photo)
assert fallback is False
assert len(crops) == 6
def test_zuschnitte_haben_kartenformat():
crops, _ = segment.segment(photo_with_cards(count=4))
for crop in crops:
height, width = crop.shape[:2]
assert (width, height) == (segment.OUT_WIDTH, segment.OUT_HEIGHT)
def test_zuschnitt_enthaelt_die_karte_und_nicht_den_tisch():
crops, _ = segment.segment(photo_with_cards(count=4))
for crop in crops:
# Die Karte ist weiss, der Untergrund dunkel. Ein Zuschnitt, der
# danebenliegt, waere im Mittel dunkel.
assert crop.mean() > 170
def test_grosser_stapel():
crops, fallback = segment.segment(photo_with_cards(count=12))
assert fallback is False
assert len(crops) == 12
def test_einzelne_formatfuellende_karte_faellt_auf_gesamtbild_zurueck():
# Randlose Karte: es gibt keine Kante zum Untergrund, also keinen Fund.
card = np.full((1080, 1712, 3), 245, dtype=np.uint8)
crops, fallback = segment.segment(card)
assert fallback is True
assert len(crops) == 1