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
Innan vi dyker in i
.onnx file, lokalt, med enbart din CPUTesseract ä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
AddOcrNer() och du "'" är klarflowchart 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 ♫
dotnet add package Mostlylucid.OcrNer
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
{
"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 |
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
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 |
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
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...
}
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
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 |
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
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 ä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
}
| 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/.
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
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
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
});
}
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)
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(); }
}
repo består av ett command-line-verktyg byggt med Spectre.Konsole. Det är designat som en framgångssaga
# 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
| 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.
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
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?
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
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
| 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) |
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
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,
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.
Paketet:
Del 1:
beroenden:
Related Articles:
© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.