# Molto chiaro.OcrNer - Il pacchetto NuGet (Parte 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/) [![Lavorando NuGet](https://img.shields.io/nuget/dt/Mostlylucid.OcrNer)](https://www.nuget.org/packages/Mostlylucid.OcrNer/) [![Distribuzione di GitHub (CLI)](https://img.shields.io/github/v/release/scottgal/mostlylucidweb?filter=ocrner-*&label=CLI)](https://github.com/scottgal/mostlylucidweb/releases?q=ocrner)

In [Parte 1](/blog/simple-ocr-ner-extraction) Ho mostrato il tubo di scarto: scaricare i modelli manualmente, scrivere un tokenizzatoreM SK2 collegare l'inferenza ONNX , e decodificare le targhette BIO a mano

Ora è un package NuGet. **Una linea di impostazioni, download del modello zero** - tutto automatico-downloads on first useM SK2

> **Nota:** Questo paquet è uno strumento semplificato, focalizzato per estrarre il testo e le entità dalle immagini. Se avete bisogno di un'intera multi-pipelina M SK2phase che può leggere il testo da *qualsiasi cosa.* (photosM SK1documenti,screenshots ,scrittura manuale,,GIF animati e video,)con corrispondenza confusa,MSC6consenso di riproduczione,M SK7e extrazione strutturata,MST8consultare [***lucido.*RAG**](https://www.lucidrag.com) dove vive la versione a livello di produzione di questo tubodotto-

[TOC]

---


## Glossario rapido (Se sei nuovo a ')

Prima di approfondire, ecco cosa significano i termini chiave.

- **OCR** (Recognizione di caratteri otticiM SK1 - convertire un'immagine di testo in caratteri di testo reali il vostro codice può funzionare con
- **NER** (Recognizione delle entità chiamateM SK1 - scansione del testo per trovare e classificare i nomi delle cose. ♫"John Smith lavora alla Microsoft a SeattleMST5 diventaMSSK6 John Smith = PersonaMSC8 Microsoft SSK9 OrganizzaturaMSM10 Seattle CMS11 LivelloMSS12
- **Il tempo di esecuzione di ONNX** - un modo per far funzionare i modelli di apprendimento automatico  come il modello BERT che usiamo per NERM SK2 sulla vostra macchina senza bisogno di Python, TensorFlowMSC4 o di una GPU\. Funziona il modello come un portatile `.onnx` file, localmente, usando solo il vostro CPUM SK2
- **BERT** - un modello linguistico predisposto di Google che capisce il contesto nel testo. [CoNLL-2003](https://www.clips.uantwerpen.be/conll2003/ner/) set di dati per riconoscere le persone, organizzazioni, posizioniM SK2 e diverse entitàMSC3
- **Florence-2** - un piccolo modello visivo di Microsoft che può descrivere cosa sia. *Vedere* in un'immagine (captioniM SK1oggetti, testo ). Differente da Tesseract nel senso che capisce l'intera scena

---


## Perché più di Tesseract semplice?

Tesseract è forte per il testo pulito del documento, ma si abbassa sulle foto rumorose, bassaM SK2 scansioni di contrasto , e mixed MST4 scena MST5 testoM ST6 immaginiM st7 Si ferma anche al testo grezzo S ST8 c'è ancora bisogno di un codice extra per trasformare quel testo in entità strutturate che si possono effettivamente usareM S ST9

Questo pacco elimina quei differenze:

1. **[ImageSharp](https://sixlabors.com/products/imagesharp/) preprocesso** - scala grigiaM SK1 aumento di contrasto, affinamento regolato per l'OCR
2. **[OpenCV](https://opencv.org/) preprocesso avanzato** - deskewMSC1 denoise, e binarizzazione per i documenti danneggiatiM SK3skewed (optMST5in)
3. **[Florence-2](https://huggingface.co/microsoft/Florence-2-base)** Visione - Local Image captioning and OCR via ONNX (no cloud API)
4. **BERT NER sopra il testo OCR** - convertire il testo estratto in entità tipificate PER/ORGM SK3LOCMST4MISCMst5 potete agire su
5. **[Microsoft.Recognizers.Texto](https://github.com/microsoft/Recognizers-Text)** - regola-estractione basata sulle dateM SK2 numeri , URLsMST4 telefoniM ST5 emailMst6 e IP MST7optMSST8inMST9
6. **La giusta integrazione DI** - `AddOcrNer()` E voi avete finito.
7. **Gli strumenti CLI** - A [Spectre.Console](https://spectreconsole.net/) command-line app che funziona fuori dal box

---


## Cosa è cambiato dalla parte 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
```

Parte 1 è stato educativo - capire cosa fa ogni pezzo

---


## Cominciamo

### Installare

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

### Registrare i servizi

L'informazione figura nella parte dispositiva. `AddOcrNer()` Il metodo di estensione registra tutto: OCR, NERM SK2 il conduttore combinato , FlorenceMSC4 la vistaMST5 il downloader del modelloMSSK6 e il preprocessore dell'immagineMSM7 Tutti come singole tonalitàMSV8 tutti pigriMSS9initialisatiM SS10

Qui' è il vero codice d'immatriculazione da `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;
});
```

Quello'è questoM SK1 Nessun download del modello, nessun percorso per i file , nessun collegamento ONNXMSC4 sotto il cappotto `AddOcrNer()` Registra questi servizi:

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

### Configurazione (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"
  }
}
```

Qui' è il vero `OcrNerConfig` Classare queste mappe a:

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

Tutte le impostazioni hanno dei predefinimenti sensibili. Si può omitare l'intera sezione e tutto funziona. I due optiM SK2in caratteristiche (`EnableAdvancedPreprocessing` e `EnableRecognizers`) predefinito a `false` Quindi il pacchetto rimane leggero per gli utenti che non ne hanno bisogno.

L'informazione figura nella parte dispositiva. `Preprocessing` l'opzione controlla l'aumento dell'immagine prima di OCR:

| Valore | Cosa fa | Quando usare S|
|-------|-------------|-------------|
| `None` | Niente pre-processo | Le immagini sono già ottimizzate |
| `Minimal` | Solo a scala grigia | Scanne puliti MSC2
| `Default` | A scala grigia + contrasto + spezzare | La maggior parte delle immagini
| `Aggressive` | Con un forte contrasto + spezzare + ingrandire | foto di scarsa qualità SSM4

---


## I quattro servizi

Il pacchetto registra cinque servizi, ciascuno usabile in modo indipendente. Prendete quello che va bene per il vostro caso d'uso M SK2 lì ' non c'è bisogno di caricare FlorenceMSC4 se tutto ciò di cui avete bisogno è NER dal testoMNK5

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

### Scegliere il giusto servizio per il vostro caso d'uso

Il principio chiave è questo. **L'efficienza.**: scegliere l'outil più leggero che faccia il lavoroM SK1 Non caricare un modello di visione 450MB quando un motore OCR

| Il servizio | Cosa fa | La dimensione del modello S| La velocità M| Usare quando R... D|
|---------|-------------|------------|-------|-------------|
| `INerService` | BERT NER dal testo | ~430MB SSK3 \~50ms S| Al momento avete il testo |  | PDF | , | database |, | input degli utenti
| `IOcrService` | Tesseract OCR dalle immagini | ~4MB | \~100ms SMK5 Avete bisogno del testo dalle scansioni dei documenti, schermi | | |
| `IOcrNerPipeline` | OCR poi NER in una sola chiamata | Entrambi i modelli | | | 3 | ms || | Avete immagini e volete entità in un solo passo |
| `ITextRecognizerService` | RegolaM SK1estrazione basata (date, telefoniMSC4 ecc.
| `IVisionService` | FlorenceM SK1 sottotittura + OCR | S~450MB M| | | ~1-3s || Dovete comprendere l'immagine, non solo leggere il testo R|

---


## NER dal testo (No Images Needed)

Se avete già il testo (in PDF,bassabase di datiM SK2input dell'utente ), potete usare il NER direttamenteMSC4 Questo è il percorso più veloce |- senza OCR | , senza elaborazione di immagini |

L'informazione figura nella parte dispositiva. `INerService` L'interfaccia è semplice - uno metodo:

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

Ecco come usarlo nel vostro servizio'

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

I modelli di risultato sono semplici:

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

La prima chiamata scarica il modello BERT NER (~430MBM SK1 da HuggingFace. Le chiamate successive usano il modello cached - lo startup è istantaneo

---


## OCR + Pipeline NER

Per le immagini, il pipeline gestisce il preprocessoM SK1 OCR, e NER in una sola chiamata `IOcrNerPipeline` Combina `IOcrService` e `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
    };
}
```

Usandola:

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

### Cosa succede sotto il cappotto

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

---


## Preprocesso dell'immagine

Parte 1 aveva chiamate di Tesseract crudeM SK1 In pratica, sia Tesserac che FlorenceMSC3 funzionano meglio con immagini preprocessateMスク4 Il preprocesso è **di solito.** ma completamente opzionale - lo si può disattivare con `Preprocessing = "None"` nella configurazione o `--preprocess none` sul CLI.

L'informazione figura nella parte dispositiva. `ImagePreprocessor` Usazioni **ImageSharp** (pure CM SK1 nessuna dipendenza nativa):

```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 prese sono costruite in.. `PreprocessingOptions` la classe li definisce:

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

| Preset | Quando usare SSK2 Cosa fa |
|--------|------------|--------------|
| `Default` | La maggior parte delle immagini | A scala grigia + 1.5 contrasto x S+ affinare leggermente MESK5
| `Minimal` | Scanne puliti | Solo a scala grigia MSC2
| `Aggressive` | Foto di scarsa qualità | 1.8x contrasto S+ forte uccisione M+ zoom più grande R|

### Preprocesso avanzato con OpenCV

Per i documenti gravemente degradati - scansioni skewed, foto rumoroseM SK2 pagine storiche sfocate - il pipeline ImageSharp non è sufficiente `EnableAdvancedPreprocessing` per passare a un intero pipeline OpenCV trasmesso da [ImageSummarizer](https://github.com/scottgal/lucidrag).

La catena di preprocessori OpenCV ha quattro fasi, ciascuna guidata da una valutazione automatica della qualità:

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

**Evaluazione della qualità** (`ImageQualityAssessor`) misura l'incertezzaM SK1 l'angolo di inclinazione , il livello di rumore, il contrastoMSC4 la uniformità della luminositàMST5 e la densità del testoM ST6 Basandosi sui risultatiMst7 raccomanda quali fasi di applicazione MST8 in modo che le immagini pulite sfuggino a un processo inutileM st9

**Deskew** (`SkewCorrector`) corregge i documenti ruotati usando tre metodiM SK1 Detezione delle linee di pieghe (default), rettangolo di area minimaMSC4 o analisi del profilo di proiezioneMNK5

**Denoise** (`NoiseReducer`) offre un'incertezza Gaussia (fastM SK2 filtro bilaterale Piccolo (proiettile -reservazione),non--meastri locali (Qualità più alta),operazioni morfologiche.

**Binarize** (`InkExtractor`) converte in nero pulito- eM SK2 bianco usando OtsuMSC3 soglia adattativaMST4 Sauvola MST5per documenti storici degradatiMSSK6 CLAHE MSST7 Otsu SST8per contrasti bassiMSS9 o rimozione di sfondo morfologicoM SS10

Lo accendere nella configurazione o sul CLI:

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

```bash
ocrner ocr damaged-scan.png -a
```

---


## Microsoft.Recognizers:RuleM SK2Estrazione di Entità basata

BERT NER trova le persone, le organizzazioni, i luoghiM SK2 e diverse entità . Ma alcuni dati strutturati MSC4 le dateMST5 i numeri telefoniciMst6 gli emailMSt7 le URLM st8 gli indirizzi IP SST9 è meglio catturato dalle regole deterministiche che da una rete neuraleSTS10

Includere `EnableRecognizers` per aggiungere un secondo passacolo di extrazione usando [Microsoft.Recognizers.Texto](https://github.com/microsoft/Recognizers-Text). Sta funzionando **dopo.** NER e estratti:

| Tipo | Esempi |
|------|----------|
| DateTime | "Giornale M15, \2024", | | "Tutorednessì", ♫"La settimana scorsaM SK8 ♪
| Numero
| URL
| Telefono | "555-1234", \"+1 | | (555) |
| E-mail  |
| Indice IP | "192.168.1.1" ≥|

Il riconoscitore supporta molte culture (enM SK1us, enMSC3gb , deMST5deMS, frMSV7frM SV8 etcMSP9 quindi gestisce localeMSS10formati specifici di data e convenzioni numericheMSSS11

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

```bash
ocrner ner "John Smith joined Microsoft on January 15, 2024. Call 555-1234." -r
```

I due metodi di extrazione si completano l'un l'altro: BERT NER capisce il contesto ("AppleM SK2 l'azienda controMSC3 "appleMST5 la fruttaMSR6 mentre i riconoscitori catturano in modo affidabile schemi strutturati che BERT potrebbe perdereMSL7 `OcrNerResult` Il modello ora include un modello opzionale. `Signals` proprietà:

```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 è un approccio completamente diverso da Tesseract. dove Tesserac è un motore specializzato per l'OCR che legge caratteri di testo in caratteri. **Il modello visivo.** che capisce l'intera immagine.

```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);
}
```

Usandola:

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

### Quando usare quale?

| Usazione | Tesseract (`IOcrService`)  | Florence`IVisionService`) |
|----------|--------------------------|-------------------------------|
| **Scanne dei documenti** | La scelta migliore - veloce, precisa MSC3 OK ma troppo grande MSC4
| **Fotografie di cartelli** | Decente | Meglio - capisce il contesto della scena S|
| **Screenshots** | Beno | Bene |
| **Copiatura dell'immagine** | PuòM SK1non lo fa | La scelta migliore |
| **La velocità** | veloce (~100ms) | più lento MSC4s
| **La dimensione del modello** |  ~4MB

Il punto è questo. **L'efficienza.**: usare Tesseract per l'estrazione dei documenti e del testo (it's 10x più veloce con un modello più piccolo SSK4x meno grande S). usare FlorenceM SK6 quando si ha davvero bisogno di un'immagine *La comprensione.*.

Florence-2 autoM SK1scarza i suoi modelli (~450MB) durante il primo uso. `{ModelDirectory}/florence2/`.

---


## Come funziona il Pipeline NER all'interno

Il pipeline del NER segue lo stesso processo di tre fasi -, descritto in dettaglio nel [Parte 1](/blog/simple-ocr-ner-extraction): **tokenizzare → inferire → decodificare**. Parte 1 passa attraverso ogni concezione - Tokenizzazione di WordPiece S, Tensorinferenza ONNX M, Decodazione di targhette BIO D, Softmax fiducia P- da zero con un esempio completo da costruire R.

Qui's quello che il pacchetto aggiunge oltre l'approccio manuale:

### Offset Tracking

Parte 1's tokenizer converte il testo in ID di toccoM SK1 Il pacchetto's `BertNerTokenizer` Anche i tracciati **offset di caratteri** - quindi sapete esattamente dove nel testo sorgente è stata trovata ogni entità:

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

Ecco come. `NerEntity.StartOffset` e `EndOffset` Funzionano - ritraggono la mappa alla posizione esatta dei caratteri nel vostro testo originale.

### Confidence-Estrazione delle entità accelerate

Parte 1' il decoder produce tutte le entità. Il filtro dell'etichetta durante la decodazione - bassaM SK3 il rumore di fiducia non raggiunge mai il vostro codiceMSC4

```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: Come funziona

Tutti i modelli vengono scaricati automaticamente durante il primo uso. Non c'è bisogno di setup manuale.

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

L'informazione figura nella parte dispositiva. `ModelDownloader` i download da HuggingFace (NER model) e GitHub (tessdataM SK3 Usa un'atomica `.tmp` schema - se il download è interrotto, non ci sono file corrottiM SK2

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

Localizzazione del caciò di default: `{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)
```

---


## L'architettura

Tutto è un singolo tono con l'initializzazione pigra. Ressource costose (ONNX `InferenceSession`, `TesseractEngine`, FlorenceM SK1 modello) vengono creati una volta usati per la prima volta e riutilizzati per tutta la vita dell'applicazione

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

Sicurezza dei fili: tutti i servizi usati `SemaphoreSlim` per l'initializzazione. Molti thread che chiamano simultaneamente il servizio durante la prima utilizzo triggereranno solo un downloadM SK1load:

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

Il repo contiene un'outil di comando-line costruito con [Spectre.Console](https://spectreconsole.net/). E' progettato come un punto di successo.

### Inizia veloce

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

**Routing intelligente**: l'auto CLIM SK1 rileva la vostra intenzione. Da `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
}
```

Se passate una stringa di testo, fa funzionare NER. se passate un file d'immagine , globM SK3 o un directoryMSC4 fa fonctionnere OCR MNK5 NER~. Non c'è bisogno di comandoMRK7

### Tre Comandi

| Comandamento | Cosa fa | | Motore | | | velocità ||
|---------|-------------|--------|-------|
| `ner <text>` | Estratto delle entità dal testo | BERT NER ONNXMSC3 S| \~50ms \ |
| `ocr <path>` | OCR + NER dalle immagini | Tesseract S+ BERT M| P~100-300ms R|
| `caption <path>` | Copiatura delle immagini + TAC opzionale | FlorenceM SK3 SSK4ONNX | |

**Tesseract è il motore OCR standard.** perché è più veloce e ottimizzato per il testo del documento. Florence-2 è per quando si vuole comprendere l'immagine M SK4captioniMSC5 testo della scena , foto dei segniMST7

### Effetto reale

Qui' il risultato reale dal fare funzionare la CLI contro i veri documenti campioni.

**NER dal testo:**

```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 con riconoscitori** - combinando le entità BERT con la regola-estrazione di segnali basata su :

```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 scopre le persone, le organizzazioni e i luoghi, la data e il numero di telefono, i modelli strutturati che una rete neurale non può estrarre.

**OCR da un documento scansionato** ( una lettera degli azionisti di AmazonM SK1 scansionata con un buco - marcature perforate):

```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 extrae near-testo verbale dalla lettera scansionata alla 89%confidenza*, e NER identifica correttamente AmazonM SK3 Jeff (Bezos+), AWS+MSC6 e Nord America+.

### Tesseract vs Florence-2: Una vera comparazione

La stessa lettera degli azionisti scannata processata da entrambi i motori:

| | Tesseract (`ocrner ocr`)  | Florence`ocrner caption --ocr`) |
|---|---|---|
| **La velocità** |
| **Accuratezza dell'OCR** | QuasiM SK1verbattibile, 89% fiducia | fortemente sconvoltoMSC5 frasi allucinate |
| **Il testo chiave** | " Negli ultimi 2 anni a Amazon, IM SK4 ho avuto l'opportunitàMSC5 ♫| |" negli ultimi 8 anni aAmazonMST9 I\' ho avuto l'occasione di scrivere molte storieMSV11 emailM SV12 \MSV13
| **Entità NER** | Jeff (PER), Amazon (ORGM SK4 AWS S(ORG+), America SSK7LOC+) M| NMSC10A R(il testo è troppo frammentato per essere affidabile.
| **Capzione** | NM SK1A | "Un foglio con qualche testo

Florence-2 è una **Visione** Modello - capisce sceneM SK1 oggetti , e relazioni spaziali. Non è mai stato progettato per competere con Tesseract nel leggere il testo di un documentoMSC4 Lo usate quando avete bisogno di un'immagine *La comprensione.* ( cos'èM SK1s in questa foto?), non testo *L'estrazione.* ( cosa dice questo documento?).

### Output JSON per l'automazione & LLM Tools

L'informazione figura nella parte dispositiva. `--json` Flag outputs structured JSON to stdout with allgging suppressed - designed for piping into other tools , LLM function callingM SK2 or automation scripts:

```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" }]
  }
}
```

Questo rende il CLI usabile come **L'outil** per LLM e gli agenti. Un LLM può chiamare `ocrner ner "..." --json`, analizzare la risposta JSON, e ragionare sulle entità strutturate - non c'è bisogno di codice personalizzato `jq`, inserirsi in un sistema agente, o leggere da qualsiasi linguaM SK2

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

Per salvare in un file invece, usate `-o` con un `.json` estensione - stessi dati strutturati, scritti al discoM SK2

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

### Trattura in serie

Progettare immagini multiple con schemi o indirizzi di glob:

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

### Tutte le opzioni CLI

| bandiera | Si applica a | Descrizione S|
|------|------------|-------------|
| `--json` | `ner`, `ocr`, `caption` | Structured JSON to stdout Simplies `--quiet`, sopprime l'interazione di tutti gli utentiM SK1 |
| `-c` | `ner`, `ocr` | Minimale soglia di fiducia delle entità (0.0-1.0) |
| `--language` | `ocr` | Tesseract language ( per esempio `eng`, `fra`) |
| `--max-tokens` | `ner`, `ocr` | Lunghezza máxima della sequenza BERT |
| `--model-dir` | `ner`, `ocr`, `caption` | Override il modello di directorio cache |
| `-p`, `--preprocess` | `ocr`, `caption` | Presito di preprocesso: `none`, `minimal`, `default`, `aggressive` |
| `-a`, `--advanced-preprocess` | `ocr`, `caption` | Utilizzare il preprocesso OpenCV (deskew, denoiseM SK3 binarizeMSC4 SSK5
| `-r`, `--recognizers` | `ner`, `ocr` | Spegnere la regola-estrazione basata (dateMSC3 numeriM SK4 URLsMST5 telefoniMst6 emailMSt7 IPsSST8 MSST9
| `--culture` | `ner`, `ocr` | cultura del riconoscitore, eM SK2g . `en-us`, `de-de` (default: `en-us`) |
| `--brief` | `caption` | Generare un sottotipo più breve, meno dettagliato |
| `-q`, `--quiet` | `ner`, `ocr`, `caption` | Modo silenzioso (Output della console ridotta) |
| `-o` | `ner`, `ocr`, `caption` | La strada del file di output (`.txt`, `.md`, `.json`) |
| `--ocr` | `caption` | Funzionare anche l'OCR durante il comando di captioning |
| `--ner` | `caption` | Estratto del NER dal testo OCR ( semplifica `--ocr`) |

---


## Rendimento: Modelli quantificati e cosa' Più avanti

Il modello NER attuale è la precisione completa di -. `protectai/bert-base-NER-onnx` (~430MBM SK1 Per molti casi di uso - specialmente su risorse-macchine limitate o quando si tratta di grandi volumi **Quantizzato** La versione dello stesso modello sarebbe significativamente più veloce con una perdita di precisione minima.

ONNX Runtime supports INT8 quantization out of the box, which typically reduce model size by M SK2x and improve inference speed by ♫2-3x on CPU ♫ . This is on the roadmap ♫ `NerModelRepo` L'opzione di configurazione già supporta il puntare ad un altro repo HuggingFace, quindi quando viene pubblicato un modello quantificato voi'd cambiate soloM SK2

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

L'architettura è progettata per questo - scambiare il modelloM SK1 mantenere la stessa API.

---


## Il quadro più grande: dove questo va bene

Questo paquet è un **Pipeline single-in fase**: un motore OCR , un modello NER, uno modello di visione opzionaleM SK3 È progettato per essere semplice e efficiente nel caso comuneMSC5

Per scenari più complessi - leggere il testo da *qualsiasi cosa.* (note scritte a manoM SK1 foto di tavole bianche, bassa frequenza - catturature fotografiche ad alta qualitàMSC4 multi-camera - consenso OCR dell'ingegnereMST6 corrispondenza confusaMSST7 e extrazione strutturata |MST8 |Check out the full pipeline at [***lucido.*RAG**](https://www.lucidrag.com). Quello' è dove vive la versione multi-phase di questo lavoro in fase di produzione

### Cosa's successivo: LLM multimodali

Florence-2 è il soffitto attuale per la visione locale in questo pacchetto. Il prossimo passo logico è un **LLM multimodale** - un modello che può vedere un'immagine *e* spiegarlo in un linguaggio naturale. Invece di un OCR separato + Passi NERM SK2 voi ' spedite l'immagine direttamente e chiedete un'estrazione strutturataMSC4

Qui' è più o meno come potrebbe apparire l'API:

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

Piccoli modelli multimodali locali (come [Phi-3.5-vision](https://huggingface.co/microsoft/Phi-3.5-vision-instruct) o [LLaVA](https://llava-vl.github.io/)) stanno diventando abbastanza buoni per questo . Il commercio-off è sempre lo stessoM SK3 modello più grande |= più intelligente ma più lento | . La scelta giusta dipende dal vostro budget di latenza e dalle esigenze di precisione |

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

Ogni livello aggiunge capacità al costo della dimensione e della latenza. Il pacchetto attualmente copre i livelli 1-3. Niveau 4 è dove arrivano gli LLM multimodali in |- e dove [***lucido.*RAG**](https://www.lucidrag.com) è il titolo.

---


## Ressource

**Questo pacchetto**:

- **[Mostlylucid.OcrNer su NuGet](https://www.nuget.org/packages/Mostlylucid.OcrNer)** - L'installere
- **[Il codice sorgente](https://github.com/scottgal/mostlylucidweb/tree/main/Mostlylucid.OcrNer)** - Browse the implementation

**Parte 1**:

- **[Extrazione semplice di OCR e NER](/blog/simple-ocr-ner-extraction)** - Il tutorial che spiega ogni pezzo

**Dipendenze**:

- **[Tesseract.NET](https://github.com/charlesw/tesseract)** - CM SK1 wrapper per Tesseract OCR
- **[BERT-base-NER ONNX](https://huggingface.co/protectai/bert-base-NER-onnx)** - Il modello NER
- **[Florence-2](https://www.nuget.org/packages/Florence2)** - Vision model NuGet package
- **[ImageSharp](https://sixlabors.com/products/imagesharp/)** - Cross-processo di immagini per la piattaforma
- **[OpenCvSharp4](https://github.com/shimat/opencvsharp)** - OpenCV wrapper per advanced preprocessing
- **[Microsoft.Recognizers.Texto](https://github.com/microsoft/Recognizers-Text)** - Regola-estrazione di entità basata
- **[Il tempo di esecuzione di ONNX](https://onnxruntime.ai/)** - Invenzione del modello multiplatforme

**Article connessi**:

- **[Il Pipeline Three-Tier OCR](/blog/constrained-fuzzy-image-ocr-pipeline)** - Quando avete bisogno di più di un semplice OCR
- **[RAG ridotto](/blog/reduced-rag-concept)** - Dove le entità estrattoe si inseriscono nel quadro generale
- **[*lucido.*RAG](https://www.lucidrag.com)** - Il tubo di produzione multi-phase -