# أنابيب الأوCR المحدودة الغامضة - ثلاثية -Tier

<!-- category -- AI,Patterns,Architecture,LLM,OCR,Florence-2 -->
<datetime class="hidden">2026-01-07T18:00</datetime>

[جزء 4: استخبارات الصورة](/blog/constrained-fuzzy-image-intelligence) قدم معمارية موجات ImageSummarizer ونماذج أوسع **نظام فرعي OCR**—ثلاثة طوابق من إستخراج النص , توجيه ذكي | , | و تحسين مسار الأفلام الذي يحقق |30× | تخفيض الرموز لGIF الرسوم المتحركة

**لماذا مقالة مختلفة?** خط أنابيب التصوير بالرنين المغناطيسي تطور من "Tesseract مع Vision LLM fallback" إلى نظام ثلاثي الأبعاد متطور -tier مع MLMSC3based OCRM SK4 multiMST5frame votingMSSK6 textMS-only strip extractionMSR8 and costMSL9aware routingMSV10 ItMSP11s complex enough to warrant its own detailed breakdownMSS12

**المقالات المترابطة**:

- [جزء 1: نمط الغموض المقيد](/blog/constrained-fuzziness-pattern) - النمط الأساسي
- [جزء 2: مُحَطَّم بـ MoM غامض](/blog/constrained-mom-mixture-of-models) - تجميع نماذج متعددة
- [جزء 3: السحب في السياق](/blog/constrained-fuzzy-context-dragging) - الذاكرة والوقت
- [جزء 4: استخبارات الصورة](/blog/constrained-fuzzy-image-intelligence) - نظرة عامة كاملة للعمارة الموجية
- [DocSummarizer](/blog/building-a-document-summarizer-with-rag) - تحليل الملفات ذات الأنماط المتشابهة
- [المزيج للبيانات](/blog/datasummarizer-how-it-works) - رسم بيانات مع التفاضل والتكامل-نهج الأول

[TOC]

---


## المشكلة: استخراج النص صعب

التصوير بالرنين المغناطيسي على الصور الحقيقية

- **خطوط مصممة**: تدرب Tesseract على الخطوط القياسية, يفشل في كتابة الديكورية
- **GIF ضوئية**: artefacts of Frame compression , jitter, changes in subtitle
- **وضوح صغير**: نص مظلم على خلفية مظلمة
- **تدوير النص**: غير- زوايا النص الأفقية
- **المحتوى المزج**: لقطة شاشة مع مناطق نصية متعددة
- **تكاليف API**: المكالمات لـ Vision LLM مكلفة ($0.001-0.01 لكل صورة

المقاربة التقليدية: "Run Tesseract , إذا فشلت في استخدام Vision LLMM SK3

**المشكلة**: هذا إما يفتقد النص المصمم ( تفشل تيسيراكت) أو يكلف أكثر من ذلك ( دائماً تستخدم الـ Vision LLM

**الحل**: أضف مستوى متوسط (FlorenceM SK2 ONNX) يتعامل مع الخطوط المصممة بشكل محليMSC4 يتدرج إلى Vision LLM فقط عندما تفشل كل الطرق المحليةMスク5

---


## العمارة الثلاثية -Tier

يقوم النظام بتشغيل الأمواج في ترتيب أولي (أعلى رقم = تنفيذ متأخر):

```
Wave Priority Order:
  40: TextLikelinessWave → Heuristic text detection
  50: OcrWave            → Tesseract OCR (if text-likely)
  51: MlOcrWave          → Florence-2 ML OCR (if Tesseract low confidence)
  55: Florence2Wave      → Florence-2 captions (optional)
  80: VisionLlmWave      → Vision LLM (escalation)
```

### الطبقة 1: Tesseract (Traditional OCR)

MSC0 الأولوية MSC1 السرعة msc2 التكلفة msc3 الأفضل ل мсc4 الحدود psc5
|----------|-------|-------|----------|------------|
| **50** | ~50ms | مجانية | نص نقي, إختلاف كبيرM SK5 шрифтات قياسية | | | Schriftات مصممة |, | منخفضة الجودة |

**الإشارات المنبعثة:**

- `ocr.text` - نص تم استخراجه
- `ocr.confidence` - نمره الثقة المتوسطة لـ Tesseract

### مستوى 2: فلورانسM SK1 أونكس (ML OCR)

MSC0 الأولوية MSC1 السرعة msc2 التكلفة msc3 الأفضل ل мсc4 الحدود psc5
|----------|-------|-------|----------|------------|
| **51** | ~200ms | مجانية | Schriftات مصممةM SK4 الميمات, النص الديكوري MPSK6 الرسوم البيانية المعقدةMPK7 النص المدور PMK8

**الإشارات المنبعثة:**

- `ocr.ml.text` - واحدM SK1 إطار فلورانس-2 رسم بياني
- `ocr.ml.multiframe_text` - متعددةM SK1 نص إطار GIF (من المفضلة للانيميشنات)
- `ocr.ml.confidence` - نمط درجة الثقة

### مستوى 3: Vision LLM (Cloud Fallback)

MSC0 الأولوية MSC1 السرعة msc2 التكلفة msc3 الأفضل ل psc4 القيود scs5
|----------|-------|-------|----------|------------|
| **80** |

**الإشارات المنبعثة:**

- `ocr.vision.text` - إستخراج النص لـ Vision LLM OCR
- `ocr.vision.confidence` - الثقة في الـ LLM
- `caption.text` - عنوان وصفي إختياري ( منفصل عن الرسم البياني

---


## الـ ONNX Arsenal: نماذج ML محلية

قبل الغوص في ثلاث طبقات من التصوير بالرنين المغناطيسي **نماذج ML محددة** التي تعمل على النظام. جميع النماذج تعمل محلياً من خلال ONNX Runtime— لا مكالمات APIM SK2 لا إعتمادات السحاب , لا تكاليف

### لماذا ONNX?

- **يجري محلياً**: لا توجد مفاتيح API, لا يوجد تأخير في الشبكة
- **إختبارية**: نفس الدخل = نفس المخرج ( لا أخذ عينات / عشوائية درجة الحرارة )*
- **أسرع**:الhardware-accelerated (CPUM SK3GPU≥),إستنتاج مُحسن
- **قابلة للنقل**: يعمل على وينډوز
- **أوتومات-لقد تم تحميله**: أول عملية تحميل نماذج تلقائيا

\* *تحذير صغير: مقدمي تنفيذ GPU يمكن أن تضع في الإعتبار اللامحدودية الضئيلة-point nondeterminismM SK2 العقد السلكي (confidence thresholdsMSC4 routing logicMST5 remains fully deterministicMSM6*

### الخمس نماذج أونكس

> **ملاحظة**: الحجم تقريبية ومتغيرة حسب النموذج/كميّنةM SK2 بحجمات تحميل تقليدية تظهر في الأسفلMSC3

| نمط | تقريبا. الحجم | الهدف | السرعة | نوع النموذج |
|-------|--------------|---------|-------|------------|
| **الشرق** | ~100MB | الكشف عن النص في المشهد | ♫~20ms ♫| ♫ الكشف عن texte ♫ |
| **CRAFT** | ~150MB | الرمز-إكتشاف النص في المنطقة ms |إختشاف tekst |
| **فلورانس-2** | ~250MB | نغمة صوتية + تُقَمّر S| | | ~200ms ♫ | الرؤية ♫ |-لغة ♫
| **Real-ESRGAN** |  ~60MB
| **قفص** | ~600MB |បង្កប់ الدلالية | ♫~100ms ♫ | ♫បង្កប់ متعددة الأشكال ♫

**المساحة الكلية للقرص**: ~1.0-1.5GB إعتماداً على الطرازات المختارة.

---


### 1. EAST: الكشف عن النص المشهدي

**كاشف دقيق وفعال للكتابة النصية في المشهد** - يجد مناطق نصية في المناظر الطبيعية

```csharp
// EAST detects text bounding boxes with confidence scores
var result = await textDetector.RunEastDetectionAsync(imagePath);

// Output: List of BoundingBox with coordinates + confidence
// Example: [BoundingBox(x1:50, y1:100, x2:300, y2:150, confidence:0.92)]
```

**كيف تعمل**:

- نموذج التعلم العميق تم تدريبه على مجموعات البيانات النصية في المشهد
- خريطة النتائج (الثقة) +خريطة هندسية (نقاط الصندوقM SK4
- يدوي النص المدور, متعددة-النص على مقياس
- يستخدم غير -مضغوط اعظمي (NMS) لدمج اللوحات المتداخلة

**لماذا ديناميكية?**

- لا عشوائية في الاستنتاج (كثافات متجمدة)
- نفس الصورة → نفس الصناديق المزدوجة
- نقاط الثقة قابلة للتكرار
- حد الهبوط هو config-driven M SK1e.gMSC3 `< 0.5 → escalate`)

**التفاصيل التقنية**:

```csharp
// EAST preprocessing (from implementation)
- Input size: 320×320 (must be multiple of 32)
- Format: BGR with mean subtraction [123.68, 116.78, 103.94]
- Output stride: 4 (downsampled 4×)
- Score threshold: 0.5
- NMS IoU threshold: 0.4
```

**مخرج مثالي**:

```
Input: meme.png (800×600)
EAST detection: 15 text regions found
  Region 1: (50, 480, 750, 580) - confidence 0.87 [bottom subtitle area]
  Region 2: (100, 50, 300, 90) - confidence 0.62 [top text]
  Region 3: ...
Route decision: ANIMATED (subtitle pattern in bottom 30%)
```

---


### 2. CRAFT: نوع المنطقة الوعي

**Character-الكشف عن مستوى النص** - يتفوق على الرسم المنحنيM SK1 الفني , والكتابة الملونة.

```csharp
// CRAFT finds character-level regions, then groups into words
var result = await textDetector.RunCraftDetectionAsync(imagePath);

// Better than EAST for: decorative fonts, curved text, logos
```

**كيف تعمل**:

- يكشف مناطق الخصائص الفردية ( أكثر رقاقة من الشرق الاوسط)
- يستخدم تقييم الffinity لجمع الشخصيات في كلمات
- خوارزميا " Flood-fill" تكتشف مكونات نصية متصلة
- يتعامل مع النص المنحني الذي يفتقده شرق

**عندما يتم استخدام "CRAFT"**:

1. EAST غير متوفر أو فشل
2. الصورة تحتوي على أحرف فنية/زينة M SK1إتجاه آلي-محصولةMSC3
3. يختار المستخدم بوضوح كاشف CRAFT

**التفاصيل التقنية**:

```csharp
// CRAFT preprocessing
- Max dimension: 1280px (maintains aspect ratio)
- Format: RGB normalized with ImageNet stats
- Mean: [0.485, 0.456, 0.406]
- Std: [0.229, 0.224, 0.225]
- Output stride: 2 (downsampled 2×)
- Threshold: 0.4 for character regions
```

**اقصى الشرق مقابل CRAFT مقارنة**:

| الميزة | شرق | كرات S|
|---------|------|-------|
| مستوى إكتشاف | كلمة/خط | حرف |
| السرعة | MSC2ms MSC3 \MSC4ms
| الأفضل لـ
| النص المنحني | محدود | ممتاز S|
| حجم النماذج | MSC2MB MSC3 | | 150 | MB | MSC5

---


### 3. حقيقي -ESRGAN: سوبرM SK3 رفع الدقة

**تحسن الصور ذات الجودة المنخفضة - قبل التصوير بالرسوم المتحركة** - 4× رفع الخطوط المضيئةM SK2 نص صغير.

```csharp
// Upscale low-quality image before running OCR
if (quality.Sharpness < 30)  // Laplacian variance threshold
{
    var upscaled = await esrganService.UpscaleAsync(imagePath, scale: 4);
    // Now run OCR on the enhanced image
}
```

**عندما يتم استخدامه**:

- سماكة الصورة < 30 | | ( | إختلاف لابلاشي
- لقد تم اكتشاف مناطق نصية لكنها صغيرة جداً (< 20 ارتفاعpx)
- نسبة الثقة في الخطوط الاصطناعية ضعيفة ولكن مناطق النص موجودة
- يطلب المستخدم بوضوح التسارع

**مثال**:

```
Input:  100×75 screenshot with tiny text
        Laplacian variance: 18 (very blurry)

ESRGAN: Upscale to 400×300 (~500ms)
        New Laplacian variance: 87 (sharp)

OCR:    Tesseract confidence: 0.92 (vs 0.42 before upscaling)
        Text: "Click here to continue" (vs garbled before)
```

**التفاصيل التقنية**:

```csharp
// Real-ESRGAN processing
- Input: Any size (processed in 128×128 tiles if large)
- Output: 4× scaled (200×150 → 800×600)
- Model: x4plus variant (general photos)
- Processing: ~500ms for 800×600 image
- Memory: ~2GB peak (tiles reduce this)
```

**الإقتصاد الرمزي**:

```
Scenario: Screenshot with tiny text

Option 1: Send low-res to Vision LLM
  Image: 100×75 = ~20 tokens
  LLM can't read tiny text → fails
  Cost: $0.0002 (wasted)

Option 2: Upscale with ESRGAN, use Tesseract
  ESRGAN: Free (local), 500ms
  Tesseract: Free (local), 50ms
  Success: 92% confidence
  Cost: $0

Result: ESRGAN + local OCR beats Vision LLM for low-res images
```

---


### 4. CLIP: ملحقات سيمانسية

**دمجات متعددة الأشكال لبحث الصور الدلالية** - يعرض الصور والكتابة في الفضاء الفيكتوري المشترك

```csharp
// Generate embedding for semantic search
var embedding = await clipService.GenerateEmbeddingAsync(imagePath);
// Returns: float[512] vector

// Later: semantic search across thousands of images
var similarImages = await vectorDb.SearchAsync(queryEmbedding, topK: 10);
```

**كيف تعمل**:

- CLIP ViT-B/32 برمجة بصرية (350MBM SK3
- يعرض الصور إلى 512- векторات بعدية
- تم تدريبهم على التوافق مع الوصفات النصية
- يُمكن " العثور على صور كهذه" بدون كلمات مرور

**إستخدام الحالات**:

- بحث الصور الدلالية في أنظمة RAG
- إكتشاف مزيف (حتى إذا تم تعديله/مقطعةM SK2
- Content-based clustering
- توصيات صور مماثلة

**التفاصيل التقنية**:

```csharp
// CLIP visual encoder
- Model: ViT-B/32 (Vision Transformer)
- Input: 224×224 RGB (center crop + resize)
- Output: 512-dimensional embedding
- Normalized: L2 norm = 1.0
- Speed: ~100ms per image
```

**مثال**:

```
Input images:
  cat_on_couch.jpg → [0.23, -0.51, 0.88, ...]
  dog_on_couch.jpg → [0.19, -0.48, 0.91, ...]
  car_photo.jpg    → [-0.67, 0.33, -0.12, ...]

Query: "animals on furniture"
  Text embedding → [0.21, -0.50, 0.89, ...]

Cosine similarity:
  cat_on_couch: 0.94 (very similar!)
  dog_on_couch: 0.91 (similar)
  car_photo: 0.12 (not similar)

Result: Returns cat and dog images
```

---


### 5. فلورانسM SK1 الرؤية-نموذج اللغة (مغطى في الطبقة МSK4

رؤية قسم 2 للتفصيلات الكاملة عن فلورانس-2 ONNX OCR و اللوحاتM SK2

---


### اتومات-نظام تحميل

جميع النماذج يتم تحميلها تلقائياً عند الاستخدام الأول:

```bash
$ imagesummarizer image.png --pipeline auto

[First run]
Downloading EAST scene text detector (~100MB)...
  Progress: ████████████████████ 100% (102.4 MB)
Downloading Florence-2 base model (~250MB)...
  Progress: ████████████████████ 100% (248.7 MB)
Downloading CLIP ViT-B/32 visual (~350MB)...
  Progress: ████████████████████ 100% (347.2 MB)

Models saved to: ~/.mostlylucid/models/
Total disk space: 1.16 GB

[Subsequent runs]
All models cached, analysis starts immediately
```

**الانهيار اللطيف**:

```csharp
// If ONNX model download fails, system falls back gracefully
EAST unavailable → Try CRAFT → Fall back to Tesseract PSM
Real-ESRGAN unavailable → Skip upscaling, use original image
CLIP unavailable → Skip embeddings, OCR still works
Florence-2 unavailable → Use Tesseract → Vision LLM escalation
```

كل فشل نموذج أونكس يتم تسجيله مع طريق التراجع , متأكداً من أن النظام لن يتعطل أبداً بسبب النماذج المفقودة .

---


### لماذا هذا مهم

> **ملاحظة الأسعار**: أمثلة من التكلفة في الأسفل تستخدم رسماً لتسعير (~$0.005/ صورة لـ Vision LLM). تكاليف API الحقيقية تختلف حسب المورد والنموذجM SK3 الإدراك الأساسيMSC4 معالجة محلية تقضي على معظم مكالمات API

**بدون نماذج أونكس** (خط الأساس):

```
Every image → Send to Vision LLM
  Cost: ~$0.005/image (example pricing)
  Time: ~2s network + inference
  100 images = ~$0.50, ~200s
```

**مع نماذج ONNX** (localM SK1first):

```
85 images → EAST + Florence-2 (local)
  Cost: $0
  Time: ~200ms

10 images → EAST + Tesseract (local)
  Cost: $0
  Time: ~50ms

5 images → EAST + Vision LLM (escalation)
  Cost: ~$0.025 (5 × $0.005)
  Time: ~2s each

100 images = ~$0.025, ~30s total
```

**الإدخار**: ~95% تخفيض من التكلفة, |~85% أسرعM SK4 **التوجيه الإفتراضي**.

نماذج ONNX تحول النظام من "probabilistic down all the way down" to "deterministic foundation + probabilistic escalation only when neededM SK4

---


## مستوى 1: Tesseract OCR

الخط الاساسي. سريع, محددM SK2 يعمل بشكل جيد للكتابة النظيفة .

```csharp
public class OcrWave : IAnalysisWave
{
    public string Name => "OcrWave";
    public int Priority => 60;  // After color/identity

    public async Task<IEnumerable<Signal>> AnalyzeAsync(
        string imagePath,
        AnalysisContext context,
        CancellationToken ct)
    {
        var signals = new List<Signal>();

        // Get preprocessed image from cache
        var image = context.GetCached<Image<Rgba32>>("image");

        // Run Tesseract OCR
        using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
        using var page = engine.Process(image);

        var text = page.GetText();
        var confidence = page.GetMeanConfidence();

        signals.Add(new Signal
        {
            Key = "ocr.text",  // Tesseract OCR result
            Value = text,
            Confidence = confidence,
            Source = Name,
            Tags = new List<string> { "ocr", "text" },
            Metadata = new Dictionary<string, object>
            {
                ["engine"] = "tesseract",
                ["mean_confidence"] = confidence,
                ["word_count"] = text.Split(' ').Length
            }
        });

        signals.Add(new Signal
        {
            Key = "ocr.confidence",
            Value = confidence,
            Confidence = 1.0,
            Source = Name
        });

        return signals;
    }
}
```

**إشارات مفاتيح**:

- `ocr.full_text` - النص المستخرج
- `ocr.early_exit` - إشارة لتخطى مستوى 2/3 إذا كان الثقة مرتفعة
- تقييم الثقة يقود قرارات التدرج

---


## الطبقة 2: فلورانس-2NX

مايكروسوفت's فلورانس-2 هو نموذج لرؤية - النموذج اللغوي الذي يتفوق على بكتابة كثافة و OCRM SK3 نسخة ONNX تعمل محلياً بدون أي تكاليف API .

### لماذا فلورانس-2?

- **أفضل من Tesseract لخطوط مصممة**: يدوي النص الزخرف, الميماتM SK2 شعارات
- **أسرع من Vision LLM**: ~200ms vs 1-5s
- **مجانية**: يشتغل محليا, لا تحتاج إلى مفاتيح API
- **فهم متعدد الأشكال**: يمكن استخراج النص في السياق (e.gMSC3 حباب الكلامM SK4

### التنفيذ

```csharp
public class MlOcrWave : IAnalysisWave
{
    private readonly Florence2OnnxModel _model;

    public string Name => "MlOcrWave";
    public int Priority => 51;  // Runs AFTER Tesseract (priority 50)

    public async Task<IEnumerable<Signal>> AnalyzeAsync(
        string imagePath,
        AnalysisContext context,
        CancellationToken ct)
    {
        var signals = new List<Signal>();

        // Check if Tesseract already succeeded with high confidence
        var tesseractConfidence = context.GetValue<double>("ocr.confidence");
        if (tesseractConfidence >= 0.95)
        {
            signals.Add(new Signal
            {
                Key = "ocr.ml.skipped",  // Consistent namespace: ocr.ml.*
                Value = true,
                Confidence = 1.0,
                Source = Name,
                Metadata = new Dictionary<string, object>
                {
                    ["reason"] = "tesseract_high_confidence",
                    ["tesseract_confidence"] = tesseractConfidence
                }
            });
            return signals;
        }

        // Run Florence-2 OCR
        var result = await _model.ExtractTextAsync(imagePath, ct);

        signals.Add(new Signal
        {
            Key = "ocr.ml.text",  // Florence-2 ML OCR text
            Value = result.Text,
            Confidence = result.Confidence,
            Source = Name,
            Tags = new List<string> { "ocr", "text", "ml" },
            Metadata = new Dictionary<string, object>
            {
                ["model"] = "florence2-base",
                ["inference_time_ms"] = result.InferenceTime,
                ["token_count"] = result.TokenCount
            }
        });

        // For animated GIFs, extract all unique frames
        if (context.GetValue<int>("identity.frame_count") > 1)
        {
            var frameResults = await ExtractMultiFrameTextAsync(
                imagePath,
                maxFrames: 10,
                ct);

            signals.Add(new Signal
            {
                Key = "ocr.ml.multiframe_text",
                Value = frameResults.CombinedText,
                Confidence = frameResults.AverageConfidence,
                Source = Name,
                Metadata = new Dictionary<string, object>
                {
                    ["frames_processed"] = frameResults.FrameCount,
                    ["unique_text_segments"] = frameResults.UniqueSegments,
                    ["deduplication_method"] = "levenshtein_85"
                }
            });
        }

        return signals;
    }
}
```

### معالجة GIFFrame متعددة

بالنسبة للGIF المتحركة , فلورانس-2 العمليات إلى 10 الأجزاء المستخرجة بشكل متوازن

```csharp
private async Task<MultiFrameResult> ExtractMultiFrameTextAsync(
    string imagePath,
    int maxFrames,
    CancellationToken ct)
{
    // Load GIF and extract frames
    using var image = await Image.LoadAsync<Rgba32>(imagePath, ct);
    var frames = new List<Image<Rgba32>>();

    int frameCount = image.Frames.Count;
    int step = Math.Max(1, frameCount / maxFrames);

    for (int i = 0; i < frameCount; i += step)
    {
        frames.Add(image.Frames.CloneFrame(i));
    }

    // Process all frames in parallel (bounded concurrency to avoid thrashing)
    var semaphore = new SemaphoreSlim(4);  // Max 4 concurrent inferences
    var tasks = frames.Select(async frame =>
    {
        await semaphore.WaitAsync(ct);
        try
        {
            var result = await _model.ExtractTextAsync(frame, ct);
            return result;
        }
        finally
        {
            semaphore.Release();
        }
    });

    var results = await Task.WhenAll(tasks);
    semaphore.Dispose();

    // Deduplicate using Levenshtein distance
    var uniqueTexts = DeduplicateByLevenshtein(
        results.Select(r => r.Text).ToList(),
        threshold: 0.85);

    return new MultiFrameResult
    {
        CombinedText = string.Join("\n", uniqueTexts),
        FrameCount = frames.Count,
        UniqueSegments = uniqueTexts.Count,
        AverageConfidence = results.Average(r => r.Confidence)
    };
}

private List<string> DeduplicateByLevenshtein(
    List<string> texts,
    double threshold)
{
    var unique = new List<string>();

    foreach (var text in texts)
    {
        bool isDuplicate = false;
        foreach (var existing in unique)
        {
            var distance = LevenshteinDistance(text, existing);
            var maxLen = Math.Max(text.Length, existing.Length);
            var similarity = 1.0 - (distance / (double)maxLen);

            if (similarity >= threshold)
            {
                isDuplicate = true;
                break;
            }
        }

        if (!isDuplicate)
        {
            unique.Add(text);
        }
    }

    return unique;
}
```

**مثال**: 93-صورة GIF | | → |10 | फ्रेमات العينة |

```
Frame 1-45:  "I'm not even mad."
Frame 46-93: "That's amazing."
```

---


## إتخاذ القرار في المسار

إكتشاف النص OpenCV (~5-20ms) يحدد أي مسار يجب أخذه

```csharp
public class TextDetectionService
{
    public TextDetectionResult DetectText(Image<Rgba32> image)
    {
        // Use OpenCV EAST text detector
        var (regions, confidence) = RunEastDetector(image);

        return new TextDetectionResult
        {
            HasText = regions.Count > 0,
            RegionCount = regions.Count,
            Confidence = confidence,
            Route = SelectRoute(regions, confidence, image)
        };
    }

    private ProcessingRoute SelectRoute(
        List<TextRegion> regions,
        double confidence,
        Image<Rgba32> image)
    {
        // No text detected
        if (regions.Count == 0)
            return ProcessingRoute.NoOcr;

        // Animated GIF with subtitle pattern
        if (image.Frames.Count > 1 && HasSubtitlePattern(regions))
            return ProcessingRoute.AnimatedFilmstrip;

        // High confidence, standard text
        if (confidence >= 0.8 && HasStandardTextCharacteristics(regions))
            return ProcessingRoute.Fast;  // Florence-2 only

        // Moderate confidence
        if (confidence >= 0.5)
            return ProcessingRoute.Balanced;  // Florence-2 + Tesseract voting

        // Low confidence, complex image
        return ProcessingRoute.Quality;  // Full pipeline + Vision LLM
    }

    private bool HasSubtitlePattern(List<TextRegion> regions)
    {
        // Subtitles are typically in bottom 30% of frame
        var bottomRegions = regions.Where(r =>
            r.BoundingBox.Y > r.ImageHeight * 0.7);

        return bottomRegions.Count() >= regions.Count * 0.5;
    }
}
```

### أداء الطريق

| الطريق | يحدد متى | المعالجة | الوقت | التكلفة |
|-------|---------------|------------|------|------|
| **أسرع** | ثقة عالية (>0.8), نص معياري MSC2 فلورانسMSc3 فقط MSC4 МСC5ms msC6 مجانية msC7
| **متوازن** | الثقة المتواضعة (0.5-0.8) | فلورانس-2 ♫+ التصويت Tesseract | | 5 | 6 | 7 | مجاني | 8
| **الجودة** | ثقة ضعيفة (<0.5), معقدة | متعددة - إطار + رؤية اللوحة اللاسلكية | | ~1-5 | | |$0.001-0.01 ||
| **تم تصويره** | GIF مع نمط عنوان فرعي | النص-شريحة فيلمية فقط | | |

---


## النص-فقط استخراج الشريط

تحسين التطور لترجمات GIF **فقط المناطق النصية**, لا إطارات كاملة.

### المشكلة

المقاربة التقليدية لـ 93-frame GIF with subtitles

```
Option 1: Process every frame
  93 frames × 300×185 × ~150 tokens/frame = 13,950 tokens
  Cost: ~$0.14 @ $0.01/1K tokens
  Time: ~27 seconds

Option 2: Sample 10 frames
  10 frames × 300×185 × ~150 tokens/frame = 1,500 tokens
  Cost: ~$0.015
  Time: ~3 seconds
  Problem: Might miss subtitle changes
```

### الحل: النص-فقط الخطوط

استخرج فقط مربعات الكتابة النصية, إزالة पिكسल्स الخلفية :

```
2 text regions × 250×50 × ~25 tokens/region = 50 tokens
Cost: ~$0.0005
Time: ~2 seconds
Token reduction: 30×
```

### التنفيذ

```csharp
public class FilmstripService
{
    public async Task<TextOnlyStrip> CreateTextOnlyStripAsync(
        string imagePath,
        CancellationToken ct)
    {
        using var gif = await Image.LoadAsync<Rgba32>(imagePath, ct);

        // 1. Detect subtitle region (bottom 30% of frames)
        var subtitleRegion = DetectSubtitleRegion(gif);

        // 2. Extract frames with text changes
        var uniqueFrames = ExtractUniqueTextFrames(gif, subtitleRegion);

        // 3. Extract tight bounding boxes around text
        var textRegions = ExtractTextBoundingBoxes(uniqueFrames);

        // 4. Create horizontal strip of text-only regions
        var strip = CreateHorizontalStrip(textRegions);

        return new TextOnlyStrip
        {
            Image = strip,
            RegionCount = textRegions.Count,
            TotalTokens = EstimateTokens(strip),
            OriginalTokens = EstimateTokens(gif),
            Reduction = CalculateReduction(strip, gif)
        };
    }

    private Rectangle DetectSubtitleRegion(Image<Rgba32> gif)
    {
        // Analyze bottom 30% of frame for text patterns
        int subtitleHeight = (int)(gif.Height * 0.3);
        int subtitleY = gif.Height - subtitleHeight;

        return new Rectangle(0, subtitleY, gif.Width, subtitleHeight);
    }

    private List<Image<Rgba32>> ExtractUniqueTextFrames(
        Image<Rgba32> gif,
        Rectangle subtitleRegion)
    {
        var uniqueFrames = new List<Image<Rgba32>>();
        Image<Rgba32>? previousFrame = null;

        for (int i = 0; i < gif.Frames.Count; i++)
        {
            var frame = gif.Frames.CloneFrame(i);
            var subtitleCrop = frame.Clone(ctx =>
                ctx.Crop(subtitleRegion));

            // Compare with previous frame
            if (previousFrame == null ||
                HasTextChanged(subtitleCrop, previousFrame, threshold: 0.05))
            {
                uniqueFrames.Add(subtitleCrop);
                previousFrame = subtitleCrop;
            }
        }

        return uniqueFrames;
    }

    private bool HasTextChanged(
        Image<Rgba32> current,
        Image<Rgba32> previous,
        double threshold)
    {
        // Threshold bright pixels (white/yellow text on dark background)
        var currentBright = CountBrightPixels(current);
        var previousBright = CountBrightPixels(previous);

        // Calculate Jaccard similarity of bright pixels
        var intersection = currentBright.Intersect(previousBright).Count();
        var union = currentBright.Union(previousBright).Count();

        var similarity = union > 0 ? intersection / (double)union : 1.0;

        // Text changed if similarity drops below threshold
        return similarity < (1.0 - threshold);
    }

    // Helper type for bounding box + crop
    private record TextCrop
    {
        public required Image<Rgba32> CroppedImage { get; init; }
        public required Rectangle Bounds { get; init; }
    }

    private List<TextCrop> ExtractTextBoundingBoxes(
        List<Image<Rgba32>> frames)
    {
        var textCrops = new List<TextCrop>();

        foreach (var frame in frames)
        {
            // Threshold to get text mask
            var mask = ThresholdBrightPixels(frame, minValue: 200);

            // Find connected components (text regions)
            var components = FindConnectedComponents(mask);

            // Get tight bounding box around all components
            var bbox = GetTightBoundingBox(components);

            // Add padding
            bbox.Inflate(5, 5);

            // Clone the region (dispose properly in production!)
            var cropped = frame.Clone(ctx => ctx.Crop(bbox));

            textCrops.Add(new TextCrop
            {
                CroppedImage = cropped,
                Bounds = bbox
            });
        }

        return textCrops;
    }

    private Image<Rgba32> CreateHorizontalStrip(
        List<TextCrop> textCrops)
    {
        // Calculate strip dimensions
        int totalWidth = textCrops.Sum(c => c.Bounds.Width);
        int maxHeight = textCrops.Max(c => c.Bounds.Height);

        // Create blank canvas
        var strip = new Image<Rgba32>(totalWidth, maxHeight);

        // Paste text regions horizontally
        int xOffset = 0;
        foreach (var crop in textCrops)
        {
            strip.Mutate(ctx => ctx.DrawImage(
                crop.CroppedImage,
                new Point(xOffset, 0),
                opacity: 1.0f));

            xOffset += crop.Bounds.Width;

            // Dispose crop after use (important!)
            crop.CroppedImage.Dispose();
        }

        return strip;
    }
}
```

### مثال بصري

**الدخل**: anchorman-not-even-mad.gif (93 frames, 300×185)

**المعالجة**:

```
1. Detect subtitle region: bottom 30% (300×55)
2. Extract unique frames: 93 frames → 2 text changes
3. Extract tight bounding boxes:
   - Frame 1-45: "I'm not even mad." → 252×49 bbox
   - Frame 46-93: "That's amazing." → 198×49 bbox
4. Create horizontal strip: 450×49 total
```

**ناتج**: النص-شريحة واحدة فقط (450×49)

![النص-مجرد شريط فقط مثال](https://raw.githubusercontent.com/scottgal/lucidrag/main/src/Mostlylucid.DocSummarizer.Images/demo-images/anchorman-not-even-mad_textonly_strip.png)

**إقتصاد الرموز**:

- الإطارات الكاملة (10 تم أخذ عينة): 300×185 | | × |
- شريط الـ OCR (2 إطارات): 300×185 | | × ♫ |2 ♫
- **النص-شريحة واحدة فقط**نغمات : 450×49 | | = |

**30× تقليل** بينما يحفظ كل نص الترجمة

---


## مستوى 3: رؤية LLM التسارع

عندما تفشل تيسيراكت و فلورانس-2 أو تنتج نتائج ضعيفة-نتائج الثقةM SK2 تتدرج إلى Vision LLM MSC3GPT -4oMスク5 Claude MSSK6 SonnetMSL7 Gemini Pro VisionMST8 أو نماذج أولاما مثل minicpmMSSK9vMS).

### بوابة الجودة

```csharp
public class OcrQualityWave : IAnalysisWave
{
    private readonly SpellChecker _spellChecker;

    public string Name => "OcrQualityWave";
    public int Priority => 58;  // After Florence-2 and Tesseract

    public async Task<IEnumerable<Signal>> AnalyzeAsync(
        string imagePath,
        AnalysisContext context,
        CancellationToken ct)
    {
        var signals = new List<Signal>();

        // Get best OCR result from earlier waves (priority order)
        string? ocrText =
            context.GetValue<string>("ocr.ml.text") ??  // Florence-2 (priority 51)
            context.GetValue<string>("ocr.text");        // Tesseract (priority 50)

        if (string.IsNullOrWhiteSpace(ocrText))
        {
            signals.Add(new Signal
            {
                Key = "ocr.quality.no_text",
                Value = true,
                Confidence = 1.0,
                Source = Name
            });
            return signals;
        }

        // Run spell check (deterministic quality assessment)
        var spellResult = _spellChecker.CheckTextQuality(ocrText);

        // Additional quality signals to avoid false positives
        var alphanumRatio = CalculateAlphanumericRatio(ocrText);  // Letters/digits vs junk
        var avgTokenLength = CalculateAverageTokenLength(ocrText);

        signals.Add(new Signal
        {
            Key = "ocr.quality.spell_check_score",
            Value = spellResult.CorrectWordsRatio,
            Confidence = 1.0,
            Source = Name,
            Metadata = new Dictionary<string, object>
            {
                ["total_words"] = spellResult.TotalWords,
                ["correct_words"] = spellResult.CorrectWords,
                ["garbled_words"] = spellResult.GarbledWords,
                ["alphanum_ratio"] = alphanumRatio,
                ["avg_token_length"] = avgTokenLength
            }
        });

        // Deterministic escalation threshold
        // NOTE: Spellcheck alone can false-trigger on proper nouns, memes, brand names.
        // Use additional signals (alphanum ratio, token length) to reduce false escalations.
        bool isGarbled = spellResult.CorrectWordsRatio < 0.5 &&
                         alphanumRatio > 0.7;  // Mostly valid characters, just not in dictionary

        signals.Add(new Signal
        {
            Key = "ocr.quality.is_garbled",
          Value = isGarbled,
            Confidence = 1.0,
            Source = Name
        });

        // Signal Vision LLM escalation
        if (isGarbled)
        {
            signals.Add(new Signal
            {
                Key = "ocr.quality.escalation_required",
                Value = true,
                Confidence = 1.0,
                Source = Name,
                Tags = new List<string> { "action_required", "escalation" },
                Metadata = new Dictionary<string, object>
                {
                    ["reason"] = "spell_check_below_threshold",
                    ["quality_score"] = spellResult.CorrectWordsRatio,
                    ["threshold"] = 0.5,
                    ["target_tier"] = "vision_llm"
                }
            });

            // Cache garbled text for Vision LLM to access
            context.SetCached("ocr.garbled_text", ocrText);
        }

        return signals;
    }
}
```

**التسارع هو محدد**: علامة إختبار اللغز < 50% | | → تتصاعد. لا الحكم الإحتمالي

### Vision LLM مع Filmstrip

عندما يتم تحفيز التسارع للGIF المتحركة , إستخدم النص - فقط الشريط МSK2

```csharp
public class VisionLlmWave : IAnalysisWave
{
    private readonly IVisionLlmClient _client;

    public string Name => "VisionLlmWave";
    public int Priority => 50;

    public async Task<IEnumerable<Signal>> AnalyzeAsync(
        string imagePath,
        AnalysisContext context,
        CancellationToken ct)
    {
        var signals = new List<Signal>();

        // Check if escalation is required
        var escalationRequired = context.GetValue<bool>(
            "ocr.quality.escalation_required");

        if (!escalationRequired)
        {
            signals.Add(new Signal
            {
                Key = "vision.llm.skipped",
                Value = true,
                Confidence = 1.0,
                Source = Name,
                Metadata = new Dictionary<string, object>
                {
                    ["reason"] = "no_escalation_required"
                }
            });
            return signals;
        }

        // For animated GIFs, use text-only strip
        string imageToProcess = imagePath;
        bool usedFilmstrip = false;

        if (context.GetValue<int>("identity.frame_count") > 1)
        {
            var filmstrip = await CreateTextOnlyStripAsync(imagePath, ct);
            imageToProcess = filmstrip.Path;
            usedFilmstrip = true;

            signals.Add(new Signal
            {
                Key = "vision.filmstrip.created",
                Value = true,
                Confidence = 1.0,
                Source = Name,
                Metadata = new Dictionary<string, object>
                {
                    ["mode"] = "text_only",
                    ["region_count"] = filmstrip.RegionCount,
                    ["token_reduction"] = filmstrip.Reduction,
                    ["original_tokens"] = filmstrip.OriginalTokens,
                    ["final_tokens"] = filmstrip.TotalTokens
                }
            });
        }

        // Build constrained prompt
        var prompt = BuildConstrainedPrompt(context);

        // Call Vision LLM
        var result = await _client.ExtractTextAsync(
            imageToProcess,
            prompt,
            ct);

        // Emit OCR text signal (Vision LLM tier)
        signals.Add(new Signal
        {
            Key = "ocr.vision.text",  // Vision LLM OCR result
            Value = result.Text,
            Confidence = 0.95,  // High but not 1.0 - still probabilistic
            Source = Name,
            Tags = new List<string> { "ocr", "vision", "llm" },
            Metadata = new Dictionary<string, object>
            {
                ["model"] = result.Model,
                ["used_filmstrip"] = usedFilmstrip,
                ["inference_time_ms"] = result.InferenceTime,
                ["token_count"] = result.TokenCount,
                ["cost_usd"] = result.Cost
            }
        });

        // Optionally emit caption if requested (separate from OCR)
        if (result.Caption != null)
        {
            signals.Add(new Signal
            {
                Key = "caption.text",  // Descriptive caption, not OCR
                Value = result.Caption,
                Confidence = 0.90,
                Source = Name,
                Tags = new List<string> { "caption", "description" }
            });
        }

        return signals;
    }

    private string BuildConstrainedPrompt(AnalysisContext context)
    {
        var sb = new StringBuilder();

        sb.AppendLine("Extract all text from this image.");
        sb.AppendLine();
        sb.AppendLine("CONSTRAINTS:");
        sb.AppendLine("- Only extract text that is actually visible");
        sb.AppendLine("- Preserve formatting and line breaks");
        sb.AppendLine("- If no text is present, return empty string");
        sb.AppendLine();

        // Add context from earlier waves
        var garbledText = context.GetCached<string>("ocr.garbled_text");
        if (!string.IsNullOrEmpty(garbledText))
        {
            sb.AppendLine("CONTEXT:");
            sb.AppendLine("Traditional OCR detected garbled text:");
            sb.AppendLine($"  \"{garbledText}\"");
            sb.AppendLine("Use this as a hint for stylized or unusual fonts.");
            sb.AppendLine();
        }

        sb.AppendLine("Return only the extracted text, no commentary.");

        return sb.ToString();
    }
}
```

---


## السلسلة الأولية

عندما تنتهي جميع الطبقات, يستعمل اختيار النص النهائي ترتيب أولوية صارمة:

```csharp
public static string? GetFinalText(DynamicImageProfile profile)
{
    // Priority chain (highest to lowest quality)
    // NOTE: This selects ONE source, but the ledger exposes ALL sources
    // with confidence scores for downstream inspection

    // 1. Vision LLM OCR (best for complex/garbled text)
    var visionText = profile.GetValue<string>("ocr.vision.text");
    if (!string.IsNullOrEmpty(visionText))
        return visionText;

    // 2. Florence-2 multi-frame GIF OCR (best for animations)
    var florenceMultiText = profile.GetValue<string>("ocr.ml.multiframe_text");
    if (!string.IsNullOrEmpty(florenceMultiText))
        return florenceMultiText;

    // 3. Florence-2 single-frame ML OCR (good for stylized fonts)
    var florenceText = profile.GetValue<string>("ocr.ml.text");
    if (!string.IsNullOrEmpty(florenceText))
        return florenceText;

    // 4. Tesseract OCR (reliable for clean standard text)
    var tesseractText = profile.GetValue<string>("ocr.text");
    if (!string.IsNullOrEmpty(tesseractText))
        return tesseractText;

    // 5. Fallback (empty)
    return string.Empty;
}
```

**كل مستوى لديه خصائص معروفة**:

| المصدر | مفاتيح الإشارات | الأفضل لـ | الثقة | التكلفة | السرعة psk6
|--------|------------|----------|------------|------|-------|
| Vision LLM OCR | `ocr.vision.text` | الرسوم البيانية المعقدةM SK1 النص المدور, مشوهة | 0.95 ♫| |$0.001-0.01 | |
| فلورانسM SK1 (GIF) | `ocr.ml.multiframe_text` | الرسوم المتحركة الGIFs مع الأشرطة الفرعية | | | 0.85-0.92 |
| فلورانسM SK1 (single) `ocr.ml.text` | Schriftات مصممة, الميماتM SK2 النص الديكوري | 0.85-0.90 \| مجاني | |~200ms | |
| Tesseract  | `ocr.text` | نص معياري نقي, متباينة عالية | إختلافات MSC3 مجانية MSC4 | MSC5 | ms | |

---


## تحليل التكاليف

### قبل System Three-Tier

100 الصور, جميعها باستخدام Vision LLM

```
100 images × $0.005/image = $0.50
Total time: 100 × 2s = 200 seconds
```

### بعد ثلاثة -نظام صور

توزيع الخطوط (نموذجي):

- 60 صور → الطريق السريع ( فلورانس-2 فقطMSC4 مجانيةMSc5 MSC6ms MSc7
- 25 صور → طريق متوازن ( فلورانس-2 + تيسيراكتMSк5 مجانيةMSC6 \MSC7msMSc8
- 10 صور → طريق الجودة (+ رؤية LLM, $0.005, ♫~2sM SK6
- 5 الصور → الطريق المحصور (مسار الأفلامMSC3 MSC4 | | 5 | 6

```
Cost:
  60 × $0 = $0
  25 × $0 = $0
  10 × $0.005 = $0.05
  5 × $0.002 = $0.01
  Total: $0.06

Time:
  60 × 0.1s = 6s
  25 × 0.3s = 7.5s
  10 × 2s = 20s
  5 × 2.5s = 12.5s
  Total: 46 seconds

Savings:
  Cost: 88% reduction ($0.50 → $0.06)
  Time: 77% reduction (200s → 46s)
```

**الطبقة الوسطى (Florence-2) تعالج 85% الصور بتكلفة صفرةM SK3**

---


## وضع كل شيء معاً

هنا ' هو التدفق الكامل لGIF الميم مع الأشرطة

```
1. Load image: anchorman-not-even-mad.gif (93 frames)

2. IdentityWave (priority 10):
   → identity.frame_count = 93
   → identity.format = "gif"
   → identity.is_animated = true

3. TextLikelinessWave (priority 40, ~10ms):
   → Heuristic text detection: 15 regions in bottom 30%
   → Subtitle pattern: DETECTED
   → text.likeliness = 0.85

4. OcrWave (priority 50, ~60ms):
   → Run Tesseract OCR on first frame
   → ocr.text = "I'm not emn mad."  (garbled)
   → ocr.confidence = 0.62

5. MlOcrWave (priority 51, ~180ms):
   → Tesseract confidence < 0.95, run Florence-2
   → Sample 10 frames (animated GIF)
   → Run Florence-2 on each frame (parallel)
   → Deduplicate: 10 results → 2 unique texts
   → ocr.ml.multiframe_text = "I'm not even mad.\nThat's amazing."
   → ocr.ml.confidence = 0.91

6. OcrQualityWave (priority 58, ~5ms):
   → Check Florence-2 result
   → Spell check: 6/6 words correct (100%)
   → ocr.quality.is_garbled = false
   → ocr.quality.escalation_required = false

7. VisionLlmWave (priority 80, SKIPPED):
   → No escalation required (Florence-2 succeeded)

Final output:
  Text: "I'm not even mad.\nThat's amazing."
  Source: ocr.ml.multiframe_text
  Confidence: 0.91
  Cost: $0 (local processing)
  Time: ~250ms total (Tesseract + Florence-2)
```

إذا فشلت فلورانس-2 (الثقة < ♫0.5), ستستمر التدفقs

```
6. OcrQualityWave:
   → Spell check: 2/6 words correct (33%)
   → ocr.quality.is_garbled = true
   → ocr.quality.escalation_required = true

7. VisionLlmWave:
   → Create text-only filmstrip (2 regions, 450×49)
   → Send to Vision LLM: "Extract all text from this strip"
   → vision.llm.text = "I'm not even mad.\nThat's amazing."
   → Confidence: 0.95
   → Cost: ~$0.002 (30× token reduction vs full frames)
   → Time: ~2.3s
```

---


## الإعداد

نظام الطبقة الثلاثة - قابلة للتركيب بالكامل :

```json
{
  "DocSummarizer": {
    "Ocr": {
      "Tesseract": {
        "Enabled": true,
        "DataPath": "/usr/share/tesseract-ocr/4.00/tessdata",
        "Languages": ["eng"],
        "EarlyExitThreshold": 0.95
      },
      "Florence2": {
        "Enabled": true,
        "ModelPath": "models/florence2-base",
        "ConfidenceThreshold": 0.85,
        "MaxFrames": 10,
        "DeduplicationMethod": "levenshtein",
        "LevenshteinThreshold": 0.85
      },
      "Quality": {
        "SpellCheckThreshold": 0.5,
        "EscalationEnabled": true
      }
    },
    "VisionLlm": {
      "Enabled": true,
      "Provider": "ollama",
      "OllamaUrl": "http://localhost:11434",
      "Model": "minicpm-v:8b",
      "MaxRetries": 3,
      "TimeoutSeconds": 30
    },
    "Filmstrip": {
      "TextOnlyMode": true,
      "SubtitleRegionPercent": 0.3,
      "BrightPixelThreshold": 200,
      "TextChangeThreshold": 0.05
    },
    "Routing": {
      "FastRouteConfidence": 0.8,
      "BalancedRouteConfidence": 0.5,
      "TextDetectionEnabled": true
    }
  }
}
```

---


## اشكال الفشل

| الفشل | الكشف | الاستجابة |
|---------|-----------|----------|
| **فشلت تيسيراكت** | الثقة < 0.7 أو إختبار الحروف < \0.5 || الهروب إلى فلورانس |-2 | |
| **فلورانس-2 فشل** | الثقة < 0.5 أو إختبار الحروف < | 0.5 | || الهروب إلى رؤية LLM |
| **إنقطاع رؤية LLM** | الطلب يتجاوز 30s S| العودة إلى أفضل نتيجة صوتية موجودة |
| **فشلت جميع الطبقات** | جميع النتائج فارغة أو مشوهة | أرجع السطر الفارغ بثقة | |
| **حد تكلفة API** | الميزانية اليومية تجاوزت | لا يستطيعون الرؤية LLM, يستخدمون فلورانسM SK3 فقط |
| **النموذج غير متوفر** | فلورانسM SK1Vision LLM offline | Skip tier, continue to next |

كل فشل هو محدد ومسجل مع provenance الكامل.

---


## مقارنة مع المقاربات الأخرى

### تقليدية: Tesseract + Manual Fallback

```
For each image:
  1. Run Tesseract
  2. If looks wrong, manually fix or skip

Problems:
- No middle tier (binary: works or doesn't)
- Manual intervention required
- No cost optimization
```

### Cloud-First: دائماً تستخدم Vision LLM

```
For each image:
  1. Send to GPT-4o/Claude
  2. Pay $0.005-0.01 per image

Problems:
- Expensive (85% of images could be free)
- Slow (network latency)
- Still hallucinates without constraints
```

### ثلاثة-Tier:LocalM SK2أول مع التزلج الذكي

```
For each image:
  1. OpenCV text detection (5-20ms, free)
  2. Route to appropriate tier
  3. Florence-2 handles 85% locally (200ms, free)
  4. Vision LLM only for complex cases (2-5s, $0.001-0.01)

Benefits:
- 88% cost reduction
- 77% faster (most images process locally)
- Deterministic escalation (auditable)
- Filmstrip optimization (30× token reduction)
- Constrained by deterministic signals
```

---


## الاستنتاجات

لقد أثبتت أنابيب الأوCR الثلاثية الـ - أن **Cost-aware routing** و **محلي- المعالجة الأولى** يمكنه تحسين الأداء والاقتصاد بشكل كبير دون أن يهدئ الجودة.

الملاحظات الرئيسية:

1. **فلورانس-2 أونكس هو المكان المناسب**: أفضل من Tesseract للخطوط المصممة, أسرع وأرخص من الـ Vision LLMs
2. **النص -لقطات فقط تحقق 30× تقليل الرموز**: نستخرج الصناديق المزدوجة, ليست إطارات كاملة
3. **التوجيه هو محدد**: إكتشاف CV المفتوح
4. **التسارع قابل للتحقق منه**: كل مستوى يصدر إشارات من provenance
5. **إن الفشل مرحاً**: سلسلة الأولوية تضمن العودة إلى أفضل مصدر متاح

مقياس النمط: **تحليل محلي ديميائي → نموذج ML محلي → تتصاعد السحاب**, كل الطبقة مع الخصائص المعروفة والتجارة بالتكاليف-offsM SK2

هذا هو الغموض المقيد الذي يطبق على الـ OCR : الإشارات التنقيبية ( اختبار اللاتغة \ , الكشف عن النص | ) نماذج تقليدية إفتراضية ♫ ( | فلورانس |-2, | الرؤية | LLM ٬ ), | والانتاج النهائي يجمع المصادر حسب الجودة ٬.

---


## الموارد

### مستندات LucidRAG

- **[مكتبة ImageSummarizer](https://github.com/scottgal/lucidrag/tree/main/src/Mostlylucid.DocSummarizer.Images)** - شفرة المصدر
- **[تكامل التصوير بالرسوم المتقاطعة](https://github.com/scottgal/lucidrag/blob/main/src/Mostlylucid.DocSummarizer.Images/docs/vision-ocr-integration.md)** - التنقلM SK1 شرائح الأفلام , إقتصاد الرموز
- **[دليل العمارة](https://github.com/scottgal/lucidrag/blob/main/src/Mostlylucid.DocSummarizer.Images/docs/architecture.md)** - موجاتM SK1 إشارات, تتصاعد
- **[مستندات أنابيب](https://github.com/scottgal/lucidrag/blob/main/src/Mostlylucid.DocSummarizer.Images/docs/pipelines.md)** - أوتوماتM SK1 متوازنة, طرق جودة
- **[الإشارات مرجعية](https://github.com/scottgal/lucidrag/blob/main/src/Mostlylucid.DocSummarizer.Images/docs/signals.md)** - دليل إشارات كامل

### أدوات CLI

- **[ImageSummarizer CLI](https://github.com/scottgal/lucidrag/tree/main/src/Mostlylucid.ImageSummarizer.Cli)** - कमांड-أداة خطية
- **[قراءة CLI](https://github.com/scottgal/lucidrag/blob/main/src/Mostlylucid.ImageSummarizer.Cli/README.md)** - الاستخدام والتركيب
- **[صور تجريبية](https://github.com/scottgal/lucidrag/tree/main/src/Mostlylucid.ImageSummarizer.Cli/demo-images)** - عينة GIF وشريحة الإطار

### أبحاث

- **[فلورانس-2 الورق](https://arxiv.org/abs/2311.06242)** - مايكروسوفت ' رؤية - نموذج اللغة
- **[كاشف نص شرقي](https://arxiv.org/abs/1704.03155)** - الكشف الفعال عن النص المشهد
- **[ورق CRAFT](https://arxiv.org/abs/1904.01941)** - إدراك منطقة الشخصية
- **[Real-ESRGAN](https://arxiv.org/abs/2107.10833)** - فائق عملي-دقة
- **[ورق قفص](https://arxiv.org/abs/2103.00020)** - تعلم نماذج بصرية قابلة للنقل

### المقالات المرتبطة

- **[جزء 4: استخبارات الصورة](/blog/constrained-fuzzy-image-intelligence)** - نظرة على فن العمارة الموجية
- **[DocSummarizer](/blog/building-a-document-summarizer-with-rag)** - أنابيب التحليل للوثائق
- **[المزيج للبيانات](/blog/datasummarizer-how-it-works)** - مقاربة رسم البيانات

---


## السلسلة

| جزء | نمط | تركيز |
|------|---------|-------|
| 1 | [الغموض المقيد](/blog/constrained-fuzziness-pattern) | عنصر واحد |
| 2 | [MoM مقيدة](/blog/constrained-mom-mixture-of-models) | أجزاء متعددة |
| 3 | [سحب السياق](/blog/constrained-fuzzy-context-dragging) | الوقت / الذاكرة |
| 4 | [ذكاء الصورة](/blog/constrained-fuzzy-image-intelligence) | فن العمارة الموجية, الأنماط |
| **4.1** | **الأنبوب الثلاثي -Tier OCR (هذه المقالة)** | **OCR, نماذج ONNX, شرائح الأفلام** |

**التالي**: الجزء 5 سيظهر كيف ImageSummarizer [DocSummarizer](/blog/building-a-document-summarizer-with-rag), و [المزيج للبيانات](/blog/datasummarizer-how-it-works) compose into multi-modal graph RAG with LucidRAG.

كل الأجزاء تتبع نفس المتغير: **مكونات الإحتمالية تقترح ; أن الأنظمة الثابتة تستمر**.