Enhanced logging, diagnostics, and robustness throughout
Added NLog-based logging and diagnostics to Console and WPF apps, with programmatic configuration and support for debugger output. Refactored apps to use dependency injection and Microsoft.Extensions.Hosting. Improved output layer extraction and fallback logic in detection/recognition, including objectness-class probability multiplication. Added crop saving for diagnostics. Introduced new CLI options for diagnostics. MainViewModel and MainWindow now use DI and log errors. NumberRecognitionEngine supports logging, crop saving, and robust fallback. Added Python diagnostic script. Improved error handling and argument parsing.
This commit is contained in:
parent
769afc08fb
commit
d2206a00cb
14 changed files with 571 additions and 78 deletions
|
|
@ -7,6 +7,9 @@
|
|||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NLog" Version="6.1.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.3" />
|
||||
<PackageReference Include="NLog.Extensions.Logging" Version="6.1.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AIFotoONLUS.Core\AIFotoONLUS.Core.csproj" />
|
||||
|
|
|
|||
|
|
@ -1,4 +1,12 @@
|
|||
using AIFotoONLUS.Core;
|
||||
using OpenCvSharp;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NLog;
|
||||
using NLog.Config;
|
||||
using NLog.Targets;
|
||||
using NLog.Extensions.Logging;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
|
@ -36,31 +44,102 @@ namespace AIFotoONLUS.ConsoleApp
|
|||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(directory) || string.IsNullOrEmpty(csvPath))
|
||||
bool diagFirst = args.Contains("--diagfirst");
|
||||
var fileIndex = Array.IndexOf(args, "--file");
|
||||
|
||||
if (fileIndex < 0)
|
||||
{
|
||||
Console.WriteLine("Missing required arguments.");
|
||||
return 1;
|
||||
if (string.IsNullOrEmpty(directory) || string.IsNullOrEmpty(csvPath))
|
||||
{
|
||||
Console.WriteLine("Missing required arguments.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!Directory.Exists(directory))
|
||||
{
|
||||
Console.WriteLine($"Directory not found: {directory}");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Directory.Exists(directory))
|
||||
// configure NLog programmatically to write to console
|
||||
var nlogConfig = new LoggingConfiguration();
|
||||
var consoleTarget = new ColoredConsoleTarget("console")
|
||||
{
|
||||
Console.WriteLine($"Directory not found: {directory}");
|
||||
return 1;
|
||||
}
|
||||
|
||||
var cfg = new ModelConfiguration
|
||||
{
|
||||
DetectionCfg = Path.Combine("models", "detection.cfg"),
|
||||
DetectionWeights = Path.Combine("models", "detection.weights"),
|
||||
RecognitionCfg = Path.Combine("models", "recognition.cfg"),
|
||||
RecognitionWeights = Path.Combine("models", "recognition.weights"),
|
||||
ConfidenceThreshold = 0.5,
|
||||
NmsThreshold = 0.4
|
||||
Layout = "${longdate}|${level:uppercase=true}|${logger}|${message} ${exception:format=toString}"
|
||||
};
|
||||
nlogConfig.AddTarget(consoleTarget);
|
||||
nlogConfig.AddRule(NLog.LogLevel.Debug, NLog.LogLevel.Fatal, consoleTarget);
|
||||
LogManager.Configuration = nlogConfig;
|
||||
|
||||
var host = Host.CreateDefaultBuilder()
|
||||
.ConfigureLogging(logging =>
|
||||
{
|
||||
logging.ClearProviders();
|
||||
logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Debug);
|
||||
logging.AddNLog();
|
||||
})
|
||||
.ConfigureServices((ctx, services) =>
|
||||
{
|
||||
services.AddSingleton(new ModelConfiguration
|
||||
{
|
||||
DetectionCfg = Path.Combine("models", "detection.cfg"),
|
||||
DetectionWeights = Path.Combine("models", "detection.weights"),
|
||||
RecognitionCfg = Path.Combine("models", "recognition.cfg"),
|
||||
RecognitionWeights = Path.Combine("models", "recognition.weights"),
|
||||
ConfidenceThreshold = 0.5,
|
||||
NmsThreshold = 0.4
|
||||
});
|
||||
|
||||
services.AddTransient<NumberRecognitionEngine>(sp =>
|
||||
{
|
||||
var cfg = sp.GetRequiredService<ModelConfiguration>();
|
||||
var logger = sp.GetService<ILogger<NumberRecognitionEngine>>();
|
||||
return new NumberRecognitionEngine(cfg, logger);
|
||||
});
|
||||
})
|
||||
.UseConsoleLifetime()
|
||||
.Build();
|
||||
|
||||
using var svcScope = host.Services.CreateScope();
|
||||
var services = svcScope.ServiceProvider;
|
||||
try
|
||||
{
|
||||
using var engine = new NumberRecognitionEngine(cfg);
|
||||
var cfg = services.GetRequiredService<ModelConfiguration>();
|
||||
using var engine = services.GetRequiredService<NumberRecognitionEngine>();
|
||||
var loggerFactory = services.GetService<ILoggerFactory>();
|
||||
var programLogger = loggerFactory?.CreateLogger("Program");
|
||||
// support --file <path> to run a single-file diagnostic via core API
|
||||
if (fileIndex >= 0 && fileIndex + 1 < args.Length)
|
||||
{
|
||||
var singleFile = args[fileIndex + 1];
|
||||
programLogger?.LogInformation("Running diagnostic for single file: {file}", singleFile);
|
||||
var diag = engine.ProcessFileWithDiagnostics(singleFile);
|
||||
programLogger?.LogInformation("File {file} -> text: {text}", diag.Result.FileName, diag.Result.Text);
|
||||
foreach (var o in diag.DetectionOutputs)
|
||||
{
|
||||
programLogger?.LogDebug("DetectionOutput {name} rows={r} cols={c}", o.Name, o.Rows, o.Cols);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (diagFirst)
|
||||
{
|
||||
var first = Directory.EnumerateFiles(directory, "*.*", SearchOption.TopDirectoryOnly)
|
||||
.FirstOrDefault(f => f.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) || f.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase));
|
||||
if (first == null)
|
||||
{
|
||||
programLogger?.LogWarning("No images found in directory {dir}", directory);
|
||||
return 1;
|
||||
}
|
||||
programLogger?.LogInformation("Diagnostic directory: {dir}", directory);
|
||||
programLogger?.LogDebug("Directory.Exists: {exists}", Directory.Exists(directory));
|
||||
programLogger?.LogDebug("CurrentDirectory: {cwd}", Directory.GetCurrentDirectory());
|
||||
programLogger?.LogInformation("Running diagnostic DetectTextRegions on: {file}", first);
|
||||
var regs = engine.DetectTextRegions(Cv2.ImRead(first)).ToArray();
|
||||
programLogger?.LogInformation("Detected regions: {count}", regs.Length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
var results = engine.ProcessDirectory(directory, textNegative).ToList();
|
||||
|
||||
using var sw = new StreamWriter(csvPath, false);
|
||||
|
|
@ -70,15 +149,17 @@ namespace AIFotoONLUS.ConsoleApp
|
|||
sw.WriteLine($"{r.FileName},{r.Text}");
|
||||
}
|
||||
|
||||
Console.WriteLine($"Results written to {csvPath}");
|
||||
programLogger?.LogInformation("Results written to {csv}", csvPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error: {ex.Message}");
|
||||
var loggerFactory = services.GetService<ILoggerFactory>();
|
||||
var programLogger = loggerFactory?.CreateLogger("Program");
|
||||
programLogger?.LogError(ex, "Error running processing");
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue