added source code samples

This commit is contained in:
Simon
2024-01-07 21:29:50 +01:00
parent bb04210d35
commit 6c95ba39a0
3 changed files with 74 additions and 30 deletions
+73 -29
View File
@@ -130,13 +130,57 @@ Für den grundlegenden Ablauf der Bildverarbeitung und der anschließenden Ergeb
Angefangen mit einem Ausgangsbild, welches über die Softwarebibliothek Magick.NET geladen wurde, beginnt die Bildverarbeitung zunächst mit dem Resampling. Falls der geladene Screenshot die Mindestauflösung von 300dpi unterschreitet, wird es mittels Lanczos2-Verfahren, eine von Magick.NET mitgelieferte Implementierung des Lanczos2-Algorithmus mit leichter Schärfung, auf die Mindestauflösung vergrößert. Anschließend wird das Bild normalisiert, in Graustufen umgewandelt und jegliche Transparenz durch einen weißen Hintergrund ersetzt. Danach wird es mittels Schwellwertverfahren binarisiert und rund um das Bild wird ein Rahmen mit einer Dicke von 10px eingefügt. Um Texterkennungsfehler durch falsche Vorder- \bzw Hintergrundfarben auszuschließen, wird das Bild schlussendlich gemeinsam mit einer farblich invertierten Version an das Texterkennungssystem weitergegeben.
\begin{CsCode}[numbers=none]
var preprocessing = new ProcessorChainConfiguration<MagickImage, MagickImage>()
.Use(new CloneImageProcessor())
.Use(new ResizeProcessor(FilterType.Lanczos2Sharp, PixelInterpolateMethod.Mesh))
.Use(new NormalizeProcessor())
.Use(_thresholdProcessor)
.Use(new AddBorderProcessor(10))
.Use(new BinarizeProcessor())
.Use(new NegateCloneProcessor())
.Complete(OnPreprocessed);
\end{CsCode}
\label{program:program_preprocessor_definition}
\captionof{program}{Auszug aus Datei "EvaluationProcessor.cs": Definition der Preprocessing-Kette}
Wurde der übergebene Screenshot vom Texterkennungssystem verarbeitet, müssen nun die Ergebnisse gefiltert werden. Dazu werden zunächst die Metadaten der einzelnen Wörter betrachtet und alle Elemente mit einer Confidence unter einem Schwellenwert von 50\% verworfen. Danach werden die erkannten Texte mittels der \csharp-Funktion ToLower() normalisiert und anschließend auf Duplikate untersucht. Sind alle Duplikate verworfen, werden die Wörter schlussendlich mittels sprachabhängigen Regular Expressions -- in diesem Fall gibt es gemäß den Annahmen in \autoref{annahmen_mehrsprachigkeit} einen Sprachfilter für Englisch und Deutsch -- gefiltert.
\begin{CsCode}[numbers=none]
var postprocessing = new ProcessorChainConfiguration<ScanResult, ScanResult>()
.Use(new ConfidenceFilter(50))
.Use(new ToLowerProcessor())
.Use(new DuplicateFilter())
.Complete(new RegexFilter(wordRegex));
\end{CsCode}
\label{program:program_postprocessor_definition}
\captionof{program}{Auszug aus Datei "EvaluationProcessor.cs": Definition der Postprocessing-Kette}
\subsubsection{Automatische Berichterstellung}
\label{components_reportgenerator}
Mithilfe des ReportGenerator-Frameworks wird die automatische Berichterstellung für unterschiedlichste Ausgabeformate abstrahiert. Durch die mitgelieferten Schnittstellendefinitionen ist es möglich, eigene Ausgabeformate zu definieren und den Funktionsumfang des ReportGenerators, wie beispielsweise das Erstellen von Tabellen oder das Anlegen und Überschriften, an die jeweilige Syntax und Dokumentstruktur anzupassen.
\begin{CsCode}[numbers=none]
public interface IDocumentGenerator : IStreamWriter
{
IDocumentGenerator Append(string? text = default);
IDocumentGenerator AppendLine(string? text = default);
IDocumentGenerator AppendParagraph(string? text = default);
IDocumentGenerator AppendHeading(int level, string text);
IDocumentGenerator AppendTable(int columns, Action<ITableGenerator> table);
string FormatImage(string path, IBounds? bounds = default);
}
\end{CsCode}
\label{program:program_reportgenerator_interface}
\captionof{program}{Auszug aus Datei "IDocumentGenerator.cs": Hauptschnittstelle für den ReportGenerator}
\subsection{Programmablauf}
Die prototypische Implementierung besteht neben den oben genannten Komponenten aus einem ausführbaren Kommandozeilenprogramm zur Texterkennung und einem Programm zum Vergleich der Ergebnisse mit den manuell verschlagworteten Soll-Daten.
@@ -167,7 +211,7 @@ Zu Beginn der Ausführung des Kommandozeilenprogramms wird für jedes zu verarbe
yield return new(new AutoThresholdProcessor(AutoThresholdMethod.Triangle));
}
\end{CsCode}
\label{program:program_processor_definition}
\label{program:program_processor_definition_dynamic}
\captionof{program}{Auszug aus Datei "Program.cs": Definition der Thresholding Prozessoren}
Ist die Erstellung der Bildbearbeitungsprozessoren abgeschlossen, wird jeder einzelne Prozessor über die Systembibliothek "System.Threading.Tasks" als eigener Auftrag (\engl{Task}) gestartet. In der Kommandozeile wird anschließend der aktuelle Status jedes Tasks angezeigt. Wurden alle Tasks abgeschlossen, wird das Programm beendet.
@@ -179,41 +223,41 @@ Wurden die in den jeweiligen Screenshots erkannten Textdaten abgelegt, werden di
Als zentrale Komponente für den Vergleich spielt die Berechnung der in \autoref{metriken} erklärten Metriken eine wesentliche Rolle. Wie in Programm \ref{program:distance_levenshtein} ersichtlich, wird die Distanz zwischen zwei \csharp-Enumerables, seien es zwei Strings oder zwei Listen, über das Verfahren nach Levenshtein berechnet.
\begin{CsCode}[numbers=none]
public static double GetDistance<T>(T reference, T? hypothesis)
where T : IEnumerable
{
var refArr = reference.Cast<object>().ToArray();
var hypArr = hypothesis?.Cast<object>().ToArray() ?? Array.Empty<object>();
var distance = new int[refArr.Length + 1, hypArr.Length + 1];
for (var x = 0; x <= refArr.Length; x++)
public static double GetDistance<T>(T reference, T? hypothesis)
where T : IEnumerable
{
distance[x, 0] = x;
}
var refArr = reference.Cast<object>().ToArray();
var hypArr = hypothesis?.Cast<object>().ToArray() ?? Array.Empty<object>();
for (var y = 0; y <= hypArr.Length; y++)
{
distance[0, y] = y;
}
var distance = new int[refArr.Length + 1, hypArr.Length + 1];
for (var x = 0; x < refArr.Length; x++)
{
for (var y = 0; y < hypArr.Length; y++)
{
var cost = Equals(refArr[x], hypArr[y]) ? 0 : 1;
for (var x = 0; x <= refArr.Length; x++)
{
distance[x, 0] = x;
}
var c1 = distance[x, y] + cost; // Bottom left
for (var y = 0; y <= hypArr.Length; y++)
{
distance[0, y] = y;
}
var c2 = distance[x, y + 1] + 1; // Top left
var c3 = distance[x + 1, y] + 1; // Bottom right
for (var x = 0; x < refArr.Length; x++)
{
for (var y = 0; y < hypArr.Length; y++)
{
var cost = Equals(refArr[x], hypArr[y]) ? 0 : 1;
distance[x + 1, y + 1] = Min(c1, c2, c3); // Top right
}
}
var c1 = distance[x, y] + cost; // Bottom left
return distance[refArr.Length, hypArr.Length];
}
var c2 = distance[x, y + 1] + 1; // Top left
var c3 = distance[x + 1, y] + 1; // Bottom right
distance[x + 1, y + 1] = Min(c1, c2, c3); // Top right
}
}
return distance[refArr.Length, hypArr.Length];
}
\end{CsCode}
\label{program:distance_levenshtein}
\captionof{program}{Auszug aus Datei "Calculator.cs": Berechnung der Levenshtein-Distanz}
+1 -1
View File
@@ -27,7 +27,7 @@
- Programmkomponenten
- ~~Bibliotheken~~
- ~~Processing-Framework~~
- Pipeline-Aufbau (Src-Code Exzerpt!)
- ~~Pipeline-Aufbau (Src-Code Exzerpt!)~~
- Programmablauf
- Bulk-Scan
- Vergleich mit Soll-Daten
BIN
View File
Binary file not shown.