Compare commits
10 commits
057766ec4b
...
f672894c3e
| Author | SHA1 | Date | |
|---|---|---|---|
| f672894c3e | |||
| dc4ebdaf42 | |||
| 986cc5f8ab | |||
| 1a9491617a | |||
| daead29d31 | |||
| f6a1aae622 | |||
| 5aae5f6486 | |||
| 97eb431b45 | |||
| a90da31e53 | |||
| f9a652f5cc |
13 changed files with 784 additions and 47 deletions
124
.forgejo/workflows/publish-aifotoonlus-core.yml
Normal file
124
.forgejo/workflows/publish-aifotoonlus-core.yml
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
name: Build And Publish AIFotoONLUS.Core
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
tags:
|
||||
- '*'
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
DOTNET_VERSION: 10.0.x
|
||||
PROJECT_PATH: src/AIFotoONLUS.Core/AIFotoONLUS.Core.csproj
|
||||
PACKAGE_OUTPUT_DIR: artifacts/nuget
|
||||
PACKAGE_ARTIFACT_NAME: aifotoonlus-core-nuget
|
||||
NUGET_SOURCE_NAME: forgejo-aifotoonlus
|
||||
NUGET_SOURCE_URL: ${{ vars.AIFOTOONLUS_NUGET_SOURCE_URL || format('{0}/api/packages/{1}/nuget/index.json', github.server_url, vars.AIFOTOONLUS_PACKAGE_OWNER || github.repository_owner) }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: docker
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: ${{ env.DOTNET_VERSION }}
|
||||
|
||||
- name: Restore
|
||||
run: dotnet restore "${{ env.PROJECT_PATH }}"
|
||||
|
||||
- name: Build
|
||||
run: dotnet build "${{ env.PROJECT_PATH }}" --configuration Release --no-restore /p:GeneratePackageOnBuild=false
|
||||
|
||||
- name: Pack
|
||||
shell: bash
|
||||
run: |
|
||||
set -eu
|
||||
mkdir -p "${{ env.PACKAGE_OUTPUT_DIR }}"
|
||||
|
||||
if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
|
||||
package_version="${GITHUB_REF_NAME#v}"
|
||||
echo "Packing tag version ${package_version}"
|
||||
dotnet pack "${{ env.PROJECT_PATH }}" \
|
||||
--configuration Release \
|
||||
--output "${{ env.PACKAGE_OUTPUT_DIR }}" \
|
||||
--no-build \
|
||||
/p:PackageVersion="${package_version}"
|
||||
else
|
||||
echo "Packing with project version or MinVer-derived version"
|
||||
dotnet pack "${{ env.PROJECT_PATH }}" \
|
||||
--configuration Release \
|
||||
--output "${{ env.PACKAGE_OUTPUT_DIR }}" \
|
||||
--no-build
|
||||
fi
|
||||
|
||||
- name: Upload package artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.PACKAGE_ARTIFACT_NAME }}
|
||||
path: ${{ env.PACKAGE_OUTPUT_DIR }}/*.nupkg
|
||||
if-no-files-found: error
|
||||
|
||||
publish:
|
||||
if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch'
|
||||
needs: build
|
||||
runs-on: docker
|
||||
env:
|
||||
FORGEJO_PACKAGE_USERNAME: ${{ secrets.FORGEJO_PACKAGE_USERNAME }}
|
||||
FORGEJO_PACKAGE_TOKEN: ${{ secrets.FORGEJO_PACKAGE_TOKEN }}
|
||||
|
||||
steps:
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: ${{ env.DOTNET_VERSION }}
|
||||
|
||||
- name: Download package artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{ env.PACKAGE_ARTIFACT_NAME }}
|
||||
path: ${{ env.PACKAGE_OUTPUT_DIR }}
|
||||
|
||||
- name: Validate publish secrets
|
||||
shell: bash
|
||||
run: |
|
||||
set -eu
|
||||
if [ -z "${FORGEJO_PACKAGE_USERNAME}" ]; then
|
||||
echo "secrets.FORGEJO_PACKAGE_USERNAME is required"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "${FORGEJO_PACKAGE_TOKEN}" ]; then
|
||||
echo "secrets.FORGEJO_PACKAGE_TOKEN is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Configure Forgejo NuGet source
|
||||
run: |
|
||||
dotnet nuget add source "${{ env.NUGET_SOURCE_URL }}" \
|
||||
--name "${{ env.NUGET_SOURCE_NAME }}" \
|
||||
--username "${FORGEJO_PACKAGE_USERNAME}" \
|
||||
--password "${FORGEJO_PACKAGE_TOKEN}" \
|
||||
--store-password-in-clear-text
|
||||
|
||||
- name: Publish package to Forgejo NuGet
|
||||
shell: bash
|
||||
run: |
|
||||
set -eu
|
||||
shopt -s nullglob
|
||||
packages=("${{ env.PACKAGE_OUTPUT_DIR }}"/*.nupkg)
|
||||
if [ "${#packages[@]}" -eq 0 ]; then
|
||||
echo "No NuGet packages found in ${{ env.PACKAGE_OUTPUT_DIR }}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dotnet nuget push "${{ env.PACKAGE_OUTPUT_DIR }}"/*.nupkg \
|
||||
--source "${{ env.NUGET_SOURCE_NAME }}" \
|
||||
--skip-duplicate
|
||||
|
|
@ -2,6 +2,16 @@ stages:
|
|||
- build
|
||||
- publish
|
||||
|
||||
# Only create pipelines automatically when a Git tag is pushed.
|
||||
# Otherwise the pipeline must be started manually (pipeline "Run" / dispatch equivalent).
|
||||
workflow:
|
||||
rules:
|
||||
- if: '$CI_COMMIT_TAG'
|
||||
when: always
|
||||
- if: '$CI_PIPELINE_SOURCE == "web"'
|
||||
when: always
|
||||
- when: never
|
||||
|
||||
variables:
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: "1"
|
||||
DOTNET_NOLOGO: "true"
|
||||
|
|
@ -16,7 +26,7 @@ build:
|
|||
stage: build
|
||||
script:
|
||||
- dotnet restore src/AIFotoONLUS.Core/AIFotoONLUS.Core.csproj
|
||||
- dotnet build src/AIFotoONLUS.Core/AIFotoONLUS.Core.csproj --configuration Release --no-restore
|
||||
- dotnet build src/AIFotoONLUS.Core/AIFotoONLUS.Core.csproj --configuration Release --no-restore /p:GeneratePackageOnBuild=false
|
||||
artifacts:
|
||||
paths:
|
||||
- src/AIFotoONLUS.Core/bin/**
|
||||
|
|
@ -25,22 +35,27 @@ build:
|
|||
publish_nuget:
|
||||
stage: publish
|
||||
image: mcr.microsoft.com/dotnet/sdk:10.0
|
||||
dependencies:
|
||||
- build
|
||||
variables:
|
||||
NUGET_SOURCE: "$CI_API_V4_URL/projects/$CI_PROJECT_ID/packages/nuget/index.json"
|
||||
script: |
|
||||
dotnet restore
|
||||
dotnet restore src/AIFotoONLUS.Core/AIFotoONLUS.Core.csproj
|
||||
git fetch --prune --unshallow || true
|
||||
git fetch origin +refs/heads/*:refs/remotes/origin/* || true
|
||||
git branch --show-current || true
|
||||
- dotnet tool install --global GitVersion.Tool --version 6.5.1 || true
|
||||
export PATH="$PATH:~/.dotnet/tools"
|
||||
GITVER=$(gitversion /showvariable NuGetVersionV2)
|
||||
echo "Raw version: $GITVER"
|
||||
PACKAGE_VERSION=$(echo "$GITVER" | sed 's/[{}]//g' | sed 's/[^0-9A-Za-z.-]//g')
|
||||
echo "Package version: $PACKAGE_VERSION"
|
||||
dotnet pack src/AIFotoONLUS.Core/AIFotoONLUS.Core.csproj -c Release -o nuget /p:PackageVersion="$PACKAGE_VERSION"
|
||||
|
||||
# If build was triggered by a Git tag, use that tag as the package version (strip leading 'v').
|
||||
# Otherwise rely on MinVer inside the project to infer a semantic version from git history.
|
||||
if [ -n "$CI_COMMIT_TAG" ]; then
|
||||
PACKAGE_VERSION="${CI_COMMIT_TAG#v}"
|
||||
echo "Using tag version: $PACKAGE_VERSION"
|
||||
dotnet pack src/AIFotoONLUS.Core/AIFotoONLUS.Core.csproj -c Release -o nuget --no-build /p:PackageVersion="$PACKAGE_VERSION" /p:EnableWindowsTargeting=true
|
||||
else
|
||||
echo "No tag detected; using MinVer to infer version at pack time"
|
||||
dotnet pack src/AIFotoONLUS.Core/AIFotoONLUS.Core.csproj -c Release -o nuget --no-build /p:EnableWindowsTargeting=true
|
||||
fi
|
||||
|
||||
dotnet nuget push "nuget/*.nupkg" --source "$NUGET_SOURCE" --api-key "$CI_JOB_TOKEN" --skip-duplicate
|
||||
only:
|
||||
- main
|
||||
- master
|
||||
- tags
|
||||
# Pipeline creation is controlled by the top-level `workflow` rules.
|
||||
# This job will run when the pipeline is created for a tag or when manually started.
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
mode: ContinuousDelivery
|
||||
branches:
|
||||
main:
|
||||
regex: ^main$
|
||||
increment: Minor
|
||||
track-merge-target: false
|
||||
master:
|
||||
regex: ^master$
|
||||
increment: Minor
|
||||
track-merge-target: false
|
||||
feature:
|
||||
regex: ^(?:feat(?:ure)?|feature)[/\\-]
|
||||
increment: Minor
|
||||
source-branches: ["main", "master"]
|
||||
hotfix:
|
||||
regex: ^hotfix[/\\-]
|
||||
increment: Patch
|
||||
ignore:
|
||||
sha: []
|
||||
commit-message-incrementing: Enabled
|
||||
65
README.md
Normal file
65
README.md
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
# AIFotoONLUS Number Recognition Library
|
||||
|
||||
This library provides a small, focused engine to detect and recognize numeric
|
||||
text (digits) in images using Darknet (YOLO) models via OpenCvSharp's DNN API.
|
||||
It is suitable for batch processing folders of images or individual files.
|
||||
|
||||
Features
|
||||
- Detection network (Darknet/Yolo) to find candidate text regions.
|
||||
- Recognition network (Darknet/Yolo) to identify digits inside detected crops.
|
||||
- Single-file and directory-level processing APIs.
|
||||
- Parallel processing with per-thread network instances for throughput.
|
||||
- Diagnostic helpers to dump network output shapes and optionally save crop images.
|
||||
|
||||
Basic usage
|
||||
1. Create a `ModelConfiguration` instance that points to your Darknet `.cfg`
|
||||
and `.weights` files for both detection and recognition networks, configure
|
||||
confidence and NMS thresholds and provide a list of number class labels.
|
||||
|
||||
2. Create an instance of `NumberRecognitionEngine`:
|
||||
|
||||
```csharp
|
||||
using var engine = new NumberRecognitionEngine(modelConfig, logger: null);
|
||||
```
|
||||
|
||||
3. Process a single image:
|
||||
|
||||
```csharp
|
||||
var result = engine.ProcessImage("/path/to/image.jpg");
|
||||
Console.WriteLine(result.Text);
|
||||
```
|
||||
|
||||
4. Process a directory (parallelized):
|
||||
|
||||
```csharp
|
||||
var results = await engine.ProcessDirectoryAsync("/path/to/images", recursive: false);
|
||||
foreach (var r in results) Console.WriteLine($"{r.FileName}: {r.Text}");
|
||||
```
|
||||
|
||||
Configuration notes
|
||||
- `ModelConfiguration` controls model file paths, input sizes, thresholds and
|
||||
whether to save cropped images for diagnostics. Make sure the paths are
|
||||
accessible to the process and the model files match the expected network
|
||||
architectures.
|
||||
|
||||
- The engine expects detection network outputs in the YOLO-style layout:
|
||||
`[cx, cy, w, h, objectness, class1, class2, ...]`.
|
||||
|
||||
Threading & diagnostics
|
||||
- For directory/batch processing the engine creates per-thread Net instances
|
||||
so OpenCV forward calls can run concurrently. It also contains fallback
|
||||
logic that will perform processing with shared nets under a lock if needed.
|
||||
|
||||
- When `EnableCropSaving` is enabled in configuration, each recognized crop is
|
||||
saved to `logs/crops` with a timestamp and optional context label to aid
|
||||
debugging false positives/negatives.
|
||||
|
||||
Troubleshooting
|
||||
- If the engine returns no detections, verify the model files are correct and
|
||||
compatible with the expected output layout. Use
|
||||
`ProcessFileWithDiagnostics` to inspect output layer shapes.
|
||||
|
||||
License & Notes
|
||||
This project is provided as-is. See repository for licensing information and
|
||||
for the model files distribution terms (models are usually not redistributed
|
||||
with code and must be obtained separately).
|
||||
27
gitversion.json
Normal file
27
gitversion.json
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"AssemblySemFileVer": "0.1.0.0",
|
||||
"AssemblySemVer": "0.1.0.0",
|
||||
"BranchName": "master",
|
||||
"BuildMetaData": null,
|
||||
"CommitDate": "2026-02-15",
|
||||
"CommitsSinceVersionSource": 11,
|
||||
"EscapedBranchName": "master",
|
||||
"FullBuildMetaData": "Branch.master.Sha.a90da31e531332a4cf0bafe604f89d0e14f3395a",
|
||||
"FullSemVer": "0.1.0-{BranchName}.11",
|
||||
"InformationalVersion": "0.1.0-{BranchName}.11+Branch.master.Sha.a90da31e531332a4cf0bafe604f89d0e14f3395a",
|
||||
"Major": 0,
|
||||
"MajorMinorPatch": "0.1.0",
|
||||
"Minor": 1,
|
||||
"Patch": 0,
|
||||
"PreReleaseLabel": "{BranchName}",
|
||||
"PreReleaseLabelWithDash": "-{BranchName}",
|
||||
"PreReleaseNumber": 11,
|
||||
"PreReleaseTag": "{BranchName}.11",
|
||||
"PreReleaseTagWithDash": "-{BranchName}.11",
|
||||
"SemVer": "0.1.0-{BranchName}.11",
|
||||
"Sha": "a90da31e531332a4cf0bafe604f89d0e14f3395a",
|
||||
"ShortSha": "a90da31",
|
||||
"UncommittedChanges": 7,
|
||||
"VersionSourceSha": "",
|
||||
"WeightedPreReleaseNumber": 11
|
||||
}
|
||||
|
|
@ -10,8 +10,14 @@
|
|||
<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" />
|
||||
<!-- MinVer for tag-based semantic versioning -->
|
||||
<PackageReference Include="MinVer" Version="3.1.0" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AIFotoONLUS.Core\AIFotoONLUS.Core.csproj" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<!-- Fallback version when no tag is present -->
|
||||
<Version>0.1.0</Version>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
@ -3,6 +3,10 @@
|
|||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<!-- Generate XML documentation file for the public API -->
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<!-- Ensure the documentation file path is predictable so it can be packed -->
|
||||
<DocumentationFile>$(OutputPath)$(AssemblyName).xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<!-- NuGet package metadata -->
|
||||
|
|
@ -10,13 +14,10 @@
|
|||
<Authors>Maddo</Authors>
|
||||
<Company>Maddo</Company>
|
||||
<Description>Core library for AIFotoONLUS image processing and recognition.</Description>
|
||||
<RepositoryUrl>https://gitlab.com/MaddoScientisto/aifotoonlus</RepositoryUrl>
|
||||
<!-- Use GitVersion MSBuild properties to set package version during CI/build. Provide fallback if variable is not defined.
|
||||
Sanitize the GitVersion output to remove characters invalid for NuGet (e.g., braces) -->
|
||||
<GitVersionRaw>$(GitVersion_NuGetVersionV2)</GitVersionRaw>
|
||||
<GitVersionSanitized>$([System.Text.RegularExpressions.Regex]::Replace('$(GitVersionRaw)','[{}]',''))</GitVersionSanitized>
|
||||
<Version Condition="'$(GitVersionSanitized)' != ''">$(GitVersionSanitized)</Version>
|
||||
<Version Condition="'$(GitVersionSanitized)' == ''">0.1.0</Version>
|
||||
<RepositoryUrl>https://forgejo.maddoscientisto.net/maddo/AIFotoONLUS</RepositoryUrl>
|
||||
<!-- Versioning: use MinVer to infer semantic versions from Git tags. When no tag is present,
|
||||
projects will fall back to the default below. -->
|
||||
<Version>0.1.0</Version>
|
||||
<PackageReleaseNotes>See Git history for release notes.</PackageReleaseNotes>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<IncludeSymbols>false</IncludeSymbols>
|
||||
|
|
@ -25,8 +26,8 @@
|
|||
<PackageReference Include="OpenCvSharp4" Version="4.13.0.20260214" />
|
||||
<PackageReference Include="OpenCvSharp4.runtime.win" Version="4.13.0.20260214" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.3" />
|
||||
<!-- GitVersion MSBuild integration for automatic semantic versioning -->
|
||||
<PackageReference Include="GitVersion.MsBuild" Version="6.5.1" PrivateAssets="all" />
|
||||
<!-- Use MinVer to infer versions from Git tags (applies at pack/build time) -->
|
||||
<PackageReference Include="MinVer" Version="3.1.0" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
</ItemGroup>
|
||||
|
|
|
|||
325
src/AIFotoONLUS.Core/AIFotoONLUS.Core.xml
Normal file
325
src/AIFotoONLUS.Core/AIFotoONLUS.Core.xml
Normal file
|
|
@ -0,0 +1,325 @@
|
|||
<?xml version="1.0"?>
|
||||
<doc>
|
||||
<assembly>
|
||||
<name>AIFotoONLUS.Core</name>
|
||||
</assembly>
|
||||
<members>
|
||||
<member name="T:AIFotoONLUS.Core.DetectedRegion">
|
||||
<summary>
|
||||
Represents a detected text region produced by the detection network.
|
||||
</summary>
|
||||
<param name="BoundingBox">Bounding rectangle of the detection in image coordinates.</param>
|
||||
<param name="Confidence">Combined confidence score for the detection (objectness * class probability).</param>
|
||||
<param name="ClassId">Class index predicted by the network (index into <see cref="P:AIFotoONLUS.Core.ModelConfiguration.NumberClasses"/>).</param>
|
||||
<param name="CenterX">Center X coordinate (in pixels) of the bounding box, used to order detections left-to-right.</param>
|
||||
</member>
|
||||
<member name="M:AIFotoONLUS.Core.DetectedRegion.#ctor(OpenCvSharp.Rect,System.Single,System.Int32,System.Double)">
|
||||
<summary>
|
||||
Represents a detected text region produced by the detection network.
|
||||
</summary>
|
||||
<param name="BoundingBox">Bounding rectangle of the detection in image coordinates.</param>
|
||||
<param name="Confidence">Combined confidence score for the detection (objectness * class probability).</param>
|
||||
<param name="ClassId">Class index predicted by the network (index into <see cref="P:AIFotoONLUS.Core.ModelConfiguration.NumberClasses"/>).</param>
|
||||
<param name="CenterX">Center X coordinate (in pixels) of the bounding box, used to order detections left-to-right.</param>
|
||||
</member>
|
||||
<member name="P:AIFotoONLUS.Core.DetectedRegion.BoundingBox">
|
||||
<summary>Bounding rectangle of the detection in image coordinates.</summary>
|
||||
</member>
|
||||
<member name="P:AIFotoONLUS.Core.DetectedRegion.Confidence">
|
||||
<summary>Combined confidence score for the detection (objectness * class probability).</summary>
|
||||
</member>
|
||||
<member name="P:AIFotoONLUS.Core.DetectedRegion.ClassId">
|
||||
<summary>Class index predicted by the network (index into <see cref="P:AIFotoONLUS.Core.ModelConfiguration.NumberClasses"/>).</summary>
|
||||
</member>
|
||||
<member name="P:AIFotoONLUS.Core.DetectedRegion.CenterX">
|
||||
<summary>Center X coordinate (in pixels) of the bounding box, used to order detections left-to-right.</summary>
|
||||
</member>
|
||||
<member name="T:AIFotoONLUS.Core.RecognitionResult">
|
||||
<summary>
|
||||
Represents the result of recognizing a single region: recognized text,
|
||||
its bounding box and confidence.
|
||||
</summary>
|
||||
<param name="Text">Recognized text for the region (usually a sequence of digits).</param>
|
||||
<param name="BoundingBox">Bounding rectangle of the recognition result.</param>
|
||||
<param name="Confidence">Confidence score associated with the recognition.</param>
|
||||
</member>
|
||||
<member name="M:AIFotoONLUS.Core.RecognitionResult.#ctor(System.String,OpenCvSharp.Rect,System.Double)">
|
||||
<summary>
|
||||
Represents the result of recognizing a single region: recognized text,
|
||||
its bounding box and confidence.
|
||||
</summary>
|
||||
<param name="Text">Recognized text for the region (usually a sequence of digits).</param>
|
||||
<param name="BoundingBox">Bounding rectangle of the recognition result.</param>
|
||||
<param name="Confidence">Confidence score associated with the recognition.</param>
|
||||
</member>
|
||||
<member name="P:AIFotoONLUS.Core.RecognitionResult.Text">
|
||||
<summary>Recognized text for the region (usually a sequence of digits).</summary>
|
||||
</member>
|
||||
<member name="P:AIFotoONLUS.Core.RecognitionResult.BoundingBox">
|
||||
<summary>Bounding rectangle of the recognition result.</summary>
|
||||
</member>
|
||||
<member name="P:AIFotoONLUS.Core.RecognitionResult.Confidence">
|
||||
<summary>Confidence score associated with the recognition.</summary>
|
||||
</member>
|
||||
<member name="T:AIFotoONLUS.Core.ImageResult">
|
||||
<summary>
|
||||
Aggregated result for a processed image.
|
||||
</summary>
|
||||
<param name="FileName">Name of the image file.</param>
|
||||
<param name="Text">Comma-separated recognized texts found in the image (may be empty).</param>
|
||||
<param name="FilePath">Full path to the processed image file.</param>
|
||||
</member>
|
||||
<member name="M:AIFotoONLUS.Core.ImageResult.#ctor(System.String,System.String,System.String)">
|
||||
<summary>
|
||||
Aggregated result for a processed image.
|
||||
</summary>
|
||||
<param name="FileName">Name of the image file.</param>
|
||||
<param name="Text">Comma-separated recognized texts found in the image (may be empty).</param>
|
||||
<param name="FilePath">Full path to the processed image file.</param>
|
||||
</member>
|
||||
<member name="P:AIFotoONLUS.Core.ImageResult.FileName">
|
||||
<summary>Name of the image file.</summary>
|
||||
</member>
|
||||
<member name="P:AIFotoONLUS.Core.ImageResult.Text">
|
||||
<summary>Comma-separated recognized texts found in the image (may be empty).</summary>
|
||||
</member>
|
||||
<member name="P:AIFotoONLUS.Core.ImageResult.FilePath">
|
||||
<summary>Full path to the processed image file.</summary>
|
||||
</member>
|
||||
<member name="T:AIFotoONLUS.Core.ModelConfiguration">
|
||||
<summary>
|
||||
Configuration options that control model file locations, input sizes
|
||||
and runtime thresholds used by <see cref="T:AIFotoONLUS.Core.NumberRecognitionEngine"/>.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AIFotoONLUS.Core.ModelConfiguration.DetectionCfg">
|
||||
<summary>
|
||||
Path to the Darknet configuration (.cfg) file for the detection network.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AIFotoONLUS.Core.ModelConfiguration.DetectionWeights">
|
||||
<summary>
|
||||
Path to the Darknet weights (.weights) file for the detection network.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AIFotoONLUS.Core.ModelConfiguration.RecognitionCfg">
|
||||
<summary>
|
||||
Path to the Darknet configuration (.cfg) file for the recognition network.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AIFotoONLUS.Core.ModelConfiguration.RecognitionWeights">
|
||||
<summary>
|
||||
Path to the Darknet weights (.weights) file for the recognition network.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AIFotoONLUS.Core.ModelConfiguration.ConfidenceThreshold">
|
||||
<summary>
|
||||
Confidence threshold used to filter out low-probability detections.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AIFotoONLUS.Core.ModelConfiguration.NmsThreshold">
|
||||
<summary>
|
||||
Non-maximum suppression (NMS) IoU threshold used to remove overlapping
|
||||
detection boxes.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AIFotoONLUS.Core.ModelConfiguration.DetectionInputSize">
|
||||
<summary>
|
||||
Input size used when preparing the blob for the detection network.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AIFotoONLUS.Core.ModelConfiguration.RecognitionInputSize">
|
||||
<summary>
|
||||
Input size used when preparing the blob for the recognition network.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AIFotoONLUS.Core.ModelConfiguration.NumberClasses">
|
||||
<summary>
|
||||
Labels representing digit classes in the recognition model. The order
|
||||
must match the class ordering used by the trained recognition network.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AIFotoONLUS.Core.ModelConfiguration.EnableCropSaving">
|
||||
<summary>
|
||||
When enabled, recognition crops will be saved to disk under
|
||||
"logs/crops" for diagnostic inspection. Disabled by default.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:AIFotoONLUS.Core.NumberRecognitionEngine.#ctor(AIFotoONLUS.Core.ModelConfiguration)">
|
||||
<summary>
|
||||
Create a new instance of <see cref="T:AIFotoONLUS.Core.NumberRecognitionEngine"/> using the
|
||||
provided <see cref="T:AIFotoONLUS.Core.ModelConfiguration"/>. The constructor loads the
|
||||
detection and recognition Darknet model files and prepares the OpenCV
|
||||
DNN nets for CPU inference.
|
||||
</summary>
|
||||
<param name="cfg">Model configuration containing file paths, thresholds
|
||||
and other options. Must not be <c>null</c>.</param>
|
||||
<remarks>
|
||||
This constructor will throw <see cref="T:System.IO.FileNotFoundException"/> when
|
||||
any of the expected model files are missing. For logging purposes an
|
||||
overload accepting an <see cref="T:Microsoft.Extensions.Logging.ILogger"/> is available.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="M:AIFotoONLUS.Core.NumberRecognitionEngine.#ctor(AIFotoONLUS.Core.ModelConfiguration,Microsoft.Extensions.Logging.ILogger)">
|
||||
<summary>
|
||||
Create a new instance of <see cref="T:AIFotoONLUS.Core.NumberRecognitionEngine"/> with an
|
||||
optional <see cref="T:Microsoft.Extensions.Logging.ILogger"/>. The logger will receive diagnostic
|
||||
messages and errors produced by the engine during processing.
|
||||
</summary>
|
||||
<param name="cfg">Model configuration containing file paths and
|
||||
runtime thresholds.</param>
|
||||
<param name="logger">Optional logger for diagnostic messages.
|
||||
May be <c>null</c>.</param>
|
||||
<exception cref="T:System.ArgumentNullException">Thrown when <paramref name="cfg"/>
|
||||
is <c>null</c>.</exception>
|
||||
<exception cref="T:System.IO.FileNotFoundException">Thrown when one of the model
|
||||
files referenced by <paramref name="cfg"/> does not exist.</exception>
|
||||
</member>
|
||||
<member name="M:AIFotoONLUS.Core.NumberRecognitionEngine.DetectTextRegions(OpenCvSharp.Mat)">
|
||||
<summary>
|
||||
Detect text regions in the supplied image using the detection network.
|
||||
</summary>
|
||||
<param name="image">Input image as an OpenCvSharp <see cref="T:OpenCvSharp.Mat"/>.
|
||||
Must not be <c>null</c>.</param>
|
||||
<returns>An enumerable of <see cref="T:AIFotoONLUS.Core.DetectedRegion"/> containing the
|
||||
bounding boxes, confidence and class information for each detected
|
||||
region. The results are already filtered with the configured
|
||||
confidence and NMS thresholds.</returns>
|
||||
</member>
|
||||
<member name="M:AIFotoONLUS.Core.NumberRecognitionEngine.RecognizeDigits(OpenCvSharp.Mat,System.String)">
|
||||
<summary>
|
||||
Recognize digits inside a cropped image region using the recognition
|
||||
network. The method runs the recognition network and returns the
|
||||
concatenated sequence of recognized digit labels ordered left-to-right.
|
||||
</summary>
|
||||
<param name="croppedImage">Cropped image containing digits as
|
||||
<see cref="T:OpenCvSharp.Mat"/>. Must not be <c>null</c>.</param>
|
||||
<param name="context">Optional context string used for diagnostics
|
||||
(e.g. when saving crop image files).</param>
|
||||
<returns>A string containing recognized digits in left-to-right order.
|
||||
Returns an empty string when no digits are recognized above the
|
||||
configured confidence threshold.</returns>
|
||||
</member>
|
||||
<member name="T:AIFotoONLUS.Core.NumberRecognitionEngine.DetectionOutput">
|
||||
<summary>
|
||||
Small DTO that describes the name and shape of a detection network
|
||||
forward output used for diagnostics.
|
||||
</summary>
|
||||
<param name="Name">Layer/output name.</param>
|
||||
<param name="Rows">Number of rows in the output Mat.</param>
|
||||
<param name="Cols">Number of columns in the output Mat.</param>
|
||||
</member>
|
||||
<member name="M:AIFotoONLUS.Core.NumberRecognitionEngine.DetectionOutput.#ctor(System.String,System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Small DTO that describes the name and shape of a detection network
|
||||
forward output used for diagnostics.
|
||||
</summary>
|
||||
<param name="Name">Layer/output name.</param>
|
||||
<param name="Rows">Number of rows in the output Mat.</param>
|
||||
<param name="Cols">Number of columns in the output Mat.</param>
|
||||
</member>
|
||||
<member name="P:AIFotoONLUS.Core.NumberRecognitionEngine.DetectionOutput.Name">
|
||||
<summary>Layer/output name.</summary>
|
||||
</member>
|
||||
<member name="P:AIFotoONLUS.Core.NumberRecognitionEngine.DetectionOutput.Rows">
|
||||
<summary>Number of rows in the output Mat.</summary>
|
||||
</member>
|
||||
<member name="P:AIFotoONLUS.Core.NumberRecognitionEngine.DetectionOutput.Cols">
|
||||
<summary>Number of columns in the output Mat.</summary>
|
||||
</member>
|
||||
<member name="T:AIFotoONLUS.Core.NumberRecognitionEngine.DiagnosticResult">
|
||||
<summary>
|
||||
Result returned by <see cref="M:AIFotoONLUS.Core.NumberRecognitionEngine.ProcessFileWithDiagnostics(System.String)"/>, contains
|
||||
the recognized text result and an array describing detection network
|
||||
forward outputs (shapes and names) which are useful for debugging
|
||||
model output layout mismatches.
|
||||
</summary>
|
||||
<param name="Result">Recognition result for the processed image.</param>
|
||||
<param name="DetectionOutputs">Array describing detection net outputs.</param>
|
||||
</member>
|
||||
<member name="M:AIFotoONLUS.Core.NumberRecognitionEngine.DiagnosticResult.#ctor(AIFotoONLUS.Core.ImageResult,AIFotoONLUS.Core.NumberRecognitionEngine.DetectionOutput[])">
|
||||
<summary>
|
||||
Result returned by <see cref="M:AIFotoONLUS.Core.NumberRecognitionEngine.ProcessFileWithDiagnostics(System.String)"/>, contains
|
||||
the recognized text result and an array describing detection network
|
||||
forward outputs (shapes and names) which are useful for debugging
|
||||
model output layout mismatches.
|
||||
</summary>
|
||||
<param name="Result">Recognition result for the processed image.</param>
|
||||
<param name="DetectionOutputs">Array describing detection net outputs.</param>
|
||||
</member>
|
||||
<member name="P:AIFotoONLUS.Core.NumberRecognitionEngine.DiagnosticResult.Result">
|
||||
<summary>Recognition result for the processed image.</summary>
|
||||
</member>
|
||||
<member name="P:AIFotoONLUS.Core.NumberRecognitionEngine.DiagnosticResult.DetectionOutputs">
|
||||
<summary>Array describing detection net outputs.</summary>
|
||||
</member>
|
||||
<member name="M:AIFotoONLUS.Core.NumberRecognitionEngine.ProcessFileWithDiagnostics(System.String)">
|
||||
<summary>
|
||||
Process a single image file and return the recognition result together
|
||||
with detection network forward output shapes for diagnostics. This
|
||||
method reads the image from disk, runs a forward pass over the
|
||||
detection network to capture the raw output Mat shapes and then calls
|
||||
the normal processing pipeline to return the recognized text.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:AIFotoONLUS.Core.NumberRecognitionEngine.ProcessImage(System.String)">
|
||||
<summary>
|
||||
Process a single image file and return the recognized text as an
|
||||
<see cref="T:AIFotoONLUS.Core.ImageResult"/>. The method detects candidate text regions
|
||||
and runs recognition on each crop. Multiple recognized digit sequences
|
||||
are joined with a comma in the returned <see cref="P:AIFotoONLUS.Core.ImageResult.Text"/>.
|
||||
</summary>
|
||||
<param name="filePath">Path to an image file on disk. Supported
|
||||
formats depend on OpenCV (typically JPEG, PNG, ...).</param>
|
||||
<returns>An <see cref="T:AIFotoONLUS.Core.ImageResult"/> containing the file name and
|
||||
recognized text (possibly empty).</returns>
|
||||
</member>
|
||||
<member name="M:AIFotoONLUS.Core.NumberRecognitionEngine.ProcessDirectory(System.String,System.Boolean)">
|
||||
<summary>
|
||||
Process all JPEG images in a directory and return the recognition
|
||||
results. This is a blocking wrapper over <see cref="M:AIFotoONLUS.Core.NumberRecognitionEngine.ProcessDirectoryAsync(System.String,System.Boolean,System.Boolean,System.IProgress{AIFotoONLUS.Core.ProcessingStats},System.IProgress{AIFotoONLUS.Core.ImageResult},System.Threading.CancellationToken)"/>.
|
||||
</summary>
|
||||
<param name="directoryPath">Path to a directory containing images.</param>
|
||||
<param name="skipTextNegative">If true, files whose names start with
|
||||
"tn_" will be skipped (convention used to mark text-negative images).</param>
|
||||
<returns>Collection of <see cref="T:AIFotoONLUS.Core.ImageResult"/> ordered by file name.</returns>
|
||||
</member>
|
||||
<member name="M:AIFotoONLUS.Core.NumberRecognitionEngine.RecognizeDigits(OpenCvSharp.Mat,OpenCvSharp.Dnn.Net,System.String)">
|
||||
<summary>
|
||||
Worker overload of <see cref="M:AIFotoONLUS.Core.NumberRecognitionEngine.RecognizeDigits(OpenCvSharp.Mat,System.String)"/> that
|
||||
accepts a <see cref="T:OpenCvSharp.Dnn.Net"/> instance. This is used by the parallel
|
||||
processing pipeline where each worker owns its own Net instance.
|
||||
</summary>
|
||||
<param name="croppedImage">Cropped region to recognize.</param>
|
||||
<param name="recognitionNet">Recognition <see cref="T:OpenCvSharp.Dnn.Net"/> to execute
|
||||
the forward pass with.</param>
|
||||
<param name="context">Optional context string for diagnostics.</param>
|
||||
<returns>Recognized digit sequence or empty string.</returns>
|
||||
</member>
|
||||
<member name="T:AIFotoONLUS.Core.ProcessingStats">
|
||||
<summary>
|
||||
Progress statistics reported during directory processing.
|
||||
</summary>
|
||||
<param name="TotalFiles">Total number of image files to process.</param>
|
||||
<param name="ProcessedFiles">Number of files processed so far.</param>
|
||||
<param name="ImagesPerSecond">Current processing throughput in images/second.</param>
|
||||
</member>
|
||||
<member name="M:AIFotoONLUS.Core.ProcessingStats.#ctor(System.Int32,System.Int32,System.Double)">
|
||||
<summary>
|
||||
Progress statistics reported during directory processing.
|
||||
</summary>
|
||||
<param name="TotalFiles">Total number of image files to process.</param>
|
||||
<param name="ProcessedFiles">Number of files processed so far.</param>
|
||||
<param name="ImagesPerSecond">Current processing throughput in images/second.</param>
|
||||
</member>
|
||||
<member name="P:AIFotoONLUS.Core.ProcessingStats.TotalFiles">
|
||||
<summary>Total number of image files to process.</summary>
|
||||
</member>
|
||||
<member name="P:AIFotoONLUS.Core.ProcessingStats.ProcessedFiles">
|
||||
<summary>Number of files processed so far.</summary>
|
||||
</member>
|
||||
<member name="P:AIFotoONLUS.Core.ProcessingStats.ImagesPerSecond">
|
||||
<summary>Current processing throughput in images/second.</summary>
|
||||
</member>
|
||||
</members>
|
||||
</doc>
|
||||
|
|
@ -2,7 +2,29 @@ using OpenCvSharp;
|
|||
|
||||
namespace AIFotoONLUS.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a detected text region produced by the detection network.
|
||||
/// </summary>
|
||||
/// <param name="BoundingBox">Bounding rectangle of the detection in image coordinates.</param>
|
||||
/// <param name="Confidence">Combined confidence score for the detection (objectness * class probability).</param>
|
||||
/// <param name="ClassId">Class index predicted by the network (index into <see cref="ModelConfiguration.NumberClasses"/>).</param>
|
||||
/// <param name="CenterX">Center X coordinate (in pixels) of the bounding box, used to order detections left-to-right.</param>
|
||||
public record DetectedRegion(Rect BoundingBox, float Confidence, int ClassId, double CenterX);
|
||||
|
||||
/// <summary>
|
||||
/// Represents the result of recognizing a single region: recognized text,
|
||||
/// its bounding box and confidence.
|
||||
/// </summary>
|
||||
/// <param name="Text">Recognized text for the region (usually a sequence of digits).</param>
|
||||
/// <param name="BoundingBox">Bounding rectangle of the recognition result.</param>
|
||||
/// <param name="Confidence">Confidence score associated with the recognition.</param>
|
||||
public record RecognitionResult(string Text, Rect BoundingBox, double Confidence);
|
||||
|
||||
/// <summary>
|
||||
/// Aggregated result for a processed image.
|
||||
/// </summary>
|
||||
/// <param name="FileName">Name of the image file.</param>
|
||||
/// <param name="Text">Comma-separated recognized texts found in the image (may be empty).</param>
|
||||
/// <param name="FilePath">Full path to the processed image file.</param>
|
||||
public record ImageResult(string FileName, string Text, string FilePath);
|
||||
}
|
||||
|
|
@ -2,21 +2,63 @@ using OpenCvSharp;
|
|||
|
||||
namespace AIFotoONLUS.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Configuration options that control model file locations, input sizes
|
||||
/// and runtime thresholds used by <see cref="NumberRecognitionEngine"/>.
|
||||
/// </summary>
|
||||
public class ModelConfiguration
|
||||
{
|
||||
/// <summary>
|
||||
/// Path to the Darknet configuration (.cfg) file for the detection network.
|
||||
/// </summary>
|
||||
public string DetectionCfg { get; set; } = "models/detection.cfg";
|
||||
|
||||
/// <summary>
|
||||
/// Path to the Darknet weights (.weights) file for the detection network.
|
||||
/// </summary>
|
||||
public string DetectionWeights { get; set; } = "models/detection.weights";
|
||||
|
||||
/// <summary>
|
||||
/// Path to the Darknet configuration (.cfg) file for the recognition network.
|
||||
/// </summary>
|
||||
public string RecognitionCfg { get; set; } = "models/recognition.cfg";
|
||||
|
||||
/// <summary>
|
||||
/// Path to the Darknet weights (.weights) file for the recognition network.
|
||||
/// </summary>
|
||||
public string RecognitionWeights { get; set; } = "models/recognition.weights";
|
||||
|
||||
/// <summary>
|
||||
/// Confidence threshold used to filter out low-probability detections.
|
||||
/// </summary>
|
||||
public double ConfidenceThreshold { get; set; } = 0.5;
|
||||
|
||||
/// <summary>
|
||||
/// Non-maximum suppression (NMS) IoU threshold used to remove overlapping
|
||||
/// detection boxes.
|
||||
/// </summary>
|
||||
public double NmsThreshold { get; set; } = 0.4;
|
||||
|
||||
/// <summary>
|
||||
/// Input size used when preparing the blob for the detection network.
|
||||
/// </summary>
|
||||
public Size DetectionInputSize { get; set; } = new Size(416, 416);
|
||||
|
||||
/// <summary>
|
||||
/// Input size used when preparing the blob for the recognition network.
|
||||
/// </summary>
|
||||
public Size RecognitionInputSize { get; set; } = new Size(140, 120);
|
||||
|
||||
/// <summary>
|
||||
/// Labels representing digit classes in the recognition model. The order
|
||||
/// must match the class ordering used by the trained recognition network.
|
||||
/// </summary>
|
||||
public string[] NumberClasses { get; set; } = new[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
|
||||
// When true, recognition crops will be saved to disk for diagnostics. Disabled by default.
|
||||
|
||||
/// <summary>
|
||||
/// When enabled, recognition crops will be saved to disk under
|
||||
/// "logs/crops" for diagnostic inspection. Disabled by default.
|
||||
/// </summary>
|
||||
public bool EnableCropSaving { get; set; } = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -12,8 +12,32 @@ using System.Threading.Tasks;
|
|||
namespace AIFotoONLUS.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// NumberRecognitionEngine: loads Darknet models via OpenCvSharp and
|
||||
/// provides methods to detect text regions and recognize digits.
|
||||
/// NumberRecognitionEngine is a high-level wrapper that loads Darknet (YOLO)
|
||||
/// models through OpenCvSharp's DNN API and exposes simple synchronous and
|
||||
/// asynchronous methods to detect numeric text regions in images and recognize
|
||||
/// the digits contained within those regions.
|
||||
///
|
||||
/// Overview
|
||||
/// - Loads two Darknet networks: a detection network (finds text regions)
|
||||
/// and a recognition network (recognizes digits inside a cropped region).
|
||||
/// - Uses OpenCvSharp (CvDnn) to create input blobs, run forward passes and
|
||||
/// perform non‑maximum suppression (NMS) on detection candidates.
|
||||
/// - Provides single-image and directory-level processing APIs. Directory
|
||||
/// processing supports parallel workers where each worker uses its own
|
||||
/// per-thread Net instances to allow concurrent forward calls.
|
||||
///
|
||||
/// Threading and performance notes
|
||||
/// - The class constructs and owns two shared Net instances used by the
|
||||
/// simple (single-threaded) APIs. When doing parallel processing the
|
||||
/// implementation creates per-thread Net instances to avoid concurrent
|
||||
/// calls into the same Net object. A small fallback path exists that will
|
||||
/// call into the shared nets under a lock when needed.
|
||||
/// - OpenCV internal threading is enabled (Cv2.SetNumThreads) when supported.
|
||||
///
|
||||
/// Diagnostics
|
||||
/// - When enabled via the configuration, crops may be saved to disk for
|
||||
/// debugging. The <see cref="ModelConfiguration"/> contains thresholds and
|
||||
/// paths used by the engine.
|
||||
/// </summary>
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
|
|
@ -27,11 +51,37 @@ namespace AIFotoONLUS.Core
|
|||
private readonly ILogger? _logger;
|
||||
private bool _disposed;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new instance of <see cref="NumberRecognitionEngine"/> using the
|
||||
/// provided <see cref="ModelConfiguration"/>. The constructor loads the
|
||||
/// detection and recognition Darknet model files and prepares the OpenCV
|
||||
/// DNN nets for CPU inference.
|
||||
/// </summary>
|
||||
/// <param name="cfg">Model configuration containing file paths, thresholds
|
||||
/// and other options. Must not be <c>null</c>.</param>
|
||||
/// <remarks>
|
||||
/// This constructor will throw <see cref="FileNotFoundException"/> when
|
||||
/// any of the expected model files are missing. For logging purposes an
|
||||
/// overload accepting an <see cref="ILogger"/> is available.
|
||||
/// </remarks>
|
||||
public NumberRecognitionEngine(ModelConfiguration cfg)
|
||||
: this(cfg, logger: null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new instance of <see cref="NumberRecognitionEngine"/> with an
|
||||
/// optional <see cref="ILogger"/>. The logger will receive diagnostic
|
||||
/// messages and errors produced by the engine during processing.
|
||||
/// </summary>
|
||||
/// <param name="cfg">Model configuration containing file paths and
|
||||
/// runtime thresholds.</param>
|
||||
/// <param name="logger">Optional logger for diagnostic messages.
|
||||
/// May be <c>null</c>.</param>
|
||||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="cfg"/>
|
||||
/// is <c>null</c>.</exception>
|
||||
/// <exception cref="FileNotFoundException">Thrown when one of the model
|
||||
/// files referenced by <paramref name="cfg"/> does not exist.</exception>
|
||||
public NumberRecognitionEngine(ModelConfiguration cfg, ILogger? logger)
|
||||
{
|
||||
_logger = logger;
|
||||
|
|
@ -77,6 +127,15 @@ namespace AIFotoONLUS.Core
|
|||
|
||||
private string[] GetOutputLayerNames(Net net) => net.GetUnconnectedOutLayersNames();
|
||||
|
||||
/// <summary>
|
||||
/// Detect text regions in the supplied image using the detection network.
|
||||
/// </summary>
|
||||
/// <param name="image">Input image as an OpenCvSharp <see cref="Mat"/>.
|
||||
/// Must not be <c>null</c>.</param>
|
||||
/// <returns>An enumerable of <see cref="DetectedRegion"/> containing the
|
||||
/// bounding boxes, confidence and class information for each detected
|
||||
/// region. The results are already filtered with the configured
|
||||
/// confidence and NMS thresholds.</returns>
|
||||
public IEnumerable<DetectedRegion> DetectTextRegions(Mat image)
|
||||
{
|
||||
if (image is null) throw new ArgumentNullException(nameof(image));
|
||||
|
|
@ -190,6 +249,18 @@ namespace AIFotoONLUS.Core
|
|||
return results;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recognize digits inside a cropped image region using the recognition
|
||||
/// network. The method runs the recognition network and returns the
|
||||
/// concatenated sequence of recognized digit labels ordered left-to-right.
|
||||
/// </summary>
|
||||
/// <param name="croppedImage">Cropped image containing digits as
|
||||
/// <see cref="Mat"/>. Must not be <c>null</c>.</param>
|
||||
/// <param name="context">Optional context string used for diagnostics
|
||||
/// (e.g. when saving crop image files).</param>
|
||||
/// <returns>A string containing recognized digits in left-to-right order.
|
||||
/// Returns an empty string when no digits are recognized above the
|
||||
/// configured confidence threshold.</returns>
|
||||
public string RecognizeDigits(Mat croppedImage, string? context = null)
|
||||
{
|
||||
if (croppedImage is null) throw new ArgumentNullException(nameof(croppedImage));
|
||||
|
|
@ -287,12 +358,31 @@ namespace AIFotoONLUS.Core
|
|||
return string.Concat(ordered);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Small DTO that describes the name and shape of a detection network
|
||||
/// forward output used for diagnostics.
|
||||
/// </summary>
|
||||
/// <param name="Name">Layer/output name.</param>
|
||||
/// <param name="Rows">Number of rows in the output Mat.</param>
|
||||
/// <param name="Cols">Number of columns in the output Mat.</param>
|
||||
public record DetectionOutput(string Name, int Rows, int Cols);
|
||||
|
||||
/// <summary>
|
||||
/// Result returned by <see cref="ProcessFileWithDiagnostics"/>, contains
|
||||
/// the recognized text result and an array describing detection network
|
||||
/// forward outputs (shapes and names) which are useful for debugging
|
||||
/// model output layout mismatches.
|
||||
/// </summary>
|
||||
/// <param name="Result">Recognition result for the processed image.</param>
|
||||
/// <param name="DetectionOutputs">Array describing detection net outputs.</param>
|
||||
public record DiagnosticResult(ImageResult Result, DetectionOutput[] DetectionOutputs);
|
||||
|
||||
/// <summary>
|
||||
/// Process a single image file and return the recognition result together with
|
||||
/// detection network forward output shapes for diagnostics.
|
||||
/// Process a single image file and return the recognition result together
|
||||
/// with detection network forward output shapes for diagnostics. This
|
||||
/// method reads the image from disk, runs a forward pass over the
|
||||
/// detection network to capture the raw output Mat shapes and then calls
|
||||
/// the normal processing pipeline to return the recognized text.
|
||||
/// </summary>
|
||||
public DiagnosticResult ProcessFileWithDiagnostics(string filePath)
|
||||
{
|
||||
|
|
@ -330,6 +420,16 @@ namespace AIFotoONLUS.Core
|
|||
return new DiagnosticResult(imgRes, outputs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process a single image file and return the recognized text as an
|
||||
/// <see cref="ImageResult"/>. The method detects candidate text regions
|
||||
/// and runs recognition on each crop. Multiple recognized digit sequences
|
||||
/// are joined with a comma in the returned <see cref="ImageResult.Text"/>.
|
||||
/// </summary>
|
||||
/// <param name="filePath">Path to an image file on disk. Supported
|
||||
/// formats depend on OpenCV (typically JPEG, PNG, ...).</param>
|
||||
/// <returns>An <see cref="ImageResult"/> containing the file name and
|
||||
/// recognized text (possibly empty).</returns>
|
||||
public ImageResult ProcessImage(string filePath)
|
||||
{
|
||||
if (!File.Exists(filePath)) throw new FileNotFoundException("Image not found", filePath);
|
||||
|
|
@ -351,6 +451,14 @@ namespace AIFotoONLUS.Core
|
|||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process all JPEG images in a directory and return the recognition
|
||||
/// results. This is a blocking wrapper over <see cref="ProcessDirectoryAsync"/>.
|
||||
/// </summary>
|
||||
/// <param name="directoryPath">Path to a directory containing images.</param>
|
||||
/// <param name="skipTextNegative">If true, files whose names start with
|
||||
/// "tn_" will be skipped (convention used to mark text-negative images).</param>
|
||||
/// <returns>Collection of <see cref="ImageResult"/> ordered by file name.</returns>
|
||||
public IEnumerable<ImageResult> ProcessDirectory(string directoryPath, bool skipTextNegative = false)
|
||||
{
|
||||
// Simple wrapper over async implementation
|
||||
|
|
@ -504,6 +612,16 @@ namespace AIFotoONLUS.Core
|
|||
}
|
||||
|
||||
// Overload RecognizeDigits that accepts a Net for worker threads
|
||||
/// <summary>
|
||||
/// Worker overload of <see cref="RecognizeDigits(Mat,string?)"/> that
|
||||
/// accepts a <see cref="Net"/> instance. This is used by the parallel
|
||||
/// processing pipeline where each worker owns its own Net instance.
|
||||
/// </summary>
|
||||
/// <param name="croppedImage">Cropped region to recognize.</param>
|
||||
/// <param name="recognitionNet">Recognition <see cref="Net"/> to execute
|
||||
/// the forward pass with.</param>
|
||||
/// <param name="context">Optional context string for diagnostics.</param>
|
||||
/// <returns>Recognized digit sequence or empty string.</returns>
|
||||
private string RecognizeDigits(Mat croppedImage, Net recognitionNet, string? context = null)
|
||||
{
|
||||
if (croppedImage is null) throw new ArgumentNullException(nameof(croppedImage));
|
||||
|
|
|
|||
|
|
@ -1,4 +1,10 @@
|
|||
namespace AIFotoONLUS.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Progress statistics reported during directory processing.
|
||||
/// </summary>
|
||||
/// <param name="TotalFiles">Total number of image files to process.</param>
|
||||
/// <param name="ProcessedFiles">Number of files processed so far.</param>
|
||||
/// <param name="ImagesPerSecond">Current processing throughput in images/second.</param>
|
||||
public record ProcessingStats(int TotalFiles, int ProcessedFiles, double ImagesPerSecond);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,13 @@
|
|||
<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" />
|
||||
<!-- MinVer for tag-based semantic versioning -->
|
||||
<PackageReference Include="MinVer" Version="3.1.0" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<!-- Fallback version when no tag is present -->
|
||||
<Version>0.1.0</Version>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AIFotoONLUS.Core\AIFotoONLUS.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue