Det mest liksägade.OcrNer - NuGet-paketet (Teil 2) (Svenska (Swedish))

Det mest liksägade.OcrNer - NuGet-paketet (Teil 2)

Thursday, 12 February 2026

//

23 minute read

NuGet NuGet-downloads GitHub-utsläpp (CLI)

I Del 1 Jag visade rutorleitungen, :, laddade ner modeller med hjälp av en hand, ,, skrev ut en tokenisator och ,, kopplade upp ONNX-förklaringar och dekoderade BIO-tag till hand.

Nu är det ett NuGet-paket Ett rutnät av installering , noll modelldownloads - allt automatiskt -downloads på första gången

Nota: Det här paketet är ett förenklat, fokusserat verktyg för att extrahera text och enheter från bilder. vad som helst ( foton, , dokument, , bilder från skärmen, M SK3 handskrivning,, animerad grafiker och till och med videor, MSC5, med fuzzy matchning, MST6, OCR-konsens, M ST7, och strukturerad extraktion, M st 8, kolla ut klarRAG var denna produktionsversion, -, finns


Vinniga Glossar (Om du är ny till detta'

Innan vi dyker in i

  • OCR (Optical Character Recognition
  • NER (Erkännande av namngedda varelser ) | | - att scanna text för att hitta och klassificera namn på saker och ting.
  • Runtime på ONNX - ett sätt att köra maskininlärningsmodeller likt den BERT-modellen vi använder för NERM SK2 på din maskin utan att behöva Python, TensorFlowMSC4 eller en GPUMska5 Den kör modellen som en bärbar .onnx file, lokalt, med enbart din CPU
  • BERT - en tidigare - tränad språkmodell från Google som förstår kontexten i text CoNLL-2003 dataset för att känna igen människor
  • Florence-2 - en liten modell från Microsoft som kan beskriva vad det är ser i en bild (captioner , objekt, textM SK3 skiljer sig från Tesseract i att den förstår hela scenen

Varför mer än enkel tesseract?

Tesseract är starkt för ren dokumenttext, men det faller ner på högljudda foton., lågt, - kontrastscanner,, och blandad." scen, + text, MSC6 bilder, M SK7 Det stannar också vid råtext, -, du behöver fortfarande extra kod för att omvandla den texten till strukturerade enheter som du faktiskt kan använda.

Det här paketet minskar dom klyftorna

  1. Bildform förprocessing - gråskala , kontrastupphöjning M SK2 Sharpening tuned for OCR
  2. OpenCV avancerad förprocessing - deskew, , denoise, ,, och binarisering för skadade, M SK3, skivade dokument.
  3. Florence-2 syn - lokalt bildskapande och OCR via ONNX ♫ ( ♫ ingen moln-API ♫) ♫
  4. BERT NER ovanför OCR-teksten - konvertera utvunnet text till utskrivna enheter PER/ORGM SK3LOCMST4MISCMst5 du kan agera på
  5. Microsoft.Recognizers.Text - regel, -baserad extraktion av datum, ,, nummer, M SK3, URLs, MST4, telefoner, M ST5, e-post, M st6 och IP.
  6. Rättvis DI-integration - AddOcrNer() och du "'" är klar
  7. CLI-verktyg - A Spectre.Konsole command-lineapp som bara fungerar ur lådan

Vad har ändrats från del 1

flowchart LR
    subgraph Part1["Part 1: Manual"]
        M1[Download models]
        M2[Write tokenizer]
        M3[Wire ONNX]
        M4[BIO decode]
    end

    subgraph Part2["Part 2: NuGet Package"]
        N1["AddOcrNer()"]
        N2[Auto-download]
        N3[ImageSharp + OpenCV]
        N4[Florence-2]
        N5[Recognizers]
        N6[CLI Tool]
    end

    Part1 -->|"packaged into"| Part2

    style N1 stroke:#090,stroke-width:3px
    style N2 stroke:#090,stroke-width:3px
    style N3 stroke:#f60,stroke-width:3px
    style N4 stroke:#f60,stroke-width:3px
    style N5 stroke:#f60,stroke-width:3px
    style N6 stroke:#f60,stroke-width:3px

Del 1 var pedagogiskt | - | förstå vad varje del gör | . | del 2 | är praktiskt ♫ - | använda det utan att tänka på insidan ♫


Nu börjar det

Installera

dotnet add package Mostlylucid.OcrNer

Register Services

Den AddOcrNer() förlängningsmetoden registrerar allting

Här är "'", den faktiska registrationskoden från ServiceCollectionExtensions.cs:

// Option 1: From appsettings.json (reads the "OcrNer" section)
builder.Services.AddOcrNer(builder.Configuration);

// Option 2: Inline configuration
builder.Services.AddOcrNer(config =>
{
    config.EnableOcr = true;
    config.TesseractLanguage = "eng";
    config.MinConfidence = 0.5f;
});

Det är det. AddOcrNer() registrerar dessa tjänster

// From ServiceCollectionExtensions.cs - what gets registered
services.AddSingleton<ModelDownloader>();           // Auto-downloads models on first use
services.AddSingleton<ImagePreprocessor>();         // ImageSharp-based image enhancement
services.AddSingleton<OpenCvPreprocessor>();        // OpenCV advanced preprocessing
services.AddSingleton<INerService, NerService>();   // BERT NER from text
services.AddSingleton<IOcrService, OcrService>();   // Tesseract OCR from images
services.AddSingleton<IOcrNerPipeline, OcrNerPipeline>();         // Combined OCR + NER
services.AddSingleton<ITextRecognizerService, TextRecognizerService>(); // Microsoft.Recognizers
services.AddSingleton<IVisionService, VisionService>();           // Florence-2 vision

Konfiguration (appsettings.jsonM SK2

{
  "OcrNer": {
    "EnableOcr": true,
    "TesseractLanguage": "eng",
    "MinConfidence": 0.5,
    "MaxSequenceLength": 512,
    "ModelDirectory": "models/ocrner",
    "Preprocessing": "Default",
    "EnableAdvancedPreprocessing": false,
    "EnableRecognizers": false,
    "RecognizerCulture": "en-us"
  }
}

Här är den faktiska OcrNerConfig klassa dessa kartor till:

// From OcrNerConfig.cs
public class OcrNerConfig
{
    public string ModelDirectory { get; set; } =
        Path.Combine(AppContext.BaseDirectory, "models", "ocrner");
    public bool EnableOcr { get; set; } = true;
    public string TesseractLanguage { get; set; } = "eng";
    public int MaxSequenceLength { get; set; } = 512;
    public float MinConfidence { get; set; } = 0.5f;
    public string NerModelRepo { get; set; } = "protectai/bert-base-NER-onnx";
    public PreprocessingLevel Preprocessing { get; set; } = PreprocessingLevel.Default;
    public bool EnableAdvancedPreprocessing { get; set; } = false;  // OpenCV pipeline
    public bool EnableRecognizers { get; set; } = false;            // Microsoft.Recognizers
    public string RecognizerCulture { get; set; } = "en-us";       // Recognizer language
}

Alla inställningar har känsliga standardinställningar. Du kan utelämna hela sektionen och allt fungerarM SK1 De två opt-inställningarna-EnableAdvancedPreprocessing och EnableRecognizers) standard false så att paketet håller sig lätt för användare som inte behöver dem

Den Preprocessing option kontrollerar bilduppgradering före OCR:

värde Vad det gör När det ska användas
None Ingen förprocessing Bilder är redan optimerade
Minimal Bara i gråskala Renta skanningar
Default Grysskall + kontrast МSK2 skarpare De flesta bilderna ♫ tillämpt
Aggressive Stark kontrast + skarpare + uppskala dålig kvalitet på foton

De fyra tjänsterna

Paketet registrerar fem tjänster

flowchart TD
    subgraph Services
        NER["INerService<br>Text → Entities"]
        OCR["IOcrService<br>Image → Text"]
        REC["ITextRecognizerService<br>Text → Signals"]
        PIPE["IOcrNerPipeline<br>Image → Entities + Signals"]
        VIS["IVisionService<br>Image → Caption"]
    end

    OCR --> PIPE
    NER --> PIPE
    REC -.-> PIPE

    style PIPE stroke:#090,stroke-width:3px
    style VIS stroke:#f60,stroke-width:3px
    style REC stroke:#f60,stroke-width:2px,stroke-dasharray: 5 5

Välja den rätta servicen för ditt användandefall

Det viktigaste principet är effektivitetVälj det minsta verktyget som gör jobbet.

Service Vad det gör Modellstorlek МSK3 Rymden ♫ Använd när
INerService BERT NER från text МSK2 MB SSK4 ms Du har redan text
IOcrService Tesseract OCR från bilder МSK2 MB ~100 ms SMK5 Du behöver text från dokumentscanning
IOcrNerPipeline OCR och sedan NER i en sändning Båda modeller МSK3 ms Du har bilder och vill ha varelser i ett steg
ITextRecognizerService regeln -baserad extraktion datum , telefoner , etc МSK5 SMK6 ingen SJ7 MVK8 ms SVK9 Ni vill ha strukturerade data tillsammans med NER-enheter
IVisionService Florence-2 undertitelning + OCR МSK4 MB ~1-3 Man behöver förståelse för bilder

NER från text ( Inga bilder behövs

Om du redan har text ( från PDFs , databaser, användardatainputningMSC3 kan du använda NER direktM SK4 Det här är den snabbaste vägen ♫ - utan OCR ♫

Den INerService gränssnittet är enkelt - en metod :

// From INerService.cs
public interface INerService
{
    Task<NerResult> ExtractEntitiesAsync(string text, CancellationToken ct = default);
}

Här' hur man använder den i sin egen tjänst

public class MyService
{
    private readonly INerService _nerService;

    public MyService(INerService nerService)
    {
        _nerService = nerService;
    }

    public async Task ProcessDocumentAsync(string text)
    {
        var result = await _nerService.ExtractEntitiesAsync(text);

        foreach (var entity in result.Entities)
        {
            // entity.Label: "PER", "ORG", "LOC", or "MISC"
            // entity.Text: "John Smith"
            // entity.Confidence: 0.9996
            // entity.StartOffset / EndOffset: character positions in the source
        }
    }
}

Resultatmodellen är enkla.

// From NerResult.cs / NerEntity.cs
public class NerResult
{
    public string SourceText { get; init; } = string.Empty;
    public List<NerEntity> Entities { get; init; } = [];
}

public class NerEntity
{
    public string Text { get; init; } = string.Empty;     // "John Smith"
    public string Label { get; init; } = string.Empty;    // "PER", "ORG", "LOC", "MISC"
    public float Confidence { get; init; }                 // 0.0 to 1.0
    public int StartOffset { get; init; }                  // Where in the source text
    public int EndOffset { get; init; }                    // End position (exclusive)
}

Den första sändningen laddar ner BERT NER-modellen (~430MBM SK1 från HuggingFace. De efterföljande sändningarna använder kaskad modellen | - | Starten är omedelbar


OCR + NER Pipeline

För bilder, hanterar pipelinen förundersökningar, OCRM SK2 och NER i en sändning IOcrNerPipeline kombinerar IOcrService och INerService:

// From OcrNerPipeline.cs - the actual pipeline code
public async Task<OcrNerResult> ProcessImageAsync(string imagePath, CancellationToken ct = default)
{
    // Step 1: OCR (includes preprocessing automatically)
    var ocrResult = await _ocrService.ExtractTextAsync(imagePath, ct);

    if (string.IsNullOrWhiteSpace(ocrResult.Text))
        return new OcrNerResult
        {
            OcrResult = ocrResult,
            NerResult = new NerResult { SourceText = string.Empty }
        };

    // Step 2: NER on extracted text
    var nerResult = await _nerService.ExtractEntitiesAsync(ocrResult.Text, ct);

    return new OcrNerResult
    {
        OcrResult = ocrResult,
        NerResult = nerResult
    };
}

Att använda den:

var pipeline = serviceProvider.GetRequiredService<IOcrNerPipeline>();

var result = await pipeline.ProcessImageAsync("invoice.png");

// What OCR found
var text = result.OcrResult.Text;           // The full extracted text
var confidence = result.OcrResult.Confidence; // 0.0 to 1.0

// What NER found in that text
foreach (var entity in result.NerResult.Entities)
{
    // [PER] John Smith, [ORG] Microsoft, [LOC] Seattle...
}

Vad händer under hyddan

flowchart LR
    IMG[Image bytes]
    PRE["ImageSharp<br>or OpenCV"]
    TESS["Tesseract<br>OCR"]
    TOK["WordPiece<br>Tokenize"]
    BERT["BERT NER<br>ONNX"]
    REC["Recognizers<br>(optional)"]
    OUT[Result]

    IMG --> PRE
    PRE --> TESS
    TESS --> TOK
    TOK --> BERT
    BERT --> REC
    REC --> OUT

    style PRE stroke:#f60,stroke-width:3px
    style BERT stroke:#f60,stroke-width:3px
    style REC stroke:#f60,stroke-width:2px,stroke-dasharray: 5 5

Bildfördelande

Del 1 hade rå Tesseract sändningar . I praktiken, fungerade både Tesserac och Florence better med förutbehandlade bilder som vanligt men helt optionellt - så kan du avaktivera det med Preprocessing = "None" i konfigurationen eller --preprocess none på CLI.

Den ImagePreprocessor användar Bildform (pure C#, inga inhemska beroenden

// From ImagePreprocessor.cs - the actual preprocessing steps
public byte[] Preprocess(byte[] imageBytes, PreprocessingOptions? options = null)
{
    options ??= PreprocessingOptions.Default;
    using var image = Image.Load<Rgba32>(imageBytes);

    image.Mutate(ctx =>
    {
        // Step 1: Upscale small images (Tesseract wants 300+ DPI equivalent)
        if (options.EnableUpscale && (image.Width < options.MinWidth || image.Height < options.MinHeight))
        {
            var scale = Math.Max(
                (float)options.MinWidth / image.Width,
                (float)options.MinHeight / image.Height);
            scale = Math.Min(scale, options.MaxUpscaleFactor);
            ctx.Resize((int)(image.Width * scale), (int)(image.Height * scale),
                KnownResamplers.Lanczos3);
        }

        // Step 2: Grayscale (single channel = faster, more accurate)
        if (options.EnableGrayscale)
            ctx.Grayscale();

        // Step 3: Contrast boost (text stands out from background)
        if (options.EnableContrast && options.ContrastAmount != 1.0f)
            ctx.Contrast(options.ContrastAmount);

        // Step 4: Sharpen (crisp character edges)
        if (options.EnableSharpen)
            ctx.GaussianSharpen(options.SharpenSigma);
    });

    using var ms = new MemoryStream();
    image.SaveAsPng(ms);  // PNG = lossless, no additional artifacts
    return ms.ToArray();
}

Tre preseter är inbyggda i. PreprocessingOptions klass definierar dem:

// From ImagePreprocessor.cs
public static PreprocessingOptions Default => new();  // Grayscale + 1.5x contrast + sharpen

public static PreprocessingOptions Minimal => new()   // Grayscale only
{
    EnableContrast = false,
    EnableSharpen = false,
    EnableUpscale = false
};

public static PreprocessingOptions Aggressive => new() // For poor quality images
{
    ContrastAmount = 1.8f,
    SharpenSigma = 1.5f,
    MinWidth = 1024,
    MinHeight = 768,
    MaxUpscaleFactor = 4.0f
};
Föreställ När man ska använda ♫ ♫ ♫ Vad det gör ♫
Default De flesta bilderna Grysskall ♫ ♫ + ♫
Minimal Klara skanningar Grysskalar bara
Aggressive De dåliga bilderna är dåliga 1.8x kontrast + tydligare skarpare + större uppskala

Utvecklad förberedels med OpenCV

För allvarligt nedbrytade dokument - skiftade skanningar , högljudda foton , fördunstade historiska sidor | - | är ImageSharp-pinget inte sufficient EnableAdvancedPreprocessing att byta till en komplett OpenCV pipeline ImageSummarizer.

OpenCV: s processorkedjor går i fyra stadier , var och en styrd av en automatisk kvalitetbedömning:

flowchart LR
    IMG[Image]
    QA["Quality<br>Assess"]
    SK["Deskew"]
    DN["Denoise"]
    BIN["Binarize"]
    OUT[Clean image]

    IMG --> QA
    QA --> SK
    SK --> DN
    DN --> BIN
    BIN --> OUT

    style QA stroke:#f60,stroke-width:2px

Kvalite चाsning (ImageQualityAssessor) mäter svaghet , skiva vinkeln M SK2 oljudsnivån МSK3 kontrasten , ljusstyrka jämlikhet , och textdensitet Mska6 Baserat på resultaten Mske7 rekommenderar den vilka steg som ska tillämpas Msko8 så att renta bilder hoppar över onödigt bearbetande

Deskew (SkewCorrector) korrigerar roterade dokument med hjälp av tre metoder: Hough-linje-detektorn | ( | standard | МSK3 | minimala yta rektangel |, | eller prognosprofilanalys |

Denoise (NoiseReducer) erbjuder Gaussiansk ojämlikhet | ( | snabbt | ), | bilateralt filter |( | beläggning | МSK4 | upprätthållande |

Binärs (InkExtractor) konverterar till ren svart - och- vitt med hjälp av OtsuM SK3 anpassningsbar tröskeln MSC4 Sauvola ( för nedbrytna historiska dokument M SK6 CLAHE

Aktivera det i konfiguration eller på CLI:

config.EnableAdvancedPreprocessing = true;
ocrner ocr damaged-scan.png -a

Microsoft.Recognizers: RegelM SK2Based Entity Extraction

BERT NER hittar människor, organisations, ,, platser, , och en massa andra varelser.. Men några strukturerade data, datum, M SK4, telefonnummer, ,, e-poster, ,, URLs, mska8, IP-adresser, är bättre fångade av deterministiska regler än av ett neuronnätverk.

Aktivera EnableRecognizers att lägga till en andra extraktionspass med Microsoft.Recognizers.Text. Den kör efter NER och extrakter:

Typ exempel
Datum och tid " Januar
Nummer 2 3 tre miljoner 4 5 6
URL
Telefon "555-1234", ♫ ♫ "+1 ♫
E-post
IP-Adresse

Den gör det möjligt att känna igen flera kulturer. (

config.EnableRecognizers = true;
config.RecognizerCulture = "en-us";
ocrner ner "John Smith joined Microsoft on January 15, 2024. Call 555-1234." -r

De två extraktionsmetoderna kompletterar varandra. OcrNerResult modellen inkluderar nu ett optionellt Signals egendom:

public class OcrNerResult
{
    public OcrResult OcrResult { get; init; } = new();
    public NerResult NerResult { get; init; } = new();
    public RecognizedSignals? Signals { get; init; }  // Only when EnableRecognizers = true
}

Florence-2 Vision

Florence-2 är ett helt annat angreppssätt än Tesseract synmodell som förstår hela bilden.

// From IVisionService.cs
public interface IVisionService
{
    Task<VisionCaptionResult> CaptionAsync(string imagePath, bool detailed = true,
        CancellationToken ct = default);
    Task<VisionOcrResult> ExtractTextAsync(string imagePath,
        CancellationToken ct = default);
    Task<bool> IsAvailableAsync(CancellationToken ct = default);
}

Att använda den:

var vision = serviceProvider.GetRequiredService<IVisionService>();

// Generate a caption describing the image
var caption = await vision.CaptionAsync("photo.jpg", detailed: true);
if (caption.Success)
{
    // caption.Caption: "A man in a blue suit standing at a podium"
    // caption.DurationMs: how long it took
}

// Extract visible text using Florence-2's built-in OCR
var ocrResult = await vision.ExtractTextAsync("screenshot.png");
if (ocrResult.Success)
{
    // ocrResult.Text: the visible text Florence-2 detected
}

När man ska använda vilken

användande fall Tesseract (IOcrService) FlorensenIVisionService)
Dokumentsskanning Det bästa valet - snabbt , korrekt МSK3 OK men överkill
Fotos av skyltar Anständigt bättre - förstår scenkontexten
Screenshots Bra Bra
Beeldskap Kan' inte göra det här Det bästa valet
Rymden snabbare (~100ms) långsammare ♫ (~1-3s ♫
Modellstorlek ~4MB ♫ ♫ ~450 ♫

Poängen är effektivitet: använda Tesseract för dokument och text extraktion (it's 10x snabbare med en smaller model förståelse.

Florence-2 auto-downloads dess modeller (~450MBM SK3 på första användning till {ModelDirectory}/florence2/.


Hur NER-tunneln fungerar internt

NER: s ledning följer samma tre steg-process som beskrivs i Del 1: att tokenisera → dra slutsatsen → avkoda. Del | 1 | går genom varje koncept ♫ - | WordPiece-tokenisering ♪ , | ONNX-tensor-förklaring ♪ МSK4 | BIO-tag-dekodering ♪, | Softmax-förtroende ♪

Här' är vad paketet lägger till bortom den manuella metoden

Offset-spårning

Del 1's tokenisator konverterar text till tokensidentityder BertNerTokenizer också spår karakter avvikelser - så du vet exakt var i källtexten varje enhet fanns

// From BertNerTokenizer.cs
// "John Smith works at Microsoft" becomes:
// [CLS] John Smith works at Micro ##soft [SEP] [PAD] ...
//
// Each token tracks its source position:
// "John"     → chars 0-4
// "Smith"    → chars 5-10
// "Micro"    → chars 20-29  (WordPiece splits "Microsoft")
// "##soft"   → chars 20-29  (same source range)

Det här är hur NerEntity.StartOffset och EndOffset jobba - de kartlägger tillbaka exakta teckenpositioner i din ursprungliga text

Konfidentitet-Extraktion av splittrade enheter

Del 1's dekoder producerar alla enheter. Paketet filtrerar under dekodering - lågtM SK3 förtroendemürset når aldrig din kod

// From NerService.cs
private void FlushEntity(
    List<NerEntity> entities, string text,
    string type, int start, int end, float confidence)
{
    if (confidence < _config.MinConfidence) return;  // Filter low-confidence

    var entityText = text[start..end].Trim();
    if (string.IsNullOrWhiteSpace(entityText)) return;

    entities.Add(new NerEntity
    {
        Text = entityText,
        Label = type,
        Confidence = confidence,
        StartOffset = start,
        EndOffset = end
    });
}

Auto-Download: Hur det fungerar

Alla modeller laddas ner automatiskt på första användning. Inga manuella installering krävs.

flowchart TD
    CALL["First API call"]
    CHECK{"Files exist<br>in cache?"}
    YES[Use cached model]
    NO["Download to .tmp file"]
    MOVE["Atomic rename<br>.tmp → final"]

    CALL --> CHECK
    CHECK -->|Yes| YES
    CHECK -->|No| NO
    NO --> MOVE
    MOVE --> YES

    style NO stroke:#f60,stroke-width:3px
    style MOVE stroke:#090,stroke-width:3px

Den ModelDownloader nedlägningar från HuggingFace (NER model) och GitHub (tessdataM SK3 Den använder en .tmp mönster - om en nedladning avbröts , inga korrupta plier finns kvar

// From ModelDownloader.cs - atomic download pattern
await using var fileStream = new FileStream(tempPath, FileMode.Create,
    FileAccess.Write, FileShare.None, 81920, true);
// ... stream download to .tmp file ...
await fileStream.FlushAsync(ct);
fileStream.Close();

File.Move(tempPath, localPath, overwrite: true);  // Atomic rename

Standard cache-positionen: {AppBaseDir}/models/ocrner/

models/ocrner/
  ner/
    model.onnx      (~430MB - BERT NER)
    vocab.txt       (~230KB - WordPiece vocabulary)
    config.json     (~1KB - label mapping)
  tessdata/
    eng.traineddata (~4MB - English OCR data)
  florence2/
    ...             (~450MB - Vision model files)

Arkitektur

Allt är en enda ton med lat initialisering. dyra resurser (ONNX InferenceSession, TesseractEngine, Florence -2 modell) skapas en gång på första användning och återanvändas under hela applikationens livstid

flowchart TD
    DI["AddOcrNer()"]

    DI --> MD["ModelDownloader<br>(singleton)"]
    DI --> PP["ImagePreprocessor<br>(singleton)"]
    DI --> CV["OpenCvPreprocessor<br>(singleton)"]
    DI --> NER["NerService<br>(singleton)"]
    DI --> OCR["OcrService<br>(singleton)"]
    DI --> PIPE["OcrNerPipeline<br>(singleton)"]
    DI --> REC["TextRecognizerService<br>(singleton)"]
    DI --> VIS["VisionService<br>(singleton)"]

    MD --> NER
    MD --> OCR
    PP --> OCR
    CV --> OCR
    NER --> PIPE
    OCR --> PIPE
    REC --> PIPE

    style DI stroke:#090,stroke-width:3px

Thread safety: alla tjänster används SemaphoreSlim för initialisering. Flera trådar som ropar på dienste samtidigt vid den första användningen kommer bara att signalera en ladda-down

// From NerService.cs - lazy init pattern used by all services
private async Task EnsureInitializedAsync(CancellationToken ct)
{
    if (_initialized) return;           // Fast path: already loaded

    await _initLock.WaitAsync(ct);      // Only one thread enters
    try
    {
        if (_initialized) return;       // Double-check after lock

        var paths = await _downloader.EnsureNerModelAsync(ct);
        _tokenizer = new BertNerTokenizer(paths.VocabPath, _config.MaxSequenceLength);
        _session = new InferenceSession(paths.ModelPath, sessionOptions);
        _initialized = true;
    }
    finally { _initLock.Release(); }
}

CLI-verktyg

repo består av ett command-line-verktyg byggt med Spectre.Konsole. Det är designat som en framgångssaga

Vinnig Start

# NER from text (auto-detected)
ocrner "John Smith works at Microsoft in Seattle"

# OCR from an image (auto-detected)
ocrner invoice.png

# Explicit commands
ocrner ner "Marie Curie won the Nobel Prize in Stockholm"
ocrner ocr scan.png
ocrner caption photo.jpg

Smart ruttering: det CLI-automatiska ♫ ♫ - ♫ tar reda på din intention ♫ Program.cs:

// From Program.cs - smart routing logic
if (IsImageFile(args2[0]) || IsGlobPattern(args2[0]) || Directory.Exists(args2[0]))
{
    args2 = ["ocr", .. args2];   // Image file → ocr command
}
else
{
    args2 = ["ner", .. args2];   // Text string → ner command
}

Om du skickar vidare en textsträng, så kör den NER. Om du går vidare med en bilddatet , globM SK3 eller directoryMska4 så driver den OCR Mske5 NER~Mske6 Det behövs inga kommandor

Tre kommandor

Kommando Vad det gör Motor
ner <text> Extrahera enheter från texten BERT NER
ocr <path> OCR ♫ + ♫ NER från bilderna ♫ ♫ Tesseract ♫
caption <path> Bild captioning + optional OCR Florence-2 M(ONNXM)

Tesseract är standard OCR-motorn eftersom det är snabbare och optimerat för dokumenttext.

Den riktiga utgången

Här är "'", den faktiska utgången från att köra CLI mot riktiga provdokument.

NER från text:

ocrner ner "Marie Curie won the Nobel Prize in Stockholm"
╭──────┬─────────────┬────────────┬──────────╮
│ Type │ Entity      │ Confidence │ Position │
├──────┼─────────────┼────────────┼──────────┤
│ PER  │ Marie Curie │ 100%       │ 0-11     │
│ MISC │ Nobel Prize │ 100%       │ 20-31    │
│ LOC  │ Stockholm   │ 100%       │ 35-44    │
╰──────┴─────────────┴────────────┴──────────╯

NER med utkännare - kombinerar BERT-enheter med regeln-baserade signalextraktion

ocrner ner "Shelby Lucier from SCS Agency in Cambridge, UK sent an invoice on 13/02/15. Call 07981423683." -r
╭──────┬───────────────┬────────────┬──────────╮
│ Type │ Entity        │ Confidence │ Position │
├──────┼───────────────┼────────────┼──────────┤
│ PER  │ Shelby Lucier │ 100%       │ 0-13     │
│ ORG  │ SCS Agency    │ 100%       │ 19-29    │
│ LOC  │ Cambridge     │ 100%       │ 33-42    │
│ LOC  │ UK            │ 100%       │ 44-46    │
╰──────┴───────────────┴────────────┴──────────╯

── Recognized Signals ─────────────────────────
  Type       Text          Details
  DateTime   13/02/15      datetimeV2.date
  Phone      07981423683

BERT hittar personerna, organisationer och platser, , och . recognisatorerna fångar datum och telefonnummer, strukturerade mönster som ett nervnätverk inte kan lita på för att extrahera.

OCR från ett scannat dokument ( ett brev från Amazons aktieägare , skannat med hål

ocrner ocr shareholder-letter.jpg -q
╭──────┬───────────────┬────────────┬──────────╮
│ Type │ Entity        │ Confidence │ Position │
├──────┼───────────────┼────────────┼──────────┤
│ ORG  │ Amazon        │ 87%        │ 285-291  │
│ PER  │ Jeff          │ 99%        │ 293-297  │
│ ORG  │ AWS           │ 95%        │ 984-987  │
│ LOC  │ America       │ 98%        │ 2315-2322│
╰──────┴───────────────┴────────────┴──────────╯
OCR Confidence: 89%

Tesseract extraherar nära -verbatimtext från den skannade bokstaven vid | 89% | confidence | , | och NER identifierar korrekt Amazon

Tesseract vs Florence-2: En verklig jämförelse

Samma skannade aktieägares brev processat av båda motorerna:

Tesseract (ocrner ocr) Florensenocrner caption --ocr)
Rymden ~200ms
OCR: s korrekthet näraM SK1 verbalt , 3 självförtroende svårt förvridna , hallucinererade fraser
Nyckeltext , ", under de senaste 2 åren på Amazon, har jag haft möjligheten att skriva många berättelser.
NER-enheter Jeff ♫ ♫ (PER ♫
Beteckning NM SK1A " Ett papper med lite text

Florence-2 är en syn modell - den förstår scener , objekt , och yttre relationer M SK3 Den var aldrig designad för att konkurrera med Tesseract när man läser dokumenttext förståelse ( vad ' är i det här fotot?), inte text extraktion ( vad säger detta dokument?

JSON utgång för automatisering & LLM verktyg

Den --json Flagg-output som strukturerar JSON till stdout med alla teckningar tryckta. - designad för att koppla in andra verktyg.

ocrner ner "Shelby Lucier from SCS Agency in Cambridge, UK sent an invoice on 13/02/15. Call 07981423683." -r --json
{
  "command": "ner",
  "success": true,
  "sourceText": "Shelby Lucier from SCS Agency in Cambridge, UK...",
  "entityCount": 4,
  "entities": [
    { "type": "PER", "text": "Shelby Lucier", "confidence": 0.9996, "startOffset": 0, "endOffset": 13 },
    { "type": "ORG", "text": "SCS Agency", "confidence": 0.999, "startOffset": 19, "endOffset": 29 },
    { "type": "LOC", "text": "Cambridge", "confidence": 0.9975, "startOffset": 33, "endOffset": 42 },
    { "type": "LOC", "text": "UK", "confidence": 0.9991, "startOffset": 44, "endOffset": 46 }
  ],
  "signals": {
    "dateTimes": [{ "text": "13/02/15", "typeName": "datetimeV2.date" }],
    "phoneNumbers": [{ "text": "07981423683" }]
  }
}

Detta gör CLI användbart som verktyg för LLMs och agenter. En LLM kan ringa ocrner ner "..." --json, analysera JSON-responsen , och resonera över strukturerade enheterna. jq, fed to an agent framework , or read from any language

# Pipe to jq for quick filtering
ocrner ocr invoice.png --json | jq '.results[0].entities[] | select(.type == "PER")'

# Use from Python, Node, or any language that can shell out
echo "John Smith at Microsoft" | ocrner ner --json

För att spara till en file istället, använda -o med en .json utlängning - samma strukturerade data , skriven på disken:

ocrner ocr "scans/*.png" -o results.json

Batchprocessing

Bearbeta flera bilder med glob-mönster eller kataloger:

# All PNGs in a directory
ocrner ocr "scans/*.png" -o results.json

# All images in a folder
ocrner ocr ./documents/

# Batch captioning with Florence-2
ocrner caption "photos/*.jpg" --ocr -o captions.md

Alla CLI-optioner

Flagg Begriper Beschreibung ♫
--json ner, ocr, caption Strukturerad JSON till stdout (klagar --quiet, spränger alla loginningar)
-c ner, ocr Minimalt värde av enhetens självförtroende
--language ocr Tesseract språk ( till exempel eng, fra)
--max-tokens ner, ocr Max. BERT-sekvenslängd
--model-dir ner, ocr, caption överrider modellens dataminne katalog
-p, --preprocess ocr, caption Förstad bearbetande förutsättning none, minimal, default, aggressive
-a, --advanced-preprocess ocr, caption Använd OpenCV-processing
-r, --recognizers ner, ocr Aktivera regeln
--culture ner, ocr Rekogniseringskultur en-us, de-de (default: en-us)
--brief caption Generera en kortare, mindre detaljerad caption
-q, --quiet ner, ocr, caption Tystnadsmodi (reduzerad konsol-utgång)
-o ner, ocr, caption Utgångspfad för filen (.txt, .md, .json)
--ocr caption kör också OCR under captionbefehl
--ner caption Extrahera NER från OCR: s text ( förenkla --ocr)

Performance: kvantifierade modeller och vad

Den nuvarande NER-modellen är den fulla protectai/bert-base-NER-onnx (~430MB kvantifierad Versionen av samma modell skulle vara betydligt snabbare med minimalt fel på precision

ONNX Runtime supporterar INT8 kvantisering ur lådan , som vanligtvis minskar modellens storlek med ~4x och förbättrar uträkningshastigheten med ♫ 2-3x på CPU ♫ NerModelRepo config-optionen stödjer redan att peka på en annan HuggingFace repo, så när ett kvantifierat modell publiceras så ändrar du bara

{
  "OcrNer": {
    "NerModelRepo": "protectai/bert-base-NER-onnx-quantized"
  }
}

Architekturen är designad för den här - byta ut modellen , behålla samma API


Den större bilden: Där det passar

Paketet är engångs---torn:, en OCR-motor, ,, ett NER-modell, ,, ett optionellt synmodell,., det är designat för att vara enkelt och effektivt i det vanliga fallet.

För mer komplexa scenarier - läsa text från vad som helst ( handskrivna anteckningar , foton av svarta tavlor| , lågt ♫ - ♫ kvalitet med kamerainspelningar ♫), ♫ med flera ♫ klarRAG. Det där ' är platsen där produktionen - klassificeras, , flera versioner av detta arbete lever i fas,

Vad's Nästa: Multimodala LLM

Florence -2 är den nuvarande takt för lokal syn i detta paket. Nästa logiska steg multimodal LLM - en modell som kan se en bild och skälet till det på ett naturligt språk

Här är ungefär hur den API skulle kunna se ut.

// Hypothetical future IMultimodalService
public interface IMultimodalService
{
    Task<StructuredExtractionResult> ExtractAsync(
        string imagePath,
        string prompt = "Extract all people, organizations, and locations from this image. Return as JSON.",
        CancellationToken ct = default);
}

// Usage
var multimodal = serviceProvider.GetRequiredService<IMultimodalService>();
var result = await multimodal.ExtractAsync("business-card.jpg");

// result.Entities: [{ "John Smith", PER }, { "Acme Corp", ORG }, { "New York", LOC }]
// result.RawText: "John Smith, VP Engineering, Acme Corp, New York, NY 10001"
// result.Summary: "Business card for John Smith at Acme Corp in New York"

Små lokala multimodella modeller (liknande Phi-3.5-vision eller LLaVA) håller på att bli bra nog för det här . Världen är alltid densamman M SK3 större modell = smartare men långsammare MSC5 Det rätta valet beror på ditt latensbudget och noggranna krav

flowchart LR
    subgraph Staged["Staged Approach: Pick Your Level"]
        T1["Tesseract OCR<br>4MB | ~100ms<br>Text extraction"]
        T2["BERT NER<br>430MB | ~50ms<br>Entity extraction"]
        T3["Florence-2<br>450MB | ~1-3s<br>Image understanding"]
        T4["Multimodal LLM<br>2-8GB | ~5-30s<br>Full reasoning"]
    end

    T1 --> T2
    T2 --> T3
    T3 -.->|"future"| T4

    style T1 stroke:#090,stroke-width:2px
    style T2 stroke:#090,stroke-width:2px
    style T3 stroke:#f60,stroke-width:2px
    style T4 stroke:#999,stroke-width:2px,stroke-dasharray: 5 5

Varje nivå adderar förmåga till kostnaden av storlek och latens. klarRAG är heading.


resurser

Paketet:

Del 1:

beroenden:

Related Articles:

Finding related posts...
logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.