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

<!-- category -- AI,OCR,NER,ONNX,CSharp,Tutorial,NuGet -->
<datetime class="hidden">2026-02-12T12:00</datetime>

[![NuGet](https://img.shields.io/nuget/v/Mostlylucid.OcrNer)](https://www.nuget.org/packages/Mostlylucid.OcrNer/) [![NuGet-downloads](https://img.shields.io/nuget/dt/Mostlylucid.OcrNer)](https://www.nuget.org/packages/Mostlylucid.OcrNer/) [![GitHub-utsläpp (CLI)](https://img.shields.io/github/v/release/scottgal/mostlylucidweb?filter=ocrner-*&label=CLI)](https://github.com/scottgal/mostlylucidweb/releases?q=ocrner)

I [Del 1](/blog/simple-ocr-ner-extraction) 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 [***klar*RAG**](https://www.lucidrag.com) var denna produktionsversion, -, finns

[TOC]

---


## 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](https://www.clips.uantwerpen.be/conll2003/ner/) 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](https://sixlabors.com/products/imagesharp/) förprocessing** - gråskala , kontrastupphöjning M SK2 Sharpening tuned for OCR
2. **[OpenCV](https://opencv.org/) avancerad förprocessing** - deskew, , denoise, ,, och binarisering för skadade, M SK3, skivade dokument.
3. **[Florence-2](https://huggingface.co/microsoft/Florence-2-base)** 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](https://github.com/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](https://spectreconsole.net/) command-lineapp som bara fungerar ur lådan

---


## Vad har ändrats från del 1

```mermaid
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

```bash
dotnet add package Mostlylucid.OcrNer
```

### Register Services

Den `AddOcrNer()` förlängningsmetoden registrerar allting

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

```csharp
// 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

```csharp
// 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

```json
{
  "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:

```csharp
// 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

```mermaid
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 **effektivitet**Vä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 :

```csharp
// 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

```csharp
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.

```csharp
// 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`:

```csharp
// 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:

```csharp
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

```mermaid
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

```csharp
// 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:

```csharp
// 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](https://github.com/scottgal/lucidrag).

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

```mermaid
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:

```csharp
config.EnableAdvancedPreprocessing = true;
```

```bash
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](https://github.com/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. (

```csharp
config.EnableRecognizers = true;
config.RecognizerCulture = "en-us";
```

```bash
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:

```csharp
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.

```csharp
// 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:

```csharp
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`)  |  Florensen`IVisionService`) |
|----------|--------------------------|-------------------------------|
| **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](/blog/simple-ocr-ner-extraction): **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

```csharp
// 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

```csharp
// 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.

```mermaid
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

```csharp
// 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/`

```text
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

```mermaid
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

```csharp
// 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](https://spectreconsole.net/). Det är designat som en framgångssaga

### Vinnig Start

```bash
# 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`:

```csharp
// 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:**

```bash
ocrner ner "Marie Curie won the Nobel Prize in Stockholm"
```

```text
╭──────┬─────────────┬────────────┬──────────╮
│ 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

```bash
ocrner ner "Shelby Lucier from SCS Agency in Cambridge, UK sent an invoice on 13/02/15. Call 07981423683." -r
```

```text
╭──────┬───────────────┬────────────┬──────────╮
│ 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

```bash
ocrner ocr shareholder-letter.jpg -q
```

```text
╭──────┬───────────────┬────────────┬──────────╮
│ 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`)  |  Florensen`ocrner 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.

```bash
ocrner ner "Shelby Lucier from SCS Agency in Cambridge, UK sent an invoice on 13/02/15. Call 07981423683." -r --json
```

```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

```bash
# 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:

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

### Batchprocessing

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

```bash
# 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

```json
{
  "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 ♫ [***klar*RAG**](https://www.lucidrag.com). 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.

```csharp
// 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](https://huggingface.co/microsoft/Phi-3.5-vision-instruct) eller [LLaVA](https://llava-vl.github.io/)) 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

```mermaid
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. [***klar*RAG**](https://www.lucidrag.com) är heading.

---


## resurser

**Paketet**:

- **[Mostlylucid.OcrNer på NuGet](https://www.nuget.org/packages/Mostlylucid.OcrNer)** - Installera den
- **[källkod](https://github.com/scottgal/mostlylucidweb/tree/main/Mostlylucid.OcrNer)** - Gå igenom implementeringen

**Del 1**:

- **[Enkel OCR och NER Feature Extraction](/blog/simple-ocr-ner-extraction)** - Instruktion som förklarar varje sak

**beroenden**:

- **[Tesseract.NET](https://github.com/charlesw/tesseract)** - CM SK1 ompackare för Tesseract OCR
- **[BERT-bas-NER ONNX](https://huggingface.co/protectai/bert-base-NER-onnx)** - NER-modellen
- **[Florence-2](https://www.nuget.org/packages/Florence2)** - NuGet-paket för Visionsmodell
- **[Bildform](https://sixlabors.com/products/imagesharp/)** - Cross -plattformimage processing
- **[OpenCvSharp4](https://github.com/shimat/opencvsharp)** - OpenCV-wrapper för avancerad preprocessing
- **[Microsoft.Recognizers.Text](https://github.com/microsoft/Recognizers-Text)** - regel -baserad enhetens extraktion
- **[Runtime på ONNX](https://onnxruntime.ai/)** - Cross -plattformmodellförklaring

**Related Articles**:

- **[Det tre---Tier-OCR-röret](/blog/constrained-fuzzy-image-ocr-pipeline)** - När du behöver mer än enkel OCR
- **[Reduzerad RAG](/blog/reduced-rag-concept)** - Där extraherade enheter passar in i större sammanhang
- **[*klar*RAG](https://www.lucidrag.com)** - Den fulla multi- -Phassproduktionskedjan