Renamed Examples to Implementation

This commit is contained in:
Simon Gruber
2024-01-08 16:23:24 +01:00
parent b17044f959
commit 6c554e444f
1240 changed files with 0 additions and 0 deletions
+20
View File
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Magick.NET-Q16-AnyCPU" Version="13.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Lookup\Lookup.Memory\Lookup.Memory.csproj" />
<ProjectReference Include="..\..\Ocr\Ocr.Tesseract.Screenshots\Ocr.Tesseract.Screenshots.csproj" />
<ProjectReference Include="..\..\Ocr\Ocr.Tesseract\Ocr.Tesseract.csproj" />
<ProjectReference Include="..\..\Process\Process.Interface\Process.Interface.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,66 @@
using System.Collections;
namespace Common.Distance;
public static class Calculator
{
/// <summary>
/// Calculates the levenshtein distance between two enumerables
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="reference"></param>
/// <param name="hypothesis"></param>
/// <returns></returns>
public static double GetDistance<T>(T reference, T? hypothesis)
where T : IEnumerable
{
// Setup
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];
// Fill matrix
for (var x = 0; x <= refArr.Length; x++)
{
// Reference on X axis
distance[x, 0] = x;
}
for (var y = 0; y <= hypArr.Length; y++)
{
// Hypothesis on Y axis
distance[0, y] = y;
}
// Calculate distance
for (var x = 0; x < refArr.Length; x++)
{
for (var y = 0; y < hypArr.Length; y++)
{
// BL Cost depends on whether the two elements are equal
var cost = Equals(refArr[x], hypArr[y]) ? 0 : 1;
// Apply distance mask
var c1 = distance[x, y] + cost; // Bottom left
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];
}
private static T Min<T>(params T[] values)
{
if (!values.Any())
{
throw new ArgumentException("Array cannot be empty", nameof(values));
}
return values.Min()!;
}
}
@@ -0,0 +1,43 @@
using System.Collections;
namespace Common.Distance;
public readonly struct DistanceComparer<T> : IDistanceComparer<T>
where T : IEnumerable
{
/// <inheritdoc />
public T Reference { get; }
/// <inheritdoc />
public T? Hypothesis { get; }
/// <inheritdoc />
public double Distance { get; }
public DistanceComparer(T reference) : this(reference, default)
{
}
public DistanceComparer(T reference, T? hypothesis)
{
Reference = reference;
Hypothesis = hypothesis;
Distance = Calculator.GetDistance(Reference, Hypothesis);
}
/// <inheritdoc />
public override string ToString()
{
var str = Hypothesis?.ToString();
if (Hypothesis is var hyp && Equals(hyp, Reference))
{
return str ?? string.Empty;
}
return
$"<strong style='color: orange;' title='REf: {Reference}, CER: {Distance}'>{str ?? "-"}</strong>";
}
}
@@ -0,0 +1,27 @@
using System.Collections;
namespace Common.Distance;
public interface IDistanceComparer
{
/// <summary>
/// The calculated absolute distance between
/// <see cref="IDistanceComparer{T}.Reference"/> and
/// <see cref="IDistanceComparer{T}.Hypothesis"/>
/// </summary>
public double Distance { get; }
}
public interface IDistanceComparer<out T> : IDistanceComparer
where T : IEnumerable
{
/// <summary>
/// The comparison reference, meaning the "known to be correct" value
/// </summary>
public T Reference { get; }
/// <summary>
/// The value hypothesis, whose correctness is checked against <see cref="Reference"/>
/// </summary>
public T? Hypothesis { get; }
}
@@ -0,0 +1,47 @@
namespace Common.Extensions;
public static class EnumerableExtensions
{
public static double Median(this IEnumerable<double> values)
{
var tValues = values.OrderBy(v => v).ToArray();
if (!tValues.Any())
{
throw new ArgumentException(
"The list must contain at least one value for calculating the median");
}
if (tValues.Length % 2 != 0)
{
return tValues[tValues.Length / 2];
}
var center = tValues.Length / 2;
return (tValues[center - 1] + tValues[center]) / 2.0;
}
public static double Median(this IEnumerable<double> values, out double deviation)
{
var tValues = values.ToArray();
var median = tValues.Median();
deviation = tValues.Select(value => Math.Abs(value - median)).Median();
return median;
}
public static double Average(this IEnumerable<double> values, out double deviation)
{
var tValues = values?.ToArray();
if (tValues is null || tValues.Length < 2)
{
throw new ArgumentException(
"The list must contain at least two values for calculating standard deviation");
}
var average = tValues.Average();
var diffSquaredSum = tValues.Sum(value => Math.Pow(value - average, 2));
deviation = Math.Sqrt(diffSquaredSum / (tValues.Length - 1));
return average;
}
}
@@ -0,0 +1,15 @@
using System.Text;
namespace Common.Extensions;
public static class StringBuilderExtensions
{
public static StringBuilder AppendHeading(this StringBuilder sb, int level, string text) => sb
.Append(new string('#', level))
.Append(' ')
.AppendParagraph(text);
public static StringBuilder AppendParagraph(this StringBuilder sb, string text) => sb
.AppendLine(text)
.AppendLine();
}
@@ -0,0 +1,39 @@
namespace Common.Extensions;
/// <summary>
/// Extensions for the string object type
/// </summary>
public static class StringExtensions
{
/// <summary>
/// Determines whether this string contains the specified string. Not case sensitive.
/// </summary>
/// <param name="source"> The source.</param>
/// <param name="contained">The contained.</param>
public static bool ContainsIgnoreCase(this string source, string contained)
{
return source?.IndexOf(contained, StringComparison.InvariantCultureIgnoreCase) >= 0;
}
/// <summary>
/// Expands a path containing a wildcard pattern
/// </summary>
/// <param name="self"></param>
/// <returns></returns>
public static IEnumerable<string> ExpandPath(this string self)
{
var parts = self.Split(Path.DirectorySeparatorChar);
var fileName = parts.Last();
if (fileName.Contains('*') || fileName.Contains('?'))
{
// Path contains file pattern
var path = Path.Combine(parts.SkipLast(1).ToArray());
return Directory.EnumerateFiles(path, fileName);
}
// Path contains no pattern
return new[] { self };
}
}
@@ -0,0 +1,50 @@
using ImageMagick;
using Lookup.Memory;
using Ocr.Tesseract.Models;
using Process.Interface;
namespace Common;
/// <summary>
/// Scanner class, scanning <see cref="MagickImage"/>s for <see cref="Word"/>s
/// via optical character recognition. Optimized for digital Screenshots.
/// </summary>
public class ScreenshotScanner
{
/// <summary>
/// The screenshot processor
/// </summary>
protected IProcessor<MagickImage, ScanResult> Processor { get; }
/// <summary>
/// Data storage
/// </summary>
public Lookup.Interface.ILookup<Word, MagickImage> Lookup { get; } =
new MemoryLookup<Word, MagickImage>();
/// <summary>
/// Constructor
/// </summary>
public ScreenshotScanner(IProcessor<MagickImage, ScanResult> processor)
{
Processor = processor;
}
/// <summary>
/// Process the provided <paramref name="images"/> and add the results to
/// the <see cref="Lookup"/>
/// </summary>
/// <param name="images">The <see cref="MagickImage"/>s to process</param>
public void Process(IEnumerable<MagickImage> images)
{
foreach (var kv in Processor.Process(images))
{
Lookup.Add(kv.Word, kv.Image);
}
}
public virtual void Clear()
{
Lookup.Clear();
}
}