package ocr import ( "bytes" "context" "image" "image/color" "image/png" "testing" ) // TestRecognizeWithLanguageAndConfidence_MultilingualCorpus ist die // geforderte Pflichtprüfung 1: Test mit mehrsprachigem Testkorpus // bestätigt korrekte Spracherkennung. func TestRecognizeWithLanguageAndConfidence_MultilingualCorpus(t *testing.T) { requireTools(t) ctx := context.Background() germanImage := knownTextImage(t, ctx, "Rechnung ueber Lieferung Nummer Zwei") englishImage := knownTextImage(t, ctx, "Invoice for delivery number two") germanResult, err := RecognizeWithLanguageAndConfidence(ctx, germanImage) if err != nil { t.Fatalf("deutsches bild: %v", err) } if germanResult.Language != "deu" { t.Fatalf("erwartete sprache 'deu' für deutschen text, habe %q (text: %q)", germanResult.Language, germanResult.Text) } englishResult, err := RecognizeWithLanguageAndConfidence(ctx, englishImage) if err != nil { t.Fatalf("englisches bild: %v", err) } if englishResult.Language != "eng" { t.Fatalf("erwartete sprache 'eng' für englischen text, habe %q (text: %q)", englishResult.Language, englishResult.Text) } } // TestRecognizeWithLanguageAndConfidence_DegradedImageLowersConfidence ist // die geforderte Pflichtprüfung 2: künstlich verschlechtertes Bild erzeugt // niedrigeren Konfidenzwert. func TestRecognizeWithLanguageAndConfidence_DegradedImageLowersConfidence(t *testing.T) { requireTools(t) ctx := context.Background() original := knownTextImage(t, ctx, "Qualitaetsvergleich Testbild Konfidenz") originalImg, err := png.Decode(bytes.NewReader(original)) if err != nil { t.Fatalf("original dekodieren: %v", err) } degradedImg := pixelate(originalImg, 12) var degradedBuf bytes.Buffer if err := png.Encode(°radedBuf, degradedImg); err != nil { t.Fatalf("verschlechtertes bild kodieren: %v", err) } originalResult, err := RecognizeWithLanguageAndConfidence(ctx, original) if err != nil { t.Fatalf("original erkennen: %v", err) } degradedResult, err := RecognizeWithLanguageAndConfidence(ctx, degradedBuf.Bytes()) if err != nil { t.Fatalf("verschlechtertes bild erkennen: %v", err) } t.Logf("original: conf=%.2f text=%q — verschlechtert: conf=%.2f text=%q", originalResult.Confidence, originalResult.Text, degradedResult.Confidence, degradedResult.Text) if degradedResult.Confidence >= originalResult.Confidence { t.Fatalf("erwartete niedrigeren konfidenzwert für verschlechtertes bild, habe original=%.2f verschlechtert=%.2f", originalResult.Confidence, degradedResult.Confidence) } } // pixelate verschlechtert img künstlich, reproduzierbar und ohne externe // Werkzeuge: Downsample um factor per Nearest-Neighbor, dann wieder auf // Originalgröße hochskaliert — zerstört Feindetails der Textglyphen. func pixelate(img image.Image, factor int) image.Image { bounds := img.Bounds() w, h := bounds.Dx(), bounds.Dy() out := image.NewRGBA(bounds) for y := 0; y < h; y++ { for x := 0; x < w; x++ { blockX := (x / factor) * factor blockY := (y / factor) * factor c := img.At(bounds.Min.X+blockX, bounds.Min.Y+blockY) out.Set(bounds.Min.X+x, bounds.Min.Y+y, colorToGray50(c)) } } return out } // colorToGray50 mischt zusätzlich mit 50% Grau, um den Kontrast zu // verringern — verstärkt die künstliche Qualitätsverschlechterung über // reine Pixelierung hinaus. func colorToGray50(c color.Color) color.Color { r, g, b, a := c.RGBA() mix := func(v uint32) uint8 { return uint8((v>>8)/2 + 128/2) } return color.RGBA{R: mix(r), G: mix(g), B: mix(b), A: uint8(a >> 8)} }