Altbilgi içeriğine atla
VIDEOLAR

Azure Computer Vision OCR'dan

Bu kılavuz,Azure Computer VisionOCR'nin yerini almak için .NET geliştiricilerini, bulut altyapısı olmadan belgeleri yerel olarak işleyen on-premise bir OCR kütüphanesi olan IronOCR ile tanıştırır. NuGet paketini ve ad alanlarını değiştirmenin mekanik adımlarını, Azure async anket modelini eşzamanlı yerel çağrılara çevirme ve spesifik desenleri — bağımlılık injeksiyonu bağlama, Form Recognizer anket döngüleri, çok sayfalı TIFF işleme ve toplu geçirme kapasitesi — taşınma sırasında en fazla dikkat gerektiren konuları ele alır.

Azure Computer VisionOCR'den Neden Geçilmelidir

Geçiş kararı soyut değildir. Ekipler tipik olarak üretimdeAzure Computer Visionile bir veya daha fazla somut operasyonel problemlerle karşılaştıktan sonra karar verirler.

Endpoint ve API anahtarı yönetimi asla bitmez. Her dağıtım ortamı — geliştirme, aşama, üretim, felaket kurtarma — bir Azure Cognitive Services kaynağı, bir endpoint URL ve en az bir API anahtarı gerektirir. Anahtarlar döndürülmelidir. Kaynaklar bölgeleri değiştirdiklerinde endpoint değişir. Her ortamın, cognitiveservices.azure.com ulaşmak için dışa yönelik güvenlik duvarı kurallarına ihtiyacı vardır. Ekiple birlikte her ortam ve geliştiriciyle birlikte operasyonel yüzey alanı büyür. IronOCR, tüm bunları yalnızca uygulama başlangıcında ayarlanan tek bir dize lisans anahtarı ile değiştirir; döngü programı yoktur ve dışa yönelik ağ gereksinimi de yoktur.

Sayfa başına faturalama, çok sayfalı belgeleri cezalandırır.Azure Computer Visionher PDF sayfasını ayrı bir işlem olarak sayar. 20 sayfalık bir sözleşme 20 faturalandırılabilir çağrıdır. 1.000 işlem başına $1.00 üzerinden, ayda 4 sayfa ortalamasıyla 50.000 çok sayfalı belge işleyen bir ekip 200.000 işlem üretir — ücretsiz kademenin üstünde aylık $195, yıllık $2.340. Bu, dört aydan kısa sürede IronOCR Lite ($999) karşısında dengeli bir noktadır, sonrasında her ek sayfa ücretsizdir.

Async yayılım, tüm çağrı yığını boyunca yayılır.Azure Computer Visioneşzamanlı dönemez — bulut G/Ç ağ gecikmesine sahiptir. await gereksinimi AnalyzeAsync üstünde tüm çağrı yöntemlerini async olmaya zorlar ve bu modelin hizmet katmanından denetleyicilere, arka plan çalışanlarına ve uyum sağlamak için yeniden yapılandırılması gereken senkron kodlara yayılmasına neden olur. Form Recognizer'ın oylamaya dayalı işlemleri bunu bileşik hale getirir: WaitUntil.Completed iş parçacığını engeller ve gerçek non-blocking davranış, UpdateStatusAsync oylama döngülerini manuel olarak yönetmeyi gerektirir.

Belgeler her çağrıda ağı terk eder. HIPAA kapsamındaki sağlık bilgilerini işleyen, ITAR kontrolündeki savunma belgelerini, avukat-müvekkil gizli iletişimlerini veya veri ikametgahı kurallarına tabi herhangi bir belge kategorisini işleyen ekipler için, zorunlu bulut iletimi mimari bir uyumsuzluktur, bir telafisi değildir. Belge içeriğinin Microsoft veri merkezlerine gönderilmesini önleyen birAzure Computer Visionmodu yoktur.

Oran sınırlamaları throughput tavanları oluşturur. Azure Computer Vision'un S1 seviyesi 10 işlem/saniyelik bir sınır koyar. : bir saat içindeki 3.600 görüntü işleme kapasitesine sahip bir toplu işlem tam tavanı vurur. Bunu aşmak HTTP 429 yanıtları döndürür, her bir çağrı yolunda üssel geri çekilme ile yeniden deneme mantığı gerektirir. IronOCR'un throughput tavanı, barındırma donanımıdır — hizmet tarafından konulmuş bir sınır yoktur, bu yüzden tekrar deneme altyapısı gerekli değildir.

Görüntü OCR vePDF OCRiki ayrı hizmet gerektirir. Standart görüntü OCR, ImageAnalysisClient __Azure.AI.Vision.ImageAnalysis kullanır. Tam PDF işleme, DocumentAnalysisClient başka bir NuGet paketi, farklı bir Azure kaynağı, farklı bir uç nokta ve farklı bir sonuç şeması olan Azure.AI.FormRecognizer.DocumentAnalysis gerektirir. Hem görüntüleri hem de PDF'leri işleyen her uygulama bu iki katı yapılandırma yükünü taşır. IronOCR, her ikisini de IronTesseract.Read() ve tek bir OcrInput yükleyici ile ele alır.

Temel Sorun

// Azure: endpoint URL + API key + async + nested block traversal — before a single character
var client = new ImageAnalysisClient(new Uri(endpoint), new AzureKeyCredential(apiKey));
using var stream = File.OpenRead(imagePath);
var result = await client.AnalyzeAsync(BinaryData.FromStream(stream), VisualFeatures.Read);
var text = string.Join("\n", result.Value.Read.Blocks.SelectMany(b => b.Lines).Select(l => l.Text));

// IronOCR: no endpoint, no key rotation, no async, no traversal
var text = new IronTesseract().Read(imagePath).Text;
// Azure: endpoint URL + API key + async + nested block traversal — before a single character
var client = new ImageAnalysisClient(new Uri(endpoint), new AzureKeyCredential(apiKey));
using var stream = File.OpenRead(imagePath);
var result = await client.AnalyzeAsync(BinaryData.FromStream(stream), VisualFeatures.Read);
var text = string.Join("\n", result.Value.Read.Blocks.SelectMany(b => b.Lines).Select(l => l.Text));

// IronOCR: no endpoint, no key rotation, no async, no traversal
var text = new IronTesseract().Read(imagePath).Text;
Imports System
Imports System.IO
Imports Azure
Imports Azure.AI.Vision
Imports IronOcr

' Azure: endpoint URL + API key + async + nested block traversal — before a single character
Dim client As New ImageAnalysisClient(New Uri(endpoint), New AzureKeyCredential(apiKey))
Using stream As FileStream = File.OpenRead(imagePath)
    Dim result = Await client.AnalyzeAsync(BinaryData.FromStream(stream), VisualFeatures.Read)
    Dim text As String = String.Join(vbLf, result.Value.Read.Blocks.SelectMany(Function(b) b.Lines).Select(Function(l) l.Text))
End Using

' IronOCR: no endpoint, no key rotation, no async, no traversal
Dim text As String = New IronTesseract().Read(imagePath).Text
$vbLabelText   $csharpLabel

IronOCR vsAzure Computer VisionOCR: Özellik Karşılaştırması

Aşağıdaki tablo, bu geçişi değerlendiren ekipler için en alakalı yetenekleri kapsamaktadır.

Özellik Azure Computer Vision OCR IronOCR
İşleme yeri Microsoft Azure bulutu Yerel, yerinde
İnternet gerekli Evet, her istekte Hayır
Azure aboneliği gerektirir Evet Hayır
Fiyatlandırma modeli İşlem başına ($1.00/1.000 işlem) Süresiz lisans ($999 dan)
Çok sayfalı PDF'lerde sayfa başına faturalama Evet — her sayfa = 1 işlem Sayfa başına maliyet yok
Ücretsiz seviye 5.000 işlem/ay Deneme modu (filigranlı)
Image OCR API'si AnalyzeAsync (sadece async) Read() (senkron)
PDF OCR Ayrı Form Recognizer servisi Yerleşik, aynı Read() çağrısı
Şifre korumalı PDF Form Recognizer aracılığıyla input.LoadPdf(path, Password: "x")
Aranabilir PDF çıktısı Manuel yapı result.SaveAsSearchablePdf()
Çok sayfalı TIFF Desteklenmiyor input.LoadImageFrames()
Otomatik görüntü ön işleme Opak sunucu tarafı, yapılandırılamaz Yeniden hizalama, Gürültü Giderme, Kontrast, İkiliye Çevirme, Keskinleştirme, Ölçekleme
Derin gürültü temizleme Hayır input.DeepCleanBackgroundNoise()
OCR sırasında barkod okuma Ayrı Image Analysis özelliği ocr.Configuration.ReadBarCodes = true
Bölge bazlı OCR Doğrudan değil (yüklemeden önce manuel kırpma) CropRectangle OcrInput üzerinde
Oran sınırlamaları S1 seviyesinde 10 TPS Sadece donanım kısıtlı
Yeniden deneme mantığı gerekli Evet (HTTP 429, 5xx) Hayır
İzole dağıtım İmkansız Tam destekli
Desteklenen diller 164+ (sunucu tarafından yönetilen) 125+ (NuGet dil paketleri)
Çoklu dil aynı anda Evet Evet (OcrLanguage.French + OcrLanguage.German)
Kelime sınırlayıcı kutuları Çokgen (değişken köşe sayısı) Dikdörtgen (x, y, genişlik, yükseklik)
Güven puanlama Kelime başına float (0,0-1,0) Kelime başına ve genel (0-100 ölçek)
hOCR içeri aktarma Hayır result.SaveAsHocrFile()
Yapılandırılmış çıktı hiyerarşisi Bloklar / Satırlar / Kelimeler Sayfalar / Paragraflar / Satırlar / Kelimeler / Karakterler
.NET uyumluluğu .NET Standard 2.0+ .NET Framework 4.6.2+, .NET Core, .NET 5–9
Çapraz platform Windows, Linux, macOS (bulut üzerinden) Windows, Linux, macOS, Docker, ARM64
Ticari destek Azure destek planları IronOCR lisansına dahil destek

Hızlı Başlangıç:Azure Computer VisionOCR'den IronOCR'ye Geçiş

Adım 1: NuGet Paketini Değiştirin

Azure Computer Vision paketini kaldırın:

dotnet remove package Azure.AI.Vision.ImageAnalysis
dotnet remove package Azure.AI.Vision.ImageAnalysis
SHELL

Proje ayrıca PDF işleme için Form Recognizer kullanıyorsa, o paketi de kaldırın:

dotnet remove package Azure.AI.FormRecognizer
dotnet remove package Azure.AI.FormRecognizer
SHELL

NuGet kullanarak IronOCR'u yükleyin:

dotnet add package IronOcr

Adım 2: Ad Alanlarını Güncelleyin

// Before (Azure Computer Vision)
using Azure;
using Azure.AI.Vision.ImageAnalysis;
// For PDF processing:
// using Azure.AI.FormRecognizer.DocumentAnalysis;

// After (IronOCR)
using IronOcr;
// Before (Azure Computer Vision)
using Azure;
using Azure.AI.Vision.ImageAnalysis;
// For PDF processing:
// using Azure.AI.FormRecognizer.DocumentAnalysis;

// After (IronOCR)
using IronOcr;
Imports IronOcr
' Before (Azure Computer Vision)
' Imports Azure
' Imports Azure.AI.Vision.ImageAnalysis
' For PDF processing:
' Imports Azure.AI.FormRecognizer.DocumentAnalysis

' After (IronOCR)
$vbLabelText   $csharpLabel

Adım 3: Lisansa İzin Verin

OCR çağrısından önce uygulama başlatma sırasında lisans anahtarını bir kez ekleyin:

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
$vbLabelText   $csharpLabel

Üretimde anahtarı bir ortam değişkeni olarak saklayın:

IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE");
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE");
Imports System

IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE")
$vbLabelText   $csharpLabel

Kod Göç Örnekleri

Bağımlılık Enjeksiyonu ile Azure İstemci Yapılandırmasının Değiştirilmesi

Önerilen Azure SDK modelini izleyen ekipler, ImageAnalysisClient DI kabında IOptions<AzureComputerVisionOptions> veya doğrudan IConfiguration bağlayarak kaydeder. Bu yapılandırma, uç nokta URL'lerini ve API anahtarlarını appsettings.json alır ve her dağıtım ortamında dışa yönelik ağ yapılandırması gerektirir.

Azure Computer Vision Yöntemi:

// appsettings.json binds to this class
public class AzureComputerVisionOptions
{
    public string Endpoint { get; set; }   // "https://your-resource.cognitiveservices.azure.com/"
    public string ApiKey   { get; set; }   // rotated periodically
}

// Program.cs / Startup.cs
services.Configure<AzureComputerVisionOptions>(
    configuration.GetSection("AzureComputerVision"));

services.AddSingleton<ImageAnalysisClient>(sp =>
{
    var opts = sp.GetRequiredService<IOptions<AzureComputerVisionOptions>>().Value;
    return new ImageAnalysisClient(
        new Uri(opts.Endpoint),
        new AzureKeyCredential(opts.ApiKey));
});

services.AddScoped<IOcrService, AzureOcrService>();
// appsettings.json binds to this class
public class AzureComputerVisionOptions
{
    public string Endpoint { get; set; }   // "https://your-resource.cognitiveservices.azure.com/"
    public string ApiKey   { get; set; }   // rotated periodically
}

// Program.cs / Startup.cs
services.Configure<AzureComputerVisionOptions>(
    configuration.GetSection("AzureComputerVision"));

services.AddSingleton<ImageAnalysisClient>(sp =>
{
    var opts = sp.GetRequiredService<IOptions<AzureComputerVisionOptions>>().Value;
    return new ImageAnalysisClient(
        new Uri(opts.Endpoint),
        new AzureKeyCredential(opts.ApiKey));
});

services.AddScoped<IOcrService, AzureOcrService>();
' appsettings.json binds to this class
Public Class AzureComputerVisionOptions
    Public Property Endpoint As String   ' "https://your-resource.cognitiveservices.azure.com/"
    Public Property ApiKey As String     ' rotated periodically
End Class

' Program.vb / Startup.vb
services.Configure(Of AzureComputerVisionOptions)(
    configuration.GetSection("AzureComputerVision"))

services.AddSingleton(Of ImageAnalysisClient)(Function(sp)
    Dim opts = sp.GetRequiredService(Of IOptions(Of AzureComputerVisionOptions))().Value
    Return New ImageAnalysisClient(
        New Uri(opts.Endpoint),
        New AzureKeyCredential(opts.ApiKey))
End Function)

services.AddScoped(Of IOcrService, AzureOcrService)()
$vbLabelText   $csharpLabel
// AzureOcrService.cs
public class AzureOcrService : IOcrService
{
    private readonly ImageAnalysisClient _client;

    public AzureOcrService(ImageAnalysisClient client)
    {
        _client = client;
    }

    public async Task<string> ReadAsync(string imagePath)
    {
        using var stream = File.OpenRead(imagePath);
        var data = BinaryData.FromStream(stream);
        var result = await _client.AnalyzeAsync(data, VisualFeatures.Read);

        return string.Join("\n",
            result.Value.Read.Blocks
                .SelectMany(b => b.Lines)
                .Select(l => l.Text));
    }
}
// AzureOcrService.cs
public class AzureOcrService : IOcrService
{
    private readonly ImageAnalysisClient _client;

    public AzureOcrService(ImageAnalysisClient client)
    {
        _client = client;
    }

    public async Task<string> ReadAsync(string imagePath)
    {
        using var stream = File.OpenRead(imagePath);
        var data = BinaryData.FromStream(stream);
        var result = await _client.AnalyzeAsync(data, VisualFeatures.Read);

        return string.Join("\n",
            result.Value.Read.Blocks
                .SelectMany(b => b.Lines)
                .Select(l => l.Text));
    }
}
Imports System.IO
Imports System.Threading.Tasks

Public Class AzureOcrService
    Implements IOcrService

    Private ReadOnly _client As ImageAnalysisClient

    Public Sub New(client As ImageAnalysisClient)
        _client = client
    End Sub

    Public Async Function ReadAsync(imagePath As String) As Task(Of String) Implements IOcrService.ReadAsync
        Using stream = File.OpenRead(imagePath)
            Dim data = BinaryData.FromStream(stream)
            Dim result = Await _client.AnalyzeAsync(data, VisualFeatures.Read)

            Return String.Join(vbLf, result.Value.Read.Blocks _
                .SelectMany(Function(b) b.Lines) _
                .Select(Function(l) l.Text))
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

IronOCR Yaklaşımı:

// Program.cs / Startup.cs
// One-time license key — no endpoint, no credential class, no options binding
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE");

// Register IronTesseract as a singleton — it is thread-safe
services.AddSingleton<IronTesseract>();
services.AddScoped<IOcrService, IronOcrService>();
// Program.cs / Startup.cs
// One-time license key — no endpoint, no credential class, no options binding
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE");

// Register IronTesseract as a singleton — it is thread-safe
services.AddSingleton<IronTesseract>();
services.AddScoped<IOcrService, IronOcrService>();
' Program.vb / Startup.vb
' One-time license key — no endpoint, no credential class, no options binding
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE")

' Register IronTesseract as a singleton — it is thread-safe
services.AddSingleton(Of IronTesseract)()
services.AddScoped(Of IOcrService, IronOcrService)()
$vbLabelText   $csharpLabel
// IronOcrService.cs
public class IronOcrService : IOcrService
{
    private readonly IronTesseract _ocr;

    public IronOcrService(IronTesseract ocr)
    {
        _ocr = ocr;
    }

    public string Read(string imagePath)
    {
        return _ocr.Read(imagePath).Text;
    }
}
// IronOcrService.cs
public class IronOcrService : IOcrService
{
    private readonly IronTesseract _ocr;

    public IronOcrService(IronTesseract ocr)
    {
        _ocr = ocr;
    }

    public string Read(string imagePath)
    {
        return _ocr.Read(imagePath).Text;
    }
}
' IronOcrService.vb
Public Class IronOcrService
    Implements IOcrService

    Private ReadOnly _ocr As IronTesseract

    Public Sub New(ocr As IronTesseract)
        _ocr = ocr
    End Sub

    Public Function Read(imagePath As String) As String Implements IOcrService.Read
        Return _ocr.Read(imagePath).Text
    End Function
End Class
$vbLabelText   $csharpLabel

DI yapılandırması, iki yapılandırma sınıfından (seçenekler + istemci fabrikası) tek bir AddSingleton<IronTesseract>() çağrısına düşer. appsettings.json Azure bölümü, anahtar kasası referansları ve cognitiveservices.azure.com için dışa yönelik güvenlik duvarı kuralları tamamen kaldırılır. IronTesseract kurulum kılavuzu, tekil örnek üzerindeki yapılandırma seçeneklerini kapsar.

Form Recognizer Anket Döngüsünün Ortadan Kaldırılması

Form Recognizer'ın AnalyzeDocumentAsync bir LongRunningOperation döndürür. WaitUntil.Completed bulut işi tamamlanana kadar çağrı iş parçacığını engeller — genellikle belge başına 2–10 saniye. Non-blocking davranış için, ekipler hiçbir OCR mantığı içermeyen 30–50 satırlık altyapı kodu ekleyerek gecikmeli bir UpdateStatusAsync oylama döngüsü yazar.

Azure Computer Vision Yöntemi:

// DocumentAnalysisClient — separate from ImageAnalysisClient, separate resource
public class FormRecognizerPdfService
{
    private readonly DocumentAnalysisClient _client;

    public FormRecognizerPdfService(string endpoint, string apiKey)
    {
        _client = new DocumentAnalysisClient(
            new Uri(endpoint),
            new AzureKeyCredential(apiKey));
    }

    // Blocking wait — thread is held for the duration of cloud processing
    public async Task<string> ExtractPdfTextBlocking(string pdfPath)
    {
        using var stream = File.OpenRead(pdfPath);

        var operation = await _client.AnalyzeDocumentAsync(
            WaitUntil.Completed,  // blocks until Azure finishes
            "prebuilt-read",
            stream);

        var docResult = operation.Value;
        var sb = new StringBuilder();
        foreach (var page in docResult.Pages)
        {
            foreach (var line in page.Lines)
            {
                sb.AppendLine(line.Content);  // .Content, not .Text
            }
        }
        return sb.ToString();
    }

    // True async — manual polling loop required
    public async Task<string> ExtractPdfTextNonBlocking(string pdfPath)
    {
        using var stream = File.OpenRead(pdfPath);

        var operation = await _client.AnalyzeDocumentAsync(
            WaitUntil.Started,  // returns immediately, not complete yet
            "prebuilt-read",
            stream);

        // Poll every 500ms until the operation finishes
        while (!operation.HasCompleted)
        {
            await Task.Delay(500);
            await operation.UpdateStatusAsync();
        }

        var docResult = operation.Value;
        var sb = new StringBuilder();
        foreach (var page in docResult.Pages)
        {
            foreach (var line in page.Lines)
            {
                sb.AppendLine(line.Content);
            }
        }
        return sb.ToString();
    }
}
// DocumentAnalysisClient — separate from ImageAnalysisClient, separate resource
public class FormRecognizerPdfService
{
    private readonly DocumentAnalysisClient _client;

    public FormRecognizerPdfService(string endpoint, string apiKey)
    {
        _client = new DocumentAnalysisClient(
            new Uri(endpoint),
            new AzureKeyCredential(apiKey));
    }

    // Blocking wait — thread is held for the duration of cloud processing
    public async Task<string> ExtractPdfTextBlocking(string pdfPath)
    {
        using var stream = File.OpenRead(pdfPath);

        var operation = await _client.AnalyzeDocumentAsync(
            WaitUntil.Completed,  // blocks until Azure finishes
            "prebuilt-read",
            stream);

        var docResult = operation.Value;
        var sb = new StringBuilder();
        foreach (var page in docResult.Pages)
        {
            foreach (var line in page.Lines)
            {
                sb.AppendLine(line.Content);  // .Content, not .Text
            }
        }
        return sb.ToString();
    }

    // True async — manual polling loop required
    public async Task<string> ExtractPdfTextNonBlocking(string pdfPath)
    {
        using var stream = File.OpenRead(pdfPath);

        var operation = await _client.AnalyzeDocumentAsync(
            WaitUntil.Started,  // returns immediately, not complete yet
            "prebuilt-read",
            stream);

        // Poll every 500ms until the operation finishes
        while (!operation.HasCompleted)
        {
            await Task.Delay(500);
            await operation.UpdateStatusAsync();
        }

        var docResult = operation.Value;
        var sb = new StringBuilder();
        foreach (var page in docResult.Pages)
        {
            foreach (var line in page.Lines)
            {
                sb.AppendLine(line.Content);
            }
        }
        return sb.ToString();
    }
}
Imports System
Imports System.IO
Imports System.Text
Imports System.Threading.Tasks
Imports Azure
Imports Azure.AI.FormRecognizer.DocumentAnalysis

' DocumentAnalysisClient — separate from ImageAnalysisClient, separate resource
Public Class FormRecognizerPdfService
    Private ReadOnly _client As DocumentAnalysisClient

    Public Sub New(endpoint As String, apiKey As String)
        _client = New DocumentAnalysisClient(
            New Uri(endpoint),
            New AzureKeyCredential(apiKey))
    End Sub

    ' Blocking wait — thread is held for the duration of cloud processing
    Public Async Function ExtractPdfTextBlocking(pdfPath As String) As Task(Of String)
        Using stream = File.OpenRead(pdfPath)
            Dim operation = Await _client.AnalyzeDocumentAsync(
                WaitUntil.Completed,  ' blocks until Azure finishes
                "prebuilt-read",
                stream)

            Dim docResult = operation.Value
            Dim sb = New StringBuilder()
            For Each page In docResult.Pages
                For Each line In page.Lines
                    sb.AppendLine(line.Content)  ' .Content, not .Text
                Next
            Next
            Return sb.ToString()
        End Using
    End Function

    ' True async — manual polling loop required
    Public Async Function ExtractPdfTextNonBlocking(pdfPath As String) As Task(Of String)
        Using stream = File.OpenRead(pdfPath)
            Dim operation = Await _client.AnalyzeDocumentAsync(
                WaitUntil.Started,  ' returns immediately, not complete yet
                "prebuilt-read",
                stream)

            ' Poll every 500ms until the operation finishes
            While Not operation.HasCompleted
                Await Task.Delay(500)
                Await operation.UpdateStatusAsync()
            End While

            Dim docResult = operation.Value
            Dim sb = New StringBuilder()
            For Each page In docResult.Pages
                For Each line In page.Lines
                    sb.AppendLine(line.Content)
                Next
            Next
            Return sb.ToString()
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

IronOCR Yaklaşımı:

// One class handles both images and PDFs — no second client or second resource
public class IronOcrDocumentService
{
    private readonly IronTesseract _ocr;

    public IronOcrDocumentService(IronTesseract ocr)
    {
        _ocr = ocr;
    }

    // Synchronous — returns immediately when local processing completes
    public string ExtractPdfText(string pdfPath)
    {
        using var input = new OcrInput();
        input.LoadPdf(pdfPath);
        return _ocr.Read(input).Text;
    }

    // Specific page range — no per-page billing penalty
    public string ExtractPageRange(string pdfPath, int startPage, int endPage)
    {
        using var input = new OcrInput();
        input.LoadPdfPages(pdfPath, startPage, endPage);
        return _ocr.Read(input).Text;
    }

    // If an async signature is required by an interface or controller
    public Task<string> ExtractPdfTextAsync(string pdfPath)
    {
        return Task.Run(() => ExtractPdfText(pdfPath));
    }
}
// One class handles both images and PDFs — no second client or second resource
public class IronOcrDocumentService
{
    private readonly IronTesseract _ocr;

    public IronOcrDocumentService(IronTesseract ocr)
    {
        _ocr = ocr;
    }

    // Synchronous — returns immediately when local processing completes
    public string ExtractPdfText(string pdfPath)
    {
        using var input = new OcrInput();
        input.LoadPdf(pdfPath);
        return _ocr.Read(input).Text;
    }

    // Specific page range — no per-page billing penalty
    public string ExtractPageRange(string pdfPath, int startPage, int endPage)
    {
        using var input = new OcrInput();
        input.LoadPdfPages(pdfPath, startPage, endPage);
        return _ocr.Read(input).Text;
    }

    // If an async signature is required by an interface or controller
    public Task<string> ExtractPdfTextAsync(string pdfPath)
    {
        return Task.Run(() => ExtractPdfText(pdfPath));
    }
}
Imports System.Threading.Tasks

' One class handles both images and PDFs — no second client or second resource
Public Class IronOcrDocumentService
    Private ReadOnly _ocr As IronTesseract

    Public Sub New(ocr As IronTesseract)
        _ocr = ocr
    End Sub

    ' Synchronous — returns immediately when local processing completes
    Public Function ExtractPdfText(pdfPath As String) As String
        Using input As New OcrInput()
            input.LoadPdf(pdfPath)
            Return _ocr.Read(input).Text
        End Using
    End Function

    ' Specific page range — no per-page billing penalty
    Public Function ExtractPageRange(pdfPath As String, startPage As Integer, endPage As Integer) As String
        Using input As New OcrInput()
            input.LoadPdfPages(pdfPath, startPage, endPage)
            Return _ocr.Read(input).Text
        End Using
    End Function

    ' If an async signature is required by an interface or controller
    Public Function ExtractPdfTextAsync(pdfPath As String) As Task(Of String)
        Return Task.Run(Function() ExtractPdfText(pdfPath))
    End Function
End Class
$vbLabelText   $csharpLabel

Anket döngüsü ve gecikme mantığı tamamen ortadan kaybolur. LoadPdfPages sayfa aralığı seçimini yönetir — sayfa başına ayrı çağrı yok, işlem sayma yok. PDF giriş kılavuzu tam detayda akış girişi, byte dizisi yükleme ve sayfa aralığı parametrelerini kapsar.

Azure Kelime Seviyesindeki SonuçlarıIronOCR Yapılandırılmış Çıktıya Eşleme

Azure Computer Vision, kelime sınırlayıcı kutularını değişken sayıda köşesi olan çokgenler olarak döndürür — tipik olarak dört, ancak garantili değildir. Sonuç hiyerarşisi Blocks → Lines → Words ve güven float 0.0–1.0 ölçeğinde. Kelime konumlarını okuyan kod, çokgen köşe dizisini yönetmeli ve herhangi bir eşik karşılaştırması için güven ölçeğini normalleştirmelidir.

Azure Computer Vision Yöntemi:

public async Task<List<WordResult>> ExtractWordPositionsAsync(string imagePath)
{
    using var stream = File.OpenRead(imagePath);
    var imageData = BinaryData.FromStream(stream);

    var response = await _client.AnalyzeAsync(imageData, VisualFeatures.Read);
    var words = new List<WordResult>();

    foreach (var block in response.Value.Read.Blocks)
    {
        foreach (var line in block.Lines)
        {
            foreach (var word in line.Words)
            {
                // BoundingPolygon is a list of ImagePoint — variable vertex count
                var polygon = word.BoundingPolygon;
                int minX = polygon.Min(p => p.X);
                int minY = polygon.Min(p => p.Y);
                int maxX = polygon.Max(p => p.X);
                int maxY = polygon.Max(p => p.Y);

                words.Add(new WordResult
                {
                    Text        = word.Text,
                    // Azure confidence: 0.0 to 1.0 — multiply by 100 for comparison
                    Confidence  = (double)word.Confidence * 100.0,
                    X           = minX,
                    Y           = minY,
                    Width       = maxX - minX,
                    Height      = maxY - minY
                });
            }
        }
    }
    return words;
}

public record WordResult(string Text, double Confidence, int X, int Y, int Width, int Height);
public async Task<List<WordResult>> ExtractWordPositionsAsync(string imagePath)
{
    using var stream = File.OpenRead(imagePath);
    var imageData = BinaryData.FromStream(stream);

    var response = await _client.AnalyzeAsync(imageData, VisualFeatures.Read);
    var words = new List<WordResult>();

    foreach (var block in response.Value.Read.Blocks)
    {
        foreach (var line in block.Lines)
        {
            foreach (var word in line.Words)
            {
                // BoundingPolygon is a list of ImagePoint — variable vertex count
                var polygon = word.BoundingPolygon;
                int minX = polygon.Min(p => p.X);
                int minY = polygon.Min(p => p.Y);
                int maxX = polygon.Max(p => p.X);
                int maxY = polygon.Max(p => p.Y);

                words.Add(new WordResult
                {
                    Text        = word.Text,
                    // Azure confidence: 0.0 to 1.0 — multiply by 100 for comparison
                    Confidence  = (double)word.Confidence * 100.0,
                    X           = minX,
                    Y           = minY,
                    Width       = maxX - minX,
                    Height      = maxY - minY
                });
            }
        }
    }
    return words;
}

public record WordResult(string Text, double Confidence, int X, int Y, int Width, int Height);
Imports System.IO
Imports System.Threading.Tasks
Imports System.Linq

Public Class ImageAnalyzer
    Private _client As SomeClientType ' Replace with the actual type of _client

    Public Async Function ExtractWordPositionsAsync(imagePath As String) As Task(Of List(Of WordResult))
        Using stream = File.OpenRead(imagePath)
            Dim imageData = BinaryData.FromStream(stream)

            Dim response = Await _client.AnalyzeAsync(imageData, VisualFeatures.Read)
            Dim words = New List(Of WordResult)()

            For Each block In response.Value.Read.Blocks
                For Each line In block.Lines
                    For Each word In line.Words
                        ' BoundingPolygon is a list of ImagePoint — variable vertex count
                        Dim polygon = word.BoundingPolygon
                        Dim minX = polygon.Min(Function(p) p.X)
                        Dim minY = polygon.Min(Function(p) p.Y)
                        Dim maxX = polygon.Max(Function(p) p.X)
                        Dim maxY = polygon.Max(Function(p) p.Y)

                        words.Add(New WordResult With {
                            .Text = word.Text,
                            ' Azure confidence: 0.0 to 1.0 — multiply by 100 for comparison
                            .Confidence = CDbl(word.Confidence) * 100.0,
                            .X = minX,
                            .Y = minY,
                            .Width = maxX - minX,
                            .Height = maxY - minY
                        })
                    Next
                Next
            Next
            Return words
        End Using
    End Function
End Class

Public Class WordResult
    Public Property Text As String
    Public Property Confidence As Double
    Public Property X As Integer
    Public Property Y As Integer
    Public Property Width As Integer
    Public Property Height As Integer
End Class
$vbLabelText   $csharpLabel

IronOCR Yaklaşımı:

public List<WordResult> ExtractWordPositions(string imagePath)
{
    var result = new IronTesseract().Read(imagePath);
    var words = new List<WordResult>();

    foreach (var page in result.Pages)
    {
        foreach (var line in page.Lines)
        {
            foreach (var word in line.Words)
            {
                // Rectangle-based bounding box — no polygon math required
                // Confidence is already 0–100, matching the converted Azure scale
                words.Add(new WordResult
                {
                    Text       = word.Text,
                    Confidence = word.Confidence,   // 0–100, no conversion needed
                    X          = word.X,
                    Y          = word.Y,
                    Width      = word.Width,
                    Height     = word.Height
                });
            }
        }
    }
    return words;
}

// Filter to only high-confidence words — common post-processing pattern
public IEnumerable<string> ExtractHighConfidenceWords(string imagePath, double threshold = 80.0)
{
    var result = new IronTesseract().Read(imagePath);
    return result.Words
        .Where(w => w.Confidence >= threshold)
        .Select(w => w.Text);
}

public record WordResult(string Text, double Confidence, int X, int Y, int Width, int Height);
public List<WordResult> ExtractWordPositions(string imagePath)
{
    var result = new IronTesseract().Read(imagePath);
    var words = new List<WordResult>();

    foreach (var page in result.Pages)
    {
        foreach (var line in page.Lines)
        {
            foreach (var word in line.Words)
            {
                // Rectangle-based bounding box — no polygon math required
                // Confidence is already 0–100, matching the converted Azure scale
                words.Add(new WordResult
                {
                    Text       = word.Text,
                    Confidence = word.Confidence,   // 0–100, no conversion needed
                    X          = word.X,
                    Y          = word.Y,
                    Width      = word.Width,
                    Height     = word.Height
                });
            }
        }
    }
    return words;
}

// Filter to only high-confidence words — common post-processing pattern
public IEnumerable<string> ExtractHighConfidenceWords(string imagePath, double threshold = 80.0)
{
    var result = new IronTesseract().Read(imagePath);
    return result.Words
        .Where(w => w.Confidence >= threshold)
        .Select(w => w.Text);
}

public record WordResult(string Text, double Confidence, int X, int Y, int Width, int Height);
Imports System.Collections.Generic
Imports System.Linq

Public Class WordExtractor

    Public Function ExtractWordPositions(imagePath As String) As List(Of WordResult)
        Dim result = New IronTesseract().Read(imagePath)
        Dim words = New List(Of WordResult)()

        For Each page In result.Pages
            For Each line In page.Lines
                For Each word In line.Words
                    ' Rectangle-based bounding box — no polygon math required
                    ' Confidence is already 0–100, matching the converted Azure scale
                    words.Add(New WordResult With {
                        .Text = word.Text,
                        .Confidence = word.Confidence,   ' 0–100, no conversion needed
                        .X = word.X,
                        .Y = word.Y,
                        .Width = word.Width,
                        .Height = word.Height
                    })
                Next
            Next
        Next

        Return words
    End Function

    ' Filter to only high-confidence words — common post-processing pattern
    Public Function ExtractHighConfidenceWords(imagePath As String, Optional threshold As Double = 80.0) As IEnumerable(Of String)
        Dim result = New IronTesseract().Read(imagePath)
        Return result.Words _
            .Where(Function(w) w.Confidence >= threshold) _
            .Select(Function(w) w.Text)
    End Function

End Class

Public Class WordResult
    Public Property Text As String
    Public Property Confidence As Double
    Public Property X As Integer
    Public Property Y As Integer
    Public Property Width As Integer
    Public Property Height As Integer
End Class
$vbLabelText   $csharpLabel

Çokgen-dikdörtgen dönüşüm ortadan kaybolur. Güven değerleri doğrudan eşleşir, mevcut her eşik mantığı, bu tek ayar ile çözülür. yapılandırılmış veri çıktısı kılavuzu tam hiyerarşiyi ve koordinat özelliklerini belgeler. Özellikle güven puanlama modeli için güven puanları kılavuzunu inceleyin.

Bulut Yüklemesi Olmadan Çok Sayfalı TIFF İşleme

Azure Computer Vision'ın ImageAnalysisClient tek görüntüleri kabul eder. Çok çerçeveli TIFF dosyaları — belge tarama iş akışlarında, faks arşivlerinde ve tıbbi görüntü işleme hatlarında yaygın olarak — ya yüklemeden önce TIFF'i tek tek görüntülere bölmeyi (çerçeve başına bir işlem) ya da ayrı yapılandırması ile birlikte Form Recognizer'a geçmeyi gerektirir. Hiçbir yol temiz değildir.

Azure Computer Vision Yöntemi:

// Azure does not support multi-frame TIFF directly via ImageAnalysisClient
// Must split frames manually and upload each as a separate transaction
public async Task<string> ExtractMultiFrameTiffAsync(string tiffPath)
{
    // Load TIFF using System.Drawing or a third-party library
    using var bitmap = new System.Drawing.Bitmap(tiffPath);
    int frameCount = bitmap.GetFrameCount(
        System.Drawing.Imaging.FrameDimension.Page);

    var allText = new StringBuilder();

    for (int i = 0; i < frameCount; i++)
    {
        // Select frame, save to temporary PNG, upload to Azure
        bitmap.SelectActiveFrame(System.Drawing.Imaging.FrameDimension.Page, i);

        using var ms = new MemoryStream();
        bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
        ms.Position = 0;

        // Each frame = 1 Azure transaction = $0.001
        var imageData = BinaryData.FromStream(ms);
        var result = await _client.AnalyzeAsync(imageData, VisualFeatures.Read);

        foreach (var block in result.Value.Read.Blocks)
            foreach (var line in block.Lines)
                allText.AppendLine(line.Text);
    }

    return allText.ToString();
}
// Azure does not support multi-frame TIFF directly via ImageAnalysisClient
// Must split frames manually and upload each as a separate transaction
public async Task<string> ExtractMultiFrameTiffAsync(string tiffPath)
{
    // Load TIFF using System.Drawing or a third-party library
    using var bitmap = new System.Drawing.Bitmap(tiffPath);
    int frameCount = bitmap.GetFrameCount(
        System.Drawing.Imaging.FrameDimension.Page);

    var allText = new StringBuilder();

    for (int i = 0; i < frameCount; i++)
    {
        // Select frame, save to temporary PNG, upload to Azure
        bitmap.SelectActiveFrame(System.Drawing.Imaging.FrameDimension.Page, i);

        using var ms = new MemoryStream();
        bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
        ms.Position = 0;

        // Each frame = 1 Azure transaction = $0.001
        var imageData = BinaryData.FromStream(ms);
        var result = await _client.AnalyzeAsync(imageData, VisualFeatures.Read);

        foreach (var block in result.Value.Read.Blocks)
            foreach (var line in block.Lines)
                allText.AppendLine(line.Text);
    }

    return allText.ToString();
}
Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.IO
Imports System.Text
Imports System.Threading.Tasks

Public Class TiffProcessor
    Private _client As ImageAnalysisClient

    Public Async Function ExtractMultiFrameTiffAsync(tiffPath As String) As Task(Of String)
        ' Load TIFF using System.Drawing or a third-party library
        Using bitmap As New Bitmap(tiffPath)
            Dim frameCount As Integer = bitmap.GetFrameCount(FrameDimension.Page)

            Dim allText As New StringBuilder()

            For i As Integer = 0 To frameCount - 1
                ' Select frame, save to temporary PNG, upload to Azure
                bitmap.SelectActiveFrame(FrameDimension.Page, i)

                Using ms As New MemoryStream()
                    bitmap.Save(ms, Imaging.ImageFormat.Png)
                    ms.Position = 0

                    ' Each frame = 1 Azure transaction = $0.001
                    Dim imageData As BinaryData = BinaryData.FromStream(ms)
                    Dim result = Await _client.AnalyzeAsync(imageData, VisualFeatures.Read)

                    For Each block In result.Value.Read.Blocks
                        For Each line In block.Lines
                            allText.AppendLine(line.Text)
                        Next
                    Next
                End Using
            Next

            Return allText.ToString()
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

IronOCR Yaklaşımı:

//IronOCR handles multi-frame TIFF natively — single call, no frame splitting
public string ExtractMultiFrameTiff(string tiffPath)
{
    using var input = new OcrInput();
    input.LoadImageFrames(tiffPath);  // all frames loaded automatically
    var result = new IronTesseract().Read(input);
    return result.Text;
}

// Access per-page data for frame-level reporting
public void ExtractTiffWithPageStats(string tiffPath)
{
    using var input = new OcrInput();
    input.LoadImageFrames(tiffPath);

    var ocr = new IronTesseract();
    var result = ocr.Read(input);

    Console.WriteLine($"Total frames processed: {result.Pages.Length}");
    foreach (var page in result.Pages)
    {
        Console.WriteLine($"Frame {page.PageNumber}: " +
            $"{page.Words.Length} words, " +
            $"confidence {page.Confidence:F1}%");
    }
}

// Combine with preprocessing for scanned TIFF archives
public string ExtractLowQualityTiffArchive(string tiffPath)
{
    using var input = new OcrInput();
    input.LoadImageFrames(tiffPath);
    input.Deskew();
    input.DeNoise();
    input.Contrast();

    var result = new IronTesseract().Read(input);
    return result.Text;
}
//IronOCR handles multi-frame TIFF natively — single call, no frame splitting
public string ExtractMultiFrameTiff(string tiffPath)
{
    using var input = new OcrInput();
    input.LoadImageFrames(tiffPath);  // all frames loaded automatically
    var result = new IronTesseract().Read(input);
    return result.Text;
}

// Access per-page data for frame-level reporting
public void ExtractTiffWithPageStats(string tiffPath)
{
    using var input = new OcrInput();
    input.LoadImageFrames(tiffPath);

    var ocr = new IronTesseract();
    var result = ocr.Read(input);

    Console.WriteLine($"Total frames processed: {result.Pages.Length}");
    foreach (var page in result.Pages)
    {
        Console.WriteLine($"Frame {page.PageNumber}: " +
            $"{page.Words.Length} words, " +
            $"confidence {page.Confidence:F1}%");
    }
}

// Combine with preprocessing for scanned TIFF archives
public string ExtractLowQualityTiffArchive(string tiffPath)
{
    using var input = new OcrInput();
    input.LoadImageFrames(tiffPath);
    input.Deskew();
    input.DeNoise();
    input.Contrast();

    var result = new IronTesseract().Read(input);
    return result.Text;
}
Imports System

' IronOCR handles multi-frame TIFF natively — single call, no frame splitting
Public Function ExtractMultiFrameTiff(tiffPath As String) As String
    Using input As New OcrInput()
        input.LoadImageFrames(tiffPath)  ' all frames loaded automatically
        Dim result = New IronTesseract().Read(input)
        Return result.Text
    End Using
End Function

' Access per-page data for frame-level reporting
Public Sub ExtractTiffWithPageStats(tiffPath As String)
    Using input As New OcrInput()
        input.LoadImageFrames(tiffPath)

        Dim ocr As New IronTesseract()
        Dim result = ocr.Read(input)

        Console.WriteLine($"Total frames processed: {result.Pages.Length}")
        For Each page In result.Pages
            Console.WriteLine($"Frame {page.PageNumber}: " &
                              $"{page.Words.Length} words, " &
                              $"confidence {page.Confidence:F1}%")
        Next
    End Using
End Sub

' Combine with preprocessing for scanned TIFF archives
Public Function ExtractLowQualityTiffArchive(tiffPath As String) As String
    Using input As New OcrInput()
        input.LoadImageFrames(tiffPath)
        input.Deskew()
        input.DeNoise()
        input.Contrast()

        Dim result = New IronTesseract().Read(input)
        Return result.Text
    End Using
End Function
$vbLabelText   $csharpLabel

Çerçeve başına işlem maliyeti sıfıra düşer. System.Drawing çerçeve çıkarma döngüsü ve onun geçici PNG serileştirme adımı tamamen kaldırılır. Doküman kalitesinin değişken olduğu faks arşiv iş akışları için, TIFF ve GIF giriş kılavuzu çerçeve seçim seçeneklerini kapsar ve görüntü kalitesi düzeltme kılavuzu tam ön işleme filtre setini belgeler.

Oran Limiti Kuyruklaması Olmadan Paralel Toplu İşleme

Azure Computer Vision'un S1 seviyesi throughput'u saniyede 10 işlemle sınırlar. Bu oranı aşan toplu görevler HTTP 429 yanıtlarını alır. Üretim uygulamaları, sınır içinde kalmak için hız sınırlaması saran bir katman, bir semafor veya bir kuyruklama katmanı gerektirir.IronOCR API, tasarım gereğince iş parçacığı güvendedir — iş parçacığı başına bir IronTesseract örneği oluşturun ve Parallel.ForEach ile çalıştırın.

Azure Computer Vision Yöntemi:

// Must throttle to 10 TPS to avoid 429 errors on S1 tier
public class ThrottledAzureBatchProcessor
{
    private readonly ImageAnalysisClient _client;
    // Semaphore limits concurrent Azure calls to stay under 10 TPS
    private readonly SemaphoreSlim _throttle = new SemaphoreSlim(10, 10);

    public async Task<Dictionary<string, string>> ProcessBatchAsync(
        IEnumerable<string> imagePaths)
    {
        var results = new ConcurrentDictionary<string, string>();
        var tasks = imagePaths.Select(async path =>
        {
            await _throttle.WaitAsync();
            try
            {
                using var stream = File.OpenRead(path);
                var data = BinaryData.FromStream(stream);
                var response = await _client.AnalyzeAsync(data, VisualFeatures.Read);

                var text = string.Join("\n",
                    response.Value.Read.Blocks
                        .SelectMany(b => b.Lines)
                        .Select(l => l.Text));

                results[path] = text;

                // Respect 1-second window for the 10 TPS ceiling
                await Task.Delay(100);
            }
            catch (RequestFailedException ex) when (ex.Status == 429)
            {
                // Rate limited despite throttling — back off and retry
                await Task.Delay(2000);
                // Re-queue or log failure — simplified here
                results[path] = string.Empty;
            }
            finally
            {
                _throttle.Release();
            }
        });

        await Task.WhenAll(tasks);
        return new Dictionary<string, string>(results);
    }
}
// Must throttle to 10 TPS to avoid 429 errors on S1 tier
public class ThrottledAzureBatchProcessor
{
    private readonly ImageAnalysisClient _client;
    // Semaphore limits concurrent Azure calls to stay under 10 TPS
    private readonly SemaphoreSlim _throttle = new SemaphoreSlim(10, 10);

    public async Task<Dictionary<string, string>> ProcessBatchAsync(
        IEnumerable<string> imagePaths)
    {
        var results = new ConcurrentDictionary<string, string>();
        var tasks = imagePaths.Select(async path =>
        {
            await _throttle.WaitAsync();
            try
            {
                using var stream = File.OpenRead(path);
                var data = BinaryData.FromStream(stream);
                var response = await _client.AnalyzeAsync(data, VisualFeatures.Read);

                var text = string.Join("\n",
                    response.Value.Read.Blocks
                        .SelectMany(b => b.Lines)
                        .Select(l => l.Text));

                results[path] = text;

                // Respect 1-second window for the 10 TPS ceiling
                await Task.Delay(100);
            }
            catch (RequestFailedException ex) when (ex.Status == 429)
            {
                // Rate limited despite throttling — back off and retry
                await Task.Delay(2000);
                // Re-queue or log failure — simplified here
                results[path] = string.Empty;
            }
            finally
            {
                _throttle.Release();
            }
        });

        await Task.WhenAll(tasks);
        return new Dictionary<string, string>(results);
    }
}
Imports System.Collections.Concurrent
Imports System.IO
Imports System.Threading
Imports System.Threading.Tasks

' Must throttle to 10 TPS to avoid 429 errors on S1 tier
Public Class ThrottledAzureBatchProcessor
    Private ReadOnly _client As ImageAnalysisClient
    ' Semaphore limits concurrent Azure calls to stay under 10 TPS
    Private ReadOnly _throttle As New SemaphoreSlim(10, 10)

    Public Async Function ProcessBatchAsync(imagePaths As IEnumerable(Of String)) As Task(Of Dictionary(Of String, String))
        Dim results As New ConcurrentDictionary(Of String, String)()
        Dim tasks = imagePaths.Select(Async Function(path)
                                          Await _throttle.WaitAsync()
                                          Try
                                              Using stream = File.OpenRead(path)
                                                  Dim data = BinaryData.FromStream(stream)
                                                  Dim response = Await _client.AnalyzeAsync(data, VisualFeatures.Read)

                                                  Dim text = String.Join(vbLf,
                                                                         response.Value.Read.Blocks _
                                                                         .SelectMany(Function(b) b.Lines) _
                                                                         .Select(Function(l) l.Text))

                                                  results(path) = text

                                                  ' Respect 1-second window for the 10 TPS ceiling
                                                  Await Task.Delay(100)
                                              End Using
                                          Catch ex As RequestFailedException When ex.Status = 429
                                              ' Rate limited despite throttling — back off and retry
                                              Await Task.Delay(2000)
                                              ' Re-queue or log failure — simplified here
                                              results(path) = String.Empty
                                          Finally
                                              _throttle.Release()
                                          End Try
                                      End Function)

        Await Task.WhenAll(tasks)
        Return New Dictionary(Of String, String)(results)
    End Function
End Class
$vbLabelText   $csharpLabel

IronOCR Yaklaşımı:

//Hayırrate limiting needed — throughput is hardware-bound
public Dictionary<string, string> ProcessBatch(IEnumerable<string> imagePaths)
{
    var results = new ConcurrentDictionary<string, string>();

    Parallel.ForEach(imagePaths, imagePath =>
    {
        // Each thread gets its own IronTesseract instance — fully thread-safe
        var ocr = new IronTesseract();
        var result = ocr.Read(imagePath);
        results[imagePath] = result.Text;
    });

    return new Dictionary<string, string>(results);
}

// With controlled parallelism for memory-constrained environments
public Dictionary<string, string> ProcessBatchControlled(
    IEnumerable<string> imagePaths, int maxDegreeOfParallelism = 4)
{
    var results = new ConcurrentDictionary<string, string>();
    var options = new ParallelOptions { MaxDegreeOfParallelism = maxDegreeOfParallelism };

    Parallel.ForEach(imagePaths, options, imagePath =>
    {
        var ocr = new IronTesseract();
        var result = ocr.Read(imagePath);
        results[imagePath] = result.Text;
    });

    return new Dictionary<string, string>(results);
}
//Hayırrate limiting needed — throughput is hardware-bound
public Dictionary<string, string> ProcessBatch(IEnumerable<string> imagePaths)
{
    var results = new ConcurrentDictionary<string, string>();

    Parallel.ForEach(imagePaths, imagePath =>
    {
        // Each thread gets its own IronTesseract instance — fully thread-safe
        var ocr = new IronTesseract();
        var result = ocr.Read(imagePath);
        results[imagePath] = result.Text;
    });

    return new Dictionary<string, string>(results);
}

// With controlled parallelism for memory-constrained environments
public Dictionary<string, string> ProcessBatchControlled(
    IEnumerable<string> imagePaths, int maxDegreeOfParallelism = 4)
{
    var results = new ConcurrentDictionary<string, string>();
    var options = new ParallelOptions { MaxDegreeOfParallelism = maxDegreeOfParallelism };

    Parallel.ForEach(imagePaths, options, imagePath =>
    {
        var ocr = new IronTesseract();
        var result = ocr.Read(imagePath);
        results[imagePath] = result.Text;
    });

    return new Dictionary<string, string>(results);
}
Imports System.Collections.Concurrent
Imports System.Collections.Generic
Imports System.Threading.Tasks

Public Class BatchProcessor
    ' Hayırrate limiting needed — throughput is hardware-bound
    Public Function ProcessBatch(imagePaths As IEnumerable(Of String)) As Dictionary(Of String, String)
        Dim results = New ConcurrentDictionary(Of String, String)()

        Parallel.ForEach(imagePaths, Sub(imagePath)
                                         ' Each thread gets its own IronTesseract instance — fully thread-safe
                                         Dim ocr = New IronTesseract()
                                         Dim result = ocr.Read(imagePath)
                                         results(imagePath) = result.Text
                                     End Sub)

        Return New Dictionary(Of String, String)(results)
    End Function

    ' With controlled parallelism for memory-constrained environments
    Public Function ProcessBatchControlled(imagePaths As IEnumerable(Of String), Optional maxDegreeOfParallelism As Integer = 4) As Dictionary(Of String, String)
        Dim results = New ConcurrentDictionary(Of String, String)()
        Dim options = New ParallelOptions With {.MaxDegreeOfParallelism = maxDegreeOfParallelism}

        Parallel.ForEach(imagePaths, options, Sub(imagePath)
                                                  Dim ocr = New IronTesseract()
                                                  Dim result = ocr.Read(imagePath)
                                                  results(imagePath) = result.Text
                                              End Sub)

        Return New Dictionary(Of String, String)(results)
    End Function
End Class
$vbLabelText   $csharpLabel

Semafor, 100ms gecikme ve HTTP 429 catch bloğu tümüyle kaldırılır. Paralellik sadece CPU çekirdekleri ve mevcut bellekle sınırlıdır, bir hizmet seviyesi ile değil. çoklu iş parçacığı örneği tam deseni zamanlama karşılaştırmaları ile gösterir ve hız optimizasyon rehberi toplu iş yükleri için motor yapılandırma ayarlarını kapsar.

Azure'un Reddettiği Düşük Kaliteli Tarama Ön İşlemesi

Azure Computer Vision sunucu tarafında görüntü geliştirme yapar, ancak opak ve yapılandırılamaz. Çok eğimli, çok gürültülü veya düşük kontrastlı belgeler, müdahale etme yolu olmadan düşük güven sonuçları veya boş metin döndürür. IronOCR, ön işleme hattını doğrudan OcrInput üzerinde açığa çıkarır.

Azure Computer Vision Yöntemi:

//Hayırclient-side preprocessing API — must preprocess externally before upload
public async Task<string> ExtractFromLowQualityScanAsync(string imagePath)
{
    // Option 1: Accept whatever Azure returns (may be empty or low-quality)
    using var stream = File.OpenRead(imagePath);
    var imageData = BinaryData.FromStream(stream);

    var result = await _client.AnalyzeAsync(imageData, VisualFeatures.Read);

    //Hayırway to know if the server applied enhancement
    //Hayırconfidence on the overall result — only per-word
    var text = string.Join("\n",
        result.Value.Read.Blocks
            .SelectMany(b => b.Lines)
            .Select(l => l.Text));

    if (string.IsNullOrWhiteSpace(text))
    {
        // Option 2: Apply external preprocessing using System.Drawing, SkiaSharp,
        // or ImageMagick, re-serialize to stream, re-upload — second billable transaction
        throw new Exception("Azure returned empty result; manual preprocessing needed");
    }

    return text;
}
//Hayırclient-side preprocessing API — must preprocess externally before upload
public async Task<string> ExtractFromLowQualityScanAsync(string imagePath)
{
    // Option 1: Accept whatever Azure returns (may be empty or low-quality)
    using var stream = File.OpenRead(imagePath);
    var imageData = BinaryData.FromStream(stream);

    var result = await _client.AnalyzeAsync(imageData, VisualFeatures.Read);

    //Hayırway to know if the server applied enhancement
    //Hayırconfidence on the overall result — only per-word
    var text = string.Join("\n",
        result.Value.Read.Blocks
            .SelectMany(b => b.Lines)
            .Select(l => l.Text));

    if (string.IsNullOrWhiteSpace(text))
    {
        // Option 2: Apply external preprocessing using System.Drawing, SkiaSharp,
        // or ImageMagick, re-serialize to stream, re-upload — second billable transaction
        throw new Exception("Azure returned empty result; manual preprocessing needed");
    }

    return text;
}
Imports System.IO
Imports System.Threading.Tasks

Public Class YourClassName
    Public Async Function ExtractFromLowQualityScanAsync(imagePath As String) As Task(Of String)
        ' Option 1: Accept whatever Azure returns (may be empty or low-quality)
        Using stream = File.OpenRead(imagePath)
            Dim imageData = BinaryData.FromStream(stream)

            Dim result = Await _client.AnalyzeAsync(imageData, VisualFeatures.Read)

            ' No way to know if the server applied enhancement
            ' No confidence on the overall result — only per-word
            Dim text = String.Join(vbCrLf,
                result.Value.Read.Blocks _
                    .SelectMany(Function(b) b.Lines) _
                    .Select(Function(l) l.Text))

            If String.IsNullOrWhiteSpace(text) Then
                ' Option 2: Apply external preprocessing using System.Drawing, SkiaSharp,
                ' or ImageMagick, re-serialize to stream, re-upload — second billable transaction
                Throw New Exception("Azure returned empty result; manual preprocessing needed")
            End If

            Return text
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

IronOCR Yaklaşımı:

// Preprocessing is part of the same call — no re-upload, no second transaction
public string ExtractFromLowQualityScan(string imagePath)
{
    using var input = new OcrInput();
    input.LoadImage(imagePath);

    // Correct common scanning defects before OCR
    input.Deskew();           // Fix rotated documents
    input.DeNoise();          // Remove scanner noise
    input.Contrast();         // Improve contrast for faded documents
    input.Binarize();         // Convert to black and white

    var ocr = new IronTesseract();
    var result = ocr.Read(input);

    Console.WriteLine($"Confidence after preprocessing: {result.Confidence:F1}%");
    return result.Text;
}

// For severely degraded documents
public string ExtractFromDegradedDocument(string imagePath)
{
    using var input = new OcrInput();
    input.LoadImage(imagePath);
    input.DeepCleanBackgroundNoise();  // Deep learning-based noise removal
    input.Deskew();
    input.Scale(150);                  // Upscale for better character resolution

    var result = new IronTesseract().Read(input);
    return result.Text;
}
// Preprocessing is part of the same call — no re-upload, no second transaction
public string ExtractFromLowQualityScan(string imagePath)
{
    using var input = new OcrInput();
    input.LoadImage(imagePath);

    // Correct common scanning defects before OCR
    input.Deskew();           // Fix rotated documents
    input.DeNoise();          // Remove scanner noise
    input.Contrast();         // Improve contrast for faded documents
    input.Binarize();         // Convert to black and white

    var ocr = new IronTesseract();
    var result = ocr.Read(input);

    Console.WriteLine($"Confidence after preprocessing: {result.Confidence:F1}%");
    return result.Text;
}

// For severely degraded documents
public string ExtractFromDegradedDocument(string imagePath)
{
    using var input = new OcrInput();
    input.LoadImage(imagePath);
    input.DeepCleanBackgroundNoise();  // Deep learning-based noise removal
    input.Deskew();
    input.Scale(150);                  // Upscale for better character resolution

    var result = new IronTesseract().Read(input);
    return result.Text;
}
Imports System

Public Class OcrProcessor
    ' Preprocessing is part of the same call — no re-upload, no second transaction
    Public Function ExtractFromLowQualityScan(imagePath As String) As String
        Using input As New OcrInput()
            input.LoadImage(imagePath)

            ' Correct common scanning defects before OCR
            input.Deskew()           ' Fix rotated documents
            input.DeNoise()          ' Remove scanner noise
            input.Contrast()         ' Improve contrast for faded documents
            input.Binarize()         ' Convert to black and white

            Dim ocr As New IronTesseract()
            Dim result = ocr.Read(input)

            Console.WriteLine($"Confidence after preprocessing: {result.Confidence:F1}%")
            Return result.Text
        End Using
    End Function

    ' For severely degraded documents
    Public Function ExtractFromDegradedDocument(imagePath As String) As String
        Using input As New OcrInput()
            input.LoadImage(imagePath)
            input.DeepCleanBackgroundNoise()  ' Deep learning-based noise removal
            input.Deskew()
            input.Scale(150)                  ' Upscale for better character resolution

            Dim result = New IronTesseract().Read(input)
            Return result.Text
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

Dış ön işleme bağımlılığı - System.Drawing, SkiaSharp veya ImageMagick - kaldırılır. Yeniden yükleme ve ikinci işlem maliyeti ortadan kaybolur. Ön işleme hattı, OcrInput yaşam döngüsünün bir parçasıdır, bu nedenle görüntü OCR motoruna ulaşmadan önce uygulanır. görüntü filtreleri eğitimi her filtreyi öncesi/sonrası doğruluk karşılaştırmaları ile ele alır.

Azure Computer Vision OCRAPI'den IronOCR Eşleme Referansı

Azure Computer Vision IronOCR Karşılığı
ImageAnalysisClient IronTesseract
new AzureKeyCredential(apiKey) IronOcr.License.LicenseKey = key
new Uri(endpoint) Gerekli değil
client.AnalyzeAsync(data, VisualFeatures.Read) ocr.Read(imagePath)
BinaryData.FromStream(stream) input.LoadImage(stream)
BinaryData.FromBytes(bytes) input.LoadImage(bytes)
result.Value.Read.Blocks result.Pages[i].Paragraphs
block.Lines result.Pages[i].Lines
line.Text line.Text
line.Words line.Words
word.Text word.Text
word.Confidence (0.0–1.0 float) word.Confidence (0–100 double)
word.BoundingPolygon word.X, word.Y, word.Width, word.Height
DocumentAnalysisClient IronTesseract + OcrInput
AnalyzeDocumentAsync(WaitUntil.Completed, "prebuilt-read", stream) ocr.Read(input) input.LoadPdf(path) ile
operation.Value.Pages result.Pages
page.Lines[i].Content result.Lines[i].Text
UpdateStatusAsync() oylama döngüsü Gerekli değil — eşzamanlı sonuç
RequestFailedException (durum 429) Geçerli değil — hız sınırları yok
RequestFailedException (durum 5xx) Geçerli değil — hizmet hataları yok
VisualFeatures.Read enum bayrak Örtük — Read() her zaman metin çıkartır
Form Recognizer prebuilt-read modeli Dahili OCR motoru (model seçimi yok)
Azure uç nokta URL'si appsettings.json içinde Gerekli değil
API anahtarı rotasyon prosedürleri Gerekli değil

Yaygın Göç Sorunları ve Çözümleri

Sorun 1: Değiştirilemeyen Async Arabirim Sözleşmeleri

Azure Computer Vision: Hizmet arayüzleri genellikle Azure async gerektirdiği için Task<string> dönüş türlerini beyan eder. Çağrı yapan kod, kontrolörler ve arka plan çalışanları, tamamı async yöntemleri olarak yazılır. IronOCR'ye geçiş, OCR katmanında async gereksinimini ortadan kaldırır, ancak her bir arabirim imzasını değiştirmek büyük bir kod tabanında her zaman mümkün değildir.

Çözüm: Mevcut arayüze uyum sağlamak için senkron IronOCR çağrısını refaktör etmeksizin Task.Run sarın:

// Existing interface — do not change it
public interface IOcrService
{
    Task<string> ReadAsync(string imagePath);
}

// New IronOCR implementation — fulfills the contract
public class IronOcrService : IOcrService
{
    private readonly IronTesseract _ocr;

    public IronOcrService(IronTesseract ocr) => _ocr = ocr;

    public Task<string> ReadAsync(string imagePath)
    {
        // Task.Run offloads to thread pool — no await chain needed
        return Task.Run(() => _ocr.Read(imagePath).Text);
    }
}
// Existing interface — do not change it
public interface IOcrService
{
    Task<string> ReadAsync(string imagePath);
}

// New IronOCR implementation — fulfills the contract
public class IronOcrService : IOcrService
{
    private readonly IronTesseract _ocr;

    public IronOcrService(IronTesseract ocr) => _ocr = ocr;

    public Task<string> ReadAsync(string imagePath)
    {
        // Task.Run offloads to thread pool — no await chain needed
        return Task.Run(() => _ocr.Read(imagePath).Text);
    }
}
Imports System.Threading.Tasks

' Existing interface — do not change it
Public Interface IOcrService
    Function ReadAsync(imagePath As String) As Task(Of String)
End Interface

' New IronOCR implementation — fulfills the contract
Public Class IronOcrService
    Implements IOcrService

    Private ReadOnly _ocr As IronTesseract

    Public Sub New(ocr As IronTesseract)
        _ocr = ocr
    End Sub

    Public Function ReadAsync(imagePath As String) As Task(Of String) Implements IOcrService.ReadAsync
        ' Task.Run offloads to thread pool — no await chain needed
        Return Task.Run(Function() _ocr.Read(imagePath).Text)
    End Function
End Class
$vbLabelText   $csharpLabel

Bu geçerli bir ara adımdır. Tam async entegrasyonunun tercih edildiği senaryolar için IronOCR'un yerleşik async desteğini async OCR kılavuzu kapsar.

Sorun 2: Yanlış Sonuçlar Üreten Güven Eşik Mantığı

Azure Computer Vision: Azure, kelime güvenini 0.0 ile 1.0 arasında bir float döndürür. Mevcut filtreleme kodu word.Confidence > 0.85f gibi eşikleri kullanır. Geçişten sonra, bu karşılaştırmalar her zaman yanlış değerlendirir çünkü IronOCR güven 0–100, 0–1 arasında değil.

Çözüm: Ortam filtresi mantığı güncellenirken mevcut Azure eşiklerini 100 ile çarpın:

// Before: Azure threshold (0.0 - 1.0 scale)
var highConfidenceWords = azureWords
    .Where(w => w.Confidence > 0.85f)
    .Select(w => w.Text);

// After:IronOCR threshold (0 - 100 scale)
var result = new IronTesseract().Read(imagePath);
var highConfidenceWords = result.Words
    .Where(w => w.Confidence > 85.0)
    .Select(w => w.Text);

// Overall document confidence — also on 0-100 scale
if (result.Confidence < 70.0)
{
    // Document may need preprocessing or manual review
}
// Before: Azure threshold (0.0 - 1.0 scale)
var highConfidenceWords = azureWords
    .Where(w => w.Confidence > 0.85f)
    .Select(w => w.Text);

// After:IronOCR threshold (0 - 100 scale)
var result = new IronTesseract().Read(imagePath);
var highConfidenceWords = result.Words
    .Where(w => w.Confidence > 85.0)
    .Select(w => w.Text);

// Overall document confidence — also on 0-100 scale
if (result.Confidence < 70.0)
{
    // Document may need preprocessing or manual review
}
Imports System.Linq

' Before: Azure threshold (0.0 - 1.0 scale)
Dim highConfidenceWords = azureWords _
    .Where(Function(w) w.Confidence > 0.85F) _
    .Select(Function(w) w.Text)

' After: IronOCR threshold (0 - 100 scale)
Dim result = New IronTesseract().Read(imagePath)
Dim highConfidenceWords = result.Words _
    .Where(Function(w) w.Confidence > 85.0) _
    .Select(Function(w) w.Text)

' Overall document confidence — also on 0-100 scale
If result.Confidence < 70.0 Then
    ' Document may need preprocessing or manual review
End If
$vbLabelText   $csharpLabel

Sorun 3: Form Recognizer'ın Önceden Yapılandırılmış Model Alanı Çıkarmasının IronOCR Eşdeğeri Yoktur

Azure Computer Vision: Form Recognizer'ın önceden oluşturulmuş fatura ve makbuz modelleri, sayfa üzerinde bu alanların nerede göründüğünü belirtmeden, adlandırılmış alanları otomatik olarak çıkarır — InvoiceTotal, VendorName, InvoiceDate. Çıkarma mantığı Azure modeline gömülüdür.

Çözüm: Model tabanlı alan çıkarımını, CropRectangle kullanarak bölge tabanlı OCR ile değiştirin. Bu, belge düzenini bilmeyi gerektirir, ancak çoğu gerçek dünya dağıtımları zaten sabit şablonlara sahiptir:

var ocr = new IronTesseract();

// Define extraction zones for a known invoice template
var headerZone    = new CropRectangle(50,  40,  400, 60);
var totalZone     = new CropRectangle(350, 600, 250, 50);
var dateZone      = new CropRectangle(400, 100, 200, 40);

string header, total, date;

using (var input = new OcrInput())
{
    input.LoadImage("invoice.jpg", headerZone);
    header = ocr.Read(input).Text.Trim();
}

using (var input = new OcrInput())
{
    input.LoadImage("invoice.jpg", totalZone);
    total = ocr.Read(input).Text.Trim();
}

using (var input = new OcrInput())
{
    input.LoadImage("invoice.jpg", dateZone);
    date = ocr.Read(input).Text.Trim();
}
var ocr = new IronTesseract();

// Define extraction zones for a known invoice template
var headerZone    = new CropRectangle(50,  40,  400, 60);
var totalZone     = new CropRectangle(350, 600, 250, 50);
var dateZone      = new CropRectangle(400, 100, 200, 40);

string header, total, date;

using (var input = new OcrInput())
{
    input.LoadImage("invoice.jpg", headerZone);
    header = ocr.Read(input).Text.Trim();
}

using (var input = new OcrInput())
{
    input.LoadImage("invoice.jpg", totalZone);
    total = ocr.Read(input).Text.Trim();
}

using (var input = new OcrInput())
{
    input.LoadImage("invoice.jpg", dateZone);
    date = ocr.Read(input).Text.Trim();
}
Imports IronOcr

Dim ocr As New IronTesseract()

' Define extraction zones for a known invoice template
Dim headerZone As New CropRectangle(50, 40, 400, 60)
Dim totalZone As New CropRectangle(350, 600, 250, 50)
Dim dateZone As New CropRectangle(400, 100, 200, 40)

Dim header As String
Dim total As String
Dim date As String

Using input As New OcrInput()
    input.LoadImage("invoice.jpg", headerZone)
    header = ocr.Read(input).Text.Trim()
End Using

Using input As New OcrInput()
    input.LoadImage("invoice.jpg", totalZone)
    total = ocr.Read(input).Text.Trim()
End Using

Using input As New OcrInput()
    input.LoadImage("invoice.jpg", dateZone)
    date = ocr.Read(input).Text.Trim()
End Using
$vbLabelText   $csharpLabel

bölge tabanlı OCR kılavuzu koordinat sistemi detayları ve çok bölgeli toplu işlemeyi kapsar.

Problem 4: Eksik hOCR ve Yapılandırılmış Dışa Aktarım

Azure Computer Vision: Azure, hOCR çıktısı sağlamaz. Aşağı kesme belge analiz araçları için standartlaştırılmış düzen verilerine ihtiyaç duyan ekipler, bağlama kutularını Azure yanıtından manuel olarak çıkarır ve kendi çıktı formatlarını oluştururlar.

Çözüm: IronOCR, tek bir çağrıda standartları uyumlu hOCR üretir:

var result = new IronTesseract().Read("document.jpg");

// Write hOCR file — recognized by most document analysis tools
result.SaveAsHocrFile("document.hocr");

// Searchable PDF — alternative for archive and search indexing workflows
result.SaveAsSearchablePdf("document-searchable.pdf");
var result = new IronTesseract().Read("document.jpg");

// Write hOCR file — recognized by most document analysis tools
result.SaveAsHocrFile("document.hocr");

// Searchable PDF — alternative for archive and search indexing workflows
result.SaveAsSearchablePdf("document-searchable.pdf");
Dim result = (New IronTesseract()).Read("document.jpg")

' Write hOCR file — recognized by most document analysis tools
result.SaveAsHocrFile("document.hocr")

' Searchable PDF — alternative for archive and search indexing workflows
result.SaveAsSearchablePdf("document-searchable.pdf")
$vbLabelText   $csharpLabel

Probleme 5: Diğer Azure Paketleri ile Azure SDK Sürüm Çatışmaları

Azure Computer Vision: Birden fazla Azure SDK paketi (Azure.Storage.Blobs, Azure.Identity, Azure.KeyVault.Secrets) kullanan projeler, Azure.Core transitif bağımlılıklar arasında sürüm çakışmaları ile karşılaşabilir. Azure SDK'nın monorepo sürümleme politikası yardımcı olur ancak tüm çakışmaları ortadan kaldıramaz, özellikle GA ve önizleme SDK sürümleri karıştırıldığında.

Çözüm: Azure.AI.Vision.ImageAnalysis ve Azure.AI.FormRecognizer kaldırılması, bu SDK paketlerini bağımlılık ağacından çıkarır. Proje Azure'u sadece OCR için kullanıyorsa, tüm Azure.* bağımlılık seti kaldırılır. Diğer Azure hizmetleri kalırsa, azaltılmış paket sayısı çatışma alanını azaltır:

# Remove only the OCR-related Azure packages
dotnet remove package Azure.AI.Vision.ImageAnalysis
dotnet remove package Azure.AI.FormRecognizer

# Verify remaining Azure packages have no new conflicts
dotnet restore
dotnet build
# Remove only the OCR-related Azure packages
dotnet remove package Azure.AI.Vision.ImageAnalysis
dotnet remove package Azure.AI.FormRecognizer

# Verify remaining Azure packages have no new conflicts
dotnet restore
dotnet build
SHELL

Problem 6: Taratılmış Belge Kalitesi, Azure Kabul Eşiğinin Altında

Azure Computer Vision: Çok düşük çözünürlüklü görüntüler (~150 DPI'nın altında) veya ciddi şekilde eğilmiş taramalar, Azure'un sunucu tarafı hattından minimum veya boş metin döndürür ve hangi iyileştirmenin denendiğine dair bir geri bildirim sağlamaz. Çağrıcı, dış ön işlem olmadan sonucu iyileştirmenin bir yoluna sahip değil.

Çözüm: IronOCR'un ön işleme hattını kullanarak görüntüyü OCR öncesinde hazırlayın:

using var input = new OcrInput();
input.LoadImage("low-quality-scan.jpg");
input.Deskew();
input.DeNoise();
input.Scale(200);       // Upscale to improve character resolution
input.Contrast();
input.Sharpen();

var result = new IronTesseract().Read(input);
Console.WriteLine($"Extraction confidence: {result.Confidence:F1}%");
using var input = new OcrInput();
input.LoadImage("low-quality-scan.jpg");
input.Deskew();
input.DeNoise();
input.Scale(200);       // Upscale to improve character resolution
input.Contrast();
input.Sharpen();

var result = new IronTesseract().Read(input);
Console.WriteLine($"Extraction confidence: {result.Confidence:F1}%");
Imports IronOcr

Using input As New OcrInput()
    input.LoadImage("low-quality-scan.jpg")
    input.Deskew()
    input.DeNoise()
    input.Scale(200) ' Upscale to improve character resolution
    input.Contrast()
    input.Sharpen()

    Dim result = New IronTesseract().Read(input)
    Console.WriteLine($"Extraction confidence: {result.Confidence:F1}%")
End Using
$vbLabelText   $csharpLabel

görüntü yönü düzeltme kılavuzu, özellikle deskew ve döndürme algılamasını kapsar.

Azure Computer Vision OCRGeçiş Kontrol Listesi

Öncesi-Geçiş

Kod tabanında tümAzure Computer Visionve Form Recognizer kullanım yerlerini bulun:

# Find all Azure OCR-related using statements
grep -r "Azure.AI.Vision.ImageAnalysis" --include="*.cs" .
grep -r "Azure.AI.FormRecognizer" --include="*.cs" .
grep -r "ImageAnalysisClient" --include="*.cs" .
grep -r "DocumentAnalysisClient" --include="*.cs" .
grep -r "AnalyzeAsync" --include="*.cs" .
grep -r "AnalyzeDocumentAsync" --include="*.cs" .
grep -r "VisualFeatures.Read" --include="*.cs" .
grep -r "WaitUntil.Completed" --include="*.cs" .
grep -r "UpdateStatusAsync" --include="*.cs" .
grep -r "AzureKeyCredential" --include="*.cs" .
# Find all Azure OCR-related using statements
grep -r "Azure.AI.Vision.ImageAnalysis" --include="*.cs" .
grep -r "Azure.AI.FormRecognizer" --include="*.cs" .
grep -r "ImageAnalysisClient" --include="*.cs" .
grep -r "DocumentAnalysisClient" --include="*.cs" .
grep -r "AnalyzeAsync" --include="*.cs" .
grep -r "AnalyzeDocumentAsync" --include="*.cs" .
grep -r "VisualFeatures.Read" --include="*.cs" .
grep -r "WaitUntil.Completed" --include="*.cs" .
grep -r "UpdateStatusAsync" --include="*.cs" .
grep -r "AzureKeyCredential" --include="*.cs" .
SHELL

Azure OCR uç noktalarını ve anahtarlarını içeren yapılandırma dosyalarını belirleyin:

grep -r "cognitiveservices.azure.com" --include="*.json" .
grep -r "AzureComputerVision\|FormRecognizer" --include="*.json" .
grep -r "ComputerVision\|FormRecognizer" --include="appsettings*.json" .
grep -r "cognitiveservices.azure.com" --include="*.json" .
grep -r "AzureComputerVision\|FormRecognizer" --include="*.json" .
grep -r "ComputerVision\|FormRecognizer" --include="appsettings*.json" .
SHELL

Kodlamaya başlanmadan önce envanter öğeleri:

  • Azure OCR hizmet desenleri uygulayan sınıf sayısı
  • OCR çağrılarından yayılan asenkron yöntem zincirlerinin sayısı
  • 0.0–1.0 Azure ölçeği kullanılarak herhangi bir kelime güvence eşiği belirleyin
  • Bölge tabanlı değişiklik gerektiren Form Recognizer önceden hazırlanmış model kullanımı (fatura, makbuz, kimlik)
  • Şu anda kare başına yükleme için bölünmüş çok kareli TIFF girişlerini tanımlayın
  • Artık gerekli olmayacak dışa giden Azure ağ kuralları için Docker ve CI/CD yapılandırmalarını kontrol edin

Kod Geçişi

  1. Azure.AI.Vision.ImageAnalysis NuGet paketini kullanan tüm projelerden kaldırın
  2. Azure.AI.FormRecognizer NuGet paketini kullanan tüm projelerden kaldırın
  3. Her etkilenen projede dotnet add package IronOcr çalıştırın
  4. Uygulama başlangıcında IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE") ekleyin
  5. using Azure; using Azure.AI.Vision.ImageAnalysis; with using IronOcr;
  6. DI'de bir singleton olarak IronTesseract kaydettirin (services.AddSingleton<IronTesseract>())
  7. AzureComputerVisionOptions ya da eşdeğer yapılandırma sınıflarını kaldırın; appsettings.json Azure OCR bölümlerini kaldırın
  8. Bütün hizmet sınıflarında ImageAnalysisClient yapıcı enjeksiyonu IronTesseract enjeksiyonu ile değiştirin
  9. AnalyzeAsync(BinaryData.FromStream(stream), VisualFeatures.Read) çağrılarını, uygun olduğu yerlerde ocr.Read(imagePath) veya ocr.Read(input) ile OcrInput ile değiştirin
  10. Tüm UpdateStatusAsync oylama döngülerini ve WaitUntil.Completed örüntülerini kaldırın; DocumentAnalysisClient, IronTesseract + OcrInput.LoadPdf() ile değiştirin
  11. Kelime güvence eşiği karşılaştırmalarını güncelleyin: Tüm Azure 0.0–1.0 değerlerini 100 ile çarpın
  12. Çokgen sınırlayıcı kutu erişimini (word.BoundingPolygon.Min/Max) doğrudan word.X, word.Y, word.Width, word.Height özellikleri ile değiştirin
  13. Çoklu çerçeveli TIFF'e çerçeve başına yükleme döngülerini input.LoadImageFrames(tiffPath) ile değiştirin
  14. Form Recognizer önceden oluşturulmuş model alan çıkarımını bilinen belge şablonları için CropRectangle tabanlı bölge OCR'ine dönüştürün
  15. HTTP 429 ve 5xx için RequestFailedException yakalama bloklarını kaldırın; hata işleme yalnızca dosya sistemi ve giriş doğrulama istisnalarına basitleştirilir

Geçiş Sonrası

  • Düz metin çıkarma çıktısının, 20+ dökümanın temsilci bir örneği için Azure sonuçlarına eşit veya daha iyi olduğunu doğrulayın
  • Çok sayfalı PDF işlemenin, izleme sırasında sayfa başına hiçbir ücretlendirme sayacı olmaksızın tüm sayfalar için metin ürettiğini teyit edin
  • Çok kareli TIFF işlemenin, kaynak kare sayısı ile aynı sayfa sayısını döndürdüğünü test edin
  • Kelime güvence değerlerinin 0-100 aralığında olduğunu ve eşik karşılaştırmalarının doğru çalıştığını doğrulayın
  • Kelime bağlantı kutusu koordinatlarının doğru bir şekilde kaynak görüntü koordinat sistemi ile hizalandığını doğrulayın
  • Toplu işleme yolunu çalıştırın ve hız sınırlama hatası veya semaphore çekişmesi olmadan tamamlandığını doğrulayın
  • Çıkış internet erişimi olmayan bir ortamda test edin, hiçbir Azure uç nokta çağrısı olmadığını doğrulayın
  • Docker ve konteyner yapılandırmalarının, cognitiveservices.azure.com için dışa yönelik güvenlik duvarı kuralları olmadan başarıyla başladığını doğrulayın
  • DI kabı yapısının başarıyla tamamlandığını ve IronTesseract singleton'ının düzgün bir şekilde çözüldüğünü kontrol edin
  • Tüm dağıtım ortamlarında IRONOCR_LICENSE ortam değişkeninin ayarlandığını ve OCR'nin lisanslı (su işaretsiz) çıktılar ürettiğini doğrulayın

IronOCR'a Geçişin Ana Faydaları

Maliyet tahmin edilebilir hale gelir. Azure Computer Vision'un işlem başına sayaç sürekli olarak çalışır. Yüksek belge hacmine sahip tek bir ay, bir IronOCR lisansının yıllık maliyetini aşabilir. Geçişten sonra, OCR bütçesi sabit bir kalem öğesi olur. İşleme hacmi, iş geliştirme, toplu yeniden işleme veya geçici artışlar nedeniyle büyüyebilir ve bu, daha büyük bir fatura üretmeden olabilir. IronOCR lisanslama sayfası $999 tek geliştirici lisansından, sınırsız geliştiriciler için $2.999'a kadar kademeli seçenekler sunar.

Uygulama yığını daha basit hale geliyor. Azure.AI.Vision.ImageAnalysis ve Azure.AI.FormRecognizer kaldırılması, iki NuGet paketini, iki Azure kaynak yapılandırmasını, iki set kimlik bilgisini ve tüm async oylama altyapısını ortadan kaldırır. Daha önce bulut I/O nedeniyle bir async Task<string> imzası gerektiren hizmet sınıfları, senkron yöntemler haline gelir. Ağ hatalarından, oran sınırlamalarından ve hizmet kullanılabilirliğinden dosya sistemi ve giriş doğrulamaya kadar hata işleme daralır. Bu kod tabanında çalışan her gelecekteki geliştirici daha az kodla karşılaşacaktır.

Doküman verileri organizasyonun kontrolünde kalır. Geçişten sonra, OCR işleme yerel bir işlem haline gelir. Belgeler kurumsal sınırları geçmez, Azure telemetrisinde görünmez ve Microsoft'un veri saklama veya işleme politikalarına tabi olmaz. HIPAA kapsama alanı olan kuruluşlar, ITAR yüklenicileri, GDPR ile düzenlenmiş kuruluşlar ve veri yerleşim gereksinimi olan herhangi bir ekip, bulut üçüncü taraf uyumluluk incelemesi yapmaksızın belgeleri işleyebilir. Linux dağıtım kılavuzu ve Docker dağıtım kılavuzu, IronOCR'nin sınırlı ortamlarda nasıl dağıtılacağını gösterir.

Toplu işlem kapasitesi donanıma göre ölçeklenir. Azure'un S1 katmanındaki 10 TPS tavanı, kuyruklama, kısıtlama veya katman yükseltmeleri gerektiren zor bir sınırdır. Geçişten sonra, eşzamanlı OCR işleri, hizmet tarafından dayatılan bir sınır olmadan mevcut CPU çekirdeklerini doyurur. Dört çekirdekli bir sunucu, aynı anda dört paralel IronTesseract örneği çalıştırabilir. çok iş parçacıklı örnek, deseni gösterir ve çekirdek sayısı ile kapasite artışını gösterir.

Ön işleme hataları kodda çözülebilir. Azure Computer Vision'ın sunucu tarafı görüntü iyileştirmesi kara kutudur. Tarama boş veya düşük güvenli geri dönerse, kabul etmek veya ek maliyetle yeniden yüklemeden önce harici olarak ön işleme yapmak dışında seçenek yoktur. IronOCR'un OcrInput boru hattı, dengeleme, gürültü azaltma, kontrast, ikilestirme, ölçek, keskinleştirme ve derin gürültü giderme işlemlerini birinci sınıf yöntemler olarak açığa çıkarır. Sorunlu tarama türleri ayarlanabilir parametreler haline gelir. ön işleme özellikleri sayfası, hangi filtrelerin hangi tarama hatalarını giderdiğine dair rehberle birlikte eksiksiz filtre setini listeler.

Lütfen dikkate alınAzure Computer Vision ve Tesseract, ilgili sahiplerinin tescilli markalarıdır. Bu site, Google veya Microsoft ile ilişkilendirilmemiş, onaylanmamış veya desteklenmemiştir. Tüm ürün adları, logolar ve markalar kendi sahiplerine aittir. Karşılaştırmalar, yalnızca bilgilendirme amaçlıdır ve yazı sırasında halka açık bilgilerle alakalı olarak yansıtılmaktadır.

Sıkça Sorulan Sorular

Neden Azure Computer Vision OCR'dan IronOCR'a geçmeliyim?

Yaygın geçiş nedenleri arasında COM ara bağlamının karmaşıklığını ortadan kaldırmak, dosya tabanlı lisans yönetimini değiştirmek, sayfa başına fatura düzenlemekten kaçınmak, Docker/kapsayıcı dağıtımını etkinleştirmek ve standart .NET araçlarıyla entegre olan bir NuGet doğal iş akışı benimsemek yer almaktadır.

Azure Computer Vision OCR'dan IronOCR'a geçişteki ana kod değişiklikleri nelerdir?

Azure Computer Vision başlatma dizilerini IronTesseract oluşturma ile değiştirin, COM yaşam döngüsü yönetimini (açık Oluştur/Yükle/Kapat desenleri) kaldırın ve sonuç özellik adlarını güncelleyin. Sonuç, önemli ölçüde daha az sablon satırıdır.

Geçişi başlatmak için IronOCR'u nasıl kurarım?

Paket Yöneticisi Konsolunda 'Install-Package IronOcr' veya CLI'da 'dotnet add package IronOcr' çalıştırın. Dil paketleri ayrı paketlerdir: Örneğin, Fransızca için 'dotnet add package IronOcr.Languages.French'.

IronOCR, Azure Computer Vision OCR'nin standart iş belgeleri için OCR doğruluğuna eşit midir?

IronOCR, faturalar, sözleşmeler, makbuzlar ve yazılı formlar dahil olmak üzere standart işletme içerikleri için yüksek doğruluğa ulaşır. Görüntü ön işleme filtreleri (dengelemeyi düzeltme, gürültü kaldırma, kontrast artırma) bozulmuş girdiler üzerindeki tanımayı daha da iyileştirir.

IronOCR, Azure Computer Vision OCR'nin ayrı olarak yüklediği dil verilerini nasıl ele alır?

IronOCR'daki dil verileri, NuGet paketleri olarak dağıtılır. 'dotnet add package IronOcr.Languages.German' komutuyla Almanca desteği yüklenir. Herhangi bir manuel dosya yerleştirme veya dizin yolu gerekmez.

Azure Computer Vision OCR'dan IronOCR'a geçiş, dağıtım altyapısında değişiklikler gerektirir mi?

IronOCR, Azure Computer Vision OCR'dan daha az altyapı değişikliği gerektirir. SDK ikili yolları, lisans dosyası yerleştirmeleri veya lisans sunucu yapılandırmaları yoktur. NuGet paketi, tamamıyla OCR motorunu içerir ve lisans anahtarı uygulama kodunda bir dize olarak ayarlanır.

Geçişten sonra IronOCR lisanslamasını nasıl yapılandırırım?

Uygulama başlangıç ​​kodunda IronOcr.License.LicenseKey = "SİZİN-ANAHTARINIZ" atayın. Docker veya Kubernetes'te, anahtarı bir ortam değişkeni olarak saklayın ve başlangıçta okuyun. Trafiği kabul etmeden önce doğrulamak için License.IsValidLicense kullanın.

IronOCR, PDF'leri Azure Computer Vision gibi işleyebilir mi?

Evet. IronOCR hem yerel hem de taranmış PDF'leri okur. Bir PDF yolu veya OcrPdfInput olan girdiye ocr.Read(input) çağrısı yapmak için IronTesseract örneği çağırın ve OcrResult sayfalarını yineleyin. Ayrı bir PDF işleme hattı gerekmez.

IronOCR, yüksek hacim işleme sırasında iş parçacığı nasıl ele alır?

IronTesseract, iş parçacığı başına örnek olacak şekilde güvenlidir. Paralel.ForEach veya Görev havuzunda her iş parçacığı için bir örnek oluşturun, OCR'u eşzamanlı olarak çalıştırın ve her örneği iş tamamlandığında bırakın. Küresel durum veya kilitleme gerekmez.

IronOCR metin çıktıktan sonra hangi çıktıları destekler?

IronOCR, metin, kelime koordinatları, güven skorları ve sayfa yapısını içeren yapılandırılmış sonuçlar döndürür. Dışa aktarma seçenekleri düz metin, aranabilir PDF ve aşağı akış işlemesi için yapılandırılmış sonuç nesneleri içerir.

IronOCR'un fiyatlandırması, Azure Computer Vision OCR'dan daha öngörülebilir mi? İş yüklerini artırırken?

IronOCR, sayfa başına veya hacim ücretlendirmesi olmadan düz oranlı sürekli lisanslama kullanır. 10.000 veya 10 milyon sayfa işleseniz de lisans maliyeti sabit kalır. Hacim ve ekip lisanslama seçenekleri IronOCR fiyatlandırma sayfasındadır.

Azure Computer Vision OCR'dan IronOCR'a geçişten sonra mevcut testlerime ne olur?

Çıkarılmış metin içeriğini doğrulayan testler, geçişten sonra çalışmaya devam etmelidir. API çağrı şablonlarını veya COM nesne yaşam döngüsünü doğrulayan testler, IronOCR'un daha basit başlatma ve sonuç modelini yansıtacak şekilde güncellenmelidir.

Curtis Chau
Teknik Yazar

Curtis Chau, Bilgisayar Bilimleri alanında Lisans Derecesine (Carleton Üniversitesi) sahip ve Node.js, TypeScript, JavaScript ve React konularında uzmanlaşmış ön uç geliştirmeyle ilgileniyor. Sezgisel ve estetik açıdan hoş kullanıcı arayüzleri oluşturma tutkunu, Curtis modern çerçevelerle çalışmayı ve iyi yapı...

Daha Fazla Oku

Iron Destek Ekibi

Haftada 5 gün, 24 saat çevrimiçiyiz.
Sohbet
E-posta
Beni Ara