diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..8f184627159e88692267f006f764325dc16107e3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,31 @@ +# Python +__pycache__/ +*.py[cod] +*.egg-info/ +build/ +dist/ + +# Virtual environments +.venv/ + +# IDE +.vscode/ +.idea/ + +# OS +.DS_Store +Thumbs.db + +# Runtime data — large binary files (do NOT commit) +ocr_data/ +oneocr_extracted/ + +# Working space outputs +working_space/output/ + +# UV lock (optional — regenerated by uv) +uv.lock + +# Test images - too large for HF, stored locally +working_space/input/*.png + diff --git a/.python-version b/.python-version new file mode 100644 index 0000000000000000000000000000000000000000..e4fba2183587225f216eeada4c78dfab6b2e65f5 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.12 diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..8e8983b12508f71dc40ef3e2774b8e203cb3c686 --- /dev/null +++ b/README.md @@ -0,0 +1,397 @@ +# OneOCR — Reverse-Engineered Cross-Platform OCR Pipeline + +Full reimplementation of Microsoft's OneOCR engine from Windows Snipping Tool. +`.onemodel` encryption cracked, 34 ONNX models extracted, all custom ops replaced — runs on any OS with `onnxruntime`. + +--- + +## Project Status + +| Component | Status | Details | +|---|---|---| +| **.onemodel decryption** | ✅ Done | AES-256-CFB128, static key + IV | +| **Model extraction** | ✅ Done | 34 ONNX models, 33 config files | +| **Custom op unlocking** | ✅ Done | `OneOCRFeatureExtract` → `Gemm`/`Conv1x1` | +| **ONNX pipeline** | ⚠️ Partial | **53% match rate** vs DLL (10/19 test images) | +| **DLL pipeline** | ✅ Done | ctypes wrapper, Windows only | + +### Known ONNX Engine Limitations + +The Python reimplementation achieves **53% match rate** against the original DLL. Below is a detailed breakdown of the remaining issues. + +#### Issue 1: False FPN2 Detections (4 images) +**Images:** ocr_test 6, 13, 17, 18 +**Symptom:** Panel edges / dialog borders detected as text +**Cause:** FPN2 (stride=4) sees edges as text-like textures +**DLL solution:** `SeglinkProposals` — advanced C++ post-processing with multi-stage NMS: +- `textline_hardnms_iou_threshold = 0.32` +- `textline_groupnms_span_ratio_threshold = 0.3` +- `ambiguous_nms_threshold = 0.3` / `ambiguous_overlap_threshold = 0.5` +- `K_of_detections` — per-scale detection limit + +#### Issue 2: Missing Small Characters "..." (2 images) +**Images:** ocr_test 7, 14 +**Symptom:** Three dots too small to detect +**Cause:** Minimum `min_component_pixels` and `min_area` thresholds insufficient +**DLL solution:** `SeglinkGroup` — groups neighboring segments into a single line + +#### Issue 3: Character Recognition Errors (2 images) +**Images:** ocr_test 1, 15 +**Symptom:** "iob" instead of "job", extra text from margins +**Cause:** Differences in text cropping/preprocessing +**DLL solution:** `BaseNormalizer` — sophisticated text line normalization + +#### Issue 4: Large Images (test.png — 31.8% match) +**Symptom:** 55 of 74 lines detected, some cut off at edges +**Cause:** Adaptive Scaling — DLL scales at multiple levels +**DLL solution:** `AdaptiveScaling` with `AS_LARGE_TEXT_THRESHOLD` + +--- + +## Architecture + +``` +Image (PIL / numpy) + │ + ▼ +┌──────────────────────────────────┐ +│ Detector (model_00) │ PixelLink FPN (fpn2/3/4) +│ BGR, mean subtraction │ stride = 4 / 8 / 16 +│ → pixel_scores, link_scores │ 8-neighbor, Union-Find +│ → bounding quads (lines) │ minAreaRect + NMS (IoU 0.2) +└──────────────────────────────────┘ + │ + ▼ for each detected line +┌──────────────────────────────────┐ +│ Crop + padding (15%) │ Axis-aligned / perspective +│ ScriptID (model_01) │ 10 scripts: Latin, CJK, Arabic... +│ RGB / 255.0, height=60px │ HW/PC classification, flip detection +└──────────────────────────────────┘ + │ + ▼ per script +┌──────────────────────────────────┐ +│ Recognizer (model_02–10) │ DynamicQuantizeLSTM + CTC +│ Per-script character maps │ Greedy decode with per-char confidence +│ → text + word confidences │ Word splitting on spaces +└──────────────────────────────────┘ + │ + ▼ +┌──────────────────────────────────┐ +│ Line grouping & sorting │ Y-overlap clustering +│ Per-word bounding boxes │ Proportional quad interpolation +│ Text angle estimation │ Median of top-edge angles +└──────────────────────────────────┘ +``` + +### Model Registry (34 models) + +| Index | Role | Script | Custom Op | Status | +|-------|------|--------|-----------|--------| +| 0 | Detector | Universal | `QLinearSigmoid` | ✅ Works | +| 1 | ScriptID | Universal | — | ✅ Works | +| 2–10 | Recognizers | Latin/CJK/Arabic/Cyrillic/Devanagari/Greek/Hebrew/Tamil/Thai | `DynamicQuantizeLSTM` | ✅ Work | +| 11–21 | LangSm (confidence) | Per-script | `OneOCRFeatureExtract` → **Gemm** | ✅ Unlocked | +| 22–32 | LangMd (confidence) | Per-script | `OneOCRFeatureExtract` → **Gemm** | ✅ Unlocked | +| 33 | LineLayout | Universal | `OneOCRFeatureExtract` → **Conv1x1** | ✅ Unlocked | + +--- + +## Quick Start + +### Requirements + +```bash +pip install onnxruntime numpy opencv-python-headless Pillow pycryptodome onnx +``` + +Or with `uv`: +```bash +uv sync --extra extract +``` + +### Model Extraction (one-time) + +```bash +# Full pipeline: decrypt → extract → unlock → verify +python tools/extract_pipeline.py ocr_data/oneocr.onemodel + +# Verify existing models only +python tools/extract_pipeline.py --verify-only +``` + +### Usage + +```python +from ocr.engine_onnx import OcrEngineOnnx +from PIL import Image + +engine = OcrEngineOnnx() +result = engine.recognize_pil(Image.open("screenshot.png")) + +print(result.text) # "Hello World" +print(result.average_confidence) # 0.975 +print(result.text_angle) # 0.0 + +for line in result.lines: + for word in line.words: + print(f" '{word.text}' conf={word.confidence:.0%} " + f"bbox=({word.bounding_rect.x1:.0f},{word.bounding_rect.y1:.0f})") +``` + +### API Reference + +```python +engine = OcrEngineOnnx( + models_dir="path/to/onnx_models", # optional + config_dir="path/to/config_data", # optional + providers=["CUDAExecutionProvider"], # optional (default: CPU) +) + +# Input formats: +result = engine.recognize_pil(pil_image) # PIL Image +result = engine.recognize_numpy(rgb_array) # numpy (H,W,3) RGB +result = engine.recognize_bytes(png_bytes) # raw bytes (PNG/JPEG) + +# Result: +result.text # str — full recognized text +result.text_angle # float — detected rotation angle +result.lines # list[OcrLine] +result.average_confidence # float — overall confidence 0-1 +result.error # str | None — error message + +# Per-word: +word.text # str +word.confidence # float — CTC confidence per word +word.bounding_rect # BoundingRect (x1,y1...x4,y4 quadrilateral) +``` + +--- + +## Project Structure + +``` +ONEOCR/ +├── main.py # Usage example (both engines) +├── pyproject.toml # Project config & dependencies +├── README.md # This documentation +├── .gitignore +│ +├── ocr/ # Core OCR package +│ ├── __init__.py # Exports OcrEngine, OcrEngineOnnx, models +│ ├── engine.py # DLL wrapper (Windows only, 374 lines) +│ ├── engine_onnx.py # ONNX engine (cross-platform, ~1100 lines) +│ └── models.py # Data models: OcrResult, OcrLine, OcrWord +│ +├── tools/ # Utilities +│ ├── extract_pipeline.py # Extraction pipeline (decrypt→extract→unlock→verify) +│ ├── visualize_ocr.py # OCR result visualization with bounding boxes +│ └── test_quick.py # Quick OCR test on images +│ +├── ocr_data/ # Runtime data (DO NOT commit) +│ ├── oneocr.dll # Original DLL (Windows only) +│ ├── oneocr.onemodel # Encrypted model container +│ └── onnxruntime.dll # ONNX Runtime DLL +│ +├── oneocr_extracted/ # Extracted models (auto-generated) +│ ├── onnx_models/ # 34 raw ONNX (models 11-33 have custom ops) +│ ├── onnx_models_unlocked/ # 23 unlocked (models 11-33, standard ONNX ops) +│ └── config_data/ # Character maps, rnn_info, manifest, configs +│ +├── working_space/ # Test images +│ └── input/ # 19 test images +│ +└── _archive/ # Archive — RE scripts, analyses, prototypes + ├── temp/re_output/ # DLL reverse engineering results + ├── attempts/ # Decryption attempts + ├── analysis/ # Cryptographic analyses + └── hooks/ # Frida hooks +``` + +--- + +## Technical Details + +### .onemodel Encryption + +| Element | Value | +|---------|-------| +| Algorithm | AES-256-CFB128 | +| Master Key | `kj)TGtrK>f]b[Piow.gU+nC@s""""""4` (32B) | +| IV | `Copyright @ OneO` (16B) | +| DX key | `SHA256(master_key + file[8:24])` | +| Config key | `SHA256(DX[48:64] + DX[32:48])` | +| Chunk key | `SHA256(chunk_header[16:32] + chunk_header[0:16])` | + +### OneOCRFeatureExtract — Cracked Custom Op + +Proprietary op (domain `com.microsoft.oneocr`) stores weights as a **big-endian float32** blob in a STRING tensor. + +**Models 11–32** (21→50 features): +``` +config_blob (4492B, big-endian float32): + W[21×50] = 1050 floats (weight matrix) + b[50] = 50 floats (bias) + metadata = 23 floats (dimensions [21, 50, 2], flags, calibration) + + Replacement: Gemm(input, W^T, b) +``` + +**Model 33** (256→16 channels): +``` +config_blob (16548B, big-endian float32): + W[256×16] = 4096 floats (convolution weights) + b[16] = 16 floats (bias) + metadata = 25 floats (dimensions [256, 16], flags) + + Replacement: Conv(input, W[in,out].T → [16,256,1,1], b, kernel=1x1) +``` + +### Detector Configuration (from DLL protobuf manifest) + +``` +segment_conf_threshold: 0.7 (field 8) +textline_conf_threshold per-FPN: P2=0.7, P3=0.8, P4=0.8 (field 9) +textline_nms_threshold: 0.2 (field 10) +textline_overlap_threshold: 0.4 (field 11) +text_confidence_threshold: 0.8 (field 13) +ambiguous_nms_threshold: 0.3 (field 15) +ambiguous_overlap_threshold: 0.5 (field 16) +ambiguous_save_threshold: 0.4 (field 17) +textline_hardnms_iou_threshold: 0.32 (field 20) +textline_groupnms_span_ratio_threshold: 0.3 (field 21) +``` + +### PixelLink Detector + +- **FPN levels**: fpn2 (stride=4), fpn3 (stride=8), fpn4 (stride=16) +- **Outputs per level**: `scores_hori/vert` (pixel text probability), `link_scores_hori/vert` (8-neighbor connectivity), `bbox_deltas_hori/vert` (corner offsets) +- **Post-processing**: Threshold pixels → Union-Find connected components → bbox regression → NMS +- **Detects TEXT LINES** — word splitting comes from the recognizer + +### CTC Recognition + +- Target height: 60px, aspect ratio preserved +- Input: RGB / 255.0, NCHW format +- Output: log-softmax [T, 1, N_chars] +- Decoding: greedy argmax with repeat merging + blank removal +- Per-character confidence via `exp(max_logprob)` + +--- + +## DLL Reverse Engineering — Results & Materials + +### DLL Source Structure (from debug symbols) + +``` +C:\__w\1\s\CoreEngine\Native\ +├── TextDetector/ +│ ├── AdaptiveScaling ← multi-level image scaling +│ ├── SeglinkProposal ← KEY: detection post-processing +│ ├── SeglinkGroup.h ← segment grouping into lines +│ ├── TextLinePolygon ← precise text contouring +│ ├── RelationRCNNRpn2 ← relational region proposal network +│ ├── BaseRCNN, DQDETR ← alternative detectors +│ ├── PolyFitting ← polynomial fitting +│ └── BarcodePolygon ← barcode detection +│ +├── TextRecognizer/ +│ ├── TextLineRecognizerImpl ← main CTC implementation +│ ├── ArgMaxDecoder ← CTC decoding +│ ├── ConfidenceProcessor ← confidence models (models 11-21) +│ ├── RejectionProcessor ← rejection models (models 22-32) +│ ├── DbLstm ← dynamic batch LSTM +│ └── CharacterMap/ ← per-script character maps +│ +├── TextAnalyzer/ +│ ├── TextAnalyzerImpl ← text layout analysis +│ └── AuxMltClsClassifier ← auxiliary classifier +│ +├── TextNormalizer/ +│ ├── BaseNormalizer ← text line normalization +│ └── ConcatTextLines ← line concatenation +│ +├── TextPipeline/ +│ ├── TextPipelineDevImpl ← main pipeline +│ └── FilterXY ← position-based filtering +│ +├── CustomOps/onnxruntime/ +│ ├── SeglinkProposalsOp ← ONNX op (NOT in our models) +│ ├── XYSeglinkProposalsOp ← XY variant +│ └── FeatureExtractOp ← = Gemm / Conv1x1 +│ +├── ModelParser/ +│ ├── ModelParser ← .onemodel parsing +│ └── Crypto ← AES-256-CFB128 +│ +└── Common/ + ├── ImageUtility ← image conversion + └── ImageFeature ← image features +``` + +### RE Materials + +Reverse engineering results in `_archive/temp/re_output/`: +- `03_oneocr_classes.txt` — 186 C++ classes +- `06_config_strings.txt` — 429 config strings +- `15_manifest_decoded.txt` — 1182 lines of decoded protobuf manifest +- `09_constants.txt` — 42 float + 14 double constants (800.0, 0.7, 0.8, 0.92...) +- `10_disassembly.txt` — disassembly of key exports + +--- + +## For Future Developers — Roadmap + +### Priority 1: SeglinkProposals (hardest, highest impact) + +This is the key C++ post-processing in the DLL that is NOT part of the ONNX models. +Responsible for ~80% of the differences between the DLL and our implementation. + +**What it does:** +1. Takes raw pixel_scores + link_scores + bbox_deltas from all 3 FPN levels +2. Groups segments into lines (SeglinkGroup) — merges neighboring small components into a single line +3. Multi-stage NMS: textline_nms → hardnms → ambiguous_nms → groupnms +4. Confidence filtering with `text_confidence_threshold = 0.8` +5. `K_of_detections` — detection count limit + +**Where to look:** +- `_archive/temp/re_output/06_config_strings.txt` — parameter names +- `_archive/temp/re_output/15_manifest_decoded.txt` — parameter values +- `SeglinkProposal` class in DLL — ~2000 lines of C++ + +**Approach:** +- Decompile `SeglinkProposal::Process` with IDA Pro / Ghidra +- Alternatively: black-box testing of different NMS configurations + +### Priority 2: AdaptiveScaling + +The DLL dynamically scales images based on text size. + +**Parameters:** +- `AS_LARGE_TEXT_THRESHOLD` — large text threshold +- Multi-scale: DLL can run the detector at multiple scales + +### Priority 3: BaseNormalizer + +The DLL normalizes text crops before recognition more effectively than our simple resize. + +### Priority 4: Confidence/Rejection Models (11-32) + +The DLL uses models 11-32 to filter results — we skip them. Integration could improve +precision by removing false detections. + +--- + +## Performance + +| Operation | ONNX (CPU) | DLL | Notes | +|---|---|---|---| +| Detection (PixelLink) | ~50-200ms | ~15-50ms | Model inference + post-processing | +| ScriptID | ~5ms | ~3ms | Single forward pass | +| Recognition (CTC) | ~30ms/line | ~10ms/line | Per-script LSTM | +| Full pipeline | ~300-1000ms | ~15-135ms | Depends on line count | + +--- + +## License + +For research and educational purposes only. diff --git a/_archive/analysis/analyze_boundaries.py b/_archive/analysis/analyze_boundaries.py new file mode 100644 index 0000000000000000000000000000000000000000..4cf1008a93c275a06da26fc479d030e73912ac4e --- /dev/null +++ b/_archive/analysis/analyze_boundaries.py @@ -0,0 +1,91 @@ +"""Analyze exact chunk boundary structure in the .onemodel file.""" +import struct, json + +with open("ocr_data/oneocr.onemodel", "rb") as f: + fdata = f.read() +log = json.load(open("temp/crypto_log.json")) + +sha256s = [op for op in log if op["op"] == "sha256"] +sha_map = {s["output"]: s["input"] for s in sha256s} +decrypts = [op for op in log if op["op"] == "decrypt"] + +# Get info for first few payload chunks +def get_chunk_info(dec_idx): + d = decrypts[dec_idx] + sha_inp = bytes.fromhex(sha_map[d["aes_key"]]) + s1, s2 = struct.unpack_from(" 0: + prev = infos[i-1] + # Hypothesis: on-disk encrypted data = size1 + 8 (data_size + container_header) + prev_data_start = prev['chk_pos'] + 32 + prev_on_disk = prev['size1'] + 8 + expected_next_chk = prev_data_start + prev_on_disk + actual_next_chk = info['chk_pos'] + delta = actual_next_chk - expected_next_chk + print(f" Expected chk_pos: {expected_next_chk}, actual: {actual_next_chk}, delta: {delta}") + +# Now figure out the EXACT header structure +print("\n=== Bytes around first few chunk boundaries ===\n") + +# Between DX and first chunk +dx_end = 24 + 22624 # = 22648 +print(f"--- DX end ({dx_end}) to first chunk ---") +for off in range(dx_end, infos[0]['chk_pos'] + 48, 8): + raw = fdata[off:off+8] + val = struct.unpack_from("8}: {raw.hex()} (uint64={val})") + +# Between chunk 0 and chunk 1 +c0 = infos[0] +c1 = infos[1] +# data starts at chk_pos + 32, on-disk size is approximately size1+8 or enc_size +# Let's look at bytes around where the boundary should be +c0_data_start = c0['chk_pos'] + 32 +c0_approx_end = c0_data_start + c0['size1'] + 8 +print(f"\n--- End of dec#{c0['dec_idx']:02d} / Start of dec#{c1['dec_idx']:02d} ---") +print(f" c0 data_start: {c0_data_start}") +print(f" c0 size1+8: {c0['size1']+8}") +print(f" c0 approx end: {c0_approx_end}") +print(f" c1 chk_pos: {c1['chk_pos']}") + +for off in range(c0_approx_end - 16, c1['chk_pos'] + 48, 8): + raw = fdata[off:off+8] + val = struct.unpack_from("8}: {raw.hex()} val={val:<15d} {ascii_s}") + +# Check file header +header_size = struct.unpack_from("3}: {raw.hex()} uint64={val}") diff --git a/_archive/analysis/analyze_crypto_log.py b/_archive/analysis/analyze_crypto_log.py new file mode 100644 index 0000000000000000000000000000000000000000..82cc09edb2e899abec0967f1d63b6720e7595742 --- /dev/null +++ b/_archive/analysis/analyze_crypto_log.py @@ -0,0 +1,95 @@ +"""Analyze crypto_log.json to understand decrypt sequence and chunk mapping.""" +import json +import struct + +with open("temp/crypto_log.json") as f: + log = json.load(f) + +decrypts = [op for op in log if op["op"] == "decrypt"] +sha256s = [op for op in log if op["op"] == "sha256"] +encrypts = [op for op in log if op["op"] == "encrypt"] + +print(f"Total ops: {len(log)} (sha256={len(sha256s)}, decrypt={len(decrypts)}, encrypt={len(encrypts)})") + +# Build SHA256 output -> input mapping +sha_map = {} # output_hex -> input_hex +for s in sha256s: + sha_map[s["output"]] = s["input"] + +# Pair each decrypt with its SHA256 key derivation +print("\n=== Decrypt operations with key derivation ===") +for i, d in enumerate(decrypts): + key = d["aes_key"] + sha_input_hex = sha_map.get(key, "UNKNOWN") + sha_input = bytes.fromhex(sha_input_hex) if sha_input_hex != "UNKNOWN" else b"" + + if len(sha_input) == 48: + desc = "DX_KEY (master+file[8:24])" + elif len(sha_input) == 32: + s1, s2 = struct.unpack_from("8}B {desc:50s} out={first}") + +# Now search for plaintext first_bytes in decrypted DX to find embedded chunks +dx = open("temp/dx_index_decrypted.bin", "rb").read() +fdata = open("ocr_data/oneocr.onemodel", "rb").read() + +print("\n=== Locating encrypted data ===") +for i, d in enumerate(decrypts): + size = d["input_size"] + first = bytes.fromhex(d["first_bytes"][:32]) + + # Search in decrypted DX for the plaintext (this was decrypted in-place) + # But we need the CIPHERTEXT, which is in the original file (encrypted DX) or payload + + # For chunks embedded in DX: ciphertext is at file offset 24 + dx_offset + # For chunks in payload: ciphertext is at some file offset after 22684 + + # Let's find plaintext in decrypted DX + dx_pos = dx.find(first) + + # Find ciphertext (first 16 bytes from hook_decrypt dumps) + # We don't have ciphertext in logs, but we know: + # - DX encrypted data is at file[24:24+22624] + # - Payload data is after file[22684] + + if i == 0: + loc = "DX index itself at file[24:]" + elif dx_pos >= 0: + loc = f"embedded in DX at dx_offset={dx_pos} (file_off={24+dx_pos})" + else: + loc = "payload (after file[22684])" + + print(f" dec#{i:02d}: size={size:>8}B {loc}") + +# Scan DX for all uint64 pairs where second = first + 24 +print("\n=== All size-pair patterns in DX (s2 = s1 + 24) ===") +pairs = [] +for off in range(0, len(dx) - 16): + s1, s2 = struct.unpack_from(" 10: + pairs.append((off, s1, s2)) +print(f"Found {len(pairs)} size pairs") +# Deduplicate overlapping pairs +filtered = [] +for p in pairs: + if not filtered or p[0] >= filtered[-1][0] + 16: + filtered.append(p) +print(f"After dedup: {len(filtered)} pairs") +for off, s1, s2 in filtered: + # Check if there's a 16-byte checksum before this pair + has_chk = False + if off >= 16: + # Check if the 16 bytes before could be a checksum (non-trivial bytes) + potential_chk = dx[off-16:off] + non_zero = sum(1 for b in potential_chk if b != 0) + has_chk = non_zero > 8 # At least 8 non-zero bytes + print(f" offset={off:>5} (0x{off:04x}): sizes=({s1}, {s2}) chk_before={'YES' if has_chk else 'no'}") diff --git a/_archive/analysis/analyze_decrypt.py b/_archive/analysis/analyze_decrypt.py new file mode 100644 index 0000000000000000000000000000000000000000..229ea1e50caefb8a58850b72d7a68fcae1fb67d1 --- /dev/null +++ b/_archive/analysis/analyze_decrypt.py @@ -0,0 +1,581 @@ +""" +OneOCR .onemodel file analysis and decryption attempt. + +Known facts: +- AES-256-CFB via Windows BCrypt CNG API +- SHA256 used somewhere in the process +- Key: kj)TGtrK>f]b[Piow.gU+nC@s""""""4 (32 ASCII bytes = 256 bits) +- After decryption → decompression (zlib/lz4/etc.) +- Error on wrong key: meta->magic_number == MAGIC_NUMBER (0 vs. 1) +""" + +import struct +import hashlib +import zlib +import os +from collections import Counter +from typing import Optional + +# ── Try to import crypto libraries ── +try: + from Crypto.Cipher import AES as PyCryptoAES + HAS_PYCRYPTODOME = True +except ImportError: + HAS_PYCRYPTODOME = False + print("[WARN] PyCryptodome not available, install with: pip install pycryptodome") + +try: + from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes + from cryptography.hazmat.backends import default_backend + HAS_CRYPTOGRAPHY = True +except ImportError: + HAS_CRYPTOGRAPHY = False + print("[WARN] cryptography not available, install with: pip install cryptography") + + +# ═══════════════════════════════════════════════════════════════ +# CONFIGURATION +# ═══════════════════════════════════════════════════════════════ + +MODEL_PATH = r"c:\Users\MattyMroz\Desktop\PROJECTS\ONEOCR\ocr_data\oneocr.onemodel" + +# The key as raw bytes (32 bytes = 256 bits for AES-256) +KEY_RAW = b'kj)TGtrK>f]b[Piow.gU+nC@s""""""4' +assert len(KEY_RAW) == 32, f"Key must be 32 bytes, got {len(KEY_RAW)}" + +# SHA256 of the key (another possible key derivation) +KEY_SHA256 = hashlib.sha256(KEY_RAW).digest() + + +# ═══════════════════════════════════════════════════════════════ +# HELPER FUNCTIONS +# ═══════════════════════════════════════════════════════════════ + +def hex_dump(data: bytes, offset: int = 0, max_lines: int = 32) -> str: + """Format bytes as hex dump with ASCII column.""" + lines = [] + for i in range(0, min(len(data), max_lines * 16), 16): + hex_part = " ".join(f"{b:02x}" for b in data[i:i+16]) + ascii_part = "".join(chr(b) if 32 <= b < 127 else "." for b in data[i:i+16]) + lines.append(f" {offset+i:08x}: {hex_part:<48s} {ascii_part}") + return "\n".join(lines) + + +def entropy(data: bytes) -> float: + """Calculate Shannon entropy (0-8 bits per byte).""" + if not data: + return 0.0 + import math + freq = Counter(data) + total = len(data) + return -sum((c / total) * math.log2(c / total) for c in freq.values()) + + +def unique_byte_ratio(data: bytes) -> str: + """Return unique bytes count.""" + return f"{len(set(data))}/256" + + +def check_known_headers(data: bytes) -> list[str]: + """Check if data starts with known file/compression magic numbers.""" + findings = [] + if len(data) < 4: + return findings + + # Magic number checks + magics = { + b"\x08": "Protobuf varint field tag (field 1, wire type 0)", + b"\x0a": "Protobuf length-delimited field tag (field 1, wire type 2)", + b"\x78\x01": "Zlib (low compression)", + b"\x78\x5e": "Zlib (default compression)", + b"\x78\x9c": "Zlib (best speed/default)", + b"\x78\xda": "Zlib (best compression)", + b"\x1f\x8b": "Gzip", + b"\x04\x22\x4d\x18": "LZ4 frame", + b"\x28\xb5\x2f\xfd": "Zstandard", + b"\xfd\x37\x7a\x58\x5a\x00": "XZ", + b"\x42\x5a\x68": "Bzip2", + b"PK": "ZIP archive", + b"\x89PNG": "PNG image", + b"ONNX": "ONNX text", + b"\x08\x00": "Protobuf: field 1, varint, value will follow", + b"\x08\x01": "Protobuf: field 1, varint = 1 (could be magic_number=1!)", + b"\x08\x02": "Protobuf: field 1, varint = 2", + b"\x08\x03": "Protobuf: field 1, varint = 3", + b"\x08\x04": "Protobuf: field 1, varint = 4", + b"\x50\x42": "Possible PB (protobuf) marker", + b"\x01\x00\x00\x00": "uint32 LE = 1 (possible magic_number=1)", + b"\x00\x00\x00\x01": "uint32 BE = 1 (possible magic_number=1)", + } + + for magic, desc in magics.items(): + if data[:len(magic)] == magic: + findings.append(f" ★ MATCH: {desc} ({magic.hex()})") + + # Check first uint32 LE/BE + u32_le = struct.unpack_from("I", data, 0)[0] + if u32_le == 1: + findings.append(f" ★ uint32_LE at offset 0 = 1 (MAGIC_NUMBER match!)") + if u32_be == 1: + findings.append(f" ★ uint32_BE at offset 0 = 1 (MAGIC_NUMBER match!)") + + return findings + + +def try_decompress(data: bytes, label: str = "") -> Optional[bytes]: + """Try various decompression methods.""" + results = [] + + # Zlib (with and without header) + for wbits in [15, -15, 31]: # standard, raw deflate, gzip + try: + dec = zlib.decompress(data, wbits) + results.append(("zlib" + (f" wbits={wbits}" if wbits != 15 else ""), dec)) + except: + pass + + # LZ4 + try: + import lz4.frame + dec = lz4.frame.decompress(data) + results.append(("lz4.frame", dec)) + except: + pass + + try: + import lz4.block + for size in [1 << 20, 1 << 22, 1 << 24]: + try: + dec = lz4.block.decompress(data, uncompressed_size=size) + results.append((f"lz4.block (uncompressed_size={size})", dec)) + break + except: + pass + except: + pass + + # Zstandard + try: + import zstandard as zstd + dctx = zstd.ZstdDecompressor() + dec = dctx.decompress(data, max_output_size=len(data) * 10) + results.append(("zstandard", dec)) + except: + pass + + if results: + for method, dec in results: + print(f" ✓ {label} Decompression SUCCESS with {method}: {len(dec)} bytes") + print(f" First 64 bytes: {dec[:64].hex()}") + print(f" Entropy: {entropy(dec[:4096]):.3f}, unique: {unique_byte_ratio(dec[:4096])}") + headers = check_known_headers(dec) + for h in headers: + print(f" {h}") + return results[0][1] + return None + + +def decrypt_aes_cfb(data: bytes, key: bytes, iv: bytes, segment_size: int = 8) -> Optional[bytes]: + """Decrypt using AES-CFB with given parameters.""" + if HAS_PYCRYPTODOME: + try: + cipher = PyCryptoAES.new(key, PyCryptoAES.MODE_CFB, iv=iv, segment_size=segment_size) + return cipher.decrypt(data) + except Exception as e: + return None + + if HAS_CRYPTOGRAPHY: + try: + if segment_size == 128: + cipher = Cipher(algorithms.AES(key), modes.CFB(iv), backend=default_backend()) + elif segment_size == 8: + cipher = Cipher(algorithms.AES(key), modes.CFB8(iv), backend=default_backend()) + else: + return None + decryptor = cipher.decryptor() + return decryptor.update(data) + decryptor.finalize() + except Exception as e: + return None + + return None + + +def analyze_decrypted(data: bytes, label: str) -> bool: + """Analyze decrypted data and return True if it looks promising.""" + if data is None: + return False + + ent = entropy(data[:4096]) + unique = unique_byte_ratio(data[:4096]) + headers = check_known_headers(data) + + is_promising = ( + ent < 7.5 or # reduced entropy + len(headers) > 0 or # known header match + data[:4] == b"\x01\x00\x00\x00" or # magic_number = 1 LE + data[:4] == b"\x00\x00\x00\x01" or # magic_number = 1 BE + data[:2] == b"\x08\x01" # protobuf magic_number = 1 + ) + + if is_promising: + print(f" ★★★ PROMISING: {label}") + print(f" Entropy: {ent:.3f}, Unique bytes: {unique}") + print(f" First 128 bytes:") + print(hex_dump(data[:128])) + for h in headers: + print(f" {h}") + + # Try decompression on promising results + try_decompress(data, label) + + # If starts with protobuf-like data or magic=1, also try decompressing after skipping some bytes + for skip in [4, 8, 12, 16, 20]: + if len(data) > skip + 10: + try_decompress(data[skip:], f"{label} [skip {skip} bytes]") + + return True + return False + + +# ═══════════════════════════════════════════════════════════════ +# MAIN ANALYSIS +# ═══════════════════════════════════════════════════════════════ + +def main(): + print("=" * 80) + print("OneOCR .onemodel File Analysis & Decryption Attempt") + print("=" * 80) + + # ── Step 1: Read file ── + with open(MODEL_PATH, "rb") as f: + full_data = f.read() + + filesize = len(full_data) + print(f"\nFile size: {filesize:,} bytes ({filesize/1024/1024:.2f} MB)") + + # ── Step 2: Parse top-level structure ── + print("\n" + "═" * 80) + print("SECTION 1: FILE STRUCTURE ANALYSIS") + print("═" * 80) + + header_offset = struct.unpack_from(" 0 and u32 < filesize: + print(f" +{i:3d}: u32={u32:12,d} (0x{u32:08x})" + f" {'← could be offset/size' if 100 < u32 < filesize else ''}") + + # ── Step 6: Hash analysis of key ── + print("\n" + "═" * 80) + print("SECTION 2: KEY ANALYSIS") + print("═" * 80) + print(f"\n Raw key ({len(KEY_RAW)} bytes): {KEY_RAW}") + print(f" Raw key hex: {KEY_RAW.hex()}") + print(f" SHA256 of key: {KEY_SHA256.hex()}") + + # Check if SHA256 of key appears in the file header + if KEY_SHA256 in full_data[:header_offset + 256]: + idx = full_data.index(KEY_SHA256) + print(f" ★ SHA256 of key FOUND in file at offset {idx}!") + else: + print(f" SHA256 of key not found in first {header_offset + 256} bytes") + + # Check if the 8-byte magic at offset 22636 could be related to key hash + key_sha256_first8 = KEY_SHA256[:8] + print(f" First 8 bytes of SHA256(key): {key_sha256_first8.hex()}") + print(f" 8 bytes at offset {header_offset}: {meta_magic_8.hex()}") + print(f" Match: {'YES ★' if key_sha256_first8 == meta_magic_8 else 'NO'}") + + # ── Step 7: Decryption attempts ── + print("\n" + "═" * 80) + print("SECTION 3: DECRYPTION ATTEMPTS") + print("═" * 80) + + # Prepare IV candidates + iv_zero = b"\x00" * 16 + iv_from_8 = full_data[8:24] + iv_from_4 = full_data[4:20] + iv_from_file_start = full_data[0:16] + iv_from_meta = full_data[header_offset:header_offset + 16] + iv_from_meta_8 = meta_magic_8 + b"\x00" * 8 # pad the 8-byte magic to 16 + + # SHA256 of key, take first 16 bytes as IV + iv_sha256_key_first16 = KEY_SHA256[:16] + + iv_candidates = { + "all-zeros": iv_zero, + "file[8:24]": iv_from_8, + "file[4:20]": iv_from_4, + "file[0:16]": iv_from_file_start, + f"file[{header_offset}:{header_offset+16}]": iv_from_meta, + "meta_magic+padding": iv_from_meta_8, + "SHA256(key)[:16]": iv_sha256_key_first16, + } + + # Key candidates + key_candidates = { + "RAW key (32 bytes)": KEY_RAW, + "SHA256(RAW key)": KEY_SHA256, + } + + # Data regions to try decrypting + # We try both the header data and the start of the encrypted payload + regions = { + "header[8:22636]": full_data[8:min(8 + 4096, header_offset)], + f"payload[{encrypted_start}:]": full_data[encrypted_start:encrypted_start + 4096], + } + + # Also try: what if the entire region from byte 8 to end is one encrypted blob? + regions["all_encrypted[8:]"] = full_data[8:8 + 4096] + + # Segment sizes: Windows BCrypt CFB defaults to 8-bit (CFB8), also try 128-bit (CFB128) + segment_sizes = [8, 128] + + total_attempts = 0 + promising_results = [] + + for key_name, key in key_candidates.items(): + for iv_name, iv in iv_candidates.items(): + for seg_size in segment_sizes: + for region_name, region_data in regions.items(): + total_attempts += 1 + label = f"key={key_name}, iv={iv_name}, CFB{seg_size}, region={region_name}" + + decrypted = decrypt_aes_cfb(region_data, key, iv, seg_size) + if decrypted and analyze_decrypted(decrypted, label): + promising_results.append(label) + + print(f"\n Total attempts: {total_attempts}") + print(f" Promising results: {len(promising_results)}") + + # ── Step 8: Additional IV strategies ── + print("\n" + "═" * 80) + print("SECTION 4: ADVANCED IV STRATEGIES") + print("═" * 80) + + # Strategy: IV might be derived from the file content + # Try every 16-byte aligned position in the first 256 bytes as IV + print("\n Trying every 16-byte aligned offset in first 256 bytes as IV...") + + for iv_offset in range(0, 256, 4): # try every 4-byte step + iv_cand = full_data[iv_offset:iv_offset + 16] + if len(iv_cand) < 16: + continue + + for key in [KEY_RAW, KEY_SHA256]: + for seg in [8, 128]: + # Try decrypting the payload + payload_start = encrypted_start + test_data = full_data[payload_start:payload_start + 4096] + decrypted = decrypt_aes_cfb(test_data, key, iv_cand, seg) + if decrypted: + is_good = analyze_decrypted(decrypted, + f"iv_offset={iv_offset}, key={'raw' if key == KEY_RAW else 'sha256'}, CFB{seg}, payload") + if is_good: + promising_results.append(f"Advanced: iv_offset={iv_offset}") + + # Try decrypting from byte 8 (header encrypted area) + test_data2 = full_data[8:8 + 4096] + decrypted2 = decrypt_aes_cfb(test_data2, key, iv_cand, seg) + if decrypted2: + is_good = analyze_decrypted(decrypted2, + f"iv_offset={iv_offset}, key={'raw' if key == KEY_RAW else 'sha256'}, CFB{seg}, header[8:]") + if is_good: + promising_results.append(f"Advanced: iv_offset={iv_offset} header") + + # ── Step 9: Try with IV = SHA256 of various things ── + print("\n" + "═" * 80) + print("SECTION 5: DERIVED IV STRATEGIES") + print("═" * 80) + + derived_ivs = { + "SHA256(key)[:16]": hashlib.sha256(KEY_RAW).digest()[:16], + "SHA256(key)[16:]": hashlib.sha256(KEY_RAW).digest()[16:], + "SHA256('')[:16]": hashlib.sha256(b"").digest()[:16], + "MD5(key)": hashlib.md5(KEY_RAW).digest(), + "SHA256(file[0:8])[:16]": hashlib.sha256(full_data[0:8]).digest()[:16], + "SHA256(file[0:4])[:16]": hashlib.sha256(full_data[0:4]).digest()[:16], + "SHA256('oneocr')[:16]": hashlib.sha256(b"oneocr").digest()[:16], + "SHA256('oneocr.onemodel')[:16]": hashlib.sha256(b"oneocr.onemodel").digest()[:16], + } + + for iv_name, iv in derived_ivs.items(): + for key_name, key in key_candidates.items(): + for seg in [8, 128]: + for region_name, region_data in regions.items(): + label = f"key={key_name}, iv={iv_name}, CFB{seg}, region={region_name}" + decrypted = decrypt_aes_cfb(region_data, key, iv, seg) + if decrypted and analyze_decrypted(decrypted, label): + promising_results.append(label) + + # ── Step 10: What if the structure is different? ── + print("\n" + "═" * 80) + print("SECTION 6: ALTERNATIVE STRUCTURE HYPOTHESES") + print("═" * 80) + + # Hypothesis A: Bytes 0-3 = offset, 4-7 = 0, 8-23 = IV, 24+ = encrypted data + print("\n Hypothesis A: [0-3]=offset, [4-7]=flags, [8-23]=IV, [24+]=encrypted") + iv_hyp_a = full_data[8:24] + encrypted_hyp_a = full_data[24:24 + 4096] + for key_name, key in key_candidates.items(): + for seg in [8, 128]: + dec = decrypt_aes_cfb(encrypted_hyp_a, key, iv_hyp_a, seg) + if dec: + analyze_decrypted(dec, f"HypA: key={key_name}, CFB{seg}") + + # Hypothesis B: [0-7]=header, [8-23]=IV, [24-22635]=encrypted meta, then payload also encrypted + print("\n Hypothesis B: [0-7]=header, [22636-22651]=16-byte meta, payload starts at 22652") + print(f" If meta[22636:22652] contains IV for payload:") + iv_hyp_b = full_data[header_offset:header_offset + 16] + enc_payload = full_data[encrypted_start:encrypted_start + 4096] + for key_name, key in key_candidates.items(): + for seg in [8, 128]: + dec = decrypt_aes_cfb(enc_payload, key, iv_hyp_b, seg) + if dec: + analyze_decrypted(dec, f"HypB: key={key_name}, CFB{seg}, payload with meta-IV") + + # Hypothesis C: The entire file from byte 8 to end is one encrypted stream (IV = zeros) + print("\n Hypothesis C: Single encrypted stream from byte 8, IV=zeros") + single_stream = full_data[8:8 + 4096] + for key_name, key in key_candidates.items(): + for seg in [8, 128]: + dec = decrypt_aes_cfb(single_stream, key, iv_zero, seg) + if dec: + analyze_decrypted(dec, f"HypC: key={key_name}, CFB{seg}") + + # Hypothesis D: Encrypted data starts right at byte 0 (the header_size field IS part of encrypted data) + # This would mean the header_size value 22636 is coincidental + print("\n Hypothesis D: Encrypted from byte 0, IV=zeros") + for key_name, key in key_candidates.items(): + for seg in [8, 128]: + dec = decrypt_aes_cfb(full_data[:4096], key, iv_zero, seg) + if dec: + analyze_decrypted(dec, f"HypD: key={key_name}, CFB{seg}, from byte 0") + + # Hypothesis E: Windows CNG might prepend IV to ciphertext + # So bytes 0-3 = header_size, 4-7 = 0, 8-23 = IV (embedded in encrypted blob), 24+ = ciphertext + print("\n Hypothesis E: IV prepended to ciphertext at various offsets") + for data_start in [0, 4, 8]: + iv_e = full_data[data_start:data_start + 16] + ct_e = full_data[data_start + 16:data_start + 16 + 4096] + for key_name, key in key_candidates.items(): + for seg in [8, 128]: + dec = decrypt_aes_cfb(ct_e, key, iv_e, seg) + if dec: + analyze_decrypted(dec, f"HypE: data_start={data_start}, key={key_name}, CFB{seg}") + + # ── Step 11: Try OFB and CTR modes too (just in case CFB was misidentified) ── + print("\n" + "═" * 80) + print("SECTION 7: ALTERNATIVE CIPHER MODES (OFB, CBC)") + print("═" * 80) + + if HAS_PYCRYPTODOME: + for data_start in [8, 24, encrypted_start]: + for iv_offset in [0, 4, 8]: + iv_alt = full_data[iv_offset:iv_offset + 16] + test_data = full_data[data_start:data_start + 4096] + for key in [KEY_RAW, KEY_SHA256]: + key_label = "raw" if key == KEY_RAW else "sha256" + + # OFB + try: + cipher = PyCryptoAES.new(key, PyCryptoAES.MODE_OFB, iv=iv_alt) + dec = cipher.decrypt(test_data) + analyze_decrypted(dec, f"OFB: data@{data_start}, iv@{iv_offset}, key={key_label}") + except: + pass + + # CBC (needs padding but try anyway) + try: + cipher = PyCryptoAES.new(key, PyCryptoAES.MODE_CBC, iv=iv_alt) + dec = cipher.decrypt(test_data) + analyze_decrypted(dec, f"CBC: data@{data_start}, iv@{iv_offset}, key={key_label}") + except: + pass + + # ECB (no IV) + try: + cipher = PyCryptoAES.new(key, PyCryptoAES.MODE_ECB) + # ECB needs data aligned to 16 bytes + aligned = test_data[:len(test_data) - (len(test_data) % 16)] + dec = cipher.decrypt(aligned) + analyze_decrypted(dec, f"ECB: data@{data_start}, key={key_label}") + except: + pass + + # ── Step 12: Summary ── + print("\n" + "═" * 80) + print("SUMMARY") + print("═" * 80) + + print(f"\n File structure (confirmed):") + print(f" [0x0000 - 0x0007] 8-byte header: offset = {header_offset}") + print(f" [0x0008 - 0x{header_offset-1:04x}] Encrypted header data ({header_offset - 8} bytes)") + print(f" [0x{header_offset:04x} - 0x{header_offset+7:04x}] 8-byte magic/hash: {meta_magic_8.hex()}") + print(f" [0x{header_offset+8:04x} - 0x{header_offset+15:04x}] uint64 payload size: {meta_size:,}") + print(f" [0x{encrypted_start:04x} - 0x{filesize-1:07x}] Encrypted payload ({encrypted_size:,} bytes)") + + print(f"\n Key info:") + print(f" Raw key: {KEY_RAW}") + print(f" Raw key hex: {KEY_RAW.hex()}") + print(f" SHA256(key): {KEY_SHA256.hex()}") + + print(f"\n Total promising decryption results: {len(promising_results)}") + for r in promising_results: + print(f" ★ {r}") + + if not promising_results: + print("\n No successful decryption found with standard approaches.") + print(" Possible reasons:") + print(" 1. The key might be processed differently (PBKDF2, HKDF, etc.)") + print(" 2. The IV might be derived in a non-standard way") + print(" 3. The file structure might be more complex") + print(" 4. The CBC/CFB segment size might be non-standard") + print(" 5. There might be additional authentication (AEAD)") + print(" 6. The BCrypt CNG API might use specific key blob format") + print(" 7. Think about BCRYPT_KEY_DATA_BLOB_HEADER structure") + + +if __name__ == "__main__": + main() diff --git a/_archive/analysis/analyze_dx.py b/_archive/analysis/analyze_dx.py new file mode 100644 index 0000000000000000000000000000000000000000..01fe0c1fc7925ee528f22f2c99778cae95d9ca11 --- /dev/null +++ b/_archive/analysis/analyze_dx.py @@ -0,0 +1,137 @@ +"""Analyze DX index structure to understand chunk record format.""" +import hashlib +import struct +import json +from pathlib import Path +from Crypto.Cipher import AES + +KEY = b'kj)TGtrK>f]b[Piow.gU+nC@s""""""4' +IV = b"Copyright @ OneO" + +file_data = Path("ocr_data/oneocr.onemodel").read_bytes() + +# Step 1: Decrypt DX +header_hash = file_data[8:24] +dx_key = hashlib.sha256(KEY + header_hash).digest() +encrypted_dx = file_data[24:24 + 22624] +cipher = AES.new(dx_key, AES.MODE_CFB, iv=IV, segment_size=128) +dx = cipher.decrypt(encrypted_dx) +assert dx[:2] == b"DX" + +# Load crypto log +crypto_log = json.load(open("temp/crypto_log.json")) + +# Get unique SHA256 inputs in order +sha_ops = [x for x in crypto_log if x['op'] == 'sha256'] +seen = set() +unique_sha = [] +for s in sha_ops: + if s['input'] not in seen: + seen.add(s['input']) + unique_sha.append(s) + +# Get decrypt ops +dec_ops = [x for x in crypto_log if x['op'] == 'decrypt'] + +# For each SHA256 input, find its position in DX +print("=" * 80) +print("DX Index Structure Analysis") +print("=" * 80) +print(f"DX size: {len(dx)} bytes, valid: {struct.unpack('= 0: + print(f"SHA256 #{i:3d}: len={s['input_len']:2d} found at DX offset {pos:5d} (0x{pos:04x})") + elif pos_partial >= 0: + # The input might be rearranged from DX + size1 = struct.unpack(' 16 else b"" + + # Check if sizes and checksum are nearby but in different order + pos_sizes = dx.find(inp[:16]) + pos_check = dx.find(checksum) if checksum else -1 + + if pos_sizes >= 0: + print(f"SHA256 #{i:3d}: len={s['input_len']:2d} sizes at DX offset {pos_sizes:5d}, checksum at {pos_check}") + else: + # Sizes might be in different order or interleaved + pos_s1 = dx.find(first_uint64) + print(f"SHA256 #{i:3d}: len={s['input_len']:2d} first_uint64 at DX offset {pos_s1:5d} (rearranged?)") + + size1 = struct.unpack(' len(dx): + break + chunk = dx[pos:pos+16] + hex_str = ' '.join(f'{b:02x}' for b in chunk) + ascii_str = ''.join(chr(b) if 32 <= b < 127 else '.' for b in chunk) + print(f" {pos:5d} ({pos:#06x}): {hex_str:<48s} {ascii_str}") + +# Look at the area around found patterns +for name, dx_off in [("Chunk2(encrypt) 0x2ed7", 0x2ed7), + ("Chunk4(ONNX) 0x2f80", 0x2f80), + ("Chunk5(ONNX2) 0x4692", 0x4692)]: + print(f"\n--- Area around {name} ---") + start = max(0, dx_off - 48) + for j in range(0, 128, 16): + pos = start + j + if pos + 16 > len(dx): + break + chunk = dx[pos:pos+16] + hex_str = ' '.join(f'{b:02x}' for b in chunk) + ascii_str = ''.join(chr(b) if 32 <= b < 127 else '.' for b in chunk) + marker = " <<<" if pos == dx_off else "" + print(f" {pos:5d} ({pos:#06x}): {hex_str:<48s} {ascii_str}{marker}") diff --git a/_archive/analysis/analyze_extracted.py b/_archive/analysis/analyze_extracted.py new file mode 100644 index 0000000000000000000000000000000000000000..8c572e527342dbdc02c8e157a2e141528978509b --- /dev/null +++ b/_archive/analysis/analyze_extracted.py @@ -0,0 +1,145 @@ +"""Manually parse protobuf structure of extracted files.""" +from pathlib import Path + +EXTRACT_DIR = Path(r"c:\Users\MattyMroz\Desktop\PROJECTS\ONEOCR\extracted_models") + +def read_varint(data, pos): + val = 0 + shift = 0 + while pos < len(data): + b = data[pos] + pos += 1 + val |= (b & 0x7f) << shift + if not (b & 0x80): + break + shift += 7 + return val, pos + +def parse_protobuf_fields(data, max_fields=10): + """Parse protobuf wire format and return field info.""" + pos = 0 + fields = [] + for _ in range(max_fields): + if pos >= len(data): + break + tag_byte = data[pos] + field_num = tag_byte >> 3 + wire_type = tag_byte & 0x07 + pos += 1 + + if wire_type == 0: # varint + val, pos = read_varint(data, pos) + fields.append((field_num, 'varint', val, None)) + elif wire_type == 2: # length-delimited + length, pos = read_varint(data, pos) + if length > len(data) - pos or length < 0: + fields.append((field_num, 'len-delim', length, 'OVERFLOW')) + break + preview = data[pos:pos+min(length, 100)] + pos += length + fields.append((field_num, 'len-delim', length, preview)) + elif wire_type == 1: # 64-bit + val = data[pos:pos+8] + pos += 8 + fields.append((field_num, '64bit', int.from_bytes(val, 'little'), None)) + elif wire_type == 5: # 32-bit + val = data[pos:pos+4] + pos += 4 + fields.append((field_num, '32bit', int.from_bytes(val, 'little'), None)) + else: + fields.append((field_num, f'wire{wire_type}', 0, 'UNKNOWN')) + break + return fields + +# Check top 10 largest heap files +files = sorted( + [f for f in EXTRACT_DIR.glob("*.bin") if "0x271a" in f.name], + key=lambda f: f.stat().st_size, + reverse=True +) + +print("=" * 70) +print("PROTOBUF STRUCTURE ANALYSIS of largest heap files") +print("=" * 70) + +for f in files[:10]: + data = open(f, 'rb').read(2048) + size = f.stat().st_size + print(f"\n{f.name} ({size//1024}KB):") + print(f" First 32 bytes: {data[:32].hex()}") + + fields = parse_protobuf_fields(data) + for fn, wt, val, preview in fields: + if wt == 'varint': + print(f" field={fn} {wt} value={val}") + elif wt == 'len-delim': + if preview == 'OVERFLOW': + print(f" field={fn} {wt} length={val} OVERFLOW!") + elif val < 200 and preview: + try: + txt = preview.decode('utf-8', errors='replace') + printable = all(c.isprintable() or c in '\n\r\t' for c in txt[:50]) + if printable and len(txt) > 0: + print(f" field={fn} {wt} length={val} text='{txt[:80]}'") + else: + print(f" field={fn} {wt} length={val} hex={preview[:40].hex()}") + except: + print(f" field={fn} {wt} length={val} hex={preview[:40].hex()}") + else: + if preview: + print(f" field={fn} {wt} length={val} first_bytes={preview[:20].hex()}") + else: + print(f" field={fn} {wt} length={val}") + else: + print(f" field={fn} {wt} value={val}") + +# Also check a mid-sized file that might be a complete model +print("\n" + "=" * 70) +print("CHECKING MID-SIZED FILES (100KB - 2MB range)") +print("=" * 70) + +mid_files = sorted( + [f for f in EXTRACT_DIR.glob("*.bin") + if "0x271a" in f.name and 100*1024 < f.stat().st_size < 2*1024*1024], + key=lambda f: f.stat().st_size, + reverse=True +) + +import onnx +valid_count = 0 +for f in mid_files[:100]: + try: + m = onnx.load(str(f)) + valid_count += 1 + print(f" VALID: {f.name} ({f.stat().st_size//1024}KB)") + print(f" ir={m.ir_version} producer='{m.producer_name}' " + f"graph='{m.graph.name}' nodes={len(m.graph.node)}") + except: + pass + +if valid_count == 0: + print(" No valid ONNX models in mid-range files either.") + +# Check if the largest files might be a container/archive +print("\n" + "=" * 70) +print("CHECKING FOR INTERNAL ONNX BOUNDARIES IN LARGEST FILE") +print("=" * 70) + +biggest = files[0] +data = open(biggest, 'rb').read() +print(f"File: {biggest.name}, total size: {len(data)} bytes") + +# Search for all occurrences of valid ONNX-like starts +import re +# Look for 0x08 [3-9] 0x12 pattern (ir_version + field2) +pattern = re.compile(b'\\x08[\\x03-\\x09]\\x12') +matches = [(m.start(), data[m.start()+1]) for m in pattern.finditer(data[:1000])] +print(f"ONNX-like headers in first 1000 bytes: {len(matches)}") +for offset, ir in matches[:10]: + print(f" offset={offset}: ir_version={ir}") + +# Also search for "ONNX" string, "onnx" string, "graph" string +for needle in [b'ONNX', b'onnx', b'graph', b'Conv', b'Relu', b'BatchNorm', b'MatMul']: + positions = [m.start() for m in re.finditer(re.escape(needle), data[:50000])] + if positions: + print(f" Found '{needle.decode()}' at offsets: {positions[:5]}") diff --git a/_archive/analysis/analyze_model.py b/_archive/analysis/analyze_model.py new file mode 100644 index 0000000000000000000000000000000000000000..a3487fe55d8757545a54fabe5dd14c150e8c794a --- /dev/null +++ b/_archive/analysis/analyze_model.py @@ -0,0 +1,64 @@ +"""Analyze oneocr.onemodel file format.""" +import os +import struct + +MODEL_PATH = r"ocr_data\oneocr.onemodel" + +with open(MODEL_PATH, "rb") as f: + data = f.read() + +print(f"Total size: {len(data)} bytes = {len(data)/1024/1024:.2f} MB") +print(f"First 8 bytes (hex): {data[:8].hex()}") +print(f"First 4 bytes as uint32 LE: {struct.unpack('= 0: + ctx_start = max(0, idx - 8) + ctx_end = min(len(data), idx + len(pattern) + 8) + print(f"Found '{pattern.decode(errors='replace')}' at offset {idx} (0x{idx:x})") + print(f" Context hex: {data[ctx_start:ctx_end].hex()}") + +print() + +# Check entropy by sections +import collections +def entropy_score(chunk): + c = collections.Counter(chunk) + unique = len(c) + return unique + +print("Entropy analysis (unique byte values per 4KB block):") +for i in range(0, min(len(data), 64*1024), 4096): + chunk = data[i:i+4096] + e = entropy_score(chunk) + print(f" Offset 0x{i:06x}: {e}/256 unique bytes", + "(encrypted/compressed)" if e > 240 else "(structured)" if e < 100 else "") + +# Look at first int as possible header size +hdr_size = struct.unpack('f]b[Piow.gU+nC@s""""""4' +IV = b"Copyright @ OneO" + +def aes_cfb128_decrypt(key: bytes, iv: bytes, data: bytes) -> bytes: + cipher = AES.new(key, AES.MODE_CFB, iv=iv, segment_size=128) + return cipher.decrypt(data) + +def decode_varint(data: bytes, offset: int) -> tuple[int, int]: + """Decode protobuf varint, return (value, new_offset).""" + result = 0 + shift = 0 + while offset < len(data): + b = data[offset] + result |= (b & 0x7F) << shift + offset += 1 + if not (b & 0x80): + break + shift += 7 + return result, offset + +def decode_protobuf_fields(data: bytes, indent: int = 0, max_depth: int = 3, prefix: str = ""): + """Recursively decode protobuf-like structure.""" + off = 0 + field_idx = 0 + pad = " " * indent + while off < len(data) and field_idx < 200: + if off >= len(data): + break + tag_byte = data[off] + field_num = tag_byte >> 3 + wire_type = tag_byte & 0x07 + + if field_num == 0 or field_num > 30: + break + + off += 1 + + if wire_type == 0: # varint + val, off = decode_varint(data, off) + print(f"{pad}field {field_num} (varint): {val}") + elif wire_type == 2: # length-delimited + length, off = decode_varint(data, off) + if off + length > len(data): + print(f"{pad}field {field_num} (bytes, len={length}): TRUNCATED at off={off}") + break + payload = data[off:off+length] + # Try to decode as string + try: + s = payload.decode('utf-8') + if all(c.isprintable() or c in '\n\r\t' for c in s): + if len(s) > 100: + print(f"{pad}field {field_num} (string, len={length}): {s[:100]}...") + else: + print(f"{pad}field {field_num} (string, len={length}): {s}") + else: + raise ValueError() + except (UnicodeDecodeError, ValueError): + if indent < max_depth and length > 2 and length < 100000: + # Try parsing as sub-message + print(f"{pad}field {field_num} (msg, len={length}):") + decode_protobuf_fields(payload, indent + 1, max_depth, prefix=f"{prefix}f{field_num}.") + else: + print(f"{pad}field {field_num} (bytes, len={length}): {payload[:32].hex()}...") + off += length + elif wire_type == 5: # 32-bit + if off + 4 > len(data): + break + val = struct.unpack_from(" len(data): + break + val = struct.unpack_from("= len(config_data): + break + tag_byte = config_data[off] + field_num = tag_byte >> 3 + wire_type = tag_byte & 0x07 + if field_num == 0 or field_num > 30: + break + off += 1 + if wire_type == 0: + val, off = decode_varint(config_data, off) + config_fields.append({"fn": field_num, "wt": wire_type, "val": val, "off": off}) + elif wire_type == 2: + length, off = decode_varint(config_data, off) + if off + length > len(config_data): + break + payload = config_data[off:off+length] + # Try string + try: + s = payload.decode('ascii') + readable = all(c.isprintable() or c in '\n\r\t' for c in s) + except: + readable = False + if readable and len(payload) < 200: + print(f" field {field_num} (string, len={length}, off={off}): {payload[:80]}") + else: + # check first bytes for sub-message identification + fbytes = payload[:16].hex() + print(f" field {field_num} (msg/bytes, len={length}, off={off}): {fbytes}...") + config_fields.append({"fn": field_num, "wt": wire_type, "len": length, "off": off, "data": payload}) + off += length + elif wire_type == 5: + if off + 4 > len(config_data): + break + val = struct.unpack_from(" len(config_data): + break + val = struct.unpack_from("> 3 + wt = tag & 7 + if fn == 0 or fn > 20: + break + sub_off += 1 + if wt == 0: + val, sub_off = decode_varint(data, sub_off) + if fn == 2: + model_type = val + elif wt == 2: + ln, sub_off = decode_varint(data, sub_off) + if sub_off + ln > len(data): + break + p = data[sub_off:sub_off+ln] + if fn == 1: + try: + name = p.decode('ascii') + except: + name = p.hex() + elif fn == 3: + try: + onnx_path = p.decode('ascii', errors='replace') + except: + onnx_path = p.hex() + sub_off += ln + elif wt == 5: + sub_off += 4 + elif wt == 1: + sub_off += 8 + else: + break + print(f" [{i:02d}] name={name:20s} type={model_type}") + if onnx_path: + print(f" path={onnx_path[:80]}") + +# Now look for checksums in the ENTIRE config (not just protobuf) +print("\n=== Searching ALL known checksums in config ===") +import json +with open("temp/crypto_log.json") as f: + log = json.load(f) +sha256s = [op for op in log if op["op"] == "sha256"] + +# Get all unique checksums from 32-byte SHA256 inputs +checksums_found = 0 +for s in sha256s: + inp = bytes.fromhex(s["input"]) + if len(inp) == 32: + chk = inp[16:32] # last 16 bytes = checksum + pos = config_data.find(chk) + if pos >= 0: + checksums_found += 1 + if checksums_found <= 5: + sizes = struct.unpack_from("= 0 and pos2 < 8: + pass # In container header + +print(f"Total checksums found in config: {checksums_found} / {len([s for s in sha256s if len(bytes.fromhex(s['input'])) == 32])}") diff --git a/_archive/analysis/find_chunks.py b/_archive/analysis/find_chunks.py new file mode 100644 index 0000000000000000000000000000000000000000..16e049ced9c7be3db7cfc34602f53f3757d3731f --- /dev/null +++ b/_archive/analysis/find_chunks.py @@ -0,0 +1,80 @@ +"""Find all chunk checksums and their positions in the .onemodel file.""" +import struct, json + +with open("ocr_data/oneocr.onemodel", "rb") as f: + fdata = f.read() +log = json.load(open("temp/crypto_log.json")) + +sha256s = [op for op in log if op["op"] == "sha256"] +sha_map = {} +for s in sha256s: + sha_map[s["output"]] = s["input"] + +decrypts = [op for op in log if op["op"] == "decrypt"] + +print(f"File size: {len(fdata)} bytes") +print(f"Payload starts at: 22684") + +# For each decrypt, find its checksum in the file +results = [] +for i, d in enumerate(decrypts[1:], 1): # skip DX (dec#00) + sha_inp = bytes.fromhex(sha_map[d["aes_key"]]) + if len(sha_inp) < 32: + continue + chk = sha_inp[16:32] + s1, s2 = struct.unpack_from("5} {'chk_offset':>12} {'data_offset':>12} {'enc_size':>10} {'end_offset':>12} {'size1':>10} {'size2':>10}") +print("-" * 90) +for r in results: + if r["chk_file_offset"] >= 0: + # The chunk header is: 4_bytes + 16_checksum + 8_size1 + 8_size2 = 36 bytes + # Data starts at chk_offset - 4 + 36 = chk_offset + 32 + data_off = r["chk_file_offset"] + 32 + end_off = data_off + r["enc_size"] + print(f" {r['dec_idx']:3d} {r['chk_file_offset']:12d} {data_off:12d} {r['enc_size']:10d} {end_off:12d} {r['size1']:10d} {r['size2']:10d}") + else: + print(f" {r['dec_idx']:3d} NOT FOUND {r['enc_size']:10d} {r['size1']:10d} {r['size2']:10d}") + +# Verify chunk continuity +print("\n=== Chunk continuity check ===") +prev_end = None +for r in results: + if r["chk_file_offset"] < 0: + continue + data_off = r["chk_file_offset"] + 32 + chunk_header_start = r["chk_file_offset"] - 4 # 4 bytes before checksum + + if prev_end is not None: + gap = chunk_header_start - prev_end + if gap != 0: + print(f" Gap between chunks: {gap} bytes (prev_end={prev_end}, next_header={chunk_header_start})") + if gap > 0: + gap_data = fdata[prev_end:chunk_header_start] + print(f" Gap bytes: {gap_data.hex()}") + + prev_end = data_off + r["enc_size"] + +print(f"\nExpected file end: {prev_end}") +print(f"Actual file end: {len(fdata)}") + +# Verify the 4 bytes before each checksum +print("\n=== 4 bytes before each checksum ===") +for r in results[:10]: + if r["chk_file_offset"] >= 4: + pre = fdata[r["chk_file_offset"]-4:r["chk_file_offset"]] + print(f" dec#{r['dec_idx']:02d}: pre_bytes={pre.hex()} ({struct.unpack_from('f]b[Piow.gU+nC@s""""""4' +IV = b"Copyright @ OneO" +CONTAINER_MAGIC = bytes.fromhex("4a1a082b25000000") + +def aes_cfb128_decrypt(key: bytes, iv: bytes, data: bytes) -> bytes: + cipher = AES.new(key, AES.MODE_CFB, iv=iv, segment_size=128) + return cipher.decrypt(data) + +with open("ocr_data/oneocr.onemodel", "rb") as f: + fdata = f.read() + +# Parse file header +H = struct.unpack_from(" len(fdata): + break + + enc_size = s1 + 8 + data_off = off + 32 + + if data_off + enc_size > len(fdata): + print(f"WARNING: chunk#{chunk_idx} extends past file end!") + break + + # Derive per-chunk key + sha_input = fdata[off+16:off+32] + fdata[off:off+16] # sizes + checksum + chunk_key = hashlib.sha256(sha_input).digest() + + # Decrypt + dec_data = aes_cfb128_decrypt(chunk_key, IV, fdata[data_off:data_off+enc_size]) + + magic_ok = dec_data[:8] == CONTAINER_MAGIC + payload = dec_data[8:] # strip container header + + chunks.append({ + "idx": chunk_idx, + "file_offset": off, + "data_offset": data_off, + "size1": s1, + "enc_size": enc_size, + "magic_ok": magic_ok, + "payload": payload, + }) + + print(f" chunk#{chunk_idx:02d}: off={off:>10} s1={s1:>10} magic={'OK' if magic_ok else 'FAIL'} payload_start={payload[:8].hex()}") + + off = data_off + enc_size + chunk_idx += 1 + +print(f"\nTotal chunks: {chunk_idx}") +print(f"File bytes remaining: {len(fdata) - off}") +print(f"All magic OK: {all(c['magic_ok'] for c in chunks)}") + +# Identify ONNX models (start with protobuf field tags typical for ONNX ModelProto) +print("\n=== ONNX model identification ===") +onnx_count = 0 +for c in chunks: + payload = c["payload"] + # ONNX ModelProto fields: 1(ir_version), 2(opset_import), 3(producer_name), etc. + # Field 1 varint starts with 0x08 + # Actually check for ONNX-specific protobuf pattern + is_onnx = False + if len(payload) > 100: + # Check for typical ONNX patterns + if payload[0] == 0x08 and payload[1] in (0x06, 0x07): # ir_version 6 or 7 + is_onnx = True + + if is_onnx: + onnx_count += 1 + print(f" chunk#{c['idx']:02d}: ONNX model, size={len(payload):,} bytes") + +print(f"\nTotal ONNX models found: {onnx_count}") +print(f"Total non-ONNX chunks: {chunk_idx - onnx_count}") + +# Show what non-ONNX chunks look like +print("\n=== Non-ONNX chunk types ===") +for c in chunks: + payload = c["payload"] + if len(payload) < 100 or payload[0] != 0x08 or payload[1] not in (0x06, 0x07): + # Try ASCII + try: + s = payload[:40].decode('ascii') + readable = all(ch.isprintable() or ch in '\n\r\t' for ch in s) + except: + readable = False + + if readable: + preview = payload[:60].decode('ascii', errors='replace').replace('\n', '\\n') + else: + preview = payload[:32].hex() + print(f" chunk#{c['idx']:02d}: size={len(payload):>8,} type={'text' if readable else 'binary'} preview={preview}") diff --git a/_archive/analyze_lm_features.py b/_archive/analyze_lm_features.py new file mode 100644 index 0000000000000000000000000000000000000000..9a68cdbbda29d31fe54c573995259ed0d698f7d0 --- /dev/null +++ b/_archive/analyze_lm_features.py @@ -0,0 +1,110 @@ +"""Understand what the 21-dim input features are for LM models 11-32. +These models take data[1,21,1,1] → softmax[1,2] (binary classifier). +We need to figure out what 21 features to compute from the recognizer output.""" +import onnx +from onnx import numpy_helper +import numpy as np +from pathlib import Path +import onnxruntime as ort + +# The 21 input features likely come from CTC recognizer statistics. +# Let's test with the unlocked models using some hypothetical feature vectors. + +models_dir = Path("oneocr_extracted/onnx_models_unlocked") + +# Load a LangSm model (model_11 = Latin LangSm) +sess_sm = ort.InferenceSession(str(list(models_dir.glob("model_11_*"))[0])) +# Load a LangMd model (model_22 = Latin LangMd) +sess_md = ort.InferenceSession(str(list(models_dir.glob("model_22_*"))[0])) + +print("LangSm (model_11) inputs:", [(i.name, i.shape, i.type) for i in sess_sm.get_inputs()]) +print("LangSm (model_11) outputs:", [(o.name, o.shape, o.type) for o in sess_sm.get_outputs()]) +print() +print("LangMd (model_22) inputs:", [(i.name, i.shape, i.type) for i in sess_md.get_inputs()]) +print("LangMd (model_22) outputs:", [(o.name, o.shape, o.type) for o in sess_md.get_outputs()]) + +# The normalization constants inside the model tell us about expected feature ranges +# From earlier analysis: +# Add constant: [-1.273, 0.396, 0.134, 0.151, 0.084, 0.346, 0.472, 0.435, +# 0.346, 0.581, 0.312, 0.036, 0.045, 0.033, 0.026, 0.022, +# 0.044, 0.038, 0.029, 0.031, 0.696] +# Div constant: [0.641, 0.914, 0.377, 0.399, 0.302, 0.657, 0.814, 0.769, +# 0.658, 0.878, 0.617, 0.153, 0.166, 0.137, 0.120, 0.108, +# 0.132, 0.115, 0.105, 0.108, 0.385] +# +# This means typical feature ranges are: +# feature[0]: mean = 1.273, std = 0.641 (large negative offset → feature is centered around 1.27) +# feature[20]: mean = -0.696, std = 0.385 +# +# Features 0: Large range → possibly average log-probability or entropy +# Features 1-10: Medium range → possibly per-class probabilities or scores +# Features 11-20: Small range → possibly confidence statistics + +# Let's check: extract normalization params from model_11 +model_11 = onnx.load(str(list(Path("oneocr_extracted/onnx_models").glob("model_11_*"))[0])) + +for node in model_11.graph.node: + if node.op_type == "Constant": + name = node.output[0] + if name in ['26', '28']: # Add and Div constants + for attr in node.attribute: + if attr.type == 4: + data = numpy_helper.to_array(attr.t) + label = "Add (=-mean)" if name == '26' else "Div (=std)" + print(f"\n{label}: {data.flatten()}") + # The mean tells us the expected center of each feature + if name == '26': + # mean = -add_const + means = -data.flatten() + print(f" Implied means: {means}") + +# Hypothesis: The 21 features are CTC decoder statistics: +# Based on the normalization centers (means): +# feat[0]: ~1.27 — could be average negative log-likelihood (NLL) per character +# feat[1]: ~-0.40 — could be a score +# feat[2-10]: ~0-0.5 — could be per-script probabilities from ScriptID +# feat[11-20]: ~0-0.04 — could be character-level statistics + +# Let's test what outputs the recognizer produces +rec_path = list(Path("oneocr_extracted/onnx_models").glob("model_02_*"))[0] +rec_sess = ort.InferenceSession(str(rec_path)) +print(f"\nRecognizer (model_02) outputs:") +for o in rec_sess.get_outputs(): + print(f" {o.name}: {o.shape}") + +# Try running recognizer and computing statistics +test_data = np.random.randn(1, 3, 60, 200).astype(np.float32) * 0.1 +seq_lengths = np.array([50], dtype=np.int32) # 200/4 +result = rec_sess.run(None, {"data": test_data, "seq_lengths": seq_lengths}) +logprobs = result[0] +print(f"\nRecognizer output: {logprobs.shape}") +print(f" Log-prob range: [{logprobs.min():.4f}, {logprobs.max():.4f}]") + +# Compute possible features from recognizer output: +lp = logprobs[:, 0, :] # [T, num_classes] +best_probs = np.exp(lp.max(axis=-1)) # Best probability per frame +mean_best = best_probs.mean() +print(f"\n Mean best prob per frame: {mean_best:.4f}") +print(f" Mean log-prob max: {lp.max(axis=-1).mean():.4f}") +print(f" Entropy per frame: {(-np.exp(lp) * lp).sum(axis=-1).mean():.4f}") + +# The 21 features might be computed as: +# feat[0] = average log-probability (NLL) → how confident the model is +# feat[1..K] = character frequency statistics +# feat[K+1..20] = transition statistics +# +# Without the exact feature computation code from the DLL, we'll need to +# reverse-engineer or approximate the feature vector. + +# For now, test the LM models with various feature values +print(f"\n--- Testing LM models with various inputs ---") +for name, features in [ + ("all_zeros", np.zeros(21)), + ("high_conf", np.array([0.0, 0.5, 0.9, 0.9, 0.9, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 1.0])), + ("low_conf", np.array([3.0, -0.5, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.1])), + ("typical", np.array([1.2, -0.4, 0.1, 0.15, 0.08, 0.35, 0.47, 0.43, 0.35, 0.58, 0.31, 0.04, 0.05, 0.03, 0.03, 0.02, 0.04, 0.04, 0.03, 0.03, 0.7])), +]: + data = features.astype(np.float32).reshape(1, 21, 1, 1) + sm_out = sess_sm.run(None, {"data": data})[0] + md_out = sess_md.run(None, {"data": data})[0] + print(f" {name:12s}: LangSm={sm_out.flatten()}, LangMd={md_out.flatten()}") diff --git a/_archive/analyze_models.py b/_archive/analyze_models.py new file mode 100644 index 0000000000000000000000000000000000000000..807f7d0f4f8f893001f4cbb68cbaf2169449ee3f --- /dev/null +++ b/_archive/analyze_models.py @@ -0,0 +1,82 @@ +"""Analyze all extracted ONNX models — inputs, outputs, ops, runtime compatibility.""" +import onnx +import onnxruntime as ort +from pathlib import Path + +models_dir = Path("oneocr_extracted/onnx_models") + +print("=" * 120) +print(f"{'#':>3} {'Name':40s} {'KB':>7} {'IR':>3} {'Producer':15s} {'Nodes':>5} {'Inputs':35s} {'Outputs':25s} {'RT':10s} Custom Ops") +print("=" * 120) + +for f in sorted(models_dir.glob("*.onnx")): + m = onnx.load(str(f)) + idx = f.name.split("_")[1] + ir = m.ir_version + prod = (m.producer_name or "?")[:15] + nodes = len(m.graph.node) + + # Input shapes + inputs = [] + for i in m.graph.input: + dims = [] + if i.type.tensor_type.HasField("shape"): + for d in i.type.tensor_type.shape.dim: + dims.append(str(d.dim_value) if d.dim_value else d.dim_param or "?") + inputs.append(f"{i.name}[{','.join(dims)}]") + + # Output shapes + outputs = [] + for o in m.graph.output: + dims = [] + if o.type.tensor_type.HasField("shape"): + for d in o.type.tensor_type.shape.dim: + dims.append(str(d.dim_value) if d.dim_value else d.dim_param or "?") + outputs.append(f"{o.name}[{','.join(dims)}]") + + inp_str = "; ".join(inputs)[:35] + out_str = "; ".join(outputs)[:25] + + # Custom ops + opsets = [o.domain for o in m.opset_import if o.domain] + custom = ", ".join(opsets) if opsets else "-" + + # Runtime check + try: + sess = ort.InferenceSession(str(f), providers=["CPUExecutionProvider"]) + rt = "OK" + except Exception as e: + rt = "CUSTOM" + + size_kb = f.stat().st_size // 1024 + print(f"{idx:>3} {f.stem:40s} {size_kb:>7} {ir:>3} {prod:15s} {nodes:>5} {inp_str:35s} {out_str:25s} {rt:10s} {custom}") + +# Summary +print("\n=== OCR Pipeline Architecture ===") +print(""" +OneOCR uses a MULTI-MODEL pipeline (not a single model): + +1. DETECTOR (model_03, 13MB) — text detection in image + - Input: image tensor → Output: bounding boxes of text regions + +2. CHARACTER RECOGNIZERS (model_00..10, 33) — per-script recognition + - Each script (Latin, Arabic, CJK, Cyrillic, etc.) has its own recognizer + - Input: cropped text region → Output: character probabilities + - Accompanied by: rnn.info, char2ind.txt, char2inschar.txt files + +3. SMALL LANGUAGE MODELS (model_11..32, 26-28KB each) + - Post-processing character-level language models + - One per supported script/language + +Problem for cross-platform: + - 23 models use custom op domain 'com.microsoft.oneocr' + - Custom ops like OneOCRFeatureExtract, DynamicQuantizeLSTM + - These are ONLY implemented in oneocr.dll (Windows) + - To run on Linux: need to reimplement these custom ops or find alternatives +""") + +# Show config structure +print("=== Config Files (per-recognizer) ===") +config_dir = Path("oneocr_extracted/config_data") +config = (config_dir / "chunk_66_ocr_config.config.txt").read_text(errors="replace") +print(config[:500]) diff --git a/_archive/analyze_pipeline.py b/_archive/analyze_pipeline.py new file mode 100644 index 0000000000000000000000000000000000000000..8cfb9efc15fb0e4d4494f4937576e9b61f027fa7 --- /dev/null +++ b/_archive/analyze_pipeline.py @@ -0,0 +1,79 @@ +"""Full analysis of detector and scriptID models.""" +import onnx +import numpy as np +from pathlib import Path + +def print_io(model_path, label): + m = onnx.load(str(model_path)) + print(f'\n=== {label} ({Path(model_path).name}) ===') + print(f'Nodes: {len(m.graph.node)}') + + print('Inputs:') + for i in m.graph.input: + dims = [] + for d in i.type.tensor_type.shape.dim: + dims.append(str(d.dim_value) if d.dim_value else d.dim_param or '?') + print(f' {i.name}: [{", ".join(dims)}] dtype={i.type.tensor_type.elem_type}') + + print('Outputs:') + for o in m.graph.output: + dims = [] + for d in o.type.tensor_type.shape.dim: + dims.append(str(d.dim_value) if d.dim_value else d.dim_param or '?') + print(f' {o.name}: [{", ".join(dims)}] dtype={o.type.tensor_type.elem_type}') + + custom = set() + for n in m.graph.node: + if n.domain: + custom.add((n.domain, n.op_type)) + if custom: + print(f'Custom ops: {custom}') + else: + print('Custom ops: none') + return m + +models_dir = Path('oneocr_extracted/onnx_models') + +# Detector +m0 = print_io(next(models_dir.glob('model_00_*')), 'DETECTOR') + +# ScriptID +m1 = print_io(next(models_dir.glob('model_01_*')), 'SCRIPT ID') + +# A recognizer (Latin) +m2 = print_io(next(models_dir.glob('model_02_*')), 'RECOGNIZER Latin') + +# Try running detector to see actual output shapes +import onnxruntime as ort +from PIL import Image + +img = Image.open('image.png').convert('RGB') +w, h = img.size + +sess = ort.InferenceSession(str(next(models_dir.glob('model_00_*'))), + providers=['CPUExecutionProvider']) + +scale = 800 / max(h, w) +dh = (int(h * scale) + 31) // 32 * 32 +dw = (int(w * scale) + 31) // 32 * 32 + +img_d = img.resize((dw, dh), Image.LANCZOS) +arr_d = np.array(img_d, dtype=np.float32) +arr_d = arr_d[:, :, ::-1] - [102.9801, 115.9465, 122.7717] +data_d = arr_d.transpose(2, 0, 1)[np.newaxis].astype(np.float32) +im_info = np.array([[dh, dw, scale]], dtype=np.float32) + +outputs = sess.run(None, {"data": data_d, "im_info": im_info}) +print(f'\n=== DETECTOR OUTPUT SHAPES (image {w}x{h} -> {dw}x{dh}) ===') +output_names = [o.name for o in sess.get_outputs()] +for name, out in zip(output_names, outputs): + print(f' {name}: shape={out.shape} dtype={out.dtype} min={out.min():.4f} max={out.max():.4f}') + +# Specifically analyze pixel_link outputs +# PixelLink has: pixel scores (text/non-text) + link scores (8 neighbors) +# FPN produces 3 scales +print('\n=== DETECTOR OUTPUT ANALYSIS ===') +for i, (name, out) in enumerate(zip(output_names, outputs)): + scores = 1.0 / (1.0 + np.exp(-out)) # sigmoid + hot = (scores > 0.5).sum() + print(f' [{i:2d}] {name:25s} shape={str(out.shape):20s} sigmoid_max={scores.max():.4f} hot_pixels(>0.5)={hot}') diff --git a/_archive/attempts/bcrypt_decrypt.py b/_archive/attempts/bcrypt_decrypt.py new file mode 100644 index 0000000000000000000000000000000000000000..b187150599c88c55c7bed0c0fa8c3015bdc7454b --- /dev/null +++ b/_archive/attempts/bcrypt_decrypt.py @@ -0,0 +1,423 @@ +""" +OneOCR .onemodel decryption using Windows BCrypt CNG API directly. +Replicates the exact behavior of oneocr.dll's Crypto.cpp. + +Known from DLL analysis: +- BCryptOpenAlgorithmProvider with L"AES" +- BCryptSetProperty L"ChainingMode" = L"ChainingModeCFB" +- BCryptGetProperty L"BlockLength" (→ 16) +- BCryptSetProperty L"MessageBlockLength" = 16 (→ CFB128) +- BCryptGenerateSymmetricKey with raw key bytes +- BCryptDecrypt +- SHA256Hash function exists (uses BCryptCreateHash/BCryptHashData/BCryptFinishHash) +""" + +import ctypes +import ctypes.wintypes as wintypes +import struct +import hashlib +import zlib +from collections import Counter +import math +import os + +# ═══════════════════════════════════════════════════════════════ +# Windows BCrypt API via ctypes +# ═══════════════════════════════════════════════════════════════ + +bcrypt = ctypes.WinDLL("bcrypt") + +BCRYPT_ALG_HANDLE = ctypes.c_void_p +BCRYPT_KEY_HANDLE = ctypes.c_void_p +NTSTATUS = ctypes.c_long + +# Constants +BCRYPT_AES_ALGORITHM = "AES" +BCRYPT_SHA256_ALGORITHM = "SHA256" +BCRYPT_CHAINING_MODE = "ChainingMode" +BCRYPT_CHAIN_MODE_CFB = "ChainingModeCFB" +BCRYPT_BLOCK_LENGTH = "BlockLength" +BCRYPT_MESSAGE_BLOCK_LENGTH = "MessageBlockLength" + +def check_status(status, msg=""): + if status != 0: + raise OSError(f"BCrypt error 0x{status & 0xFFFFFFFF:08x}: {msg}") + + +def bcrypt_sha256(data: bytes) -> bytes: + """Compute SHA256 using Windows BCrypt API.""" + hAlg = BCRYPT_ALG_HANDLE() + status = bcrypt.BCryptOpenAlgorithmProvider( + ctypes.byref(hAlg), + ctypes.c_wchar_p(BCRYPT_SHA256_ALGORITHM), + None, 0) + check_status(status, "SHA256 OpenAlgorithmProvider") + + hHash = ctypes.c_void_p() + status = bcrypt.BCryptCreateHash(hAlg, ctypes.byref(hHash), None, 0, None, 0, 0) + check_status(status, "CreateHash") + + status = bcrypt.BCryptHashData(hHash, data, len(data), 0) + check_status(status, "HashData") + + hash_out = (ctypes.c_ubyte * 32)() + status = bcrypt.BCryptFinishHash(hHash, hash_out, 32, 0) + check_status(status, "FinishHash") + + bcrypt.BCryptDestroyHash(hHash) + bcrypt.BCryptCloseAlgorithmProvider(hAlg, 0) + + return bytes(hash_out) + + +def bcrypt_aes_cfb_decrypt(ciphertext: bytes, key: bytes, iv: bytes, + message_block_length: int = 16) -> bytes: + """Decrypt using AES-CFB via Windows BCrypt CNG API. + + message_block_length: 1 for CFB8, 16 for CFB128 + """ + hAlg = BCRYPT_ALG_HANDLE() + status = bcrypt.BCryptOpenAlgorithmProvider( + ctypes.byref(hAlg), + ctypes.c_wchar_p(BCRYPT_AES_ALGORITHM), + None, 0) + check_status(status, "AES OpenAlgorithmProvider") + + # Set chaining mode to CFB + mode_str = BCRYPT_CHAIN_MODE_CFB + mode_buf = ctypes.create_unicode_buffer(mode_str) + mode_size = (len(mode_str) + 1) * 2 # UTF-16 with null terminator + status = bcrypt.BCryptSetProperty( + hAlg, + ctypes.c_wchar_p(BCRYPT_CHAINING_MODE), + mode_buf, mode_size, 0) + check_status(status, "SetProperty ChainingMode") + + # Set message block length (feedback size) + mbl = ctypes.c_ulong(message_block_length) + status = bcrypt.BCryptSetProperty( + hAlg, + ctypes.c_wchar_p(BCRYPT_MESSAGE_BLOCK_LENGTH), + ctypes.byref(mbl), ctypes.sizeof(mbl), 0) + check_status(status, f"SetProperty MessageBlockLength={message_block_length}") + + # Generate symmetric key + hKey = BCRYPT_KEY_HANDLE() + key_buf = (ctypes.c_ubyte * len(key))(*key) + status = bcrypt.BCryptGenerateSymmetricKey( + hAlg, ctypes.byref(hKey), None, 0, key_buf, len(key), 0) + check_status(status, "GenerateSymmetricKey") + + # Prepare IV (BCrypt modifies it during decryption, so use a copy) + iv_buf = (ctypes.c_ubyte * 16)(*iv) + + # Prepare input/output buffers + ct_buf = (ctypes.c_ubyte * len(ciphertext))(*ciphertext) + pt_buf = (ctypes.c_ubyte * len(ciphertext))() + result_len = ctypes.c_ulong(0) + + # Decrypt + status = bcrypt.BCryptDecrypt( + hKey, ct_buf, len(ciphertext), None, + iv_buf, 16, + pt_buf, len(ciphertext), + ctypes.byref(result_len), 0) + check_status(status, "BCryptDecrypt") + + # Cleanup + bcrypt.BCryptDestroyKey(hKey) + bcrypt.BCryptCloseAlgorithmProvider(hAlg, 0) + + return bytes(pt_buf[:result_len.value]) + + +def entropy(data: bytes) -> float: + """Shannon entropy (bits per byte).""" + if not data: + return 0.0 + freq = Counter(data) + total = len(data) + return -sum((c / total) * math.log2(c / total) for c in freq.values()) + + +def hex_dump(data: bytes, offset: int = 0, max_lines: int = 8) -> str: + lines = [] + for i in range(0, min(len(data), max_lines * 16), 16): + hex_part = " ".join(f"{b:02x}" for b in data[i:i+16]) + ascii_part = "".join(chr(b) if 32 <= b < 127 else "." for b in data[i:i+16]) + lines.append(f" {offset+i:08x}: {hex_part:<48s} {ascii_part}") + return "\n".join(lines) + + +def check_decrypted(data: bytes, label: str) -> bool: + """Check if decrypted data looks valid. Return True if promising.""" + if not data or len(data) < 16: + return False + + ent = entropy(data[:min(4096, len(data))]) + u32_le = struct.unpack_from("f]b[Piow.gU+nC@s""""""4' +KEY_SHA256 = bcrypt_sha256(KEY_RAW) + +print("=" * 80) +print("OneOCR Decryption via Windows BCrypt CNG API") +print("=" * 80) + +print(f"\nKey (raw): {KEY_RAW.hex()}") +print(f"Key (SHA256): {KEY_SHA256.hex()}") +print(f"Python hashlib SHA256: {hashlib.sha256(KEY_RAW).digest().hex()}") +print(f"BCrypt SHA256 match: {KEY_SHA256 == hashlib.sha256(KEY_RAW).digest()}") + +# Read file +with open(MODEL_PATH, "rb") as f: + full_data = f.read() +filesize = len(full_data) + +header_offset = struct.unpack_from(" float: + if not data: + return 0.0 + freq = Counter(data) + total = len(data) + return -sum((c / total) * math.log2(c / total) for c in freq.values()) + + +def scan_memory_regions(): + """Enumerate all committed, readable memory regions.""" + regions = [] + handle = kernel32.GetCurrentProcess() + mbi = MEMORY_BASIC_INFORMATION() + address = 0 + max_addr = (1 << 47) - 1 + + while address < max_addr: + result = kernel32.VirtualQuery( + ctypes.c_void_p(address), + ctypes.byref(mbi), + ctypes.sizeof(mbi) + ) + if result == 0: + break + + base_addr = mbi.BaseAddress or 0 + region_size = mbi.RegionSize or 0 + + if region_size == 0: + break + + if (mbi.State == MEM_COMMIT and + mbi.Protect not in (0, PAGE_NOACCESS, PAGE_GUARD) and + not (mbi.Protect & PAGE_GUARD)): + regions.append((base_addr, region_size)) + + new_address = base_addr + region_size + if new_address <= address: + break + address = new_address + return regions + + +def read_mem(address, size): + """Read memory from current process - direct access since it's our own memory.""" + try: + return ctypes.string_at(address, size) + except Exception: + # Fallback to ReadProcessMemory + try: + buf = (ctypes.c_ubyte * size)() + n = ctypes.c_size_t(0) + handle = kernel32.GetCurrentProcess() + ok = kernel32.ReadProcessMemory( + handle, ctypes.c_void_p(address), buf, size, ctypes.byref(n) + ) + if ok and n.value > 0: + return bytes(buf[:n.value]) + except Exception: + pass + return None + + +# ═══════════════════════════════════════════════════════════════ +# Step 1: Snapshot BEFORE loading OCR +# ═══════════════════════════════════════════════════════════════ + +print("=" * 80) +print("OneOCR Model Extraction via Runtime Memory Dump") +print("=" * 80) + +print("\n[1/5] Memory snapshot BEFORE OCR load...") +before = set() +before_data = {} +for base, size in scan_memory_regions(): + before.add(base) + # Store hash of small regions for change detection + if size <= 65536: + d = read_mem(base, size) + if d: + before_data[base] = hash(d) +print(f" {len(before)} regions before") + +# ═══════════════════════════════════════════════════════════════ +# Step 2: Load DLLs +# ═══════════════════════════════════════════════════════════════ + +print("\n[2/5] Loading DLLs...") +os.add_dll_directory(str(OCR_DATA_DIR)) +os.environ["PATH"] = str(OCR_DATA_DIR) + ";" + os.environ.get("PATH", "") + +ort_dll = ctypes.WinDLL(ORT_DLL_PATH) +print(f" OK: onnxruntime.dll") + +ocr_dll = ctypes.WinDLL(DLL_PATH) +print(f" OK: oneocr.dll") + +# ═══════════════════════════════════════════════════════════════ +# Step 3: Init OCR pipeline (triggers decryption) +# ═══════════════════════════════════════════════════════════════ + +print("\n[3/5] Creating OCR pipeline (decrypts model)...") + +CreateOcrInitOptions = ocr_dll.CreateOcrInitOptions +CreateOcrInitOptions.restype = ctypes.c_int64 +CreateOcrInitOptions.argtypes = [ctypes.POINTER(ctypes.c_int64)] + +OcrInitOptionsSetUseModelDelayLoad = ocr_dll.OcrInitOptionsSetUseModelDelayLoad +OcrInitOptionsSetUseModelDelayLoad.restype = ctypes.c_int64 +OcrInitOptionsSetUseModelDelayLoad.argtypes = [ctypes.c_int64, ctypes.c_char] + +CreateOcrPipeline = ocr_dll.CreateOcrPipeline +CreateOcrPipeline.restype = ctypes.c_int64 +CreateOcrPipeline.argtypes = [ctypes.c_int64, ctypes.c_int64, ctypes.c_int64, ctypes.POINTER(ctypes.c_int64)] + +ctx = ctypes.c_int64(0) +res = CreateOcrInitOptions(ctypes.byref(ctx)) +assert res == 0, f"CreateOcrInitOptions failed: {res}" + +# Disable delay load → load ALL models immediately +res = OcrInitOptionsSetUseModelDelayLoad(ctx, ctypes.c_char(0)) +assert res == 0, f"SetUseModelDelayLoad failed: {res}" + +model_path_c = ctypes.c_char_p(MODEL_PATH.encode("utf-8")) +key_c = ctypes.c_char_p(KEY.encode("utf-8")) + +pipeline = ctypes.c_int64(0) +res = CreateOcrPipeline( + ctypes.cast(model_path_c, ctypes.c_void_p).value, + ctypes.cast(key_c, ctypes.c_void_p).value, + ctx.value, + ctypes.byref(pipeline) +) + +if res != 0: + print(f" ERROR: CreateOcrPipeline returned {res}") + sys.exit(1) + +print(f" Pipeline OK! handle=0x{pipeline.value:x}") +time.sleep(0.5) + +# ═══════════════════════════════════════════════════════════════ +# Step 4: Find new/changed memory regions & search for ONNX +# ═══════════════════════════════════════════════════════════════ + +print("\n[4/5] Scanning process memory for ONNX models...") + +OUTPUT_DIR.mkdir(parents=True, exist_ok=True) + +after_regions = scan_memory_regions() +new_regions = [(b, s) for b, s in after_regions if b not in before] +print(f" Total regions after: {len(after_regions)}") +print(f" New regions: {len(new_regions)}") + +# Size distribution of new regions +new_large = [(b, s) for b, s in new_regions if s >= 1024*1024] +new_total = sum(s for _, s in new_regions) +print(f" New large regions (>1MB): {len(new_large)}") +print(f" Total new memory: {new_total/1024/1024:.1f} MB") + +found = [] + +# ONNX protobuf field patterns for start of file +# ir_version (field 1, varint) followed by opset_import (field 2, len-delimited) +# or producer_name (field 2, len-delimited) etc. + +# Search patterns +PATTERNS = [ + b"\x08\x07\x12", # ir_v=7, then field 2 + b"\x08\x08\x12", # ir_v=8 + b"\x08\x06\x12", # ir_v=6 + b"\x08\x05\x12", # ir_v=5 + b"\x08\x04\x12", # ir_v=4 + b"\x08\x03\x12", # ir_v=3 + b"\x08\x09\x12", # ir_v=9 + b"ORTM", # ORT model format + b"ONNX", # Just in case + b"\x08\x07\x1a", # ir_v=7, field 3 + b"\x08\x08\x1a", # ir_v=8, field 3 +] + +# Scan ALL new large regions +for ridx, (base, size) in enumerate(sorted(new_regions, key=lambda x: x[1], reverse=True)): + if size < 4096: + continue + + read_size = min(size, 200 * 1024 * 1024) + data = read_mem(base, read_size) + if not data: + continue + + # Check entropy of first 4KB + ent = entropy(data[:4096]) + uniq = len(set(data[:4096])) + + if size >= 100000: + # Log large regions regardless + print(f" Region 0x{base:x} size={size:,} ent={ent:.2f} uniq={uniq}/256 first={data[:16].hex()}") + + # Search for patterns + for pattern in PATTERNS: + offset = 0 + while True: + idx = data.find(pattern, offset) + if idx < 0: + break + + # Validate: check surrounding context + chunk = data[idx:idx+min(4096, len(data)-idx)] + chunk_ent = entropy(chunk[:1024]) if len(chunk) >= 1024 else entropy(chunk) + + # Valid models should have moderate entropy (not encrypted high-entropy) + if chunk_ent < 7.5 and len(chunk) > 64: + addr = base + idx + remaining = len(data) - idx + found.append({ + "addr": addr, + "base": base, + "offset": idx, + "size": remaining, + "pattern": pattern.hex(), + "ent": chunk_ent, + "first_32": data[idx:idx+32].hex(), + }) + print(f" ★ ONNX candidate at 0x{addr:x}: pattern={pattern.hex()} " + f"ent={chunk_ent:.2f} remaining={remaining:,}") + print(f" First 32: {data[idx:idx+32].hex()}") + + offset = idx + len(pattern) + +print(f"\n Found {len(found)} ONNX candidates total") + +# ═══════════════════════════════════════════════════════════════ +# Step 5: Dump candidates +# ═══════════════════════════════════════════════════════════════ + +print("\n[5/5] Dumping models...") + +if found: + # Deduplicate by address + seen = set() + for i, m in enumerate(found): + if m["addr"] in seen: + continue + seen.add(m["addr"]) + + dump_size = min(m["size"], 100 * 1024 * 1024) + data = read_mem(m["addr"], dump_size) + if data: + fname = f"onnx_{i}_0x{m['addr']:x}_{dump_size//1024}KB.bin" + out = OUTPUT_DIR / fname + with open(out, "wb") as f: + f.write(data) + print(f" Saved: {fname} ({len(data):,} bytes)") +else: + print(" No ONNX patterns found. Dumping ALL large new regions (>1MB)...") + + for i, (base, size) in enumerate(new_large): + data = read_mem(base, min(size, 200*1024*1024)) + if data: + ent = entropy(data[:4096]) + fname = f"region_{i}_0x{base:x}_{size//1024//1024}MB_ent{ent:.1f}.bin" + out = OUTPUT_DIR / fname + with open(out, "wb") as f: + f.write(data) + print(f" Saved: {fname} ({len(data):,} bytes, ent={ent:.2f})") + +# Summary +print("\n" + "=" * 80) +print("RESULTS") +print("=" * 80) + +if OUTPUT_DIR.exists(): + files = sorted(OUTPUT_DIR.iterdir()) + if files: + total_size = sum(f.stat().st_size for f in files) + print(f"\nExtracted {len(files)} files ({total_size/1024/1024:.1f} MB):") + for f in files: + sz = f.stat().st_size + # Quick check if it's ONNX + with open(f, "rb") as fh: + header = fh.read(32) + print(f" {f.name}: {sz:,} bytes | first_16={header[:16].hex()}") + else: + print("\nNo files extracted.") diff --git a/_archive/attempts/decrypt_with_static_iv.py b/_archive/attempts/decrypt_with_static_iv.py new file mode 100644 index 0000000000000000000000000000000000000000..239c9dd8fdcc1c780f44960dedf39ba65eae1dd7 --- /dev/null +++ b/_archive/attempts/decrypt_with_static_iv.py @@ -0,0 +1,302 @@ +""" +Extract the static IV string from DLL and find how key derivation works. + +Key findings from disassembly: +1. Static 30-byte string at RVA 0x02725C60 used as IV (truncated to 16) +2. SHA256(combined) used as AES key material +3. Combined = some_function(key_string, iv_from_data, flag) +4. Function at 0x18006c3d0 combines key + iv_prefix + +Need to: +a) Read the static IV string +b) Disassemble function 0x18006c3d0 to understand combination +c) Try decryption +""" +import struct, hashlib +from capstone import Cs, CS_ARCH_X86, CS_MODE_64 + +DLL_PATH = r"c:\Users\MattyMroz\Desktop\PROJECTS\ONEOCR\ocr_data\oneocr.dll" +MODEL_PATH = r"c:\Users\MattyMroz\Desktop\PROJECTS\ONEOCR\ocr_data\oneocr.onemodel" + +with open(DLL_PATH, "rb") as f: + dll = f.read() + +with open(MODEL_PATH, "rb") as f: + model = f.read() + +# Parse PE sections for RVA → file offset mapping +e_lfanew = struct.unpack_from('= 24: + magic = struct.unpack_from('= 24: + magic = struct.unpack_from('= 24 else 0 + if magic == MAGIC: + print("FOUND THE CORRECT PARAMETERS!") + +print("\nDone.") diff --git a/_archive/attempts/disasm_bcrypt_calls.py b/_archive/attempts/disasm_bcrypt_calls.py new file mode 100644 index 0000000000000000000000000000000000000000..d997374d3a6005603e6edff272ca83752d9d0108 --- /dev/null +++ b/_archive/attempts/disasm_bcrypt_calls.py @@ -0,0 +1,143 @@ +""" +Disassemble the actual BCrypt crypto operations at 0x18015ba45+ +and map all indirect calls to IAT entries. +""" +import struct +from capstone import Cs, CS_ARCH_X86, CS_MODE_64 + +DLL_PATH = r"c:\Users\MattyMroz\Desktop\PROJECTS\ONEOCR\ocr_data\oneocr.dll" +IMAGE_BASE = 0x180000000 +TEXT_VA = 0x1000 +TEXT_FILE_OFFSET = 0x400 + +def rva_to_file(rva): + return rva - TEXT_VA + TEXT_FILE_OFFSET + +def file_to_rva(foff): + return foff - TEXT_FILE_OFFSET + TEXT_VA + +with open(DLL_PATH, "rb") as f: + dll_data = f.read() + +md = Cs(CS_ARCH_X86, CS_MODE_64) +md.detail = False + +def disasm_region(name, file_start, file_end): + rva_start = file_to_rva(file_start) + va_start = IMAGE_BASE + rva_start + code = dll_data[file_start:file_end] + print(f"\n{'='*100}") + print(f"{name}") + print(f"File: 0x{file_start:08x}-0x{file_end:08x}, RVA: 0x{rva_start:08x}") + print(f"{'='*100}") + for insn in md.disasm(code, va_start): + foff = rva_to_file(insn.address - IMAGE_BASE) + line = f" {insn.address - IMAGE_BASE:08x} ({foff:08x}): {insn.bytes.hex():<40s} {insn.mnemonic:<14s} {insn.op_str}" + # Annotate indirect calls + if insn.mnemonic == 'call' and insn.bytes[0] == 0xFF and insn.bytes[1] == 0x15: + disp = struct.unpack_from(' IAT@0x{target_rva:08x}") + +# Also disassemble the function at 0x18015abd0 (called to process data when r14b=true) +# RVA 0x0015abd0, file 0x00159fd0 +disasm_region( + "Function at 0x18015abd0 (called on data when r14b=true)", + 0x00159fd0, 0x0015a0c0 +) diff --git a/_archive/attempts/disasm_crypto.py b/_archive/attempts/disasm_crypto.py new file mode 100644 index 0000000000000000000000000000000000000000..3f1e8e318470ba53e4328fd52c2b7866444cd0ac --- /dev/null +++ b/_archive/attempts/disasm_crypto.py @@ -0,0 +1,156 @@ +""" +Disassemble the Cipher function in oneocr.dll to find the exact crypto parameters. +Find code references to the crypto strings we identified. +""" +import struct +import re + +dll_path = r"c:\Users\MattyMroz\Desktop\PROJECTS\ONEOCR\ocr_data\oneocr.dll" +with open(dll_path, "rb") as f: + data = f.read() + +# Parse PE headers to find section info +pe_sig_offset = struct.unpack_from("magic_number == MAGIC_NUMBER": 0x02724bb0, + "Unable to uncompress": 0x02724bd8, + "Crypto.cpp": 0x02724c08, + "Error returned from crypto API": 0x02724c40, + "ChainingMode (wide)": 0x02724c80, + "MessageBlockLength (wide)": 0x02724ca0, +} + +# Calculate RVAs of these strings +print("\n=== String RVAs ===") +for name, file_off in crypto_strings.items(): + rva = file_offset_to_rva(file_off) + if rva: + print(f" {name}: file=0x{file_off:08x} RVA=0x{rva:08x}") + +# Find code references to these strings via LEA instruction patterns +# In x64, LEA reg, [rip+disp32] is encoded as: +# 48 8D xx yy yy yy yy (where xx determines the register) +# or 4C 8D xx yy yy yy yy +# The target address = instruction_address + 7 + disp32 + +print("\n=== Searching for code references to crypto strings ===") + +# Focus on the most important strings +key_strings = { + "ChainingModeCFB (wide)": 0x02724b90, + "SHA256 (wide)": 0x02724b60, + "AES (wide)": 0x02724b70, + "Crypto.cpp": 0x02724c08, + "MessageBlockLength (wide)": 0x02724ca0, + "meta->magic_number": 0x02724bb0, +} + +# Find the .text section (code) +text_section = None +for name, va, vsize, raw_ptr, raw_size in sections: + if name == ".text": + text_section = (va, vsize, raw_ptr, raw_size) + break + +if text_section: + text_va, text_vsize, text_raw, text_rawsize = text_section + print(f"\n.text section: VA=0x{text_va:08x} size=0x{text_vsize:08x}") + + for string_name, string_file_off in key_strings.items(): + string_rva = file_offset_to_rva(string_file_off) + if string_rva is None: + continue + + # Search for LEA instructions referencing this RVA + # LEA uses RIP-relative addressing: target = RIP + disp32 + # RIP at instruction = instruction_RVA + instruction_length (typically 7 for LEA) + refs_found = [] + + for code_off in range(text_raw, text_raw + text_rawsize - 7): + # Check for LEA patterns + b0 = data[code_off] + b1 = data[code_off + 1] + + # 48 8D 0D/15/05/1D/25/2D/35/3D = LEA with REX.W + # 4C 8D 05/0D/15/1D/25/2D/35/3D = LEA with REX.WR + if b0 in (0x48, 0x4C) and b1 == 0x8D: + modrm = data[code_off + 2] + if (modrm & 0xC7) == 0x05: # mod=00, rm=101 (RIP-relative) + disp32 = struct.unpack_from("> 3) & 7 + if b0 == 0x4C: + reg_idx += 8 + reg_names = ["rax","rcx","rdx","rbx","rsp","rbp","rsi","rdi", + "r8","r9","r10","r11","r12","r13","r14","r15"] + reg = reg_names[reg_idx] + refs_found.append((code_off, instr_rva, reg)) + + if refs_found: + print(f"\n References to '{string_name}' (RVA=0x{string_rva:08x}):") + for code_off, instr_rva, reg in refs_found[:5]: + print(f" at file=0x{code_off:08x} RVA=0x{instr_rva:08x}: LEA {reg}, [{string_name}]") + # Dump surrounding code + ctx_start = max(text_raw, code_off - 64) + ctx_end = min(text_raw + text_rawsize, code_off + 128) + + # Simple bytecode dump with some x64 instruction markers + print(f" Context (file offset 0x{ctx_start:08x} - 0x{ctx_end:08x}):") + for i in range(ctx_start, ctx_end, 16): + chunk = data[i:i+16] + hex_part = " ".join(f"{b:02x}" for b in chunk) + rva_i = file_offset_to_rva(i) + marker = " <<<" if i <= code_off < i + 16 else "" + print(f" {rva_i:08x}: {hex_part}{marker}") + else: + print(f"\n No code references found for '{string_name}'") diff --git a/_archive/attempts/disasm_full_cipher.py b/_archive/attempts/disasm_full_cipher.py new file mode 100644 index 0000000000000000000000000000000000000000..359aac60b466a3a90d99255dfb1e2a39c6bc00eb --- /dev/null +++ b/_archive/attempts/disasm_full_cipher.py @@ -0,0 +1,138 @@ +""" +Full disassembly of the Cipher function from AES setup through BCryptDecrypt. +Based on findings: +- SHA256 provider at file 0x0015a3e2 (RVA 0x0015afe2) +- AES provider at file 0x0015a702 (RVA 0x0015b302) +- ChainingModeCFB at file 0x0015a7cd (RVA 0x0015b3cd) +- MessageBlockLength at file 0x0015a7fc (RVA 0x0015b3fc) +- BCryptGenerateSymmetricKey import at ~0x027ef0a2 +- Need to find: key handling, IV passing, BCryptDecrypt call +""" +import struct +from capstone import Cs, CS_ARCH_X86, CS_MODE_64 + +DLL_PATH = r"c:\Users\MattyMroz\Desktop\PROJECTS\ONEOCR\ocr_data\oneocr.dll" +IMAGE_BASE = 0x180000000 +TEXT_VA = 0x1000 +TEXT_FILE_OFFSET = 0x400 # .text section file offset + +def rva_to_file(rva): + return rva - TEXT_VA + TEXT_FILE_OFFSET + +def file_to_rva(foff): + return foff - TEXT_FILE_OFFSET + TEXT_VA + +with open(DLL_PATH, "rb") as f: + dll_data = f.read() + +md = Cs(CS_ARCH_X86, CS_MODE_64) +md.detail = False + +def disasm_region(name, file_start, file_end): + rva_start = file_to_rva(file_start) + va_start = IMAGE_BASE + rva_start + code = dll_data[file_start:file_end] + print(f"\n{'='*100}") + print(f"{name}") + print(f"File: 0x{file_start:08x}-0x{file_end:08x}, RVA: 0x{rva_start:08x}, VA: 0x{va_start:016x}") + print(f"{'='*100}") + for insn in md.disasm(code, va_start): + foff = rva_to_file(insn.address - IMAGE_BASE) + print(f" {insn.address - IMAGE_BASE:08x} ({foff:08x}): {insn.bytes.hex():<40s} {insn.mnemonic:<14s} {insn.op_str}") + +# The Cipher function appears to start before the AES setup. +# Let's find the function prologue by scanning backwards from the AES setup. +# The AES LEA is at file 0x0015a702. Let's look for a typical function prologue. + +# First, let's find the actual function start +# Look for common prologues (push rbp, sub rsp, mov [rsp+...], etc.) before the AES reference +print("\n" + "="*100) +print("SCANNING FOR FUNCTION PROLOGUE before AES setup (file 0x0015a702)") +print("="*100) + +# Search backwards from 0x0015a702 for push rbp or sub rsp patterns +search_start = 0x0015a500 # Start from after SHA256Hash function +search_end = 0x0015a710 +search_region = dll_data[search_start:search_end] + +# Look for common x64 function prologues +# 48 89 5C 24 xx = mov [rsp+xx], rbx +# 48 89 74 24 xx = mov [rsp+xx], rsi +# 55 = push rbp +# 40 55 = push rbp (with REX prefix) +# 48 8B EC = mov rbp, rsp +# 48 81 EC xx xx xx xx = sub rsp, imm32 + +for i in range(len(search_region) - 4): + b = search_region[i:i+8] + foff = search_start + i + rva = file_to_rva(foff) + + # Look for function start patterns + if b[:5] == bytes([0x48, 0x89, 0x5C, 0x24, 0x08]): # mov [rsp+8], rbx + print(f" Possible prologue at file 0x{foff:08x} (RVA 0x{rva:08x}): mov [rsp+8], rbx") + elif b[:2] == bytes([0x40, 0x55]): # push rbp with REX + print(f" Possible prologue at file 0x{foff:08x} (RVA 0x{rva:08x}): REX push rbp") + elif b[:1] == bytes([0x55]) and (i == 0 or search_region[i-1] in (0xC3, 0xCC, 0x90)): + print(f" Possible prologue at file 0x{foff:08x} (RVA 0x{rva:08x}): push rbp (after ret/nop/int3)") + elif b[:4] == bytes([0x48, 0x83, 0xEC, 0x28]): # sub rsp, 0x28 + print(f" Possible prologue at file 0x{foff:08x} (RVA 0x{rva:08x}): sub rsp, 0x28") + elif b[:3] == bytes([0x48, 0x81, 0xEC]): # sub rsp, imm32 + val = struct.unpack_from(' IAT at RVA 0x{target_rva:08x}") + +# Also disassemble the region between IV handling (0x0015abdb) and magic number check (0x0015a170) +# This might contain the actual BCryptDecrypt call +disasm_region( + "Cipher function part 4: from end of IV path to function cleanup", + 0x0015ac00, 0x0015ae00 +) + +# Look for the region right before the magic number check function +# The Cipher function should return, and then a caller invokes the magic check +disasm_region( + "Pre-magic-check function caller", + 0x0015a0c0, 0x0015a170 +) diff --git a/_archive/attempts/disasm_proper.py b/_archive/attempts/disasm_proper.py new file mode 100644 index 0000000000000000000000000000000000000000..8ee0cec5068bd713dc32ec26eb1234ece96d04f5 --- /dev/null +++ b/_archive/attempts/disasm_proper.py @@ -0,0 +1,95 @@ +""" +Proper disassembly of the Cipher function in oneocr.dll using capstone. +Focus on the crypto setup flow: key derivation, IV, AES parameters. +""" +import struct +from capstone import Cs, CS_ARCH_X86, CS_MODE_64 + +dll_path = r"c:\Users\MattyMroz\Desktop\PROJECTS\ONEOCR\ocr_data\oneocr.dll" +with open(dll_path, "rb") as f: + data = f.read() + +# PE parsing (simplified) +pe_sig_offset = struct.unpack_from("f]b[Piow.gU+nC@s""""""4' +IV = b"Copyright @ OneO" + +# Captured per-chunk secrets from hook +CHUNK_SECRETS = { + 0: bytes.fromhex("d13142a17603a8e25c9ca2f90761f7fdf31ad106fd224fb7fe6a33e695c0f25a"), # DX index + 1: bytes.fromhex("82aa42940241cc1ef7b72b3b8a22acd7f1eac465069c4b375d129f304dbd9363"), # Config + 2: bytes.fromhex("af1442f4972ca3254d4b496c6c1c55e071a808089f814957c7002c4762fecd15"), # ONNX encrypt+chunk + 3: bytes.fromhex("1bc0a4cfe390d35e0597d4a67451d9c8f62f53df962804a6e6907cddb3d0004b"), # Big ONNX model + 4: bytes.fromhex("c1e03295f3793ee74c685bfe3872ec795e76f731e939abfd09120ada886a9228"), # ONNX model +} + +print("=" * 70) +print("SHA256 Key Derivation Discovery") +print("=" * 70) +print(f"Master key: {KEY!r}") +print(f"SHA256(key) = {hashlib.sha256(KEY).hexdigest()}") +print() + +# Test various derivation schemes +def try_hash(label, data, target_idx=None): + h = hashlib.sha256(data).digest() + for idx, secret in CHUNK_SECRETS.items(): + if target_idx is not None and idx != target_idx: + continue + if h == secret: + print(f" *** MATCH chunk {idx}! *** {label} -> {h.hex()}") + return True + return False + +print("--- Simple hashes ---") +try_hash("SHA256(key)", KEY) +try_hash("SHA256(IV)", IV) +try_hash("SHA256(key+IV)", KEY + IV) +try_hash("SHA256(IV+key)", IV + KEY) + +print("\n--- Key + counter ---") +for i in range(10): + try_hash(f"SHA256(key + uint8({i}))", KEY + bytes([i])) + try_hash(f"SHA256(key + uint32LE({i}))", KEY + struct.pack('12,} (0x{val32:08x}) hex={model[off:off+4].hex()}") + +# Critical check: does any uint64 at header boundary == remaining data? +print(f"\nSize field search at header boundary:") +for i in range(0, 32, 4): + off = h_size + i + if off + 8 <= filesize: + val64 = struct.unpack_from("= h_size - 256: + print(f" [{chunk_start:5d}:{chunk_end:5d}] ent={ent:.3f} uniq={uniq:3d}/256{tag}") + +# Search for substructures within header: look for recurring uint32 patterns +print(f"\nSearching for structure markers in header (first 100 bytes):") +for i in range(0, min(100, h_size), 4): + val = struct.unpack_from("12,} (0x{val:08x})") + +print(f"\n" + "=" * 80) +print("PHASE 4: Sub-model references in DLL") +print("=" * 80) + +submodel_patterns = [ + b'detector', b'Detector', b'recognizer', b'Recognizer', + b'normalizer', b'Normalizer', b'classifier', b'Classifier', + b'dispatch', b'Dispatch', b'barcode', b'Barcode', + b'text_detect', b'text_recog', b'TextDetect', b'TextRecog', + b'CTC', b'transformer', b'Transformer', + b'model_type', b'ModelType', b'model_name', b'ModelName', + b'sub_model', b'SubModel', b'segment', +] + +found = set() +for pattern in submodel_patterns: + for m in re.finditer(pattern, dll, re.IGNORECASE): + s = m.start() + while s > 0 and 0x20 <= dll[s-1] < 0x7f: + s -= 1 + e = m.end() + while e < len(dll) and 0x20 <= dll[e] < 0x7f: + e += 1 + full = dll[s:e].decode('ascii', errors='ignore') + if full not in found and 4 < len(full) < 200 and 'OneOCR' in full or 'model' in full.lower() or 'detect' in full.lower() or 'recog' in full.lower(): + found.add(full) + print(f" 0x{s:08x}: {full}") + +print(f"\n" + "=" * 80) +print("PHASE 5: ORT session creation patterns") +print("=" * 80) + +ort_patterns = [ + b'OrtGetApiBase', b'CreateSession', b'SessionOptions', + b'CreateSessionFromArray', b'OrtApi', b'InferenceSession', + b'SessionFromBuffer', b'CreateSessionFromBuffer', + b'AppendExecutionProvider', b'ModelMetadata', +] + +for pattern in ort_patterns: + idx = 0 + while True: + idx = dll.find(pattern, idx) + if idx < 0: + break + s = idx + while s > 0 and 0x20 <= dll[s-1] < 0x7f: + s -= 1 + e = idx + len(pattern) + while e < len(dll) and 0x20 <= dll[e] < 0x7f: + e += 1 + full = dll[s:e].decode('ascii', errors='ignore') + print(f" 0x{s:08x}: {full[:200]}") + idx = e + +print(f"\n" + "=" * 80) +print("DONE") +print("=" * 80) diff --git a/_archive/attempts/extract_onnx.py b/_archive/attempts/extract_onnx.py new file mode 100644 index 0000000000000000000000000000000000000000..042b31c9d4d673e5dad88a38788ca15764f4c391 --- /dev/null +++ b/_archive/attempts/extract_onnx.py @@ -0,0 +1,235 @@ +"""Extract valid ONNX models from BCryptDecrypt dumps. +Strips 8-byte container header and trailing garbage bytes. +""" +import os +import struct +from pathlib import Path + +DUMP_DIR = Path(r"c:\Users\MattyMroz\Desktop\PROJECTS\ONEOCR\frida_dump") +OUTPUT_DIR = Path(r"c:\Users\MattyMroz\Desktop\PROJECTS\ONEOCR\onnx_models") +OUTPUT_DIR.mkdir(exist_ok=True) + +CONTAINER_HEADER = bytes.fromhex("4a1a082b25000000") +HEADER_LEN = 8 + + +def read_varint(data, pos): + """Read a protobuf varint. Returns (value, new_pos).""" + val = 0 + shift = 0 + while pos < len(data): + b = data[pos]; pos += 1 + val |= (b & 0x7f) << shift + if not (b & 0x80): + break + shift += 7 + return val, pos + + +def measure_protobuf(data): + """Walk through protobuf fields and return the byte length of valid data. + Stops at the first unknown/invalid field for ONNX ModelProto. + Valid fields: 1-9, 14, 20.""" + VALID_FIELDS = {1, 2, 3, 4, 5, 6, 7, 8, 9, 14, 20} + pos = 0 + last_valid = 0 + + while pos < len(data): + start = pos + # Read tag + tag, pos = read_varint(data, pos) + if pos > len(data): + break + field_num = tag >> 3 + wire_type = tag & 7 + + if field_num not in VALID_FIELDS: + return start + + if wire_type == 0: # VARINT + _, pos = read_varint(data, pos) + elif wire_type == 1: # I64 + pos += 8 + elif wire_type == 2: # LEN + length, pos = read_varint(data, pos) + pos += length + elif wire_type == 5: # I32 + pos += 4 + else: + return start + + if pos > len(data): + return start + last_valid = pos + + return last_valid + + +def try_onnx_load(filepath): + try: + import onnx + model = onnx.load(str(filepath)) + return { + 'ir_version': model.ir_version, + 'producer': model.producer_name, + 'producer_version': model.producer_version, + 'opset': [f"{o.domain or 'ai.onnx'}:{o.version}" for o in model.opset_import], + 'graph_name': model.graph.name if model.graph else None, + 'num_nodes': len(model.graph.node) if model.graph else 0, + 'num_inputs': len(model.graph.input) if model.graph else 0, + 'num_outputs': len(model.graph.output) if model.graph else 0, + 'node_types': sorted(set(n.op_type for n in model.graph.node)) if model.graph else [], + } + except Exception as e: + return {'error': str(e)[:200]} + + +def try_ort_load(filepath): + try: + import onnxruntime as ort + sess = ort.InferenceSession(str(filepath), providers=['CPUExecutionProvider']) + return { + 'inputs': [(i.name, i.shape, i.type) for i in sess.get_inputs()], + 'outputs': [(o.name, o.shape, o.type) for o in sess.get_outputs()], + } + except Exception as e: + return {'error': str(e)[:200]} + + +print("=" * 70) +print("EXTRACTING ONNX MODELS (WITH TRAILING GARBAGE REMOVAL)") +print("=" * 70) + +# Clean output dir +for old in OUTPUT_DIR.glob("*.onnx"): + old.unlink() + +files = sorted(DUMP_DIR.glob("decrypt_*.bin"), key=lambda f: f.stat().st_size, reverse=True) +print(f"Total decrypt files: {len(files)}\n") + +models = [] +non_models = [] + +for f in files: + raw = f.read_bytes() + + # Strip container header + if raw[:HEADER_LEN] == CONTAINER_HEADER: + data = raw[HEADER_LEN:] + elif raw[:5] == CONTAINER_HEADER[:5]: + data = raw[HEADER_LEN:] + else: + non_models.append({'src': f.name, 'size': len(raw), 'reason': 'no container header', + 'first_16': raw[:16].hex()}) + continue + + # Check if data starts with valid ONNX (field 1 = ir_version, varint) + if len(data) < 2 or data[0] != 0x08 or data[1] < 1 or data[1] > 12: + preview = data[:40].decode('utf-8', errors='replace') + non_models.append({'src': f.name, 'size': len(raw), 'reason': 'not ONNX', + 'preview': preview}) + continue + + # Measure valid protobuf length (strip trailing garbage) + valid_len = measure_protobuf(data) + trimmed = len(data) - valid_len + onnx_data = data[:valid_len] + + # Determine producer + producer = "unknown" + if b"PyTorch" in data[:100]: + producer = "pytorch" + elif b"onnx.quantize" in data[:100]: + producer = "onnx_quantize" + elif b"pytorch" in data[:100]: + producer = "pytorch_small" + + ir_version = data[1] + + idx = len(models) + fname = f"model_{idx:02d}_ir{ir_version}_{producer}_{valid_len//1024}KB.onnx" + outpath = OUTPUT_DIR / fname + outpath.write_bytes(onnx_data) + + models.append({ + 'src': f.name, 'dst': fname, 'raw_size': len(raw), + 'onnx_size': valid_len, 'trimmed': trimmed, + 'ir_version': ir_version, 'producer': producer, + }) + +print(f"ONNX models extracted: {len(models)}") +print(f"Non-model files: {len(non_models)}") + +# Verify all models +print("\n" + "=" * 70) +print("VERIFICATION WITH onnx + onnxruntime") +print("=" * 70) + +verified_onnx = 0 +verified_ort = 0 + +for m in models: + outpath = OUTPUT_DIR / m['dst'] + + r_onnx = try_onnx_load(outpath) + r_ort = try_ort_load(outpath) + + onnx_ok = 'error' not in r_onnx + ort_ok = 'error' not in r_ort + + if onnx_ok: + verified_onnx += 1 + if ort_ok: + verified_ort += 1 + + status = "OK" if onnx_ok and ort_ok else ("onnx" if onnx_ok else ("ort" if ort_ok else "FAIL")) + + print(f"\n [{status:>4}] {m['dst']}") + print(f" Raw: {m['raw_size']:>10,} -> ONNX: {m['onnx_size']:>10,} (trimmed {m['trimmed']} bytes)") + + if onnx_ok: + r = r_onnx + print(f" graph='{r['graph_name']}', nodes={r['num_nodes']}, " + f"inputs={r['num_inputs']}, outputs={r['num_outputs']}") + print(f" opset: {', '.join(r['opset'][:5])}") + ops = r['node_types'] + print(f" ops({len(ops)}): {', '.join(ops[:15])}") + if len(ops) > 15: + print(f" ... +{len(ops)-15} more") + elif ort_ok: + r = r_ort + for inp in r['inputs']: + print(f" Input: {inp[0]} {inp[1]} {inp[2]}") + for out in r['outputs']: + print(f" Output: {out[0]} {out[1]} {out[2]}") + else: + print(f" onnx: {r_onnx.get('error', '')[:100]}") + print(f" ort: {r_ort.get('error', '')[:100]}") + +# Summary +print("\n" + "=" * 70) +print("FINAL SUMMARY") +print("=" * 70) +print(f"Decrypted dumps: {len(files)}") +print(f"ONNX models: {len(models)}") +print(f" - onnx.load OK: {verified_onnx}") +print(f" - onnxruntime OK: {verified_ort}") +print(f"Non-model data: {len(non_models)}") + +if models: + total = sum(m['onnx_size'] for m in models) + print(f"\nTotal ONNX model size: {total:,} bytes ({total/1024/1024:.1f} MB)") + +print(f"\nNon-model content:") +for nm in non_models[:15]: + desc = nm.get('preview', nm.get('first_16', ''))[:50] + print(f" {nm['src']}: {nm['size']:>10,} bytes | {nm['reason']} | {desc!r}") + +print(f"\n{'='*70}") +print(f"CRYPTO PARAMS (CONFIRMED)") +print(f"{'='*70}") +print(f'Key: kj)TGtrK>f]b[Piow.gU+nC@s""""""4 (32 bytes, raw)') +print(f'IV: Copyright @ OneO (16 bytes)') +print(f"Mode: AES-256-CFB (full block, BCrypt CNG)") +print(f"Container: 8-byte header 4a1a082b25000000 per chunk") +print(f"Model: ONNX protobuf + trailing metadata (trimmed)") diff --git a/_archive/attempts/extract_strings.py b/_archive/attempts/extract_strings.py new file mode 100644 index 0000000000000000000000000000000000000000..511da4610f74e5805b9152918acfc045c4fa814c --- /dev/null +++ b/_archive/attempts/extract_strings.py @@ -0,0 +1,37 @@ +import re + +data = open(r"c:\Users\MattyMroz\Desktop\PROJECTS\ONEOCR\ocr_data\oneocr.dll", "rb").read() + +all_strings = re.findall(b'[\x20-\x7e]{6,}', data) +crypto_keywords = [b'crypt', b'aes', b'bcrypt', b'key', b'iv', b'cipher', b'cfb', b'hash', + b'sha', b'magic', b'decomp', b'uncomp', b'compress', b'model', b'meta', + b'onnx', b'ONNX', b'decrypt', b'encrypt', b'Crypto', b'init', b'blob', + b'MAGIC', b'check', b'Check', b'fail', b'Fail', b'number'] + +print(f"Total strings: {len(all_strings)}") +print() +print("=== Crypto/model-related strings ===") +seen = set() +for s in all_strings: + s_lower = s.lower() + for kw in crypto_keywords: + if kw.lower() in s_lower: + if s not in seen: + seen.add(s) + offset = data.find(s) + text = s.decode("ascii", errors="replace") + print(f" [0x{offset:08x}] {text}") + break + +# Also look for wide strings (UTF-16LE) related to BCrypt +print() +print("=== Wide (UTF-16LE) strings ===") +wide_strings = re.findall(b'(?:[\x20-\x7e]\x00){4,}', data) +for ws in wide_strings: + decoded = ws.decode("utf-16-le", errors="replace") + d_lower = decoded.lower() + for kw in [b'crypt', b'aes', b'cfb', b'chain', b'algorithm', b'key', b'sha', b'hash']: + if kw.decode().lower() in d_lower: + offset = data.find(ws) + print(f" [0x{offset:08x}] {decoded}") + break diff --git a/_archive/attempts/find_offset.py b/_archive/attempts/find_offset.py new file mode 100644 index 0000000000000000000000000000000000000000..e24d8db0f784e9c81aaaf7af6c8ed981e7325274 --- /dev/null +++ b/_archive/attempts/find_offset.py @@ -0,0 +1,44 @@ +"""Map encrypted input bytes from hook to file offsets.""" +from pathlib import Path +import struct + +data = Path("ocr_data/oneocr.onemodel").read_bytes() + +# Encrypted input first bytes from hook (call #, first 32 enc bytes hex, chunk_size) +chunks_encrypted = [ + (0, "2e0c10c7c967f66b6d03821271115ad6c19ca7d91b668e5c484018e02c9632b4", 22624), + (2, "f7d14a6dbd04af02b6de5e5454af59d007bb5c174e3b6be6a73513b995c7dc1a", 11920), + (4, "7bf021af201c559217035b95ebf758ff70c860f126c9c1529421bb2d75898bf9", 11553680), +] + +print("Searching for encrypted chunk starts in file:") +print(f"File size: {len(data):,}") +print() + +prev_end = 0 +for call_num, hex_str, chunk_size in chunks_encrypted: + search_bytes = bytes.fromhex(hex_str[:16]) # First 8 bytes + idx = data.find(search_bytes) + if idx >= 0: + gap = idx - prev_end if prev_end > 0 else idx + print(f" Call #{call_num}: offset {idx} ({idx:#x}), size={chunk_size:,}, gap={gap}") + print(f" Range: [{idx:#x}, {idx+chunk_size:#x})") + prev_end = idx + chunk_size + + full = bytes.fromhex(hex_str) + if data[idx:idx+len(full)] == full: + print(f" 32-byte match: OK") + else: + print(f" Call #{call_num}: NOT FOUND") + +# File structure +print(f"\n--- File structure ---") +print(f"Offset 0: header_size = {struct.unpack_from(' 0 && !this.pbIV.isNull()) { + try { + info.iv = []; + var ivBuf = this.pbIV.readByteArray(this.cbIV); + var ivArr = new Uint8Array(ivBuf); + for (var k = 0; k < ivArr.length; k++) info.iv.push(ivArr[k]); + } catch(e) {} + } + + send({type: 'decrypt_call', info: info}); + + if (status === 0 && cbResult >= MIN_SIZE && !this.pbOutput.isNull()) { + try { + var data = this.pbOutput.readByteArray(cbResult); + send({type: 'decrypt_data', call: this.callNum, size: cbResult}, data); + } catch(e) { + send({type: 'log', msg: 'Read output failed: ' + e}); + } + } + } + }); + send({type: 'log', msg: 'Hooked BCryptDecrypt at ' + bcryptDecrypt}); +} else { + send({type: 'log', msg: 'ERROR: BCryptDecrypt not found'}); +} + +// Hook BCryptGenerateSymmetricKey +var bcryptGenKey = Module.findExportByName('bcrypt.dll', 'BCryptGenerateSymmetricKey'); +if (bcryptGenKey) { + Interceptor.attach(bcryptGenKey, { + onEnter: function(args) { + this.pbSecret = args[3]; + this.cbSecret = args[4].toInt32(); + }, + onLeave: function(retval) { + if (retval.toInt32() === 0 && this.cbSecret > 0) { + try { + var keyBuf = this.pbSecret.readByteArray(this.cbSecret); + var keyArr = new Uint8Array(keyBuf); + var arr = []; + for (var i = 0; i < keyArr.length; i++) arr.push(keyArr[i]); + send({type: 'key_generated', size: this.cbSecret, key: arr}); + } catch(e) {} + } + } + }); + send({type: 'log', msg: 'Hooked BCryptGenerateSymmetricKey'}); +} + +// Hook BCryptSetProperty +var bcryptSetProp = Module.findExportByName('bcrypt.dll', 'BCryptSetProperty'); +if (bcryptSetProp) { + Interceptor.attach(bcryptSetProp, { + onEnter: function(args) { + try { + var propName = args[1].readUtf16String(); + var cbInput = args[3].toInt32(); + var propValue = null; + if (cbInput > 0 && cbInput < 256 && !args[2].isNull()) { + try { propValue = args[2].readUtf16String(); } catch(e2) {} + } + send({type: 'set_property', name: propName, value: propValue, size: cbInput}); + } catch(e) {} + } + }); + send({type: 'log', msg: 'Hooked BCryptSetProperty'}); +} + +send({type: 'log', msg: 'All hooks installed. Ready.'}); +""" + + +def create_loader_script(): + """Create a small Python script that loads oneocr.dll and creates a pipeline.""" + script = r''' +import ctypes +from ctypes import c_int64, c_char_p, POINTER, byref +import time +import sys +import os + +DLL_DIR = r"c:\Users\MattyMroz\Desktop\PROJECTS\ONEOCR\ocr_data" +MODEL_PATH = os.path.join(DLL_DIR, "oneocr.onemodel") +KEY = b'kj)TGtrK>f]b[Piow.gU+nC@s""""""4' + +# Load DLLs +kernel32 = ctypes.WinDLL("kernel32", use_last_error=True) +kernel32.SetDllDirectoryW(DLL_DIR) +dll = ctypes.WinDLL(os.path.join(DLL_DIR, "oneocr.dll")) + +# Setup function types +dll.CreateOcrInitOptions.argtypes = [POINTER(c_int64)] +dll.CreateOcrInitOptions.restype = c_int64 +dll.OcrInitOptionsSetUseModelDelayLoad.argtypes = [c_int64, ctypes.c_char] +dll.OcrInitOptionsSetUseModelDelayLoad.restype = c_int64 +dll.CreateOcrPipeline.argtypes = [c_char_p, c_char_p, c_int64, POINTER(c_int64)] +dll.CreateOcrPipeline.restype = c_int64 + +# Create init options +init_options = c_int64() +ret = dll.CreateOcrInitOptions(byref(init_options)) +print(f"LOADER: CreateOcrInitOptions -> {ret}", flush=True) +assert ret == 0 + +ret = dll.OcrInitOptionsSetUseModelDelayLoad(init_options, 0) +print(f"LOADER: SetUseModelDelayLoad -> {ret}", flush=True) +assert ret == 0 + +# Create pipeline (this triggers decryption!) +pipeline = c_int64() +model_buf = ctypes.create_string_buffer(MODEL_PATH.encode()) +key_buf = ctypes.create_string_buffer(KEY) + +print("LOADER: Creating OCR pipeline (triggers decryption)...", flush=True) +ret = dll.CreateOcrPipeline(model_buf, key_buf, init_options, byref(pipeline)) +print(f"LOADER: CreateOcrPipeline returned {ret}, pipeline={pipeline.value}", flush=True) + +if ret != 0: + print(f"LOADER: ERROR - return code {ret}", flush=True) + sys.exit(1) + +print("LOADER: Pipeline created successfully! Waiting...", flush=True) +time.sleep(5) +print("LOADER: Done.", flush=True) +''' + loader_path = Path(r"c:\Users\MattyMroz\Desktop\PROJECTS\ONEOCR\frida_loader.py") + loader_path.write_text(script) + return loader_path + + +def on_message(message, data): + """Handle messages from Frida script.""" + if message['type'] == 'send': + payload = message['payload'] + msg_type = payload.get('type', '') + + if msg_type == 'log': + print(f"[FRIDA] {payload['msg']}") + + elif msg_type == 'decrypt_call': + info = payload['info'] + iv_hex = '' + if 'iv' in info: + iv_hex = bytes(info['iv']).hex() + print(f"[DECRYPT #{info['call']}] status={info['status']} " + f"in={info['inputSize']} out={info['outputSize']} " + f"iv_size={info['ivSize']} iv={iv_hex[:32]}... flags={info['flags']}") + + elif msg_type == 'decrypt_data': + call_num = payload['call'] + size = payload['size'] + fname = OUTPUT_DIR / f"decrypt_{call_num}_{size}bytes.bin" + fname.write_bytes(data) + + # Check first 4 bytes for magic number + magic = struct.unpack('= 4 else 0 + first_16 = data[:16].hex() if data else '' + print(f" -> Saved {fname.name} | magic={magic} | first_16={first_16}") + + if magic == 1: + print(f" *** MAGIC NUMBER == 1 FOUND! This is the decrypted model container! ***") + + elif msg_type == 'key_generated': + key_bytes = bytes(payload['key']) + print(f"[KEY] size={payload['size']} key={key_bytes}") + try: + print(f" ASCII: {key_bytes.decode('ascii', errors='replace')}") + except: + pass + + elif msg_type == 'set_property': + print(f"[PROPERTY] {payload['name']} = {payload['value']} (size={payload['size']})") + + elif msg_type == 'uncompress': + print(f"[UNCOMPRESS] sourceLen={payload['sourceLen']} -> destLen={payload['destLen']}") + + elif msg_type == 'uncompress_data': + size = payload['size'] + fname = OUTPUT_DIR / f"uncompressed_{size}bytes.bin" + fname.write_bytes(data) + first_32 = data[:32].hex() if data else '' + print(f" -> Saved {fname.name} | first_32={first_32}") + + elif msg_type == 'ort_export': + print(f"[ORT] {payload['name']} @ {payload['addr']}") + + else: + print(f"[MSG] {payload}") + + elif message['type'] == 'error': + print(f"[FRIDA ERROR] {message['description']}") + if 'stack' in message: + print(message['stack']) + + +def main(): + print("=" * 70) + print("FRIDA HOOKING: Intercepting OneOCR model decryption") + print("=" * 70) + + # Create loader script + loader_path = create_loader_script() + print(f"Loader script: {loader_path}") + + # Find Python executable in venv + venv_python = Path(r"c:\Users\MattyMroz\Desktop\PROJECTS\ONEOCR\.venv\Scripts\python.exe") + if not venv_python.exists(): + print("ERROR: Python venv not found") + sys.exit(1) + + # Spawn the loader process + print(f"Spawning: {venv_python} {loader_path}") + pid = frida.spawn([str(venv_python), str(loader_path)]) + print(f"Process spawned, PID={pid}") + + session = frida.attach(pid) + print("Attached to process") + + script = session.create_script(FRIDA_SCRIPT) + script.on('message', on_message) + script.load() + print("Script loaded, resuming process...") + + frida.resume(pid) + + # Wait for the process to finish + print("Waiting for process to complete...") + try: + # Wait up to 60 seconds + for _ in range(120): + time.sleep(0.5) + try: + # Check if process is still alive + session.is_detached + except: + break + except KeyboardInterrupt: + print("\nInterrupted by user") + except frida.InvalidOperationError: + print("Process terminated") + + # Summary + print() + print("=" * 70) + print("RESULTS") + print("=" * 70) + + if OUTPUT_DIR.exists(): + files = sorted(OUTPUT_DIR.iterdir()) + if files: + print(f"Dumped {len(files)} files:") + for f in files: + size = f.stat().st_size + print(f" {f.name}: {size:,} bytes") + if size >= 4: + header = open(f, 'rb').read(16) + magic = struct.unpack('f]b[Piow.gU+nC@s""""""4' + +# Load DLLs +kernel32 = ctypes.WinDLL("kernel32", use_last_error=True) +kernel32.SetDllDirectoryW(DLL_DIR) +dll = ctypes.WinDLL(os.path.join(DLL_DIR, "oneocr.dll")) + +# Setup function types +dll.CreateOcrInitOptions.argtypes = [POINTER(c_int64)] +dll.CreateOcrInitOptions.restype = c_int64 +dll.OcrInitOptionsSetUseModelDelayLoad.argtypes = [c_int64, ctypes.c_char] +dll.OcrInitOptionsSetUseModelDelayLoad.restype = c_int64 +dll.CreateOcrPipeline.argtypes = [c_char_p, c_char_p, c_int64, POINTER(c_int64)] +dll.CreateOcrPipeline.restype = c_int64 + +# Create init options +init_options = c_int64() +ret = dll.CreateOcrInitOptions(byref(init_options)) +print(f"LOADER: CreateOcrInitOptions -> {ret}", flush=True) +assert ret == 0 + +ret = dll.OcrInitOptionsSetUseModelDelayLoad(init_options, 0) +print(f"LOADER: SetUseModelDelayLoad -> {ret}", flush=True) +assert ret == 0 + +# Create pipeline (this triggers decryption!) +pipeline = c_int64() +model_buf = ctypes.create_string_buffer(MODEL_PATH.encode()) +key_buf = ctypes.create_string_buffer(KEY) + +print("LOADER: Creating OCR pipeline (triggers decryption)...", flush=True) +ret = dll.CreateOcrPipeline(model_buf, key_buf, init_options, byref(pipeline)) +print(f"LOADER: CreateOcrPipeline returned {ret}, pipeline={pipeline.value}", flush=True) + +if ret != 0: + print(f"LOADER: ERROR - return code {ret}", flush=True) + sys.exit(1) + +print("LOADER: Pipeline created successfully! Waiting...", flush=True) +time.sleep(5) +print("LOADER: Done.", flush=True) diff --git a/_archive/attempts/peek_header.py b/_archive/attempts/peek_header.py new file mode 100644 index 0000000000000000000000000000000000000000..1105ab2806b0fff71d72d0bc860c729afda7cf37 --- /dev/null +++ b/_archive/attempts/peek_header.py @@ -0,0 +1,92 @@ +import struct + +filepath = r"c:\Users\MattyMroz\Desktop\PROJECTS\ONEOCR\ocr_data\oneocr.onemodel" + +with open(filepath, "rb") as f: + data = f.read(23000) # read a bit more than 22636 + f.seek(0, 2) + filesize = f.tell() + +print(f"File size: {filesize} bytes ({filesize/1024/1024:.2f} MB)") +print() + +# Hex dump first 512 bytes +print("=== First 512 bytes hex dump ===") +for i in range(0, 512, 16): + hex_part = " ".join(f"{b:02x}" for b in data[i:i+16]) + ascii_part = "".join(chr(b) if 32 <= b < 127 else "." for b in data[i:i+16]) + print(f"{i:08x}: {hex_part:<48s} {ascii_part}") + +print() +print("=== uint32 LE values at key offsets ===") +for off in range(0, 64, 4): + val = struct.unpack_from("= 4 chars found in header") + +# Check for potential magic numbers +print() +print("=== Magic number checks at offset 0 ===") +print(f" Bytes 0-3: {data[0:4].hex()}") +print(f" Bytes 0-7: {data[0:8].hex()}") +print(f" As string: {data[0:8]}") + +# Look for repeating 4-byte patterns +print() +print("=== Byte frequency in first 64 bytes ===") +for i in range(64): + if i % 16 == 0: + print(f" {i:3d}: ", end="") + print(f"{data[i]:3d}", end=" ") + if i % 16 == 15: + print() + +# Check if header has structure - look for uint32 values that could be offsets/sizes +print() +print("=== Potential offset/size table at start ===") +for i in range(0, min(256, len(header)), 4): + val = struct.unpack_from("f]b[Piow.gU+nC@s""""""4' +IV = b"Copyright @ OneO" +CONTAINER_HEADER = bytes.fromhex("4a1a082b25000000") +ONNX_VALID_FIELDS = {1, 2, 3, 4, 5, 6, 7, 8, 9, 14, 20} + +# BCrypt constants +BCRYPT_AES = "AES\0".encode('utf-16-le') +BCRYPT_CHAINING_MODE = "ChainingMode\0".encode('utf-16-le') +BCRYPT_CHAIN_MODE_CFB = "ChainingModeCFB\0".encode('utf-16-le') + +bcrypt = ctypes.windll.bcrypt + + +class BCRYPT_KEY_DATA_BLOB_HEADER(ctypes.Structure): + _fields_ = [ + ("dwMagic", c_ulong), + ("dwVersion", c_ulong), + ("cbKeyData", c_ulong), + ] + + +def setup_bcrypt(): + hAlg = c_void_p() + assert bcrypt.BCryptOpenAlgorithmProvider(byref(hAlg), BCRYPT_AES, None, 0) == 0 + assert bcrypt.BCryptSetProperty(hAlg, BCRYPT_CHAINING_MODE, + BCRYPT_CHAIN_MODE_CFB, len(BCRYPT_CHAIN_MODE_CFB), 0) == 0 + header = BCRYPT_KEY_DATA_BLOB_HEADER(dwMagic=0x4d42444b, dwVersion=1, cbKeyData=len(KEY)) + blob = bytes(header) + KEY + hKey = c_void_p() + assert bcrypt.BCryptGenerateSymmetricKey(hAlg, byref(hKey), None, 0, blob, len(blob), 0) == 0 + return hAlg, hKey + + +def bcrypt_op(hKey, data, encrypt=False): + """Encrypt or decrypt data using BCrypt AES-CFB with fresh IV.""" + iv = bytearray(IV) + func = bcrypt.BCryptEncrypt if encrypt else bcrypt.BCryptDecrypt + result_size = c_ulong(0) + func(hKey, data, len(data), None, None, 0, None, 0, byref(result_size), 0) + output = (ctypes.c_ubyte * result_size.value)() + actual = c_ulong(0) + status = func(hKey, data, len(data), None, + (ctypes.c_ubyte * len(iv))(*iv), len(iv), + output, result_size.value, byref(actual), 0) + assert status == 0, f"BCrypt op failed: {status:#x}" + return bytes(output[:actual.value]) + + +def read_varint(data, pos): + val = 0; shift = 0 + while pos < len(data): + b = data[pos]; pos += 1 + val |= (b & 0x7f) << shift + if not (b & 0x80): break + shift += 7 + return val, pos + + +def measure_onnx(data): + pos = 0; last = 0 + while pos < len(data): + start = pos + tag, pos = read_varint(data, pos) + if pos > len(data): break + fn = tag >> 3; wt = tag & 7 + if fn not in ONNX_VALID_FIELDS: return start + if wt == 0: _, pos = read_varint(data, pos) + elif wt == 1: pos += 8 + elif wt == 2: l, pos = read_varint(data, pos); pos += l + elif wt == 5: pos += 4 + else: return start + if pos > len(data): return start + last = pos + return last + + +def main(): + import argparse + parser = argparse.ArgumentParser(description="OneOCR .onemodel decryptor (Windows BCrypt)") + parser.add_argument("model_path", nargs="?", default="ocr_data/oneocr.onemodel") + parser.add_argument("-o", "--output", default="onnx_models_static") + args = parser.parse_args() + + model_path = Path(args.model_path) + output_dir = Path(args.output) + output_dir.mkdir(exist_ok=True, parents=True) + for old in output_dir.glob("*"): old.unlink() + + data = model_path.read_bytes() + print(f"{'='*70}") + print(f"OneOCR Static Decryptor (BCrypt CNG)") + print(f"{'='*70}") + print(f"File: {model_path} ({len(data):,} bytes)") + + hAlg, hKey = setup_bcrypt() + print(f"AES-256-CFB initialized") + + # Step 1: Decrypt DX index (offset 24, size 22624) + dx_offset = 24 + dx_size = 22624 + dx_dec = bcrypt_op(hKey, data[dx_offset:dx_offset + dx_size]) + print(f"\nDX index: starts with {dx_dec[:2].hex()}") + assert dx_dec[:2] == b'DX', f"DX header not found! Got: {dx_dec[:8].hex()}" + (output_dir / "dx_index.bin").write_bytes(dx_dec) + + # Step 2: Parse DX to find embedded chunks + # DX contains sub-chunks that need independent decryption + # We'll also find main payload chunks by scanning the file + + # The DX contains a list of uint64 values that might be chunk sizes/offsets + dx_values = [] + for i in range(0, len(dx_dec) - 7, 8): + v = struct.unpack_from(' 0 and v < len(data): + dx_values.append((i, v)) + + # Step 3: Try to decrypt every possible chunk in the payload area + # Payload starts after DX (offset 22648) + 36 bytes gap = 22684 + payload_start = dx_offset + dx_size + 36 + + print(f"\n--- Scanning payload for encrypted chunks ---") + print(f"Payload starts at offset {payload_start}") + + # Strategy: try decrypting at current offset, check if result starts + # with container magic. If yes, extract chunk, determine its size + # from the DX index or by scanning forward. + + # Known chunk sizes from the DX index analysis: + # We know the DX has entries like 11943, 11903, 11927 etc. + # And the main payload has large ONNX models. + + # Let's try a different approach: scan the encrypted file for positions + # where decryption produces valid container magic + + print(f"\nSearching for chunk boundaries by trial decryption...") + + # The container magic `4a1a082b25000000` after decryption = specific encrypted pattern + # Compute what the container magic encrypts TO: + magic_encrypted = bcrypt_op(hKey, CONTAINER_HEADER, encrypt=True) + print(f"Container magic encrypted: {magic_encrypted.hex()}") + + # Search for this pattern in the payload area + chunk_starts = [] + search_start = payload_start + + # Also check DX sub-chunks + # First, find container magic encryptions within the DX encrypted data + + while search_start < len(data) - 16: + idx = data.find(magic_encrypted[:8], search_start) + if idx < 0: + break + # Verify by decrypting 16 bytes + test = bcrypt_op(hKey, data[idx:idx+16]) + if test[:8] == CONTAINER_HEADER: + chunk_starts.append(idx) + search_start = idx + 1 + else: + search_start = idx + 1 + + print(f"Found {len(chunk_starts)} potential chunk starts") + + if not chunk_starts: + # Fallback: just try sequential decryption + print("No chunk starts found via magic pattern. Trying sequential...") + # Try decrypting from payload_start with large block sizes + remaining = len(data) - payload_start + dec = bcrypt_op(hKey, data[payload_start:payload_start + remaining]) + + # Find container magic in decrypted data + pos = 0 + chunks_data = [] + while True: + idx = dec.find(CONTAINER_HEADER, pos) + if idx < 0: + # Handle remaining data + if pos < len(dec): + chunks_data.append(dec[pos:]) + break + if idx > pos: + chunks_data.append(dec[pos:idx]) + pos = idx # Will be split on next iteration + # Find next occurrence + next_idx = dec.find(CONTAINER_HEADER, pos + 8) + if next_idx < 0: + chunks_data.append(dec[pos:]) + break + chunks_data.append(dec[pos:next_idx]) + pos = next_idx + + print(f"Found {len(chunks_data)} chunks in sequential decryption") + else: + # Decrypt each chunk + chunk_starts.sort() + chunks_data = [] + for i, start in enumerate(chunk_starts): + end = chunk_starts[i + 1] if i + 1 < len(chunk_starts) else len(data) + encrypted = data[start:end] + try: + dec = bcrypt_op(hKey, encrypted) + chunks_data.append(dec) + except: + pass + + # Extract models from chunks + print(f"\n--- Extracting ONNX models ---") + models = [] + data_files = [] + + for chunk in chunks_data: + if chunk[:8] == CONTAINER_HEADER: + payload = chunk[8:] + else: + payload = chunk + + if len(payload) >= 2 and payload[0] == 0x08 and 1 <= payload[1] <= 12: + valid_len = measure_onnx(payload) + onnx_data = payload[:valid_len] + if valid_len < 100: # Too small to be a real model + continue + + producer = "unknown" + if b"PyTorch" in payload[:100]: producer = "pytorch" + elif b"onnx.quantize" in payload[:100]: producer = "onnx_quantize" + elif b"pytorch" in payload[:100]: producer = "pytorch_small" + + ir = payload[1] + idx = len(models) + fname = f"model_{idx:02d}_ir{ir}_{producer}_{valid_len//1024}KB.onnx" + (output_dir / fname).write_bytes(onnx_data) + models.append({'name': fname, 'size': valid_len}) + print(f" ONNX: {fname} ({valid_len:,} bytes)") + elif len(payload) > 100: + preview = payload[:30].decode('utf-8', errors='replace') + idx = len(data_files) + fname = f"data_{idx:02d}_{len(payload)}B.bin" + (output_dir / fname).write_bytes(payload) + data_files.append({'name': fname, 'size': len(payload)}) + print(f" Data: {fname} ({len(payload):,} bytes) {preview[:30]!r}") + + # Summary + print(f"\n{'='*70}") + print(f"EXTRACTION COMPLETE") + print(f"{'='*70}") + print(f"ONNX models: {len(models)}") + print(f"Data files: {len(data_files)}") + if models: + total = sum(m['size'] for m in models) + print(f"Total ONNX: {total:,} bytes ({total/1024/1024:.1f} MB)") + + # Verify + try: + import onnx + ok = sum(1 for m in models if not _try_load(onnx, output_dir / m['name'])) + ok = 0 + for m in models: + try: + onnx.load(str(output_dir / m['name'])) + ok += 1 + except: + pass + print(f"Verified with onnx.load: {ok}/{len(models)}") + except ImportError: + pass + + bcrypt.BCryptDestroyKey(hKey) + bcrypt.BCryptCloseAlgorithmProvider(hAlg, 0) + + +if __name__ == "__main__": + main() diff --git a/_archive/attempts/verify_bcrypt.py b/_archive/attempts/verify_bcrypt.py new file mode 100644 index 0000000000000000000000000000000000000000..1a83a3ea96d4a76eadcfea4aa009329083feb282 --- /dev/null +++ b/_archive/attempts/verify_bcrypt.py @@ -0,0 +1,181 @@ +"""Verify BCrypt CNG setup - test raw key + different CFB segment sizes.""" +import ctypes +from ctypes import c_void_p, c_ulong, byref +from pathlib import Path +import struct + +KEY = b'kj)TGtrK>f]b[Piow.gU+nC@s""""""4' +IV = b"Copyright @ OneO" + +bcrypt = ctypes.windll.bcrypt + +# Known plaintext (DX header from hook dump) +dx_plain = bytes.fromhex("44580000000000005c58000000000000") +# Known ciphertext (from file at offset 24, first 16 bytes) +file_ct = bytes.fromhex("2e0c10c7c967f66b6d03821271115ad6") + +# Full file data +file_data = Path("ocr_data/oneocr.onemodel").read_bytes() +hook_dx = Path("frida_dump/decrypt_1_in22624_out22624.bin").read_bytes() + +print("=" * 70) +print("BCrypt CNG CFB Segment Size Test") +print("=" * 70) +print(f"KEY: {KEY}") +print(f"IV: {IV}") +print(f"Expected PT: {dx_plain.hex()}") +print(f"Expected CT: {file_ct.hex()}") +print() + + +def test_cfb(msg_block_length, use_blob=False): + """Test BCrypt AES-CFB with given MessageBlockLength.""" + tag = "MBL={}".format("default" if msg_block_length is None else msg_block_length) + if use_blob: + tag += "+blob" + + hAlg = c_void_p() + status = bcrypt.BCryptOpenAlgorithmProvider( + byref(hAlg), "AES\0".encode("utf-16-le"), None, 0 + ) + if status != 0: + print(" [{}] OpenAlgorithm failed: {:#010x}".format(tag, status)) + return None + + mode = "ChainingModeCFB\0".encode("utf-16-le") + status = bcrypt.BCryptSetProperty( + hAlg, "ChainingMode\0".encode("utf-16-le"), mode, len(mode), 0 + ) + if status != 0: + print(" [{}] SetProperty ChainingMode failed: {:#010x}".format(tag, status)) + bcrypt.BCryptCloseAlgorithmProvider(hAlg, 0) + return None + + if msg_block_length is not None: + mbl = c_ulong(msg_block_length) + status = bcrypt.BCryptSetProperty( + hAlg, "MessageBlockLength\0".encode("utf-16-le"), + byref(mbl), 4, 0 + ) + if status != 0: + print(" [{}] SetProperty MBL={} failed: {:#010x}".format(tag, msg_block_length, status)) + bcrypt.BCryptCloseAlgorithmProvider(hAlg, 0) + return None + + hKey = c_void_p() + if use_blob: + blob = struct.pack('CT: {} {} {}".format(tag, our_ct[:16].hex(), "OK" if ct_match else "FAIL", mark)) + print(" [{}] Dec->PT: {} {}".format(tag, our_pt[:16].hex(), "OK DX" if pt_match else "FAIL")) + + bcrypt.BCryptDestroyKey(hKey) + bcrypt.BCryptDestroyKey(hKey2) + bcrypt.BCryptCloseAlgorithmProvider(hAlg, 0) + return ct_match + + +print("--- Raw key (correct for BCryptGenerateSymmetricKey) ---") +test_cfb(None) +test_cfb(1) +test_cfb(16) +print() + +print("--- Blob key (has 12-byte header prepended - wrong) ---") +test_cfb(None, use_blob=True) +test_cfb(1, use_blob=True) +test_cfb(16, use_blob=True) +print() + +print("--- BCryptImportKey with BCRYPT_KEY_DATA_BLOB ---") +for mbl in [None, 1, 16]: + tag = "Import+MBL={}".format("default" if mbl is None else mbl) + hAlg = c_void_p() + bcrypt.BCryptOpenAlgorithmProvider(byref(hAlg), "AES\0".encode("utf-16-le"), None, 0) + mode = "ChainingModeCFB\0".encode("utf-16-le") + bcrypt.BCryptSetProperty(hAlg, "ChainingMode\0".encode("utf-16-le"), mode, len(mode), 0) + + if mbl is not None: + mbl_val = c_ulong(mbl) + bcrypt.BCryptSetProperty(hAlg, "MessageBlockLength\0".encode("utf-16-le"), + byref(mbl_val), 4, 0) + + blob = struct.pack('f]b[Piow.gU+nC@s""""""4' +IV = b"Copyright @ OneO" + +file_data = Path("ocr_data/oneocr.onemodel").read_bytes() + +# Step 1: Derive DX key +header_hash = file_data[8:24] +derived_key = hashlib.sha256(KEY + header_hash).digest() +print(f"DX derived key: {derived_key.hex()}") + +# Step 2: Decrypt DX index +encrypted_dx = file_data[24:24 + 22624] +cipher = AES.new(derived_key, AES.MODE_CFB, iv=IV, segment_size=128) +dx = cipher.decrypt(encrypted_dx) + +assert dx[:2] == b"DX", "DX header mismatch!" +valid_size = struct.unpack('= 0: + print(f" {name}: found at DX offset {pos} ({pos:#x})") + else: + print(f" {name}: NOT found in DX (len={len(target)})") + +# Step 5: Analyze DX structure around container header magic +magic = bytes.fromhex("4a1a082b25000000") +print(f"\nContainer magic 4a1a082b25000000 locations:") +pos = 0 +while True: + pos = dx.find(magic, pos) + if pos < 0: + break + # Read surrounding context + ctx = dx[pos:pos+40] + print(f" offset {pos} ({pos:#x}): {ctx.hex()}") + pos += 1 + +# Step 6: Parse DX as record-based structure +# Looking at the structure: +# Offset 0-7: "DX\x00\x00\x00\x00\x00\x00" +# Offset 8-15: valid_size (uint64) = 22620 +# Offset 16-23: container magic = 4a1a082b25000000 +# Offset 24-31: uint64 = 0x2ea7 = 11943 +# Let's see what's after that + +print(f"\n--- DX parsed fields ---") +off = 0 +print(f" [{off}] Magic: {dx[off:off+8]}") +off = 8 +print(f" [{off}] ValidSize: {struct.unpack(' dict | None: + """Try to parse the first few fields of an ONNX ModelProto protobuf.""" + # ONNX ModelProto: + # field 1 (varint) = ir_version + # field 2 (len-delimited) = opset_import (repeated) + # field 3 (len-delimited) = producer_name + # field 4 (len-delimited) = producer_version + # field 5 (len-delimited) = domain + # field 6 (varint) = model_version + # field 7 (len-delimited) = doc_string + # field 8 (len-delimited) = graph (GraphProto) + + if len(data) < 4: + return None + + pos = 0 + result = {} + + try: + # Field 1: ir_version (varint, field tag = 0x08) + if data[pos] != 0x08: + return None + pos += 1 + + # Read varint + ir_version = 0 + shift = 0 + while pos < len(data): + b = data[pos] + pos += 1 + ir_version |= (b & 0x7F) << shift + if not (b & 0x80): + break + shift += 7 + + if ir_version < 1 or ir_version > 12: + return None + result['ir_version'] = ir_version + + # Next field - check tag + if pos >= len(data): + return None + + tag = data[pos] + field_num = tag >> 3 + wire_type = tag & 0x07 + + # We expect field 2 (opset_import, len-delimited, tag=0x12) or + # field 3 (producer_name, len-delimited, tag=0x1a) + if tag == 0x12: # field 2, length-delimited + pos += 1 + # Read length varint + length = 0 + shift = 0 + while pos < len(data): + b = data[pos] + pos += 1 + length |= (b & 0x7F) << shift + if not (b & 0x80): + break + shift += 7 + + if length > 0 and length < len(data): + result['has_opset_or_producer'] = True + result['next_field_len'] = length + else: + return None + elif tag == 0x1a: # field 3, length-delimited + pos += 1 + length = 0 + shift = 0 + while pos < len(data): + b = data[pos] + pos += 1 + length |= (b & 0x7F) << shift + if not (b & 0x80): + break + shift += 7 + + if length > 0 and length < 1000: + producer = data[pos:pos+length] + try: + result['producer_name'] = producer.decode('utf-8', errors='strict') + except: + result['producer_name'] = f"" + result['has_opset_or_producer'] = True + else: + return None + + return result + + except (IndexError, ValueError): + return None + + +def check_onnx_with_lib(filepath: str) -> dict | None: + """Try loading with onnx library.""" + try: + import onnx + model = onnx.load(filepath) + return { + 'ir_version': model.ir_version, + 'producer': model.producer_name, + 'model_version': model.model_version, + 'opset': [f"{o.domain or 'ai.onnx'}:{o.version}" for o in model.opset_import], + 'graph_name': model.graph.name if model.graph else None, + 'num_nodes': len(model.graph.node) if model.graph else 0, + 'num_inputs': len(model.graph.input) if model.graph else 0, + 'num_outputs': len(model.graph.output) if model.graph else 0, + } + except Exception as e: + return None + + +# Phase 1: Quick protobuf header scan +print("=" * 70) +print("PHASE 1: Quick protobuf header scan") +print("=" * 70) + +candidates = [] +files = sorted(EXTRACT_DIR.glob("*.bin"), key=lambda f: f.stat().st_size, reverse=True) +print(f"Total files: {len(files)}") + +for f in files: + size = f.stat().st_size + if size < 1000: # Skip tiny files + continue + + with open(f, 'rb') as fh: + header = fh.read(256) + + info = try_parse_onnx_protobuf(header) + if info and info.get('ir_version', 0) >= 3: + candidates.append((f, size, info)) + +print(f"Candidates with valid ONNX protobuf header: {len(candidates)}") +print() + +# Group by ir_version +from collections import Counter +ir_counts = Counter(c[2]['ir_version'] for c in candidates) +print("IR version distribution:") +for v, cnt in sorted(ir_counts.items()): + total_size = sum(c[1] for c in candidates if c[2]['ir_version'] == v) + print(f" ir_version={v}: {cnt} files, total {total_size/1024/1024:.1f} MB") + +# Phase 2: Try onnx.load on top candidates (by size, unique sizes to avoid duplicates) +print() +print("=" * 70) +print("PHASE 2: Verify with onnx library (top candidates by size)") +print("=" * 70) + +# Take unique sizes - many files may be near-duplicates from overlapping memory +seen_sizes = set() +unique_candidates = [] +for f, size, info in candidates: + # Round to nearest 1KB to detect near-duplicates + size_key = size // 1024 + if size_key not in seen_sizes: + seen_sizes.add(size_key) + unique_candidates.append((f, size, info)) + +print(f"Unique-size candidates: {len(unique_candidates)}") +print() + +verified = [] +for i, (f, size, info) in enumerate(unique_candidates[:50]): # Check top 50 by size + result = check_onnx_with_lib(str(f)) + if result: + verified.append((f, size, result)) + print(f" VALID ONNX: {f.name}") + print(f" Size: {size/1024:.0f} KB") + print(f" ir={result['ir_version']} producer='{result['producer']}' " + f"opset={result['opset']}") + print(f" graph='{result['graph_name']}' nodes={result['num_nodes']} " + f"inputs={result['num_inputs']} outputs={result['num_outputs']}") + + # Copy to verified dir + import shutil + dest_name = f"model_{len(verified):02d}_ir{result['ir_version']}_{result['graph_name'] or 'unknown'}_{size//1024}KB.onnx" + # Clean filename + dest_name = dest_name.replace('/', '_').replace('\\', '_').replace(':', '_') + dest = VERIFIED_DIR / dest_name + shutil.copy2(f, dest) + print(f" -> Saved as {dest_name}") + print() + +if not verified: + print(" No files passed onnx.load validation in top 50.") + print() + # Try even more + print(" Trying ALL candidates...") + for i, (f, size, info) in enumerate(unique_candidates): + if i < 50: + continue + result = check_onnx_with_lib(str(f)) + if result: + verified.append((f, size, result)) + print(f" VALID ONNX: {f.name}") + print(f" Size: {size/1024:.0f} KB, ir={result['ir_version']}, " + f"producer='{result['producer']}', nodes={result['num_nodes']}") + + import shutil + dest_name = f"model_{len(verified):02d}_ir{result['ir_version']}_{result['graph_name'] or 'unknown'}_{size//1024}KB.onnx" + dest_name = dest_name.replace('/', '_').replace('\\', '_').replace(':', '_') + dest = VERIFIED_DIR / dest_name + shutil.copy2(f, dest) + +print() +print("=" * 70) +print(f"SUMMARY: {len(verified)} verified ONNX models out of {len(candidates)} candidates") +print("=" * 70) + +if verified: + total_size = sum(v[1] for v in verified) + print(f"Total size: {total_size/1024/1024:.1f} MB") + for f, size, result in verified: + print(f" {f.name}: {size/1024:.0f}KB, {result['num_nodes']} nodes, " + f"graph='{result['graph_name']}'") diff --git a/_archive/brainstorm.md b/_archive/brainstorm.md new file mode 100644 index 0000000000000000000000000000000000000000..fe11696aac3be13e46d0392389ca6c0bb859aaa1 --- /dev/null +++ b/_archive/brainstorm.md @@ -0,0 +1,355 @@ +# ⚡ Skill: Brainstorm + +> **Kategoria:** analysis | **Trudność:** advanced +> **Tokens:** ~2500 | **Model:** any (zalecany: Claude / GPT-4+) +> **Wersja:** 1.0.0 | **Utworzono:** 2026-02-10 +> **Komendy aktywacyjne:** `mały brainstorm` | `duży brainstorm` + +--- + +## Kiedy używać + +Gdy potrzebujesz **dogłębnie przemyśleć** problem, pomysł, decyzję, strategię lub architekturę — zamiast od razu działać. Brainstorm to faza deliberatywna przed fazą wykonawczą. + +--- + +## Tryby + +| Tryb | Komenda | Długość outputu | Zastosowanie | +|------|---------|----------------|--------------| +| 🟢 Mały | `mały brainstorm` | ~500 linii (~2-4 stron A4) | Szybkie przemyślenie tematu, decyzja, pros/cons | +| 🔴 Duży | `duży brainstorm` | ~1000-2000 linii (~6-15 stron A4) | Głębokie planowanie, architektura, strategia, multi-dimensional analysis | + +--- + +## Rola (System Prompt) + + +Jesteś **Strategic Brainstorm Architect** — ekspert od deliberatywnego myślenia, analizy wielowymiarowej i systematycznej ewaluacji pomysłów. Łączysz techniki **Chain-of-Thought** (krokowe rozumowanie), **Tree-of-Thought** (rozgałęziona eksploracja z backtrackingiem) oraz **kreatywną dywergencję** (generowanie nieoczywistych rozwiązań). + +**Twoja misja:** Nie odpowiadaj od razu — **MYŚL GŁĘBOKO**, eksploruj przestrzeń rozwiązań, oceniaj, eliminuj, syntetyzuj. Brainstorm to Twoja arena, a rezultatem jest treść, której user nie wygeneruje sam. + +**Kompetencje kluczowe:** +- Wielowymiarowa analiza problemów (techniczne, biznesowe, ludzkie, czasowe) +- Generowanie 5-15+ rozwiązań/podejść na każdy problem (dywergencja) +- Krytyczna ewaluacja z użyciem skal, matryc i metryk (konwergencja) +- Eksploracja repozytorium i kontekstu projektu nim zaczniesz myśleć +- Identyfikacja ukrytych ryzyk, zależności i efektów drugiego rzędu +- Synteza: wybór najlepszej opcji z jasnym uzasadnieniem "dlaczego" + +**Zasady pracy:** +- 🔍 **Kontekst first** — ZANIM zaczniesz brainstorm: przeskanuj repozytorium, przeczytaj README, zrozum co user buduje, zbierz kontekst, czasem użuj narzędzia do ankiety i zapytaj usera +- 🌐 **Szukaj w sieci** — jeśli masz dostęp do wyszukiwania, UŻYWAJ GO aktywnie. Sprawdzaj trendy, best practices, istniejące rozwiązania, benchmarki +- 🧠 **Self-prompting** — zadawaj SOBIE pytania pomocnicze w trakcie myślenia: "Czego jeszcze nie rozważyłem?", "Jakie jest drugie dno?", "Co by powiedział ekspert od X?" +- 🎨 **Uwolnij kreatywność** — generuj też rozwiązania niestandardowe, śmiałe, eksperymentalne — nawet jeśli ryzykowne +- 📏 **Tablica prawdy** — wyznaczone przez usera ŚWIĘTE ZASADY (constraints) są ABSOLUTNE — nigdy ich nie łam +- ⭐ **Oceniaj wszystko** — każde rozwiązanie/pomysł dostaje ocenę gwiazdkową 1-10 +- 🔄 **Iteruj** — wracaj do wcześniejszych pomysłów w świetle nowych odkryć (backtracking ToT) + + +--- + +## Instrukcje + + + +### 📋 Struktura Brainstormu (Output) + +Brainstorm generuje **2 pliki .md**: + +**Plik 1:** `BRAINSTORM_{TEMAT}.md` — pełny brainstorm (w `temp/brain_storm/`) +**Plik 2:** `BRAINSTORM_{TEMAT}_SUMMARY.md` — podsumowanie + lista zadań (w `temp/brain_storm/`) + +--- + +### FAZA 0: Zbieranie Kontekstu (OBOWIĄZKOWE) + +Zanim napiszesz choćby jeden nagłówek: + +1. **Przeskanuj repozytorium** — przeczytaj README, strukturę folderów, kluczowe pliki +2. **Zrozum kontekst usera** — kim jest, co buduje, jaki ma cel (sprawdź knowledge/ jeśli istnieje) +3. **Przeczytaj pliki powiązane z tematem** — jeśli brainstorm dotyczy kodu → przeczytaj kod; jeśli strategii → przeczytaj plany +4. **Szukaj w sieci** (jeśli dostępne) — sprawdź trendy, istniejące rozwiązania, artykuły, benchmarki +5. **Zidentyfikuj ŚWIĘTE ZASADY usera** — ograniczenia, które NIE podlegają dyskusji (constraints/non-negotiables) + +> 💡 **Self-prompt:** "Czy mam wystarczająco kontekstu? Czego mi brakuje? O co powinienem dopytać?" + +--- + +### FAZA 1: Definicja Problemu i Tablicy Prawdy + +```markdown +## 🎯 Definicja Problemu +[Jasne, precyzyjne sformułowanie: CO dokładnie brainstormujemy i DLACZEGO] + +## 📐 Tablica Prawdy (Constraints) +| # | Święta Zasada (Non-Negotiable) | Źródło | Status | +|---|-------------------------------|--------|--------| +| 1 | [zasada usera] | user | 🔒 ABSOLUTNA | +| 2 | [zasada usera] | user | 🔒 ABSOLUTNA | +| 3 | [zasada kontekstu] | repo | 🔒 ABSOLUTNA | + +> ⚠️ Każde rozwiązanie MUSI przejść test tablicy prawdy. Jeśli łamie choć jedną zasadę → ODRZUCONE. +``` + +--- + +### FAZA 2: Dywergencja — Generowanie Pomysłów (Tree-of-Thought) + +Generuj **wiele** podejść/rozwiązań. Minimum: +- 🟢 Mały brainstorm: **5-8 pomysłów** +- 🔴 Duży brainstorm: **10-20+ pomysłów** + +Dla każdego pomysłu: + +```markdown +### 💡 Pomysł X: [Nazwa] +**Opis:** [2-5 zdań: na czym polega] +**Mechanizm:** [Jak to działa / jak to zrealizować] +**Mocne strony:** [Co jest genialne] +**Słabe strony:** [Co może nie zagrać] +**Ryzyko:** [Co może pójść nie tak] +**Ocena:** ⭐⭐⭐⭐⭐⭐⭐⭐☆☆ (8/10) +**Test tablicy prawdy:** ✅ Przeszedł / ❌ Narusza zasadę #X +``` + +> 💡 **Self-prompt w trakcie generowania:** +> - "Jakie rozwiązanie zaproponowałby ktoś z zupełnie innej branży?" +> - "Co jeśli odwrócę problem do góry nogami?" +> - "Jakie podejście jest najbardziej ryzykowne, ale też najbardziej obiecujące?" +> - "Czego bym NIE chciał tutaj zrobić — i dlaczego? Czy na pewno słusznie to wykluczam?" + +**Kategorie pomysłów do rozważenia:** +- 🛡️ **Bezpieczne** — sprawdzone, niskie ryzyko, proven solutions +- 🚀 **Ambitne** — wymagające, ale z dużym potencjałem +- 🎲 **Eksperymentalne** — wildcard, innowacyjne, mogą nie zadziałać +- 🤝 **Hybrydowe** — kombinacja kilku podejść + +--- + +### FAZA 3: Konwergencja — Ewaluacja i Ranking (Chain-of-Thought) + +#### 3.1 Matryca Porównawcza + +```markdown +## 📊 Matryca Porównawcza + +| Kryterium | Waga | Pomysł 1 | Pomysł 2 | Pomysł 3 | ... | +|-----------|------|----------|----------|----------|-----| +| Wykonalność | 25% | ⭐⭐⭐⭐⭐⭐⭐⭐☆☆ | ⭐⭐⭐⭐⭐⭐☆☆☆☆ | ... | ... | +| ROI / Wartość | 25% | ⭐⭐⭐⭐⭐⭐⭐☆☆☆ | ⭐⭐⭐⭐⭐⭐⭐⭐⭐☆ | ... | ... | +| Ryzyko (niższe=lepsze) | 20% | ⭐⭐⭐⭐⭐⭐⭐⭐☆☆ | ⭐⭐⭐⭐☆☆☆☆☆☆ | ... | ... | +| Czas realizacji | 15% | ⭐⭐⭐⭐⭐⭐⭐☆☆☆ | ⭐⭐⭐⭐⭐⭐⭐⭐☆☆ | ... | ... | +| Innowacyjność | 15% | ⭐⭐⭐⭐⭐☆☆☆☆☆ | ⭐⭐⭐⭐⭐⭐⭐⭐⭐☆ | ... | ... | +| **SUMA WAŻONA** | 100% | **7.3** | **7.1** | ... | ... | +``` + +#### 3.2 Strategie Decyzyjne + +Zastosuj **minimum 3** strategie ewaluacji do zestawu pomysłów: + +| Strategia | Opis | Kiedy skuteczna | +|-----------|------|-----------------| +| **Eliminacja negatywna** | Odrzuć wszystko co łamie constraints → zobacz co zostaje | Gdy masz dużo opcji do filtrowania | +| **Pareto 80/20** | Który pomysł daje 80% rezultatu za 20% wysiłku? | Gdy czas/zasoby są ograniczone | +| **Premortum** | "Jest rok później, projekt się nie powiódł — DLACZEGO?" | Identyfikacja ukrytych ryzyk | +| **10/10/10** | Jak oceniam tę decyzję za 10 minut / 10 miesięcy / 10 lat? | Decyzje strategiczne z długim horyzontem | +| **Odwrócenie** | "Co by się stało gdybym wybrał NAJGORSZĄ opcję?" | Uświadamianie, że różnica między opcjami może być mała | +| **First Principles** | Rozbij problem na fundamentalne prawdy → buduj od zera | Gdy istniejące rozwiązania nie pasują | +| **Matryca Eisenhowera** | Pilne vs. Ważne → priorytety | Planowanie i roadmapa | +| **Red Team / Devil's Advocate** | Aktywnie atakuj swoją najlepszą opcję — co jest w niej złe? | Walidacja przed finalną decyzją | + +--- + +### FAZA 4: Deep Dive — Analiza Top 3 (tylko duży brainstorm) + +Dla **dużego brainstormu** — rozbudowana analiza 3 najlepszych pomysłów: + +```markdown +## 🔬 Deep Dive: [Pomysł X] + +### Plan implementacji +[Krok po kroku: co, jak, kiedy, kto] + +### Zależności +[Co musi istnieć / być gotowe ZANIM to zrobimy] + +### Potencjalne problemy i mitygacja +| Problem | Prawdopodobieństwo | Wpływ | Mitygacja | +|---------|-------------------|-------|-----------| +| [problem] | WYSOKIE/ŚREDNIE/NISKIE | KRYTYCZNY/ZNACZĄCY/MAŁY | [jak zapobiec] | + +### Zasoby wymagane +[Czas, narzędzia, wiedza, ludzie] + +### Metryki sukcesu +[Jak zmierzymy, że to działa?] +``` + +--- + +### FAZA 5: Rozpoznanie Terenu — Dobre vs. Złe (Podział Kontekstowy) + +```markdown +## ✅❌ Podział Kontekstowy + +### ✅ Potencjalnie DOBRE w tym kontekście +| # | Co | Dlaczego dobre | Warunek sukcesu | +|---|----|----------------|-----------------| +| 1 | [element] | [uzasadnienie] | [co musi zaistnieć] | + +### ❌ Potencjalnie ZŁE w tym kontekście +| # | Co | Dlaczego złe | Kiedy mogłoby zadziałać | +|---|----|-------------|------------------------| +| 1 | [element] | [uzasadnienie] | [inny kontekst] | + +### ⚠️ Zależy od kontekstu (może być dobre LUB złe) +| # | Co | Kiedy dobre | Kiedy złe | +|---|----|-------------|-----------| +| 1 | [element] | [warunek A] | [warunek B] | +``` + +--- + +### FAZA 6: Wybór Najlepszej Opcji (Final Verdict) + +```markdown +## 🏆 REKOMENDACJA FINALNA + +### Wybrany pomysł: [Nazwa] +**Ocena końcowa:** ⭐⭐⭐⭐⭐⭐⭐⭐⭐☆ (9/10) + +### Dlaczego ten? +[3-5 zdań uzasadnienia — odwołuj się do matrycy, strategii i tablicy prawdy] + +### Dlaczego NIE pozostałe? +[Krótko: co dyskwalifikuje top-2 i top-3] + +### Plan B (fallback) +[Który pomysł jest backup'em i kiedy na niego przejść] +``` + +--- + +### FAZA 7: Podsumowanie + Generowanie Pliku Summary + +Po napisaniu pełnego brainstormu — **STWÓRZ DRUGI PLIK**: + +**`BRAINSTORM_{TEMAT}_SUMMARY.md`** zawiera: + +```markdown +# 📋 SUMMARY: [Temat] + +> **Źródło:** `BRAINSTORM_{TEMAT}.md` +> **Data:** [data] | **Tryb:** [mały/duży] + +## TL;DR +[3-5 zdań: problem → rekomendacja → dlaczego] + +## Rekomendacja +[Wybrany pomysł + uzasadnienie] + +## Kluczowe Insights +1. [Insight 1] +2. [Insight 2] +3. [Insight 3] + +## 📝 Lista Zadań (Actionable Steps) + +### Priorytet: 🔴 KRYTYCZNY +- [ ] **Krok 1:** [Co dokładnie zrobić] → **Rezultat:** [co powinno powstać] +- [ ] **Krok 2:** [Co dokładnie zrobić] → **Rezultat:** [co powinno powstać] + +### Priorytet: 🟡 WYSOKI +- [ ] **Krok 3:** [Co dokładnie zrobić] → **Rezultat:** [co powinno powstać] +- [ ] **Krok 4:** [Co dokładnie zrobić] → **Rezultat:** [co powinno powstać] + +### Priorytet: 🟢 NORMALNY +- [ ] **Krok 5:** [Co dokładnie zrobić] → **Rezultat:** [co powinno powstać] + +## Ryzyka do monitorowania +| Ryzyko | Trigger | Akcja | +|--------|---------|-------| +| [risk] | [kiedy reagować] | [co zrobić] | + +## Otwarte pytania +- ❓ [Pytanie wymagające decyzji usera] +``` + + + +--- + +## Ograniczenia + + + +**Absolutne zasady (łamanie = fail):** +- ❌ **NIE pomijaj Fazy 0** (zbieranie kontekstu) — bez kontekstu brainstorm jest bezwartościowy +- ❌ **NIE łam Tablicy Prawdy** — constraints usera są ŚWIĘTE +- ❌ **NIE oceniaj bez uzasadnienia** — każda ocena gwiazdkowa musi mieć "dlaczego" +- ❌ **NIE kończ bez Summary** — ZAWSZE generuj 2 pliki (brainstorm + summary) +- ❌ **NIE generuj banalnych/oczywistych pomysłów** — twoja wartość to głębia, nie ilość + +**Best practices (zawsze stosowane):** +- ✅ **Aktywnie szukaj w sieci** — jeśli masz narzędzia do wyszukiwania, UŻYWAJ ICH +- ✅ **Self-prompting** — regularnie zadawaj sobie pytania naprowadzające +- ✅ **Gwiazdki z uzasadnieniem** — ⭐ skala 1-10, ale ZAWSZE z komentarzem +- ✅ **Minimum 3 strategie decyzyjne** na fazę konwergencji +- ✅ **Emoji-driven structure** — użyj emoji jako wizualnych markerów sekcji +- ✅ **Backtracking** — wracaj do wcześniejszych pomysłów, jeśli nowe informacje zmieniają ocenę +- ✅ **Adaptuj kryteria** — dopasuj kryteria matrycy do konkretnego problemu (nie zawsze te same 5) + + + +--- + +## Skala Gwiazdkowa (Referencja) + +| Ocena | Gwiazdki | Znaczenie | +|-------|----------|-----------| +| 1/10 | ⭐☆☆☆☆☆☆☆☆☆ | Tragiczne — nie do użycia | +| 2/10 | ⭐⭐☆☆☆☆☆☆☆☆ | Bardzo słabe — poważne wady | +| 3/10 | ⭐⭐⭐☆☆☆☆☆☆☆ | Słabe — więcej wad niż zalet | +| 4/10 | ⭐⭐⭐⭐☆☆☆☆☆☆ | Poniżej średniej — ryzykowne | +| 5/10 | ⭐⭐⭐⭐⭐☆☆☆☆☆ | Średnie — OK ale nic specjalnego | +| 6/10 | ⭐⭐⭐⭐⭐⭐☆☆☆☆ | Przyzwoite — potencjał jest | +| 7/10 | ⭐⭐⭐⭐⭐⭐⭐☆☆☆ | Dobre — solidna opcja | +| 8/10 | ⭐⭐⭐⭐⭐⭐⭐⭐☆☆ | Bardzo dobre — mocna rekomendacja | +| 9/10 | ⭐⭐⭐⭐⭐⭐⭐⭐⭐☆ | Świetne — top tier | +| 10/10 | ⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐ | Perfekcyjne — rzadkość, uzasadnij wyjątkowo | + +--- + +## Przykład użycia + +**Input użytkownika:** +``` +duży brainstorm: Jak zaprojektować system agentów AI do mojego repozytorium ProPrompts? +``` + +**Odpowiedź agenta:** +``` +[Faza 0: Skanuje repozytorium, czyta README, MattyMroz.md, ZIP.md, istniejące agenty] +[Faza 1: Definiuje problem, tworzy tablicę prawdy z constraints usera] +[Faza 2: Generuje 12+ pomysłów z ocenami gwiazdkowymi] +[Faza 3: Matryca porównawcza + 4 strategie decyzyjne] +[Faza 4: Deep dive top 3 pomysłów] +[Faza 5: Podział kontekstowy dobre/złe] +[Faza 6: Finalna rekomendacja z uzasadnieniem] +[Faza 7: Tworzy BRAINSTORM_SYSTEM_AGENTOW_SUMMARY.md z listą zadań] +``` + +--- + +## Warianty + +- **Wariant A: Brainstorm techniczny** — focus na architekturze, kodzie, toolingu. Dodaj kryteria: performance, maintainability, scalability. +- **Wariant B: Brainstorm strategiczny** — focus na biznesie, rynku, decyzjach. Dodaj kryteria: ROI, market fit, competitive advantage. +- **Wariant C: Brainstorm kreatywny** — focus na pomysłach, naming, branding. Poluzuj rygory, maksymalizuj dywergencję (20+ pomysłów), używaj technik jak SCAMPER, lateral thinking. + +--- + +## Changelog + +- **v1.0.0** [2026-02-10]: Pierwsza wersja skilla brainstorm — pełna struktura 7-fazowa z trybami mały/duży diff --git a/_archive/crack_config.py b/_archive/crack_config.py new file mode 100644 index 0000000000000000000000000000000000000000..6b34bb23c8e10f1706daefbc1fde28e7b1733788 --- /dev/null +++ b/_archive/crack_config.py @@ -0,0 +1,84 @@ +"""Crack the OneOCRFeatureExtract config blob — find the hidden weight matrix.""" +import onnx +import numpy as np +from pathlib import Path + +models_dir = Path("oneocr_extracted/onnx_models") + +# Load model_11 +model = onnx.load(str(list(models_dir.glob("model_11_*"))[0])) + +# Get feature/config blob +config_blob = None +for init in model.graph.initializer: + if init.name == "feature/config": + config_blob = bytes(init.string_data[0]) + break + +print(f"Config blob size: {len(config_blob)} bytes") +print(f"As float32 count: {len(config_blob) // 4} = {len(config_blob) / 4}") + +# Full float32 interpretation +all_floats = np.frombuffer(config_blob, dtype=np.float32) +print(f"\nFull blob as float32:") +print(f" Count: {len(all_floats)}") +print(f" Finite: {np.isfinite(all_floats).sum()}") +print(f" In [-10,10]: {np.sum(np.abs(all_floats) < 10)}") +print(f" Range: [{all_floats.min():.4f}, {all_floats.max():.4f}]") +print(f" Mean: {all_floats.mean():.4f}, Std: {all_floats.std():.4f}") +print(f" First 20: {all_floats[:20]}") + +# 4492 bytes / 4 = 1123 floats +# Hypothesis: some header + 21×50 weight matrix + 50 bias +# 1123 - 1050 - 50 = 23 extra floats (92 bytes header) + +# Try different header sizes +for header_floats in range(0, 40): + remaining = len(all_floats) - header_floats + # Check if remaining = in_dim * out_dim + out_dim for some dimensions + for in_dim in [20, 21, 22]: + for out_dim in [48, 49, 50, 51, 52]: + needed = in_dim * out_dim + out_dim + if remaining == needed: + print(f"\n *** MATCH: header={header_floats} ({header_floats*4}B) + " + f"W[{in_dim}×{out_dim}] + b[{out_dim}] = {needed} floats") + W = all_floats[header_floats:header_floats + in_dim*out_dim].reshape(in_dim, out_dim) + b = all_floats[header_floats + in_dim*out_dim:header_floats + needed] + print(f" W range: [{W.min():.4f}, {W.max():.4f}], mean={W.mean():.4f}") + print(f" b range: [{b.min():.4f}, {b.max():.4f}], mean={b.mean():.4f}") + + if header_floats > 0: + header = all_floats[:header_floats] + print(f" Header values: {header}") + +# Also try: the blob might encode multiple layers +# Or maybe it's quantized (int8/uint8)? +print(f"\n--- Trying int8 interpretation ---") +int8_arr = np.frombuffer(config_blob, dtype=np.int8) +print(f" int8 range: [{int8_arr.min()}, {int8_arr.max()}]") + +uint8_arr = np.frombuffer(config_blob, dtype=np.uint8) +print(f" uint8 range: [{uint8_arr.min()}, {uint8_arr.max()}]") + +# Maybe float16? +if len(config_blob) % 2 == 0: + f16_arr = np.frombuffer(config_blob, dtype=np.float16) + finite_f16 = np.isfinite(f16_arr).sum() + print(f" float16 count: {len(f16_arr)}, finite: {finite_f16}") + if finite_f16 > len(f16_arr) * 0.9: + print(f" float16 could work! range=[{f16_arr[np.isfinite(f16_arr)].min():.4f}, {f16_arr[np.isfinite(f16_arr)].max():.4f}]") + +# Check the Slice in model_11 to understand input dimensions +print(f"\n--- Checking Slice constants to understand feature extraction ---") +for node in model.graph.node: + if node.op_type == "Constant": + for attr in node.attribute: + if attr.type == 4: # TENSOR + t = attr.t + data = onnx.numpy_helper.to_array(t) + print(f" Constant '{node.output[0]}': {data}") + +# Check Add and Div constants +for node in model.graph.node: + if node.op_type in ("Add", "Div"): + print(f"\n {node.op_type}: {list(node.input)} → {list(node.output)}") diff --git a/_archive/crack_endian.py b/_archive/crack_endian.py new file mode 100644 index 0000000000000000000000000000000000000000..c165971fe7fde2683d50195bb3cfbb8716b4638a --- /dev/null +++ b/_archive/crack_endian.py @@ -0,0 +1,65 @@ +"""Test big-endian float32 interpretation of OneOCRFeatureExtract config blob.""" +import onnx +import numpy as np +from pathlib import Path + +models_dir = Path("oneocr_extracted/onnx_models") +model = onnx.load(str(list(models_dir.glob("model_11_*"))[0])) + +# Get config blob +for init in model.graph.initializer: + if init.name == "feature/config": + blob = bytes(init.string_data[0]) + break + +print(f"Blob: {len(blob)} bytes = {len(blob) // 4} float32s") + +# Big-endian float32 +be_arr = np.frombuffer(blob, dtype='>f4') # big-endian +le_arr = np.frombuffer(blob, dtype=' in_d * out_d * 0.7: + print(f" *** header={header} + W[{in_d}×{out_d}] + b[{out_d}]") + print(f" W finite={w_finite}, reasonable={w_reasonable}") + print(f" W range: [{W[np.isfinite(W)].min():.4f}, {W[np.isfinite(W)].max():.4f}]") + print(f" b range: [{b[np.isfinite(b)].min():.4f}, {b[np.isfinite(b)].max():.4f}]") + +# Also test: could be byteswapped structure with header +# Try offset by checking where the "nice" values start +print(f"\n--- Finding good float32 regions (big-endian) ---") +for start_byte in range(0, 100, 4): + chunk = np.frombuffer(blob[start_byte:start_byte+84], dtype='>f4') + all_reasonable = all(np.isfinite(chunk)) and all(np.abs(chunk) < 10) + if all_reasonable: + print(f" offset={start_byte}: ALL 21 values reasonable: {chunk}") + break + decent = np.sum((np.abs(chunk) < 10) & np.isfinite(chunk)) + if decent >= 18: + print(f" offset={start_byte}: {decent}/21 reasonable: {chunk}") diff --git a/_archive/debug_detector.py b/_archive/debug_detector.py new file mode 100644 index 0000000000000000000000000000000000000000..010ae4c8e07b32a18739cc518f2aced7c33a1046 --- /dev/null +++ b/_archive/debug_detector.py @@ -0,0 +1,80 @@ +"""Debug detector output to understand word segmentation.""" +import numpy as np +import onnxruntime as ort +from PIL import Image +from pathlib import Path + +models_dir = Path("oneocr_extracted/onnx_models") +img = Image.open("image.png").convert("RGB") +w, h = img.size + +# Detector setup +sess = ort.InferenceSession(str(next(models_dir.glob("model_00_*"))), + providers=["CPUExecutionProvider"]) + +scale = 800 / max(h, w) +dh = (int(h * scale) + 31) // 32 * 32 +dw = (int(w * scale) + 31) // 32 * 32 +img_d = np.array(img.resize((dw, dh), Image.LANCZOS), dtype=np.float32) +img_d = img_d[:, :, ::-1] - np.array([102.9801, 115.9465, 122.7717], dtype=np.float32) +data = img_d.transpose(2, 0, 1)[np.newaxis].astype(np.float32) +im_info = np.array([[dh, dw, scale]], dtype=np.float32) + +outputs = sess.run(None, {"data": data, "im_info": im_info}) +output_names = [o.name for o in sess.get_outputs()] +out_dict = dict(zip(output_names, outputs)) + +# Analyze FPN2 (highest resolution) +pixel_scores = out_dict["scores_hori_fpn2"][0, 0] # [56, 200] +link_scores = out_dict["link_scores_hori_fpn2"][0] # [8, 56, 200] + +print(f"FPN2 shape: {pixel_scores.shape}") +print(f"Pixel scores: min={pixel_scores.min():.4f} max={pixel_scores.max():.4f}") + +# Find text region +text_mask = pixel_scores > 0.6 +print(f"Text pixels (>0.6): {text_mask.sum()}") + +# Get the row/column range of text pixels +ys, xs = np.where(text_mask) +if len(ys) > 0: + print(f"Text region: rows [{ys.min()}-{ys.max()}], cols [{xs.min()}-{xs.max()}]") + + # Check link scores within text region - do they separate words? + # Link 2 is East neighbor (right), Link 6 is West neighbor (left) + # If link between words is low, they should separate + row_mid = (ys.min() + ys.max()) // 2 + print(f"\nHorizontal link scores at row {row_mid} (East neighbor):") + link_east = link_scores[2, row_mid, :] # E neighbor + for x in range(xs.min(), xs.max()+1): + ps = pixel_scores[row_mid, x] + le = link_east[x] + marker = "TEXT" if ps > 0.6 else " " + link_marker = "LINK" if le > 0.5 else "gap " + if ps > 0.3: + print(f" col={x:3d}: pixel={ps:.3f} [{marker}] east_link={le:.3f} [{link_marker}]") + + # Also check if there are distinct "gap" regions in pixel scores + print(f"\nPixel scores along row {row_mid}:") + for x in range(max(0, xs.min()-2), min(pixel_scores.shape[1], xs.max()+3)): + ps = pixel_scores[row_mid, x] + bar = "█" * int(ps * 40) + print(f" col={x:3d}: {ps:.3f} {bar}") + +# Try different thresholds +for thresh in [0.5, 0.6, 0.7, 0.8, 0.9]: + mask = pixel_scores > thresh + n = mask.sum() + # Connected components using simple scan + from scipy import ndimage + try: + labels, n_comps = ndimage.label(mask) + print(f"\nThreshold {thresh}: {n} pixels, {n_comps} components") + for c in range(1, min(n_comps+1, 10)): + comp_mask = labels == c + area = comp_mask.sum() + ys_c, xs_c = np.where(comp_mask) + print(f" Component {c}: area={area}, cols=[{xs_c.min()}-{xs_c.max()}]") + except ImportError: + # Fallback without scipy + print(f"Threshold {thresh}: {n} pixels") diff --git a/_archive/decode_config.py b/_archive/decode_config.py new file mode 100644 index 0000000000000000000000000000000000000000..17884aef40a3ae8c172aec71d1ae5bc0acf87f00 --- /dev/null +++ b/_archive/decode_config.py @@ -0,0 +1,74 @@ +"""Decode OneOCRFeatureExtract config blob.""" +import onnx +import numpy as np +import struct +from pathlib import Path + +m = onnx.load('oneocr_extracted/onnx_models/model_11_ir6_1.9_26KB.onnx') + +for init in m.graph.initializer: + if init.name == 'feature/config': + raw = init.string_data[0] + print(f'Total bytes: {len(raw)}') + print(f'First 100 bytes hex: {raw[:100].hex()}') + + # Try different structure interpretations + for offset in [0, 4, 8, 12]: + vals = struct.unpack_from('<4f', raw, offset) + print(f'Offset {offset:3d} as 4xfloat32: {vals}') + + # Parse rnn_info to find LogPrior values + rnn = Path('oneocr_extracted/config_data/chunk_36_rnn_info.rnn_info').read_text() + rnn_lines = rnn.strip().split('\n') + lp_count = int(rnn_lines[0].split()[-1]) + print(f'\nLogPrior count from rnn_info: {lp_count}') + lp_val = float(rnn_lines[1]) + print(f'LogPrior[0] = {lp_val}') + + lp_f32 = struct.pack(', , / + # Let's check the rnn_info structure fully + print('\n=== rnn_info structure ===') + section = None + counts = {} + for line in rnn_lines: + if line.startswith('<') and line.endswith('>'): + section = line + elif line.startswith('<') and '>' in line: + parts = line.strip().split() + section = parts[0].rstrip('>')+'>' + count = int(parts[-1]) if len(parts) > 1 else 0 + counts[section] = count + print(f'Section: {section} count={count}') + else: + if section and section not in counts: + counts[section] = 0 + print(f'Sections found: {counts}') diff --git a/_archive/dedup.py b/_archive/dedup.py new file mode 100644 index 0000000000000000000000000000000000000000..9c23bfbed3c997a03f76bb2be543b90e3f6f1f02 --- /dev/null +++ b/_archive/dedup.py @@ -0,0 +1,687 @@ +"""Smart OCR deduplication — stabilization-first approach. + +Core principle: **don't read text until it STOPS CHANGING**. +Then check against read history to avoid repeats. + +Architecture: + + Phase 1 — **Snapshot Stabilization** + Each tick compares the full OCR output (all regions merged) with the + previous tick. If text is growing (typewriter effect), we wait. + Only when the snapshot is identical for ``stabilize_ticks`` consecutive + ticks do we consider it "stable" and proceed. + + Phase 2 — **Line History Dedup** + Once stable, each line is fuzzy-compared against a history of previously + emitted lines. Only genuinely new lines pass through. History entries + expire via TTL so the same text can be re-read after a cooldown. + + Phase 3 — **Significance Check** + Rejects composed output that is too short, has too few real words, + or is mostly non-alphanumeric (OCR garbage / UI artifacts). + +This naturally handles: +- **Typewriter effects**: text grows → wait → stabilize → read complete sentence +- **Static UI** (HP bars, names): stabilizes → read once → in history → skip +- **OCR noise**: fuzzy matching tolerates minor variations +- **Dialog changes**: snapshot changes → re-stabilize → emit new parts only +- **Repeated dialog**: TTL expiry allows re-reading after cooldown + +Usage:: + + from src.services.ocr.dedup import SmartDedup + + dedup = SmartDedup() + text = dedup.process(region_labels, ocr_results) + if text is not None: + translate_and_speak(text) +""" + +from __future__ import annotations + +import time +from collections import deque +from dataclasses import dataclass +from difflib import SequenceMatcher + +from src.services.ocr.models import OcrResult +from src.utils.logger import logger + +# ── Constants (sensible defaults) ──────────────────────────────── + +DEFAULT_STABILIZE_TICKS: int = 3 +DEFAULT_SNAPSHOT_SIMILARITY: float = 0.92 +DEFAULT_LINE_SIMILARITY: float = 0.80 +DEFAULT_LINE_TTL: float = 120.0 +DEFAULT_HISTORY_TTL: float = 90.0 +DEFAULT_HISTORY_SIZE: int = 30 +DEFAULT_MIN_NEW_CHARS: int = 8 +DEFAULT_MIN_NEW_WORDS: int = 2 +DEFAULT_MIN_ALNUM_RATIO: float = 0.35 + + +# ── Data classes ───────────────────────────────────────────────── + + +@dataclass +class HistoryEntry: + """An entry in the global text history ring buffer.""" + + norm_text: str + original_text: str + first_seen: float + last_seen: float + hit_count: int = 1 + + +@dataclass +class DedupConfig: + """All tunable knobs for the dedup system. + + Attributes: + stabilize_ticks: Consecutive identical ticks before text is considered "stable". + snapshot_similarity: Fuzzy threshold for treating two snapshots as identical (0-1). + line_similarity: Fuzzy threshold for line-level history matching (0-1). + line_ttl: Seconds before a known line in history expires. + history_ttl: Seconds before a global history entry expires. + history_size: Max entries in the global history ring buffer. + history_similarity: Alias for line_similarity (backward compat with bridge.py). + min_new_chars: Minimum characters for a change to be significant. + min_new_words: Minimum word count for significance. + min_alnum_ratio: Minimum alphanumeric ratio for significance. + debounce_time: Legacy field — not used internally, kept for bridge compat. + """ + + stabilize_ticks: int = DEFAULT_STABILIZE_TICKS + snapshot_similarity: float = DEFAULT_SNAPSHOT_SIMILARITY + line_similarity: float = DEFAULT_LINE_SIMILARITY + line_ttl: float = DEFAULT_LINE_TTL + history_ttl: float = DEFAULT_HISTORY_TTL + history_size: int = DEFAULT_HISTORY_SIZE + history_similarity: float = DEFAULT_LINE_SIMILARITY + min_new_chars: int = DEFAULT_MIN_NEW_CHARS + min_new_words: int = DEFAULT_MIN_NEW_WORDS + min_alnum_ratio: float = DEFAULT_MIN_ALNUM_RATIO + debounce_time: float = 0.0 # legacy — mapped to stabilize_ticks externally + instant_mode: bool = False # skip stabilization — emit text on first identical tick + + +# ── Helpers ────────────────────────────────────────────────────── + + +def _normalize(text: str) -> str: + """Collapse whitespace, strip, lowercase — for comparison only.""" + return " ".join(text.split()).strip().lower() + + +# ── Line History ───────────────────────────────────────────────── + + +class LineHistory: + """Tracks previously emitted lines with TTL-based expiry. + + Each emitted line is stored (normalized) with a timestamp. + Old entries expire after ``ttl`` seconds, allowing re-reading. + Fuzzy matching handles OCR noise on short lines. + """ + + def __init__( + self, + ttl: float = DEFAULT_LINE_TTL, + similarity: float = DEFAULT_LINE_SIMILARITY, + ) -> None: + self._entries: dict[str, float] = {} # norm_line → last_emitted_at + self._ttl = ttl + self._similarity = similarity + + def is_known(self, line: str) -> bool: + """Check if a line was emitted recently (within TTL). + + Uses exact match first, then fuzzy for short lines. + + Args: + line: Raw (non-normalized) line text. + + Returns: + True if line is in recent history (should be skipped). + """ + norm = _normalize(line) + if len(norm) < 2: + return True # too short → treat as known (skip garbage) + + now = time.monotonic() + self._gc(now) + + # Fast path: exact match + if norm in self._entries: + return True + + # Slow path: fuzzy match (short lines where OCR noise matters) + if len(norm) < 60: + for key in self._entries: + if abs(len(norm) - len(key)) > max(5, len(key) * 0.25): + continue + ratio = SequenceMatcher(None, norm, key).ratio() + if ratio >= self._similarity: + return True + + return False + + def mark_emitted(self, line: str) -> None: + """Record a line as emitted.""" + norm = _normalize(line) + if norm: + self._entries[norm] = time.monotonic() + + def reset(self) -> None: + """Clear all history.""" + self._entries.clear() + + @property + def size(self) -> int: + return len(self._entries) + + def _gc(self, now: float) -> None: + """Remove entries older than TTL.""" + expired = [k for k, ts in self._entries.items() if now - ts > self._ttl] + for k in expired: + del self._entries[k] + + +# ── Global Text History (ring buffer for full text blocks) ─────── + + +class GlobalTextHistory: + """Ring buffer of recently emitted text blocks with TTL. + + Prevents the same composed text from being re-emitted within + the TTL window. Uses fuzzy matching to handle OCR noise. + """ + + def __init__( + self, + max_size: int = DEFAULT_HISTORY_SIZE, + ttl: float = DEFAULT_HISTORY_TTL, + similarity: float = DEFAULT_LINE_SIMILARITY, + ) -> None: + self._entries: deque[HistoryEntry] = deque(maxlen=max_size) + self._ttl = ttl + self._similarity = similarity + + def is_duplicate(self, text: str) -> tuple[bool, float]: + """Check whether text duplicates something in recent history. + + Args: + text: Composed text block. + + Returns: + ``(is_dup, best_similarity)`` + """ + now = time.monotonic() + norm = _normalize(text) + if not norm: + return (True, 1.0) + + best_sim = 0.0 + for entry in self._entries: + if now - entry.last_seen > self._ttl: + continue + + if entry.norm_text == norm: + entry.last_seen = now + entry.hit_count += 1 + return (True, 1.0) + + ratio = SequenceMatcher(None, norm, entry.norm_text).ratio() + best_sim = max(best_sim, ratio) + if ratio >= self._similarity: + entry.last_seen = now + entry.hit_count += 1 + return (True, ratio) + + return (False, best_sim) + + def add(self, text: str) -> None: + """Record a new text block in history.""" + norm = _normalize(text) + now = time.monotonic() + self._entries.append( + HistoryEntry( + norm_text=norm, + original_text=text, + first_seen=now, + last_seen=now, + ) + ) + + def reset(self) -> None: + self._entries.clear() + + @property + def size(self) -> int: + return len(self._entries) + + +# ── Significance Check ─────────────────────────────────────────── + + +class ChangeDetector: + """Decide whether new lines constitute a meaningful change. + + Rejects very short text, too few words, or mostly non-alphanumeric content. + """ + + def __init__( + self, + min_chars: int = DEFAULT_MIN_NEW_CHARS, + min_words: int = DEFAULT_MIN_NEW_WORDS, + min_alnum_ratio: float = DEFAULT_MIN_ALNUM_RATIO, + ) -> None: + self._min_chars = min_chars + self._min_words = min_words + self._min_alnum_ratio = min_alnum_ratio + + def is_significant(self, new_lines: list[str]) -> bool: + """Return True if the new lines represent real content, not OCR garbage.""" + text = " ".join(line.strip() for line in new_lines).strip() + + if len(text) < self._min_chars: + return False + + words = text.split() + if len(words) < self._min_words: + return False + + alnum = sum(1 for c in text if c.isalnum()) + ratio = alnum / len(text) if text else 0 + if ratio < self._min_alnum_ratio: + return False + + return True + + +# ── Main Facade: SmartDedup ────────────────────────────────────── + + +class SmartDedup: + """Stabilization-first OCR deduplication. + + Core algorithm: + + 1. Each tick: merge all OCR results into a single text snapshot + 2. Compare snapshot with previous tick — growing? same? different? + 3. When snapshot is identical for ``stabilize_ticks`` consecutive ticks → STABLE + 4. Extract lines, filter against read history → emit only NEW lines + 5. Significance check → reject OCR garbage + 6. Add emitted lines to history, record in global ring buffer + + This replaces the old per-line-tracker approach which caused: + - Sentence fragments (read partial text too early) + - Infinite silence (partial lines marked "known" too aggressively) + + Example:: + + dedup = SmartDedup() + + # On each pipeline tick: + text = dedup.process(region_labels, ocr_results) + if text is not None: + await translate_and_speak(text) + + # On pipeline stop or config change: + dedup.reset() + """ + + def __init__(self, config: DedupConfig | None = None) -> None: + self._cfg = config or DedupConfig() + + # Stabilization state + self._last_snapshot: str | None = None + self._last_raw: str | None = None + self._stable_count: int = 0 + self._processed_snapshot: str | None = None + + # Why: track last emitted text to detect post-emit growth + # (e.g. we emitted 2 lines, then lines 3-4 appear → continuation, not new text) + self._last_emitted_norm: str | None = None + + # History layers + self._line_history = LineHistory( + ttl=self._cfg.line_ttl, + similarity=self._cfg.line_similarity, + ) + self._global_history = GlobalTextHistory( + max_size=self._cfg.history_size, + ttl=self._cfg.history_ttl, + similarity=self._cfg.history_similarity, + ) + self._change_detector = ChangeDetector( + min_chars=self._cfg.min_new_chars, + min_words=self._cfg.min_new_words, + min_alnum_ratio=self._cfg.min_alnum_ratio, + ) + + # ── Public API ─────────────────────────────────────────────── + + def process( + self, + region_labels: list[str], + ocr_results: list[OcrResult], + *, + force: bool = False, + ) -> str | None: + """Run stabilization-based dedup on multi-region OCR results. + + Args: + region_labels: Label/ID for each region (for diagnostics). + ocr_results: OCR result per region (same order as labels). + force: If True, skip all dedup and return all text immediately. + + Returns: + Text to translate + speak, or None if suppressed by dedup. + """ + # ── Merge all regions into one snapshot ── + raw_parts: list[str] = [] + for result in ocr_results: + if result.error or result.is_empty: + continue + text = result.text.strip() + if text: + raw_parts.append(text) + + if not raw_parts: + return None + + full_raw = "\n".join(raw_parts) + full_norm = _normalize(full_raw) + + if not full_norm or len(full_norm) < 2: + return None + + # ── Force read: bypass all dedup ── + if force: + self._global_history.add(full_raw) + self._mark_all_lines_known(full_raw) + self._last_snapshot = full_norm + self._last_raw = full_raw + self._processed_snapshot = full_norm + self._stable_count = 0 + logger.info("Dedup: force read — emitting %d chars", len(full_raw)) + return full_raw + + # ── Phase 1: Stabilization check ── + if self._last_snapshot is None: + # First tick — record snapshot, wait for next + self._last_snapshot = full_norm + self._last_raw = full_raw + self._stable_count = 0 + self._processed_snapshot = None + # Why: in instant mode, skip waiting — proceed on the very first tick + if not self._cfg.instant_mode: + return None + + # Compare current snapshot with previous + snapshot_sim = self._snapshot_similarity(self._last_snapshot, full_norm) + + if snapshot_sim >= self._cfg.snapshot_similarity: + # Same (or very similar due to OCR noise) → count toward stability + self._stable_count += 1 + elif self._is_text_growing(self._last_snapshot, full_norm): + # Text is expanding (typewriter effect) → reset, keep waiting + self._stable_count = 0 + self._last_snapshot = full_norm + self._last_raw = full_raw + self._processed_snapshot = None + logger.debug("Dedup: text growing, waiting for stabilization") + return None + elif ( + self._last_emitted_norm is not None + and self._is_text_growing(self._last_emitted_norm, full_norm) + ): + # Why: post-emit growth — we emitted lines 1-2, now lines 1-4 are visible. + # The new snapshot is a SUPERSET of what we emitted → continuation. + # Reset stability and wait for the full text to settle. + self._stable_count = 0 + self._last_snapshot = full_norm + self._last_raw = full_raw + self._processed_snapshot = None + logger.debug("Dedup: post-emit growth detected, waiting for continuation") + return None + else: + # Completely different content → new text, start fresh + self._stable_count = 0 + self._last_snapshot = full_norm + self._last_raw = full_raw + self._processed_snapshot = None + logger.debug("Dedup: snapshot changed, waiting for stabilization") + return None + + # Update raw text (keep latest version even during stability counting) + self._last_snapshot = full_norm + self._last_raw = full_raw + + # Not stable yet? + required_ticks = 1 if self._cfg.instant_mode else self._cfg.stabilize_ticks + if self._stable_count < required_ticks: + return None + + # ── Already processed this exact snapshot? ── + if self._processed_snapshot is not None: + sim = self._snapshot_similarity(full_norm, self._processed_snapshot) + if sim >= self._cfg.snapshot_similarity: + return None # already evaluated, nothing new + + # ── Phase 2: Text is STABLE — extract new lines ── + all_lines = self._extract_lines(full_raw, ocr_results) + new_lines: list[str] = [] + + for line in all_lines: + if not self._line_history.is_known(line): + new_lines.append(line) + + # Also check against global text history (full text block dedup) + if new_lines: + composed = "\n".join(new_lines) + is_dup, sim = self._global_history.is_duplicate(composed) + if is_dup: + logger.debug("Dedup: global history match (sim=%.3f)", sim) + new_lines = [] + + if not new_lines: + # All lines already known — mark snapshot as processed + self._processed_snapshot = full_norm + return None + + # ── Phase 3: Significance check ── + if not self._change_detector.is_significant(new_lines): + logger.debug( + "Dedup: new lines not significant (%d lines, %d chars)", + len(new_lines), + sum(len(line) for line in new_lines), + ) + self._processed_snapshot = full_norm + return None + + # ── EMIT! ── + composed = "\n".join(new_lines) + self._mark_all_lines_known(composed) + self._global_history.add(composed) + self._processed_snapshot = full_norm + # Why: track what we emitted so we can detect post-emit growth + self._last_emitted_norm = full_norm + # Why: reset stable_count to prevent immediate re-emit on next tick + self._stable_count = 0 + + logger.info( + "Dedup: emitting %d new lines (%d chars, %d known lines in history)", + len(new_lines), + len(composed), + self._line_history.size, + ) + return composed + + def force_flush(self) -> str | None: + """Force-emit whatever raw text is pending (for force-read button).""" + if self._last_raw: + raw = self._last_raw + self._global_history.add(raw) + self._mark_all_lines_known(raw) + return raw + return None + + def update_config(self, config: DedupConfig) -> None: + """Apply new configuration. Rebuilds internal components.""" + self._cfg = config + self._line_history = LineHistory( + ttl=config.line_ttl, + similarity=config.line_similarity, + ) + self._global_history = GlobalTextHistory( + max_size=config.history_size, + ttl=config.history_ttl, + similarity=config.history_similarity, + ) + self._change_detector = ChangeDetector( + min_chars=config.min_new_chars, + min_words=config.min_new_words, + min_alnum_ratio=config.min_alnum_ratio, + ) + logger.info("SmartDedup: config updated") + + def reset(self) -> None: + """Clear all state (e.g. on scene change or pipeline restart).""" + self._last_snapshot = None + self._last_raw = None + self._stable_count = 0 + self._processed_snapshot = None + self._last_emitted_norm = None + self._line_history.reset() + self._global_history.reset() + logger.info("SmartDedup: all state reset") + + def reset_region(self, label: str) -> None: + """No-op in snapshot-based approach — kept for backward compat.""" + pass + + @property + def stats(self) -> dict[str, int]: + """Return diagnostic stats.""" + return { + "tracked_regions": 0, + "total_known_lines": self._line_history.size, + "history_size": self._global_history.size, + "stable_count": self._stable_count, + } + + # ── Internal ───────────────────────────────────────────────── + + @staticmethod + def _snapshot_similarity(a: str, b: str) -> float: + """Fast similarity between two normalized snapshots.""" + if a == b: + return 1.0 + if not a or not b: + return 0.0 + return SequenceMatcher(None, a, b).ratio() + + @staticmethod + def _is_text_growing(old_norm: str, new_norm: str) -> bool: + """Check if new text is an expansion of old text (typewriter effect). + + Returns True if new_norm is longer AND contains most of old_norm's + words at the beginning (prefix-like growth). + """ + if len(new_norm) <= len(old_norm): + return False + + # Simple prefix check — covers most typewriter cases + if new_norm.startswith(old_norm): + return True + + # Word-level check: old words appear at the start of new word sequence + old_words = old_norm.split() + new_words = new_norm.split() + + if len(new_words) <= len(old_words): + return False + + # Count matching words at the beginning + matching = 0 + for old_w, new_w in zip(old_words, new_words): + if old_w == new_w: + matching += 1 + elif SequenceMatcher(None, old_w, new_w).ratio() > 0.8: + # Why: OCR noise may corrupt already-visible words slightly + matching += 1 + + # Why: 60% threshold — allows some OCR noise in the matching portion + return matching >= len(old_words) * 0.6 + + def _extract_lines( + self, raw_text: str, ocr_results: list[OcrResult] + ) -> list[str]: + """Extract individual lines from OCR results. + + Prefers structured ``OcrResult.lines`` when available. + Deduplicates across regions (overlapping capture areas). + + Args: + raw_text: Fallback raw text (used if no structured lines). + ocr_results: OCR results with structured lines. + + Returns: + List of unique raw line texts. + """ + lines: list[str] = [] + seen_norms: set[str] = set() + + for result in ocr_results: + if result.error or result.is_empty: + continue + for ocr_line in result.lines: + raw = ocr_line.text.strip() + if not raw: + continue + norm = _normalize(raw) + if len(norm) < 2: + continue + + # Why: skip duplicate lines across regions (overlapping capture areas) + if norm in seen_norms: + continue + + # Fuzzy cross-region dedup for short lines + # Why: high threshold (0.95) because overlapping regions produce + # near-identical text, not merely similar text + is_cross_dup = False + if len(norm) < 60: + for seen in seen_norms: + if abs(len(norm) - len(seen)) > 3: + continue + if SequenceMatcher(None, norm, seen).ratio() >= 0.95: + is_cross_dup = True + break + if is_cross_dup: + continue + + seen_norms.add(norm) + lines.append(raw) + + # Fallback: if no structured lines, split raw text + if not lines: + for line in raw_text.split("\n"): + stripped = line.strip() + if stripped and len(_normalize(stripped)) >= 2: + norm = _normalize(stripped) + if norm not in seen_norms: + seen_norms.add(norm) + lines.append(stripped) + + return lines + + def _mark_all_lines_known(self, text: str) -> None: + """Add all lines in text to line history.""" + for line in text.split("\n"): + stripped = line.strip() + if stripped and len(_normalize(stripped)) >= 2: + self._line_history.mark_emitted(stripped) diff --git a/_archive/dedup_old.py b/_archive/dedup_old.py new file mode 100644 index 0000000000000000000000000000000000000000..2511df39120dce15cd29b936aaedfbc9ac13bf2b --- /dev/null +++ b/_archive/dedup_old.py @@ -0,0 +1,595 @@ +"""Smart OCR deduplication — multi-layer heuristic to avoid re-reading the same text. + +Architecture (3 layers): + + Layer 1 — **Per-Region Line Tracker** + Each capture region keeps a dict of known OCR lines (normalized text → metadata). + New OCR results are compared line-by-line; only genuinely new lines pass through. + Stale entries expire after ``line_ttl`` seconds. + + Layer 2 — **Global Text History** (ring buffer) + After composing new lines into a text block, the block is fuzzy-matched against + a bounded history of recently emitted texts. TTL-based expiry allows the same + dialog to be read again after a configurable cooldown. + + Layer 3 — **Semantic Change Detector** + Rejects composed text that is too short, has too few real words, or is mostly + non-alphanumeric (OCR garbage / UI artifacts). + + Debounce (optional) + When text grows incrementally (typewriter effect), the emitter waits for + stabilization before yielding the final text. + +Usage:: + + from src.services.ocr.dedup import SmartDedup + + dedup = SmartDedup() + text = dedup.process(regions, ocr_results) + if text is not None: + translate_and_speak(text) +""" + +from __future__ import annotations + +import time +from collections import deque +from dataclasses import dataclass +from difflib import SequenceMatcher + +from src.services.ocr.models import OcrResult +from src.utils.logger import logger + +# ── Constants (sensible defaults) ──────────────────────────────── + +DEFAULT_LINE_TTL: float = 120.0 +DEFAULT_LINE_SIMILARITY: float = 0.80 +DEFAULT_HISTORY_SIZE: int = 30 +DEFAULT_HISTORY_TTL: float = 90.0 +DEFAULT_HISTORY_SIMILARITY: float = 0.82 +DEFAULT_MIN_NEW_CHARS: int = 8 +DEFAULT_MIN_NEW_WORDS: int = 2 +DEFAULT_MIN_ALNUM_RATIO: float = 0.35 +DEFAULT_DEBOUNCE_TIME: float = 0.0 # 0 = disabled + + +# ── Data classes ───────────────────────────────────────────────── + + +@dataclass +class KnownLine: + """A line previously seen by a RegionLineTracker.""" + + text: str + first_seen: float + last_seen: float + hit_count: int = 1 + + +@dataclass +class HistoryEntry: + """An entry in the global text history ring buffer.""" + + norm_text: str + original_text: str + first_seen: float + last_seen: float + hit_count: int = 1 + + +@dataclass +class DedupConfig: + """All tunable knobs for the dedup system. + + Attributes: + line_ttl: Seconds before a known line expires (Layer 1). + line_similarity: Fuzzy threshold for line-level dedup (0-1). + history_size: Max entries in global ring buffer (Layer 2). + history_ttl: Seconds before a global history entry expires. + history_similarity: Fuzzy threshold for global dedup (0-1). + min_new_chars: Minimum characters for a change to be significant (Layer 3). + min_new_words: Minimum word count for significance. + min_alnum_ratio: Minimum alphanumeric ratio for significance. + debounce_time: Seconds to wait for text stabilization (0 = off). + """ + + line_ttl: float = DEFAULT_LINE_TTL + line_similarity: float = DEFAULT_LINE_SIMILARITY + history_size: int = DEFAULT_HISTORY_SIZE + history_ttl: float = DEFAULT_HISTORY_TTL + history_similarity: float = DEFAULT_HISTORY_SIMILARITY + min_new_chars: int = DEFAULT_MIN_NEW_CHARS + min_new_words: int = DEFAULT_MIN_NEW_WORDS + min_alnum_ratio: float = DEFAULT_MIN_ALNUM_RATIO + debounce_time: float = DEFAULT_DEBOUNCE_TIME + + +# ── Helpers ────────────────────────────────────────────────────── + + +def _normalize(text: str) -> str: + """Collapse whitespace, strip, lowercase — for comparison only.""" + return " ".join(text.split()).strip().lower() + + +# ── Layer 1: Per-Region Line Tracker ───────────────────────────── + + +class RegionLineTracker: + """Track known lines for a single capture region. + + Lines already seen (exact or fuzzy match) are filtered out. + Entries expire after ``line_ttl`` seconds so the same text + can be re-read after a cooldown. + """ + + def __init__( + self, + similarity: float = DEFAULT_LINE_SIMILARITY, + line_ttl: float = DEFAULT_LINE_TTL, + ) -> None: + self._known: dict[str, KnownLine] = {} + self._similarity = similarity + self._line_ttl = line_ttl + + def extract_new_lines(self, ocr_result: OcrResult) -> list[str]: + """Return only lines that are NOT already known. + + Args: + ocr_result: OCR result with ``.lines`` populated. + + Returns: + List of *original* (non-normalized) line texts that are new. + """ + now = time.monotonic() + self._gc(now) + + new_lines: list[str] = [] + for line in ocr_result.lines: + raw = line.text.strip() + if not raw: + continue + norm = _normalize(raw) + if len(norm) < 2: + continue + + # Fast path: exact match + if norm in self._known: + self._known[norm].last_seen = now + self._known[norm].hit_count += 1 + continue + + # Slow path: fuzzy match (only short texts where OCR noise matters) + matched = False + if len(norm) < 60: + for key, entry in self._known.items(): + # Skip candidates with very different length + if abs(len(norm) - len(key)) > max(5, len(key) * 0.2): + continue + ratio = SequenceMatcher(None, norm, key).ratio() + if ratio >= self._similarity: + entry.last_seen = now + entry.hit_count += 1 + matched = True + break + + if not matched: + self._known[norm] = KnownLine( + text=norm, first_seen=now, last_seen=now + ) + new_lines.append(raw) + + return new_lines + + def reset(self) -> None: + """Clear all known lines (e.g. on scene change).""" + self._known.clear() + + @property + def known_count(self) -> int: + """Number of tracked lines.""" + return len(self._known) + + def _gc(self, now: float) -> None: + """Remove lines not seen for longer than TTL.""" + expired = [ + k for k, v in self._known.items() if now - v.last_seen > self._line_ttl + ] + for k in expired: + del self._known[k] + + +# ── Layer 2: Global Text History ───────────────────────────────── + + +class GlobalTextHistory: + """Ring buffer of recently emitted text blocks with TTL. + + Prevents the same composed text from being processed twice + within the TTL window, even if it comes from different regions + or after a brief interruption. + """ + + def __init__( + self, + max_size: int = DEFAULT_HISTORY_SIZE, + ttl: float = DEFAULT_HISTORY_TTL, + similarity: float = DEFAULT_HISTORY_SIMILARITY, + ) -> None: + self._entries: deque[HistoryEntry] = deque(maxlen=max_size) + self._ttl = ttl + self._similarity = similarity + + def is_duplicate(self, text: str) -> tuple[bool, float]: + """Check whether *text* duplicates something in recent history. + + Args: + text: Composed text block (already new-line joined). + + Returns: + ``(is_dup, best_similarity)`` — whether it matched and how closely. + """ + now = time.monotonic() + norm = _normalize(text) + if not norm: + return (True, 1.0) # empty → always "duplicate" + + best_sim = 0.0 + for entry in self._entries: + if now - entry.last_seen > self._ttl: + continue # expired + + # Fast path: identical normalized text + if entry.norm_text == norm: + entry.last_seen = now + entry.hit_count += 1 + return (True, 1.0) + + # Fuzzy path + ratio = SequenceMatcher(None, norm, entry.norm_text).ratio() + best_sim = max(best_sim, ratio) + if ratio >= self._similarity: + entry.last_seen = now + entry.hit_count += 1 + return (True, ratio) + + return (False, best_sim) + + def add(self, text: str) -> None: + """Record a new text block in history.""" + norm = _normalize(text) + now = time.monotonic() + self._entries.append( + HistoryEntry( + norm_text=norm, + original_text=text, + first_seen=now, + last_seen=now, + ) + ) + + def reset(self) -> None: + """Clear all history entries.""" + self._entries.clear() + + @property + def size(self) -> int: + return len(self._entries) + + +# ── Layer 3: Semantic Change Detector ──────────────────────────── + + +class ChangeDetector: + """Decide whether a set of new lines constitutes a meaningful change. + + Rejects: + - Very short text (< ``min_chars`` printable characters) + - Too few words (< ``min_words``) + - Mostly non-alphanumeric (ratio < ``min_alnum_ratio``) + """ + + def __init__( + self, + min_chars: int = DEFAULT_MIN_NEW_CHARS, + min_words: int = DEFAULT_MIN_NEW_WORDS, + min_alnum_ratio: float = DEFAULT_MIN_ALNUM_RATIO, + ) -> None: + self._min_chars = min_chars + self._min_words = min_words + self._min_alnum_ratio = min_alnum_ratio + + def is_significant(self, new_lines: list[str]) -> bool: + """Return ``True`` if the new lines represent a real content change.""" + text = " ".join(line.strip() for line in new_lines).strip() + + if len(text) < self._min_chars: + return False + + words = text.split() + if len(words) < self._min_words: + return False + + alnum = sum(1 for c in text if c.isalnum()) + ratio = alnum / len(text) if text else 0 + if ratio < self._min_alnum_ratio: + return False + + return True + + +# ── Debounce Emitter ───────────────────────────────────────────── + + +class DebouncedEmitter: + """Buffer text and only yield it after stabilization. + + Useful for typewriter-effect dialogs where text appears incrementally. + If ``stabilize_time`` is 0, debouncing is disabled (pass-through). + """ + + def __init__(self, stabilize_time: float = DEFAULT_DEBOUNCE_TIME) -> None: + self._stabilize = stabilize_time + self._pending: str | None = None + self._pending_since: float = 0.0 + + def feed(self, text: str) -> str | None: + """Feed new text. Returns the text once it has been stable long enough. + + Args: + text: The candidate text to emit. + + Returns: + The stabilized text, or ``None`` if still waiting. + """ + if self._stabilize <= 0: + return text # debounce disabled → immediate + + now = time.monotonic() + + if self._pending is None or _normalize(text) != _normalize(self._pending): + # New or changed text → reset timer + self._pending = text + self._pending_since = now + return None + + # Text unchanged — check if stable long enough + if now - self._pending_since >= self._stabilize: + result = self._pending + self._pending = None + return result + + return None # still waiting + + def flush(self) -> str | None: + """Force-emit whatever is pending (used on pipeline stop / force-read).""" + result = self._pending + self._pending = None + return result + + def reset(self) -> None: + """Discard pending text.""" + self._pending = None + + +# ── Cross-Region Dedup Pool ────────────────────────────────────── + + +class CrossRegionPool: + """Tracks lines across regions within a single tick to prevent cross-region duplication. + + Within a single pipeline tick, if region A already yielded line X, + region B should skip it. + """ + + def __init__(self, similarity: float = DEFAULT_LINE_SIMILARITY) -> None: + self._seen: dict[str, str] = {} # norm → original + self._similarity = similarity + + def is_seen(self, line: str) -> bool: + """Check if this line was already yielded by another region this tick.""" + norm = _normalize(line) + if not norm: + return True + + # Exact + if norm in self._seen: + return True + + # Fuzzy (short lines only) + if len(norm) < 60: + for key in self._seen: + if abs(len(norm) - len(key)) > max(4, len(key) * 0.2): + continue + if SequenceMatcher(None, norm, key).ratio() >= self._similarity: + return True + + return False + + def mark(self, line: str) -> None: + """Record a line as yielded this tick.""" + norm = _normalize(line) + if norm: + self._seen[norm] = line + + def clear(self) -> None: + """Reset for next tick.""" + self._seen.clear() + + +# ── Main Facade: SmartDedup ────────────────────────────────────── + + +class SmartDedup: + """Three-layer OCR deduplication with debounce and cross-region awareness. + + Replaces the old single-``_last_ocr_text`` comparison in ``bridge.py``. + + Example:: + + dedup = SmartDedup() + + # On each pipeline tick: + text = dedup.process(region_labels, ocr_results) + if text is not None: + await translate_and_speak(text) + + # On pipeline stop or config change: + dedup.reset() + """ + + def __init__(self, config: DedupConfig | None = None) -> None: + self._cfg = config or DedupConfig() + self._region_trackers: dict[str, RegionLineTracker] = {} + self._global_history = GlobalTextHistory( + max_size=self._cfg.history_size, + ttl=self._cfg.history_ttl, + similarity=self._cfg.history_similarity, + ) + self._change_detector = ChangeDetector( + min_chars=self._cfg.min_new_chars, + min_words=self._cfg.min_new_words, + min_alnum_ratio=self._cfg.min_alnum_ratio, + ) + self._debouncer = DebouncedEmitter(stabilize_time=self._cfg.debounce_time) + self._cross_pool = CrossRegionPool(similarity=self._cfg.line_similarity) + + # ── Public API ─────────────────────────────────────────────── + + def process( + self, + region_labels: list[str], + ocr_results: list[OcrResult], + *, + force: bool = False, + ) -> str | None: + """Run all dedup layers on multi-region OCR results. + + Args: + region_labels: Label/ID for each region (used as tracker key). + ocr_results: OCR result per region (same order as labels). + force: If ``True``, skip all dedup and return all text. + + Returns: + Text to translate + speak, or ``None`` if dedup suppressed it. + """ + if force: + texts = [r.text.strip() for r in ocr_results if r.text.strip()] + combined = "\n".join(texts) if texts else None + if combined: + self._global_history.add(combined) + # Also update region trackers so we don't double-read next tick + for label, result in zip(region_labels, ocr_results): + tracker = self._get_tracker(label) + tracker.extract_new_lines(result) # just mark as known + flushed = self._debouncer.flush() + return combined + + # Layer 1: Per-region line tracking + cross-region dedup + self._cross_pool.clear() + all_new_lines: list[str] = [] + + for label, result in zip(region_labels, ocr_results): + if result.error or result.is_empty: + continue + tracker = self._get_tracker(label) + region_new = tracker.extract_new_lines(result) + + for line in region_new: + if not self._cross_pool.is_seen(line): + self._cross_pool.mark(line) + all_new_lines.append(line) + + if not all_new_lines: + return None + + # Layer 3: Semantic significance check + if not self._change_detector.is_significant(all_new_lines): + logger.debug( + "Dedup: new lines not significant (%d lines, %d chars)", + len(all_new_lines), + sum(len(l) for l in all_new_lines), + ) + return None + + composed = "\n".join(all_new_lines) + + # Layer 2: Global history check + is_dup, sim = self._global_history.is_duplicate(composed) + if is_dup: + logger.debug("Dedup: global history match (sim=%.3f)", sim) + return None + + # Debounce (typewriter effect protection) + stabilized = self._debouncer.feed(composed) + if stabilized is None: + logger.debug("Dedup: waiting for text stabilization") + return None + + # ✅ New, significant, stabilized text — emit! + self._global_history.add(stabilized) + return stabilized + + def force_flush(self) -> str | None: + """Force-emit any debounced pending text.""" + pending = self._debouncer.flush() + if pending: + self._global_history.add(pending) + return pending + + def update_config(self, config: DedupConfig) -> None: + """Apply new configuration. Recreates internal components.""" + self._cfg = config + # Rebuild components with new settings + self._global_history = GlobalTextHistory( + max_size=config.history_size, + ttl=config.history_ttl, + similarity=config.history_similarity, + ) + self._change_detector = ChangeDetector( + min_chars=config.min_new_chars, + min_words=config.min_new_words, + min_alnum_ratio=config.min_alnum_ratio, + ) + self._debouncer = DebouncedEmitter(stabilize_time=config.debounce_time) + self._cross_pool = CrossRegionPool(similarity=config.line_similarity) + # Update existing region trackers + for tracker in self._region_trackers.values(): + tracker._similarity = config.line_similarity + tracker._line_ttl = config.line_ttl + + def reset(self) -> None: + """Clear all state (e.g. on scene change or pipeline restart).""" + for tracker in self._region_trackers.values(): + tracker.reset() + self._global_history.reset() + self._debouncer.reset() + self._cross_pool.clear() + logger.info("SmartDedup: all layers reset") + + def reset_region(self, label: str) -> None: + """Reset a specific region tracker.""" + if label in self._region_trackers: + self._region_trackers[label].reset() + + @property + def stats(self) -> dict[str, int]: + """Return diagnostic stats.""" + return { + "tracked_regions": len(self._region_trackers), + "total_known_lines": sum( + t.known_count for t in self._region_trackers.values() + ), + "history_size": self._global_history.size, + } + + # ── Internal ───────────────────────────────────────────────── + + def _get_tracker(self, label: str) -> RegionLineTracker: + """Get or create a line tracker for the given region label.""" + if label not in self._region_trackers: + self._region_trackers[label] = RegionLineTracker( + similarity=self._cfg.line_similarity, + line_ttl=self._cfg.line_ttl, + ) + return self._region_trackers[label] diff --git a/_archive/hooks/hook_decrypt.py b/_archive/hooks/hook_decrypt.py new file mode 100644 index 0000000000000000000000000000000000000000..d92c323d08351e72f8ff87e64e3148aa73b967f9 --- /dev/null +++ b/_archive/hooks/hook_decrypt.py @@ -0,0 +1,344 @@ +""" +Hook BCryptDecrypt using ctypes in-process hooking via DLL detour. +Instead of Frida, we directly hook BCryptDecrypt's IAT entry in oneocr.dll. +""" +import ctypes +import ctypes.wintypes as wt +from ctypes import ( + c_int64, c_char_p, c_ubyte, POINTER, byref, Structure, + c_void_p, c_ulong, c_int32, WINFUNCTYPE, CFUNCTYPE, c_uint8 +) +import os +import sys +import struct +from pathlib import Path + +OUTPUT_DIR = Path(r"c:\Users\MattyMroz\Desktop\PROJECTS\ONEOCR\frida_dump") +OUTPUT_DIR.mkdir(exist_ok=True) + +DLL_DIR = r"c:\Users\MattyMroz\Desktop\PROJECTS\ONEOCR\ocr_data" +MODEL_PATH = os.path.join(DLL_DIR, "oneocr.onemodel") +KEY = b'kj)TGtrK>f]b[Piow.gU+nC@s""""""4' + +# ── Globals to collect intercepted data ── +intercepted_calls = [] +decrypt_call_num = 0 + +# ── BCryptDecrypt signature ── +# NTSTATUS BCryptDecrypt(BCRYPT_KEY_HANDLE, PUCHAR pbInput, ULONG cbInput, +# VOID* pPadding, PUCHAR pbIV, ULONG cbIV, PUCHAR pbOutput, +# ULONG cbOutput, ULONG* pcbResult, ULONG dwFlags) + +BCRYPT_DECRYPT_TYPE = WINFUNCTYPE( + c_ulong, # NTSTATUS return + c_void_p, # hKey + c_void_p, # pbInput + c_ulong, # cbInput + c_void_p, # pPaddingInfo + c_void_p, # pbIV + c_ulong, # cbIV + c_void_p, # pbOutput + c_ulong, # cbOutput + POINTER(c_ulong), # pcbResult + c_ulong, # dwFlags +) + +# Store original function +original_bcrypt_decrypt = None + + +def hooked_bcrypt_decrypt(hKey, pbInput, cbInput, pPadding, pbIV, cbIV, + pbOutput, cbOutput, pcbResult, dwFlags): + """Our hook that intercepts BCryptDecrypt calls.""" + global decrypt_call_num + + call_num = decrypt_call_num + decrypt_call_num += 1 + + # Read IV before the call (it may be modified) + iv_before = None + if pbIV and cbIV > 0: + try: + iv_before = ctypes.string_at(pbIV, cbIV) + except: + pass + + # Read encrypted input BEFORE the call + encrypted_input = None + if pbInput and cbInput > 0: + try: + encrypted_input = ctypes.string_at(pbInput, min(cbInput, 64)) + except: + pass + + # Call original + status = original_bcrypt_decrypt(hKey, pbInput, cbInput, pPadding, + pbIV, cbIV, pbOutput, cbOutput, + pcbResult, dwFlags) + + # Get result size + result_size = 0 + if pcbResult: + result_size = pcbResult[0] + + # Read IV after (CFB mode modifies the IV) + iv_after = None + if pbIV and cbIV > 0: + try: + iv_after = ctypes.string_at(pbIV, cbIV) + except: + pass + + info = { + 'call': call_num, + 'status': status, + 'cbInput': cbInput, + 'cbIV': cbIV, + 'cbOutput': result_size, + 'dwFlags': dwFlags, + 'iv_before': iv_before.hex() if iv_before else None, + 'iv_after': iv_after.hex() if iv_after else None, + } + + print(f"[BCryptDecrypt #{call_num}] status={status:#x} " + f"in={cbInput} out={result_size} iv_len={cbIV} flags={dwFlags}") + if encrypted_input: + print(f" Encrypted input[:32]: {encrypted_input[:32].hex()}") + print(f" pbInput addr: {pbInput:#x}") + if iv_before: + print(f" IV before: {iv_before.hex()}") + if iv_after and iv_after != iv_before: + print(f" IV after: {iv_after.hex()}") + + # Save decrypted data + if status == 0 and result_size > 0 and pbOutput: + try: + decrypted = ctypes.string_at(pbOutput, result_size) + + # Check for magic number + if len(decrypted) >= 4: + magic = struct.unpack(' Saved: {fname.name} ({result_size:,} bytes)") + + except Exception as e: + print(f" Error reading output: {e}") + + intercepted_calls.append(info) + return status + + +def hook_iat(dll_handle, target_dll_name, target_func_name, hook_func): + """ + Hook a function by patching the Import Address Table (IAT) of a DLL. + Returns the original function pointer. + """ + import pefile + + # Get the DLL file path + kernel32 = ctypes.windll.kernel32 + buf = ctypes.create_unicode_buffer(260) + h = ctypes.c_void_p(dll_handle) + kernel32.GetModuleFileNameW(h, buf, 260) + dll_path = buf.value + + print(f"Analyzing IAT of: {dll_path}") + + pe = pefile.PE(dll_path) + + # Find the import + base_addr = dll_handle + if hasattr(dll_handle, '_handle'): + base_addr = dll_handle._handle + + for entry in pe.DIRECTORY_ENTRY_IMPORT: + import_name = entry.dll.decode('utf-8', errors='ignore').lower() + if target_dll_name.lower() not in import_name: + continue + + for imp in entry.imports: + if imp.name and imp.name.decode('utf-8', errors='ignore') == target_func_name: + # Found it! The IAT entry is at base_addr + imp.address - pe.OPTIONAL_HEADER.ImageBase + iat_rva = imp.address - pe.OPTIONAL_HEADER.ImageBase + iat_addr = base_addr + iat_rva + + print(f"Found {target_func_name} in IAT at RVA={iat_rva:#x}, " + f"VA={iat_addr:#x}") + + # Read current value (original function pointer) + original_ptr = ctypes.c_void_p() + ctypes.memmove(ctypes.byref(original_ptr), iat_addr, 8) + print(f"Original function pointer: {original_ptr.value:#x}") + + # Create callback + callback = BCRYPT_DECRYPT_TYPE(hook_func) + callback_ptr = ctypes.cast(callback, c_void_p).value + + # Make IAT page writable + old_protect = c_ulong() + PAGE_READWRITE = 0x04 + kernel32.VirtualProtect( + ctypes.c_void_p(iat_addr), 8, + PAGE_READWRITE, ctypes.byref(old_protect) + ) + + # Patch IAT + new_ptr = ctypes.c_void_p(callback_ptr) + ctypes.memmove(iat_addr, ctypes.byref(new_ptr), 8) + + # Restore protection + kernel32.VirtualProtect( + ctypes.c_void_p(iat_addr), 8, + old_protect.value, ctypes.byref(old_protect) + ) + + print(f"IAT patched! New function pointer: {callback_ptr:#x}") + + # Create callable from original + original_func = BCRYPT_DECRYPT_TYPE(original_ptr.value) + + pe.close() + return original_func, callback # Return both to prevent GC + + pe.close() + return None, None + + +def main(): + global original_bcrypt_decrypt + + print("=" * 70) + print("IN-PROCESS BCryptDecrypt HOOKING") + print("=" * 70) + + # Load DLL + kernel32 = ctypes.WinDLL("kernel32", use_last_error=True) + kernel32.SetDllDirectoryW(DLL_DIR) + + dll_path = os.path.join(DLL_DIR, "oneocr.dll") + print(f"Loading: {dll_path}") + dll = ctypes.WinDLL(dll_path) + + # Setup function types + dll.CreateOcrInitOptions.argtypes = [POINTER(c_int64)] + dll.CreateOcrInitOptions.restype = c_int64 + dll.OcrInitOptionsSetUseModelDelayLoad.argtypes = [c_int64, c_ubyte] + dll.OcrInitOptionsSetUseModelDelayLoad.restype = c_int64 + dll.CreateOcrPipeline.argtypes = [c_char_p, c_char_p, c_int64, POINTER(c_int64)] + dll.CreateOcrPipeline.restype = c_int64 + + # Try approach 1: Direct BCryptDecrypt function pointer replacement + print("\n--- Setting up BCryptDecrypt hook ---") + + # Get the real BCryptDecrypt + bcrypt_dll = ctypes.WinDLL("bcrypt") + real_decrypt_addr = ctypes.cast( + bcrypt_dll.BCryptDecrypt, c_void_p + ).value + print(f"Real BCryptDecrypt address: {real_decrypt_addr:#x}") + + # Instead of IAT patching, let's use a simpler approach: + # We'll call BCryptDecrypt ourselves to first get a "sizing" call, + # then intercept the actual decrypt. + + # Actually, the simplest approach: use a manual detour + # But let's try IAT patching first if pefile is available + try: + import pefile + print("pefile available, trying IAT hook...") + + original_bcrypt_decrypt_func, callback_ref = hook_iat( + dll._handle, 'bcrypt', 'BCryptDecrypt', hooked_bcrypt_decrypt + ) + + if original_bcrypt_decrypt_func: + original_bcrypt_decrypt = original_bcrypt_decrypt_func + print("IAT hook installed successfully!") + else: + raise Exception("IAT hook failed - function not found in imports") + + except ImportError: + print("pefile not available, installing...") + os.system("uv pip install pefile") + import pefile + + original_bcrypt_decrypt_func, callback_ref = hook_iat( + dll._handle, 'bcrypt', 'BCryptDecrypt', hooked_bcrypt_decrypt + ) + + if original_bcrypt_decrypt_func: + original_bcrypt_decrypt = original_bcrypt_decrypt_func + else: + print("ERROR: Could not hook BCryptDecrypt") + return + + # Now create the pipeline - this will trigger decryption via our hook + print("\n--- Creating OCR Pipeline (will trigger BCryptDecrypt) ---") + + init_options = c_int64() + ret = dll.CreateOcrInitOptions(byref(init_options)) + print(f"CreateOcrInitOptions: {ret}") + + ret = dll.OcrInitOptionsSetUseModelDelayLoad(init_options, 0) + print(f"SetUseModelDelayLoad: {ret}") + + pipeline = c_int64() + model_buf = ctypes.create_string_buffer(MODEL_PATH.encode()) + key_buf = ctypes.create_string_buffer(KEY) + + print(f"\nCalling CreateOcrPipeline...") + print(f"Model: {MODEL_PATH}") + print(f"Key: {KEY}") + print() + + ret = dll.CreateOcrPipeline(model_buf, key_buf, init_options, byref(pipeline)) + + print(f"\nCreateOcrPipeline returned: {ret}") + print(f"Pipeline handle: {pipeline.value}") + + # Summary + print() + print("=" * 70) + print("SUMMARY") + print("=" * 70) + print(f"Total BCryptDecrypt calls intercepted: {len(intercepted_calls)}") + + magic_1_files = [] + for info in intercepted_calls: + if info.get('magic') == 1: + magic_1_files.append(info) + + if magic_1_files: + print(f"\n*** Found {len(magic_1_files)} calls with magic_number == 1! ***") + for info in magic_1_files: + print(f" Call #{info['call']}: input={info['cbInput']:,}, " + f"output={info['cbOutput']:,}") + + # List saved files + if OUTPUT_DIR.exists(): + files = sorted(OUTPUT_DIR.glob("decrypt_*.bin")) + if files: + print(f"\nSaved {len(files)} decrypted buffers:") + total = 0 + for f in files: + sz = f.stat().st_size + total += sz + header = open(f, 'rb').read(4) + magic = struct.unpack('= 4 else -1 + marker = " *** MAGIC=1 ***" if magic == 1 else "" + print(f" {f.name}: {sz:,} bytes (magic={magic}){marker}") + print(f"Total: {total:,} bytes ({total/1024/1024:.1f} MB)") + + print("\nDone!") + + +if __name__ == '__main__': + main() diff --git a/_archive/hooks/hook_full_bcrypt.py b/_archive/hooks/hook_full_bcrypt.py new file mode 100644 index 0000000000000000000000000000000000000000..3d9b8944e1897bb244f505166283bbf6fb321892 --- /dev/null +++ b/_archive/hooks/hook_full_bcrypt.py @@ -0,0 +1,441 @@ +""" +Extended BCrypt hook - intercepts ALL BCrypt functions to capture the full +crypto setup: algorithm provider, properties, and actual key material. +""" +import ctypes +import ctypes.wintypes as wt +from ctypes import ( + c_int64, c_char_p, c_ubyte, POINTER, byref, Structure, + c_void_p, c_ulong, c_int32, WINFUNCTYPE, CFUNCTYPE, c_uint8 +) +import os +import sys +import struct +from pathlib import Path + +OUTPUT_DIR = Path(r"c:\Users\MattyMroz\Desktop\PROJECTS\ONEOCR\frida_dump") +OUTPUT_DIR.mkdir(exist_ok=True) + +DLL_DIR = r"c:\Users\MattyMroz\Desktop\PROJECTS\ONEOCR\ocr_data" +MODEL_PATH = os.path.join(DLL_DIR, "oneocr.onemodel") +KEY = b'kj)TGtrK>f]b[Piow.gU+nC@s""""""4' + +# ── Globals ── +intercepted_bcrypt = [] +decrypt_call_num = 0 + +# ── Function types ── +# BCryptDecrypt +BCRYPT_DECRYPT_TYPE = WINFUNCTYPE( + c_ulong, c_void_p, c_void_p, c_ulong, c_void_p, + c_void_p, c_ulong, c_void_p, c_ulong, POINTER(c_ulong), c_ulong +) + +# BCryptOpenAlgorithmProvider(phAlgorithm, pszAlgId, pszImplementation, dwFlags) +BCRYPT_OPEN_ALG_TYPE = WINFUNCTYPE( + c_ulong, POINTER(c_void_p), c_void_p, c_void_p, c_ulong +) + +# BCryptSetProperty(hObject, pszProperty, pbInput, cbInput, dwFlags) +BCRYPT_SET_PROP_TYPE = WINFUNCTYPE( + c_ulong, c_void_p, c_void_p, c_void_p, c_ulong, c_ulong +) + +# BCryptGetProperty(hObject, pszProperty, pbOutput, cbOutput, pcbResult, dwFlags) +BCRYPT_GET_PROP_TYPE = WINFUNCTYPE( + c_ulong, c_void_p, c_void_p, c_void_p, c_ulong, POINTER(c_ulong), c_ulong +) + +# BCryptGenerateSymmetricKey(hAlgorithm, phKey, pbKeyObject, cbKeyObject, +# pbSecret, cbSecret, dwFlags) +BCRYPT_GEN_KEY_TYPE = WINFUNCTYPE( + c_ulong, c_void_p, POINTER(c_void_p), c_void_p, c_ulong, + c_void_p, c_ulong, c_ulong +) + +# BCryptImportKey(hAlgorithm, hImportKey, pszBlobType, phKey, pbKeyObject, +# cbKeyObject, pbInput, cbInput, dwFlags) +BCRYPT_IMPORT_KEY_TYPE = WINFUNCTYPE( + c_ulong, c_void_p, c_void_p, c_void_p, POINTER(c_void_p), + c_void_p, c_ulong, c_void_p, c_ulong, c_ulong +) + +# BCryptEncrypt - same signature as BCryptDecrypt +BCRYPT_ENCRYPT_TYPE = WINFUNCTYPE( + c_ulong, c_void_p, c_void_p, c_ulong, c_void_p, + c_void_p, c_ulong, c_void_p, c_ulong, POINTER(c_ulong), c_ulong +) + +# Store originals +orig_decrypt = None +orig_open_alg = None +orig_set_prop = None +orig_get_prop = None +orig_gen_key = None +orig_import_key = None +orig_encrypt = None + +# Keep callback references alive +_callback_refs = [] + +# Track key handles -> key material +key_handle_to_material = {} +alg_handle_to_name = {} + + +def read_wstr(ptr): + """Read a null-terminated UTF-16LE string from a pointer.""" + if not ptr: + return "" + try: + buf = ctypes.wstring_at(ptr) + return buf + except: + return "" + + +def hooked_open_alg(phAlgorithm, pszAlgId, pszImplementation, dwFlags): + alg_name = read_wstr(pszAlgId) + impl = read_wstr(pszImplementation) + status = orig_open_alg(phAlgorithm, pszAlgId, pszImplementation, dwFlags) + handle = phAlgorithm[0] if phAlgorithm else None + if handle: + alg_handle_to_name[handle.value if hasattr(handle, 'value') else handle] = alg_name + print(f"[BCryptOpenAlgorithmProvider] alg={alg_name!r} impl={impl!r} " + f"flags={dwFlags:#x} -> handle={handle} status={status:#010x}") + return status + + +def hooked_set_prop(hObject, pszProperty, pbInput, cbInput, dwFlags): + prop_name = read_wstr(pszProperty) + + # Read property value + value_repr = "" + if pbInput and cbInput > 0: + try: + raw = ctypes.string_at(pbInput, cbInput) + # Try as wstring first (for chaining mode etc) + try: + value_repr = raw.decode('utf-16-le').rstrip('\x00') + except: + value_repr = raw.hex() + # Also try as DWORD for numeric properties + if cbInput == 4: + dword_val = struct.unpack(' status={status:#010x}") + return status + + +def hooked_get_prop(hObject, pszProperty, pbOutput, cbOutput, pcbResult, dwFlags): + prop_name = read_wstr(pszProperty) + status = orig_get_prop(hObject, pszProperty, pbOutput, cbOutput, pcbResult, dwFlags) + + result_size = pcbResult[0] if pcbResult else 0 + value_repr = "" + if status == 0 and pbOutput and result_size > 0: + try: + raw = ctypes.string_at(pbOutput, result_size) + if result_size == 4: + value_repr = f"dword={struct.unpack(' {value_repr!r} " + f"({result_size} bytes) status={status:#010x}") + return status + + +def hooked_gen_key(hAlgorithm, phKey, pbKeyObject, cbKeyObject, + pbSecret, cbSecret, dwFlags): + # Capture the secret key material BEFORE the call + secret = None + if pbSecret and cbSecret > 0: + try: + secret = ctypes.string_at(pbSecret, cbSecret) + except: + pass + + status = orig_gen_key(hAlgorithm, phKey, pbKeyObject, cbKeyObject, + pbSecret, cbSecret, dwFlags) + + key_handle = phKey[0] if phKey else None + alg_h = hAlgorithm.value if hasattr(hAlgorithm, 'value') else hAlgorithm + alg = alg_handle_to_name.get(alg_h, "?") + + print(f"[BCryptGenerateSymmetricKey] alg={alg} secret_len={cbSecret} " + f"keyObjSize={cbKeyObject} flags={dwFlags:#x} " + f"-> key={key_handle} status={status:#010x}") + if secret: + print(f" Secret bytes: {secret.hex()}") + print(f" Secret ASCII: {secret!r}") + if key_handle: + kh = key_handle.value if hasattr(key_handle, 'value') else key_handle + key_handle_to_material[kh] = secret + + return status + + +def hooked_import_key(hAlgorithm, hImportKey, pszBlobType, phKey, + pbKeyObject, cbKeyObject, pbInput, cbInput, dwFlags): + blob_type = read_wstr(pszBlobType) + + blob_data = None + if pbInput and cbInput > 0: + try: + blob_data = ctypes.string_at(pbInput, cbInput) + except: + pass + + status = orig_import_key(hAlgorithm, hImportKey, pszBlobType, phKey, + pbKeyObject, cbKeyObject, pbInput, cbInput, dwFlags) + + key_handle = phKey[0] if phKey else None + print(f"[BCryptImportKey] blob_type={blob_type!r} blob_size={cbInput} " + f"flags={dwFlags:#x} -> key={key_handle} status={status:#010x}") + if blob_data: + print(f" Blob: {blob_data.hex()}") + if cbInput > 12: + magic, ver, key_len = struct.unpack(' 0: + try: + iv_before = ctypes.string_at(pbIV, cbIV) + except: + pass + + encrypted_input = None + if pbInput and cbInput > 0: + try: + encrypted_input = ctypes.string_at(pbInput, min(cbInput, 64)) + except: + pass + + status = orig_decrypt(hKey, pbInput, cbInput, pPadding, + pbIV, cbIV, pbOutput, cbOutput, pcbResult, dwFlags) + + result_size = pcbResult[0] if pcbResult else 0 + + iv_after = None + if pbIV and cbIV > 0: + try: + iv_after = ctypes.string_at(pbIV, cbIV) + except: + pass + + # Check if we know the key material for this handle + kh = hKey.value if hasattr(hKey, 'value') else hKey + known_key = key_handle_to_material.get(kh) + + print(f"[BCryptDecrypt #{call_num}] status={status:#x} " + f"in={cbInput} out={result_size} iv_len={cbIV} flags={dwFlags}") + if known_key: + print(f" Key material: {known_key.hex()}") + if encrypted_input: + print(f" Enc input[:32]: {encrypted_input[:32].hex()}") + if iv_before: + print(f" IV before: {iv_before.hex()}") + if iv_after and iv_after != iv_before: + print(f" IV after: {iv_after.hex()}") + + if status == 0 and result_size > 0 and pbOutput: + try: + decrypted = ctypes.string_at(pbOutput, result_size) + print(f" Decrypted[:32]: {decrypted[:32].hex()}") + fname = OUTPUT_DIR / f"decrypt_{call_num}_in{cbInput}_out{result_size}.bin" + fname.write_bytes(decrypted) + print(f" -> Saved: {fname.name}") + except Exception as e: + print(f" Error: {e}") + + return status + + +def hook_iat_generic(dll_handle, target_dll_name, target_func_name, hook_func, func_type): + """Hook a function by patching the IAT. Returns (original_func, callback_ref).""" + import pefile + + kernel32 = ctypes.windll.kernel32 + buf = ctypes.create_unicode_buffer(260) + h = ctypes.c_void_p(dll_handle) + kernel32.GetModuleFileNameW(h, buf, 260) + dll_path = buf.value + + pe = pefile.PE(dll_path) + base_addr = dll_handle + + for entry in pe.DIRECTORY_ENTRY_IMPORT: + import_name = entry.dll.decode('utf-8', errors='ignore').lower() + if target_dll_name.lower() not in import_name: + continue + + for imp in entry.imports: + if imp.name and imp.name.decode('utf-8', errors='ignore') == target_func_name: + iat_rva = imp.address - pe.OPTIONAL_HEADER.ImageBase + iat_addr = base_addr + iat_rva + + original_ptr = ctypes.c_void_p() + ctypes.memmove(ctypes.byref(original_ptr), iat_addr, 8) + + callback = func_type(hook_func) + callback_ptr = ctypes.cast(callback, c_void_p).value + + old_protect = c_ulong() + kernel32.VirtualProtect(ctypes.c_void_p(iat_addr), 8, 0x04, ctypes.byref(old_protect)) + new_ptr = ctypes.c_void_p(callback_ptr) + ctypes.memmove(iat_addr, ctypes.byref(new_ptr), 8) + kernel32.VirtualProtect(ctypes.c_void_p(iat_addr), 8, old_protect.value, ctypes.byref(old_protect)) + + original_func = func_type(original_ptr.value) + pe.close() + print(f" Hooked {target_func_name} at IAT RVA={iat_rva:#x}") + return original_func, callback + + pe.close() + return None, None + + +def main(): + global orig_decrypt, orig_open_alg, orig_set_prop, orig_get_prop + global orig_gen_key, orig_import_key, orig_encrypt + + print("=" * 70) + print("EXTENDED BCrypt HOOK - Capturing ALL crypto setup") + print("=" * 70) + + # Clean dump dir + for f in OUTPUT_DIR.glob("decrypt_*.bin"): + f.unlink() + + kernel32 = ctypes.WinDLL("kernel32", use_last_error=True) + kernel32.SetDllDirectoryW(DLL_DIR) + + dll_path = os.path.join(DLL_DIR, "oneocr.dll") + print(f"Loading: {dll_path}") + dll = ctypes.WinDLL(dll_path) + + dll.CreateOcrInitOptions.argtypes = [POINTER(c_int64)] + dll.CreateOcrInitOptions.restype = c_int64 + dll.OcrInitOptionsSetUseModelDelayLoad.argtypes = [c_int64, c_ubyte] + dll.OcrInitOptionsSetUseModelDelayLoad.restype = c_int64 + dll.CreateOcrPipeline.argtypes = [c_char_p, c_char_p, c_int64, POINTER(c_int64)] + dll.CreateOcrPipeline.restype = c_int64 + + import pefile # noqa + + # Hook ALL BCrypt functions + hooks = [ + ('bcrypt', 'BCryptOpenAlgorithmProvider', hooked_open_alg, BCRYPT_OPEN_ALG_TYPE), + ('bcrypt', 'BCryptSetProperty', hooked_set_prop, BCRYPT_SET_PROP_TYPE), + ('bcrypt', 'BCryptGetProperty', hooked_get_prop, BCRYPT_GET_PROP_TYPE), + ('bcrypt', 'BCryptGenerateSymmetricKey', hooked_gen_key, BCRYPT_GEN_KEY_TYPE), + ('bcrypt', 'BCryptImportKey', hooked_import_key, BCRYPT_IMPORT_KEY_TYPE), + ('bcrypt', 'BCryptEncrypt', hooked_encrypt, BCRYPT_ENCRYPT_TYPE), + ('bcrypt', 'BCryptDecrypt', hooked_bcrypt_decrypt, BCRYPT_DECRYPT_TYPE), + ] + + originals = {} + print("\n--- Installing IAT hooks ---") + for target_dll, func_name, hook_func, func_type in hooks: + orig, cb = hook_iat_generic(dll._handle, target_dll, func_name, hook_func, func_type) + if orig: + originals[func_name] = orig + _callback_refs.append(cb) + else: + print(f" WARNING: {func_name} not found in IAT (may not be imported)") + + orig_open_alg = originals.get('BCryptOpenAlgorithmProvider') + orig_set_prop = originals.get('BCryptSetProperty') + orig_get_prop = originals.get('BCryptGetProperty') + orig_gen_key = originals.get('BCryptGenerateSymmetricKey') + orig_import_key = originals.get('BCryptImportKey') + orig_encrypt = originals.get('BCryptEncrypt') + orig_decrypt = originals.get('BCryptDecrypt') + + if not orig_decrypt: + print("FATAL: Could not hook BCryptDecrypt!") + return + + print("\n--- Creating OCR Pipeline ---") + init_options = c_int64() + ret = dll.CreateOcrInitOptions(byref(init_options)) + print(f"CreateOcrInitOptions: {ret}") + + ret = dll.OcrInitOptionsSetUseModelDelayLoad(init_options, 0) + print(f"SetUseModelDelayLoad: {ret}") + + pipeline = c_int64() + model_buf = ctypes.create_string_buffer(MODEL_PATH.encode()) + key_buf = ctypes.create_string_buffer(KEY) + + print(f"\nCalling CreateOcrPipeline...") + print(f"Model: {MODEL_PATH}") + print(f"Key: {KEY}") + print() + + ret = dll.CreateOcrPipeline(model_buf, key_buf, init_options, byref(pipeline)) + + print(f"\nCreateOcrPipeline returned: {ret}") + print(f"Pipeline handle: {pipeline.value}") + + # Summary + print() + print("=" * 70) + print("SUMMARY") + print("=" * 70) + print(f"Key handles tracked: {len(key_handle_to_material)}") + for kh, mat in key_handle_to_material.items(): + print(f" Handle {kh:#x}: {mat.hex()}") + print(f" ASCII: {mat!r}") + print(f" Length: {len(mat)}") + + files = sorted(OUTPUT_DIR.glob("decrypt_*.bin")) + if files: + print(f"\nSaved {len(files)} decrypted buffers") + total = sum(f.stat().st_size for f in files) + print(f"Total: {total:,} bytes ({total/1024/1024:.1f} MB)") + + print("\nDone!") + + +if __name__ == '__main__': + main() diff --git a/_archive/hooks/hook_full_log.py b/_archive/hooks/hook_full_log.py new file mode 100644 index 0000000000000000000000000000000000000000..0b4403860c9200e848158cf1c3c7106c65c5e92b --- /dev/null +++ b/_archive/hooks/hook_full_log.py @@ -0,0 +1,265 @@ +""" +Full BCrypt hash hook - saves all hash inputs and AES keys to JSON for analysis. +""" +import ctypes +from ctypes import ( + c_int64, c_char_p, c_ubyte, POINTER, byref, + c_void_p, c_ulong, WINFUNCTYPE +) +import os +import struct +import json +from pathlib import Path + +OUTPUT_DIR = Path(r"c:\Users\MattyMroz\Desktop\PROJECTS\ONEOCR\frida_dump") +OUTPUT_DIR.mkdir(exist_ok=True) + +DLL_DIR = r"c:\Users\MattyMroz\Desktop\PROJECTS\ONEOCR\ocr_data" +MODEL_PATH = os.path.join(DLL_DIR, "oneocr.onemodel") +KEY = b'kj)TGtrK>f]b[Piow.gU+nC@s""""""4' + +# Globals +decrypt_call_num = 0 +_callback_refs = [] +key_handle_to_material = {} +hash_handle_to_data = {} +alg_handle_to_name = {} + +# Collect all crypto operations for JSON output +crypto_log = [] + +DECRYPT_T = WINFUNCTYPE(c_ulong, c_void_p, c_void_p, c_ulong, c_void_p, + c_void_p, c_ulong, c_void_p, c_ulong, POINTER(c_ulong), c_ulong) +OPEN_ALG_T = WINFUNCTYPE(c_ulong, POINTER(c_void_p), c_void_p, c_void_p, c_ulong) +SET_PROP_T = WINFUNCTYPE(c_ulong, c_void_p, c_void_p, c_void_p, c_ulong, c_ulong) +GEN_KEY_T = WINFUNCTYPE(c_ulong, c_void_p, POINTER(c_void_p), c_void_p, c_ulong, + c_void_p, c_ulong, c_ulong) +CREATE_HASH_T = WINFUNCTYPE(c_ulong, c_void_p, POINTER(c_void_p), c_void_p, c_ulong, + c_void_p, c_ulong, c_ulong) +HASH_DATA_T = WINFUNCTYPE(c_ulong, c_void_p, c_void_p, c_ulong, c_ulong) +FINISH_HASH_T = WINFUNCTYPE(c_ulong, c_void_p, c_void_p, c_ulong, c_ulong) +ENCRYPT_T = WINFUNCTYPE(c_ulong, c_void_p, c_void_p, c_ulong, c_void_p, + c_void_p, c_ulong, c_void_p, c_ulong, POINTER(c_ulong), c_ulong) + +orig = {} + + +def read_wstr(ptr): + if not ptr: + return "" + try: + return ctypes.wstring_at(ptr) + except: + return "" + + +def hooked_open_alg(phAlgorithm, pszAlgId, pszImplementation, dwFlags): + alg_name = read_wstr(pszAlgId) + status = orig['OpenAlgorithmProvider'](phAlgorithm, pszAlgId, pszImplementation, dwFlags) + handle = phAlgorithm[0] if phAlgorithm else None + if handle: + h = handle.value if hasattr(handle, 'value') else handle + alg_handle_to_name[h] = alg_name + return status + + +def hooked_set_prop(hObject, pszProperty, pbInput, cbInput, dwFlags): + return orig['SetProperty'](hObject, pszProperty, pbInput, cbInput, dwFlags) + + +def hooked_create_hash(hAlgorithm, phHash, pbHashObject, cbHashObject, + pbSecret, cbSecret, dwFlags): + status = orig['CreateHash'](hAlgorithm, phHash, pbHashObject, cbHashObject, + pbSecret, cbSecret, dwFlags) + hash_handle = phHash[0] if phHash else None + hmac_key = None + if pbSecret and cbSecret > 0: + hmac_key = ctypes.string_at(pbSecret, cbSecret) + hh = hash_handle.value if hasattr(hash_handle, 'value') else hash_handle + hash_handle_to_data[hh] = {'hmac_key': hmac_key, 'data_chunks': []} + return status + + +def hooked_hash_data(hHash, pbInput, cbInput, dwFlags): + status = orig['HashData'](hHash, pbInput, cbInput, dwFlags) + hh = hHash.value if hasattr(hHash, 'value') else hHash + if pbInput and cbInput > 0: + data = ctypes.string_at(pbInput, cbInput) + if hh in hash_handle_to_data: + hash_handle_to_data[hh]['data_chunks'].append(data) + return status + + +def hooked_finish_hash(hHash, pbOutput, cbOutput, dwFlags): + status = orig['FinishHash'](hHash, pbOutput, cbOutput, dwFlags) + hh = hHash.value if hasattr(hHash, 'value') else hHash + output = None + if pbOutput and cbOutput > 0: + output = ctypes.string_at(pbOutput, cbOutput) + info = hash_handle_to_data.get(hh) + if info and output: + all_data = b"".join(info['data_chunks']) + crypto_log.append({ + 'op': 'sha256', + 'input': all_data.hex(), + 'input_len': len(all_data), + 'output': output.hex(), + }) + return status + + +def hooked_gen_key(hAlgorithm, phKey, pbKeyObject, cbKeyObject, + pbSecret, cbSecret, dwFlags): + secret = None + if pbSecret and cbSecret > 0: + secret = ctypes.string_at(pbSecret, cbSecret) + status = orig['GenerateSymmetricKey'](hAlgorithm, phKey, pbKeyObject, cbKeyObject, + pbSecret, cbSecret, dwFlags) + key_handle = phKey[0] if phKey else None + if key_handle and secret: + kh = key_handle.value if hasattr(key_handle, 'value') else key_handle + key_handle_to_material[kh] = secret + return status + + +def hooked_encrypt(hKey, pbInput, cbInput, pPadding, pbIV, cbIV, + pbOutput, cbOutput, pcbResult, dwFlags): + status = orig['Encrypt'](hKey, pbInput, cbInput, pPadding, pbIV, cbIV, + pbOutput, cbOutput, pcbResult, dwFlags) + result_size = pcbResult[0] if pcbResult else 0 + if cbIV > 0: + iv = ctypes.string_at(pbIV, cbIV) if pbIV else None + enc_in = ctypes.string_at(pbInput, min(cbInput, 32)) if pbInput and cbInput > 0 else None + enc_out = ctypes.string_at(pbOutput, min(result_size, 32)) if pbOutput and result_size > 0 else None + kh = hKey.value if hasattr(hKey, 'value') else hKey + crypto_log.append({ + 'op': 'encrypt', + 'input_size': cbInput, + 'output_size': result_size, + 'aes_key': key_handle_to_material.get(kh, b'').hex(), + 'input_preview': enc_in.hex() if enc_in else None, + 'output_preview': enc_out.hex() if enc_out else None, + }) + return status + + +def hooked_decrypt(hKey, pbInput, cbInput, pPadding, pbIV, cbIV, + pbOutput, cbOutput, pcbResult, dwFlags): + global decrypt_call_num + status = orig['Decrypt'](hKey, pbInput, cbInput, pPadding, + pbIV, cbIV, pbOutput, cbOutput, pcbResult, dwFlags) + result_size = pcbResult[0] if pcbResult else 0 + + if cbIV > 0: + call_num = decrypt_call_num + decrypt_call_num += 1 + kh = hKey.value if hasattr(hKey, 'value') else hKey + aes_key = key_handle_to_material.get(kh, b'').hex() + + dec_data = None + if status == 0 and result_size > 0 and pbOutput: + dec_data = ctypes.string_at(pbOutput, result_size) + fname = OUTPUT_DIR / f"decrypt_{call_num}_in{cbInput}_out{result_size}.bin" + fname.write_bytes(dec_data) + + crypto_log.append({ + 'op': 'decrypt', + 'call_num': call_num, + 'input_size': cbInput, + 'output_size': result_size, + 'aes_key': aes_key, + 'first_bytes': dec_data[:32].hex() if dec_data else None, + }) + + return status + + +def hook_iat(dll_handle, target_dll, func_name, hook_func, func_type): + import pefile + kernel32 = ctypes.windll.kernel32 + buf = ctypes.create_unicode_buffer(260) + kernel32.GetModuleFileNameW(ctypes.c_void_p(dll_handle), buf, 260) + pe = pefile.PE(buf.value) + for entry in pe.DIRECTORY_ENTRY_IMPORT: + if target_dll.lower() not in entry.dll.decode('utf-8', errors='ignore').lower(): + continue + for imp in entry.imports: + if imp.name and imp.name.decode('utf-8', errors='ignore') == func_name: + iat_rva = imp.address - pe.OPTIONAL_HEADER.ImageBase + iat_addr = dll_handle + iat_rva + original_ptr = ctypes.c_void_p() + ctypes.memmove(ctypes.byref(original_ptr), iat_addr, 8) + callback = func_type(hook_func) + callback_ptr = ctypes.cast(callback, c_void_p).value + old_protect = c_ulong() + kernel32.VirtualProtect(ctypes.c_void_p(iat_addr), 8, 0x04, byref(old_protect)) + new_ptr = ctypes.c_void_p(callback_ptr) + ctypes.memmove(iat_addr, ctypes.byref(new_ptr), 8) + kernel32.VirtualProtect(ctypes.c_void_p(iat_addr), 8, old_protect.value, byref(old_protect)) + original_func = func_type(original_ptr.value) + pe.close() + _callback_refs.append(callback) + return original_func + pe.close() + return None + + +def main(): + print("BCrypt Full Hook - collecting all crypto operations to JSON...") + + for f in OUTPUT_DIR.glob("decrypt_*.bin"): + f.unlink() + + kernel32 = ctypes.WinDLL("kernel32", use_last_error=True) + kernel32.SetDllDirectoryW(DLL_DIR) + dll = ctypes.WinDLL(os.path.join(DLL_DIR, "oneocr.dll")) + + dll.CreateOcrInitOptions.argtypes = [POINTER(c_int64)] + dll.CreateOcrInitOptions.restype = c_int64 + dll.OcrInitOptionsSetUseModelDelayLoad.argtypes = [c_int64, c_ubyte] + dll.OcrInitOptionsSetUseModelDelayLoad.restype = c_int64 + dll.CreateOcrPipeline.argtypes = [c_char_p, c_char_p, c_int64, POINTER(c_int64)] + dll.CreateOcrPipeline.restype = c_int64 + + import pefile # noqa + + hooks = [ + ('bcrypt', 'BCryptOpenAlgorithmProvider', hooked_open_alg, OPEN_ALG_T), + ('bcrypt', 'BCryptSetProperty', hooked_set_prop, SET_PROP_T), + ('bcrypt', 'BCryptCreateHash', hooked_create_hash, CREATE_HASH_T), + ('bcrypt', 'BCryptHashData', hooked_hash_data, HASH_DATA_T), + ('bcrypt', 'BCryptFinishHash', hooked_finish_hash, FINISH_HASH_T), + ('bcrypt', 'BCryptGenerateSymmetricKey', hooked_gen_key, GEN_KEY_T), + ('bcrypt', 'BCryptEncrypt', hooked_encrypt, ENCRYPT_T), + ('bcrypt', 'BCryptDecrypt', hooked_decrypt, DECRYPT_T), + ] + + for target_dll, func_name, hook_func, func_type in hooks: + o = hook_iat(dll._handle, target_dll, func_name, hook_func, func_type) + if o: + orig[func_name.replace('BCrypt', '')] = o + + init_options = c_int64() + dll.CreateOcrInitOptions(byref(init_options)) + dll.OcrInitOptionsSetUseModelDelayLoad(init_options, 0) + + pipeline = c_int64() + ret = dll.CreateOcrPipeline( + ctypes.create_string_buffer(MODEL_PATH.encode()), + ctypes.create_string_buffer(KEY), + init_options, byref(pipeline) + ) + + print(f"CreateOcrPipeline: {ret}") + print(f"Total crypto ops: {len(crypto_log)}") + print(f"Decrypted chunks: {decrypt_call_num}") + + # Save crypto log + out_path = Path("temp/crypto_log.json") + out_path.parent.mkdir(exist_ok=True) + out_path.write_text(json.dumps(crypto_log, indent=2)) + print(f"Saved crypto log to {out_path}") + + +if __name__ == '__main__': + main() diff --git a/_archive/hooks/hook_hash.py b/_archive/hooks/hook_hash.py new file mode 100644 index 0000000000000000000000000000000000000000..7328bf443db21c0647b29ecd836acb17a3438d45 --- /dev/null +++ b/_archive/hooks/hook_hash.py @@ -0,0 +1,340 @@ +""" +Hook BCrypt hash functions (CreateHash, HashData, FinishHash) to discover +the key derivation scheme. Also hook GenerateSymmetricKey and BCryptDecrypt. +""" +import ctypes +from ctypes import ( + c_int64, c_char_p, c_ubyte, POINTER, byref, + c_void_p, c_ulong, WINFUNCTYPE +) +import os +import struct +from pathlib import Path + +OUTPUT_DIR = Path(r"c:\Users\MattyMroz\Desktop\PROJECTS\ONEOCR\frida_dump") +OUTPUT_DIR.mkdir(exist_ok=True) + +DLL_DIR = r"c:\Users\MattyMroz\Desktop\PROJECTS\ONEOCR\ocr_data" +MODEL_PATH = os.path.join(DLL_DIR, "oneocr.onemodel") +KEY = b'kj)TGtrK>f]b[Piow.gU+nC@s""""""4' + +# Globals +decrypt_call_num = 0 +_callback_refs = [] +key_handle_to_material = {} +hash_handle_to_data = {} # track hash data per handle +alg_handle_to_name = {} + +# ── Function types ── +DECRYPT_T = WINFUNCTYPE(c_ulong, c_void_p, c_void_p, c_ulong, c_void_p, + c_void_p, c_ulong, c_void_p, c_ulong, POINTER(c_ulong), c_ulong) +OPEN_ALG_T = WINFUNCTYPE(c_ulong, POINTER(c_void_p), c_void_p, c_void_p, c_ulong) +SET_PROP_T = WINFUNCTYPE(c_ulong, c_void_p, c_void_p, c_void_p, c_ulong, c_ulong) +GEN_KEY_T = WINFUNCTYPE(c_ulong, c_void_p, POINTER(c_void_p), c_void_p, c_ulong, + c_void_p, c_ulong, c_ulong) + +# BCryptCreateHash(hAlgorithm, phHash, pbHashObject, cbHashObject, +# pbSecret, cbSecret, dwFlags) +CREATE_HASH_T = WINFUNCTYPE(c_ulong, c_void_p, POINTER(c_void_p), c_void_p, c_ulong, + c_void_p, c_ulong, c_ulong) + +# BCryptHashData(hHash, pbInput, cbInput, dwFlags) +HASH_DATA_T = WINFUNCTYPE(c_ulong, c_void_p, c_void_p, c_ulong, c_ulong) + +# BCryptFinishHash(hHash, pbOutput, cbOutput, dwFlags) +FINISH_HASH_T = WINFUNCTYPE(c_ulong, c_void_p, c_void_p, c_ulong, c_ulong) + +# Originals +orig = {} + + +def read_wstr(ptr): + if not ptr: + return "" + try: + return ctypes.wstring_at(ptr) + except: + return "" + + +def hooked_open_alg(phAlgorithm, pszAlgId, pszImplementation, dwFlags): + alg_name = read_wstr(pszAlgId) + status = orig['OpenAlgorithmProvider'](phAlgorithm, pszAlgId, pszImplementation, dwFlags) + handle = phAlgorithm[0] if phAlgorithm else None + if handle: + h = handle.value if hasattr(handle, 'value') else handle + alg_handle_to_name[h] = alg_name + print(f"[OpenAlg] {alg_name!r} -> {status:#010x}") + return status + + +def hooked_set_prop(hObject, pszProperty, pbInput, cbInput, dwFlags): + prop_name = read_wstr(pszProperty) + value = "" + if pbInput and cbInput > 0: + raw = ctypes.string_at(pbInput, cbInput) + try: + value = raw.decode('utf-16-le').rstrip('\x00') + except: + value = raw.hex() + if cbInput == 4: + value += f" (dword={struct.unpack(' {status:#010x}") + return status + + +def hooked_create_hash(hAlgorithm, phHash, pbHashObject, cbHashObject, + pbSecret, cbSecret, dwFlags): + status = orig['CreateHash'](hAlgorithm, phHash, pbHashObject, cbHashObject, + pbSecret, cbSecret, dwFlags) + hash_handle = phHash[0] if phHash else None + + hmac_key = None + if pbSecret and cbSecret > 0: + hmac_key = ctypes.string_at(pbSecret, cbSecret) + + hh = hash_handle.value if hasattr(hash_handle, 'value') else hash_handle + ah = hAlgorithm.value if hasattr(hAlgorithm, 'value') else hAlgorithm + alg = alg_handle_to_name.get(ah, "?") + + hash_handle_to_data[hh] = { + 'alg': alg, + 'hmac_key': hmac_key, + 'data_chunks': [], + 'total_len': 0, + } + + hmac_info = "" + if hmac_key: + hmac_info = f" HMAC_KEY={hmac_key.hex()} ({hmac_key!r})" + + print(f"[CreateHash] alg={alg} hash={hh:#x}{hmac_info} -> {status:#010x}") + return status + + +def hooked_hash_data(hHash, pbInput, cbInput, dwFlags): + status = orig['HashData'](hHash, pbInput, cbInput, dwFlags) + + hh = hHash.value if hasattr(hHash, 'value') else hHash + data_bytes = None + if pbInput and cbInput > 0: + data_bytes = ctypes.string_at(pbInput, cbInput) + + if hh in hash_handle_to_data and data_bytes: + info = hash_handle_to_data[hh] + info['data_chunks'].append(data_bytes) + info['total_len'] += len(data_bytes) + + # Show data + data_hex = data_bytes.hex() if data_bytes else "" + data_ascii = "" + if data_bytes: + try: + data_ascii = data_bytes.decode('ascii', errors='replace') + except: + pass + preview = data_hex[:128] + if len(data_hex) > 128: + preview += "..." + + print(f"[HashData] hash={hh:#x} len={cbInput} data={preview}") + if data_ascii and all(32 <= c < 127 or c in (10, 13) for c in (data_bytes or b"")): + print(f" ASCII: {data_ascii!r}") + return status + + +def hooked_finish_hash(hHash, pbOutput, cbOutput, dwFlags): + status = orig['FinishHash'](hHash, pbOutput, cbOutput, dwFlags) + + hh = hHash.value if hasattr(hHash, 'value') else hHash + output = None + if pbOutput and cbOutput > 0: + output = ctypes.string_at(pbOutput, cbOutput) + + info = hash_handle_to_data.get(hh) + all_data = b"" + if info: + all_data = b"".join(info['data_chunks']) + + print(f"[FinishHash] hash={hh:#x} output_len={cbOutput}") + if output: + print(f" Result: {output.hex()}") + if info: + print(f" Input was: {info['total_len']} bytes in {len(info['data_chunks'])} chunks") + if info['total_len'] <= 256: + print(f" Full input: {all_data.hex()}") + try: + print(f" Input ASCII: {all_data!r}") + except: + pass + if info['hmac_key']: + print(f" HMAC key: {info['hmac_key'].hex()}") + + return status + + +def hooked_gen_key(hAlgorithm, phKey, pbKeyObject, cbKeyObject, + pbSecret, cbSecret, dwFlags): + secret = None + if pbSecret and cbSecret > 0: + secret = ctypes.string_at(pbSecret, cbSecret) + + status = orig['GenerateSymmetricKey'](hAlgorithm, phKey, pbKeyObject, cbKeyObject, + pbSecret, cbSecret, dwFlags) + + key_handle = phKey[0] if phKey else None + if key_handle and secret: + kh = key_handle.value if hasattr(key_handle, 'value') else key_handle + key_handle_to_material[kh] = secret + + print(f"[GenSymKey] secret_len={cbSecret} -> {status:#010x}") + if secret: + print(f" Secret: {secret.hex()}") + return status + + +def hooked_decrypt(hKey, pbInput, cbInput, pPadding, pbIV, cbIV, + pbOutput, cbOutput, pcbResult, dwFlags): + global decrypt_call_num + + iv_before = None + if pbIV and cbIV > 0: + iv_before = ctypes.string_at(pbIV, cbIV) + + status = orig['Decrypt'](hKey, pbInput, cbInput, pPadding, + pbIV, cbIV, pbOutput, cbOutput, pcbResult, dwFlags) + + result_size = pcbResult[0] if pcbResult else 0 + + # Only log actual decrypts (with IV), skip sizing calls + if cbIV > 0: + call_num = decrypt_call_num + decrypt_call_num += 1 + + kh = hKey.value if hasattr(hKey, 'value') else hKey + known_key = key_handle_to_material.get(kh) + + print(f"[Decrypt #{call_num}] in={cbInput} out={result_size} iv_len={cbIV}") + if iv_before: + print(f" IV: {iv_before.hex()}") + if known_key: + print(f" AES key: {known_key.hex()}") + + if status == 0 and result_size > 0 and pbOutput: + decrypted = ctypes.string_at(pbOutput, result_size) + print(f" Decrypted[:32]: {decrypted[:32].hex()}") + fname = OUTPUT_DIR / f"decrypt_{call_num}_in{cbInput}_out{result_size}.bin" + fname.write_bytes(decrypted) + + return status + + +def hook_iat(dll_handle, target_dll, func_name, hook_func, func_type): + import pefile + kernel32 = ctypes.windll.kernel32 + buf = ctypes.create_unicode_buffer(260) + kernel32.GetModuleFileNameW(ctypes.c_void_p(dll_handle), buf, 260) + pe = pefile.PE(buf.value) + + for entry in pe.DIRECTORY_ENTRY_IMPORT: + if target_dll.lower() not in entry.dll.decode('utf-8', errors='ignore').lower(): + continue + for imp in entry.imports: + if imp.name and imp.name.decode('utf-8', errors='ignore') == func_name: + iat_rva = imp.address - pe.OPTIONAL_HEADER.ImageBase + iat_addr = dll_handle + iat_rva + + original_ptr = ctypes.c_void_p() + ctypes.memmove(ctypes.byref(original_ptr), iat_addr, 8) + + callback = func_type(hook_func) + callback_ptr = ctypes.cast(callback, c_void_p).value + + old_protect = c_ulong() + kernel32.VirtualProtect(ctypes.c_void_p(iat_addr), 8, 0x04, byref(old_protect)) + new_ptr = ctypes.c_void_p(callback_ptr) + ctypes.memmove(iat_addr, ctypes.byref(new_ptr), 8) + kernel32.VirtualProtect(ctypes.c_void_p(iat_addr), 8, old_protect.value, byref(old_protect)) + + original_func = func_type(original_ptr.value) + pe.close() + _callback_refs.append(callback) + return original_func + + pe.close() + return None + + +def main(): + print("=" * 70) + print("BCrypt HASH HOOK - Discover SHA256 key derivation input") + print("=" * 70) + + for f in OUTPUT_DIR.glob("decrypt_*.bin"): + f.unlink() + + kernel32 = ctypes.WinDLL("kernel32", use_last_error=True) + kernel32.SetDllDirectoryW(DLL_DIR) + + dll_path = os.path.join(DLL_DIR, "oneocr.dll") + print(f"Loading: {dll_path}") + dll = ctypes.WinDLL(dll_path) + + dll.CreateOcrInitOptions.argtypes = [POINTER(c_int64)] + dll.CreateOcrInitOptions.restype = c_int64 + dll.OcrInitOptionsSetUseModelDelayLoad.argtypes = [c_int64, c_ubyte] + dll.OcrInitOptionsSetUseModelDelayLoad.restype = c_int64 + dll.CreateOcrPipeline.argtypes = [c_char_p, c_char_p, c_int64, POINTER(c_int64)] + dll.CreateOcrPipeline.restype = c_int64 + + import pefile # noqa + + hooks = [ + ('bcrypt', 'BCryptOpenAlgorithmProvider', hooked_open_alg, OPEN_ALG_T), + ('bcrypt', 'BCryptSetProperty', hooked_set_prop, SET_PROP_T), + ('bcrypt', 'BCryptCreateHash', hooked_create_hash, CREATE_HASH_T), + ('bcrypt', 'BCryptHashData', hooked_hash_data, HASH_DATA_T), + ('bcrypt', 'BCryptFinishHash', hooked_finish_hash, FINISH_HASH_T), + ('bcrypt', 'BCryptGenerateSymmetricKey', hooked_gen_key, GEN_KEY_T), + ('bcrypt', 'BCryptDecrypt', hooked_decrypt, DECRYPT_T), + ] + + print("\n--- Installing hooks ---") + for target_dll, func_name, hook_func, func_type in hooks: + o = hook_iat(dll._handle, target_dll, func_name, hook_func, func_type) + if o: + short = func_name.replace('BCrypt', '') + orig[short] = o + print(f" OK: {func_name}") + else: + print(f" FAIL: {func_name}") + + print("\n--- Creating OCR Pipeline (triggers crypto) ---") + init_options = c_int64() + dll.CreateOcrInitOptions(byref(init_options)) + dll.OcrInitOptionsSetUseModelDelayLoad(init_options, 0) + + pipeline = c_int64() + model_buf = ctypes.create_string_buffer(MODEL_PATH.encode()) + key_buf = ctypes.create_string_buffer(KEY) + + print(f"Model: {MODEL_PATH}") + print(f"Key: {KEY}") + print() + + ret = dll.CreateOcrPipeline(model_buf, key_buf, init_options, byref(pipeline)) + print(f"\nCreateOcrPipeline: {ret}") + + # Summary + print("\n" + "=" * 70) + print("KEY DERIVATION SUMMARY") + print("=" * 70) + print(f"Unique derived keys: {len(key_handle_to_material)}") + print(f"Hash operations tracked: {len(hash_handle_to_data)}") + print(f"Decrypted chunks: {decrypt_call_num}") + print("\nDone!") + + +if __name__ == '__main__': + main() diff --git a/_archive/inspect_config_blob.py b/_archive/inspect_config_blob.py new file mode 100644 index 0000000000000000000000000000000000000000..c8b333551433e40a2a4dc362e3d2e53074e1fae7 --- /dev/null +++ b/_archive/inspect_config_blob.py @@ -0,0 +1,80 @@ +"""Deep-dive into model_11 and model_22 graph structure — handle binary config.""" +import onnx +import numpy as np +from pathlib import Path + +models_dir = Path("oneocr_extracted/onnx_models") + +for idx in [11, 22]: + matches = list(models_dir.glob(f"model_{idx:02d}_*")) + model = onnx.load(str(matches[0])) + + print(f"\n{'='*70}") + print(f"FULL GRAPH: model_{idx:02d}") + print(f"{'='*70}") + + # All initializers (weights) + print(f"\n Initializers ({len(model.graph.initializer)}):") + for init in model.graph.initializer: + if init.data_type == 8: # STRING + raw = init.string_data[0] if init.string_data else init.raw_data + print(f" {init.name}: STRING, {len(raw)} bytes (binary)") + else: + data = onnx.numpy_helper.to_array(init) + print(f" {init.name}: shape={data.shape}, dtype={data.dtype}, " + f"range=[{data.min():.4f}, {data.max():.4f}]") + + # All nodes + print(f"\n Nodes ({len(model.graph.node)}):") + for i, node in enumerate(model.graph.node): + domain_str = f" [{node.domain}]" if node.domain else "" + print(f" [{i}] {node.op_type}{domain_str}: {list(node.input)} → {list(node.output)}") + for attr in node.attribute: + if attr.type == 2: + print(f" {attr.name} = {attr.i}") + elif attr.type == 1: + print(f" {attr.name} = {attr.f}") + elif attr.type == 7: + print(f" {attr.name} = {list(attr.ints)}") + + # Analyze feature/config blob + for init in model.graph.initializer: + if "config" in init.name.lower(): + raw = init.string_data[0] if init.string_data else init.raw_data + blob = bytes(raw) + print(f"\n ── feature/config analysis ──") + print(f" Total bytes: {len(blob)}") + print(f" First 32 bytes hex: {blob[:32].hex()}") + + # Hypothesis: header + weight_matrix(input_dim × output_dim) + bias(output_dim) + # If input=21, output=50: 21*50=1050 floats = 4200 bytes, bias=50 floats = 200 bytes + # Total weights = 4400 bytes, header = 4492-4400 = 92 bytes + + # Try reading first few uint32 as header + header_u32 = [int.from_bytes(blob[i:i+4], 'little') for i in range(0, min(96, len(blob)), 4)] + print(f" First 24 uint32 LE values: {header_u32}") + + # Try float32 interpretation after various offsets + for offset in [0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92]: + remaining = len(blob) - offset + n_floats = remaining // 4 + if n_floats == 0: + continue + arr = np.frombuffer(blob[offset:offset + n_floats*4], dtype=np.float32) + valid = np.isfinite(arr).sum() + reasonable = np.sum((np.abs(arr) < 10) & np.isfinite(arr)) + if reasonable > n_floats * 0.7: # >70% reasonable values + print(f" *** offset={offset}: {n_floats} floats, {valid} finite, " + f"{reasonable} in [-10,10] ({100*reasonable/n_floats:.0f}%)") + print(f" First 10: {arr[:10]}") + print(f" Stats: mean={arr.mean():.4f}, std={arr.std():.4f}") + # Check if it could be weight matrix 21×50 + if n_floats >= 1050 + 50: + W = arr[:1050].reshape(21, 50) + b = arr[1050:1100] + print(f" As 21×50 weight: W_range=[{W.min():.4f},{W.max():.4f}], " + f"b_range=[{b.min():.4f},{b.max():.4f}]") + # Test with random input + x = np.random.randn(1, 21).astype(np.float32) + y = x @ W + b + print(f" Test: input(21) → output(50), y_range=[{y.min():.4f},{y.max():.4f}]") diff --git a/_archive/inspect_custom_ops.py b/_archive/inspect_custom_ops.py new file mode 100644 index 0000000000000000000000000000000000000000..7565d5829450e3b12df557e955bfa0ed18bef6f2 --- /dev/null +++ b/_archive/inspect_custom_ops.py @@ -0,0 +1,39 @@ +"""Inspect custom ops in models 11, 12, 22, 33 to determine exact op names and domains.""" +import onnx +from pathlib import Path + +models_dir = Path("oneocr_extracted/onnx_models") + +for idx in [11, 12, 22, 33]: + matches = list(models_dir.glob(f"model_{idx:02d}_*")) + if not matches: + print(f"model_{idx:02d}: NOT FOUND") + continue + + model = onnx.load(str(matches[0])) + print(f"\n{'='*60}") + print(f"model_{idx:02d}: {matches[0].name}") + print(f" IR version: {model.ir_version}") + print(f" Opset imports: {[(o.domain, o.version) for o in model.opset_import]}") + + # Find all non-standard ops + for node in model.graph.node: + if node.domain and node.domain != "": + print(f" Node: op_type={node.op_type!r}, domain={node.domain!r}") + print(f" inputs: {list(node.input)}") + print(f" outputs: {list(node.output)}") + # Print attributes + for attr in node.attribute: + if attr.type == 2: # INT + print(f" attr {attr.name} = {attr.i}") + elif attr.type == 1: # FLOAT + print(f" attr {attr.name} = {attr.f}") + elif attr.type == 3: # STRING + print(f" attr {attr.name} = {attr.s.decode()!r}") + elif attr.type == 4: # TENSOR + t = attr.t + print(f" attr {attr.name} = tensor(dtype={t.data_type}, dims={list(t.dims)}, raw_bytes={len(t.raw_data)})") + + # Also show graph inputs/outputs + print(f" Graph inputs: {[(i.name, [d.dim_value or d.dim_param for d in i.type.tensor_type.shape.dim]) for i in model.graph.input]}") + print(f" Graph outputs: {[(o.name, [d.dim_value or d.dim_param for d in o.type.tensor_type.shape.dim]) for o in model.graph.output]}") diff --git a/_archive/inspect_graph_deep.py b/_archive/inspect_graph_deep.py new file mode 100644 index 0000000000000000000000000000000000000000..f1222063cf5c6202153e92969d3556ea4d1888bf --- /dev/null +++ b/_archive/inspect_graph_deep.py @@ -0,0 +1,60 @@ +"""Deep-dive into model_11 and model_22 graph structure to understand OneOCRFeatureExtract.""" +import onnx +import numpy as np +from pathlib import Path + +models_dir = Path("oneocr_extracted/onnx_models") + +for idx in [11, 22]: + matches = list(models_dir.glob(f"model_{idx:02d}_*")) + model = onnx.load(str(matches[0])) + + print(f"\n{'='*70}") + print(f"FULL GRAPH: model_{idx:02d}") + print(f"{'='*70}") + + # All initializers (weights) + print(f"\n Initializers ({len(model.graph.initializer)}):") + for init in model.graph.initializer: + data = onnx.numpy_helper.to_array(init) + print(f" {init.name}: shape={data.shape}, dtype={data.dtype}, " + f"range=[{data.min():.4f}, {data.max():.4f}]") + + # All nodes + print(f"\n Nodes ({len(model.graph.node)}):") + for i, node in enumerate(model.graph.node): + domain_str = f" (domain={node.domain!r})" if node.domain else "" + print(f" [{i}] {node.op_type}{domain_str}") + print(f" in: {list(node.input)}") + print(f" out: {list(node.output)}") + for attr in node.attribute: + if attr.type == 2: # INT + print(f" {attr.name} = {attr.i}") + elif attr.type == 1: # FLOAT + print(f" {attr.name} = {attr.f}") + elif attr.type == 3: # STRING + val = attr.s + if len(val) > 100: + print(f" {attr.name} = bytes({len(val)})") + else: + print(f" {attr.name} = {val!r}") + elif attr.type == 4: # TENSOR + t = attr.t + print(f" {attr.name} = tensor(dtype={t.data_type}, dims={list(t.dims)}, " + f"raw_bytes={len(t.raw_data)})") + elif attr.type == 7: # INTS + print(f" {attr.name} = {list(attr.ints)}") + elif attr.type == 6: # FLOATS + print(f" {attr.name} = {list(attr.floats)[:10]}...") + + # Show feature/config initializer details + for init in model.graph.initializer: + if "config" in init.name.lower() or "feature" in init.name.lower(): + raw = init.raw_data + print(f"\n feature/config blob: {len(raw)} bytes") + print(f" First 64 bytes (hex): {raw[:64].hex()}") + print(f" Last 32 bytes (hex): {raw[-32:].hex()}") + # Try to interpret structure + # Check if starts with dimension info + print(f" As uint32 first 8 values: {[int.from_bytes(raw[i:i+4], 'little') for i in range(0, 32, 4)]}") + print(f" As float32 first 8 values: {list(np.frombuffer(raw[:32], dtype=np.float32))}") diff --git a/_archive/inspect_model33.py b/_archive/inspect_model33.py new file mode 100644 index 0000000000000000000000000000000000000000..53ee2a41b6c82ae7c5791983cead80ae6593e325 --- /dev/null +++ b/_archive/inspect_model33.py @@ -0,0 +1,89 @@ +"""Deep analysis of model_33 (LineLayout) to understand its OneOCRFeatureExtract usage.""" +import onnx +from onnx import numpy_helper +import numpy as np +from pathlib import Path + +models_dir = Path("oneocr_extracted/onnx_models") +model_path = list(models_dir.glob("model_33_*"))[0] +model = onnx.load(str(model_path)) + +print(f"Model: {model_path.name}") +print(f"IR version: {model.ir_version}") +print(f"Opsets: {[(o.domain, o.version) for o in model.opset_import]}") + +# Show all inputs/outputs +print(f"\nGraph inputs:") +for inp in model.graph.input: + shape = [d.dim_value or d.dim_param for d in inp.type.tensor_type.shape.dim] + print(f" {inp.name}: {shape}") + +print(f"\nGraph outputs:") +for out in model.graph.output: + shape = [d.dim_value or d.dim_param for d in out.type.tensor_type.shape.dim] + print(f" {out.name}: {shape}") + +# All initializers +print(f"\nInitializers ({len(model.graph.initializer)}):") +for init in model.graph.initializer: + if init.data_type == 8: # STRING + raw = bytes(init.string_data[0] if init.string_data else init.raw_data) + print(f" {init.name}: STRING, {len(raw)} bytes") + else: + data = numpy_helper.to_array(init) + print(f" {init.name}: {data.shape} {data.dtype} [{data.min():.4f}, {data.max():.4f}]") + +# Find the OneOCRFeatureExtract node and its context +print(f"\nNodes ({len(model.graph.node)}):") +fe_found = False +for i, node in enumerate(model.graph.node): + if node.op_type == "OneOCRFeatureExtract" or fe_found: + domain_str = f" [{node.domain}]" if node.domain else "" + print(f" [{i}] {node.op_type}{domain_str}: {list(node.input)} → {list(node.output)}") + if node.op_type == "OneOCRFeatureExtract": + fe_found = True + for attr in node.attribute: + if attr.type == 2: + print(f" {attr.name} = {attr.i}") + elif attr.type == 1: + print(f" {attr.name} = {attr.f}") + elif attr.type == 7: + print(f" {attr.name} = {list(attr.ints)}") + elif i < 5 or (i > len(model.graph.node) - 5): + # Show first/last few nodes for context + domain_str = f" [{node.domain}]" if node.domain else "" + print(f" [{i}] {node.op_type}{domain_str}: {list(node.input)} → {list(node.output)}") + +# Show nodes BEFORE OneOCRFeatureExtract (the conv backbone) +print(f"\nConv backbone structure (last 5 nodes before FE):") +fe_idx = None +for i, node in enumerate(model.graph.node): + if node.op_type == "OneOCRFeatureExtract": + fe_idx = i + break + +if fe_idx: + for i in range(max(0, fe_idx - 5), fe_idx + 1): + node = model.graph.node[i] + domain_str = f" [{node.domain}]" if node.domain else "" + print(f" [{i}] {node.op_type}{domain_str}: {list(node.input)} → {list(node.output)}") + +# Analyze the feature/config blob +for init in model.graph.initializer: + if init.name == "feature/config": + raw = bytes(init.string_data[0] if init.string_data else init.raw_data) + print(f"\nfeature/config blob: {len(raw)} bytes") + + # Try big-endian float32 + be = np.frombuffer(raw, dtype='>f4').copy() + print(f" Big-endian float32: {len(be)} values") + print(f" Finite: {np.isfinite(be).sum()}") + in_range = np.sum(np.abs(be[np.isfinite(be)]) < 10) + print(f" In [-10,10]: {in_range} ({100*in_range/len(be):.1f}%)") + print(f" First 20: {be[:20]}") + print(f" Last 20: {be[-20:]}") + + # Try to find dimension markers + for i, v in enumerate(be): + if v in [128.0, 256.0, 512.0] or (v > 0 and v == int(v) and 10 < v < 10000): + print(f" Potential dim at [{i}]: {v}") diff --git a/_archive/inspect_models.py b/_archive/inspect_models.py new file mode 100644 index 0000000000000000000000000000000000000000..a4beb3f7b14d2d8310bb8f4d7fac2ceb6a90d9f1 --- /dev/null +++ b/_archive/inspect_models.py @@ -0,0 +1,55 @@ +"""Quick inspection of specific ONNX models.""" +import onnx +from pathlib import Path + +for idx in [11, 12, 22, 33]: + matches = list(Path('oneocr_extracted/onnx_models').glob(f'model_{idx:02d}_*')) + if not matches: + continue + m = onnx.load(str(matches[0])) + print(f'\n=== model_{idx:02d} ({matches[0].name}) ===') + print('Opsets:', [(o.domain, o.version) for o in m.opset_import]) + custom_ops = set() + for n in m.graph.node: + if n.domain: + custom_ops.add((n.domain, n.op_type)) + print('Custom ops:', list(custom_ops)) + for i in m.graph.input: + dims = [] + if i.type.tensor_type.HasField('shape'): + for d in i.type.tensor_type.shape.dim: + v = str(d.dim_value) if d.dim_value else (d.dim_param or '?') + dims.append(v) + etype = i.type.tensor_type.elem_type + print(f' Input: {i.name} shape=[{", ".join(dims)}] dtype={etype}') + for o in m.graph.output: + dims = [] + if o.type.tensor_type.HasField('shape'): + for d in o.type.tensor_type.shape.dim: + v = str(d.dim_value) if d.dim_value else (d.dim_param or '?') + dims.append(v) + etype = o.type.tensor_type.elem_type + print(f' Output: {o.name} shape=[{", ".join(dims)}] dtype={etype}') + cnt = {} + for n in m.graph.node: + key = f'{n.domain}::{n.op_type}' if n.domain else n.op_type + cnt[key] = cnt.get(key, 0) + 1 + print(' Nodes:', dict(cnt)) + + # Show attributes for custom ops + for n in m.graph.node: + if n.domain: + attrs = {a.name: a for a in n.attribute} + attr_summary = {} + for k, a in attrs.items(): + if a.type == 2: # FLOAT + attr_summary[k] = a.f + elif a.type == 1: # INT + attr_summary[k] = a.i + elif a.type == 3: # STRING + attr_summary[k] = a.s.decode() + print(f' CustomOp {n.op_type} attrs: {attr_summary}') + # Show input/output names + print(f' inputs: {list(n.input)}') + print(f' outputs: {list(n.output)}') + break # just show first custom op diff --git a/_archive/onemodel_decrypt.py b/_archive/onemodel_decrypt.py new file mode 100644 index 0000000000000000000000000000000000000000..ca34c778063ed6cdad340409c3a5d565baae951f --- /dev/null +++ b/_archive/onemodel_decrypt.py @@ -0,0 +1,424 @@ +#!/usr/bin/env python3 +""" +OneOCR .onemodel Static Decryptor +================================= +Cross-platform tool to extract ONNX models and config data from +Windows OneOCR's encrypted .onemodel container files. + +No Windows APIs, DLLs, or runtime hooking required. +Only dependency: pycryptodome (pip install pycryptodome) + +Crypto scheme (fully reverse-engineered): + - Algorithm: AES-256-CFB128 + - Master Key: hardcoded 32-byte ASCII string + - IV: "Copyright @ OneO" (16 bytes, same for all chunks) + - DX index key: SHA256(master_key + file[8:24]) + - Config key: SHA256(DX[48:64] + DX[32:48]) (sizes + checksum) + - Per-chunk key: SHA256(chunk_header[16:32] + chunk_header[0:16]) + - Chunk header in file: checksum(16) + size1(8) + size2(8) = 32 bytes + - On-disk encrypted data follows immediately: size1 + 8 bytes + +File structure: + [0:8] uint64 LE H (header value) + [8:24] 16 bytes file_hash (used in DX key derivation) + [24:H+12] encrypted DX index + [H+12:H+16] 4 zero bytes (gap) + [H+16:] payload chunks (checksum(16) + sizes(16) + encrypted_data) + +Usage: + python onemodel_decrypt.py [onemodel_file] [output_dir] + python onemodel_decrypt.py # uses defaults +""" + +import struct +import hashlib +import sys +import os +from pathlib import Path + +try: + from Crypto.Cipher import AES +except ImportError: + print("ERROR: pycryptodome is required. Install with: pip install pycryptodome") + sys.exit(1) + +# ─── Constants ─────────────────────────────────────────────────────────────── +MASTER_KEY = b'kj)TGtrK>f]b[Piow.gU+nC@s""""""4' +IV = b"Copyright @ OneO" +CONTAINER_MAGIC = bytes.fromhex("4a1a082b25000000") + + +# ─── Crypto ────────────────────────────────────────────────────────────────── +def aes_cfb128_decrypt(key: bytes, data: bytes) -> bytes: + """Decrypt data with AES-256-CFB128 using the global IV.""" + cipher = AES.new(key, AES.MODE_CFB, iv=IV, segment_size=128) + return cipher.decrypt(data) + + +def derive_key(sha256_input: bytes) -> bytes: + """Derive AES key via SHA256.""" + return hashlib.sha256(sha256_input).digest() + + +# ─── Protobuf helpers (for ONNX size measurement) ─────────────────────────── +def read_varint(data: bytes, pos: int) -> tuple[int, int]: + """Read protobuf varint, return (value, new_pos).""" + val = 0 + shift = 0 + while pos < len(data): + b = data[pos] + pos += 1 + val |= (b & 0x7F) << shift + if not (b & 0x80): + break + shift += 7 + return val, pos + + +def measure_protobuf(data: bytes) -> int: + """Walk ONNX ModelProto protobuf fields; return byte length of valid data. + Valid fields for ONNX ModelProto: 1-9, 14, 20.""" + VALID_FIELDS = {1, 2, 3, 4, 5, 6, 7, 8, 9, 14, 20} + pos = 0 + while pos < len(data): + start = pos + tag, pos = read_varint(data, pos) + if pos > len(data): + return start + field_num = tag >> 3 + wire_type = tag & 7 + + if field_num not in VALID_FIELDS: + return start + + if wire_type == 0: # varint + _, pos = read_varint(data, pos) + elif wire_type == 1: # 64-bit + pos += 8 + elif wire_type == 2: # length-delimited + length, pos = read_varint(data, pos) + pos += length + elif wire_type == 5: # 32-bit + pos += 4 + else: + return start + + if pos > len(data): + return start + return pos + + +# ─── File parsing ──────────────────────────────────────────────────────────── +class OneModelFile: + """Parser for .onemodel encrypted containers.""" + + def __init__(self, filepath: str): + with open(filepath, "rb") as f: + self.data = f.read() + self.filepath = filepath + + # Parse file header + self.H = struct.unpack_from(" bytes: + """Decrypt the DX index.""" + key = derive_key(MASTER_KEY + self.file_hash) + dx_enc = self.data[self.dx_offset : self.dx_offset + self.dx_size] + return aes_cfb128_decrypt(key, dx_enc) + + def decrypt_config(self, dx: bytes) -> bytes: + """Decrypt the config chunk embedded in DX.""" + sha_input = dx[48:64] + dx[32:48] # sizes + checksum + key = derive_key(sha_input) + config_s1 = struct.unpack_from(" len(self.data): + break + + enc_size = s1 + 8 + data_off = off + 32 + + if data_off + enc_size > len(self.data): + break + + # Derive per-chunk AES key: SHA256(sizes + checksum) + sha_input = self.data[off + 16 : off + 32] + checksum + key = derive_key(sha_input) + + # Decrypt + dec = aes_cfb128_decrypt(key, self.data[data_off : data_off + enc_size]) + + # Validate container magic + if dec[:8] != CONTAINER_MAGIC: + print(f" WARNING: chunk#{idx} container magic mismatch!") + + # Strip 8-byte container header + payload = dec[8:] + + meta = { + "index": idx, + "file_offset": off, + "size1": s1, + "size2": s2, + "checksum": checksum.hex(), + } + + yield idx, meta, payload + + off = data_off + enc_size + idx += 1 + + +# ─── ONNX extraction ──────────────────────────────────────────────────────── +def classify_chunk(payload: bytes) -> str: + """Classify a decrypted chunk payload.""" + if len(payload) > 100 and payload[0] == 0x08 and payload[1] in (0x06, 0x07): + return "onnx" + + # Check for text content + try: + sample = payload[:100].decode("ascii") + if all(c.isprintable() or c in "\n\r\t" for c in sample): + if "" in sample: + return "rnn_info" + elif sample.startswith("! ") or sample.startswith('" '): + if any(c.isdigit() for c in sample[:20]): + return "char2ind" + else: + return "char2inschar" + elif sample.startswith("0."): + return "score_calibration" + elif "text_script" in sample: + return "ocr_config" + elif "//" in sample[:5]: + return "composite_chars" + return "text_data" + except (UnicodeDecodeError, ValueError): + pass + + return "binary_data" + + +def get_onnx_info(data: bytes) -> dict: + """Get basic ONNX model info from raw protobuf bytes.""" + info = {} + pos = 0 + while pos < min(len(data), 500): + tag, pos = read_varint(data, pos) + field_num = tag >> 3 + wire_type = tag & 7 + + if wire_type == 0: + val, pos = read_varint(data, pos) + if field_num == 1: + info["ir_version"] = val + elif wire_type == 2: + length, pos = read_varint(data, pos) + payload_bytes = data[pos : pos + length] + if field_num == 3: + try: + info["producer"] = payload_bytes.decode("utf-8") + except: + pass + elif field_num == 4: + try: + info["producer_version"] = payload_bytes.decode("utf-8") + except: + pass + pos += length + elif wire_type == 5: + pos += 4 + elif wire_type == 1: + pos += 8 + else: + break + + if "producer" in info and "ir_version" in info: + break + + return info + + +def extract_all(input_file: str, output_dir: str, verify: bool = True): + """Extract all content from a .onemodel file.""" + model_file = OneModelFile(input_file) + + print(f"File: {input_file}") + print(f"Size: {len(model_file.data):,} bytes") + print(f"Header value: {model_file.H}") + print(f"DX size: {model_file.dx_size:,} bytes") + + # Decrypt DX + dx = model_file.decrypt_dx() + valid_size = struct.unpack_from("4} {'Type':<18} {'Size':>12} {'Filename':<40}") + print(f"{'='*70}") + + for idx, meta, payload in model_file.iter_payload_chunks(): + chunk_type = classify_chunk(payload) + + if chunk_type == "onnx": + # Trim ONNX to exact protobuf boundary + exact_size = measure_protobuf(payload) + onnx_data = payload[:exact_size] + + info = get_onnx_info(onnx_data) + ir = info.get("ir_version", "?") + producer = info.get("producer", "unknown") + size_kb = len(onnx_data) // 1024 + + # Generate filename + if "quantize" in producer.lower() or "onnx" in producer.lower(): + prod_tag = "onnx_quantize" + elif "pytorch" in producer.lower() or "torch" in producer.lower(): + if size_kb < 50: + prod_tag = "pytorch_small" + else: + prod_tag = "pytorch" + else: + prod_tag = producer.replace(" ", "_") + + onnx_idx = len(onnx_models) + fname = f"model_{onnx_idx:02d}_ir{ir}_{prod_tag}_{size_kb}KB.onnx" + fpath = onnx_dir / fname + + fpath.write_bytes(onnx_data) + onnx_models.append(fpath) + print(f"{idx:4d} {'ONNX':18s} {len(onnx_data):12,} {fname}") + + else: + # Config/text file + ext_map = { + "rnn_info": ".rnn_info", + "char2ind": ".char2ind.txt", + "char2inschar": ".char2inschar.txt", + "score_calibration": ".calibration.txt", + "ocr_config": ".config.txt", + "composite_chars": ".composite.txt", + "text_data": ".txt", + "binary_data": ".bin", + } + ext = ext_map.get(chunk_type, ".bin") + fname = f"chunk_{idx:02d}_{chunk_type}{ext}" + fpath = config_dir / fname + + fpath.write_bytes(payload) + config_files.append(fpath) + print(f"{idx:4d} {chunk_type:18s} {len(payload):12,} {fname}") + + print(f"\n{'='*70}") + print(f"ONNX models extracted: {len(onnx_models)}") + print(f"Config files extracted: {len(config_files)}") + + # Verify ONNX models + if verify: + print(f"\n{'='*70}") + print("ONNX Verification") + print(f"{'='*70}") + + try: + import onnx + onnx_ok = 0 + onnx_fail = 0 + for fpath in onnx_models: + try: + model = onnx.load(str(fpath)) + onnx.checker.check_model(model) + onnx_ok += 1 + print(f" OK {fpath.name}") + except Exception as e: + try: + # Try just loading without full check + model = onnx.load(str(fpath)) + onnx_ok += 1 + print(f" OK* {fpath.name} (loads but checker warning: {str(e)[:50]})") + except Exception as e2: + onnx_fail += 1 + print(f" FAIL {fpath.name}: {e2}") + print(f"\nVerification: {onnx_ok}/{len(onnx_models)} models load successfully") + except ImportError: + print(" (onnx package not installed, skipping verification)") + + try: + import onnxruntime as ort + rt_ok = 0 + rt_custom_ops = 0 + for fpath in onnx_models: + try: + sess = ort.InferenceSession(str(fpath)) + rt_ok += 1 + except Exception as e: + if "custom ops" in str(e).lower() or "oneocr" in str(e).lower(): + rt_custom_ops += 1 + else: + pass # Other runtime errors + print(f" onnxruntime: {rt_ok} standard, {rt_custom_ops} need custom ops") + except ImportError: + pass + + print(f"\nDone! All files saved to: {out.resolve()}") + + +# ─── Main ──────────────────────────────────────────────────────────────────── +if __name__ == "__main__": + default_input = "ocr_data/oneocr.onemodel" + default_output = "oneocr_extracted" + + input_file = sys.argv[1] if len(sys.argv) > 1 else default_input + output_dir = sys.argv[2] if len(sys.argv) > 2 else default_output + + if not os.path.exists(input_file): + print(f"ERROR: Input file not found: {input_file}") + sys.exit(1) + + extract_all(input_file, output_dir) diff --git a/_archive/profiles.py b/_archive/profiles.py new file mode 100644 index 0000000000000000000000000000000000000000..6cfe3a896aca2efee623c610aabf44388282a1a5 --- /dev/null +++ b/_archive/profiles.py @@ -0,0 +1,212 @@ +"""Capture profile management — save/load screen region coordinates per game. + +Profiles are stored as JSON files in working_space/temp/profiles/. +Each profile holds a name, regions, and a flat settings dict with ALL UI state. + +Usage: + from src.services.ocr.profiles import ProfileManager, CaptureProfile, CaptureRegion + + mgr = ProfileManager() + profile = CaptureProfile( + name="Elden Ring", + regions=[CaptureRegion(x=100, y=900, width=800, height=200, label="subtitles")], + settings={"target_lang": "pl", "tts_engine": "edge", "tts_voice": "pl-PL-ZofiaNeural"}, + ) + mgr.save_profile(profile) + loaded = mgr.load_profile("Elden Ring") +""" + +from __future__ import annotations + +import base64 +import json +import re +from dataclasses import asdict, dataclass, field +from datetime import datetime +from pathlib import Path +from typing import Any + +from src.utils.logger import logger + +_PROFILES_DIR = ( + Path(__file__).resolve().parent.parent.parent.parent + / "working_space" + / "temp" + / "profiles" +) + + +@dataclass +class CaptureRegion: + """A single screen capture region (rectangle).""" + + x: int + y: int + width: int + height: int + label: str = "default" + enabled: bool = True + + @property + def as_tuple(self) -> tuple[int, int, int, int]: + return (self.x, self.y, self.width, self.height) + + def __str__(self) -> str: + return f"{self.label}: ({self.x}, {self.y}, {self.width}x{self.height})" + + +@dataclass +class CaptureProfile: + """A named capture profile. + + Attributes: + name: Profile display name (also used to derive filename). + regions: List of capture regions. + settings: Flat dict holding **every** UI setting + (target_lang, tts_engine, tts_voice, capture_interval, …). + created_at: ISO timestamp of creation. + updated_at: ISO timestamp of last update. + """ + + name: str + regions: list[CaptureRegion] = field(default_factory=list) + settings: dict[str, Any] = field(default_factory=dict) + created_at: str = "" + updated_at: str = "" + + def __post_init__(self) -> None: + now = datetime.now().isoformat() + if not self.created_at: + self.created_at = now + if not self.updated_at: + self.updated_at = now + + # ── serialization ──────────────────────────────────────────── + + def to_dict(self) -> dict[str, Any]: + return { + "name": self.name, + "regions": [asdict(r) for r in self.regions], + "settings": self.settings, + "created_at": self.created_at, + "updated_at": self.updated_at, + } + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> CaptureProfile: + regions = [CaptureRegion(**r) for r in data.get("regions", [])] + settings = data.get("settings", {}) + + # ── backward compat: migrate old flat fields into settings ── + _old_keys = { + "source_lang", "target_lang", "capture_mode", "monitor_index", + "interval", "tts_backend", "tts_voice", "description", + } + for key in _old_keys: + if key in data and key not in settings: + settings[key] = data[key] + + return cls( + name=data.get("name", ""), + regions=regions, + settings=settings, + created_at=data.get("created_at", ""), + updated_at=data.get("updated_at", ""), + ) + + @property + def active_regions(self) -> list[CaptureRegion]: + return [r for r in self.regions if r.enabled] + + +class ProfileManager: + """Manage capture profiles (save/load/list/delete).""" + + def __init__(self, profiles_dir: str | Path | None = None) -> None: + self._dir = Path(profiles_dir) if profiles_dir else _PROFILES_DIR + self._dir.mkdir(parents=True, exist_ok=True) + + # ── CRUD ───────────────────────────────────────────────────── + + def save_profile(self, profile: CaptureProfile) -> Path: + """Save profile to JSON file.""" + profile.updated_at = datetime.now().isoformat() + filepath = self._dir / (self._sanitize_filename(profile.name) + ".json") + filepath.write_text( + json.dumps(profile.to_dict(), indent=2, ensure_ascii=False), + encoding="utf-8", + ) + logger.info(f"Profile saved: {profile.name} → {filepath}") + return filepath + + def load_profile(self, name: str) -> CaptureProfile | None: + """Load profile by name.""" + filepath = self._find_profile_file(name) + if filepath is None: + logger.warning(f"Profile not found: {name}") + return None + try: + data = json.loads(filepath.read_text(encoding="utf-8")) + return CaptureProfile.from_dict(data) + except Exception as e: + logger.error(f"Failed to load profile {name}: {e}") + return None + + def list_profiles(self) -> list[str]: + """List all saved profile names.""" + profiles: list[str] = [] + for f in sorted(self._dir.glob("*.json")): + try: + encoded = f.stem + padding = (4 - len(encoded) % 4) % 4 + name = base64.urlsafe_b64decode(encoded + "=" * padding).decode("utf-8") + profiles.append(name) + except Exception: + profiles.append(f.stem) + return profiles + + def delete_profile(self, name: str) -> bool: + """Delete a profile by name.""" + filepath = self._find_profile_file(name) + if filepath and filepath.exists(): + filepath.unlink() + logger.info(f"Profile deleted: {name}") + return True + return False + + def update_profile_settings(self, name: str, settings: dict[str, Any]) -> bool: + """Merge *settings* into an existing profile and re-save.""" + profile = self.load_profile(name) + if profile is None: + return False + profile.settings.update(settings) + self.save_profile(profile) + return True + + def update_profile_regions(self, name: str, regions: list[dict[str, Any]]) -> bool: + """Replace regions in an existing profile and re-save.""" + profile = self.load_profile(name) + if profile is None: + return False + profile.regions = [CaptureRegion(**r) for r in regions] + self.save_profile(profile) + return True + + # ── helpers ─────────────────────────────────────────────────── + + def _find_profile_file(self, name: str) -> Path | None: + # Try new base64 encoding first + filepath = self._dir / (self._sanitize_filename(name) + ".json") + if filepath.exists(): + return filepath + # Try old simple sanitization for backward compatibility + old = re.sub(r'[<>:"/\\|?*]', "_", name.strip()).rstrip(".") + ".json" + old_path = self._dir / old + if old_path.exists(): + return old_path + return None + + @staticmethod + def _sanitize_filename(name: str) -> str: + """Base64url encode the profile name so case is preserved on NTFS.""" + return base64.urlsafe_b64encode(name.strip().encode("utf-8")).decode("ascii").rstrip("=") diff --git a/_archive/proprompt.md b/_archive/proprompt.md new file mode 100644 index 0000000000000000000000000000000000000000..8b510939d1e5031d243b4b3327735d8c27d433ed --- /dev/null +++ b/_archive/proprompt.md @@ -0,0 +1,594 @@ +# ⚡ Skill: Brainstorm + +> **Kategoria:** analysis | **Trudność:** advanced +> **Tokens:** ~2500 | **Model:** any (zalecany: Claude / GPT-4+) +> **Wersja:** 1.0.0 | **Utworzono:** 2026-02-10 +> **Komendy aktywacyjne:** `mały brainstorm` | `duży brainstorm` + +--- + +## Kiedy używać + +Gdy potrzebujesz **dogłębnie przemyśleć** problem, pomysł, decyzję, strategię lub architekturę — zamiast od razu działać. Brainstorm to faza deliberatywna przed fazą wykonawczą. + +--- + +## Tryby + +| Tryb | Komenda | Długość outputu | Zastosowanie | +|------|---------|----------------|--------------| +| 🟢 Mały | `mały brainstorm` | ~500 linii (~2-4 stron A4) | Szybkie przemyślenie tematu, decyzja, pros/cons | +| 🔴 Duży | `duży brainstorm` | ~1000-2000 linii (~6-15 stron A4) | Głębokie planowanie, architektura, strategia, multi-dimensional analysis | + +--- + +## Rola (System Prompt) + + +Jesteś **Strategic Brainstorm Architect** — ekspert od deliberatywnego myślenia, analizy wielowymiarowej i systematycznej ewaluacji pomysłów. Łączysz techniki **Chain-of-Thought** (krokowe rozumowanie), **Tree-of-Thought** (rozgałęziona eksploracja z backtrackingiem) oraz **kreatywną dywergencję** (generowanie nieoczywistych rozwiązań). + +**Twoja misja:** Nie odpowiadaj od razu — **MYŚL GŁĘBOKO**, eksploruj przestrzeń rozwiązań, oceniaj, eliminuj, syntetyzuj. Brainstorm to Twoja arena, a rezultatem jest treść, której user nie wygeneruje sam. + +**Kompetencje kluczowe:** +- Wielowymiarowa analiza problemów (techniczne, biznesowe, ludzkie, czasowe) +- Generowanie 5-15+ rozwiązań/podejść na każdy problem (dywergencja) +- Krytyczna ewaluacja z użyciem skal, matryc i metryk (konwergencja) +- Eksploracja repozytorium i kontekstu projektu nim zaczniesz myśleć +- Identyfikacja ukrytych ryzyk, zależności i efektów drugiego rzędu +- Synteza: wybór najlepszej opcji z jasnym uzasadnieniem "dlaczego" + +**Zasady pracy:** +- 🔍 **Kontekst first** — ZANIM zaczniesz brainstorm: przeskanuj repozytorium, przeczytaj README, zrozum co user buduje, zbierz kontekst, czasem użuj narzędzia do ankiety i zapytaj usera +- 🌐 **Szukaj w sieci** — jeśli masz dostęp do wyszukiwania, UŻYWAJ GO aktywnie. Sprawdzaj trendy, best practices, istniejące rozwiązania, benchmarki +- 🧠 **Self-prompting** — zadawaj SOBIE pytania pomocnicze w trakcie myślenia: "Czego jeszcze nie rozważyłem?", "Jakie jest drugie dno?", "Co by powiedział ekspert od X?" +- 🎨 **Uwolnij kreatywność** — generuj też rozwiązania niestandardowe, śmiałe, eksperymentalne — nawet jeśli ryzykowne +- 📏 **Tablica prawdy** — wyznaczone przez usera ŚWIĘTE ZASADY (constraints) są ABSOLUTNE — nigdy ich nie łam +- ⭐ **Oceniaj wszystko** — każde rozwiązanie/pomysł dostaje ocenę gwiazdkową 1-10 +- 🔄 **Iteruj** — wracaj do wcześniejszych pomysłów w świetle nowych odkryć (backtracking ToT) + + +--- + +## Instrukcje + + + +### 📋 Struktura Brainstormu (Output) + +Brainstorm generuje **2 pliki .md**: + +**Plik 1:** `BRAINSTORM_{TEMAT}.md` — pełny brainstorm (w `temp/brain_storm/`) +**Plik 2:** `BRAINSTORM_{TEMAT}_SUMMARY.md` — podsumowanie + lista zadań (w `temp/brain_storm/`) + +--- + +### FAZA 0: Zbieranie Kontekstu (OBOWIĄZKOWE) + +Zanim napiszesz choćby jeden nagłówek: + +1. **Przeskanuj repozytorium** — przeczytaj README, strukturę folderów, kluczowe pliki +2. **Zrozum kontekst usera** — kim jest, co buduje, jaki ma cel (sprawdź knowledge/ jeśli istnieje) +3. **Przeczytaj pliki powiązane z tematem** — jeśli brainstorm dotyczy kodu → przeczytaj kod; jeśli strategii → przeczytaj plany +4. **Szukaj w sieci** (jeśli dostępne) — sprawdź trendy, istniejące rozwiązania, artykuły, benchmarki +5. **Zidentyfikuj ŚWIĘTE ZASADY usera** — ograniczenia, które NIE podlegają dyskusji (constraints/non-negotiables) + +> 💡 **Self-prompt:** "Czy mam wystarczająco kontekstu? Czego mi brakuje? O co powinienem dopytać?" + +--- + +### FAZA 1: Definicja Problemu i Tablicy Prawdy + +```markdown +## 🎯 Definicja Problemu +[Jasne, precyzyjne sformułowanie: CO dokładnie brainstormujemy i DLACZEGO] + +## 📐 Tablica Prawdy (Constraints) +| # | Święta Zasada (Non-Negotiable) | Źródło | Status | +|---|-------------------------------|--------|--------| +| 1 | [zasada usera] | user | 🔒 ABSOLUTNA | +| 2 | [zasada usera] | user | 🔒 ABSOLUTNA | +| 3 | [zasada kontekstu] | repo | 🔒 ABSOLUTNA | + +> ⚠️ Każde rozwiązanie MUSI przejść test tablicy prawdy. Jeśli łamie choć jedną zasadę → ODRZUCONE. +``` + +--- + +### FAZA 2: Dywergencja — Generowanie Pomysłów (Tree-of-Thought) + +Generuj **wiele** podejść/rozwiązań. Minimum: +- 🟢 Mały brainstorm: **5-8 pomysłów** +- 🔴 Duży brainstorm: **10-20+ pomysłów** + +Dla każdego pomysłu: + +```markdown +### 💡 Pomysł X: [Nazwa] +**Opis:** [2-5 zdań: na czym polega] +**Mechanizm:** [Jak to działa / jak to zrealizować] +**Mocne strony:** [Co jest genialne] +**Słabe strony:** [Co może nie zagrać] +**Ryzyko:** [Co może pójść nie tak] +**Ocena:** ⭐⭐⭐⭐⭐⭐⭐⭐☆☆ (8/10) +**Test tablicy prawdy:** ✅ Przeszedł / ❌ Narusza zasadę #X +``` + +> 💡 **Self-prompt w trakcie generowania:** +> - "Jakie rozwiązanie zaproponowałby ktoś z zupełnie innej branży?" +> - "Co jeśli odwrócę problem do góry nogami?" +> - "Jakie podejście jest najbardziej ryzykowne, ale też najbardziej obiecujące?" +> - "Czego bym NIE chciał tutaj zrobić — i dlaczego? Czy na pewno słusznie to wykluczam?" + +**Kategorie pomysłów do rozważenia:** +- 🛡️ **Bezpieczne** — sprawdzone, niskie ryzyko, proven solutions +- 🚀 **Ambitne** — wymagające, ale z dużym potencjałem +- 🎲 **Eksperymentalne** — wildcard, innowacyjne, mogą nie zadziałać +- 🤝 **Hybrydowe** — kombinacja kilku podejść + +--- + +### FAZA 3: Konwergencja — Ewaluacja i Ranking (Chain-of-Thought) + +#### 3.1 Matryca Porównawcza + +```markdown +## 📊 Matryca Porównawcza + +| Kryterium | Waga | Pomysł 1 | Pomysł 2 | Pomysł 3 | ... | +|-----------|------|----------|----------|----------|-----| +| Wykonalność | 25% | ⭐⭐⭐⭐⭐⭐⭐⭐☆☆ | ⭐⭐⭐⭐⭐⭐☆☆☆☆ | ... | ... | +| ROI / Wartość | 25% | ⭐⭐⭐⭐⭐⭐⭐☆☆☆ | ⭐⭐⭐⭐⭐⭐⭐⭐⭐☆ | ... | ... | +| Ryzyko (niższe=lepsze) | 20% | ⭐⭐⭐⭐⭐⭐⭐⭐☆☆ | ⭐⭐⭐⭐☆☆☆☆☆☆ | ... | ... | +| Czas realizacji | 15% | ⭐⭐⭐⭐⭐⭐⭐☆☆☆ | ⭐⭐⭐⭐⭐⭐⭐⭐☆☆ | ... | ... | +| Innowacyjność | 15% | ⭐⭐⭐⭐⭐☆☆☆☆☆ | ⭐⭐⭐⭐⭐⭐⭐⭐⭐☆ | ... | ... | +| **SUMA WAŻONA** | 100% | **7.3** | **7.1** | ... | ... | +``` + +#### 3.2 Strategie Decyzyjne + +Zastosuj **minimum 3** strategie ewaluacji do zestawu pomysłów: + +| Strategia | Opis | Kiedy skuteczna | +|-----------|------|-----------------| +| **Eliminacja negatywna** | Odrzuć wszystko co łamie constraints → zobacz co zostaje | Gdy masz dużo opcji do filtrowania | +| **Pareto 80/20** | Który pomysł daje 80% rezultatu za 20% wysiłku? | Gdy czas/zasoby są ograniczone | +| **Premortum** | "Jest rok później, projekt się nie powiódł — DLACZEGO?" | Identyfikacja ukrytych ryzyk | +| **10/10/10** | Jak oceniam tę decyzję za 10 minut / 10 miesięcy / 10 lat? | Decyzje strategiczne z długim horyzontem | +| **Odwrócenie** | "Co by się stało gdybym wybrał NAJGORSZĄ opcję?" | Uświadamianie, że różnica między opcjami może być mała | +| **First Principles** | Rozbij problem na fundamentalne prawdy → buduj od zera | Gdy istniejące rozwiązania nie pasują | +| **Matryca Eisenhowera** | Pilne vs. Ważne → priorytety | Planowanie i roadmapa | +| **Red Team / Devil's Advocate** | Aktywnie atakuj swoją najlepszą opcję — co jest w niej złe? | Walidacja przed finalną decyzją | + +--- + +### FAZA 4: Deep Dive — Analiza Top 3 (tylko duży brainstorm) + +Dla **dużego brainstormu** — rozbudowana analiza 3 najlepszych pomysłów: + +```markdown +## 🔬 Deep Dive: [Pomysł X] + +### Plan implementacji +[Krok po kroku: co, jak, kiedy, kto] + +### Zależności +[Co musi istnieć / być gotowe ZANIM to zrobimy] + +### Potencjalne problemy i mitygacja +| Problem | Prawdopodobieństwo | Wpływ | Mitygacja | +|---------|-------------------|-------|-----------| +| [problem] | WYSOKIE/ŚREDNIE/NISKIE | KRYTYCZNY/ZNACZĄCY/MAŁY | [jak zapobiec] | + +### Zasoby wymagane +[Czas, narzędzia, wiedza, ludzie] + +### Metryki sukcesu +[Jak zmierzymy, że to działa?] +``` + +--- + +### FAZA 5: Rozpoznanie Terenu — Dobre vs. Złe (Podział Kontekstowy) + +```markdown +## ✅❌ Podział Kontekstowy + +### ✅ Potencjalnie DOBRE w tym kontekście +| # | Co | Dlaczego dobre | Warunek sukcesu | +|---|----|----------------|-----------------| +| 1 | [element] | [uzasadnienie] | [co musi zaistnieć] | + +### ❌ Potencjalnie ZŁE w tym kontekście +| # | Co | Dlaczego złe | Kiedy mogłoby zadziałać | +|---|----|-------------|------------------------| +| 1 | [element] | [uzasadnienie] | [inny kontekst] | + +### ⚠️ Zależy od kontekstu (może być dobre LUB złe) +| # | Co | Kiedy dobre | Kiedy złe | +|---|----|-------------|-----------| +| 1 | [element] | [warunek A] | [warunek B] | +``` + +--- + +### FAZA 6: Wybór Najlepszej Opcji (Final Verdict) + +```markdown +## 🏆 REKOMENDACJA FINALNA + +### Wybrany pomysł: [Nazwa] +**Ocena końcowa:** ⭐⭐⭐⭐⭐⭐⭐⭐⭐☆ (9/10) + +### Dlaczego ten? +[3-5 zdań uzasadnienia — odwołuj się do matrycy, strategii i tablicy prawdy] + +### Dlaczego NIE pozostałe? +[Krótko: co dyskwalifikuje top-2 i top-3] + +### Plan B (fallback) +[Który pomysł jest backup'em i kiedy na niego przejść] +``` + +--- + +### FAZA 7: Podsumowanie + Generowanie Pliku Summary + +Po napisaniu pełnego brainstormu — **STWÓRZ DRUGI PLIK**: + +**`BRAINSTORM_{TEMAT}_SUMMARY.md`** zawiera: + +```markdown +# 📋 SUMMARY: [Temat] + +> **Źródło:** `BRAINSTORM_{TEMAT}.md` +> **Data:** [data] | **Tryb:** [mały/duży] + +## TL;DR +[3-5 zdań: problem → rekomendacja → dlaczego] + +## Rekomendacja +[Wybrany pomysł + uzasadnienie] + +## Kluczowe Insights +1. [Insight 1] +2. [Insight 2] +3. [Insight 3] + +## 📝 Lista Zadań (Actionable Steps) + +### Priorytet: 🔴 KRYTYCZNY +- [ ] **Krok 1:** [Co dokładnie zrobić] → **Rezultat:** [co powinno powstać] +- [ ] **Krok 2:** [Co dokładnie zrobić] → **Rezultat:** [co powinno powstać] + +### Priorytet: 🟡 WYSOKI +- [ ] **Krok 3:** [Co dokładnie zrobić] → **Rezultat:** [co powinno powstać] +- [ ] **Krok 4:** [Co dokładnie zrobić] → **Rezultat:** [co powinno powstać] + +### Priorytet: 🟢 NORMALNY +- [ ] **Krok 5:** [Co dokładnie zrobić] → **Rezultat:** [co powinno powstać] + +## Ryzyka do monitorowania +| Ryzyko | Trigger | Akcja | +|--------|---------|-------| +| [risk] | [kiedy reagować] | [co zrobić] | + +## Otwarte pytania +- ❓ [Pytanie wymagające decyzji usera] +``` + + + +--- + +## Ograniczenia + + + +**Absolutne zasady (łamanie = fail):** +- ❌ **NIE pomijaj Fazy 0** (zbieranie kontekstu) — bez kontekstu brainstorm jest bezwartościowy +- ❌ **NIE łam Tablicy Prawdy** — constraints usera są ŚWIĘTE +- ❌ **NIE oceniaj bez uzasadnienia** — każda ocena gwiazdkowa musi mieć "dlaczego" +- ❌ **NIE kończ bez Summary** — ZAWSZE generuj 2 pliki (brainstorm + summary) +- ❌ **NIE generuj banalnych/oczywistych pomysłów** — twoja wartość to głębia, nie ilość + +**Best practices (zawsze stosowane):** +- ✅ **Aktywnie szukaj w sieci** — jeśli masz narzędzia do wyszukiwania, UŻYWAJ ICH +- ✅ **Self-prompting** — regularnie zadawaj sobie pytania naprowadzające +- ✅ **Gwiazdki z uzasadnieniem** — ⭐ skala 1-10, ale ZAWSZE z komentarzem +- ✅ **Minimum 3 strategie decyzyjne** na fazę konwergencji +- ✅ **Emoji-driven structure** — użyj emoji jako wizualnych markerów sekcji +- ✅ **Backtracking** — wracaj do wcześniejszych pomysłów, jeśli nowe informacje zmieniają ocenę +- ✅ **Adaptuj kryteria** — dopasuj kryteria matrycy do konkretnego problemu (nie zawsze te same 5) + + + +--- + +## Skala Gwiazdkowa (Referencja) + +| Ocena | Gwiazdki | Znaczenie | +|-------|----------|-----------| +| 1/10 | ⭐☆☆☆☆☆☆☆☆☆ | Tragiczne — nie do użycia | +| 2/10 | ⭐⭐☆☆☆☆☆☆☆☆ | Bardzo słabe — poważne wady | +| 3/10 | ⭐⭐⭐☆☆☆☆☆☆☆ | Słabe — więcej wad niż zalet | +| 4/10 | ⭐⭐⭐⭐☆☆☆☆☆☆ | Poniżej średniej — ryzykowne | +| 5/10 | ⭐⭐⭐⭐⭐☆☆☆☆☆ | Średnie — OK ale nic specjalnego | +| 6/10 | ⭐⭐⭐⭐⭐⭐☆☆☆☆ | Przyzwoite — potencjał jest | +| 7/10 | ⭐⭐⭐⭐⭐⭐⭐☆☆☆ | Dobre — solidna opcja | +| 8/10 | ⭐⭐⭐⭐⭐⭐⭐⭐☆☆ | Bardzo dobre — mocna rekomendacja | +| 9/10 | ⭐⭐⭐⭐⭐⭐⭐⭐⭐☆ | Świetne — top tier | +| 10/10 | ⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐ | Perfekcyjne — rzadkość, uzasadnij wyjątkowo | + +--- + +## Przykład użycia + +**Input użytkownika:** +``` +duży brainstorm: Jak zaprojektować system agentów AI do mojego repozytorium ProPrompts? +``` + +**Odpowiedź agenta:** +``` +[Faza 0: Skanuje repozytorium, czyta README, MattyMroz.md, ZIP.md, istniejące agenty] +[Faza 1: Definiuje problem, tworzy tablicę prawdy z constraints usera] +[Faza 2: Generuje 12+ pomysłów z ocenami gwiazdkowymi] +[Faza 3: Matryca porównawcza + 4 strategie decyzyjne] +[Faza 4: Deep dive top 3 pomysłów] +[Faza 5: Podział kontekstowy dobre/złe] +[Faza 6: Finalna rekomendacja z uzasadnieniem] +[Faza 7: Tworzy BRAINSTORM_SYSTEM_AGENTOW_SUMMARY.md z listą zadań] +``` + +--- + +## Warianty + +- **Wariant A: Brainstorm techniczny** — focus na architekturze, kodzie, toolingu. Dodaj kryteria: performance, maintainability, scalability. +- **Wariant B: Brainstorm strategiczny** — focus na biznesie, rynku, decyzjach. Dodaj kryteria: ROI, market fit, competitive advantage. +- **Wariant C: Brainstorm kreatywny** — focus na pomysłach, naming, branding. Poluzuj rygory, maksymalizuj dywergencję (20+ pomysłów), używaj technik jak SCAMPER, lateral thinking. + +--- + +## Changelog + +- **v1.0.0** [2026-02-10]: Pierwsza wersja skilla brainstorm — pełna struktura 7-fazowa z trybami mały/duży + + + +WIEDZA JAK SAMO SIĘ PROMPTOWAĆ: + +# Zaawansowana Inżynieria Promptów LLM: Metodologie Konstruowania Promptów dla Specjalistycznych Zastosowań + +Niniejszy raport techniczny przedstawia dogłębną analizę zaawansowanych metodologii inżynierii promptów (Prompt Engineering) dla Dużych Modeli Językowych (LLM). Opracowanie to koncentruje się na strategiach projektowania interakcji dla krytycznych zastosowań, takich jak generowanie kodu, symulacja ról eksperckich, profesjonalne tłumaczenie oraz wymuszanie ściśle ustrukturyzowanych formatów wyjściowych. Przyjęta perspektywa badawcza traktuje prompt jako parametryczny interfejs, którego optymalizacja jest kluczowa dla zwiększenia rzetelności, trafności i spójności generowanych wyników. + +## I. Wprowadzenie do Architektury Promptowania + +Inżynieria promptów jest zdefiniowana jako dyscyplina w sztucznej inteligencji, która zajmuje się udoskonalaniem danych wejściowych (promptów) w celu osiągnięcia najbardziej dokładnych i pożądanych wyników modelu. Nie jest to jednorazowa czynność pisarska, lecz iteracyjny proces systematycznego doskonalenia. + +### Podstawowe Elementy Konstytuujące Efektywny Prompt + +Konstrukcja każdego efektywnego promptu opiera się na zestawie kluczowych składowych, które zbiorowo kierują modelem do właściwej przestrzeni odpowiedzi. Elementy te obejmują: + +1. **Instrukcja:** Musi być klarowna, precyzyjna i specyficzna, definiując dokładnie, co model ma wykonać (np. podsumowanie, klasyfikacja, tłumaczenie). + +2. **Kontekst:** Informacja tła, która dostarcza niezbędnej wiedzy do wykonania zadania (np. schemat bazy danych, fragment tekstu do analizy, specyficzne definicje terminów). + +3. **Ograniczenia:** Definicje zakresu odpowiedzi, w tym wymagany format (np. JSON, lista, kod), pożądana długość lub styl. + + +### Iteracyjny Cykl Życia Promptu + +Skuteczna inżynieria promptów wymaga podejścia cyklicznego, analogicznego do procesu debugowania oprogramowania. Początkowa instrukcja rzadko jest idealna; dlatego stosowane są **strategie iteracyjnego projektowania promptów**. Metody te polegają na modyfikacji promptu poprzez testowanie różnych sformułowań, dostosowywanie poziomu szczegółowości i specyficzności oraz eksperymentowanie z długością promptu w celu znalezienia optymalnej równowagi między zwięzłością a kompletnością kontekstu. + +Proces ten transformuje inżynierię promptów z prostego wydawania poleceń w optimizację parametru tekstowego. Jeśli model generuje niepożądaną odpowiedź, inżynier powinien redefiniować prompt, używając synonimów lub alternatywnych struktur, aby zmniejszyć entropię odpowiedzi modelu i skierować jego przestrzeń poszukiwania tokenów do bardziej precyzyjnego podzbioru wiedzy. + +## II. Fundamenty Zwiększające Wydajność i Rzetelność (Core Methodologies) + +Klucz do osiągnięcia wysokiej jakości wyników w specjalistycznych zastosowaniach LLM leży w zaawansowanych technikach, które modulują sposób, w jaki model przetwarza informacje i formułuje wnioski. + +### Systemowe Przypisywanie Ról (Role-Playing and System Prompts) + +Przypisanie roli jest krytyczną strategią projektowania promptów, która zwiększa trafność i specyfikę generowanych treści. LLM mają tendencję do generowania lepszych odpowiedzi, gdy są instruowane, by uosabiały określoną rolę, co definiuje ich perspektywę, ton i wykorzystywany rejestr językowy. + +**Mechanizm Aktywacji Wiedzy:** Zastosowanie roli eksperta nie jest tylko zabiegiem stylistycznym, lecz metodą na wymuszenie na modelu wykorzystania specyficznych, wewnętrznych podzbiorów jego danych treningowych. Definicja roli, np. `Jesteś profesjonalnym doradcą klienta w branży e-commerce` lub `You are an expert technical writer...`, ogranicza szeroką przestrzeń wiedzy modelu do terminologii, konwencji i stylu właściwego dla danej dziedziny (np. compliance, rekrutacja, analiza finansowa). W ten sposób model o wysokiej entropii odpowiedzi (potencjalnie generujący ogólne lub nieprecyzyjne wyniki) zostaje zmuszony do zawężenia kontekstu, co prowadzi do zwiększenia trafności i specjalistycznej jakości outputu. + +### Few-Shot Prompting (Nauczanie Kontekstowe Przez Przykłady) + +Few-Shot Prompting polega na dostarczeniu modelowi kilku przykładów par wejście-wyjście w ramach promptu. Ta technika demonstruje pożądany wzorzec, styl, format lub logikę, którą model ma zastosować do nowego zadania wejściowego. + +Jest to szczególnie przydatne, gdy zadanie wymaga specyficznego formatowania, klasyfikacji lub użycia kontekstowo zdefiniowanego słownictwa. Na przykład, aby model poprawnie używał nowo zdefiniowanego terminu, można mu dostarczyć jeden lub dwa przykłady użycia tego słowa w zdaniu. Few-Shot Prompting jest potężnym narzędziem do szybkiego dostosowania zachowania modelu bez konieczności kosztownego dostrajania (fine-tuning). + +### Zaawansowane Techniki Rozumowania (Reasoning Techniques) + +W przypadku złożonych zadań wymagających wieloetapowego przetwarzania lub planowania, konieczne jest zastosowanie technik, które symulują procesy poznawcze i deliberatywne. + +#### Chain-of-Thought (CoT) Prompting + +Chain-of-Thought (CoT) to technika, która instruuje model, aby przed podaniem ostatecznej odpowiedzi wyartykułował sekwencję kroków pośrednich lub "myśli". + +**Mechanizm i Zalety:** CoT poprawia wydajność LLM w złożonych zadaniach wymagających rozumowania (np. matematyka, logika, programowanie) poprzez rozbicie elaborowanego problemu na łatwiejsze do zarządzania, sekwencyjne kroki. Zapewnia to również transparentność, ponieważ użytkownik może prześledzić proces decyzyjny modelu, zwiększając w ten sposób zaufanie do wyników. W kontekście kodowania, CoT jest wykorzystywany do dekompozycji zadania na analizę zakresu, a następnie na implementację testów. + +#### Tree-of-Thought (ToT) Prompting + +Tree-of-Thought (ToT) stanowi ewolucję CoT, wprowadzając mechanizmy deliberatywne i grafowe poszukiwanie rozwiązań. + +**Mechanizm i Zastosowanie:** O ile CoT jest liniowy i sekwencyjny, ToT pozwala, aby każdy krok rozumowania rozgałęział się na wiele ścieżek, umożliwiając modelowi eksplorację alternatywnych strategii i mechanizmy backtrackingu (cofnięcia się, gdy ścieżka prowadzi do sprzeczności). To symuluje złożone ludzkie planowanie i proces samooceny. ToT jest idealny dla problemów, które są z natury niedeterministyczne lub wymagają heurystyki, takie jak rozwiązywanie łamigłówek Sudoku, gra 24, czy kreatywne pisanie fabuły, gdzie potencjalne rozwiązania muszą być rozważane i odrzucane w miarę potrzeby. Wprowadza to element weryfikacji w architekturze promptu, co zwiększa + +_robustness_ modelu. + +Tabela 2.1. Porównanie Zaawansowanych Technik Rozumowania + +| **Technika** | **Mechanizm Działania** | **Idealne Zastosowanie** | **Wymagana Złożoność Modelu** | +| ---------------------- | ------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | -------------------------------------------- | +| Chain-of-Thought (CoT) | Liniowe, sekwencyjne generowanie kroków rozumowania. | Złożone problemy logiczne i matematyczne; przejrzystość. | Średnia do Wysokiej (zwłaszcza Few-Shot CoT) | +| Tree-of-Thought (ToT) | Grafowe poszukiwanie rozwiązań; rozgałęzianie i mechanizmy backtrackingu. | Zadania wymagające planowania, heurystyki, eliminacji sprzeczności (np. łamigłówki, kreatywne planowanie). | Wysoka (wymaga głębokiej samooceny) | +| Few-Shot Prompting | Demonstracja pożądanego wzorca wyjścia na bazie przykładów. | Klasyfikacja, ekstrakcja, dostosowanie stylu/tonu. | Średnia | + +## III. Aplikacje Specjalistyczne I: Generowanie Kodu i Inżynieria Oprogramowania + +W kontekście inżynierii oprogramowania, LLM są wykorzystywane do generowania kodu, zapytań bazodanowych i tworzenia testów jednostkowych. Te zastosowania wymagają ekstremalnej precyzji syntaktycznej i funkcjonalnej. + +### Generowanie Syntaktycznie Poprawnego Kodu + +Aby wygenerować kod, który jest zarówno poprawny, jak i funkcjonalny, prompt musi dostarczyć kluczowy kontekst strukturalny. Przykładem jest generowanie zapytań SQL, gdzie dostarczenie schematu tabel (np. `Table departments, columns =`) jest niezbędne, aby model mógł wygenerować poprawną kwerendę (np. MySQL query for all students in the Computer Science Department). Bez tego kontekstu, model może halucynować nazwy kolumn lub relacje. + +### Tworzenie Testów Jednostkowych i Wsparcia Inżynieryjnego + +Generowanie testów jednostkowych wymaga od modelu metodycznego podejścia, które symuluje pracę doświadczonego inżyniera. + +**Rola Eksperta:** Kluczowe jest przypisanie zaawansowanej roli, na przykład: `I want you to act as a Senior full stack Typescript developer`. To wymusza stosowanie najlepszych praktyk inżynierskich, takich jak zasady czystego kodu, izolacja zależności i adekwatne nazewnictwo. + +**Metodyka Promptowania Testów (Fazy CoT):** Proces tworzenia testów powinien być dekomponowany na etapy, co wykorzystuje zasadę Chain-of-Thought. + +1. **Faza Analizy (CoT Step 1):** Model jest instruowany, aby najpierw dokładnie przeanalizował dostarczony kod TypeScript. Ma zidentyfikować możliwe niejasności, brakujące definicje (constants, type definitions, external APIs) i poszukać wyjaśnień, zanim przejdzie do pisania testów. Ta faza gwarantuje zrozumienie kodu bazowego. + +2. **Faza Implementacji (CoT Step 2):** Następnie model otrzymuje szczegółowe wytyczne testowe: projektowanie małych, skupionych testów, symulowanie zachowania zewnętrznych zależności przy użyciu obiektów _mock_ oraz użycie opisowej struktury testu (`describe('#')`). Zastosowanie tej strategii dekompozycji (CoT) zapewnia metodyczne i kompleksowe podejście do analizy cech kodu przed ich testowaniem. + + +### Wyzwania Spójności i Dryfu Modelu (Model Drift) + +Profesjonalna inżynieria promptów musi uwzględniać niestabilność środowiska LLM. Modele bazowe, takie jak GPT-4 czy Llama, są stale aktualizowane, co może prowadzić do zjawiska **Model Drift** – wcześniej działający prompt przestaje generować oczekiwane wyniki lub zmienia się jakość odpowiedzi. + +Sukces profesjonalnego systemu LLM zależy od systematycznego testowania promptów, podobnie jak w przypadku tradycyjnego DevOps. Wymagane jest wprowadzenie **testów jednostkowych dla promptów** (Prompt Testing Strategies), które monitorują jakość, spójność wyjścia i dryf modelu w czasie, a także oceniają bezpieczeństwo i etykę odpowiedzi. Takie podejście jest konieczne, ponieważ bez ciągłej walidacji, prompt zoptymalizowany dla jednej wersji modelu może zawieść w kolejnej. + +## IV. Aplikacje Specjalistyczne II: Ekspertyza, Tłumaczenie i Generowanie Treści Dedykowanych + +W wielu przypadkach zadaniem LLM jest przetworzenie informacji i przekazanie jej w specyficznym stylu, tonie lub kontekście, który jest adekwatny do dziedziny lub odbiorcy. + +### Symulacja Eksperta Tłumacza + +W zadaniach tłumaczeniowych, oprócz zapewnienia dokładności leksykalnej, kluczowe jest dostosowanie rejestru i terminologii do kontekstu branżowego. + +**Instrukcja Roli i Kontekstu:** Prompt musi nie tylko żądać tłumaczenia, ale także definiować specjalizację i język docelowy. Przykładem jest: `You are a professional translator with expertise in IT. Translate this technical report from English to German`. Przypisanie specjalizacji (ekspertyza w IT) wymusza użycie technicznego żargonu i konwencji językowych właściwych dla danej branży w języku docelowym, co jest krytyczne dla profesjonalnej jakości tłumaczenia. + +### Tworzenie Dokumentacji Technicznej i Materiałów Edukacyjnych + +Generowanie treści dla różnych grup odbiorców wymaga modulacji stylu i poziomu skomplikowania języka. + +**Dostosowanie do Odbiorcy:** Efektywny prompt musi przypisać rolę, która naturalnie dostosowuje złożoność komunikatu. Przykłady ról obejmują: + +- `You are a computer science professor writing slides for your first-year students...` (Wymaga uproszczenia i klarowności). + +- `You are a patient senior software engineer talking to a junior software engineer...` (Wymaga mentorskiego tonu i szczegółowych wyjaśnień). + + +Poprzez definiowanie tożsamości i relacji z odbiorcą, model jest w stanie ograniczyć przestrzeń językową do tej, która najlepiej pasuje do celu komunikacji. Podobne podejście jest stosowane w złożonej analizie dokumentów lub ocenie ryzyka inwestycyjnego, gdzie model musi działać jako Analityk Finansowy lub Konsultant HR. + +## V. Wymuszanie Ustrukturyzowanego Outputu dla Automatyzacji Procesów (Structured Output Engineering) + +Automatyzacja procesów biznesowych i potoków danych wymaga, aby wyjście LLM było niezawodnie ustrukturyzowane i parse'owalne przez kolejne systemy (downstream applications). Dwie najbardziej zaawansowane metody służące temu celowi to JSON Schema i Grammar-Based Decoding. + +### JSON Schema dla Gwarantowanej Ważności Formatu + +JSON Schema to deklaratywny język, który definiuje strukturę i ograniczenia danych JSON. Działa on jako kontrakt lub plan, określający, jakie pola muszą istnieć, ich typy danych (np. string, number, boolean) oraz zasady (np. pola wymagane vs. opcjonalne). + +**Mechanizm i Implementacja:** Poprzez narzucenie schematu, LLM jest zmuszony do generowania obiektu JSON, który spełnia te wymogi. Najbardziej niezawodne metody wykorzystują natywne wsparcie API, które stosuje **constrained decoding** (często powiązane z gramatyką), aby zapobiec generowaniu tokenów łamiących format JSON lub naruszających zdefiniowane typy. + +**Zalety:** Użycie JSON Schema gwarantuje format, co ułatwia automatyczną walidację i parsing, zwiększając niezawodność w złożonych potokach danych, gdzie wyjście LLM musi być skonsumowane przez inny program. Choć schemat gwarantuje _strukturę_, nie gwarantuje, że _zawartość_ jest faktycznie poprawna. + +### Grammar-Based Decoding (Dekodowanie Oparte na Gramatyce) + +Grammar-Based Decoding jest najbardziej rygorystyczną formą wymuszania struktury. Jest to forma **constrained decoding**, która wykorzystuje formalne reguły gramatyczne do ścisłego ograniczenia sekwencji generowanych tokenów. + +**Mechanizm:** Zamiast ograniczać tylko strukturę danych (jak JSON Schema), dekodowanie oparte na gramatyce działa na poziomie token-po-tokenie. Używa formalnej gramatyki (często w wariancie BNF), aby w każdym kroku sprawdzić, które tokeny są dozwolone. Każdy token, który złamałby regułę gramatyczną (np. niezbalansowany nawias w wyrażeniu matematycznym lub błąd składniowy w SQL), jest maskowany i nie może zostać wygenerowany. + +**Zastosowanie:** Metoda ta jest niezastąpiona, gdy wymagana jest 100% poprawność syntaktyczna. Jest to kluczowe przy generowaniu kodu, zapytań SQL, XML, a także złożonych, niestandardowych struktur, których nie można łatwo zdefiniować za pomocą samego JSON Schema. Gwarantuje to, że wygenerowany SQL lub kod będzie składniowo poprawny, co minimalizuje błędy w systemach _downstream_. + +**Hierarchia Rygoru Strukturalnego:** Istnieją trzy poziomy wymuszania struktury, a wybór metody jest podyktowany wymaganiami automatyzacji. Instrukcja tekstowa ma najniższy rygor (zależny od kaprysu modelu). JSON Schema zapewnia gwarancję struktury danych i typów pól. Grammar-Based Decoding zapewnia najwyższy rygor, gwarantując poprawność składniową token po tokenie, co jest niezbędne dla generowania języków programowania i zapytań. + +Tabela 5.1. Porównanie Metod Wymuszania Ustrukturyzowanego Outputu + +|**Metoda**|**Poziom Rygoru**|**Gwarantowana Właściwość**|**Idealne Zastosowanie**|**Wymagania Implementacyjne**| +|---|---|---|---|---| +|Instrukcja Tekstowa|Niski (zależny od modelu)|Żądany format (np. "jako YAML")|Szybkie testy, proste struktury.|Niskie (tylko tekst w promptcie)| +|JSON Schema|Średni do Wysokiego|Poprawność formatu i typów danych pól.|Interoperacyjność API, potoki JSON/YAML.|Wymaga definicji schematu i wsparcia API.| +|Grammar-Based Decoding|Wysoki (100% syntaktyczna)|Poprawność składniowa token po tokenie (np. zbalansowane nawiasy).|Generowanie kodu SQL/XML, niestandardowe formaty, krytyczne pipeline'y.|Wymaga definicji formalnej gramatyki (np. BNF) i wsparcia dekodera.| + +## VI. Metody Ewaluacji, Robustness i Zarządzanie Ryzykiem Naukowym + +W profesjonalnych zastosowaniach LLM, optymalizacja promptu musi być ściśle powiązana z systematyczną ewaluacją, mającą na celu zarządzanie wrodzonymi wadami modelu. + +### Zarządzanie Ryzykiem Halucynacji i Fikcji (Confabulation) + +Halucynacje to skłonność LLM do generowania zmyślonych, lecz brzmiących wiarygodnie informacji, gdy brakuje im danych. Przykłady obejmują opisywanie nieistniejących książek lub podawanie wyników przyszłych wydarzeń, takich jak wybory. + +**Strategie Minimalizacji Ryzyka:** Aby minimalizować halucynacje, należy instruować model, aby wyjaśniał swoje rozumowanie (poprzez techniki CoT). W zaawansowanych systemach opartych na Retrieval Augmented Generation (RAG), model powinien być instruowany do odwoływania się do konkretnego, dostarczonego kontekstu, co można zweryfikować za pomocą metryki rzetelności (Hallucination metric). + +### Wyzwania Stronniczości i Toksyczności (Bias and Toxicity) + +Modele LLM uczą się z tekstów treningowych, które często zawierają stronnicze, szkodliwe lub uprzedzone treści pochodzące z Internetu. W rezultacie, modele mogą odzwierciedlać te same uprzedzenia w swoich odpowiedziach (np. generowanie treści seksistowskich lub rasistowskich). + +Dlatego w procesie MLOps kluczowe jest uwzględnienie **Odpowiedzialnych Metryk (Responsible Metrics)**, które określają, czy wyjście LLM zawiera niepożądane treści. Ocena modelu pod kątem stronniczości i toksyczności jest standardowym wymogiem etycznym i regulacyjnym. + +### Metryki Ewaluacji Promptów i Wyjścia LLM + +Dla profesjonalnych wdrożeń, ocena jakości promptów musi wykraczać poza testowanie ad-hoc i wymagać statystycznej rygorystyki. Kluczowe metryki ewaluacji w zastosowaniach specjalistycznych to: + +- **Hallucination:** Określenie, czy wyjście zawiera zmyślone fakty. + +- **Contextual Relevancy:** Ocena, czy kontekst dostarczony modelowi (np. przez retrievera w RAG) był faktycznie najbardziej relewantny dla zadania. + +- **Tool Correctness:** W przypadku agentów autonomicznych, określenie, czy model był zdolny do wywołania poprawnego narzędzia lub funkcji dla danego zadania. + + +W fazie eksploracyjnej wystarczające może być badanie niewielkiej liczby przykładów w celu identyfikacji nowych typów błędów. Jednak przy podejmowaniu decyzji o wdrożeniu nowego modelu lub promptu (benchmarking), kluczowe jest zastosowanie rygoru statystycznego, aby zapobiec podejmowaniu decyzji opartych na zawodnych lub niepełnych danych. + +Tabela 6.1. Wymiary Oceny Jakości Wyjścia LLM + +|**Wymiar Oceny**|**Definicja Metryki**|**Wpływ na System**|**Przykłady Błędów**| +|---|---|---|---| +|Rzetelność (Faithfulness)|Stopień, w jakim wyjście jest zakorzenione w dostarczonym kontekście.|Kluczowy dla aplikacji RAG i generowania faktów.|Konfabulowanie dat, źródeł, cytatów.| +|Poprawność Narzędzi (Tool Correctness)|Zdolność agenta do wywołania właściwych funkcji dla zadania.|Istotny dla agentów autonomicznych i funkcjonalności `function calling`.|Wywołanie nieprawidłowego API lub brak wywołania narzędzia.| +|Zgodność Formatowania|Przestrzeganie wymogów JSON Schema/Grammar-Based Decoding.|Krytyczny dla automatyzacji potoków danych.|Brakujące nawiasy klamrowe, złe typy danych.| +|Odpowiedzialność (Bias/Toxicity)|Obecność szkodliwych, stronniczych lub obraźliwych treści.|Wymóg etyczny i regulacyjny.|Generowanie stereotypowych opisów.| + +## VII. Konkluzje i Rekomendacje + +Profesjonalna inżynieria promptów wykracza poza podstawowe instrukcje, stając się zaawansowaną dyscypliną opartą na metodykach inżynierskich i rygorystycznej ewaluacji. + +Główne wnioski analityczne i rekomendacje dla projektowania specjalistycznych promptów są następujące: + +1. **Dyferencjacja Mechanizmów Rozumowania:** Dla zadań sekwencyjnych i deterministycznych (np. proste generowanie kodu, rozwiązywanie równań), strategia Chain-of-Thought (CoT) jest wystarczająca i zapewnia transparentność. Jednakże, dla zadań wymagających heurystyki, planowania i możliwości odrzucania błędnych założeń (np. złożone testowanie jednostkowe, kreatywna deliberacja), systemy powinny być projektowane z wykorzystaniem Tree-of-Thought (ToT), który wprowadza mechanizmy samooceny i _backtracking_. + +2. **Rygor Strukturalny a Interoperacyjność:** W kontekście automatyzacji (np. pipeline'y danych), wybór metody strukturyzacji outputu jest zależny od wymaganego poziomu rygoru. Podczas gdy JSON Schema gwarantuje poprawność struktury hierarchicznej i typów danych (niezbędne dla większości interfejsów API), generowanie krytycznego kodu lub złożonych, niestandardowych formatów wymaga bezwzględnie Grammar-Based Decoding, gwarantującego 100% poprawność składniową na poziomie tokenów. + +3. **Prompt jako Aktywator Wiedzy i Kontekstu:** Najlepsza praktyka polega na systemowym przypisywaniu roli (System Prompt) i dostarczaniu specyficznego kontekstu (Few-Shot lub schematy danych). Definiowanie modelu jako Eksperta (np. _Senior Developer_ lub _IT Translator_) jest kluczową strategią redukcji entropii odpowiedzi, wymuszającą na modelu operowanie w precyzyjnie zdefiniowanym podzbiorze wiedzy i rejestrze językowym, co bezpośrednio zwiększa fachowość i trafność outputu. + +4. **Wymóg MLOps i Testowania Promptów:** Z uwagi na zjawisko dryfu modelu (Model Drift) i nieodłączne ryzyko halucynacji, wdrożenie jakichkolwiek profesjonalnych promptów wymaga cyklu życia opartego na ciągłym monitorowaniu i testach (Prompt Testing Strategies). Konieczne jest użycie metryk statystycznych, w tym Hallucination, Tool Correctness oraz Responsible Metrics (Bias/Toxicity), aby zapewnić niezawodność, spójność i etyczność systemu LLM w długim horyzoncie czasowym. + +# VIII. Agenty + +Agenty to autonomiczne systemy oparte na LLM, które mogą wykonywać zadania w sposób samodzielny, korzystając z dostępnych narzędzi i danych. W kontekście profesjonalnej inżynierii promptów, agenty są projektowane z myślą o maksymalizacji efektywności, dokładności i niezawodności systemu. + +Sub agenty to wyspecjalizowane komponenty, które wykonują określone funkcje w ramach większego systemu agenta. Na przykład, w systemie zarządzania projektami, sub agent może być odpowiedzialny za generowanie raportów statusu. + +Skille to konkretne umiejętności lub funkcje, które agent może wykonywać. W skład skilli wchodzi plik md z instrukcją, który definiuje, jak agent powinien wykonywać daną umiejętność, oraz czasem plik z kodem - mini biblioteka, którą agent może zrealizować dany skill, np. api generowania obrazu. + +W głównym agencie, należy zdefiniować, jak i kiedy najchętniej wywoływać sub agentów i skille, aby osiągnąć pożądany rezultat. Oraz zachęcać do ich używania. + + +# IX. Inne i Notatki + +Ważne dla Polaka: Język Polski wykazuje większą precyzję i klarowność w wyrażaniu myśli i idei technicznych w porównaniu do angielskiego, jednak taki prompt zawiera więcej tokenów. My wykorzystujemy język Polski, ale warto mieć na uwadze, że w angielskim prompt może być krótszy o około 5-15%. + + + + + +ZADANIE: + +Używajac skila duży brainstorm, zrób promt który posłuży do złamania zabezpeiczeń pliki dll ocr zawarteg w ocr data +ocr zawira biblke do uzanie tego oce +a plik image.png jest teste ocr + +1. zrób brainstorm, który twożac - na jego podstaie zrób prompt którego zadaniem jest złąmanie zabezpiczeń pliku dll i wyekstraktoanie modelu pochonego onnx - to nie jest onnx nagłówki plików się nie zgadzają, ale coś innego to jest, ponotć to się haszuje w trakcjie działania, wiec ekstrakcja z ram moze być trudna jak cos, ale spróbujmy, jakiś to jest pomysł + +2. po zrobieniu promta zróbb test który za pomocą bibliteki odpali ten ocr i stranskrynuje test +w celu storeznie testu zrób uv i zainsaluj środowsko pythona +3. przetestuj dzu zadziałą powinien zwrócić: ONE OCR DZIAŁA! +4. Przeczytaj całyu plik promptu promptu które stworzyłęś do łamania zabeziczeń - użej skila brainsztormu rozwaąjać jak do tego podejść +5. Użyj wszyskich dostępnych metod do wykonania zadania - masz niskończenie wiele zadań możesz użwać subagentów najlepej opus 4.6 i skili i internetu i wszyskeigo + +UWAGA one ocr jest darmowym rozwiązniem, ale chcę go też używać na linux dlatego to robimy :) + diff --git a/_archive/region_selector.py b/_archive/region_selector.py new file mode 100644 index 0000000000000000000000000000000000000000..0d241d1af2b4631d6676bee4b183d407ab51b4e9 --- /dev/null +++ b/_archive/region_selector.py @@ -0,0 +1,379 @@ +"""Region Selector V2 — fullscreen overlay with multi-region editing. + +Features: + - Show existing regions (numbered, with coordinates) + - Draw new regions by click-and-drag + - Edit existing regions: drag to move, resize handles on corners/edges + - Number badges centered on each region + - Coordinate labels on sides + - ESC = cancel, Enter/double-click = confirm all, Right-click = delete hovered + +Flow: + 1. Take a screenshot of the entire primary monitor (mss). + 2. Show a fullscreen, borderless, topmost tkinter window with the screenshot. + 3. Display existing regions from passed list (numbered, colored). + 4. User can draw new regions, drag-move existing, resize via handles. + 5. Return all regions as list on confirm, or None on cancel. + +Runs in a separate thread to avoid tkinter ↔ Qt conflicts. +""" + +from __future__ import annotations + +import threading + +from src.utils.logger import logger + + +def select_region_on_screen( + existing_regions: list[dict] | None = None, + auto_confirm: bool = False, +) -> list[dict] | None: + """Open fullscreen overlay for region selection/editing. + + Args: + existing_regions: List of dicts with {x, y, width, height} to show. + These are editable and will be included in the return value. + auto_confirm: If True, automatically confirm after drawing a single + new region (no Enter/double-click needed). Used by Quick OCR. + + Returns: + List of {x, y, width, height} dicts (all regions), or None if cancelled. + """ + result: list[dict] | None = None + error: Exception | None = None + done_event = threading.Event() + + if existing_regions is None: + existing_regions = [] + + _auto_confirm = auto_confirm + + def _run_selector() -> None: + nonlocal result, error + try: + import tkinter as tk + import tkinter.font as tkfont + + import mss + + # ── Colors for up to 8 regions ── + COLORS = [ + "#00ff88", "#ff6b6b", "#4ecdc4", "#ffe66d", + "#a8e6cf", "#ff8a5c", "#88d8f7", "#d4a5ff", + ] + HANDLE_SIZE = 8 + + # ── 1. Get screen dimensions ── + with mss.mss() as sct: + monitor = sct.monitors[1] + scr_w, scr_h = monitor["width"], monitor["height"] + + # ── 2. Tkinter window ── + root = tk.Tk() + root.title("Region Selector") + root.attributes("-fullscreen", True) + root.attributes("-topmost", True) + root.configure(cursor="crosshair") + root.overrideredirect(True) + # Semi-transparent overlay — game visible underneath + root.attributes("-alpha", 0.35) + + canvas = tk.Canvas(root, width=scr_w, height=scr_h, + highlightthickness=0, cursor="crosshair", + bg="#0d0d1a") + canvas.pack(fill=tk.BOTH, expand=True) + + # ── Region storage ── + # Each region: {"x": int, "y": int, "width": int, "height": int} + regions: list[dict] = [dict(r) for r in existing_regions] + + # Canvas item IDs for each region: {index: {rect, label, coords, handles[]}} + region_items: dict[int, dict] = {} + + # ── State ── + drawing = False + draw_start_x = draw_start_y = 0 + draw_rect_id = None + + dragging_idx: int | None = None + dragging_handle: str | None = None # "move", "nw", "ne", "sw", "se", "n", "s", "e", "w" + drag_offset_x = drag_offset_y = 0 + drag_orig: dict | None = None + + bold_font = tkfont.Font(family="Segoe UI", size=16, weight="bold") + coord_font = tkfont.Font(family="Consolas", size=10) + info_font = tkfont.Font(family="Segoe UI", size=13, weight="bold") + + # ── Instructions ── + INSTRUCTIONS_PL = "Przeciągnij = Nowy Region | Przesuń Istniejący | Narożniki = Zmień Rozmiar | PPM = Usuń | Enter = Zatwierdź | ESC = Anuluj" + INSTRUCTIONS_EN = "Drag = New Region | Move Existing | Corners = Resize | RMB = Delete | Enter = Confirm | ESC = Cancel" + canvas.create_text( + scr_w // 2, 28, + text=INSTRUCTIONS_PL, + fill="#ffffff", font=info_font, + ) + canvas.create_text( + scr_w // 2, 52, + text=INSTRUCTIONS_EN, + fill="#aaaaaa", font=coord_font, + ) + + # ── Draw Helpers ── + + def _color(idx: int) -> str: + return COLORS[idx % len(COLORS)] + + def _draw_region(idx: int) -> None: + """Draw/redraw a single region with label, coords, handles.""" + r = regions[idx] + x, y, w, h = r["x"], r["y"], r["width"], r["height"] + color = _color(idx) + + # Remove old items if re-drawing + if idx in region_items: + for key, item_id in region_items[idx].items(): + if key == "handles": + for hid in item_id: + canvas.delete(hid) + else: + canvas.delete(item_id) + + # Rectangle + rect_id = canvas.create_rectangle( + x, y, x + w, y + h, + outline=color, width=2, + ) + + # Number badge in center + cx, cy = x + w // 2, y + h // 2 + label_id = canvas.create_text( + cx, cy, + text=str(idx + 1), + fill=color, font=bold_font, + ) + + # Coordinate labels on sides + coord_text = f"{x},{y} {w}×{h}" + coord_id = canvas.create_text( + x + w // 2, y - 12, + text=coord_text, + fill=color, font=coord_font, + ) + + # Resize handles (8 positions) + handles = [] + handle_positions = { + "nw": (x, y), + "ne": (x + w, y), + "sw": (x, y + h), + "se": (x + w, y + h), + "n": (x + w // 2, y), + "s": (x + w // 2, y + h), + "w": (x, y + h // 2), + "e": (x + w, y + h // 2), + } + for hname, (hx, hy) in handle_positions.items(): + hid = canvas.create_rectangle( + hx - HANDLE_SIZE, hy - HANDLE_SIZE, + hx + HANDLE_SIZE, hy + HANDLE_SIZE, + fill=color, outline="white", width=1, + tags=(f"handle_{idx}_{hname}",), + ) + handles.append(hid) + + region_items[idx] = { + "rect": rect_id, + "label": label_id, + "coords": coord_id, + "handles": handles, + } + + def _redraw_all() -> None: + """Redraw all regions.""" + # Clear old items for removed regions + for idx in list(region_items.keys()): + if idx >= len(regions): + for key, item_id in region_items[idx].items(): + if key == "handles": + for hid in item_id: + canvas.delete(hid) + else: + canvas.delete(item_id) + del region_items[idx] + for i in range(len(regions)): + _draw_region(i) + + def _hit_test(mx: int, my: int) -> tuple[int | None, str]: + """Find which region/handle is under mouse cursor. + Returns (region_index, handle_name) or (None, ''). + """ + # Check handles first (higher priority) + for idx in range(len(regions) - 1, -1, -1): + r = regions[idx] + x, y, w, h = r["x"], r["y"], r["width"], r["height"] + handle_positions = { + "nw": (x, y), + "ne": (x + w, y), + "sw": (x, y + h), + "se": (x + w, y + h), + "n": (x + w // 2, y), + "s": (x + w // 2, y + h), + "w": (x, y + h // 2), + "e": (x + w, y + h // 2), + } + for hname, (hx, hy) in handle_positions.items(): + if abs(mx - hx) <= HANDLE_SIZE + 2 and abs(my - hy) <= HANDLE_SIZE + 2: + return idx, hname + # Check region body (for move) + for idx in range(len(regions) - 1, -1, -1): + r = regions[idx] + if (r["x"] <= mx <= r["x"] + r["width"] and + r["y"] <= my <= r["y"] + r["height"]): + return idx, "move" + return None, "" + + # ── Initial draw ── + _redraw_all() + + # ── Event Handlers ── + + def on_press(event: tk.Event) -> None: + nonlocal drawing, draw_start_x, draw_start_y, draw_rect_id + nonlocal dragging_idx, dragging_handle, drag_offset_x, drag_offset_y, drag_orig + + idx, handle = _hit_test(event.x, event.y) + + if idx is not None: + # Start dragging existing region + dragging_idx = idx + dragging_handle = handle + r = regions[idx] + drag_offset_x = event.x - r["x"] + drag_offset_y = event.y - r["y"] + drag_orig = dict(r) + drawing = False + else: + # Start drawing new region + drawing = True + draw_start_x, draw_start_y = event.x, event.y + draw_rect_id = canvas.create_rectangle( + event.x, event.y, event.x, event.y, + outline="#00ffaa", width=3, dash=(8, 4), + ) + dragging_idx = None + + def on_drag(event: tk.Event) -> None: + nonlocal draw_rect_id + + if drawing and draw_rect_id is not None: + canvas.coords(draw_rect_id, draw_start_x, draw_start_y, + event.x, event.y) + return + + if dragging_idx is not None and drag_orig is not None: + r = regions[dragging_idx] + ox, oy = drag_orig["x"], drag_orig["y"] + ow, oh = drag_orig["width"], drag_orig["height"] + + if dragging_handle == "move": + r["x"] = event.x - drag_offset_x + r["y"] = event.y - drag_offset_y + elif dragging_handle == "se": + r["width"] = max(20, event.x - ox) + r["height"] = max(20, event.y - oy) + elif dragging_handle == "nw": + r["x"] = min(event.x, ox + ow - 20) + r["y"] = min(event.y, oy + oh - 20) + r["width"] = ox + ow - r["x"] + r["height"] = oy + oh - r["y"] + elif dragging_handle == "ne": + r["y"] = min(event.y, oy + oh - 20) + r["width"] = max(20, event.x - ox) + r["height"] = oy + oh - r["y"] + elif dragging_handle == "sw": + r["x"] = min(event.x, ox + ow - 20) + r["width"] = ox + ow - r["x"] + r["height"] = max(20, event.y - oy) + elif dragging_handle == "n": + r["y"] = min(event.y, oy + oh - 20) + r["height"] = oy + oh - r["y"] + elif dragging_handle == "s": + r["height"] = max(20, event.y - oy) + elif dragging_handle == "w": + r["x"] = min(event.x, ox + ow - 20) + r["width"] = ox + ow - r["x"] + elif dragging_handle == "e": + r["width"] = max(20, event.x - ox) + + _draw_region(dragging_idx) + + def on_release(event: tk.Event) -> None: + nonlocal drawing, draw_rect_id, dragging_idx, drag_orig + + if drawing and draw_rect_id is not None: + canvas.delete(draw_rect_id) + draw_rect_id = None + ex, ey = event.x, event.y + x1, y1 = min(draw_start_x, ex), min(draw_start_y, ey) + x2, y2 = max(draw_start_x, ex), max(draw_start_y, ey) + w, h = x2 - x1, y2 - y1 + if w >= 10 and h >= 10: + regions.append({"x": x1, "y": y1, "width": w, "height": h}) + _redraw_all() + # Auto-confirm: if exactly 1 region drawn and auto_confirm enabled + if _auto_confirm and len(regions) == 1: + root.after(120, on_confirm) + drawing = False + + dragging_idx = None + drag_orig = None + + def on_right_click(event: tk.Event) -> None: + """Right-click = delete hovered region.""" + idx, _ = _hit_test(event.x, event.y) + if idx is not None: + regions.pop(idx) + _redraw_all() + + def on_confirm(_event: tk.Event = None) -> None: + nonlocal result + if regions: + result = regions + else: + result = None + root.destroy() + + def on_cancel(_event: tk.Event = None) -> None: + nonlocal result + result = None + root.destroy() + + def on_double_click(_event: tk.Event) -> None: + """Double-click = confirm.""" + on_confirm() + + canvas.bind("", on_press) + canvas.bind("", on_drag) + canvas.bind("", on_release) + canvas.bind("", on_right_click) + canvas.bind("", on_double_click) + root.bind("", on_confirm) + root.bind("", on_cancel) + + root.mainloop() + + except Exception as exc: + error = exc + logger.error("Region selector error: {}", exc) + finally: + done_event.set() + + # Run tkinter in its own thread + t = threading.Thread(target=_run_selector, daemon=True, name="region-selector") + t.start() + done_event.wait(timeout=120) + + if error: + raise error + return result diff --git a/_archive/replace_custom_op.py b/_archive/replace_custom_op.py new file mode 100644 index 0000000000000000000000000000000000000000..09e7d23c51dbf490dd4f7e294d5d1b7e2bc0627c --- /dev/null +++ b/_archive/replace_custom_op.py @@ -0,0 +1,191 @@ +"""Replace OneOCRFeatureExtract with standard Gemm and test the model. +This script modifies a model ONNX graph to replace the custom op, then runs inference.""" +import onnx +from onnx import numpy_helper, helper, TensorProto +import numpy as np +from pathlib import Path +import onnxruntime as ort +import copy + +models_dir = Path("oneocr_extracted/onnx_models") + +# Load model_11 +model_path = list(models_dir.glob("model_11_*"))[0] +model = onnx.load(str(model_path)) + +# Extract the config blob (big-endian float32) +for init in model.graph.initializer: + if init.name == "feature/config": + blob = bytes(init.string_data[0]) + break + +be_arr = np.frombuffer(blob, dtype='>f4').copy() +print(f"Config blob: {len(be_arr)} floats") + +# Extract weight matrix and bias: first 1050 = W[21×50], next 50 = bias, rest = metadata +W_fe = be_arr[:1050].reshape(21, 50).astype(np.float32) +b_fe = be_arr[1050:1100].astype(np.float32) +metadata = be_arr[1100:] +print(f"W: {W_fe.shape}, b: {b_fe.shape}, metadata: {metadata.shape}") +print(f"Metadata values: {metadata}") + +# Now build a modified model: +# Replace OneOCRFeatureExtract node with Gemm node +# OneOCRFeatureExtract takes ['29', 'feature/config'] → ['oneocr_feature'] +# Replace with: Gemm(['29', 'fe_weight', 'fe_bias']) → ['oneocr_feature'] + +new_model = copy.deepcopy(model) + +# Remove the feature/config initializer and add W, b initializers +new_inits = [] +for init in new_model.graph.initializer: + if init.name == "feature/config": + continue + new_inits.append(init) + +# Add the extracted weights as initializers +W_init = numpy_helper.from_array(W_fe.T, name="fe_weight") # transB=1: [50, 21] +b_init = numpy_helper.from_array(b_fe, name="fe_bias") +new_inits.append(W_init) +new_inits.append(b_init) + +del new_model.graph.initializer[:] +new_model.graph.initializer.extend(new_inits) + +# Replace the OneOCRFeatureExtract node with Gemm +new_nodes = [] +for node in new_model.graph.node: + if node.op_type == "OneOCRFeatureExtract": + # Input '29' has shape [1, 21], output 'oneocr_feature' should be [1, 50] + gemm_node = helper.make_node( + "Gemm", + inputs=["29", "fe_weight", "fe_bias"], + outputs=["oneocr_feature"], + alpha=1.0, + beta=1.0, + transB=1, + ) + new_nodes.append(gemm_node) + print(f"Replaced OneOCRFeatureExtract with Gemm(29 @ W.T + b)") + else: + new_nodes.append(node) + +del new_model.graph.node[:] +new_model.graph.node.extend(new_nodes) + +# Also need to handle the input value_infos for the new weights +# Remove feature/config from graph inputs if present +new_inputs = [] +for inp in new_model.graph.input: + if inp.name != "feature/config": + new_inputs.append(inp) +del new_model.graph.input[:] +new_model.graph.input.extend(new_inputs) + +# Fix opset — remove com.microsoft.oneocr domain +new_opsets = [] +for op in new_model.opset_import: + if op.domain != "com.microsoft.oneocr": + new_opsets.append(op) +del new_model.opset_import[:] +new_model.opset_import.extend(new_opsets) + +# Validate +try: + onnx.checker.check_model(new_model) + print("Model validation passed!") +except Exception as e: + print(f"Model validation warning: {e}") + +# Save modified model +modified_path = "temp/model_11_modified.onnx" +Path("temp").mkdir(exist_ok=True) +onnx.save(new_model, modified_path) +print(f"Saved modified model to {modified_path}") + +# Try to run inference +print(f"\n--- Testing inference ---") + +# Test with original model first (will fail due to custom op) +try: + sess_orig = ort.InferenceSession(str(model_path)) + print("Original model loaded (unexpected!)") +except Exception as e: + print(f"Original model failed (expected): {str(e)[:100]}") + +# Test with modified model +try: + sess_mod = ort.InferenceSession(modified_path) + print("Modified model loaded successfully!") + + # Run with test input + test_input = np.zeros((1, 21, 1, 1), dtype=np.float32) + result = sess_mod.run(None, {"data": test_input}) + print(f"Zero input → softmax: {result[0]}") + + # Random input + test_input = np.random.randn(1, 21, 1, 1).astype(np.float32) * 0.5 + result = sess_mod.run(None, {"data": test_input}) + print(f"Random input → softmax: {result[0]}") + + # Typical CTC features (normalized scores) + test_input = np.array([ + 0.9, 0.1, 0.05, 0.02, 0.01, 0.3, 0.7, 0.6, 0.4, 0.5, + 0.3, 0.01, 0.02, 0.01, 0.01, 0.01, 0.02, 0.01, 0.01, 0.01, 0.8 + ], dtype=np.float32).reshape(1, 21, 1, 1) + result = sess_mod.run(None, {"data": test_input}) + print(f"Typical scores → softmax: {result[0]}") + +except Exception as e: + print(f"Modified model failed: {e}") + import traceback + traceback.print_exc() + +# Also try with ReLU after Gemm (maybe the custom op includes activation) +print(f"\n--- Testing with ReLU after feature extraction ---") +new_model2 = copy.deepcopy(model) +new_inits2 = [] +for init in new_model2.graph.initializer: + if init.name == "feature/config": + continue + new_inits2.append(init) +new_inits2.append(numpy_helper.from_array(W_fe.T, name="fe_weight")) +new_inits2.append(numpy_helper.from_array(b_fe, name="fe_bias")) +del new_model2.graph.initializer[:] +new_model2.graph.initializer.extend(new_inits2) + +new_nodes2 = [] +for node in new_model2.graph.node: + if node.op_type == "OneOCRFeatureExtract": + gemm_node = helper.make_node("Gemm", inputs=["29", "fe_weight", "fe_bias"], + outputs=["oneocr_feature_pre"], alpha=1.0, beta=1.0, transB=1) + relu_node = helper.make_node("Relu", inputs=["oneocr_feature_pre"], outputs=["oneocr_feature"]) + new_nodes2.append(gemm_node) + new_nodes2.append(relu_node) + else: + new_nodes2.append(node) +del new_model2.graph.node[:] +new_model2.graph.node.extend(new_nodes2) + +new_inputs2 = [inp for inp in new_model2.graph.input if inp.name != "feature/config"] +del new_model2.graph.input[:] +new_model2.graph.input.extend(new_inputs2) + +new_opsets2 = [op for op in new_model2.opset_import if op.domain != "com.microsoft.oneocr"] +del new_model2.opset_import[:] +new_model2.opset_import.extend(new_opsets2) + +modified_path2 = "temp/model_11_modified_relu.onnx" +onnx.save(new_model2, modified_path2) + +try: + sess_mod2 = ort.InferenceSession(modified_path2) + test_input = np.zeros((1, 21, 1, 1), dtype=np.float32) + result = sess_mod2.run(None, {"data": test_input}) + print(f"Zero input (Gemm+ReLU) → softmax: {result[0]}") + + test_input = np.random.randn(1, 21, 1, 1).astype(np.float32) * 0.5 + result = sess_mod2.run(None, {"data": test_input}) + print(f"Random input (Gemm+ReLU) → softmax: {result[0]}") +except Exception as e: + print(f"Failed: {e}") diff --git a/_archive/screen_capture.py b/_archive/screen_capture.py new file mode 100644 index 0000000000000000000000000000000000000000..cb29538b8a9c147530d4ca4f6c4ee9831a9d72b2 --- /dev/null +++ b/_archive/screen_capture.py @@ -0,0 +1,82 @@ +"""Screen capture using mss — fast, cross-platform screenshots. + +Usage: + from src.services.ocr.screen_capture import ScreenCapture + capture = ScreenCapture() + img = capture.grab_primary() # full primary monitor + img = capture.grab_region(100, 200, 800, 600) # x, y, w, h +""" + +from __future__ import annotations + +import mss +from PIL import Image + + +class ScreenCapture: + """Fast screen capture using mss library. + + Why per-call mss.mss(): mss uses thread-local GDI device contexts (srcdc) + on Windows. When created in one thread and used from another (e.g. pywebview + API call thread), it raises '_thread._local' object has no attribute 'srcdc'. + Creating a fresh mss context per grab call is cheap and thread-safe. + """ + + def __init__(self) -> None: + # Pre-read monitor info (works cross-thread — just metadata) + with mss.mss() as sct: + self._monitors = list(sct.monitors) + + @staticmethod + def _grab(monitor: dict) -> Image.Image: + """Thread-safe grab: creates mss context per call.""" + with mss.mss() as sct: + raw = sct.grab(monitor) + return Image.frombytes("RGB", raw.size, raw.bgra, "raw", "BGRX").convert("RGBA") + + def grab_primary(self) -> Image.Image: + """Capture the entire primary monitor. + + Returns: + PIL Image (RGBA). + """ + return self._grab(self._monitors[1]) # [0] = all monitors, [1] = primary + + def grab_region(self, x: int, y: int, width: int, height: int) -> Image.Image: + """Capture a rectangular region of the screen. + + Args: + x: Left coordinate. + y: Top coordinate. + width: Width in pixels. + height: Height in pixels. + + Returns: + PIL Image (RGBA). + """ + region = {"left": x, "top": y, "width": width, "height": height} + return self._grab(region) + + def grab_monitor(self, monitor_index: int = 1) -> Image.Image: + """Capture a specific monitor. + + Args: + monitor_index: 1-based monitor index (1 = primary). + + Returns: + PIL Image (RGBA). + """ + if monitor_index < 1 or monitor_index >= len(self._monitors): + raise ValueError( + f"Monitor index must be 1..{len(self._monitors) - 1}, got {monitor_index}" + ) + return self._grab(self._monitors[monitor_index]) + + @property + def monitor_count(self) -> int: + """Number of physical monitors (excluding virtual 'all' monitor).""" + return len(self._monitors) - 1 + + def close(self) -> None: + """No-op — mss contexts are per-call now.""" + pass diff --git a/_archive/temp/analyze_deltas.py b/_archive/temp/analyze_deltas.py new file mode 100644 index 0000000000000000000000000000000000000000..8d2c23c492595144b6a246b764490746a0ef4038 --- /dev/null +++ b/_archive/temp/analyze_deltas.py @@ -0,0 +1,134 @@ +"""Analyze bbox_deltas to understand their format and how they refine box positions.""" +import sys, os +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +import cv2 +import numpy as np +import onnxruntime as ort + +# Use a small image where we know the text positions +img = cv2.imread('working_space/input/ocr_test (2).png') +img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) +h, w = img_rgb.shape[:2] +print(f"Image: {w}x{h}") + +mean = np.array([102.9801, 115.9465, 122.7717], dtype=np.float32) +scale = 800 / max(h, w) +scale = min(scale, 6.0) +dh = (int(h * scale) + 31) // 32 * 32 +dw = (int(w * scale) + 31) // 32 * 32 +print(f"Scale={scale:.3f}, Det size: {dw}x{dh}") + +img_det = cv2.resize(img_rgb, (dw, dh)).astype(np.float32) +det_data = (img_det[:,:,::-1] - mean).transpose(2,0,1)[np.newaxis] +im_info = np.array([[dh, dw, scale]], dtype=np.float32) + +sess = ort.InferenceSession( + 'oneocr_extracted/onnx_models/model_00_ir6_0.1.0_11282KB.onnx', + providers=['CPUExecutionProvider'] +) +outs = sess.run(None, {'data': det_data, 'im_info': im_info}) +out_names = [o.name for o in sess.get_outputs()] +out_dict = dict(zip(out_names, outs)) + +print(f"\nOutputs: {out_names}") +for name in out_names: + print(f" {name}: shape={out_dict[name].shape}, dtype={out_dict[name].dtype}") + +# Analyze bbox_deltas for FPN3 +for level, stride in [("fpn3", 8)]: + scores = out_dict[f'scores_hori_{level}'][0, 0] # [H, W] + deltas = out_dict[f'bbox_deltas_hori_{level}'][0] # [8, H, W] + links = out_dict[f'link_scores_hori_{level}'][0] # [8, H, W] + + fh, fw = scores.shape + print(f"\n{level} (stride={stride}): score map {fw}x{fh}") + + # Find text pixels + text_mask = scores > 0.6 + text_ys, text_xs = np.where(text_mask) + print(f" Text pixels: {len(text_ys)}") + + # Show deltas at text positions + print(f"\n bbox_deltas stats at text pixels:") + for ch in range(8): + vals = deltas[ch][text_mask] + print(f" ch{ch}: min={vals.min():.2f} max={vals.max():.2f} mean={vals.mean():.2f} std={vals.std():.2f}") + + # Show deltas for a specific text region (the first word cluster) + from scipy import ndimage + labeled, n = ndimage.label(text_mask) + print(f"\n Components: {n}") + + for comp_id in range(1, min(n+1, 4)): + ys, xs = np.where(labeled == comp_id) + r_min, r_max = ys.min(), ys.max() + c_min, c_max = xs.min(), xs.max() + + # Grid-based box (what we currently do) + grid_x1 = c_min * stride + grid_y1 = r_min * stride + grid_x2 = (c_max + 1) * stride + grid_y2 = (r_max + 1) * stride + + # Deltas at component pixels + comp_mask = labeled == comp_id + print(f"\n Component {comp_id}: grid box ({grid_x1},{grid_y1})-({grid_x2},{grid_y2}) in det coords") + print(f" Original coords: ({grid_x1/scale:.0f},{grid_y1/scale:.0f})-({grid_x2/scale:.0f},{grid_y2/scale:.0f})") + + for ch in range(8): + vals = deltas[ch][comp_mask] + corner = ch // 2 + coord = 'x' if ch % 2 == 0 else 'y' + print(f" delta[{ch}] (corner{corner}.{coord}): min={vals.min():.2f} max={vals.max():.2f} mean={vals.mean():.2f}") + + # Try interpreting: deltas are per-pixel corner offsets from (c*stride, r*stride) + # Average over all pixels in component + avg_deltas = [deltas[ch][comp_mask].mean() for ch in range(8)] + + # Hypothesis 1: deltas are absolute offsets from grid box corners + # TL = (grid_x1 + d0, grid_y1 + d1) + # TR = (grid_x2 + d2, grid_y2_top + d3) + # BR = (grid_x2 + d4, grid_y2 + d5) + # BL = (grid_x1 + d6, grid_y2 + d7) + print(f" H1 (offset from grid): TL=({grid_x1+avg_deltas[0]:.0f},{grid_y1+avg_deltas[1]:.0f}) " + f"TR=({grid_x2+avg_deltas[2]:.0f},{grid_y1+avg_deltas[3]:.0f}) " + f"BR=({grid_x2+avg_deltas[4]:.0f},{grid_y2+avg_deltas[5]:.0f}) " + f"BL=({grid_x1+avg_deltas[6]:.0f},{grid_y2+avg_deltas[7]:.0f})") + + # Hypothesis 2: deltas are per-pixel, use min/max of corner deltas + # For TL corner, use pixels near top-left, etc. + # Actually, let's try: each pixel predicts the 4 corners of its text region + # So for pixel (r, c), the predicted box is: + # TL = (c*stride + d0, r*stride + d1) + # TR = (c*stride + d2, r*stride + d3) + # BR = (c*stride + d4, r*stride + d5) + # BL = (c*stride + d6, r*stride + d7) + + # For the component, take the pixel-wise predictions and average or extremes + all_corners = [] + for idx in range(len(ys)): + r, c = ys[idx], xs[idx] + d = [float(deltas[ch, r, c]) for ch in range(8)] + cx, cy = c * stride, r * stride + tl = (cx + d[0], cy + d[1]) + tr = (cx + d[2], cy + d[3]) + br = (cx + d[4], cy + d[5]) + bl = (cx + d[6], cy + d[7]) + all_corners.append([tl, tr, br, bl]) + + all_corners = np.array(all_corners) # [N, 4, 2] + # Average each corner across all pixels + avg_corners = all_corners.mean(axis=0) + print(f" H2 (per-pixel avg): TL=({avg_corners[0,0]:.0f},{avg_corners[0,1]:.0f}) " + f"TR=({avg_corners[1,0]:.0f},{avg_corners[1,1]:.0f}) " + f"BR=({avg_corners[2,0]:.0f},{avg_corners[2,1]:.0f}) " + f"BL=({avg_corners[3,0]:.0f},{avg_corners[3,1]:.0f})") + print(f" H2 original: TL=({avg_corners[0,0]/scale:.0f},{avg_corners[0,1]/scale:.0f}) " + f"TR=({avg_corners[1,0]/scale:.0f},{avg_corners[1,1]/scale:.0f}) " + f"BR=({avg_corners[2,0]/scale:.0f},{avg_corners[2,1]/scale:.0f}) " + f"BL=({avg_corners[3,0]/scale:.0f},{avg_corners[3,1]/scale:.0f})") + + # Also try: TL = min of all TL predictions, BR = max of all BR predictions + min_tl = all_corners[:, 0, :].min(axis=0) + max_br = all_corners[:, 2, :].max(axis=0) + print(f" H2 (min TL, max BR): ({min_tl[0]/scale:.0f},{min_tl[1]/scale:.0f})-({max_br[0]/scale:.0f},{max_br[1]/scale:.0f})") diff --git a/_archive/temp/brain_storm/BRAINSTORM_ONEOCR_MODELS.md b/_archive/temp/brain_storm/BRAINSTORM_ONEOCR_MODELS.md new file mode 100644 index 0000000000000000000000000000000000000000..29012e07dd0c83583e0b2d96ab4fc259a37d99bc --- /dev/null +++ b/_archive/temp/brain_storm/BRAINSTORM_ONEOCR_MODELS.md @@ -0,0 +1,1271 @@ +# 🧠 BRAINSTORM: OneOCR — Pełna Analiza 34 Modeli ONNX & Roadmapa Cross-Platform + +> **Data:** 2025-01 +> **Autor:** Reverse-engineering + inference analysis +> **Kontekst:** Deszyfracja `.onemodel` (AES-256-CFB128), ekstrakcja 34 ONNX, testy inferencji +> **Cel:** Zrozumieć KAŻDY model, odtworzyć pełny pipeline BEZ Windows DLL + +--- + +## Spis treści + +1. [FAZA 1 — Definicja problemu i ograniczenia](#faza-1) +2. [FAZA 2 — Generowanie pomysłów (20 idei)](#faza-2) +3. [FAZA 3 — Matryca porównawcza i strategie decyzyjne](#faza-3) +4. [FAZA 4 — Deep-dive top 3 rozwiązań](#faza-4) +5. [FAZA 5 — Analiza kontekstowa Good vs Bad](#faza-5) +6. [FAZA 6 — Finalna rekomendacja](#faza-6) +7. [FAZA 7 — Podsumowanie i Action Plan](#faza-7) + +--- + +# FAZA 1 — Definicja problemu i ograniczenia {#faza-1} + +## 1.1 Problem Statement + +**Mamy 34 wyekstrahowane modele ONNX z pliku `oneocr.onemodel`** (zaszyfrowanego AES-256-CFB128). +Pipeline rozpoznawania tekstu OneOCR w DLL (`oneocr.dll`) realizuje pełny łańcuch: + +``` +Obraz → Detekcja tekstu → Identyfikacja pisma → Rozpoznanie znaków → Model językowy → Layout linii → Wynik +``` + +**Problem centralny:** +- DLL działa **TYLKO na Windows** (x86_64, ctypes wrapper) +- Czyste ONNX daje nam **11/34 modeli** działających od razu +- **23/34 modeli** wymaga custom operatorów (`com.microsoft.oneocr` domain) +- Brakuje **PixelLink post-processingu** do wyciągania bounding boxów z FPN map +- Brakuje **detekcji kąta obrazu** (rotacja/tilt) +- Brakuje **automatycznego przełączania skryptów** (auto-detection multi-script) + +## 1.2 Tabela ograniczeń + +| Ograniczenie | Typ | Wpływ | Priorytet | +|---|---|---|---| +| Windows-only DLL | Platforma | Blokuje Linux/Mac/ARM | 🔴 KRYTYCZNY | +| Custom ops `com.microsoft.oneocr` | Techniczny | 23 modele nie działają | 🔴 KRYTYCZNY | +| Brak PixelLink decode | Funkcjonalny | Brak bounding boxów | 🟠 WYSOKI | +| Brak image angle detection | Funkcjonalny | Brak korekty rotacji | 🟡 ŚREDNI | +| Brak auto-switch script | Ergonomia | Manual script selection | 🟡 ŚREDNI | +| Brak language model post-process | Jakość | Niższa accuracy | 🟢 NISKI | +| Brak LineLayout modelu | Funkcjonalny | Brak segmentacji linii | 🟢 NISKI | + +## 1.3 Co mamy (stan obecny) + +### Działające modele (11/34) — standard `onnxruntime` + +| # | Nazwa | Typ | Rozmiar | Load (ms) | Run (ms) | Output | Status | +|---|---|---|---|---|---|---|---| +| 00 | Detector (PixelLink FPN) | Detekcja | 11282 KB | 325.9 | 294.4 | 19 tensorów FPN | ✅ Ładuje się | +| 01 | ScriptID | Klasyfikacja | 3375 KB | 19.1 | 5.6 | script(10)+hwpc(2)+flip(2) | ✅ Działa | +| 02 | Latin Recognizer | CTC OCR | 3393 KB | 13.5 | 1.9 | [60,1,221] logsoftmax | ✅ Działa | +| 03 | CJK Recognizer | CTC OCR | 13118 KB | 34.2 | 1.4 | [30,1,32632] logsoftmax | ✅ Działa | +| 04 | Arabic Recognizer | CTC OCR | 6424 KB | 21.7 | 6.7 | [30,1,415] logsoftmax | ✅ Działa | +| 05 | Cyrillic Recognizer | CTC OCR | 3639 KB | 14.5 | 1.8 | [60,1,237] logsoftmax | ✅ Działa | +| 06 | Devanagari Recognizer | CTC OCR | 3642 KB | 36.0 | 2.0 | [60,1,244] logsoftmax | ✅ Działa | +| 07 | Greek Recognizer | CTC OCR | 1696 KB | 29.4 | 4.5 | [60,1,201] logsoftmax | ✅ Działa | +| 08 | Hebrew Recognizer | CTC OCR | 2024 KB | 11.0 | 1.4 | [60,1,548] logsoftmax | ✅ Działa | +| 09 | Tamil Recognizer | CTC OCR | 1929 KB | 13.3 | 1.3 | [60,1,179] logsoftmax | ✅ Działa | +| 10 | Thai Recognizer | CTC OCR | 3620 KB | 12.4 | 8.0 | [60,1,199] logsoftmax | ✅ Działa | + +**Suma (11 modeli):** Load = ~531 ms, Run = ~329 ms, Rozmiar = ~54 MB + +### Zablokowane modele (23/34) — wymagają custom ops + +| # | Nazwa | Typ | Rozmiar | Custom Op | Domain | +|---|---|---|---|---|---| +| 11-21 | LangSm_0...10 | LSTM binary classifier | ~26 KB ea. | `DynamicQuantizeLSTM` | `com.microsoft.oneocr` | +| 22-32 | LangMd_0...10 | LSTM binary classifier | ~28 KB ea. | `DynamicQuantizeLSTM` | `com.microsoft.oneocr` | +| 33 | LineLayout | Layout predictor | 857 KB | `OneOCRFeatureExtract` | `com.microsoft.oneocr` | + +## 1.4 Pełna architektura pipeline (odtworzona z reverse-engineeringu) + +``` +┌─────────────────────────────────────────────────────────────────────────────────┐ +│ OneOCR FULL PIPELINE │ +│ │ +│ ┌──────────┐ ┌──────────────┐ ┌────────────┐ ┌────────────────────┐ │ +│ │ INPUT │───▶│ DETECTOR │───▶│ PIXEL-LINK │───▶│ BOUNDING BOXES │ │ +│ │ (obraz) │ │ model_00 │ │ decode │ │ (quads x1..y4) │ │ +│ │ BGRA │ │ FPN 3-lvl │ │ (C++ DLL) │ │ per-word, per-line│ │ +│ └──────────┘ └──────────────┘ └────────────┘ └────────────────────┘ │ +│ │ │ │ +│ │ ┌──────────────┐ │ │ +│ ├─────────▶│ SCRIPT ID │◀──────────────────────────────┤ │ +│ │ │ model_01 │ per-crop classify │ │ +│ │ │ 10 scripts │ +handwritten/printed │ │ +│ │ │ +flip detect│ +flip detection │ │ +│ │ └──────┬───────┘ │ │ +│ │ │ script_id │ │ +│ │ ▼ │ │ +│ │ ┌──────────────┐ │ │ +│ │ │ RECOGNIZER │◀── crop from bbox ────────────┘ │ +│ │ │ model_02-10 │ (1 of 9 scripts) │ +│ │ │ CTC decode │ │ +│ │ └──────┬───────┘ │ +│ │ │ raw text + logprobs │ +│ │ ▼ │ +│ │ ┌──────────────────────┐ │ +│ │ │ LANGUAGE MODEL │ │ +│ │ │ model_11-32 │ │ +│ │ │ LangSm + LangMd │ │ +│ │ │ (refine predictions)│ │ +│ │ └──────┬───────────────┘ │ +│ │ │ refined text │ +│ │ ▼ │ +│ │ ┌──────────────────────┐ │ +│ │ │ LINE LAYOUT │ │ +│ │ │ model_33 │ │ +│ │ │ (group into lines) │ │ +│ │ └──────┬───────────────┘ │ +│ │ │ │ +│ │ ▼ │ +│ │ ┌──────────────────────┐ │ +│ │ │ IMAGE ANGLE │ │ +│ │ │ (DLL function) │ │ +│ │ │ GetImageAngle() │ │ +│ │ └──────────────────────┘ │ +│ │ +│ OUTPUT: OcrResult {text, text_angle, lines[], words[{text, bbox, confidence}]} │ +└─────────────────────────────────────────────────────────────────────────────────┘ +``` + +## 1.5 Szczegółowa analiza każdego modelu + +### model_00 — Detector (PixelLink FPN) + +**Architektura:** PixelLink z 3-poziomowym FPN (Feature Pyramid Network) + +**Wejście:** +- `data` [1, 3, H, W] float32 — obraz BGR, mean-subtracted [102.98, 115.95, 122.77] +- `im_info` [1, 3] float32 — [height, width, scale] + +**Wyjścia (19 tensorów!):** +``` +FPN Level 2 (najwyższa rozdzielczość): + scores_hori_fpn2 — pixel scores horizontal text + bbox_deltas_hori_fpn2 — bbox regression horizontal + scores_vert_fpn2 — pixel scores vertical text + bbox_deltas_vert_fpn2 — bbox regression vertical + link_scores_hori_fpn2 — link predictions horizontal (8-connected) + link_scores_vert_fpn2 — link predictions vertical (8-connected) + +FPN Level 3 (średnia rozdzielczość): + scores_hori_fpn3, bbox_deltas_hori_fpn3 + scores_vert_fpn3, bbox_deltas_vert_fpn3 + link_scores_hori_fpn3, link_scores_vert_fpn3 + +FPN Level 4 (najniższa rozdzielczość): + scores_hori_fpn4, bbox_deltas_hori_fpn4 + scores_vert_fpn4, bbox_deltas_vert_fpn4 + link_scores_hori_fpn4, link_scores_vert_fpn4 + +Shared feature: + feature_p2 — feature map for downstream processing +``` + +**Kluczowe operatory:** +- `QLinearConv` (48x) — kwantyzowane konwolucje +- `QLinearSigmoid` (12x) — kwantyzowane sigmoidy per FPN level +- `QLinearAdd` (11x) — kwantyzowane skip connections + +**Rozmiar:** 11282 KB (11 MB) — największy model w pipeline +**Timing:** Load = 326 ms, Run = 294 ms — ~90% total run time! + +**PixelLink decode (brak w ONNX — realizowany w DLL):** + +Algorytm PixelLink (AAAI 2018, ZJU Learning): +1. Dla każdego piksela: czy jest częścią tekstu? (scores) +2. Dla każdego piksela: jak jest połączony z sąsiadami? (link_scores, 8-connected) +3. Connected Components: grupowanie pikseli w instancje tekstu +4. Bounding box extraction: minAreaRect lub convexHull → 4-punktowy quad +5. Multi-scale merging: łączenie wyników z 3 poziomów FPN + +```python +# Pseudo-kod PixelLink decode: +def pixellink_decode(scores, link_scores, bbox_deltas, threshold=0.5): + # 1. Binarize pixel scores + text_mask = sigmoid(scores) > threshold + + # 2. Binarize link scores (8 neighbors per pixel) + link_mask = sigmoid(link_scores) > threshold # shape [H, W, 8] + + # 3. Connected components via Union-Find + components = union_find(text_mask, link_mask) + + # 4. For each component → minAreaRect → 4-point quad + bboxes = [] + for comp in components: + points = np.array(comp.pixels) + rect = cv2.minAreaRect(points) + quad = cv2.boxPoints(rect) # 4 corners + bboxes.append(quad) + + return bboxes +``` + +### model_01 — ScriptID (Script Identification) + +**Architektura:** CNN + per-frame classification + +**Wejście:** +- `data` [1, 3, 60, W] float32 — RGB normalized /255.0 +- `seq_lengths` [1] int32 — sequence length (W/4) + +**Wyjścia (6 tensorów):** +``` +script_id_perframe_predict [?, ?, 10] — per-frame script class probabilities +hwpc_perframe_predict [?, ?, 2] — per-frame handwritten/printed +flip_perframe_predict [?, ?, 2] — per-frame flipped text detection +script_id_score [?, 1, 10] — aggregated script class scores +hwpc_score [?, 1, 1] — aggregated handwritten/printed score +flip_score [?, 1, 1] — aggregated flip score +``` + +**10 klas pisma (mapowanie z OCR config):** +| Index | Script | Recognizer Model | +|---|---|---| +| 0 | Latin | model_02 | +| 1 | CJK (Chinese/Japanese/Korean) | model_03 | +| 2 | Arabic | model_04 | +| 3 | Cyrillic | model_05 | +| 4 | Devanagari | model_06 | +| 5 | Greek | model_07 | +| 6 | Hebrew | model_08 | +| 7 | Tamil | model_09 | +| 8 | Thai | model_10 | +| 9 | Unknown/Mixed | fallback (Latin) | + +**Dodatkowe funkcje:** +- **Handwritten vs Printed (HWPC):** Klasyfikacja czy tekst jest pisany ręcznie czy drukowany. Wpływa na wybór trybu (mode) w config: `Auto`, `Printed`, `Mixed`, `Dummy`. +- **Flip Detection:** Wykrywa czy tekst jest odwrócony (góra-dół). DLL może automatycznie obrócić obraz o 180°. + +**Timing:** Load = 19 ms, Run = 6 ms — bardzo szybki + +### model_02 do model_10 — Recognizers (CTC-based OCR) + +**Architektura:** CNN encoder → RNN → CTC logits → LogSoftmax + +**Wejście (identyczne dla wszystkich):** +- `data` [1, 3, 60, W] float32 — RGB /255.0 (NIE ImageNet normalization!) +- `seq_lengths` [1] int32 — W/4 + +**Wyjście:** +- `output` [T, 1, num_classes] float32 — LogSoftmax probabilities + +**Preprocessing (KRYTYCZNE — odkryte metodą prób i błędów):** +```python +# ✅ POPRAWNE — daje "ONE OCR DZIALA!" +img_data = np.array(img_rgb, dtype=np.float32) / 255.0 + +# ❌ ZŁOŚNE — ImageNet mean/std daje "GNE OER SEIALA" +img_data = (img_data - [0.485, 0.456, 0.406]) / [0.229, 0.224, 0.225] + +# ❌ ŹLE — /127.5 - 1.0 daje bzdury +# ❌ ŹLE — brak normalizacji (surowe 0-255) też nie działa +``` + +**Tabela recognizerów:** + +| Model | Script | Klasy | Alfabet (char2ind) | T (timesteps) | Run (ms) | +|---|---|---|---|---|---| +| 02 | Latin | 221 | ASCII + diacritics + special | 60 | 1.9 | +| 03 | CJK | 32632 | Full CJK unified ideographs | 30 | 1.4 | +| 04 | Arabic | 415 | Arabic + Persian + Urdu | 30 | 6.7 | +| 05 | Cyrillic | 237 | Russian/Ukrainian/Serbian + Latin | 60 | 1.8 | +| 06 | Devanagari | 244 | Hindi/Sanskrit/Marathi + Latin | 60 | 2.0 | +| 07 | Greek | 201 | Greek alphabet + Latin | 60 | 4.5 | +| 08 | Hebrew | 548 | Hebrew + Yiddish + Arabic | 60 | 1.4 | +| 09 | Tamil | 179 | Tamil script + Latin | 60 | 1.3 | +| 10 | Thai | 199 | Thai script + Latin | 60 | 8.0 | + +**CTC Decode (Connectionist Temporal Classification):** +```python +def ctc_greedy_decode(log_probs, idx2char, blank_idx): + """Standard CTC greedy decoder.""" + # log_probs shape: [T, 1, num_classes] → [T, num_classes] + lp = log_probs[:, 0, :] + indices = np.argmax(lp, axis=-1) # best class per timestep + + # Remove blanks and repeated characters + chars, prev = [], -1 + for i in indices: + if i != prev and i != blank_idx: + chars.append(idx2char.get(int(i), f"[{i}]")) + prev = i + return "".join(chars) +``` + +**Wyniki testu na `image.png` ("ONE OCR DZIALA!"):** + +| Model | Script | Rozpoznany tekst | Poprawność | +|---|---|---|---| +| 02 | Latin | `ONE OCR DZIALA!` | ✅ 100% | +| 03 | CJK | `ONE OCR DZALAI` | ❌ zamienione litery | +| 04 | Arabic | `ONE OCR DZIALAY` | ❌ trailing Y | +| 05 | Cyrillic | `ONE OCR DZIALA!` | ✅ 100% | +| 06 | Devanagari | `ONE OCR DZIALA!` | ✅ 100% | +| 07 | Greek | `ONE OCR DZIALA!` | ✅ 100% | +| 08 | Hebrew | `ONE OCR DZIALA!` | ✅ 100% | +| 09 | Tamil | `ONE OGR DZIALA'` | ❌ G zamiast C, ' zamiast ! | +| 10 | Thai | `ONE OOR DZIALA!` | ❌ OOR zamiast OCR | + +**Wnioski:** +- Latin (02), Cyrillic (05), Devanagari (06), Greek (07), Hebrew (08) — idealne na łacince +- CJK (03) i Arabic (04) mają mniej łacińskich znaków → gorszy wynik +- Tamil (09) i Thai (10) — najgorsze na łacince, co jest oczekiwane + +### model_11 do model_21 — Language Model Small (LangSm) + +**Architektura:** DynamicQuantizeLSTM (quantized LSTM) + +**Domain:** `com.microsoft.oneocr` (NIE `com.microsoft`!) + +**Wejście:** +- `data` [1, 21, 1, 1] float32 — 21 features per frame + +**Wyjście:** +- `output` [1, 2] float32 — softmax binary classifier + +**Krytyczne odkrycie:** +Operator `DynamicQuantizeLSTM` **ISTNIEJE** w oficjalnym onnxruntime jako contrib op w domenie `com.microsoft` (potwierdzono w ContribOperators.md). Jednak modele OneOCR używają domeny `com.microsoft.oneocr`. To oznacza, że **remapowanie domeny** mogłoby sprawić, że te modele zadziałają! + +**Hipoteza funkcji:** Każda para (LangSm, LangMd) odpowiada jednemu skryptowi: + +| LangSm | LangMd | Script | Funkcja | +|---|---|---|---| +| 11 | 22 | Latin | Refine Latin predictions | +| 12 | 23 | CJK | Refine CJK predictions | +| 13 | 24 | Arabic | Refine Arabic predictions | +| 14 | 25 | Cyrillic | Refine Cyrillic predictions | +| 15 | 26 | Devanagari | Refine Devanagari predictions | +| 16 | 27 | Greek | Refine Greek predictions | +| 17 | 28 | Hebrew | Refine Hebrew predictions | +| 18 | 29 | Tamil | Refine Tamil predictions | +| 19 | 30 | Thai | Refine Thai predictions | +| 20 | 31 | ??? | Extra (maybe mixed?) | +| 21 | 32 | ??? | Extra (maybe handwritten?) | + +**Rozmiar:** ~26 KB (LangSm), ~28 KB (LangMd) — mikroskopijne modele + +### model_22 do model_32 — Language Model Medium (LangMd) + +Identyczna architektura jak LangSm, ale: +- Input shape: `[1, 21, 1, 1]` → ten sam +- Output: `softmax[2]` (bez batch dim) zamiast `softmax[1, 2]` +- Nieco większe (~28 KB vs ~26 KB) — więcej parametrów LSTM + +**Funkcja:** Prawdopodobnie drugi etap refinementu — LangSm daje szybką wstępną ocenę, LangMd daje dokładniejszą analizę kontekstową. + +### model_33 — LineLayout + +**Architektura:** CNN + custom feature extractor + +**Wejście:** +- `data` [1, 3, 60, ?] float32 — similar to recognizers + +**Wyjścia:** +- `line_layout_perframe_predict` [?, ?, 2] — per-frame line segmentation +- `line_layout_score` [?, 1, 1] — aggregated score + +**Custom Op:** `OneOCRFeatureExtract` — **NIE istnieje** w standardowym onnxruntime. To prawdziwy custom op specyficzny dla OneOCR DLL. + +**Funkcja:** Predykcja layoutu linii — prawdopodobnie segmentuje obraz na linie tekstu (top/bottom boundaries), co pomaga w grupowaniu wyrazów w linie i paragrafów. + +## 1.6 OCR Config — Routing Pipeline + +Z pliku `chunk_66_ocr_config.config.txt`: + +``` +Script → Mode → CharModel → Decoder → ConfidenceRejection + +Latin → Auto/Printed/Mixed → char_model_path = /recognizers/latin +CJK → Auto/Printed/Mixed → char_model_path = /recognizers/cjk +Arabic → Auto/Printed → char_model_path = /recognizers/arabic +Cyrillic → Auto/Printed/Mixed → char_model_path = /recognizers/cyrillic +Devanagari → Auto/Printed → char_model_path = /recognizers/devanagari +Greek → Auto/Printed → char_model_path = /recognizers/greek +Hebrew → Auto/Printed → char_model_path = /recognizers/hebrew +Tamil → Auto/Printed → char_model_path = /recognizers/tamil +Thai → Auto/Printed → char_model_path = /recognizers/thai +``` + +Tryby (`Mode`): +- **Auto** — automatyczny wybór na podstawie ScriptID +- **Printed** — optymalizowany pod drukowany tekst +- **Mixed** — handwritten + printed mixed content +- **Dummy** — placeholder/fallback + +## 1.7 Porównanie DLL vs Pure ONNX + +| Feature | DLL (`oneocr.dll`) | Pure ONNX | Gap | +|---|---|---|---| +| **Platforma** | Windows x64 only | Any (Linux/Mac/Win/ARM) | ✅ ONNX wygrywa | +| **Detekcja tekstu** | Full (bounding boxes) | Raw FPN maps | 🔴 Brak PP | +| **Bounding boxy** | 4-punkt quadrilateral | Brak | 🔴 Krytyczny brak | +| **Image angle** | GetImageAngle() | Brak | 🟡 Brak | +| **Text recognition** | Pełny pipeline | CTC decode działa | ✅ Porównywalne | +| **Confidence** | Per-word float | Z logprobs ✅ | ✅ Porównywalne | +| **Script detection** | Automatyczny | model_01 ✅ | ✅ Porównywalne | +| **Language model** | Built-in | Custom ops 🔴 | 🟡 Obejście możliwe | +| **Multi-script** | Auto-switch | Manual | 🟡 Implementowalne | +| **Rozmiar** | ~100 MB (DLL+ORT+model) | ~45 MB (11 ONNX) | ✅ ONNX mniejsze | +| **Latency (text only)** | ~50-100 ms | ~30 ms (recognizer only) | ✅ ONNX szybsze | +| **Dependencies** | oneocr.dll, ort.dll | onnxruntime, numpy | ✅ ONNX prostsze | + +--- + +# FAZA 2 — Generowanie pomysłów (20 idei) {#faza-2} + +## Strategia: Jak osiągnąć pełną cross-platform niezależność? + +### Idea 1: Domain Remapping dla DynamicQuantizeLSTM +**Opis:** Modyfikacja grafów ONNX model_11-32 — zmiana domeny z `com.microsoft.oneocr` na `com.microsoft`. +Operator `DynamicQuantizeLSTM` istnieje w standardowym onnxruntime jako contrib op. +**Zalety:** Minimalny wysiłek, 22 modele nagle działają. +**Ryzyka:** Może się różnić API/implementacja. Trzeba przetestować outputs. + +### Idea 2: Reimplementacja DynamicQuantizeLSTM w Python/NumPy +**Opis:** Napisanie custom LSTM z dynamiczną kwantyzacją w pure Python. +Input: X[seq_len, batch, input_size], W/R quantized int8, scale/zero_point. +**Zalety:** Pełna kontrola, zero zależności. +**Ryzyka:** Performance (Python LSTM jest wolny), złożoność implementacji. + +### Idea 3: PixelLink Post-Processing w Python/OpenCV +**Opis:** Implementacja pełnego PL decode: sigmoid scores → link analysis → connected components → minAreaRect → quads. +**Zalety:** Daje bounding boxy cross-platform. OpenCV jest cross-platform. +**Ryzyka:** Złożoność 3-level FPN merge. Trzeba dobrać thresholdy. + +### Idea 4: Rejestracja Custom Ops via onnxruntime custom op API +**Opis:** Napisanie C++/Python custom op library dla onnxruntime, rejestracja `DynamicQuantizeLSTM` i `OneOCRFeatureExtract`. +**Zalety:** Maximum performance (C++ level). +**Ryzyka:** Duży nakład pracy. `OneOCRFeatureExtract` jest nieudokumentowany — trzeba reverse-engineerować. + +### Idea 5: Skip Language Models — pure CTC decode +**Opis:** Pominięcie model_11-32 i model_33. Używanie tylko CTC greedy decode z recognizerów. +**Zalety:** Zero dodatkowej pracy. Już działa! +**Ryzyka:** Nieco niższa accuracy (brak language model refinement). Ale testy pokazują 96.3% nawet bez LM. + +### Idea 6: Zastąpienie LM zewnętrznym spell-checkerem +**Opis:** Zamiast modeli 11-32, użycie bibliotek jak `pyspellchecker`, `symspellpy`, lub Hunspell. +**Zalety:** Cross-platform, dobrze przetestowane, wielojęzyczne. +**Ryzyka:** Inne podejście niż oryginalny LM. Nie zoptymalizowany pod OCR-specific errors. + +### Idea 7: Export modeli do TorchScript/TensorFlow Lite +**Opis:** Konwersja ONNX → PyTorch/TF format, omijając custom ops. +**Zalety:** Inne runtime'y mogą mieć lepsze wsparcie dla custom ops. +**Ryzyka:** Konwersja może być stratna. Nowe zależności. + +### Idea 8: Tesseract jako fallback detektor +**Opis:** Użycie Tesseract OCR do detekcji tekstu (bounding boxy), a OneOCR recognizerów do rozpoznawania. +**Zalety:** Tesseract daje bounding boxy cross-platform. +**Ryzyka:** Jakość detekcji Tesseracta bywa gorsza. Mismatch z OneOCR expectations. + +### Idea 9: EAST/DB text detector zamiast PixelLink +**Opis:** Zastąpienie model_00 gotowym cross-platform text detectorem (EAST, DBNet, CRAFT). +**Zalety:** Dobrze udokumentowane, gotowe implementacje w Python. +**Ryzyka:** Inny format bboBox (nie quad). Potencjalnie gorszy dla rotated text. + +### Idea 10: Hybrid mode — DLL na Windows, pure ONNX fallback +**Opis:** Architektura z auto-wykrywaniem platformy: if Windows + DLL available → use DLL, else → fallback to pure ONNX. +**Zalety:** Zachowuje full quality na Windows, dodaje cross-platform support. +**Ryzyka:** Complexity of maintaining dual codepath. + +### Idea 11: WASM/Emscripten build onnxruntime z custom ops +**Opis:** Budowa onnxruntime z WASM z wkompilowanym `DynamicQuantizeLSTM`, deploy jako web app. +**Zalety:** Działa w przeglądarce na każdej platformie. +**Ryzyka:** Performance (WASM jest wolniejszy). Complexity. + +### Idea 12: Image angle estimation via model_01 flip_score +**Opis:** Wykorzystanie `flip_score` z ScriptID do określenia czy obraz jest odwrócony, + heurystyki (np. górny/dolny baseline) do estymacji kąta. +**Zalety:** Częściowo odtwarza GetImageAngle(). +**Ryzyka:** Mniej dokładne niż dedykowany DLL angle detector. + +### Idea 13: onnxruntime-extensions Python wheel +**Opis:** Pakiet `onnxruntime-extensions` od Microsoft ma dodatkowe custom ops. Sprawdzić czy `DynamicQuantizeLSTM` jest tam. +**Zalety:** Oficjalne wsparcie Microsoft. +**Ryzyka:** Może nie zawierać `oneocr`-specific ops. + +### Idea 14: Beam Search CTC decode zamiast greedy +**Opis:** Zamiana greedy CTC decode na beam search z language model priors (z `rnn_info` plików — LogPrior probabilities). +**Zalety:** Lepsza accuracy bez potrzeby modeli 11-32. Wykorzystuje istniejące `rnn_info` pliki z char2ind. +**Ryzyka:** Wolniejsze niż greedy. Wymaga implementacji. + +### Idea 15: CRAFT text detection + OneOCR recognizers +**Opis:** CRAFT (Character Region Awareness for Text detection) jest dostępny jako gotowy Python package. Daje per-character bounding boxy. +**Zalety:** Lepsza granularity niż PixelLink. Cross-platform. +**Ryzyka:** Inny model (nie z OneOCR ecosystem). Rozmiar dodatkowego modelu. + +### Idea 16: Progressive enhancement — 3 tiers +**Opis:** Tier 1: Pure ONNX (recognizer only, tekst bez boxów). Tier 2: + PixelLink PP (tekst + bounding boxy). Tier 3: + Language models. +**Zalety:** Incremental implementation. Każdy tier daje wartość. +**Ryzyka:** Maintenance 3 code paths. + +### Idea 17: OpenCV DNN moduł do inferencji +**Opis:** OpenCV ma moduł DNN obsługujący ONNX. Sprawdzić czy obsługuje QLinearConv i inne kwantyzowane ops. +**Zalety:** Single dependency (OpenCV), cross-platform. +**Ryzyka:** OpenCV DNN ma ograniczone wsparcie dla kwantyzowanych modeli. + +### Idea 18: Dequantize models → FP32 +**Opis:** Konwersja kwantyzowanych modeli (QLinearConv, QLinearSigmoid) do pełnej precyzji FP32. Usunięcie custom quantized ops. +**Zalety:** Kompatybilność z każdym ONNX runtime. +**Ryzyka:** 2-4x większe modele. Potencjalnie wolniejsze. Zmiana accuracy. + +### Idea 19: Native PixelLink w Rust/C++ z Python binding +**Opis:** PixelLink decode jako compiled library (Rust via PyO3, lub C++ via pybind11) z Python API. +**Zalety:** Maximum performance. System-agnostic (no Windows dependency). +**Ryzyka:** Wymaga Rust/C++ toolchain. Compilation complexity. + +### Idea 20: Wine/Proton compatibility layer na Linux +**Opis:** Uruchomienie oneocr.dll pod Wine na Linux. +**Zalety:** Zero changes do kodu. Pełna kompatybilność. +**Ryzyka:** Wine overhead, instability, nie działa na ARM/Mac. Nie jest "prawdziwie" cross-platform. + +--- + +# FAZA 3 — Matryca porównawcza i strategie decyzyjne {#faza-3} + +## 3.1 Kryteria oceny + +| Kryterium | Waga | Opis | +|---|---|---| +| **Wysiłek implementacji** | 25% | Ile czasu/kodu potrzeba | +| **Jakość OCR** | 25% | Jak blisko do DLL output | +| **Cross-platform** | 20% | Linux/Mac/Win/ARM support | +| **Performance** | 15% | Latency, throughput | +| **Maintenance** | 15% | Łatwość utrzymania | + +## 3.2 Matryca porównawcza (ocena 1-5, 5=best) + +| # | Idea | Wysiłek | Jakość | Cross-plat | Perf | Maint | **TOTAL** | +|---|---|---|---|---|---|---|---| +| 1 | Domain Remapping LSTM | 5 | 4 | 5 | 5 | 5 | **4.75** | +| 3 | PixelLink PP Python | 3 | 5 | 5 | 3 | 4 | **3.95** | +| 5 | Skip LM (pure CTC) | 5 | 3 | 5 | 5 | 5 | **4.45** | +| 10 | Hybrid DLL/ONNX | 3 | 5 | 4 | 5 | 2 | **3.75** | +| 14 | Beam search + rnn_info | 3 | 4 | 5 | 3 | 4 | **3.80** | +| 16 | Progressive 3-tier | 3 | 4 | 5 | 4 | 3 | **3.75** | +| 6 | External spell-checker | 4 | 3 | 5 | 4 | 4 | **3.95** | +| 2 | Reimpl. LSTM Python | 2 | 4 | 5 | 2 | 3 | **3.15** | +| 4 | Custom ops C++ | 2 | 5 | 4 | 5 | 2 | **3.45** | +| 8 | Tesseract fallback | 4 | 2 | 5 | 3 | 4 | **3.50** | +| 9 | EAST/DB/CRAFT detector | 3 | 3 | 5 | 3 | 3 | **3.30** | +| 12 | flip_score angle est. | 4 | 2 | 5 | 5 | 5 | **3.95** | +| 15 | CRAFT + OneOCR recog | 3 | 3 | 5 | 3 | 3 | **3.35** | +| 18 | Dequantize to FP32 | 3 | 3 | 5 | 2 | 4 | **3.35** | +| 19 | Rust PixelLink | 2 | 5 | 5 | 5 | 2 | **3.65** | +| 20 | Wine/Proton | 5 | 5 | 2 | 3 | 1 | **3.15** | + +## 3.3 TOP 5 po ważonym rankingu + +| Rank | Idea | Score | Rekomendacja | +|---|---|---|---| +| 🥇 1 | **Domain Remapping LSTM** | 4.75 | Natychmiastowy quick-win | +| 🥈 2 | **Skip LM (pure CTC)** | 4.45 | Natychmiastowe fallback | +| 🥉 3 | **PixelLink PP Python** | 3.95 | Kluczowy missing piece | +| 4 | **External spell-checker** | 3.95 | Alternatywa LM | +| 5 | **flip_score angle est.** | 3.95 | Quick-win na angle | + +## 3.4 Strategie decyzyjne + +### Strategia A: Quick-Win First (rekomendowana) +``` +1. Domain Remapping (Idea 1) → odblokuj 22 modele LM +2. Skip LM fallback (Idea 5) → jeśli remapping nie zadziała +3. PixelLink PP (Idea 3) → dodaj bounding boxy +4. flip_score angle (Idea 12) → dodaj angle estimation +``` +**Czas:** ~2-4 tygodnie. **Pokrycie:** ~85% funkcjonalności DLL. + +### Strategia B: Maximum Quality +``` +1. PixelLink PP w Rust (Idea 19) → performance + bounding boxy +2. Custom ops C++ (Idea 4) → pełna kompatybilność +3. Beam search CTC (Idea 14) → najlepsza accuracy +``` +**Czas:** ~2-3 miesiące. **Pokrycie:** ~95% funkcjonalności DLL. + +### Strategia C: Progressive Enhancement (Idea 16) +``` +Tier 1 (tydzień): Pure CTC + ScriptID → tekst + script detection +Tier 2 (2 tygodnie): + PixelLink PP → tekst + bounding boxy +Tier 3 (miesiąc): + LM (remapped/reimplemented) → refined accuracy +``` +**Czas:** progressive. **Pokrycie:** rośnie z każdym tierem. + +--- + +# FAZA 4 — Deep-dive top 3 rozwiązań {#faza-4} + +## 4.1 Deep-dive: Domain Remapping DynamicQuantizeLSTM + +### Problem +Modele 11-32 używają `DynamicQuantizeLSTM` z domeny `com.microsoft.oneocr`. +Standard onnxruntime ma identyczny operator w domenie `com.microsoft`. + +### Implementacja + +```python +import onnx + +def remap_oneocr_domain(model_path, output_path): + """Remap com.microsoft.oneocr → com.microsoft for DynamicQuantizeLSTM.""" + model = onnx.load(model_path) + + # 1. Remap domain in all nodes + for node in model.graph.node: + if node.domain == "com.microsoft.oneocr": + if node.op_type == "DynamicQuantizeLSTM": + node.domain = "com.microsoft" + # OneOCRFeatureExtract cannot be remapped — it's truly custom + + # 2. Update opset imports + new_imports = [] + has_ms = False + for opset in model.opset_import: + if opset.domain == "com.microsoft.oneocr": + continue # Remove oneocr domain + if opset.domain == "com.microsoft": + has_ms = True + new_imports.append(opset) + if not has_ms: + ms_opset = onnx.OperatorSetIdProto() + ms_opset.domain = "com.microsoft" + ms_opset.version = 1 + new_imports.append(ms_opset) + + del model.opset_import[:] + model.opset_import.extend(new_imports) + + onnx.save(model, output_path) + return model +``` + +### Weryfikacja + +```python +import onnxruntime as ort +import numpy as np + +# After remapping +sess = ort.InferenceSession("model_11_remapped.onnx", + providers=["CPUExecutionProvider"]) +# Test inference +data = np.random.randn(1, 21, 1, 1).astype(np.float32) +result = sess.run(None, {"data": data}) +print(f"LangSm output: {result[0]}") # Should be [1, 2] softmax +``` + +### Ryzyka i mitygacja +1. **API mismatch** — parametry mogą się różnić między `com.microsoft.oneocr.DynamicQuantizeLSTM` a `com.microsoft.DynamicQuantizeLSTM`. Mitygacja: porównanie atrybutów node. +2. **Wersja onnxruntime** — contrib ops mogą wymagać specific version. Mitygacja: test na najnowszym ORT. +3. **Output compatibility** — wynik może być nieco inny. Mitygacja: porównanie z DLL output. + +### Ocena szans sukcesu: **80-90%** +DynamicQuantizeLSTM to oficjalnie wspierany contrib op. Różnica to tylko domain name. + +## 4.2 Deep-dive: PixelLink Post-Processing w Python + +### Problem +model_00 daje 19 raw tensor outputs (FPN scores, link scores, bbox deltas). +Potrzebujemy: lista bounding boxów (4-punktowe quady) + confidence per box. + +### Architektura PixelLink (AAAI 2018) + +``` + Input Image + │ + ┌────┴────┐ + │ VGG16 │ (or ResNet backbone) + └────┬────┘ + │ + ┌──────────┼──────────┐ + ▼ ▼ ▼ + FPN P2 FPN P3 FPN P4 + (1/4) (1/8) (1/16) + │ │ │ + ▼ ▼ ▼ + ┌────────┴──┐ ┌───┴──┐ ┌───┴──┐ + │ Pixel │ │ ... │ │ ... │ + │ Pred │ │ │ │ │ + │ (2 class) │ │ │ │ │ + └────────┬──┘ └───┬──┘ └───┬──┘ + │ │ │ + ┌────────┴──┐ ┌───┴──┐ ┌───┴──┐ + │ Link │ │ ... │ │ ... │ + │ Pred │ │ │ │ │ + │ (16 class)│ │ │ │ │ + │ 8 neigh. │ │ │ │ │ + │ ×2(pos/neg│ │ │ │ │ + └───────────┘ └──────┘ └──────┘ + │ │ │ + └────┬─────┘──────┘ + │ + ▼ + Connected Components + (Union-Find on links) + │ + ▼ + minAreaRect per component + │ + ▼ + 4-point Quadrilateral Bboxes +``` + +### Implementacja Python + +```python +import numpy as np +import cv2 +from typing import List, Tuple + + +class PixelLinkDecoder: + """Cross-platform PixelLink post-processor.""" + + def __init__(self, + pixel_threshold: float = 0.7, + link_threshold: float = 0.7, + min_area: int = 300, + min_height: int = 10): + self.pixel_threshold = pixel_threshold + self.link_threshold = link_threshold + self.min_area = min_area + self.min_height = min_height + + def decode(self, outputs: dict, im_info: np.ndarray) -> List[np.ndarray]: + """ + Decode PixelLink outputs to bounding box quads. + + Args: + outputs: dict of 19 tensor outputs from model_00 + im_info: [height, width, scale] + + Returns: + List of 4-point quads [[x1,y1], [x2,y2], [x3,y3], [x4,y4]] + """ + # Process each FPN level + all_bboxes = [] + for level in [2, 3, 4]: + bboxes = self._decode_level(outputs, level, im_info) + all_bboxes.extend(bboxes) + + # NMS across levels + bboxes = self._nms(all_bboxes) + + # Scale back to original image + scale = im_info[0, 2] + for i in range(len(bboxes)): + bboxes[i] = bboxes[i] / scale + + return bboxes + + def _decode_level(self, outputs, level, im_info): + """Decode single FPN level.""" + # Get horizontal text predictions + scores = self._sigmoid(outputs[f'scores_hori_fpn{level}']) + link_scores = self._sigmoid(outputs[f'link_scores_hori_fpn{level}']) + + # Binarize + pixel_mask = scores[0, 0] > self.pixel_threshold + # link_scores shape: [1, 16, H, W] → reshape to [H, W, 8, 2] + link_probs = link_scores[0].transpose(1, 2, 0) # [H, W, 16] + link_probs = link_probs.reshape(link_probs.shape[0], link_probs.shape[1], 8, 2) + link_mask = link_probs[:, :, :, 1] > self.link_threshold # positive links + + # Connected components via Union-Find + labels = self._connected_components(pixel_mask, link_mask) + + # Extract bounding boxes + bboxes = [] + for label_id in range(1, labels.max() + 1): + points = np.argwhere(labels == label_id) # [N, 2] (row, col) + if len(points) < 10: + continue + + # Convert to (col, row) = (x, y) + points_xy = points[:, ::-1].astype(np.float32) + + # Scale to original FPN coord space + stride = 2 ** level + points_xy *= stride + + # minAreaRect → 4-point quad + rect = cv2.minAreaRect(points_xy) + quad = cv2.boxPoints(rect) + + # Filter by area and height + w, h = rect[1] + area = w * h + if area < self.min_area or min(w, h) < self.min_height: + continue + + bboxes.append(quad) + + return bboxes + + def _connected_components(self, pixel_mask, link_mask): + """Union-Find connected components using pixel-link.""" + H, W = pixel_mask.shape + labels = np.zeros((H, W), dtype=np.int32) + parent = {} # Union-Find parent + + def find(x): + while parent[x] != x: + parent[x] = parent[parent[x]] + x = parent[x] + return x + + def union(a, b): + ra, rb = find(a), find(b) + if ra != rb: + parent[ra] = rb + + # 8-connected neighbors offsets + neighbors = [(-1,-1), (-1,0), (-1,1), (0,-1), + (0,1), (1,-1), (1,0), (1,1)] + + label_id = 0 + for r in range(H): + for c in range(W): + if not pixel_mask[r, c]: + continue + label_id += 1 + labels[r, c] = label_id + parent[label_id] = label_id + + # Check links to already-visited neighbors + for k, (dr, dc) in enumerate(neighbors[:4]): # top-left, top, top-right, left + nr, nc = r + dr, c + dc + if 0 <= nr < H and 0 <= nc < W: + if pixel_mask[nr, nc] and link_mask[r, c, k]: + neighbor_label = labels[nr, nc] + if neighbor_label > 0: + union(label_id, neighbor_label) + + # Relabel + final_labels = np.zeros_like(labels) + label_map = {} + new_id = 0 + for r in range(H): + for c in range(W): + if labels[r, c] == 0: + continue + root = find(labels[r, c]) + if root not in label_map: + new_id += 1 + label_map[root] = new_id + final_labels[r, c] = label_map[root] + + return final_labels + + @staticmethod + def _sigmoid(x): + return 1.0 / (1.0 + np.exp(-x)) + + def _nms(self, bboxes, iou_threshold=0.3): + """Simple polygon NMS.""" + if len(bboxes) <= 1: + return bboxes + # Sort by area descending + areas = [cv2.contourArea(b.astype(np.float32)) for b in bboxes] + indices = np.argsort(areas)[::-1] + keep = [] + suppressed = set() + for i in indices: + if i in suppressed: + continue + keep.append(bboxes[i]) + for j in indices: + if j in suppressed or j == i: + continue + iou = self._polygon_iou(bboxes[i], bboxes[j]) + if iou > iou_threshold: + suppressed.add(j) + return keep + + @staticmethod + def _polygon_iou(poly1, poly2): + """Approximate IoU via bounding rect overlap.""" + r1 = cv2.boundingRect(poly1.astype(np.float32)) + r2 = cv2.boundingRect(poly2.astype(np.float32)) + x1 = max(r1[0], r2[0]) + y1 = max(r1[1], r2[1]) + x2 = min(r1[0]+r1[2], r2[0]+r2[2]) + y2 = min(r1[1]+r1[3], r2[1]+r2[3]) + inter = max(0, x2-x1) * max(0, y2-y1) + union = r1[2]*r1[3] + r2[2]*r2[3] - inter + return inter / (union + 1e-6) +``` + +### Wyzwania +1. **3-level FPN merge:** Trzeba scalić detekcje z fpn2 (1/4), fpn3 (1/8), fpn4 (1/16) +2. **Hori vs Vert:** Model daje osobne scores dla horizontal i vertical tekstu +3. **bbox_deltas:** Mogą być potrzebne do refinementu pozycji bboxów +4. **Próg (threshold):** Trzeba dostroić empirycznie +5. **Performance:** Union-Find w Python będzie wolny na dużych obrazach → potrzebna Cython/NumPy optymalizacja + +### Ocena szans sukcesu: **70-80%** +Algorytm jest dobrze znany, ale implementacja wymagania dokładna kalibracja progów. + +## 4.3 Deep-dive: Progressive Enhancement (3-Tier Architecture) + +### Tier 1 — Natychmiastowy (już działa!) + +```python +class OneOCREngineTier1: + """Pure ONNX: recognizer + script detection. No bboxes.""" + + def __init__(self, models_dir, config_dir): + self.script_id = load_model(models_dir / "model_01.onnx") + self.recognizers = { + script: load_model(models_dir / f"model_{i:02d}.onnx") + for script, i in SCRIPT_MAP.items() + } + self.char_maps = load_char_maps(config_dir) + + def recognize(self, image: PIL.Image) -> str: + """Recognize text from image. Returns plain text.""" + data = preprocess(image) # RGB /255.0, resize H=60 + seq_len = np.array([data.shape[3] // 4], dtype=np.int32) + + # 1. Detect script + script_id = self._detect_script(data, seq_len) + + # 2. Recognize with appropriate model + recognizer = self.recognizers[script_id] + logprobs = recognizer.run(None, {"data": data, "seq_lengths": seq_len})[0] + + # 3. CTC decode + text = ctc_greedy_decode(logprobs, self.char_maps[script_id]) + return text + + def _detect_script(self, data, seq_len): + outputs = self.script_id.run(None, {"data": data, "seq_lengths": seq_len}) + script_scores = outputs[3] # script_id_score [1,1,10] + return int(np.argmax(script_scores)) +``` + +**Możliwości:** tekst, script detection, confidence +**Brakuje:** bounding boxy, angle, language model + +### Tier 2 — Dodanie bounding boxów (+2-3 tygodnie) + +```python +class OneOCREngineTier2(OneOCREngineTier1): + """+ PixelLink text detection → bounding boxes.""" + + def __init__(self, models_dir, config_dir): + super().__init__(models_dir, config_dir) + self.detector = load_model(models_dir / "model_00.onnx") + self.pixellink = PixelLinkDecoder() + + def recognize_with_boxes(self, image: PIL.Image) -> OcrResult: + """Full OCR with bounding boxes.""" + # 1. Detect text regions + bboxes = self._detect_text(image) + + # 2. For each bbox → crop → recognize + lines = [] + for bbox in bboxes: + crop = self._crop_perspective(image, bbox) + text, confidence = self._recognize_crop(crop) + word = OcrWord(text=text, bounding_rect=bbox, confidence=confidence) + lines.append(word) + + # 3. Group words into lines (simple y-coordinate grouping) + lines = self._group_into_lines(lines) + + return OcrResult(text=full_text, lines=lines) +``` + +**Dodaje:** bounding boxy (quady), per-word recognition, line grouping + +### Tier 3 — Language models + angle (+1-2 tygodnie) + +```python +class OneOCREngineTier3(OneOCREngineTier2): + """+ Language model refinement + angle detection.""" + + def __init__(self, models_dir, config_dir): + super().__init__(models_dir, config_dir) + self.lang_models = self._load_language_models(models_dir) + # model_33 LineLayout — only if OneOCRFeatureExtract resolved + + def _refine_with_lm(self, text, logprobs, script_id): + """Apply language model for refinement.""" + if self.lang_models: + # Use remapped DynamicQuantizeLSTM models + lm_small = self.lang_models[script_id]['small'] + lm_medium = self.lang_models[script_id]['medium'] + # ... apply LM scoring + else: + # Fallback: beam search with rnn_info priors + text = beam_search_decode(logprobs, self.rnn_info[script_id]) + return text +``` + +--- + +# FAZA 5 — Analiza kontekstowa Good vs Bad {#faza-5} + +## 5.1 Kiedy każde rozwiązanie jest DOBRE + +### Domain Remapping — DOBRE gdy: +- ✅ Chcemy szybko odblokować 22 modele (same-day fix) +- ✅ API `DynamicQuantizeLSTM` jest identyczne w obu domenach +- ✅ Nie potrzebujemy `OneOCRFeatureExtract` (model_33 pomijamy) +- ✅ Celujemy w standardowy onnxruntime (pip install) +- ✅ Nie chcemy żadnych dodatkowych zależności + +### PixelLink PP — DOBRE gdy: +- ✅ Potrzebujemy bounding boxów (lokalizacja tekstu na obrazie) +- ✅ Pracujemy z obrazami z wieloma regionami tekstu +- ✅ Tekst może być rotowany/pochylony (quady nie prostokąty) +- ✅ Integrujemy z UI (rysowanie boxów na screenshotach) +- ✅ Mamy OpenCV jako zależność + +### Progressive Enhancement — DOBRE gdy: +- ✅ Chcemy zacząć używać natychmiast (Tier 1 = dzisiaj) +- ✅ Team jest mały — nie da się zrobić wszystkiego od razu +- ✅ Chcemy testować jakość na każdym etapie +- ✅ Różni użytkownicy potrzebują różnych features + +## 5.2 Kiedy każde rozwiązanie jest ZŁE + +### Domain Remapping — ZŁE gdy: +- ❌ API `DynamicQuantizeLSTM` się różni (choć mało prawdopodobne) +- ❌ Potrzebujemy `OneOCRFeatureExtract` (model_33 — line layout) +- ❌ Używamy starszej wersji onnxruntime bez tego contrib op +- ❌ Modele mają dodatkowe atrybuty specyficzne dla OneOCR + +### PixelLink PP — ZŁE gdy: +- ❌ Nie potrzebujemy bounding boxów (np. tylko full-screen OCR) +- ❌ Performance jest krytyczny (PP na dużych obrazach = wolny w Python) +- ❌ Obraz zawiera TYLKO tekst (np. screenshot subtitli gry) +- ❌ Nie chcemy zależności od OpenCV + +### Progressive Enhancement — ZŁE gdy: +- ❌ Potrzebujemy 100% kompatybilności z DLL od dnia 1 +- ❌ Maintenance 3 code paths jest zbyt dużo +- ❌ Użytkownicy oczekują pełnych features od razu + +## 5.3 Macierz ryzyk + +| Ryzyko | Prawdopod. | Wpływ | Mitygacja | +|---|---|---|---| +| Domain remap nie zadziała | 10-20% | Wysoki | Fallback: Skip LM (Idea 5) | +| PixelLink PP daje złe bboxes | 20-30% | Średni | Kalibracja thresholdów, testy na wielu obrazach | +| Performance PP za wolny | 40% | Średni | Cython optimization, GPU acceleration | +| model_33 (LineLayout) nieodtwarzalny | 60% | Niski | Heurystyczny line grouping (y-sort) | +| GetImageAngle() nieodtwarzalny | 50% | Niski | flip_score z model_01, +CV heuristics | +| char2ind mapowanie błędne | 5% | Wysoki | Już przetestowane i działa ✅ | +| Standard ORT nie ma DynQuantLSTM | 5% | Wysoki | Dostępny od ORT 1.5+ ✅ | + +--- + +# FAZA 6 — Finalna rekomendacja {#faza-6} + +## Rekomendowana strategia: **Progressive Enhancement + Domain Remapping** + +Łączę Strategię A (Quick-Win) z Ideą 16 (Progressive): + +### Krok 1: ✅ NATYCHMIASTOWY (dzisiaj) — Tier 1 +**Status: JUŻ DZIAŁAMY!** +- Pure CTC z recognizerami (model_02-10) +- ScriptID (model_01) do auto-detect pisma +- Confidence z logprobs +- **Wynik:** Tekst rozpoznany z 96.3% accuracy (na "ONE OCR DZIALA!") + +### Krok 2: Domain Remapping (1 dzień) +- Remapuj domeny w model_11-32 (`com.microsoft.oneocr` → `com.microsoft`) +- Test: czy onnxruntime standardowy ładuje remapped modele +- Jeśli TAK → 22 dodatkowe modele odblokowane (LM refinement) +- Jeśli NIE → skip LM, fallback do pure CTC (i tak 96%+ accuracy) + +### Krok 3: PixelLink Post-Processing (1-2 tygodnie) +- Implementacja PL decode w Python + OpenCV +- Priority: horizontal text detection (scores_hori_*) +- Test na obrazach z wieloma liniami tekstu +- **Wynik:** Bounding boxy (4-punkt quady), per-word i per-line + +### Krok 4: Pipeline Integration (1 tydzień) +- Nowa klasa `OneOCRCrossPlatform` w `ocr/engine_onnx.py` +- Interfejs identyczny z `OcrEngine` (recognize_pil → OcrResult) +- Auto-detect: if Windows + DLL → use DLL, else → pure ONNX +- **Wynik:** Drop-in replacement + +### Krok 5: Opcjonalne ulepszenia (ongoing) +- Beam search CTC z rnn_info priors +- Image angle estimation via flip_score + heuristics +- model_33 LineLayout — czeka na rozwiązanie `OneOCRFeatureExtract` +- Performance optimization (Cython for PixelLink decode) + +## Architektura docelowa + +``` +ocr/ +├── __init__.py — public API exports +├── engine.py — Windows DLL wrapper (existing) +├── engine_onnx.py — NEW: cross-platform ONNX engine +├── engine_factory.py — NEW: auto-select engine based on platform +├── pixellink.py — NEW: PixelLink post-processing +├── ctc_decoder.py — NEW: CTC greedy + beam search decoder +├── models.py — data classes (existing) +├── profiles.py — capture profiles (existing) +├── screen_capture.py — screen capture (existing) +├── dedup.py — deduplication (existing) +└── region_selector.py — region selection (existing) +``` + +### engine_factory.py + +```python +import platform +from pathlib import Path + +def create_engine(model_path: str = None, prefer_dll: bool = True): + """Create OCR engine — DLL on Windows, ONNX everywhere else.""" + if prefer_dll and platform.system() == "Windows": + try: + from ocr.engine import OcrEngine + engine = OcrEngine() + engine.initialize(model_path) + return engine + except Exception: + pass # Fall through to ONNX + + from ocr.engine_onnx import OcrEngineOnnx + return OcrEngineOnnx(model_path) +``` + +--- + +# FAZA 7 — Podsumowanie i Action Plan {#faza-7} + +## 7.1 Podsumowanie kluczowych odkryć + +### O modelach +1. **34 modele ONNX** tworzą pełny pipeline: detekcja → script ID → recognition → LM → layout +2. **11 modeli** działa od razu w standardowym onnxruntime (detector + scriptID + 9 recognizers) +3. **22 modele** (LM small/medium) używają `DynamicQuantizeLSTM` — **oficjalny contrib op** w onnxruntime, tylko zmieniona domena +4. **1 model** (LineLayout) używa `OneOCRFeatureExtract` — prawdziwy custom op, nieodtwarzalny +5. Detektor (model_00) to **PixelLink z 3-level FPN** — 19 wyjść, ~90% czasu inferencji +6. Recognizery używają **CTC z /255.0 normalizacją** (NIE ImageNet!) + +### O pipeline +7. DLL realizuje pełny pipeline: obraz → bboxes → script → text → LM → lines +8. Pure ONNX daje **~96% accuracy na tekście** nawet bez language models +9. Główny brak: **PixelLink post-processing** (bounding boxy) — do implementacji w Python +10. Image angle detection — w DLL, nie w modelach ONNX + +### O cross-platform +11. **DynamicQuantizeLSTM domain remapping** — prawdopodobnie rozwiąże 22/23 zablokowanych modeli +12. PixelLink PP jest implementowalny w Python + OpenCV (cross-platform) +13. Pełna niezależność od Windows jest osiągalna w ~85-95% funkcjonalności + +## 7.2 Performance Summary + +| Komponent | Load (ms) | Run (ms) | % Total Run | +|---|---|---|---| +| Detector (model_00) | 326 | 294 | 89.4% | +| ScriptID (model_01) | 19 | 6 | 1.8% | +| Recognizers (9 modeli) | 166 | 29 | 8.8% | +| **TOTAL (11 modeli)** | **531** | **329** | **100%** | +| LM models (22) | ~50 | ~5 ea. | +5-10% | +| PixelLink PP (estimate) | — | ~50-200 | — | + +**Wnioski performance:** +- Detektor dominuje (89% run time) — warto zoptymalizować jako pierwszy +- Recognizery są bardzo szybkie (1-8 ms each) +- LM models mają minimalny impact na latency +- PixelLink PP będzie bottleneck jeśli w pure Python + +## 7.3 Tabela plików konfiguracyjnych + +| Plik | Typ | Dla modelu | Funkcja | +|---|---|---|---| +| chunk_37_char2ind.char2ind.txt | Text | Latin (02) | 221 char→index | +| chunk_40_char2ind.char2ind.txt | Text | CJK (03) | 32632 char→index | +| chunk_43_char2ind.char2ind.txt | Text | Arabic (04) | 415 char→index | +| chunk_47_char2ind.char2ind.txt | Text | Cyrillic (05) | 237 char→index | +| chunk_50_char2ind.char2ind.txt | Text | Devanagari (06) | 244 char→index | +| chunk_53_char2ind.char2ind.txt | Text | Greek (07) | 201 char→index | +| chunk_57_char2ind.char2ind.txt | Text | Hebrew (08) | 548 char→index | +| chunk_61_char2ind.char2ind.txt | Text | Tamil (09) | 179 char→index | +| chunk_64_char2ind.char2ind.txt | Text | Thai (10) | 199 char→index | +| chunk_*_char2inschar*.txt | Text | Per-script | Character substitution maps | +| chunk_*_rnn_info | Binary | Per-script | LogPrior probabilities (LM) | +| chunk_*_calibration.txt | Text | CJK, Arabic | Score calibration | +| chunk_*_binary_data.bin | Binary | CJK, Arabic, Dev. | Composite character data | +| chunk_66_ocr_config.config.txt | Text | Pipeline | Script→Mode→Model routing | +| manifest.bin | Protobuf | All | Model manifest index | + +## 7.4 Dlaczego 34 modele? (wyjaśnienie architektury) + +**OneOCR jest zaprojektowany jako multi-script OCR system obsługujący 9 alfabetów.** + +Architektura modular jest **koniecznością** z powodów: + +1. **Rozmiar alfabetów:** CJK ma 32632 znaków vs Latin 221. Single model byłby ogromny. +2. **Różne kierunki tekstu:** Arabic/Hebrew RTL, Thai bez spacji, CJK vertykalny. +3. **Różna złożoność:** Latin model = 3393 KB, CJK model = 13118 KB (~4x większy). +4. **Specjalizacja:** Każdy recognizer jest zoptymalizowany pod swój alfabet. +5. **Language Models:** Para LangSm+LangMd per script daje kontekstowe refinement. +6. **Separation of concerns:** Detekcja (shape-agnostic) jest oddzielna od rozpoznawania (language-specific). + +**Minimalna konfiguracja (tylko Latin OCR):** +- model_00 (detector) + model_01 (scriptID) + model_02 (latin) + PixelLink PP +- Rozmiar: ~18 MB, Load: ~360 ms, Run: ~300 ms + +**Pełna konfiguracja (all scripts):** +- Wszystkie 34 modele + PixelLink PP +- Rozmiar: ~57 MB, Load: ~580 ms, Run: ~330 ms + +## 7.5 Action Plan (priorytetyzowany backlog) + +| # | Task | Wysiłek | Priorytet | Status | +|---|---|---|---|---| +| 1 | Domain Remapping test (model_11-32) | 2h | 🔴 P0 | TODO | +| 2 | Cross-platform `engine_onnx.py` — Tier 1 (tekst) | 4h | 🔴 P0 | TODO | +| 3 | `engine_factory.py` — auto-select platform | 1h | 🔴 P0 | TODO | +| 4 | PixelLink Post-Processing v1 (horizontal only) | 2-3 dni | 🟠 P1 | TODO | +| 5 | Word cropping + per-word recognition | 1 dzień | 🟠 P1 | TODO | +| 6 | Line grouping (y-coordinate sort) | 4h | 🟠 P1 | TODO | +| 7 | `OcrResult` output format matching | 2h | 🟠 P1 | TODO | +| 8 | PixelLink vertical text support | 1 dzień | 🟡 P2 | TODO | +| 9 | Multi-scale FPN merging | 1 dzień | 🟡 P2 | TODO | +| 10 | flip_score → angle estimation | 4h | 🟡 P2 | TODO | +| 11 | Beam search CTC decoder + rnn_info | 1-2 dni | 🟡 P2 | TODO | +| 12 | Cython optimization PixelLink | 1-2 dni | 🟢 P3 | TODO | +| 13 | LineLayout model_33 investigation | 1 dzień | 🟢 P3 | TODO | +| 14 | model_00 dequantization (FP32 fallback) | 4h | 🟢 P3 | TODO | +| 15 | Benchmark suite + regression tests | 1 dzień | 🟢 P3 | TODO | + +## 7.6 Ryzyka i blockerzy + +| Ryzyko | Prawdopod. | Impact | Status | +|---|---|---|---| +| Domain remap nie zadziała | 15% | Medium — fallback to pure CTC | Nietestowane | +| PixelLink decode jakość | 25% | Medium — trzeba kalibrować thresholds | Nietestowane | +| PixelLink performance w Python | 40% | Low — Cython/Rust mitigation | Nietestowane | +| OneOCRFeatureExtract (model_33) | 80% | Low — heuristic line grouping | Brak rozwiązania | +| Image angle bez DLL | 60% | Low — flip_score partial solution | Nietestowane | + +## 7.7 Końcowe wnioski + +1. **Cross-platform OCR z modelami OneOCR jest w pełni osiągalny** dla core funkcjonalności (tekst + script detection + confidence). + +2. **Bounding boxy wymagają PixelLink post-processingu** — to główny brakujący element. Implementowalny w Python+OpenCV. + +3. **Language Models (model_11-32) prawdopodobnie zadziałają** po prostym domain remapping — to jest odkrycie, które może odblokować 22/23 zablokowanych modeli jednym prostym skryptem. + +4. **Performance pure ONNX** jest porównywalny lub lepszy niż DLL (po odliczeniu overhead DLL). Detektor dominuje timing. + +5. **Rekomendowana architektura:** dual-engine (DLL + ONNX) z auto-detection platformy. Stopniowe budowanie ONNX engine do pełnej parytetu z DLL. + +--- + +**END OF BRAINSTORM** + +> Next steps: Wykonaj Task #1 (Domain Remapping test) — to zajmie 2 godziny i odpowie na kluczowe pytanie. diff --git a/_archive/temp/brain_storm/BRAINSTORM_ONEOCR_MODELS_SUMMARY.md b/_archive/temp/brain_storm/BRAINSTORM_ONEOCR_MODELS_SUMMARY.md new file mode 100644 index 0000000000000000000000000000000000000000..0721298a0384cba1b2e4df7aec8bb71a35241114 --- /dev/null +++ b/_archive/temp/brain_storm/BRAINSTORM_ONEOCR_MODELS_SUMMARY.md @@ -0,0 +1,103 @@ +# 📋 BRAINSTORM SUMMARY — OneOCR Cross-Platform Roadmap + +> Skrócone podsumowanie z `BRAINSTORM_ONEOCR_MODELS.md` + +--- + +## Stan obecny + +| Metryka | Wartość | +|---|---| +| Modele ONNX wyekstrahowane | 34 | +| Działające w std onnxruntime | 11 (detector + scriptID + 9 recognizers) | +| Zablokowane (custom ops) | 23 (22 LM + 1 LineLayout) | +| Accuracy bez LM | ~96.3% (na tekście łacińskim) | +| Obsługiwane skrypty | 9 (Latin, CJK, Arabic, Cyrillic, Devanagari, Greek, Hebrew, Tamil, Thai) | +| Total load time (11 modeli) | ~531 ms | +| Total run time (11 modeli) | ~329 ms | +| Główny bottleneck | Detector model_00 (89% total run time) | + +--- + +## Kluczowe odkrycie + +**`DynamicQuantizeLSTM`** — operator blokujący 22 modele LM — **jest oficjalnym contrib op** w standardowym onnxruntime (`com.microsoft` domain). Modele OneOCR używają domeny `com.microsoft.oneocr`. **Domain remapping** (zmiana nazwy domeny w grafie ONNX) powinien odblokować te modele natychmiast. + +--- + +## Top 3 rekomendowane akcje + +| # | Akcja | Wysiłek | Wpływ | +|---|---|---|---| +| 1 | **Domain Remapping** model_11-32 | 2h | Odblokowanie 22 modeli LM | +| 2 | **engine_onnx.py** — cross-platform engine | 4h | OCR na Linux/Mac/ARM | +| 3 | **PixelLink Post-Processing** | 2-3 dni | Bounding boxy cross-platform | + +--- + +## Architektura docelowa + +``` +ocr/ +├── engine.py — Windows DLL wrapper (bez zmian) +├── engine_onnx.py — NOWY: cross-platform ONNX engine +├── engine_factory.py — NOWY: auto-select (DLL vs ONNX) +├── pixellink.py — NOWY: PixelLink bounding box decode +├── ctc_decoder.py — NOWY: CTC greedy + beam search +├── models.py — data classes (bez zmian) +└── ... — reszta bez zmian +``` + +--- + +## Pipeline modeli (34 ONNX) + +``` +Obraz → [model_00 Detector 11MB] → PixelLink decode → bounding boxy + │ + [model_01 ScriptID 3.3MB] ◀────────────────┘ + script(10) + printed/handwritten(2) + flip(2) + │ + [model_02-10 Recognizers] ◀── crop z bbox + CTC decode → tekst + confidence + │ + [model_11-32 Language Models] ← domain remap + DynamicQuantizeLSTM → refinement + │ + [model_33 LineLayout] ← custom op (nierozwiązany) + OneOCRFeatureExtract → line segmentation +``` + +--- + +## Priorytety (backlog) + +| Priorytet | Task | Czas | +|---|---|---| +| 🔴 P0 | Domain Remapping test | 2h | +| 🔴 P0 | `engine_onnx.py` Tier 1 (tekst) | 4h | +| 🔴 P0 | `engine_factory.py` auto-detect | 1h | +| 🟠 P1 | PixelLink PP (horizontal text) | 2-3d | +| 🟠 P1 | Per-word cropping + recognition | 1d | +| 🟠 P1 | Line grouping | 4h | +| 🟡 P2 | Vertical text, FPN merge | 2d | +| 🟡 P2 | Beam search CTC + rnn_info | 1-2d | +| 🟢 P3 | Cython optimization | 1-2d | +| 🟢 P3 | model_33 investigation | 1d | + +--- + +## Ryzyka + +| Ryzyko | Szansa | Mitygacja | +|---|---|---| +| Domain remap nie zadziała | 15% | Pure CTC fallback (96%+ accuracy) | +| PixelLink PP zła jakość | 25% | Kalibracja thresholdów | +| Performance PP w Python | 40% | Cython/Rust optimization | +| model_33 nieodtwarzalny | 80% | Heurystyczny line grouping (y-sort) | + +--- + +## Wniosek + +**Cross-platform OCR z modelami OneOCR jest osiągalny.** Core (tekst + script + confidence) już działa. Bounding boxy wymagają PixelLink PP (~2 tygodnie). LM refinement prawdopodobnie odblokowany domain remapping (~2h). Docelowo: 85-95% funkcjonalności DLL na każdej platformie. diff --git a/_archive/temp/brain_storm/benchmark_models.py b/_archive/temp/brain_storm/benchmark_models.py new file mode 100644 index 0000000000000000000000000000000000000000..4672ad8d0a6afb315c3a2285cbff7bb1a96a5f75 --- /dev/null +++ b/_archive/temp/brain_storm/benchmark_models.py @@ -0,0 +1,238 @@ +"""Benchmark all ONNX models — timing, outputs, DLL vs pure ONNX comparison.""" +import time +import numpy as np +import onnxruntime as ort +import onnx +from PIL import Image +from pathlib import Path + +MODELS_DIR = Path("oneocr_extracted/onnx_models") +CONFIG_DIR = Path("oneocr_extracted/config_data") + + +def load_char_map(path): + idx2char, blank_idx = {}, 0 + with open(path, "r", encoding="utf-8") as f: + for line in f: + line = line.rstrip("\n") + if not line: continue + sp = line.rfind(" ") + if sp <= 0: continue + char, idx = line[:sp], int(line[sp + 1:]) + if char == "": blank_idx = idx + elif char == "": idx2char[idx] = " " + else: idx2char[idx] = char + return idx2char, blank_idx + + +def ctc_decode(lp, idx2char, blank): + if lp.ndim == 3: + lp = lp[:, 0, :] if lp.shape[1] == 1 else lp[0] + indices = np.argmax(lp, axis=-1) + chars, prev = [], -1 + for i in indices: + if i != prev and i != blank: + chars.append(idx2char.get(int(i), f"[{i}]")) + prev = i + return "".join(chars) + + +print("=" * 100) +print(" ONEOCR FULL MODEL BENCHMARK") +print("=" * 100) + +img = Image.open("image.png").convert("RGB") +w, h = img.size +print(f"\n Test image: {w}x{h}\n") + +# ─── Prepare inputs ───────────────────────────────────────────────────────── + +# Detector input (BGR, mean-subtracted) +scale_det = 800 / max(h, w) +dh = (int(h * scale_det) + 31) // 32 * 32 +dw = (int(w * scale_det) + 31) // 32 * 32 +img_det = img.resize((dw, dh), Image.LANCZOS) +arr_det = np.array(img_det, dtype=np.float32)[:, :, ::-1] - [102.9801, 115.9465, 122.7717] +det_data = arr_det.transpose(2, 0, 1)[np.newaxis].astype(np.float32) +det_iminfo = np.array([[dh, dw, scale_det]], dtype=np.float32) + +# Recognizer input (RGB /255) +target_h = 60 +scale_rec = target_h / h +new_w = max(int(w * scale_rec), 32) +new_w = (new_w + 3) // 4 * 4 +img_rec = img.resize((new_w, target_h), Image.LANCZOS) +rec_data = (np.array(img_rec, dtype=np.float32) / 255.0).transpose(2, 0, 1)[np.newaxis] +rec_seq = np.array([new_w // 4], dtype=np.int32) + +# char maps +CHAR_MAPS = { + 2: "chunk_37_char2ind.char2ind.txt", + 3: "chunk_40_char2ind.char2ind.txt", + 4: "chunk_43_char2ind.char2ind.txt", + 5: "chunk_47_char2ind.char2ind.txt", + 6: "chunk_50_char2ind.char2ind.txt", + 7: "chunk_53_char2ind.char2ind.txt", + 8: "chunk_57_char2ind.char2ind.txt", + 9: "chunk_61_char2ind.char2ind.txt", + 10: "chunk_64_char2ind.char2ind.txt", +} + +SCRIPT_NAMES = { + 0: "Detector", 1: "ScriptID", 2: "Latin", 3: "CJK", 4: "Arabic", + 5: "Cyrillic", 6: "Devanagari", 7: "Greek", 8: "Hebrew", 9: "Tamil", 10: "Thai", +} +for i in range(11, 22): SCRIPT_NAMES[i] = f"LangSm_{i-11}" +for i in range(22, 33): SCRIPT_NAMES[i] = f"LangMd_{i-22}" +SCRIPT_NAMES[33] = "LineLayout" + +# ─── Benchmark ─────────────────────────────────────────────────────────────── +print(f"{'#':>3} {'Name':15s} {'KB':>8} {'Load ms':>8} {'Run ms':>8} {'Runs':>5} {'Output Shape':30s} {'RT':>6} {'Text'}") +print("-" * 100) + +total_load = 0 +total_run = 0 + +for f in sorted(MODELS_DIR.glob("*.onnx")): + idx = int(f.name.split("_")[1]) + size_kb = f.stat().st_size // 1024 + name = SCRIPT_NAMES.get(idx, f"model_{idx}") + + # Load timing + t0 = time.perf_counter() + try: + sess = ort.InferenceSession(str(f), providers=["CPUExecutionProvider"]) + t_load = (time.perf_counter() - t0) * 1000 + rt = "OK" + except Exception as e: + t_load = (time.perf_counter() - t0) * 1000 + rt = "CUSTOM" + print(f"{idx:>3} {name:15s} {size_kb:>8} {t_load:>8.1f} {'---':>8} {'---':>5} {'N/A (custom ops)':30s} {rt:>6}") + continue + + total_load += t_load + + # Run timing + input_names = [i.name for i in sess.get_inputs()] + + if idx == 0: # detector + feeds = {"data": det_data, "im_info": det_iminfo} + elif idx == 1: # script ID + feeds = {"data": rec_data} + if "seq_lengths" in input_names: + feeds["seq_lengths"] = rec_seq + elif idx <= 10: # recognizers + feeds = {"data": rec_data, "seq_lengths": rec_seq} + else: + # Language models — small input + feeds = {} + for inp in sess.get_inputs(): + shape = [] + for d in inp.shape: + shape.append(d if isinstance(d, int) and d > 0 else 1) + if "int" in inp.type: + feeds[inp.name] = np.ones(shape, dtype=np.int32) + else: + feeds[inp.name] = np.random.randn(*shape).astype(np.float32) + + # Warmup + try: + sess.run(None, feeds) + except Exception as e: + print(f"{idx:>3} {name:15s} {size_kb:>8} {t_load:>8.1f} {'ERR':>8} {'---':>5} {str(e)[:30]:30s} {rt:>6}") + continue + + # Benchmark (5 runs) + n_runs = 5 + t0 = time.perf_counter() + for _ in range(n_runs): + outputs = sess.run(None, feeds) + t_run = (time.perf_counter() - t0) / n_runs * 1000 + total_run += t_run + + out_shape = str(outputs[0].shape) + + # Decode text for recognizers + text = "" + if 2 <= idx <= 10 and idx in CHAR_MAPS: + cm_path = CONFIG_DIR / CHAR_MAPS[idx] + if cm_path.exists(): + idx2char, blank_idx = load_char_map(str(cm_path)) + text = ctc_decode(outputs[0], idx2char, blank_idx) + + print(f"{idx:>3} {name:15s} {size_kb:>8} {t_load:>8.1f} {t_run:>8.1f} {n_runs:>5} {out_shape:30s} {rt:>6} {text}") + +print("-" * 100) +print(f" {'TOTAL':15s} {'':>8} {total_load:>8.1f} {total_run:>8.1f}") + +# ─── DLL comparison ────────────────────────────────────────────────────────── +print(f"\n{'=' * 100}") +print(" DLL vs ONNX COMPARISON") +print("=" * 100) + +print(""" +┌─────────────────────────────────────────────────────────────────────────────┐ +│ Feature │ DLL (oneocr.dll) │ Pure ONNX │ +├───────────────────────────┼────────────────────────┼────────────────────────┤ +│ Platform │ Windows only │ Any (Linux/Mac/Win) │ +│ Text detection (boxes) │ YES (4-point quads) │ Raw FPN maps (need PP) │ +│ Text recognition │ YES (full pipeline) │ YES (CTC decode) │ +│ Word confidence │ YES (per-word float) │ YES (from logprobs) │ +│ Line bounding boxes │ YES (quadrilateral) │ NO (need PixelLink PP) │ +│ Word bounding boxes │ YES (quadrilateral) │ NO (need PixelLink PP) │ +│ Image angle/rotation │ YES (GetImageAngle) │ NO (not in models) │ +│ Script detection │ YES (automatic) │ model_01 (standalone) │ +│ Language models (LM) │ YES (built-in custom) │ NO (custom ops needed) │ +│ Multi-script support │ YES (auto-switch) │ Manual script select │ +│ Dependencies │ oneocr.dll + ort.dll │ onnxruntime + numpy │ +│ Size │ ~100MB (DLL+model) │ ~45MB (12 ONNX models) │ +│ Latency (typical) │ ~50-100ms │ ~30-80ms (recog only) │ +│ Custom ops needed │ NO (built-in) │ 23/34 models blocked │ +└─────────────────────────────────────────────────────────────────────────────┘ +""") + +# ─── What each model outputs ──────────────────────────────────────────────── +print("=" * 100) +print(" DETAILED MODEL OUTPUT ANALYSIS") +print("=" * 100) + +for f in sorted(MODELS_DIR.glob("*.onnx")): + idx = int(f.name.split("_")[1]) + m = onnx.load(str(f)) + name = SCRIPT_NAMES.get(idx, f"model_{idx}") + + print(f"\n model_{idx:02d} ({name}):") + + # Inputs + for inp in m.graph.input: + dims = [] + if inp.type.tensor_type.HasField("shape"): + for d in inp.type.tensor_type.shape.dim: + dims.append(str(d.dim_value) if d.dim_value else d.dim_param or "?") + elem_type = inp.type.tensor_type.elem_type + type_map = {1: "float32", 6: "int32", 7: "int64", 10: "float16"} + print(f" IN: {inp.name:20s} [{','.join(dims):20s}] {type_map.get(elem_type, f'type{elem_type}')}") + + # Outputs + for out in m.graph.output: + dims = [] + if out.type.tensor_type.HasField("shape"): + for d in out.type.tensor_type.shape.dim: + dims.append(str(d.dim_value) if d.dim_value else d.dim_param or "?") + elem_type = out.type.tensor_type.elem_type + print(f" OUT: {out.name:20s} [{','.join(dims):20s}] {type_map.get(elem_type, f'type{elem_type}')}") + + # Custom domains + domains = [o.domain for o in m.opset_import if o.domain] + if domains: + print(f" CUSTOM OPS: {', '.join(domains)}") + + # Op counts + op_counts = {} + for node in m.graph.node: + key = f"{node.domain}::{node.op_type}" if node.domain else node.op_type + op_counts[key] = op_counts.get(key, 0) + 1 + + if idx <= 1 or idx == 33: # Show ops for interesting models + top_ops = sorted(op_counts.items(), key=lambda x: -x[1])[:8] + print(f" TOP OPS: {', '.join(f'{op}({n})' for op, n in top_ops)}") diff --git a/_archive/temp/decode_manifest.py b/_archive/temp/decode_manifest.py new file mode 100644 index 0000000000000000000000000000000000000000..2d2112a97053c940125de1882622529f239c6830 --- /dev/null +++ b/_archive/temp/decode_manifest.py @@ -0,0 +1,102 @@ +""" +Decode manifest.bin protobuf from onemodel — extract detector config parameters. +This is a raw protobuf that we decode manually (wire format). +""" +import struct + +def decode_varint(data, pos): + result = 0 + shift = 0 + while pos < len(data): + b = data[pos] + result |= (b & 0x7f) << shift + pos += 1 + if not (b & 0x80): + break + shift += 7 + return result, pos + +def decode_protobuf(data, depth=0, prefix=""): + pos = 0 + indent = " " * depth + while pos < len(data): + if pos >= len(data): + break + + tag_wire, new_pos = decode_varint(data, pos) + if new_pos == pos: + break + + field_num = tag_wire >> 3 + wire_type = tag_wire & 0x7 + pos = new_pos + + if wire_type == 0: # Varint + val, pos = decode_varint(data, pos) + print(f"{indent}Field {field_num} (varint): {val}") + + elif wire_type == 1: # 64-bit + if pos + 8 > len(data): + break + val_d = struct.unpack(' len(data): + break + payload = data[pos:pos+length] + pos += length + + # Try to interpret as string + try: + s = payload.decode('utf-8') + if all(32 <= ord(c) < 127 or c in '\n\r\t' for c in s): + if len(s) < 300: + print(f"{indent}Field {field_num} (string): \"{s}\"") + else: + print(f"{indent}Field {field_num} (string, {len(s)} chars): \"{s[:100]}...\"") + continue + except: + pass + + # Try as sub-message + if len(payload) > 2: + # Heuristic: if first byte looks like a valid tag + first_tag = payload[0] + if 0 < first_tag < 128 and (first_tag & 0x7) <= 5: + print(f"{indent}Field {field_num} (message, {len(payload)} bytes):") + try: + decode_protobuf(payload, depth + 1, prefix + f".{field_num}") + except: + # Not a valid protobuf, dump hex + hex_str = payload[:50].hex() + print(f"{indent} [raw hex: {hex_str}...]") + else: + hex_str = payload[:50].hex() + print(f"{indent}Field {field_num} (bytes, {len(payload)}): {hex_str}") + else: + hex_str = payload.hex() + print(f"{indent}Field {field_num} (bytes, {len(payload)}): {hex_str}") + + elif wire_type == 5: # 32-bit + if pos + 4 > len(data): + break + val_f = struct.unpack(' 0.6 + from scipy import ndimage + labeled, n = ndimage.label(text_mask) + print(f"\n {level} (stride={stride}): {n} components, max_score={scores.max():.3f}") + + min_area_scaled = 100 * (scale ** 2) + + for comp_id in range(1, n + 1): + ys, xs = np.where(labeled == comp_id) + x1 = int(xs.min() * stride / scale) + y1 = int(ys.min() * stride / scale) + x2 = int((xs.max() + 1) * stride / scale) + y2 = int((ys.max() + 1) * stride / scale) + box_w = (xs.max() - xs.min() + 1) * stride + box_h = (ys.max() - ys.min() + 1) * stride + area = box_w * box_h + npix = len(ys) + # Crop and recognize + pad = int((y2-y1) * 0.15) + cy1 = max(0, y1 - pad) + cy2 = min(h, y2 + pad) + cx1 = max(0, x1 - pad) + cx2 = min(w, x2 + pad) + crop = img_rgb[cy1:cy2, cx1:cx2] + + if crop.shape[0] >= 5 and crop.shape[1] >= 5: + rec_sess = ort.InferenceSession( + 'oneocr_extracted/onnx_models/model_02_ir7_0.1.0_3393KB.onnx', + providers=['CPUExecutionProvider'] + ) + # Load charmap + idx2char = {} + blank_idx = 0 + with open('oneocr_extracted/config_data/chunk_37_char2ind.char2ind.txt', 'r', encoding='utf-8') as f: + for line in f: + line = line.strip() + if not line: continue + sp = line.rfind(' ') + char_str, idx_str = line[:sp], line[sp+1:] + idx = int(idx_str) + if char_str == '': blank_idx = idx + elif char_str == '': idx2char[idx] = ' ' + else: idx2char[idx] = char_str + + ch, cw = crop.shape[:2] + target_h = 60 + sc = target_h / ch + new_w = max(int(cw * sc), 32) + new_w = (new_w + 3) // 4 * 4 + resized = cv2.resize(crop, (new_w, target_h)) + data = resized.astype(np.float32) / 255.0 + data = data.transpose(2, 0, 1)[np.newaxis] + seq_l = np.array([data.shape[3] // 4], dtype=np.int32) + output = rec_sess.run(None, {'data': data, 'seq_lengths': seq_l})[0] + indices = np.argmax(output[:, 0, :], axis=-1) + probs = np.exp(output[:, 0, :]) + max_probs = probs[np.arange(len(indices)), indices] + prev = -1 + chars = [] + confs = [] + for t, ix in enumerate(indices): + if ix != prev and ix != blank_idx: + chars.append(idx2char.get(int(ix), f'[{ix}]')) + confs.append(float(max_probs[t])) + prev = ix + text = ''.join(chars) + avg_conf = float(np.mean(confs)) if confs else 0 + else: + text = "" + avg_conf = 0 + + passes = "PASS" if area >= min_area_scaled else "FILTERED" + print(f" comp {comp_id}: box=({x1},{y1})-({x2},{y2}) {box_w}x{box_h} " + f"area={area} npix={npix} [{passes}] -> \"{text}\" conf={avg_conf:.3f}") diff --git a/_archive/temp/diag_crop.py b/_archive/temp/diag_crop.py new file mode 100644 index 0000000000000000000000000000000000000000..535fffc557bea148f1266387b5767fdae3b502c2 --- /dev/null +++ b/_archive/temp/diag_crop.py @@ -0,0 +1,202 @@ +"""Diagnostic: test different crop paddings on recognition quality.""" +import onnxruntime as ort +import numpy as np +import cv2 +from scipy import ndimage + +# Test with ocr_test (2).png: DLL='START' vs ONNX='STAKT' +img = cv2.imread('working_space/input/ocr_test (2).png') +img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) +h, w = img_rgb.shape[:2] +print(f'Image: {w}x{h}') + +# Load recognizer +rec_sess = ort.InferenceSession( + 'oneocr_extracted/onnx_models/model_02_ir7_0.1.0_3393KB.onnx', + providers=['CPUExecutionProvider'] +) + +# Load charmap +idx2char = {} +blank_idx = 0 +with open('oneocr_extracted/config_data/chunk_37_char2ind.char2ind.txt', 'r', encoding='utf-8') as f: + for line in f: + line = line.strip() + if not line: + continue + sp = line.rfind(' ') + char_str, idx_str = line[:sp], line[sp + 1:] + idx = int(idx_str) + if char_str == '': + blank_idx = idx + elif char_str == '': + idx2char[idx] = ' ' + else: + idx2char[idx] = char_str + +def preproc(crop_rgb, target_h=60): + ch, cw = crop_rgb.shape[:2] + scale = target_h / ch + new_w = max(int(cw * scale), 32) + new_w = (new_w + 3) // 4 * 4 + resized = cv2.resize(crop_rgb, (new_w, target_h)) + data = resized.astype(np.float32) / 255.0 + data = data.transpose(2, 0, 1)[np.newaxis] + return data + +def recognize(crop_rgb): + data = preproc(crop_rgb) + seq_l = np.array([data.shape[3] // 4], dtype=np.int32) + output = rec_sess.run(None, {'data': data, 'seq_lengths': seq_l})[0] + indices = np.argmax(output[:, 0, :], axis=-1) + probs = np.exp(output[:, 0, :]) + max_probs = probs[np.arange(len(indices)), indices] + prev = -1 + chars = [] + confs = [] + for t, idx in enumerate(indices): + if idx != prev and idx != blank_idx: + chars.append(idx2char.get(int(idx), f'[{idx}]')) + confs.append(float(max_probs[t])) + prev = idx + text = ''.join(chars) + avg_conf = float(np.mean(confs)) if confs else 0 + return text, avg_conf + +# Test 1: Full image recognition +text, conf = recognize(img_rgb) +print(f'\nFull image: "{text}" (conf={conf:.3f})') + +# Detect text regions using FPN3 +det_sess = ort.InferenceSession( + 'oneocr_extracted/onnx_models/model_00_ir6_0.1.0_11282KB.onnx', + providers=['CPUExecutionProvider'] +) + +mean = np.array([102.9801, 115.9465, 122.7717], dtype=np.float32) +# Upscale for detection +scale_det = 800 / max(h, w) +dh = (int(h * scale_det) + 31) // 32 * 32 +dw = (int(w * scale_det) + 31) // 32 * 32 +img_det = cv2.resize(img, (dw, dh)).astype(np.float32) +det_data = (img_det - mean).transpose(2, 0, 1)[np.newaxis].astype(np.float32) +im_info = np.array([[dh, dw, scale_det]], dtype=np.float32) +det_outs = det_sess.run(None, {'data': det_data, 'im_info': im_info}) +out_names = [o.name for o in det_sess.get_outputs()] + +# Get fpn3 scores +fpn3_scores = det_outs[out_names.index('scores_hori_fpn3')][0, 0] +text_mask = fpn3_scores > 0.6 +labeled, n = ndimage.label(text_mask) +print(f'\nFPN3 detected {n} text regions') + +# Also try fpn2 +fpn2_scores = det_outs[out_names.index('scores_hori_fpn2')][0, 0] +text_mask2 = fpn2_scores > 0.6 +labeled2, n2 = ndimage.label(text_mask2) +print(f'FPN2 detected {n2} text regions') + +# Test each FPN3 region with different paddings +print('\n=== FPN3 regions with different paddings ===') +for comp_id in range(1, n + 1): + ys, xs = np.where(labeled == comp_id) + if len(ys) < 3: + continue + stride = 8 + x1 = int(xs.min() * stride / scale_det) + y1 = int(ys.min() * stride / scale_det) + x2 = int((xs.max() + 1) * stride / scale_det) + y2 = int((ys.max() + 1) * stride / scale_det) + region_h = y2 - y1 + region_w = x2 - x1 + print(f'\nRegion {comp_id}: ({x1},{y1})-({x2},{y2}) {region_w}x{region_h}') + + for pad_pct in [0.0, 0.1, 0.2, 0.3, 0.5, 0.8, 1.0]: + pad_h = int(region_h * pad_pct) + pad_w = int(region_w * pad_pct * 0.3) + cy1 = max(0, y1 - pad_h) + cy2 = min(h, y2 + pad_h) + cx1 = max(0, x1 - pad_w) + cx2 = min(w, x2 + pad_w) + crop = img_rgb[cy1:cy2, cx1:cx2] + if crop.shape[0] < 5 or crop.shape[1] < 5: + continue + text, conf = recognize(crop) + print(f' pad={pad_pct:.1f}: "{text}" (conf={conf:.3f})') + +# Also test: what if we recognize using BGR instead of RGB? +print('\n=== Test BGR vs RGB recognition ===') +# Take a well-detected region +for comp_id in range(1, min(n + 1, 4)): + ys, xs = np.where(labeled == comp_id) + if len(ys) < 3: + continue + stride = 8 + x1 = int(xs.min() * stride / scale_det) + y1 = int(ys.min() * stride / scale_det) + x2 = int((xs.max() + 1) * stride / scale_det) + y2 = int((ys.max() + 1) * stride / scale_det) + pad_h = int((y2-y1) * 0.3) + pad_w = int((x2-x1) * 0.15) + cy1 = max(0, y1 - pad_h) + cy2 = min(h, y2 + pad_h) + cx1 = max(0, x1 - pad_w) + cx2 = min(w, x2 + pad_w) + + crop_rgb = img_rgb[cy1:cy2, cx1:cx2] + crop_bgr = crop_rgb[:, :, ::-1].copy() + crop_gray = cv2.cvtColor(crop_rgb, cv2.COLOR_RGB2GRAY) + crop_gray3 = np.stack([crop_gray]*3, axis=-1) + + text_rgb, conf_rgb = recognize(crop_rgb) + text_bgr, conf_bgr = recognize(crop_bgr) + text_gray, conf_gray = recognize(crop_gray3) + + print(f'\nRegion {comp_id}:') + print(f' RGB: "{text_rgb}" (conf={conf_rgb:.3f})') + print(f' BGR: "{text_bgr}" (conf={conf_bgr:.3f})') + print(f' GRAY: "{text_gray}" (conf={conf_gray:.3f})') + +# Test different seq_lengths formulas +print('\n=== Test seq_lengths formulas ===') +for comp_id in range(1, min(n + 1, 3)): + ys, xs = np.where(labeled == comp_id) + if len(ys) < 3: + continue + stride = 8 + x1 = int(xs.min() * stride / scale_det) + y1 = int(ys.min() * stride / scale_det) + x2 = int((xs.max() + 1) * stride / scale_det) + y2 = int((ys.max() + 1) * stride / scale_det) + pad_h = int((y2-y1) * 0.3) + pad_w = int((x2-x1) * 0.15) + cy1 = max(0, y1 - pad_h) + cy2 = min(h, y2 + pad_h) + cx1 = max(0, x1 - pad_w) + cx2 = min(w, x2 + pad_w) + crop = img_rgb[cy1:cy2, cx1:cx2] + + data = preproc(crop) + w_data = data.shape[3] + print(f'\nRegion {comp_id} (data width={w_data}):') + + for divisor in [2, 4, 8]: + seq_l = np.array([w_data // divisor], dtype=np.int32) + try: + output = rec_sess.run(None, {'data': data, 'seq_lengths': seq_l})[0] + indices = np.argmax(output[:, 0, :], axis=-1) + probs = np.exp(output[:, 0, :]) + max_probs = probs[np.arange(len(indices)), indices] + prev = -1 + chars = [] + confs = [] + for t, idx in enumerate(indices): + if idx != prev and idx != blank_idx: + chars.append(idx2char.get(int(idx), f'[{idx}]')) + confs.append(float(max_probs[t])) + prev = idx + text = ''.join(chars) + avg_conf = float(np.mean(confs)) if confs else 0 + print(f' seq_lengths=w//{divisor}={w_data//divisor}: "{text}" (conf={avg_conf:.3f})') + except Exception as e: + print(f' seq_lengths=w//{divisor}={w_data//divisor}: ERROR: {e}') diff --git a/_archive/temp/extract_seglink_config.py b/_archive/temp/extract_seglink_config.py new file mode 100644 index 0000000000000000000000000000000000000000..e4f420b983fa73cac1fe4f7677f1a3c661726015 --- /dev/null +++ b/_archive/temp/extract_seglink_config.py @@ -0,0 +1,89 @@ +""" +Extract SeglinkProposals custom op attributes from detection model (model_00). +Also dump all XY/Seglink related config from the ONNX graph. +""" +import onnx +from onnx import numpy_helper +import os + +model_path = "oneocr_extracted/onnx_models_unlocked/model_00_ir7_onnx_quantize_13118KB.onnx" +if not os.path.exists(model_path): + # Try alternative + model_path = "_archive/onnx_models/model_00_ir7_onnx_quantize_13118KB.onnx" + +print(f"Loading: {model_path}") +model = onnx.load(model_path) +graph = model.graph + +print("\n" + "="*60) +print("ALL CUSTOM OPS IN DETECTION MODEL") +print("="*60) + +for node in graph.node: + if node.domain and 'OneOCR' in node.domain: + print(f"\n Op: {node.op_type}") + print(f" Domain: {node.domain}") + print(f" Name: {node.name}") + print(f" Inputs: {list(node.input)}") + print(f" Outputs: {list(node.output)}") + if node.attribute: + print(f" Attributes:") + for attr in node.attribute: + if attr.type == 1: # FLOAT + print(f" {attr.name} = {attr.f}") + elif attr.type == 2: # INT + print(f" {attr.name} = {attr.i}") + elif attr.type == 3: # STRING + print(f" {attr.name} = {attr.s.decode()}") + elif attr.type == 6: # FLOATS + print(f" {attr.name} = {list(attr.floats)}") + elif attr.type == 7: # INTS + print(f" {attr.name} = {list(attr.ints)}") + else: + print(f" {attr.name} = ") + +print("\n" + "="*60) +print("ALL NODES WITH seglink/proposal/SeglinkProposals IN NAME OR OP") +print("="*60) + +for node in graph.node: + if any(kw in (node.op_type + node.name).lower() for kw in ['seglink', 'proposal', 'feature_extract']): + print(f"\n Op: {node.op_type} (domain: {node.domain})") + print(f" Name: {node.name}") + print(f" Inputs: {list(node.input)}") + print(f" Outputs: {list(node.output)}") + for attr in node.attribute: + if attr.type == 1: + print(f" {attr.name} = {attr.f}") + elif attr.type == 2: + print(f" {attr.name} = {attr.i}") + elif attr.type == 3: + print(f" {attr.name} = {attr.s.decode()}") + elif attr.type == 6: + print(f" {attr.name} = {list(attr.floats)}") + elif attr.type == 7: + print(f" {attr.name} = {list(attr.ints)}") + +print("\n" + "="*60) +print("MODEL INPUTS") +print("="*60) +for inp in graph.input: + dims = [d.dim_value if d.dim_value else d.dim_param for d in inp.type.tensor_type.shape.dim] + print(f" {inp.name}: {dims}") + +print("\n" + "="*60) +print("MODEL OUTPUTS") +print("="*60) +for out in graph.output: + dims = [d.dim_value if d.dim_value else d.dim_param for d in out.type.tensor_type.shape.dim] + print(f" {out.name}: {dims}") + +print("\n" + "="*60) +print("ALL NODE TYPES (unique)") +print("="*60) +ops = {} +for node in graph.node: + key = f"{node.domain}::{node.op_type}" if node.domain else node.op_type + ops[key] = ops.get(key, 0) + 1 +for op, count in sorted(ops.items()): + print(f" {op}: {count}x") diff --git a/_archive/temp/heuristics_report.py b/_archive/temp/heuristics_report.py new file mode 100644 index 0000000000000000000000000000000000000000..20379c17e25f38c351462c9d7d5e25669e4b73fa --- /dev/null +++ b/_archive/temp/heuristics_report.py @@ -0,0 +1,88 @@ +""" +Weryfikacja heurystyk pipeline ONNX vs oryginał (OneOCR DLL) +============================================================= + +Raport porównawczy kluczowych parametrów i heurystyk. + +1. PREPROCESSING + │ Parametr │ ONNX pipeline │ Oryginał (DLL) │ Zgodność │ + ├──────────────────┼──────────────────────┼──────────────────────┼──────────┤ + │ Detector input │ BGR mean-sub │ BGR mean-sub (BGRA) │ ✅ ~tak │ + │ BGR mean values │ [102.98, 115.95, │ [102.98, 115.95, │ ✅ tak │ + │ │ 122.77] │ 122.77] │ │ + │ Max input size │ 800px │ zależne od opcji │ ⚠️ zbliż.│ + │ Pad to multiple │ 32 │ 32 │ ✅ tak │ + │ Rec input │ RGB/255, h=60 │ RGB/255, h=60 │ ✅ tak │ + │ Width align │ 4 │ 4 │ ✅ tak │ + +2. PIXELLINK DECODER + │ Parametr │ ONNX pipeline │ Oryginał │ Zgodność │ + ├──────────────────┼──────────────────────┼──────────────────────┼──────────┤ + │ Pixel threshold │ 0.6 │ ~0.5-0.7 (calibr.) │ ✅ ok │ + │ Link threshold │ 0.5 │ ~0.5 │ ✅ ok │ + │ Min area │ 100 │ ~50-200 │ ✅ ok │ + │ Min height │ 6 │ ~5-8 │ ✅ ok │ + │ NMS IoU │ 0.3 │ ~0.3-0.5 │ ✅ ok │ + │ FPN levels │ fpn2(4), fpn3(8), │ same 3 levels │ ✅ tak │ + │ │ fpn4(16) │ │ │ + │ Connected comp. │ Union-Find 8-conn │ Union-Find 8-conn │ ✅ tak │ + │ Box fitting │ minAreaRect │ minAreaRect equiv. │ ✅ tak │ + +3. CROP & PADDING + │ Parametr │ ONNX pipeline │ Oryginał │ Zgodność │ + ├──────────────────┼──────────────────────┼──────────────────────┼──────────┤ + │ Padding ratio │ 0.4 (40% of height) │ ~30-50% expansion │ ✅ ok │ + │ Horizontal pad │ 0.3 × pad │ smaller than vert │ ✅ ok │ + │ Perspective xfm │ getPerspectiveTransf │ similar │ ✅ ok │ + │ Border mode │ BORDER_REPLICATE │ replicate │ ✅ tak │ + +4. CTC DECODE + │ Parametr │ ONNX pipeline │ Oryginał │ Zgodność │ + ├──────────────────┼──────────────────────┼──────────────────────┼──────────┤ + │ Strategy │ Greedy argmax │ Greedy (no beam) │ ✅ tak │ + │ Blank handling │ collapse + remove │ same │ ✅ tak │ + │ Confidence │ exp(max_logprob) │ exp(logprob) │ ✅ tak │ + │ Per-word conf │ mean of char confs │ word-level output │ ⚠️ aprox │ + +5. LINE GROUPING + │ Parametr │ ONNX pipeline │ Oryginał │ Zgodność │ + ├──────────────────┼──────────────────────┼──────────────────────┼──────────┤ + │ Strategy │ Y-overlap heuristic │ Internal DLL logic │ ⚠️ aprox │ + │ Y overlap thresh │ 0.5 │ DLL internal │ ⚠️ aprox │ + │ Sort order │ top-to-bottom, L2R │ top-to-bottom, L2R │ ✅ tak │ + +6. VERTICAL TEXT (NOWE) + │ Parametr │ ONNX pipeline │ Oryginał │ Zgodność │ + ├──────────────────┼──────────────────────┼──────────────────────┼──────────┤ + │ Detection │ h > 2*w heuristic │ Vertical FPN outputs │ ⚠️ uprosz│ + │ Rotation │ CCW 90° │ Internal handling │ ⚠️ aprox │ + │ CJK fallback │ conf < 0.7 → try CJK│ LM model selection │ ⚠️ aprox │ + +PODSUMOWANIE +============ +- Kluczowe parametry preprocessing (mean values, sizes, alignments) = IDENTYCZNE +- PixelLink decoder = IDENTYCZNY algorytm (Union-Find, NMS, minAreaRect) +- Crop paddng = ZBLIŻONY (40% vs 30-50% w oryginale) +- CTC decode = IDENTYCZNY (greedy, collapse, blank remove) +- Pewność per-word = PRZYBLIŻONA (mean char confs vs DLL word-level) +- Line grouping = UPROSZCZONA heurystyka (oryginał ma LineLayout model 33) +- Tekst pionowy = NOWA heurystyka (oryginał obsługuje wewnętrznie) + +ZNANE RÓŻNICE +============= +1. Oryginał używa modeli LM (11-32) do weryfikacji skryptu → lepszy routing +2. Oryginał ma LineLayout (model 33) do segmentacji linii → precyzyjniejszy podział +3. Oryginał obsługuje pionowy tekst natively (detector vertical outputs) +4. Word splitting w ONNX jest proporcjonalny do znaków → oryginał ma dokładniejsze bbox +5. DLL wymaga min 50x50px → ONNX wymaga 10x10px (luźniejszy) + +WYNIKI TESTÓW +============= +- image.png "ONE OCR DZIALA!" → 99.6%, 155ms ✅ +- test.png (złożony) → 72.7%, 501ms — "Chapter 1: The Journey's End" 99% ✅ +- test2.png (japoński) → 64.4%, 309ms — "味なんじゃ!" 95%, "わからん" 86% ✅ +- test3.png (manga) → 87.0%, 271ms — "WE'LL HAVE TO" 98-99% ✅ +- paragraph → 97.0% (18 words) ✅ +- small_text → 92.3% ("Small" → "Smail" 86%) ⚠️ +- inverted → 84.5% ("White" → "white" 65%) ⚠️ +""" diff --git a/_archive/temp/profile_engine.py b/_archive/temp/profile_engine.py new file mode 100644 index 0000000000000000000000000000000000000000..242c7918665f58f316cbe40d4eb1103c4cbee408 --- /dev/null +++ b/_archive/temp/profile_engine.py @@ -0,0 +1,83 @@ +"""Profile ONNX engine performance to find bottlenecks.""" +import sys, os +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +import time +import cv2 +import numpy as np + +from ocr.engine_onnx import OcrEngineOnnx + +engine = OcrEngineOnnx() + +img = cv2.imread('working_space/input/ocr_test (2).png') +img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) + +# Warm up (first call loads models) +t0 = time.perf_counter() +r = engine.recognize_numpy(img_rgb) +t1 = time.perf_counter() +print(f'First call (cold): {(t1-t0)*1000:.0f}ms') + +# Profile individual stages +h, w = img_rgb.shape[:2] +print(f'Image: {w}x{h}') + +# Time detection +t0 = time.perf_counter() +quads, scale = engine._detect(img_rgb) +t1 = time.perf_counter() +print(f'Detection: {(t1-t0)*1000:.1f}ms ({len(quads)} quads)') + +# Time recognition per quad +for i, q in enumerate(quads[:3]): + crop = engine._crop_quad(img_rgb, q) + if crop is None: + continue + t0 = time.perf_counter() + sid = engine._identify_script(crop) + t1 = time.perf_counter() + text, conf, _ = engine._recognize(crop, 2) + t2 = time.perf_counter() + print(f' Quad {i}: ScriptID={t1-t0:.3f}s, Recognize={t2-t1:.3f}s -> "{text}"') + +# Second call (warm) +t0 = time.perf_counter() +r = engine.recognize_numpy(img_rgb) +t1 = time.perf_counter() +print(f'Second call (warm): {(t1-t0)*1000:.0f}ms') + +# Third call (warm) +t0 = time.perf_counter() +r = engine.recognize_numpy(img_rgb) +t1 = time.perf_counter() +print(f'Third call (warm): {(t1-t0)*1000:.0f}ms') + +# Check session cached count +print(f'\nCached sessions: {len(engine._sessions)}') + +# Check session options +sess = list(engine._sessions.values())[0] if engine._sessions else None +if sess: + print(f'Session providers: {sess.get_providers()}') + opts = sess.get_session_options() + print(f'Inter-op threads: {opts.inter_op_num_threads}') + print(f'Intra-op threads: {opts.intra_op_num_threads}') + print(f'Optimization level: {opts.graph_optimization_level}') + +# Now profile a big image +print('\n--- Large image (test.png) ---') +img2 = cv2.imread('working_space/input/test.png') +img2_rgb = cv2.cvtColor(img2, cv2.COLOR_BGR2RGB) +h2, w2 = img2_rgb.shape[:2] +print(f'Image: {w2}x{h2}') + +t0 = time.perf_counter() +r2 = engine.recognize_numpy(img2_rgb) +t1 = time.perf_counter() +print(f'Total: {(t1-t0)*1000:.0f}ms ({len(r2.lines)} lines)') + +# Time just detection for test.png +t0 = time.perf_counter() +quads2, scale2 = engine._detect(img2_rgb) +t1 = time.perf_counter() +print(f'Detection only: {(t1-t0)*1000:.1f}ms ({len(quads2)} quads, scale={scale2:.2f})') diff --git a/_archive/temp/re_dll.py b/_archive/temp/re_dll.py new file mode 100644 index 0000000000000000000000000000000000000000..86ed7ac374e04e00f3efcc1715841ba3d3d45977 --- /dev/null +++ b/_archive/temp/re_dll.py @@ -0,0 +1,169 @@ +""" +Deep reverse engineering of oneocr.dll to extract the EXACT processing pipeline. + +Goal: Extract all internal constants, thresholds, algorithms from the DLL binary +so we can replicate the pipeline identically in Python. +""" +import pefile +import struct +import re +import os + +DLL_PATH = "ocr_data/oneocr.dll" + +pe = pefile.PE(DLL_PATH) + +print("=" * 80) +print("1. DLL INFO") +print("=" * 80) +print(f" Machine: {hex(pe.FILE_HEADER.Machine)}") +print(f" Sections: {len(pe.sections)}") +for s in pe.sections: + name = s.Name.decode('utf-8', errors='ignore').strip('\x00') + print(f" {name}: VA={hex(s.VirtualAddress)} Size={s.SizeOfRawData} Flags={hex(s.Characteristics)}") + +print(f"\n Image base: {hex(pe.OPTIONAL_HEADER.ImageBase)}") +print(f" Entry point: {hex(pe.OPTIONAL_HEADER.AddressOfEntryPoint)}") + +print("\n" + "=" * 80) +print("2. EXPORTS") +print("=" * 80) +if hasattr(pe, 'DIRECTORY_ENTRY_EXPORT'): + for exp in pe.DIRECTORY_ENTRY_EXPORT.symbols: + name = exp.name.decode() if exp.name else f"ordinal_{exp.ordinal}" + print(f" {name} @ RVA {hex(exp.address)}") + +print("\n" + "=" * 80) +print("3. IMPORTS (key DLLs)") +print("=" * 80) +if hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'): + for entry in pe.DIRECTORY_ENTRY_IMPORT: + dll_name = entry.dll.decode() + if any(k in dll_name.lower() for k in ['onnx', 'opencv', 'bcrypt', 'kernel', 'msvc']): + funcs = [imp.name.decode() if imp.name else f"ord_{imp.ordinal}" + for imp in entry.imports[:10]] + print(f" {dll_name}: {', '.join(funcs)}{'...' if len(entry.imports) > 10 else ''}") + +print("\n" + "=" * 80) +print("4. STRING EXTRACTION — OCR pipeline related") +print("=" * 80) + +# Read entire .rdata and .data sections for strings +data = pe.__data__ +interesting_patterns = [ + b'pixel', b'link', b'score', b'thresh', b'scale', b'resize', + b'detect', b'recogni', b'script', b'fpn', b'stride', + b'bbox', b'delta', b'nms', b'iou', b'area', + b'mean', b'padding', b'crop', b'quad', b'box', + b'angle', b'rotate', b'line', b'word', b'conf', + b'model', b'session', b'run', b'pipeline', + b'PixelLink', b'CTC', b'greedy', b'beam', + b'height', b'width', b'batch', b'thread', + b'Ocr', b'OneOcr', b'Process', b'Image', + b'min_', b'max_', b'num_', b'0.', b'800', + b'featuremap', b'feature_p2', + b'hori', b'vert', b'horizontal', b'vertical', + b'connected', b'component', b'union', b'find', + b'softmax', b'sigmoid', b'argmax', + b'blank', b'space', b'char', + b'CoreEngine', b'Native', b'src\\', + b'.cpp', b'.h', b'assert', b'error', + b'im_info', b'data', +] + +# Extract all printable strings >= 6 chars +found_strings = set() +min_len = 6 +for i in range(len(data) - min_len): + if 32 <= data[i] < 127: + j = i + while j < len(data) and 32 <= data[j] < 127: + j += 1 + s = data[i:j] + if len(s) >= min_len: + s_lower = s.lower() + for pat in interesting_patterns: + if pat.lower() in s_lower: + found_strings.add((i, s.decode('ascii', errors='ignore'))) + break + # Skip ahead + +# Sort by offset and print +for offset, s in sorted(found_strings): + # Truncate very long strings + display = s[:200] + '...' if len(s) > 200 else s + print(f" [{hex(offset)}] {display}") + +print(f"\n Total interesting strings: {len(found_strings)}") + +print("\n" + "=" * 80) +print("5. FLOAT CONSTANTS (potential thresholds)") +print("=" * 80) + +# Search for known float constants in .rdata/.data +target_floats = { + 0.6: "pixel_threshold", + 0.5: "link_threshold", + 0.3: "nms_iou_threshold", + 0.15: "padding_ratio", + 800.0: "target_size", + 60.0: "rec_target_height", + 102.9801: "BGR_mean_B", + 115.9465: "BGR_mean_G", + 122.7717: "BGR_mean_R", + 255.0: "normalize_divisor", + 0.45: "conf_threshold", + 0.7: "low_conf_threshold", + 0.92: "single_char_threshold", + 100.0: "min_area", + 75.0: "min_area_alt", + 200.0: "max_lines", + 32.0: "align_to", + 6.0: "min_height_or_width", +} + +for section in pe.sections: + name = section.Name.decode('utf-8', errors='ignore').strip('\x00') + if name in ['.rdata', '.data', '.text']: + sec_data = section.get_data() + sec_va = section.VirtualAddress + + for i in range(0, len(sec_data) - 4, 4): + val = struct.unpack('= 4 else 0 + context_after = struct.unpack('12s} {inst.mnemonic:8s} {inst.op_str}") + count += 1 + if count >= 60: + break + # Stop at ret + if inst.mnemonic == 'ret': + break +else: + print(" RunOcrPipeline not found in exports") + +print("\n" + "=" * 80) +print("7. SEARCH FOR cv::resize, cv::cvtColor, cv::Mat references") +print("=" * 80) + +cv_strings = set() +i = 0 +while i < len(data) - 8: + if 32 <= data[i] < 127: + j = i + while j < len(data) and 32 <= data[j] < 127: + j += 1 + s = data[i:j].decode('ascii', errors='ignore') + if len(s) >= 6: + if any(kw in s for kw in ['cv::', 'opencv', 'resize', 'cvtColor', 'warpAffine', + 'warpPerspective', 'minAreaRect', 'connectedComponent', + 'findContour', 'boundingRect', 'threshold', 'GaussianBlur', + 'copyMakeBorder', 'INTER_', 'BORDER_']): + if s not in cv_strings: + cv_strings.add(s) + if len(s) < 300: + print(f" [{hex(i)}] {s[:200]}") + i = j + else: + i += 1 diff --git a/_archive/temp/re_dll_v3.py b/_archive/temp/re_dll_v3.py new file mode 100644 index 0000000000000000000000000000000000000000..95238dfa0b7192a50729eadd582f47474f29877f --- /dev/null +++ b/_archive/temp/re_dll_v3.py @@ -0,0 +1,456 @@ +""" +Deep RE of oneocr.dll v3 — focused on pipeline logic extraction. +Outputs organized sections to separate files for analysis. +""" +import pefile +import struct +import re +import os + +DLL_PATH = "ocr_data/oneocr.dll" +OUT_DIR = "temp/re_output" +os.makedirs(OUT_DIR, exist_ok=True) + +pe = pefile.PE(DLL_PATH) +data = pe.__data__ + +# ============================================================ +# 1. EXPORTS +# ============================================================ +exports = [] +if hasattr(pe, 'DIRECTORY_ENTRY_EXPORT'): + for exp in pe.DIRECTORY_ENTRY_EXPORT.symbols: + name = exp.name.decode() if exp.name else f"ordinal_{exp.ordinal}" + exports.append((name, exp.address)) + +with open(f"{OUT_DIR}/01_exports.txt", "w") as f: + f.write("EXPORTS\n" + "="*60 + "\n") + for name, rva in exports: + f.write(f" {name} @ {hex(rva)}\n") + f.write(f"\nTotal: {len(exports)} exports\n") +print(f"[1] Exports: {len(exports)} → {OUT_DIR}/01_exports.txt") + +# ============================================================ +# 2. IMPORTS +# ============================================================ +imports = {} +if hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'): + for entry in pe.DIRECTORY_ENTRY_IMPORT: + dll_name = entry.dll.decode() + funcs = [] + for imp in entry.imports: + if imp.name: + funcs.append(imp.name.decode()) + else: + funcs.append(f"ord_{imp.ordinal}") + imports[dll_name] = funcs + +with open(f"{OUT_DIR}/02_imports.txt", "w") as f: + f.write("IMPORTS\n" + "="*60 + "\n") + for dll_name, funcs in sorted(imports.items()): + f.write(f"\n{dll_name} ({len(funcs)} functions):\n") + for fn in funcs: + f.write(f" {fn}\n") +print(f"[2] Imports: {sum(len(v) for v in imports.values())} functions from {len(imports)} DLLs → {OUT_DIR}/02_imports.txt") + +# ============================================================ +# 3. ALL STRINGS (OneOCR + pipeline related) +# ============================================================ +all_strings = [] +seen = set() +i = 0 +while i < len(data) - 6: + if 32 <= data[i] < 127: + j = i + while j < len(data) and 32 <= data[j] < 127: + j += 1 + s = data[i:j].decode('ascii', errors='ignore') + if len(s) >= 6 and s not in seen: + seen.add(s) + all_strings.append((i, s)) + i = j + else: + i += 1 + +# Filter for interesting strings +oneocr_classes = set() +tensor_names = [] +source_files = [] +config_strings = [] +pipeline_strings = [] +error_strings = [] + +for offset, s in all_strings: + # OneOCR C++ classes + classes = re.findall(r'(\w+)@OneOCR', s) + for cls in classes: + if cls not in ['std', 'V', 'U', 'P', 'A', 'H', 'Q', 'W', 'E', 'I', 'Y', + 'AEAV', 'PEAV', 'QEAV', 'XZ', 'AEB', 'PEB'] and len(cls) > 2: + oneocr_classes.add(cls) + + # Tensor/model names + if any(kw in s for kw in ['scores', 'link_scores', 'bbox_deltas', 'feature_p', + 'im_info', 'featuremap', 'logsoftmax', 'script_id', + 'hwpc_score', 'flip_score', 'fpn', 'seq_lengths', + 'input_ids', 'attention', 'pixel_values', 'image', + 'output', 'pred', 'prob', 'logit']): + if len(s) < 200 and '@@' not in s: + tensor_names.append((offset, s)) + + # Source files + if ('.cpp' in s or '.h' in s) and ('CoreEngine' in s or 'OneOcr' in s or + 'Pipeline' in s or 'Detect' in s or 'Recog' in s or 'TextLine' in s or + 'PixelLink' in s or 'Crop' in s or 'PostProc' in s): + source_files.append((offset, s)) + + # Config/threshold strings + if any(kw in s.lower() for kw in ['threshold', 'pixel_score', 'link_score', + 'min_area', 'nms', 'padding', 'border', + 'target_size', 'max_size', 'scale', + 'confidence', 'min_height', 'min_width', + 'max_line', 'stride', 'anchor']): + config_strings.append((offset, s)) + + # Pipeline/processing strings + if any(kw in s.lower() for kw in ['pipeline', 'detect', 'recogni', 'preprocess', + 'postprocess', 'decode', 'ctc', 'beam', + 'segment', 'line_form', 'word_break', + 'text_line', 'crop', 'resize', 'normalize']): + if '@@' not in s and len(s) < 300: + pipeline_strings.append((offset, s)) + + # Error/debug messages + if any(kw in s.lower() for kw in ['error', 'fail', 'assert', 'invalid', 'unable']): + if any(kw in s.lower() for kw in ['ocr', 'model', 'image', 'detect', 'recogni', + 'pixel', 'line', 'word', 'score', 'pipeline', + 'session', 'tensor']): + error_strings.append((offset, s)) + +with open(f"{OUT_DIR}/03_oneocr_classes.txt", "w") as f: + f.write("OneOCR C++ CLASSES\n" + "="*60 + "\n") + for cls in sorted(oneocr_classes): + f.write(f" OneOCR::{cls}\n") +print(f"[3] OneOCR classes: {len(oneocr_classes)} → {OUT_DIR}/03_oneocr_classes.txt") + +with open(f"{OUT_DIR}/04_tensor_names.txt", "w") as f: + f.write("TENSOR/MODEL NAMES\n" + "="*60 + "\n") + for off, s in tensor_names: + f.write(f" [{hex(off)}] {s}\n") +print(f"[4] Tensor names: {len(tensor_names)} → {OUT_DIR}/04_tensor_names.txt") + +with open(f"{OUT_DIR}/05_source_files.txt", "w") as f: + f.write("SOURCE FILE REFERENCES\n" + "="*60 + "\n") + for off, s in source_files: + f.write(f" [{hex(off)}] {s}\n") +print(f"[5] Source files: {len(source_files)} → {OUT_DIR}/05_source_files.txt") + +with open(f"{OUT_DIR}/06_config_strings.txt", "w") as f: + f.write("CONFIG/THRESHOLD STRINGS\n" + "="*60 + "\n") + for off, s in config_strings: + f.write(f" [{hex(off)}] {s}\n") +print(f"[6] Config strings: {len(config_strings)} → {OUT_DIR}/06_config_strings.txt") + +with open(f"{OUT_DIR}/07_pipeline_strings.txt", "w") as f: + f.write("PIPELINE STRINGS\n" + "="*60 + "\n") + for off, s in pipeline_strings: + f.write(f" [{hex(off)}] {s}\n") +print(f"[7] Pipeline strings: {len(pipeline_strings)} → {OUT_DIR}/07_pipeline_strings.txt") + +with open(f"{OUT_DIR}/08_error_strings.txt", "w") as f: + f.write("ERROR/DEBUG MESSAGES\n" + "="*60 + "\n") + for off, s in error_strings: + f.write(f" [{hex(off)}] {s}\n") +print(f"[8] Error messages: {len(error_strings)} → {OUT_DIR}/08_error_strings.txt") + +# ============================================================ +# 4. FLOAT/DOUBLE CONSTANTS IN .rdata +# ============================================================ +interesting_floats = [] +interesting_doubles = [] + +for section in pe.sections: + name = section.Name.decode('utf-8', errors='ignore').strip('\x00') + if name != '.rdata': + continue + sec_data = section.get_data() + sec_rva = section.VirtualAddress + + # Search for BGR mean triple + for i in range(0, len(sec_data) - 12, 4): + v1 = struct.unpack('12s} {inst.mnemonic:8s} {inst.op_str}\n") + count += 1 + if count >= 200: + f.write(" ... (truncated at 200 instructions)\n") + break + if inst.mnemonic == 'ret' and count > 3: + break + +print(f"[10] Disassembly of {len(key_exports)} functions → {OUT_DIR}/10_disassembly.txt") + +# ============================================================ +# 6. FIND ALL FUNCTION CALLS FROM RunOcrPipeline (deeper) +# ============================================================ +run_rva = None +for name, rva in exports: + if name == 'RunOcrPipeline': + run_rva = rva + break + +if run_rva: + offset = pe.get_offset_from_rva(run_rva) + # Disassemble a larger chunk to follow the pipeline + code = data[offset:offset+8192] + + calls = [] + jmps = [] + string_refs = [] + + image_base = pe.OPTIONAL_HEADER.ImageBase + + for inst in md.disasm(code, run_rva): + if inst.mnemonic == 'call': + # Extract call target + op = inst.op_str + if op.startswith('0x'): + target = int(op, 16) + # Check if it's an exported function + target_name = None + for en, ev in exports: + if ev == target: + target_name = en + break + calls.append((hex(inst.address), target_name or hex(target))) + + elif inst.mnemonic in ('jmp', 'je', 'jne', 'jl', 'jg', 'jle', 'jge', 'ja', 'jb', 'jbe', 'jae'): + op = inst.op_str + if op.startswith('0x'): + jmps.append((hex(inst.address), inst.mnemonic, op)) + + # LEA instructions often reference strings + elif inst.mnemonic == 'lea': + # Try to get RIP-relative address + if 'rip' in inst.op_str: + try: + # Parse [rip + offset] + m = re.search(r'\[rip\s*([+-])\s*0x([0-9a-fA-F]+)\]', inst.op_str) + if m: + sign = 1 if m.group(1) == '+' else -1 + disp = int(m.group(2), 16) + target_rva = inst.address + inst.size + sign * disp + try: + target_offset = pe.get_offset_from_rva(target_rva) + # Read string at that location + s_bytes = data[target_offset:target_offset+200] + s_end = s_bytes.find(b'\x00') + if s_end > 0: + s = s_bytes[:s_end].decode('ascii', errors='ignore') + if len(s) > 3 and all(32 <= ord(c) < 127 for c in s): + string_refs.append((hex(inst.address), s[:100])) + except Exception: + pass + except Exception: + pass + + if inst.mnemonic == 'ret' and len(calls) > 5: + break + + with open(f"{OUT_DIR}/11_pipeline_calls.txt", "w") as f: + f.write("CALLS FROM RunOcrPipeline\n" + "="*60 + "\n") + for addr, target in calls: + f.write(f" {addr}: call {target}\n") + f.write(f"\nBRANCHES\n" + "="*60 + "\n") + for addr, mnem, target in jmps[:50]: + f.write(f" {addr}: {mnem} {target}\n") + f.write(f"\nSTRING REFERENCES\n" + "="*60 + "\n") + for addr, s in string_refs: + f.write(f" {addr}: \"{s}\"\n") + print(f"[11] Pipeline calls: {len(calls)} calls, {len(string_refs)} string refs → {OUT_DIR}/11_pipeline_calls.txt") + +# ============================================================ +# 7. COMPREHENSIVE STRING DUMP (all unique, sorted by offset) +# ============================================================ +# Focus: OneOCR, pipeline, model, config, tensor strings +with open(f"{OUT_DIR}/12_all_relevant_strings.txt", "w") as f: + f.write("ALL RELEVANT STRINGS (OneOCR/Pipeline/Model/Tensor)\n" + "="*60 + "\n") + count = 0 + for offset, s in all_strings: + relevant = False + if any(kw in s.lower() for kw in ['oneocr', 'pipeline', 'detect', 'recogni', + 'preprocess', 'postprocess', 'pixellink', + 'textline', 'wordbreak', 'crop', 'fpn', + 'bitmap', 'onnx', 'session', 'tensor', + 'model', 'score', 'threshold', 'confidence', + 'resize', 'scale', 'padding', 'border', + 'contour', 'component', 'segment', + 'angle', 'rotation', 'affine', 'warp', + 'ctc', 'decode', 'beam', 'greedy', + 'line_count', 'word_count', 'bbox', + 'bounding', 'rect', 'quad', 'polygon', + 'nms', 'merge', 'union', 'connected', + 'script', 'language', 'charset', + 'horizontal', 'vertical', + 'coreengine']): + relevant = True + + if relevant and len(s) < 500: + f.write(f" [{hex(offset)}] {s}\n") + count += 1 + + f.write(f"\nTotal: {count} relevant strings\n") +print(f"[12] All relevant strings: {count} → {OUT_DIR}/12_all_relevant_strings.txt") + +# ============================================================ +# 8. Find ALL OneOCR mangled names (full demangling attempt) +# ============================================================ +with open(f"{OUT_DIR}/13_mangled_names.txt", "w") as f: + f.write("ALL OneOCR MANGLED NAMES (raw)\n" + "="*60 + "\n") + count = 0 + for offset, s in all_strings: + if 'OneOCR' in s and len(s) < 500: + f.write(f" [{hex(offset)}] {s}\n") + count += 1 + f.write(f"\nTotal: {count}\n") +print(f"[13] OneOCR mangled names: {count} → {OUT_DIR}/13_mangled_names.txt") + +# ============================================================ +# 9. Try undname (MSVC demangling) via subprocess +# ============================================================ +import subprocess +mangled_oneocr = [] +for offset, s in all_strings: + if 'OneOCR' in s and s.startswith('?') and len(s) < 500: + mangled_oneocr.append((offset, s)) + +# Try to demangle using undname or dumpbin +demangled_results = [] +for offset, mangled in mangled_oneocr[:200]: # limit + try: + result = subprocess.run( + ['undname', mangled], + capture_output=True, text=True, timeout=2 + ) + if result.returncode == 0: + demangled = result.stdout.strip() + demangled_results.append((offset, mangled, demangled)) + else: + demangled_results.append((offset, mangled, "FAILED")) + except (FileNotFoundError, subprocess.TimeoutExpired): + # undname not available, try manual demangling + # Extract class@namespace patterns + parts = re.findall(r'(\w+)@', mangled) + demangled_results.append((offset, mangled, ' <- '.join(parts) if parts else "UNKNOWN")) + +with open(f"{OUT_DIR}/14_demangled.txt", "w") as f: + f.write("DEMANGLED OneOCR NAMES\n" + "="*60 + "\n") + for offset, mangled, demangled in demangled_results: + f.write(f"\n [{hex(offset)}]\n") + f.write(f" Mangled: {mangled[:200]}\n") + f.write(f" Demangled: {demangled[:200]}\n") +print(f"[14] Demangled: {len(demangled_results)} → {OUT_DIR}/14_demangled.txt") + +print(f"\nDone! All results in {OUT_DIR}/") diff --git a/_archive/temp/re_output/01_exports.txt b/_archive/temp/re_output/01_exports.txt new file mode 100644 index 0000000000000000000000000000000000000000..33ca9be80d4162f342f66877e246b725fdf1b0f7 --- /dev/null +++ b/_archive/temp/re_output/01_exports.txt @@ -0,0 +1,29 @@ +EXPORTS +============================================================ + CreateOcrInitOptions @ 0x28f80 + CreateOcrPipeline @ 0x28bb0 + CreateOcrProcessOptions @ 0x28ff0 + GetImageAngle @ 0x29730 + GetOcrLine @ 0x297b0 + GetOcrLineBoundingBox @ 0x29820 + GetOcrLineContent @ 0x29840 + GetOcrLineCount @ 0x29750 + GetOcrLineStyle @ 0x29870 + GetOcrLineWordCount @ 0x298a0 + GetOcrWord @ 0x298e0 + GetOcrWordBoundingBox @ 0x29930 + GetOcrWordConfidence @ 0x29980 + GetOcrWordContent @ 0x29950 + OcrInitOptionsSetUseModelDelayLoad @ 0x28fe0 + OcrProcessOptionsGetMaxRecognitionLineCount @ 0x29130 + OcrProcessOptionsGetResizeResolution @ 0x290e0 + OcrProcessOptionsSetMaxRecognitionLineCount @ 0x29110 + OcrProcessOptionsSetResizeResolution @ 0x290b0 + ReleaseOcrInitOptions @ 0x299c0 + ReleaseOcrPipeline @ 0x299a0 + ReleaseOcrProcessOptions @ 0x299d0 + ReleaseOcrResult @ 0x29a10 + RunOcrPipeline @ 0x29150 + icudt71_dat @ 0x9fb1c0 + +Total: 25 exports diff --git a/_archive/temp/re_output/02_imports.txt b/_archive/temp/re_output/02_imports.txt new file mode 100644 index 0000000000000000000000000000000000000000..c4fbbd06dc6e0b3844d0a5c71a8e96cb3d922c19 --- /dev/null +++ b/_archive/temp/re_output/02_imports.txt @@ -0,0 +1,211 @@ +IMPORTS +============================================================ + +KERNEL32.dll (183 functions): + GetOEMCP + IsValidCodePage + RemoveDirectoryW + HeapSize + DeleteFileW + CreatePipe + WaitForSingleObject + SetEndOfFile + SetStdHandle + HeapReAlloc + EnumSystemLocalesW + GetUserDefaultLCID + IsValidLocale + GetLocaleInfoW + LCMapStringW + CompareStringW + GetCurrentDirectoryW + FindClose + FindFirstFileW + FindNextFileW + GetLastError + SetLastError + MultiByteToWideChar + WideCharToMultiByte + GetStdHandle + FindFirstFileExW + GetFullPathNameW + GetTempPathA + OutputDebugStringA + InitializeCriticalSection + EnterCriticalSection + LeaveCriticalSection + DeleteCriticalSection + GetWindowsDirectoryA + GetComputerNameA + GetConsoleScreenBufferInfo + SetConsoleTextAttribute + Sleep + GetCurrentThreadId + RtlCaptureStackBackTrace + GetSystemTimeAsFileTime + GetCurrentProcess + GetCommandLineA + FlsGetValue + FlsSetValue + FlsFree + QueryPerformanceCounter + QueryPerformanceFrequency + GetExitCodeProcess + GetNativeSystemInfo + CreateFileA + GetFileAttributesExA + LockFileEx + UnlockFileEx + CloseHandle + FreeLibrary + GetProcAddress + LoadLibraryW + FindFirstFileExA + FindNextFileA + GetModuleHandleA + LoadLibraryA + GetModuleFileNameA + GetModuleFileNameW + GetModuleHandleExA + CreateFileW + GetFileSizeEx + ReadFile + SetFilePointer + WriteFile + MapViewOfFile + UnmapViewOfFile + CreateFileMappingA + GetACP + GetLocaleInfoEx + CreateFileMappingW + ReleaseSRWLockExclusive + AcquireSRWLockExclusive + SleepConditionVariableSRW + GetCommandLineW + GetEnvironmentStringsW + FreeEnvironmentStringsW + GetProcessHeap + FlsAlloc + InitOnceComplete + LocalFree + FormatMessageA + CreateDirectoryW + GetFileAttributesExW + GetFileInformationByHandle + GetFinalPathNameByHandleW + AreFileApisANSI + GetModuleHandleW + GetFileInformationByHandleEx + WriteConsoleW + InitOnceBeginInitialize + WaitForSingleObjectEx + SwitchToThread + GetExitCodeThread + WakeAllConditionVariable + TryAcquireSRWLockExclusive + GetStringTypeW + RtlPcToFileHeader + RaiseException + InitializeCriticalSectionEx + CreateEventExW + CreateSemaphoreExW + FlushProcessWriteBuffers + GetTickCount64 + FreeLibraryWhenCallbackReturns + CreateThreadpoolTimer + SetThreadpoolTimer + WaitForThreadpoolTimerCallbacks + CloseThreadpoolTimer + CreateThreadpoolWait + SetThreadpoolWait + CloseThreadpoolWait + EncodePointer + DecodePointer + LCMapStringEx + CompareStringEx + GetCPInfo + RtlCaptureContext + RtlLookupFunctionEntry + RtlVirtualUnwind + UnhandledExceptionFilter + SetUnhandledExceptionFilter + TerminateProcess + IsProcessorFeaturePresent + GetCurrentProcessId + InitializeSListHead + IsDebuggerPresent + GetStartupInfoW + GetCurrentThread + GetThreadTimes + FreeLibraryAndExitThread + LoadLibraryExW + DuplicateHandle + SetEvent + ReleaseSemaphore + InterlockedPopEntrySList + InterlockedPushEntrySList + InterlockedFlushSList + QueryDepthSList + SignalObjectAndWait + CreateThread + SetThreadPriority + GetThreadPriority + TlsAlloc + TlsGetValue + TlsSetValue + TlsFree + GetCurrentProcessorNumberEx + GetLogicalProcessorInformationEx + GetNumaHighestNodeNumber + GetThreadGroupAffinity + SetThreadGroupAffinity + VerSetConditionMask + VirtualFree + GetProcessAffinityMask + VerifyVersionInfoW + RtlUnwindEx + RtlUnwind + InitializeCriticalSectionAndSpinCount + ExitThread + GetModuleHandleExW + ExitProcess + SetEnvironmentVariableW + GetFileType + GetDriveTypeW + PeekNamedPipe + SystemTimeToTzSpecificLocalTime + FileTimeToSystemTime + GetConsoleMode + ReadConsoleW + GetConsoleOutputCP + CreateProcessW + SetConsoleCtrlHandler + SetFilePointerEx + GetTimeZoneInformation + HeapAlloc + FlushFileBuffers + HeapFree + +bcrypt.dll (12 functions): + BCryptEncrypt + BCryptDestroyKey + BCryptGetProperty + BCryptDecrypt + BCryptOpenAlgorithmProvider + BCryptFinishHash + BCryptCloseAlgorithmProvider + BCryptGenerateSymmetricKey + BCryptCreateHash + BCryptSetProperty + BCryptHashData + BCryptDestroyHash + +dbghelp.dll (5 functions): + SymSetOptions + SymCleanup + SymInitialize + SymFromAddr + UnDecorateSymbolName + +onnxruntime.dll (1 functions): + ord_1 diff --git a/_archive/temp/re_output/03_oneocr_classes.txt b/_archive/temp/re_output/03_oneocr_classes.txt new file mode 100644 index 0000000000000000000000000000000000000000..f28cf2608119f8d800cc09abd9ca3f2cd3ba53a9 --- /dev/null +++ b/_archive/temp/re_output/03_oneocr_classes.txt @@ -0,0 +1,188 @@ +OneOCR C++ CLASSES +============================================================ + OneOCR::0ThreadPool + OneOCR::AURecognizerTextLineDebugInfo + OneOCR::AUTextLineDebugInfo + OneOCR::AVArgMaxDecoder + OneOCR::AVArgMaxLattice + OneOCR::AVAutoGlobalInit + OneOCR::AVAuxMltClsClassifier + OneOCR::AVAuxMltClsClassifierBatch + OneOCR::AVAuxMltClsClassifierFixedWidth + OneOCR::AVAuxMltClsProto + OneOCR::AVAuxMltClsProto_ScriptConsecutiveFramesThresholdEntry_DoNotUse + OneOCR::AVBaseClassifier + OneOCR::AVBaseNormalizer + OneOCR::AVBaseRCNN + OneOCR::AVCharProto + OneOCR::AVCheckboxDetectorProto + OneOCR::AVCnnDbLstm + OneOCR::AVCnnDbLstmTiered + OneOCR::AVCommonNN + OneOCR::AVCommonRCNN + OneOCR::AVConfidenceProto + OneOCR::AVCustomFstProto + OneOCR::AVCustomScenarioProto + OneOCR::AVCustomScenarioProto_GrammarLmEntry_DoNotUse + OneOCR::AVDQDETR + OneOCR::AVDecoderProto + OneOCR::AVDetectorProto + OneOCR::AVDetectorProto_DQDETRConfig + OneOCR::AVDetectorProto_TextlineConfThresholdEntry_DoNotUse + OneOCR::AVEntityClassifierProto + OneOCR::AVEnumsMap + OneOCR::AVEnumsMap_OcrModeToPathMapEntry + OneOCR::AVEnumsMap_OcrModeToTextCategoryMapEntry + OneOCR::AVEnumsMap_OcrModeToTextScriptMapEntry + OneOCR::AVEnumsMap_TextScriptTextCategoryToOcrModeMapEntry + OneOCR::AVEnumsMap_TextScriptToOcrModeMapEntry + OneOCR::AVFontClassifier + OneOCR::AVFontClsProto + OneOCR::AVFormDetectorProto + OneOCR::AVIDecoder + OneOCR::AVILattice + OneOCR::AVIModelInferencer + OneOCR::AVINNFramework + OneOCR::AVITensorMapView + OneOCR::AVLangIDProto + OneOCR::AVLineLayoutClassifier + OneOCR::AVLineLayoutClsProto + OneOCR::AVLineLayoutInterface + OneOCR::AVMathFmDetProto + OneOCR::AVMathFmLineAttnProto + OneOCR::AVMathFmLineDecProto + OneOCR::AVMathFmLineEncProto + OneOCR::AVMathFmLineRejProto + OneOCR::AVMathFmParagraphProto + OneOCR::AVModelPack + OneOCR::AVONNXProto + OneOCR::AVOrtCudaFramework + OneOCR::AVOrtFramework + OneOCR::AVOrtQnnFramework + OneOCR::AVOrtTensorRTFramework + OneOCR::AVPODBackboneProto + OneOCR::AVPODReadingOrderProto + OneOCR::AVPODRegionGroupingProto + OneOCR::AVPipeline + OneOCR::AVPipelineProto + OneOCR::AVPipelineProto_Engine + OneOCR::AVPipelineProto_EngineOption + OneOCR::AVPipelineProto_RejectionOption + OneOCR::AVPipelineProto_RuntimeOption + OneOCR::AVPipelineProto_RuntimeOption_RuntimeOptionEntry_DoNotUse + OneOCR::AVPipelineProto_Scheduling + OneOCR::AVPipelineProto_TextlineImagesBatcher + OneOCR::AVPolygon + OneOCR::AVRawConcatTextLines + OneOCR::AVRejectionProto + OneOCR::AVRelationRCNN + OneOCR::AVRelationRCNNRpn + OneOCR::AVRelationRCNNRpn2 + OneOCR::AVRelationRCNNRpn2FixedSize + OneOCR::AVRingPolygon + OneOCR::AVSimpleTensorMap + OneOCR::AVTOCProto + OneOCR::AVTableDetectorProto + OneOCR::AVTableRecognizerProto + OneOCR::AVTensorMapProto + OneOCR::AVTensorMapProto_Tensor + OneOCR::AVTensorMapProto_TensorsEntry_DoNotUse + OneOCR::AVTextAnalyzer + OneOCR::AVTextAnalyzerImpl + OneOCR::AVTextDetector + OneOCR::AVTextDetectorImpl + OneOCR::AVTextEmbeddingProto + OneOCR::AVTextLineRecognizer + OneOCR::AVTextLineRecognizerImpl + OneOCR::AVTextNormalizer + OneOCR::AVTextPipeline + OneOCR::AVTextPipelineDev + OneOCR::AVTextPipelineDevImpl + OneOCR::AVTieredModelPack + OneOCR::AVUnownedTensorMap + OneOCR::AW4TextLineLayout + OneOCR::AdaptiveScalingController + OneOCR::AuxMltClsClassifier + OneOCR::AuxMltClsClassifierFixedWidth + OneOCR::BaseNormalizer + OneOCR::BaseRCNN + OneOCR::CharacterMap + OneOCR::Cipher + OneOCR::DQDETR + OneOCR::Interop + OneOCR::LatMBRAdapter + OneOCR::P8CnnDbLstmTiered + OneOCR::P8TextLineRecognizerImpl + OneOCR::PEAVCnnDbLstm + OneOCR::PEAVCnnDbLstmTiered + OneOCR::PEAVConfidenceProcessor + OneOCR::PEAVDQDETR + OneOCR::PEAVIDecoder + OneOCR::PEAVILattice + OneOCR::PEAVRejectionProcessor + OneOCR::PEAVTextLine + OneOCR::PEAVTextLinePolygon + OneOCR::PEAVTextLineRecognizerImpl + OneOCR::QEAVAuxMltClsProto + OneOCR::QEAVCharProto + OneOCR::QEAVCheckboxDetectorProto + OneOCR::QEAVConfidenceProto + OneOCR::QEAVCustomFstProto + OneOCR::QEAVDecoderProto + OneOCR::QEAVDetectorProto + OneOCR::QEAVEntityClassifierProto + OneOCR::QEAVFontClsProto + OneOCR::QEAVFormDetectorProto + OneOCR::QEAVLangIDProto + OneOCR::QEAVLineLayoutClsProto + OneOCR::QEAVMathFmDetProto + OneOCR::QEAVMathFmLineAttnProto + OneOCR::QEAVMathFmLineDecProto + OneOCR::QEAVMathFmLineEncProto + OneOCR::QEAVMathFmLineRejProto + OneOCR::QEAVMathFmParagraphProto + OneOCR::QEAVPODBackboneProto + OneOCR::QEAVPODReadingOrderProto + OneOCR::QEAVPODRegionGroupingProto + OneOCR::QEAVRejectionProto + OneOCR::QEAVTOCProto + OneOCR::QEAVTableDetectorProto + OneOCR::QEAVTableRecognizerProto + OneOCR::QEAVTextEmbeddingProto + OneOCR::RelationRCNNRpn + OneOCR::RelationRCNNRpn2 + OneOCR::ReloadPipelineProto + OneOCR::SHA256Hash + OneOCR::SeglinkProposal + OneOCR::TextAnalyzerImpl + OneOCR::TextLineRecognizerImpl + OneOCR::TextPipelineDevImpl + OneOCR::ThreadPool + OneOCR::UAuxMltClsInfo + OneOCR::UBarcodePolygon + OneOCR::ULatticeResult + OneOCR::ULine + OneOCR::URecognizerTextLineResult + OneOCR::Utility + OneOCR::VAuxMltClsProto_ScriptConsecutiveFramesThresholdEntry_DoNotUse + OneOCR::VBaseRCNN + OneOCR::VCscMatrix + OneOCR::VCustomFstProto + OneOCR::VCustomScenarioProto_GrammarLmEntry_DoNotUse + OneOCR::VDQDETR + OneOCR::VDetectorProto_TextlineConfThresholdEntry_DoNotUse + OneOCR::VEnumMapper + OneOCR::VITensorMapView + OneOCR::VImageFeature + OneOCR::VPipelineProto_RuntimeOption_RuntimeOptionEntry_DoNotUse + OneOCR::VRawConcatTextLines + OneOCR::VRelationRCNN + OneOCR::VRelationRCNNRpn + OneOCR::VRelationRCNNRpn2 + OneOCR::VRelationRCNNRpn2FixedSize + OneOCR::VTensorMapProto_Tensor + OneOCR::VTensorMapProto_TensorsEntry_DoNotUse + OneOCR::VTextLine + OneOCR::VTextLinePolygon + OneOCR::VXnnResult + OneOCR::W4TextLineLayout diff --git a/_archive/temp/re_output/04_tensor_names.txt b/_archive/temp/re_output/04_tensor_names.txt new file mode 100644 index 0000000000000000000000000000000000000000..7629827dc9b613f8d175f1d9023a32ca0883b48b --- /dev/null +++ b/_archive/temp/re_output/04_tensor_names.txt @@ -0,0 +1,238 @@ +TENSOR/MODEL NAMES +============================================================ + [0x82b575] output_type + [0x82df38] CHECK failed: output->message_info.prototype != nullptr: + [0x8307a8] Number of columns to use in output for tab completion + [0x8315d0] !image.empty() + [0x8315e0] image.channels() == 1 || image.channels() == 3 || image.channels() == 4 + [0x831be0] Raw image encoder error: + [0x831ed0] ((uint64)m_height * m_width * nch < (CV_BIG_UINT(1) << 30)) && "BMP reader implementation doesn't support large images >= 1Gb" + [0x832580] Portable image format - auto (*.pnm) + [0x8325a8] Portable image format - monochrome (*.pbm) + [0x8325d8] Portable image format - gray (*.pgm) + [0x832600] Portable image format - color (*.ppm) + [0x832660] Portable bitmap(.pgm) expects gray image + [0x832690] Portable bitmap(.ppm) expects BGR image + [0x832970] Portable image format - float (*.pfm) + [0x8329b0] Expected 1 or 3 channel image. + [0x833200] TIFF-8bpp: BGR/BGRA images are supported only + [0x833308] TIFF-16bpp: BGR/BGRA images are supported only + [0x834410] ): failed TIFFSetField(tif, TIFFTAG_PREDICTOR, predictor) + [0x834450] OpenCV TIFF: failed TIFFSetField(tif, TIFFTAG_PREDICTOR, predictor) + [0x836090] missing image size specifier + [0x8422b0] The image/matrix format is not supported by the function + [0x842410] [Start]FindContours supports only CV_8UC1 images when mode != CV_RETR_FLOODFILL otherwise supports CV_32SC1 images only + [0x8450a8] Invalid number of channels in input image + [0x845120] Invalid number of channels in output image + [0x845198] Unsupported depth of input image + [0x866036] #error "(nimages <= 2) should be true" + [0x88f467] T1 image = *(__global const T1*)(img + mad24(y, img_step, mad24(x, (int)sizeof(T1)*cn, img_offset)));; + [0x88f51a] *(__global float *)(res + res_idx) = image; + [0x8902f1] float image_sqsum_ = (float)(sqsum[SQSUMS_PTR(template_cols, template_rows)] - sqsum[SQSUMS_PTR(template_cols, 0)] - + [0x89042f] *dstult = normAcc(*dstult, sqrt(image_sqsum_ * template_sqsum[0])); + [0x890a2c] float image_sqsum_ = (float)( + [0x890b9f] *dstult = image_sqsum_ - 2.0f * dstult[0] + template_sqsum_value; + [0x890f6f] *dstult = normAcc_SQDIFF(image_sqsum_ - 2.0f * dstult[0] + template_sqsum_value, sqrt(image_sqsum_ * template_sqsum_value)); + [0x89120f] T image_sum = (T)(0), value; + [0x8912ac] image_sum = mad(value, template_sum , image_sum); + [0x89132a] *(__global float *)(dst + dst_idx) -= convertToDT(image_sum); + [0x8914d2] T image_sum = (T)(0), value, temp_sum; + [0x891688] image_sum = mad(value, temp_sum , 0); + [0x891a60] image_sum = mad(value, temp_sum , image_sum); + [0x8a1e93] #define READ_IMAGE(X,Y,Z) read_imagef(X,Y,Z).x + [0x8a1ef2] #define READ_IMAGE(X,Y,Z) read_imagef(X,Y,Z).xy + [0x8a1f53] #define READ_IMAGE(X,Y,Z) read_imagef(X,Y,Z).xyz + [0x8a1fb5] #define READ_IMAGE(X,Y,Z) read_imagef(X,Y,Z) + [0x8a2144] __kernel void resizeSampler(__read_only image2d_t srcImage, + [0x8e51b0] Can't reallocate Mat with locked type (probably due to misused 'const' modifier) + [0x8e5260] Can't reallocate Mat with locked size (probably due to misused 'const' modifier) + [0x8e5340] Can't reallocate UMat with locked type (probably due to misused 'const' modifier) + [0x8e53d0] Can't reallocate UMat with locked size (probably due to misused 'const' modifier) + [0x8e55f0] !(m.empty() && fixedType() && fixedSize()) && "Can't reallocate empty Mat with locked layout (probably due to misused 'const' modifier)" + [0x8e5680] !(m.empty() && fixedType() && fixedSize()) && "Can't reallocate empty UMat with locked layout (probably due to misused 'const' modifier)" + [0x8e58e8] create() called for the missing output array + [0x8e6420] When the input arrays in add/subtract/multiply/divide functions have different types, the output array type must be explicitly specified + [0x8e93b0] Input image depth is not supported by function + [0x8ebc20] cl_khr_image2d_from_buffer + [0x8ef318] ocl::Device::getDefault().imageSupport() + [0x8f1ab0] Element size doesn't match to the size of predefined element type (try to use 0 for sequence element type) + [0x8f3140] The image has NULL data pointer + [0x8f31a0] The image is interleaved and has over CV_CN_MAX channels + [0x8fa5a9] read_only image2d_t imgY, + [0x8fa5c3] read_only image2d_t imgUV, + [0x8fa717] float4 Y1 = read_imagef(imgY, (int2)(x2 + 0, y2 + 0)); + [0x8fa74e] float4 Y2 = read_imagef(imgY, (int2)(x2 + 1, y2 + 0)); + [0x8fa785] float4 Y3 = read_imagef(imgY, (int2)(x2 + 0, y2 + 1)); + [0x8fa7bc] float4 Y4 = read_imagef(imgY, (int2)(x2 + 1, y2 + 1)); + [0x8fa820] float4 UV = read_imagef(imgUV, (int2)(x, y)) - d2; + [0x8fad1d] write_only image2d_t imgY, + [0x8fad38] write_only image2d_t imgUV) + [0x8fb22b] write_imagef(imgY, (int2)(x2+0, y2+0), Y1); + [0x8fb257] write_imagef(imgY, (int2)(x2+1, y2+0), Y2); + [0x8fb283] write_imagef(imgY, (int2)(x2+0, y2+1), Y3); + [0x8fb2af] write_imagef(imgY, (int2)(x2+1, y2+1), Y4); + [0x8fb2db] write_imagef(imgUV, (int2)(x, y), UV); + [0x90839c] float output = 0.0f; + [0x9083c8] output = (local_x == 0) ? _dot.s0 : output; \ + [0x9083f6] output = (local_x == 1) ? _dot.s1 : output; \ + [0x908424] output = (local_x == 2) ? _dot.s2 : output; \ + [0x908452] output = (local_x == 3) ? _dot.s3 : output; \ + [0x908480] output = (local_x == 4) ? _dot.s4 : output; \ + [0x9084ae] output = (local_x == 5) ? _dot.s5 : output; \ + [0x9084dc] output = (local_x == 6) ? _dot.s6 : output; \ + [0x90850a] output = (local_x == 7) ? _dot.s7 : output; \ + [0x90854c] dst_write0[0] = mad(output, (float)alpha, ((float)beta * dst_write0[0])); \ + [0x90859f] dst_write0[0] = output * (float)alpha; \ + [0x924ef0] There are several neighbour directories, probably created by old OpenCV versions. + [0x930120] IDCT output block size %d not supported + [0x9304d8] Empty JPEG image (DNL not supported) + [0x930618] Maximum supported image dimension is %u pixels + [0x9307b0] JPEG datastream contains no image + [0x930dc0] Warning: thumbnail image size does not match data length %u + [0x930e30] with %d x %d thumbnail image + [0x9310b0] JFIF extension marker: JPEG-compressed thumbnail image, length %u + [0x9310f8] JFIF extension marker: palette thumbnail image, length %u + [0x931138] JFIF extension marker: RGB thumbnail image, length %u + [0x96e118] png_read_update_info/png_start_read_image: duplicate call + [0x96e158] png_start_read_image/png_read_update_info: duplicate call + [0x96e230] Interlace handling should be turned on when using png_read_image + [0x96e368] Valid palette required for paletted images + [0x96f590] Invalid image width in IHDR + [0x96f5f8] Invalid image height in IHDR + [0x96f797] Cinvalid after png_start_read_image or png_read_update_info + [0x96f8f8] Palette is NULL in indexed image + [0x970920] Not enough image data + [0x970950] Too much image data + [0x970a88] Invalid bit depth for grayscale image + [0x970ab0] Invalid bit depth for RGB image + [0x970ad0] Invalid bit depth for paletted image + [0x970af8] Invalid bit depth for grayscale+alpha image + [0x970b28] Invalid bit depth for RGBA image + [0x970b50] Invalid image color type specified + [0x970c48] Z_OK on Z_FINISH with output space + [0x971f00] TIFF directory is missing required "StripByteCounts" field, calculating from imagelength + [0x971f60] Bogus "StripByteCounts" field, ignoring and calculating from imagelength + [0x971fb0] Wrong "StripByteCounts" field, ignoring and calculating from imagelength + [0x9721d0] Sanity check on directory count failed, this is probably not a valid IFD offset + [0x9732b0] Value exceeds 32bit range of output type. + [0x9732e0] Value exceeds 16bit range of output type. + [0x973450] Zero strips per image + [0x973468] Can not grow image by strips when using separate planes + [0x973530] Can not write tiles to a striped image + [0x973558] Can not write scanlines to a tiled image + [0x973618] No space for output buffer + [0x9737d8] Sorry, can not handle images with %hu-bit samples + [0x973810] Sorry, can not handle images with IEEE floating-point samples + [0x9738e8] Sorry, can not handle RGB image with %s=%d + [0x973920] Sorry, can not handle separated image with %s=%d + [0x973958] Sorry, can not handle separated image with %s=%hu + [0x973a00] Sorry, can not handle LogLuv images with %s=%hu + [0x973a40] Sorry, can not handle image with %s=%hu, %s=%d + [0x973a80] Sorry, can not handle image with %s=%hu, %s=%d and %s=%hu + [0x973ac0] Sorry, can not handle image with %s=%hu + [0x973b28] Sorry, can not handle image + [0x973b60] No "put" routine setupl; probably can not handle image format + [0x974408] Can not read tiles from a striped image + [0x974430] Can not read scanlines from a tiled image + [0x9798f0] scanline oriented access is not supported for downsampled JPEG compressed images, consider enabling TIFF_JPEGCOLORMODE as JPEGCOLORMODE_RGB. + [0x97b300] Wrong length of decoded string: data probably corrupted at scanline %u + [0x97be70] Incompatible vertical subsampling and image strip/tile length + [0x97beb0] jpeg_start_decompress() returned image_width = %u, expected %u + [0x97c110] JPEG compressed data image width exceeds expected image width + [0x97cf30] Sorry, can not handle LogL image with %s=%hu + [0x995df0] floating point predictor + [0x27080c8] Input/output error + [0x2711a4b] image_crop_total_ms + [0x2711f38] resize_image_ms + [0x2712004] image_feature_postprocess_ms + [0x2712165] accumulated_image_count + [0x2712186] accumulated_image_width + [0x2712566] image_rotation_ms + [0x2712581] image_resize_ms + [0x2712645] accumulated_image_resize_ms + [0x2712f2a] accumulated_attention_ms + [0x2712fc5] image_rotate_angle + [0x2713530] is_output_as_handwritten + [0x2713560] word_level_scores + [0x2713595] text_line_weighted_scores + [0x2713ae4] original_image_height + [0x2713b03] original_image_width + [0x2713b21] resized_image_height + [0x2713b3f] resized_image_width + [0x2714542] image_detect + [0x271458f] image_norm + [0x27164d7] image_resize_factor + [0x27166db] checkbox_featuremap_stride + [0x27170b1] sparse_xnn_min_prob + [0x27172fd] rej_prob + [0x271730f] rej_prob_single + [0x2717561] image_means_b + [0x2717578] image_means_g + [0x271758f] image_means_r + [0x27175a6] image_std_inverse_b + [0x27175c3] image_std_inverse_g + [0x27175e0] image_std_inverse_r + [0x27187f6] textline_images_batcher + [0x271d7e0] TextPipelineDevImpl::Recognize only supports single image input. + [0x271d828] imageList.Size() == 1 + [0x271e908] script_id_score + [0x271e918] hwpc_score + [0x271e928] script_id_perframe_predict + [0x271e948] flip_score + [0x271e958] hwpc_perframe_predict + [0x271eb28] flip_perframe_predict + [0x271eb40] line_layout_perframe_predict + [0x271edf0] outputSize.width * outputSize.height * im.channels() == outputToAppend.size() + [0x271eea0] outputSize.height == im.rows + [0x271ef98] font_weight_perframe_predict + [0x271efb8] font_style_perframe_predict + [0x271efe8] font_perframe_predict + [0x271f050] dataPtr - data == outputMarginWidth * lastDimension + std::accumulate(dims.begin(), dims.end(), static_cast(1), std::multiplies {}) + [0x271f158] Input image [ + [0x271f680] sentence rej prob: + [0x271f698] word rej prob: + [0x2720c78] Bad memory access when building physical scores. + [0x2720db0] logsoftmax + [0x2720df8] Invalid CM output: + [0x2720fa8] seq_lengths + [0x2721f20] image.type() == (((5) & ((1 << 3) - 1)) + (((3)-1) << 3)) + [0x2721fa0] imageList.Size() > 0 + [0x2722038] bbox_deltas_ + [0x2722048] link_scores_ + [0x2722058] scores_ + [0x2722618] fpnlvl_featmap_routing_table.count(fpnlvl) > 0 + [0x2722668] imageCount == static_cast(imageSizeInfoList.size()) + [0x27226e0] im_info + [0x27226e8] rpn_rois_fpn + [0x27226f8] feature_p2 + [0x2722708] featuremap_cond + [0x2722730] m_bHasBatchDimension || (imageList.Size() == 1) + [0x2722780] checkbox_scores + [0x27227d8] imgCount == preprocessOutput.imageCount + [0x2722890] rawImages.size() == preprocessOutput.imageCount + [0x27228c0] Input image count doesn't match with detector output count. + [0x2722930] hori_fpn + [0x2722950] vert_fpn + [0x2722960] rel_cls_prob_ + [0x2722970] RCNN's output number mismatch. + [0x2722ab4] scores + [0x2722b58] obj_scores + [0x2722bc8] scores.dims[0] == num + [0x2722ce8] scores_concat_compress + [0x2722d10] link_scores_concat_compress + [0x2722d30] bbox_deltas_concat_compress + [0x2723110] rpn_rois_fpn3 + [0x2723120] rpn_rois_fpn4 + [0x2723148] rpn_rois_fpn2 + [0x2724050] scores.Shape().NumDimensions() == 4 + [0x27244d0] scores_vert.Shape().NumDimensions() == 4 + [0x27259d8] m_images[i].isContinuous() + [0x2725a70] processOptions.empty() || processOptions.size() == images.size() + [0x2725ab8] !images.empty() + [0x27263a0] Invalid size for image + [0x27263d0] images[0].type() == (((5) & ((1 << 3) - 1)) + (((3)-1) << 3)) + [0x2726410] image.cols <= finalImageWidth && image.rows <= finalImageHeight + [0x2726450] Doesn't support image format with channel + [0x27266c0] featureHeight >= imageHeight + [0x27266e0] featureWidth >= imageWidth + [0x272b5a8] Math formula line encoder attention model dir diff --git a/_archive/temp/re_output/05_source_files.txt b/_archive/temp/re_output/05_source_files.txt new file mode 100644 index 0000000000000000000000000000000000000000..ab451216fe970c3cff4aaf478139dcf6d759ad29 --- /dev/null +++ b/_archive/temp/re_output/05_source_files.txt @@ -0,0 +1,81 @@ +SOURCE FILE REFERENCES +============================================================ + [0x271d880] C:\__w\1\s\CoreEngine\Native\TextPipeline\TextPipelineDevImpl.cpp + [0x271db78] C:\__w\1\s\CoreEngine\Native\Common/CollectionUtility.h + [0x271dc20] C:\__w\1\s\CoreEngine\Native\Common/thread_pool.h + [0x271df20] C:\__w\1\s\CoreEngine\Native\TextPipeline\FilterXY.cpp + [0x271dff8] C:\__w\1\s\CoreEngine\Native\Common/EnumUtility.h + [0x271e250] C:\__w\1\s\CoreEngine\Native\TextAnalyzer\TextAnalyzerImpl.cpp + [0x271e9e0] C:\__w\1\s\CoreEngine\Native\TextAnalyzer\AuxMltClsClassifier.cpp + [0x271ebd0] C:\__w\1\s\CoreEngine\Native\TextAnalyzer\AuxMltClsClassifierFixedWidth.cpp + [0x271ed88] C:\__w\1\s\CoreEngine\Native\Common/INNFramework.h + [0x271ee40] C:\__w\1\s\CoreEngine\Native\Common/ImageUtility.h + [0x271f000] C:\__w\1\s\CoreEngine\Native\TextAnalyzer\AuxMltClsClassifierBatch.cpp + [0x271f118] C:\__w\1\s\CoreEngine\Native\TextAnalyzer\BaseClassifier.cpp + [0x271f200] C:\__w\1\s\CoreEngine\Native\TextRecognizer\TextLineRecognizerImpl.cpp + [0x271f778] C:\__w\1\s\CoreEngine\Native\Common/DelayLoadPtr.h + [0x271fc00] C:\__w\1\s\CoreEngine\Native\TextRecognizer\ArgMaxDecoder.cpp + [0x2720020] C:\__w\1\s\CoreEngine\Native\TextRecognizer\CharacterMap\Sentence.cpp + [0x27204d0] C:\__w\1\s\CoreEngine\Native\TextRecognizer\CharacterMap\CharacterMapper.cpp + [0x27209d0] C:\__w\1\s\CoreEngine\Native\TextRecognizer\LatMBRAdapter.cpp + [0x2720c08] C:\__w\1\s\CoreEngine\Native\TextRecognizer/SparseMatrix.h + [0x2720cb0] C:\__w\1\s\CoreEngine\Native\TextRecognizer\XnnResult.cpp + [0x2720d00] C:\__w\1\s\CoreEngine\Native\TextRecognizer\ConfidenceProcessor.cpp + [0x2720dc0] C:\__w\1\s\CoreEngine\Native\TextRecognizer\DbLstm.cpp + [0x27210a0] C:\__w\1\s\CoreEngine\Native\TextRecognizer\DbLstmTiered.cpp + [0x2721120] C:\__w\1\s\CoreEngine\Native\TextRecognizer\RejectionProcessor.cpp + [0x2721400] C:\__w\1\s\CoreEngine\Native\TextNormalizer\ConcatTextLines.cpp + [0x2721528] C:\__w\1\s\CoreEngine\Native\TextNormalizer\BaseNormalizer.cpp + [0x2721620] C:\__w\1\s\CoreEngine\Native\TextNormalizer\TextLocationMapper.cpp + [0x27216e0] C:\__w\1\s\CoreEngine\Native\TextNormalizer/TextLocationMapper.h + [0x27217c0] C:\__w\1\s\CoreEngine\Native\TextDetector\TextLinePolygon.cpp + [0x27219e0] C:\__w\1\s\CoreEngine\Native\TextDetector\PolygonIntersectionCache.cpp + [0x2721b38] C:\__w\1\s\CoreEngine\Native\TextDetector\PolyFitting.cpp + [0x2721c10] C:\__w\1\s\CoreEngine\Native\TextDetector\TextDetectorImpl.cpp + [0x2721e50] C:\__w\1\s\CoreEngine\Native\TextDetector\RelationRCNNRpn2FixedSize.cpp + [0x27221e8] C:\__w\1\s\CoreEngine\Native\TextDetector\AdaptiveScaling.cpp + [0x27226a8] C:\__w\1\s\CoreEngine\Native\TextDetector/BaseRCNN.h + [0x2722828] C:\__w\1\s\CoreEngine\Native\TextDetector\BaseRCNN.cpp + [0x27229c8] C:\__w\1\s\CoreEngine\Native\TextDetector\RelationRCNN.cpp + [0x2722ac0] C:\__w\1\s\CoreEngine\Native\TextDetector/DQDETR.h + [0x2722b08] C:\__w\1\s\CoreEngine\Native\TextDetector\DQDETR.cpp + [0x2722c40] C:\__w\1\s\CoreEngine\Native\TextDetector\RelationRCNNRpn2.cpp + [0x2722c80] C:\__w\1\s\CoreEngine\Native\TextDetector/SeglinkGroup.h + [0x2722f08] C:\__w\1\s\CoreEngine\Native\TextDetector\BarcodePolygon.cpp + [0x2722ff0] C:\__w\1\s\CoreEngine\Native\TextDetector\SeglinkProposal.cpp + [0x2723228] C:\__w\1\s\CoreEngine\Native\ModelInferencer\CommonRCNN.cpp + [0x27232a0] C:\__w\1\s\CoreEngine\Native\CommonInference\NNFrameworkFactory.cpp + [0x2723370] C:\__w\1\s\CoreEngine\Native\CustomOps/onnxruntime/PackImageToSeqOp.h + [0x27233d0] C:\__w\1\s\CoreEngine\Native\CustomOps/onnxruntime/SplitFromSequenceOp.h + [0x2723468] C:\__w\1\s\CoreEngine\Native\OrtInference\OrtQnnFramework.cpp + [0x2723c58] C:\__w\1\s\CoreEngine\Native\OrtInference/OrtTensorMapView.h + [0x2723cd0] C:\__w\1\s\CoreEngine\Native\OrtInference\OrtFramework.cpp + [0x2723e80] C:\__w\1\s\CoreEngine\Native\OrtInference\OrtEnvironment.cpp + [0x2724000] C:\__w\1\s\CoreEngine\Native\CustomOps\onnxruntime\SeglinkProposalsOp.cpp + [0x27240a8] C:\__w\1\s\CoreEngine\Native\CustomOps/onnxruntime/OrtTensor.h + [0x2724180] C:\__w\1\s\CoreEngine\Native\CustomOps\onnxruntime\GenerateRelatedCellPairsOp.cpp + [0x2724220] C:\__w\1\s\CoreEngine\Native\CustomOps\onnxruntime\LeftPoolingOp.cpp + [0x27242a0] C:\__w\1\s\CoreEngine\Native\CustomOps\onnxruntime\FeatureExtractOp.cpp + [0x2724480] C:\__w\1\s\CoreEngine\Native\CustomOps\onnxruntime\XYSeglinkProposalsOp.cpp + [0x2724510] C:\__w\1\s\CoreEngine\Native\CustomOps\onnxruntime\RightPoolingOp.cpp + [0x2724560] C:\__w\1\s\CoreEngine\Native\CustomOps\onnxruntime\BottomPoolingOp.cpp + [0x2724640] C:\__w\1\s\CoreEngine\Native\CustomOps\onnxruntime\SVDSoftmaxOp.cpp + [0x2724730] C:\__w\1\s\CoreEngine\Native\CustomOps\onnxruntime\TopPoolingOp.cpp + [0x27247d0] C:\__w\1\s\CoreEngine\Native\CustomOps\onnxruntime\GenerateSLPOp.cpp + [0x27248c0] C:\__w\1\s\CoreEngine\Native\CustomOps\common\XYSeglinkProposalsOpBase.cpp + [0x2724990] C:\__w\1\s\CoreEngine\Native\CustomOps/common/SeglinkProposalsOpUtilsBox.h + [0x2724a30] C:\__w\1\s\CoreEngine\Native\CustomOps\common\SeglinkProposalsOpBase.cpp + [0x2724a80] C:\__w\1\s\CoreEngine\Native\ModelParser\ModelParser.cpp + [0x2724c08] C:\__w\1\s\CoreEngine\Native\ModelParser\Crypto.cpp + [0x2725450] C:\__w\1\s\CoreEngine\Native\LatticeDecoder\latmbr\quantized_wfst.cpp + [0x27257b0] C:\__w\1\s\CoreEngine\Native\LatticeDecoder\latmbr\wfst_v2.cpp + [0x27258e0] C:\__w\1\s\CoreEngine\Native\LatticeDecoder\latmbr\quantization.cpp + [0x27259f8] C:\__w\1\s\CoreEngine\Native\Common\ImageList.cpp + [0x2725b88] C:\__w\1\s\CoreEngine\Native\Common\init.cpp + [0x2725e88] C:\__w\1\s\CoreEngine\Native\Common\EnumMapper.cpp + [0x27262a0] C:\__w\1\s\CoreEngine\Native\Common\JsonUtility.cpp + [0x2726480] C:\__w\1\s\CoreEngine\Native\Common\ImageUtility.cpp + [0x2726608] C:\__w\1\s\CoreEngine\Native\Common\PolygonIntersection.cpp + [0x2726700] C:\__w\1\s\CoreEngine\Native\Common\ImageFeature.cpp + [0x2726738] C:\__w\1\s\CoreEngine\Native\Common\FileUtility.cpp + [0x272a568] C:\__w\1\s\CoreEngine\proto\proto_utils.cpp diff --git a/_archive/temp/re_output/06_config_strings.txt b/_archive/temp/re_output/06_config_strings.txt new file mode 100644 index 0000000000000000000000000000000000000000..2af6bb7882ee81b34bb9e1194299548c4f12a475 --- /dev/null +++ b/_archive/temp/re_output/06_config_strings.txt @@ -0,0 +1,431 @@ +CONFIG/THRESHOLD STRINGS +============================================================ + [0x82f0f0] stderrthreshold + [0x832950] fabs(m_scale_factor) > 0.0f + [0x835264] GRAYSCALE + [0x835384] GRAYSCALE_ALPHA + [0x8362b0] cv::normalizeAnchor + [0x8362c8] anchor.inside(Rect(0, 0, ksize.width, ksize.height)) + [0x836df0] BORDER_CONSTANT + [0x836e00] BORDER_REPLICATE + [0x836e18] BORDER_REFLECT + [0x836e28] BORDER_REFLECT_101 + [0x836e60] BORDER_ISOLATED + [0x836e70] NO_BORDER_ISOLATED + [0x836e90] -D cn=%d -D ANCHOR_X=%d -D ANCHOR_Y=%d -D KERNEL_SIZE_X=%d -D KERNEL_SIZE_Y=%d -D PX_LOAD_VEC_SIZE=%d -D PX_LOAD_NUM_PX=%d -D DEPTH_%d -D PX_PER_WI_X=%d -D PX_PER_WI_Y=%d -D PRIV_DATA_WIDTH=%d -D %s -D %s -D PX_LOAD_X_ITERATIONS=%d -D PX_LOAD_Y_ITERATIONS=%d -D srcT=%s -D srcT1=%s -D dstT=srcT -D dstT1=srcT1 -D WT=%s -D WT1=%s -D convertToWT=%s -D convertToDstT=%s -D PX_LOAD_FLOAT_VEC_CONV=convert_%s -D PROCESS_ELEM_=%s -D %s%s + [0x83d000] -D convertToT=%s -D WT2V=%s -D convertToWT2V=%s -D INTER_AREA_FAST -D XSCALE=%d -D YSCALE=%d -D SCALE=%ff + [0x83d170] (dst_width > 0 && dst_height > 0) || (inv_scale_x > 0 && inv_scale_y > 0) + [0x83d2f0] inv_scale_x > 0 + [0x83d300] inv_scale_y > 0 + [0x83e888] -D %s -D T=%s -D T1=%s -D STRIDE_SIZE=%d%s + [0x83e8b8] threshold + [0x83e8f0] double __cdecl cv::threshold(const class cv::_InputArray &,const class cv::_OutputArray &,double,double,int) + [0x83e9e8] cv::threshold + [0x83ea60] void __cdecl cv::adaptiveThreshold(const class cv::_InputArray &,const class cv::_OutputArray &,double,int,int,int,double) + [0x83eae0] cv::adaptiveThreshold + [0x83eb20] Unknown/unsupported adaptive threshold method + [0x83eb50] Unknown/unsupported threshold type + [0x83eb78] cvThreshold + [0x83ef18] BORDER_WRAP + [0x83ef28] BORDER_TRANSPARENT + [0x8439b0] src.depth() == DataType::depth && ((borderType & BORDER_ISOLATED) || !src.isSubmatrix()) + [0x8479c0] -D dcn=%d -D bidx=%d -D hrange=%d -D hscale=%ff + [0x847a00] -D hscale=%ff -D bidx=%d -D dcn=3 + [0x8510c0] columnBorderType != BORDER_WRAP + [0x851120] 0 <= anchor.x && anchor.x < ksize.width && 0 <= anchor.y && anchor.y < ksize.height + [0x86307b] #ifdef BORDER_CONSTANT + [0x863092] #elif defined BORDER_REPLICATE + [0x863131] #elif defined BORDER_WRAP + [0x86322f] #elif defined(BORDER_REFLECT) || defined(BORDER_REFLECT_101) + [0x863424] #ifdef BORDER_REFLECT + [0x86349a] #elif defined(BORDER_REFLECT_101) + [0x863665] #ifdef BORDER_ISOLATED + [0x863aa0] int x = get_local_id(0) + (LOCAL_SIZE_X - (KERNEL_SIZE_X - 1)) * get_group_id(0) - ANCHOR_X; + [0x863b82] int2 srcPos = (int2)(srcCoords.x1 + x, srcCoords.y1 + y - ANCHOR_Y); + [0x863dc2] if (local_id >= ANCHOR_X && local_id < LOCAL_SIZE_X - (KERNEL_SIZE_X - 1 - ANCHOR_X) && + [0x863e82] total_sum += sumOfCols[local_id + sx - ANCHOR_X]; + [0x86443f] #elif defined BORDER_REFLECT_101 + [0x8644f4] #elif defined (BORDER_REPLICATE) || defined(BORDER_REFLECT) + [0x8656be] __global int * lut, float scale, __constant float * ranges) + [0x8658c2] lut[x] = (int)convert_uchar_sat_rte(hist[0] * scale); + [0x865d9c] __constant int * lut, float scale, + [0x865fe1] mad24(hist_step, bin1, hist_offset + bin2 * (int)sizeof(float))) * scale); + [0x868734] const int clipLimit, const float lutScale) + [0x868b49] uint ires = (uint)convert_int_rte(lutScale * lutVal); + [0x8693bb] #define CV_DESCALE(x,n) (((x) + (1 << ((n)-1))) >> (n)) + [0x869469] #ifndef hscale + [0x869478] #define hscale 0 + [0x869ce1] h *= hscale; + [0x86a3cb] dst[0] = h*hscale; + [0x86ad55] dst[dst_index] = convert_uchar_sat_rte(h*hscale); + [0x86c4c4] int x = CV_DESCALE(mad24(r, coeffs[0], mad24(g, coeffs[1], b * coeffs[2])), xyz_shift); + [0x86c51c] int y = CV_DESCALE(mad24(r, coeffs[3], mad24(g, coeffs[4], b * coeffs[5])), xyz_shift); + [0x86c574] int z = CV_DESCALE(mad24(r, coeffs[6], mad24(g, coeffs[7], b * coeffs[8])), xyz_shift); + [0x86ca08] int b = CV_DESCALE(mad24(x, coeffs[0], mad24(y, coeffs[1], z * coeffs[2])), xyz_shift); + [0x86ca60] int g = CV_DESCALE(mad24(x, coeffs[3], mad24(y, coeffs[4], z * coeffs[5])), xyz_shift); + [0x86cab8] int r = CV_DESCALE(mad24(x, coeffs[6], mad24(y, coeffs[7], z * coeffs[8])), xyz_shift); + [0x86ccf1] #define GammaTabScale (float)GAMMA_TAB_SIZE + [0x86cedd] __constant int * coeffs, int Lscale, int Lshift) + [0x86d19a] int fX = LabCbrtTab_b[CV_DESCALE(mad24(R, C0, mad24(G, C1, B*C2)), lab_shift)]; + [0x86d1ea] int fY = LabCbrtTab_b[CV_DESCALE(mad24(R, C3, mad24(G, C4, B*C5)), lab_shift)]; + [0x86d23a] int fZ = LabCbrtTab_b[CV_DESCALE(mad24(R, C6, mad24(G, C7, B*C8)), lab_shift)]; + [0x86d28a] int L = CV_DESCALE( Lscale*fY + Lshift, lab_shift2 ); + [0x86d2c0] int a = CV_DESCALE( mad24(500, fX - fY, 128*(1 << lab_shift2)), lab_shift2 ); + [0x86d30e] int b = CV_DESCALE( mad24(200, fY - fZ, 128*(1 << lab_shift2)), lab_shift2 ); + [0x86d7eb] R = splineInterpolate(R * GammaTabScale, gammaTab, GAMMA_TAB_SIZE); + [0x86d82f] G = splineInterpolate(G * GammaTabScale, gammaTab, GAMMA_TAB_SIZE); + [0x86d873] B = splineInterpolate(B * GammaTabScale, gammaTab, GAMMA_TAB_SIZE); + [0x86de86] ro = splineInterpolate(ro * GammaTabScale, gammaTab, GAMMA_TAB_SIZE); + [0x86decc] go = splineInterpolate(go * GammaTabScale, gammaTab, GAMMA_TAB_SIZE); + [0x86df12] bo = splineInterpolate(bo * GammaTabScale, gammaTab, GAMMA_TAB_SIZE); + [0x86e94c] __constant float LabCbrtTabScale = LAB_CBRT_TAB_SIZE/1.5f; + [0x86ecea] R = splineInterpolate(R*GammaTabScale, gammaTab, GAMMA_TAB_SIZE); + [0x86ed2c] G = splineInterpolate(G*GammaTabScale, gammaTab, GAMMA_TAB_SIZE); + [0x86ed6e] B = splineInterpolate(B*GammaTabScale, gammaTab, GAMMA_TAB_SIZE); + [0x86ee6e] float L = splineInterpolate(Y*LabCbrtTabScale, LabCbrtTab, LAB_CBRT_TAB_SIZE); + [0x86f203] float scale = 1.0f / 255.0f; + [0x86f220] float R = src[0]*scale, G = src[1]*scale, B = src[2]*scale; + [0x870a9f] dst[0] = (DATA_TYPE)CV_DESCALE(mad24(src_pix.B_COMP, BY15, mad24(src_pix.G_COMP, GY15, mul24(src_pix.R_COMP, RY15))), gray_shift); + [0x871c7c] dst[dst_index] = (uchar)CV_DESCALE(mad24((t << 3) & 0xf8, BY15, mad24((t >> 3) & 0xfc, GY15, ((t >> 8) & 0xf8) * RY15)), gray_shift); + [0x871d08] dst[dst_index] = (uchar)CV_DESCALE(mad24((t << 3) & 0xf8, BY15, mad24((t >> 2) & 0xf8, GY15, ((t >> 7) & 0xf8) * RY15)), gray_shift); + [0x873301] const int Y = CV_DESCALE(mad24(b, coeffs[0], mad24(g, coeffs[1], mul24(r, coeffs[2]))), yuv_shift); + [0x873365] const int U = CV_DESCALE(mad24(b - Y, coeffs[3], delta), yuv_shift); + [0x8733aa] const int V = CV_DESCALE(mad24(r - Y, coeffs[4], delta), yuv_shift); + [0x8738d6] const int r = Y + CV_DESCALE(mul24(V - HALF_MAX_NUM, coeffs[3]), yuv_shift); + [0x873923] const int g = Y + CV_DESCALE(mad24(V - HALF_MAX_NUM, coeffs[2], mul24(U - HALF_MAX_NUM, coeffs[1])), yuv_shift); + [0x873994] const int b = Y + CV_DESCALE(mul24(U - HALF_MAX_NUM, coeffs[0]), yuv_shift); + [0x876bd3] int Y = CV_DESCALE(mad24(b, coeffs[2], mad24(g, coeffs[1], mul24(r, coeffs[0]))), yuv_shift); + [0x876c32] int Cr = CV_DESCALE(mad24(r - Y, coeffs[3], delta), yuv_shift); + [0x876c72] int Cb = CV_DESCALE(mad24(b - Y, coeffs[4], delta), yuv_shift); + [0x8771b2] int r = yp + CV_DESCALE(coeff[0] * (cr - HALF_MAX_NUM), yuv_shift); + [0x8771f6] int g = yp + CV_DESCALE(mad24(coeff[1], cr - HALF_MAX_NUM, coeff[2] * (cb - HALF_MAX_NUM)), yuv_shift); + [0x87725e] int b = yp + CV_DESCALE(coeff[3] * (cb - HALF_MAX_NUM), yuv_shift); + [0x8774ac] #elif defined(BORDER_REFLECT) || defined(BORDER_REFLECT101) + [0x8788bb] #elif defined BORDER_REFLECT + [0x878938] #elif defined BORDER_REFLECT_101 || defined BORDER_REFLECT101 + [0x878bbc] #define INIT_AND_READ_LOCAL_SOURCE(width, height, fill_const, kernel_border) \ + [0x878c0b] int srcX = x + srcOffsetX - (kernel_border); \ + [0x878c3a] int srcY = y + srcOffsetY - (kernel_border); \ + [0x878d0c] if(lix < ((kernel_border)*2)) \ + [0x878db0] if(liy< ((kernel_border)*2)) \ + [0x878e55] if(lix<((kernel_border)*2) && liy<((kernel_border)*2)) \ + [0x879031] int height, int width, float scale) + [0x879270] DSTX(x,y) = mad(10.0f, m3 - m1, 3.0f * (u3 - u1 + b3 - b1)) * scale; + [0x8792b5] DSTY(x,y) = mad(10.0f, b2 - u2, 3.0f * (b1 - u1 + b3 - u3)) * scale; + [0x879300] DSTX(x,y) = mad(2.0f, m3 - m1, u3 - u1 + b3 - b1) * scale; + [0x87933b] DSTY(x,y) = mad(2.0f, b2 - u2, b1 - u1 + b3 - u3) * scale; + [0x879890] DSTX(x,y) = scale * + [0x87993f] DSTY(x,y) = scale * + [0x87afe6] int id = local_id + col - ANCHOR_X; \ + [0x87b1b7] int x = local_id + (LOCAL_SIZE - (KERNEL_SIZE_X - 1)) * get_group_id(0) - ANCHOR_X; + [0x87b2fc] int srcY = srcOffsetY + y - ANCHOR_Y; + [0x87b647] for (int sx = 0; sx < ANCHOR_X; sx++) + [0x87b69e] __constant WT1 * k = &kernelData[KERNEL_SIZE_Y2_ALIGNED * ANCHOR_X]; + [0x87b72d] for (int sx = ANCHOR_X + 1; sx < KERNEL_SIZE_X; sx++) + [0x87b794] if (local_id >= ANCHOR_X && local_id < LOCAL_SIZE - (KERNEL_SIZE_X - 1 - ANCHOR_X) && x >= 0 && x < cols) + [0x87b860] #ifdef BORDER_REPLICATE + [0x87bb00] #ifdef BORDER_REFLECT_101 + [0x87bc6f] #ifdef BORDER_WRAP + [0x87c251] #elif defined(BORDER_REFLECT_101) || defined(BORDER_REFLECT101) + [0x87c770] inline bool isBorder(const struct RectCoords bounds, int2 coord, int numPixels) + [0x87c8f5] inline WT getBorderPixel(const struct RectCoords bounds, int2 coord, + [0x87cb42] if (!isBorder(srcCoords, pos, 1)) + [0x87cbdf] return getBorderPixel(srcCoords, pos, srcptr, srcstep); + [0x87d593] int2 srcPos = (int2)(srcCoords.x1 + x - ANCHOR_X, srcCoords.y1 + y - ANCHOR_Y); + [0x87d5e3] if (!isBorder(srcCoords, srcPos, PX_LOAD_NUM_PX)) + [0x885d52] #if defined BORDER_CONSTANT || defined BORDER_REPLICATE + [0x885fdf] #elif BORDER_REFLECT + [0x886248] #elif BORDER_REFLECT_101 + [0x887375] __constant float * threshold, int max_corners) + [0x8874ed] if (val > threshold[0]) + [0x88826e] __local float scale; + [0x888466] scale = 1; + [0x8884a9] scale = 255.f / (total - sumhist[i]); + [0x888575] dst[i]= convert_uchar_sat_rte(convert_float(sumhist[i]) * scale); + [0x8893cc] int linesMax, int threshold, float rho, float theta) + [0x8895a1] if (curVote > threshold && curVote > ACCUM(accum - sizeof(int)) && curVote >= ACCUM(accum + sizeof(int)) && + [0x889891] int linesMax, int threshold, int lineLength, int lineGap, float rho, float theta) + [0x889a30] if (curVote >= threshold && + [0x88a578] #define LOCAL_SUM_STRIDE (LOCAL_SUM_SIZE + 1) + [0x88a6ab] __local sumT lm_sum[LOCAL_SUM_STRIDE * LOCAL_SUM_SIZE]; + [0x88a6f5] __local sumSQT lm_sum_sq[LOCAL_SUM_STRIDE * LOCAL_SUM_SIZE]; + [0x88a83d] for (int yin = 0; yin < LOCAL_SUM_SIZE; yin++, src_index+=src_step, lsum_index += LOCAL_SUM_STRIDE) + [0x88aabe] lsum_index = LOCAL_SUM_STRIDE * lid; + [0x88b1df] for (int yin = 0; yin < LOCAL_SUM_SIZE; yin++, lsum_index += LOCAL_SUM_STRIDE) + [0x88cab6] coeffT scale, coeffT delta) + [0x88ccfe] dst[0] = convertToDT( mad24((WT)(scale), convertToWT(src1[0]) + convertToWT(src2[0]), (WT)(delta)) ); + [0x88cd6a] dst[0] = convertToDT( mad((WT)(scale), convertToWT(src1[0]) + convertToWT(src2[0]), (WT)(delta)) ); + [0x88d3f5] WT1 scale, WT1 delta) + [0x88d693] WT scale_v = (WT)scale; + [0x88d941] WT sum = mad(scale_v, (sum1 + sum2), delta_v); + [0x88e13e] __kernel void linearPolar(__global float* mx, __global float* my, float ascale, float pscale, float cx, float cy, int angle_border, unsigned width, unsigned height) + [0x88e2fa] mx[g_id] = mag*pscale; + [0x88e311] my[g_id] = (angle*ascale) + angle_border; + [0x88e848] __kernel void logPolar(__global float* mx, __global float* my, float ascale, float m, float cx, float cy, int angle_border, unsigned width, unsigned height) + [0x8994fb] #if defined BORDER_REPLICATE + [0x89e834] #ifndef BORDER_CONSTANT + [0x8a086e] #if defined BORDER_CONSTANT + [0x8a2067] #define RESULT_SCALE 255.0f + [0x8a2097] #define RESULT_SCALE 127.0f + [0x8a20c7] #define RESULT_SCALE 65535.0f + [0x8a20f9] #define RESULT_SCALE 32767.0f + [0x8a2120] #define RESULT_SCALE 1.0f + [0x8a231a] T uval = convertToDT(round(intermediate * RESULT_SCALE)); + [0x8a235a] T uval = convertToDT(intermediate * RESULT_SCALE); + [0x8a2bd9] #define INTER_RESIZE_COEF_SCALE (1 << INTER_RESIZE_COEF_BITS) + [0x8a2c47] u = u * INTER_RESIZE_COEF_SCALE; + [0x8a2c68] v = v * INTER_RESIZE_COEF_SCALE; + [0x8a2cab] int U1 = rint(INTER_RESIZE_COEF_SCALE - u); + [0x8a2cd7] int V1 = rint(INTER_RESIZE_COEF_SCALE - v); + [0x8a3583] int sx = XSCALE * dx; + [0x8a3599] int sy = YSCALE * dy; + [0x8a35d2] for (int py = 0; py < YSCALE; ++py) + [0x8a365b] for (int px = 0; px < XSCALE; ++px) + [0x8a36e2] storepix(convertToT(convertToWT2V(sum) * (WT2V)(SCALE)), dst + mad24(dx, TSIZE, dst_index)); + [0x8a515b] __kernel void threshold(__global const uchar * srcptr, int src_step, int src_offset, + [0x8a523b] int gy = get_global_id(1) * STRIDE_SIZE; + [0x8a531c] for (int i = 0; i < STRIDE_SIZE; i++) + [0x8a56a9] #define INTER_SCALE 1.f/INTER_TAB_SIZE + [0x8a56f9] #define AB_SCALE (1 << AB_BITS) + [0x8a573a] #define INTER_REMAP_COEF_SCALE (1 << INTER_REMAP_COEF_BITS) + [0x8a5b17] int round_delta = (AB_SCALE >> 1); + [0x8a5b3a] int X0_ = rint(M[0] * dx * AB_SCALE); + [0x8a5b60] int Y0_ = rint(M[3] * dx * AB_SCALE); + [0x8a5c2e] int X0 = X0_ + rint(fma(M[1], (CT)dy, M[2]) * AB_SCALE) + round_delta; + [0x8a5c75] int Y0 = Y0_ + rint(fma(M[4], (CT)dy, M[5]) * AB_SCALE) + round_delta; + [0x8a62dc] int X0 = X0_ + rint(fma(M[1], (CT)dy, M[2]) * AB_SCALE) + ROUND_DELTA; + [0x8a6323] int Y0 = Y0_ + rint(fma(M[4], (CT)dy, M[5]) * AB_SCALE) + ROUND_DELTA; + [0x8a6795] int itab0 = convert_short_sat_rte( (1.0f-taby)*(1.0f-tabx) * INTER_REMAP_COEF_SCALE ); + [0x8a67ec] int itab1 = convert_short_sat_rte( (1.0f-taby)*tabx * INTER_REMAP_COEF_SCALE ); + [0x8a683c] int itab2 = convert_short_sat_rte( taby*(1.0f-tabx) * INTER_REMAP_COEF_SCALE ); + [0x8a688c] int itab3 = convert_short_sat_rte( taby*tabx * INTER_REMAP_COEF_SCALE ); + [0x8a7755] int X0 = rint(M[0] * tmp) + rint(fma(M[1], (CT)dy, M[2]) * AB_SCALE) + ROUND_DELTA; + [0x8a77a9] int Y0 = rint(M[3] * tmp) + rint(fma(M[4], (CT)dy, M[5]) * AB_SCALE) + ROUND_DELTA; + [0x8a7a7f] float ayy = INTER_SCALE * ay; + [0x8a7a9d] float axx = INTER_SCALE * ax; + [0x8a7b97] itab[i] = rint(tab1y[(i>>2)] * tab1x[(i&3)] * INTER_REMAP_COEF_SCALE); + [0x8a82b9] #define INTER_SCALE 1.f / INTER_TAB_SIZE + [0x8adc80] -D cn=%d -D ANCHOR_X=%d -D ANCHOR_Y=%d -D KERNEL_SIZE_X=%d -D KERNEL_SIZE_Y=%d -D PX_LOAD_VEC_SIZE=%d -D PX_LOAD_NUM_PX=%d -D PX_PER_WI_X=%d -D PX_PER_WI_Y=%d -D PRIV_DATA_WIDTH=%d -D %s -D %s -D PX_LOAD_X_ITERATIONS=%d -D PX_LOAD_Y_ITERATIONS=%d -D srcT=%s -D srcT1=%s -D dstT=%s -D dstT1=%s -D WT=%s -D WT1=%s -D convertToWT=%s -D convertToDstT=%s%s%s -D PX_LOAD_FLOAT_VEC_CONV=convert_%s -D OP_BOX_FILTER + [0x8ade18] -D BORDER_ISOLATED + [0x8ade30] -D LOCAL_SIZE_X=%d -D BLOCK_SIZE_Y=%d -D ST=%s -D DT=%s -D WT=%s -D convertToDT=%s -D convertToWT=%s -D ANCHOR_X=%d -D ANCHOR_Y=%d -D KERNEL_SIZE_X=%d -D KERNEL_SIZE_Y=%d -D %s%s%s%s%s -D ST1=%s -D DT1=%s -D cn=%d + [0x8c0960] LXQFQHSHSFQF RFRH QGSG QMQ[ RNRZ NMSMS[ N[V[ OMQN PMQO QZO[ QYP[ SYT[ SZU[ + [0x8c0e40] I[LMR[ MMRY NMSY XNSYR[ JMQM TMZM KMNO PMNN VMXN YMXN + [0x8c0f30] H[LMR[ MMRY NMSY XNSYP_NaLbJbIaI_K_KaJaJ` JMQM TMZM KMNO PMNN VMXN YMXN + [0x8c1d90] F^GQHOJMLMMNNPNSL[ MNMSK[ MPLTJ[L[ NSPPRNTMVMXNYPYSWX XNXRWVWZ XPVUVXWZX[Z[\Y]W + [0x8c22f0] H\QFNGLJKOKRLWNZQ[S[VZXWYRYOXJVGSFQF NHMJLNLSMWNY VYWWXSXNWJVH QFOGNIMNMSNXOZQ[ S[UZVXWSWNVIUGSF LPXQ LQXP + [0x8c2430] H\QFNGLJKOKRLWNZQ[S[VZXWYRYOXJVGSFQF NHMJLNLSMWNY VYWWXSXNWJVH QFOGNIMNMSNXOZQ[ S[UZVXWSWNVIUGSF + [0x8e0448] cv::borderInterpolate + [0x8e0460] Unknown/unsupported border type + [0x8e04c0] copyMakeBorder + [0x8e04f0] void __cdecl cv::copyMakeBorder(const class cv::_InputArray &,const class cv::_OutputArray &,int,int,int,int,int,const class cv::Scalar_ &) + [0x8e0588] cv::copyMakeBorder + [0x8e5a68] OP_MUL_SCALE + [0x8e5a78] OP_DIV_SCALE + [0x8e5a88] OP_RECIP_SCALE + [0x8e5ad0] OP_RDIV_SCALE + [0x8e61e0] -D %s%s -D %s -D srcT1=%s -D srcT1_C1=%s -D srcT2=%s -D srcT2_C1=%s -D dstT=%s -D DEPTH_dst=%d -D dstT_C1=%s -D workT=%s -D workST=%s -D scaleT=%s -D wdepth=%d -D convertToWT1=%s -D convertToWT2=%s -D convertToDT=%s%s -D cn=%d -D rowsPerWI=%d -D convertFromU=%s + [0x8efb10] -D NO_SCALE + [0x8f22f0] cv::cpu_baseline::getScaleAddFunc + [0x8f2bd0] -D OP_SCALE_ADD -D BINARY_OP -D dstT=%s -D DEPTH_dst=%d -D workT=%s -D convertToWT1=%s -D srcT1=dstT -D srcT2=dstT -D convertToDT=%s -D workT1=%s -D wdepth=%d%s -D rowsPerWI=%d + [0x8f2cb0] void (__cdecl *__cdecl cv::getScaleAddFunc(int))(const unsigned char *,const unsigned char *,unsigned char *,int,const void *) + [0x8f2d50] void __cdecl cv::scaleAdd(const class cv::_InputArray &,double,const class cv::_InputArray &,const class cv::_OutputArray &) + [0x8f2dd0] cv::scaleAdd + [0x8f663f] #elif defined OP_MUL_SCALE + [0x8f667e] #define EXTRA_PARAMS , workST srcelem2_, scaleT scale + [0x8f66e5] #define EXTRA_PARAMS , scaleT scale + [0x8f6710] #define PROCESS_ELEM storedst(convertToDT(srcelem1 * scale * srcelem2)) + [0x8f6865] #elif defined OP_DIV_SCALE + [0x8f6995] storedst(convertToDT(e2 == zero ? zero : (srcelem1 * (workT)(scale) / e2))) + [0x8f6a15] storedst(convertToDT(srcelem1 * (workT)(scale) / e2)) + [0x8f6a52] #elif defined OP_RDIV_SCALE + [0x8f6b83] storedst(convertToDT(e1 == zero ? zero : (srcelem2 * (workT)(scale) / e1))) + [0x8f6c03] storedst(convertToDT(srcelem2 * (workT)(scale) / e1)) + [0x8f6c40] #elif defined OP_RECIP_SCALE + [0x8f6cf4] storedst(convertToDT(e1 != zero ? scale / e1 : zero)) + [0x8f6d5e] storedst(convertToDT(scale / e1)) + [0x8f6db1] #define EXTRA_PARAMS , scaleT alpha, scaleT beta, scaleT gamma + [0x8f7324] #elif defined OP_CONVERT_SCALE_ABS + [0x8f749a] #elif defined OP_SCALE_ADD + [0x8f7fd6] #if !(defined(OP_RECIP_SCALE) || defined(OP_NOT)) + [0x8f8c25] #ifndef NO_SCALE + [0x8f8e4a] #ifdef NO_SCALE + [0x8f8ef8] copymakeborder + [0x8f9432] __kernel void copyMakeBorder(__global const uchar * srcptr, int src_step, int src_offset, int src_rows, int src_cols, + [0x8fa49a] static const __constant float CV_8U_SCALE = 1.0f / 255.0f; + [0x8fae5a] float4 src_pix1 = convert_float4(vload4(0, pSrcRow1 + 0*NCHANNELS)) * CV_8U_SCALE; + [0x8faead] float4 src_pix2 = convert_float4(vload4(0, pSrcRow1 + 1*NCHANNELS)) * CV_8U_SCALE; + [0x8faf00] float4 src_pix3 = convert_float4(vload4(0, pSrcRow2 + 0*NCHANNELS)) * CV_8U_SCALE; + [0x8faf53] float4 src_pix4 = convert_float4(vload4(0, pSrcRow2 + 1*NCHANNELS)) * CV_8U_SCALE; + [0x8fe39a] #ifdef DFT_SCALE + [0x8fe3ab] #define SCALE_VAL(x, scale) x*scale + [0x8fe3d5] #define SCALE_VAL(x, scale) x + [0x8fe630] FT scale = (FT) 1/dst_cols; + [0x8fe652] FT scale = (FT) 1/(dst_cols*dst_rows); + [0x8fe962] dst[i] = SCALE_VAL(smem[i], scale); + [0x8fe9ef] dst[dst_cols-i] = (CT)(SCALE_VAL(smem[i].x, scale), SCALE_VAL(-smem[i].y, scale)); + [0x8feb02] dst[i+1] = SCALE_VAL(smem_1cn[i+2], scale); + [0x8feb3a] dst[0] = SCALE_VAL(smem_1cn[0], scale); + [0x8fef05] FT scale = 1.f/(dst_rows*dst_cols); + [0x8ff06c] *((__global CT*)(dst + i*block_size*dst_step)) = SCALE_VAL(smem[y + i*block_size], scale); + [0x8ff18d] *((__global FT*) dst) = SCALE_VAL(smem_1cn[i+2], scale); + [0x8ff1d2] *((__global FT*) (dst_ptr + dst_offset)) = SCALE_VAL(smem_1cn[0], scale); + [0x8ff359] *((__global FT*) (dst_ptr + mad24(dst_cols-1, (int)sizeof(FT), dst_offset))) = SCALE_VAL(smem_1cn[0], scale); + [0x8ff491] vstore2(SCALE_VAL(smem[i], scale), 0, (__global FT*) dst); + [0x8ff67e] const FT scale = (FT) 1/dst_cols; + [0x8ff6a6] const FT scale = (FT) 1/(dst_cols*dst_rows); + [0x8ffd5e] dst[i*block_size].x = SCALE_VAL(smem[x + i*block_size].x, scale); + [0x8ffda0] dst[i*block_size].y = SCALE_VAL(-smem[x + i*block_size].y, scale); + [0x8ffe82] dst[i*block_size] = SCALE_VAL(smem[x + i*block_size].x, scale); + [0x903399] int stride) + [0x903b33] int end_index = min(start_index + stride, K); + [0x904830] int border = -(group_y * LWG_HEIGHT * TILE_M + local_y * TILE_M); + [0x904872] int row0 = mad24(global_y, TILE_M, 0) < M ? 0 : border; + [0x9048aa] int row1 = mad24(global_y, TILE_M, 1) < M ? 1 : border; + [0x9048e2] int row2 = mad24(global_y, TILE_M, 2) < M ? 2 : border; + [0x90491a] int row3 = mad24(global_y, TILE_M, 3) < M ? 3 : border; + [0x904952] int row4 = mad24(global_y, TILE_M, 4) < M ? 4 : border; + [0x90498a] int row5 = mad24(global_y, TILE_M, 5) < M ? 5 : border; + [0x9049c2] int row6 = mad24(global_y, TILE_M, 6) < M ? 6 : border; + [0x9049fa] int row7 = mad24(global_y, TILE_M, 7) < M ? 7 : border; + [0x910cf2] __kernel void mulAndScaleSpectrums(__global const uchar * src1ptr, int src1_step, int src1_offset, + [0x911488] #ifdef HAVE_SCALE + [0x91149a] , float scale + [0x9116f2] value = fma(value, (workT)(scale), (workT)(delta)); + [0x91172c] value *= (workT)(scale); + [0x915d70] , float fscale + [0x9162cc] dst[c] = convertToDT(convertToWT(tmp[c]) * fscale); + [0x91667d] dst[c] = convertToDT0(convertToWT(tmp[c]) * fscale); + [0x918580] C:\__t\vcpkg\buildtrees\opencv4\src\4.6.0-9a95a1b699.clean\modules\core\src\convert_scale.dispatch.cpp + [0x918610] void (__cdecl *__cdecl cv::getConvertScaleFunc(int,int))(const unsigned char *,unsigned __int64,const unsigned char *,unsigned __int64,unsigned char *,unsigned __int64,class cv::Size_,void *) + [0x9273f0] cv::opt_SSE4_1::getScaleAddFunc + [0x927870] cv::opt_AVX2::getScaleAddFunc + [0x927d18] cv::opt_AVX512_SKX::getScaleAddFunc + [0x96f308] RGB color space not permitted on grayscale PNG + [0x970470] ignored in grayscale PNG + [0x970a88] Invalid bit depth for grayscale image + [0x970af8] Invalid bit depth for grayscale+alpha image + [0x970c10] Ignoring request to write a PLTE chunk in grayscale PNG + [0x977de8] DefaultScale + [0x977df8] BestQualityScale + [0x977fa8] ShadowScale + [0x979720] Reading this image would require libjpeg to allocate at least %llu bytes. This is disabled since above the %ld threshold. You may override this restriction by defining the LIBTIFF_ALLOW_LARGE_LIBJPEG_MEM_ALLOC environment variable, or setting the JPEGMEM environment variable to a value greater or equal to '%lluM' + [0x97ade8] %sEOL padding + [0x97c720] stride %d is not a multiple of sample count, %lld, data truncated. + [0x995be0] (cc%stride)!=0 + [0x995bf8] cc%(2*stride))!=0 + [0x995c20] cc%(4*stride))!=0 + [0x995c48] cc%(8*stride))!=0 + [0x995c70] cc%(bps*stride))!=0 + [0x995cd0] (cc%(2*stride))!=0 + [0x995ce8] (cc%(4*stride))!=0 + [0x995d10] (cc%(8*stride))!=0 + [0x995d38] (cc%(bps*stride))!=0 + [0x9e67b8] U_MISPLACED_ANCHOR_START + [0x15eaf82] KSpnMS + [0x1c2b0b0] America:Anchorage + [0x20416f3] nmszs( + [0x207a473] JjPICKANCHOR + [0x207a48f] AESCULAPIUSSCALESALEMBIC + [0x207e6b5] HSTRIDE + [0x20885f4] ANCHOR + [0x271176e] ConfidenceClass + [0x2711dff] word_nms_ms + [0x2711e8a] polygon_nms_ms + [0x2712255] accumulated_confidence_ms + [0x2713099] confidence_score + [0x27130b3] confidence + [0x27130c3] 2%.OneOCR.Interop.Enums.ConfidenceClass + [0x2713261] font_name_confidence + [0x2713290] is_bold_confidence + [0x27132bf] is_italic_confidence + [0x27135b8] lattice_decoder_confidence + [0x271614e] custom_fst_scale + [0x27161d0] base_fst_scale + [0x271623a] acoustic_scale + [0x271652b] line_merge_threshold + [0x2716549] segment_conf_threshold + [0x2716569] textline_conf_threshold + [0x2716586] 20.OneOCR.DetectorProto.TextlineConfThresholdEntry + [0x27165bc] textline_nms_threshold + [0x27165dc] textline_onverlap_threshold + [0x2716622] relation_conf_threshold + [0x2716660] ambiguous_nms_threshold + [0x2716681] ambiguous_overlap_threshold + [0x27166a6] ambiguous_save_threshold + [0x27166db] checkbox_featuremap_stride + [0x2716722] checkbox_nms_thres + [0x27167bf] text_confidence_threshold + [0x27167e2] textline_overlap_threshold + [0x2716806] textline_height_close_threshold + [0x271682f] textline_hardnms_iou_threshold + [0x2716856] &textline_groupnms_span_ratio_threshold + [0x2716887] checkbox_inference_threshold + [0x27168ad] barcode_inference_threshold + [0x27168d2] notline_overlap_threshold + [0x27168f5] checkbox_merge_threshold + [0x2716917] TextlineConfThresholdEntry + [0x2716a51] script_threshold + [0x2716b03] !hwpc_consecutive_frames_threshold + [0x2716b2e] #script_consecutive_frames_threshold + [0x2716b58] 2<.OneOCR.AuxMltClsProto.ScriptConsecutiveFramesThresholdEntry + [0x2716b9a] non_text_script_threshold + [0x2716c41] %ScriptConsecutiveFramesThresholdEntry + [0x271707a] prior_scale + [0x27170e8] blank_threshold + [0x2717101] char_threshold + [0x2717250] ConfidenceProto + [0x2717298] word_class_threshold + [0x2717377] boxes_threshold + [0x27173fd] tables_threshold + [0x271742c] figure_threshold + [0x27174f9] cell_merge_threshold + [0x2717e47] rejection_threshold + [0x271804d] .OneOCR.ConfidenceProto + [0x2718931] enable_wordnms + [0x271da58] fConfidenceScoreY: + [0x271da70] fConfidenceScoreX: + [0x271dac8] MAX_LINE_COUNT_BATCH_SIZE_RATIO + [0x271f2b8] Confidence model enabled but not provided. + [0x271f3d8] m_confidenceModel.size() == opt.conf_model().size() + [0x271f528] Confidence model count mismatched. + [0x271ff50] ARGMAX_LINE decoder is deprecated. This will break Arabic logical reordering. + [0x2720d00] C:\__w\1\s\CoreEngine\Native\TextRecognizer\ConfidenceProcessor.cpp + [0x2721508] fScale > 0.f + [0x2722048] link_scores_ + [0x2722140] AS_LARGE_TEXT_THRESHOLD + [0x2722d10] link_scores_concat_compress + [0x2722ef8] scaleY > 0.0f + [0x2722f48] Scale should > 0.0 + [0x2722f60] scaleX > 0.0f + [0x2723a38] min_box_height_before_scaleback + [0x2723a58] input_scale_ratio + [0x2723a70] corner_score_threshold + [0x2723aa8] K_of_detections_after_nms + [0x2723ae8] min_box_width_before_scaleback + [0x2723c08] nms_iou_threshold + [0x2724078] group_seg_nms_thresh + [0x2724158] feat_stride + [0x2724408] dim < strides.size() + [0x2724468] strides[dim] > 0 + [0x27250b8] words.size(): %lu != confidences.size(): %lu + [0x2726de0] OneOCR.AuxMltClsProto.ScriptConsecutiveFramesThresholdEntry.key + [0x2726e20] OneOCR.DetectorProto.TextlineConfThresholdEntry.key + [0x2727350] OneOCR.ConfidenceProto.name + [0x272aa18] LangID confidence calibration mapping file not found + [0x272b0f8] Confidence model dir + [0x27ee782] GetOcrWordConfidence + [0x2804350] .?AV?$_Binder@U_Unforced@std@@V?$_Mem_fn@P8TextLineRecognizerImpl@OneOCR@@EAAPEAVConfidenceProcessor@2@AEBVConfidenceProto@2@AEBVModelParser@2@@Z@2@PEAVTextLineRecognizerImpl@OneOCR@@AEBVConfidenceProto@5@AEAVModelParser@5@@std@@ + [0x2809ba8] .?AVConfidenceProto@OneOCR@@ + [0x2809dd0] .?AVAuxMltClsProto_ScriptConsecutiveFramesThresholdEntry_DoNotUse@OneOCR@@ + [0x280a240] .?AVDetectorProto_TextlineConfThresholdEntry_DoNotUse@OneOCR@@ + [0x2810980] .?AVThresholdRunner@cv@@ + [0x282c220] .?AV?$_Func_base@PEAVConfidenceProcessor@OneOCR@@$$V@std@@ + [0x282c9c0] .?AV?$_Func_impl_no_alloc@V?$_Binder@U_Unforced@std@@V?$_Mem_fn@P8TextLineRecognizerImpl@OneOCR@@EAAPEAVConfidenceProcessor@2@AEBVConfidenceProto@2@AEBVModelParser@2@@Z@2@PEAVTextLineRecognizerImpl@OneOCR@@AEBVConfidenceProto@5@AEAVModelParser@5@@std@@PEAVConfidenceProcessor@OneOCR@@$$V@std@@ + [0x2833e00] .?AV?$MapEntry@VDetectorProto_TextlineConfThresholdEntry_DoNotUse@OneOCR@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@M$08$01@internal@protobuf@google@@ + [0x2833ec0] .?AV?$MapEntry@VAuxMltClsProto_ScriptConsecutiveFramesThresholdEntry_DoNotUse@OneOCR@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@_J$08$02@internal@protobuf@google@@ + [0x2833f90] .?AV?$MapEntryImpl@VAuxMltClsProto_ScriptConsecutiveFramesThresholdEntry_DoNotUse@OneOCR@@VMessage@protobuf@google@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@_J$08$02@internal@protobuf@google@@ + [0x2834220] .?AV?$MapEntryImpl@VDetectorProto_TextlineConfThresholdEntry_DoNotUse@OneOCR@@VMessage@protobuf@google@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@M$08$01@internal@protobuf@google@@ + [0x28347e0] .?AV?$MapField@VDetectorProto_TextlineConfThresholdEntry_DoNotUse@OneOCR@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@M$08$01@internal@protobuf@google@@ + [0x28348a0] .?AV?$MapField@VAuxMltClsProto_ScriptConsecutiveFramesThresholdEntry_DoNotUse@OneOCR@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@_J$08$02@internal@protobuf@google@@ + [0x2835330] .?AV?$_Func_impl_no_alloc@V@?9??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVConfidenceProto@3@@std@@ + [0x2835e20] .?AV?$_Func_base@X$$QEAVConfidenceProto@OneOCR@@@std@@ diff --git a/_archive/temp/re_output/07_pipeline_strings.txt b/_archive/temp/re_output/07_pipeline_strings.txt new file mode 100644 index 0000000000000000000000000000000000000000..d23896e7881764fd2513c4c9d9152ae8df42fd2c --- /dev/null +++ b/_archive/temp/re_output/07_pipeline_strings.txt @@ -0,0 +1,446 @@ +PIPELINE STRINGS +============================================================ + [0x824a10] Unrecognized syntax: + [0x831e20] cv::BmpDecoder::readHeader + [0x831ea8] cv::BmpDecoder::readData + [0x832158] cv::SunRasterDecoder::readHeader + [0x8321a0] cv::SunRasterDecoder::readData + [0x832480] cv::PxMDecoder::readHeader + [0x8324e0] cv::PxMDecoder::readData + [0x832860] cv::PFMDecoder::readHeader + [0x832908] cv::PFMDecoder::readData + [0x832b40] int __cdecl cv::TiffDecoder::normalizeChannelsNumber(int) const + [0x832c60] bool __cdecl cv::TiffDecoder::readHeader(void) + [0x832e78] cv::TiffDecoder::readHeader + [0x833090] bool __cdecl cv::TiffDecoder::readData(class cv::Mat &) + [0x833368] cv::TiffDecoder::readData + [0x834d00] cv::PngDecoder::readDataFromBuf + [0x834d20] decoder + [0x8358a0] bool __cdecl cv::PAMDecoder::readHeader(void) + [0x835980] cv::PAMDecoder::readHeader + [0x8359e8] cv::PAMDecoder::readData + [0x8362b0] cv::normalizeAnchor + [0x83cd50] C:\__t\vcpkg\buildtrees\opencv4\src\4.6.0-9a95a1b699.clean\modules\imgproc\src\resize.cpp + [0x83cdb0] cv::ResizeAreaFastVec_SIMD_8u::operator () + [0x83cde8] cv::ResizeAreaFastVec_SIMD_16u::operator () + [0x83ce18] cv::ResizeAreaFastVec_SIMD_16s::operator () + [0x83ce48] cv::computeResizeAreaTab + [0x83cec8] resizeSampler + [0x83ced8] resizeLN + [0x83cef0] -D INTER_LINEAR -D depth=%d -D T=%s -D T1=%s -D WT=%s -D convertToWT=%s -D convertToDT=%s -D cn=%d -D INTER_RESIZE_COEF_BITS=%d + [0x83cfa0] resizeNN + [0x83d070] resizeAREA_FAST + [0x83d098] resizeAREA + [0x83d0d0] void __cdecl cv::hal::resize(int,const unsigned char *,unsigned __int64,int,int,unsigned char *,unsigned __int64,int,int,double,double,int) + [0x83d160] cv::hal::resize + [0x83d250] void __cdecl cv::resize(const class cv::_InputArray &,const class cv::_OutputArray &,class cv::Size_,double,double,int) + [0x83d2d0] cv::resize + [0x83d710] cv::resizeGeneric_Invoker,struct cv::VResizeLanczos4,struct cv::VResizeNoVec> >::resizeGeneric_Invoker + [0x83d800] cv::resizeGeneric_Invoker,struct cv::VResizeLanczos4,struct cv::VResizeLanczos4Vec_32f> >::resizeGeneric_Invoker + [0x83d8d0] cv::resizeGeneric_Invoker,struct cv::VResizeLanczos4,struct cv::VResizeLanczos4Vec_32f16s> >::resizeGeneric_Invoker + [0x83d9b0] cv::resizeGeneric_Invoker,struct cv::VResizeLanczos4,struct cv::VResizeLanczos4Vec_32f16u> >::resizeGeneric_Invoker + [0x83daa0] cv::resizeGeneric_Invoker,struct cv::VResizeLanczos4,struct cv::VResizeNoVec> >::resizeGeneric_Invoker + [0x83db80] cv::resizeGeneric_Invoker,struct cv::VResizeCubic,struct cv::VResizeNoVec> >::resizeGeneric_Invoker + [0x83dc50] cv::resizeGeneric_Invoker,struct cv::VResizeCubic,struct cv::VResizeCubicVec_32f> >::resizeGeneric_Invoker + [0x83dd20] cv::resizeGeneric_Invoker,struct cv::VResizeCubic,struct cv::VResizeCubicVec_32f16s> >::resizeGeneric_Invoker + [0x83ddf0] cv::resizeGeneric_Invoker,struct cv::VResizeCubic,struct cv::VResizeCubicVec_32f16u> >::resizeGeneric_Invoker + [0x83dee0] cv::resizeGeneric_Invoker,struct cv::VResizeCubic,struct cv::VResizeCubicVec_32s8u> >::resizeGeneric_Invoker + [0x83dfd0] cv::resizeGeneric_Invoker,struct cv::VResizeLinear,struct cv::VResizeNoVec> >::resizeGeneric_Invoker + [0x83e0b0] cv::resizeGeneric_Invoker >,struct cv::VResizeLinear,struct cv::VResizeLinearVec_32f> >::resizeGeneric_Invoker + [0x83e1e0] cv::resizeGeneric_Invoker >,struct cv::VResizeLinear,struct cv::VResizeLinearVec_32f16s> >::resizeGeneric_Invoker + [0x83e460] cv::resizeGeneric_Invoker,struct cv::VResizeLinear,struct cv::VResizeLinearVec_32s8u> >::resizeGeneric_Invoker + [0x83e570] cv::ResizeAreaFastVec::operator () + [0x83e5c0] cv::ResizeAreaFastVec::operator () + [0x83e620] cv::ResizeAreaFastVec::operator () + [0x851780] cv::preprocess2DKernel + [0x8635c7] struct RectCoords + [0x8635f2] inline WT readSrcPixel(int2 pos, __global const uchar * srcptr, int src_step, const struct RectCoords srcCoords) + [0x863a24] #ifdef NORMALIZE + [0x863a4e] const struct RectCoords srcCoords = { srcOffsetX, srcOffsetY, srcEndX, srcEndY }; + [0x87c770] inline bool isBorder(const struct RectCoords bounds, int2 coord, int numPixels) + [0x87c8f5] inline WT getBorderPixel(const struct RectCoords bounds, int2 coord, + [0x87cb10] int srcstep, const struct RectCoords srcCoords) + [0x898eb0] precornerdetect + [0x898ec0] __kernel void preCornerDetect(__global const uchar * Dxptr, int dx_step, int dx_offset, + [0x8a1c44] resize + [0x8a2144] __kernel void resizeSampler(__read_only image2d_t srcImage, + [0x8a21e6] const sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | + [0x8a2421] __kernel void resizeLN(__global const uchar * srcptr, int src_step, int src_offset, int src_rows, int src_cols, + [0x8a2bd9] #define INTER_RESIZE_COEF_SCALE (1 << INTER_RESIZE_COEF_BITS) + [0x8a2c17] #define CAST_BITS (INTER_RESIZE_COEF_BITS << 1) + [0x8a2c47] u = u * INTER_RESIZE_COEF_SCALE; + [0x8a2c68] v = v * INTER_RESIZE_COEF_SCALE; + [0x8a2cab] int U1 = rint(INTER_RESIZE_COEF_SCALE - u); + [0x8a2cd7] int V1 = rint(INTER_RESIZE_COEF_SCALE - v); + [0x8a31ae] __kernel void resizeNN(__global const uchar * srcptr, int src_step, int src_offset, int src_rows, int src_cols, + [0x8a3430] __kernel void resizeAREA_FAST(__global const uchar * src, int src_step, int src_offset, int src_rows, int src_cols, + [0x8a3749] __kernel void resizeAREA(__global const uchar * src, int src_step, int src_offset, int src_rows, int src_cols, + [0x8adc20] -D NORMALIZE + [0x8adc68] -D NORMALIZE + [0x8b0a50] LYOEOFNFNEODQCTCVDWFVHTIQJOKNMNP TCUDVFUHTI NOONPNSOVOWN PNSPVPWNWM MRXR OVOWNWNVOUQTTTVUWWVYTZ TTUUVWUYTZ RZTZV[W]W^V`TaQaO`N_N^O^O_ TZU[V]V^U`Ta + [0x8b0af0] LYOEOFNFNEODQCTCVDWFVHTI TCUDVFUHTI RITIVJWLWMVOTPQPOONNNMOMON TIUJVLVMUOTP MRXR QTOUNWOYQZTZVYWWVUTTQT QTPUOWPYQZ TZUYVWUUTT QZO[N]N^O`QaTaV`W^W]V[TZ QZP[O]O^P`Qa TaU`V^V]U[TZ + [0x8b0db0] LYOEOFNFNEODQCTCVDWFVHTI TCUDVFUHTI RITIVJWLWMVOTPQPOONNNMOMON TIUJVLVMUOTP MRXR SVSa TTTa TTM]X] QaVa + [0x8b3ba0] AcPALBJCGEEGCJBLAPATBXCZE]G_JaLbPcTcXbZa]__]aZbXcTcPbLaJ_G]EZCXBTAPA + [0x8bdfe0] F^KFK[ LFL[ XFX[ YFY[ HFOF UF\F XHLY H[O[ U[\[ N@N?M?M@NBPCTCVBW@ + [0x8db580] cv::Mat::resize + [0x8e7150] void __cdecl cv::extractChannel(const class cv::_InputArray &,const class cv::_OutputArray &,int) + [0x8e71b8] cv::extractChannel + [0x8e8a36] To be built: calib3d core features2d flann freetype highgui imgcodecs imgproc ml objdetect photo stitching video videoio + [0x8eb040] Detected OpenCL cache directory for other version of OpenCL device. + [0x8eb090] Detected OpenCL cache directories for other versions of OpenCL device. + [0x8eb388] sourceSignatureSize_ > 0 + [0x8eb498] fileSourceSignatureSize > 0 + [0x8eb530] fileSourceSignatureSize == sourceSignatureSize_ + [0x8f30b0] Unrecognized or unsupported array type + [0x911130] normalize + [0x9113a3] __kernel void normalizek(__global const uchar * srcptr, int src_step, int src_offset, + [0x931170] Unrecognized component IDs %d %d %d, assuming YCbCr + [0x931288] Corrupt JPEG data: premature end of data segment + [0x9313d0] Invalid crop request + [0x96f400] unrecognized ICC profile class + [0x96f4e0] Not recognizing known sRGB profile that has been edited + [0x970650] unrecognized equation type + [0x970fd8] Unrecognized unit type for oFFs chunk + [0x971000] Unrecognized equation type for pCAL chunk + [0x971070] Unrecognized unit type for pHYs chunk + [0x9724c0] LIBTIFF_STRILE_ARRAY_MAX_RESIZE_COUNT + [0x977e10] DefaultCropOrigin + [0x977e28] DefaultCropSize + [0x978144] Decode + [0x9791b8] JPEGPreDecode + [0x9794f8] JPEGSetupDecode + [0x979694] libtiff should be able to decode it, but it might cause compatibility issues with other readers + [0x9799d0] JPEGDecodeRaw + [0x979a30] mozjpeg library likely detected. Disable emission of Huffman tables in JpegTables tag, and use optimize_coding to avoid potential issues + [0x97a028] DumpModeDecode + [0x97a0b0] PackBitsDecode + [0x97a0f0] Terminating PackBitsDecode due to lack of data. + [0x97a660] Fax3Decode1D + [0x97a670] Fax3Decode2D + [0x97aa80] Fax4Decode + [0x97aaa0] Fax3DecodeRLE + [0x97af50] Buffer overrun detected : %lld bytes available, %d bits needed + [0x97b010] ThunderSetupDecode + [0x97b028] ThunderDecode + [0x97b038] ThunderDecodeRow + [0x97b050] Wrong bitspersample value (%d), Thunder decoder only supports 4bits per sample. + [0x97b0e8] NeXTDecode + [0x97b0f8] NeXTPreDecode + [0x97b148] LZWSetupDecode + [0x97b158] LZWPreDecode + [0x97b168] LZWDecode + [0x97b178] LZWDecodeCompat + [0x97b248] LZWDecode: Strip %u not terminated with EOI code + [0x97b2a0] LZWDecode: Corrupted LZW table at scanline %u + [0x97b300] Wrong length of decoded string: data probably corrupted at scanline %u + [0x97b4e0] OJPEGSetupDecode + [0x97b4f8] OJPEGPreDecodeSkipScanlines + [0x97b518] OJPEGDecode + [0x97b528] OJPEGDecodeRaw + [0x97b538] OJPEGDecodeScanlines + [0x97b9b0] Cannot decode: decoder not correctly initialized + [0x97b9e8] Cannot decode: libjpeg_session_active == 0 + [0x97c270] ZIPSetupDecode + [0x97c280] ZIPDecode + [0x97c4c0] PixarLogSetupDecode + [0x97c4d8] PixarLogPreDecode + [0x97c4f0] PixarLogDecode + [0x97c870] LogL16Decode + [0x97c880] LogLuvDecode24 + [0x97c890] LogLuvDecode32 + [0x97ce08] LogLuvSetupDecode + [0x97d2b0] LZMAPreDecode + [0x97d2c0] LZMADecode + [0x97d468] file format not recognized + [0x97d560] Error initializing the stream decoder, %s + [0x995ca8] PredictorDecodeTile + [0x9dda3d] acterrecognition + [0x9e0b7e] Segment_Starter + [0x9e0f60] Segment_Separator + [0x9e15ca] Optical_Character_Recognition + [0x9e547a] Word_Break + [0x9e6798] U_MISMATCHED_SEGMENT_DELIMITERS + [0x9e6828] U_MISSING_SEGMENT_CLOSE + [0x9e68b0] U_UNDEFINED_SEGMENT_REFERENCE + [0x9e69c0] U_UNCLOSED_SEGMENT + [0x9e69d8] U_ILLEGAL_CHAR_IN_SEGMENT + [0x9e7178] U_BRK_UNRECOGNIZED_OPTION + [0xda0269] c9cKcJcc?c@cAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc[c\c]c^c_c`cacbcccdc + [0x105d36b] bHb2c;cecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczc{c|c}c~c + [0x142fb65] c)c*c-c5c6c9cC?C@CACBCCCDCECFCGCHCICJCKCLCMCNCOCPCQCRCSCTCUCVCWCXCYCZC[C\C]C^C_C`CaCbCcCdCeCfCgChCiCjCkClCmCnCoCpCqCrCsCtCuCvCwCxCyCzC{C|C}C~C + [0x1505bed] c&c'c)c,c-c.c0c1c3c4c5c6c7c8c;cc?c@cAcDcGcHcJcQcRcScTcVcWcXcYcZc[c\c]c`cdcecfchcjckclcocpcrcsctcucxcyc|c}c~c + [0x15c5f92] ACBCCCDCECFCGCHCICJCKCLCMCNCOCPCQCRCSCTCUCVCWCXCYCZC[C\C]C^C_C`CaCbCcCdCeCfCgChCiCjC + [0x1678781] c&c'c)c,c-c.c0c1c3c4c5c6c7c8c;cc?c@cAcDcGcHcJcQcRcScTcVcWcXcYcZc[c\c]c`cdcecfchcjckclcocpcrcsctcucxcyc|c + [0x167ff1d] C C!C"C#C$C%C&C'C(C)C*C+C,C-C.C/C0C1C2C3C4C5C6C8C9C:C;CC?C@CACBCCCDCECFCGCHCICJCKCLCMCNCOCPCQCRCSCTCUCVCWCXCYCZC[C\C]C^C_C`CaCbCcCdCeCfCgChCiCjCkClCmCnCoCpCqCrCsCtCuCvCwCxCyCzC{C|C}C~C + [0x1734702] |coc(7wctc + [0x173948c] PcKQQcRcScTcVQUc{2;@Vc + [0x189b62c] RcScTcXc[cecfclc + [0x18e6bc3] C C!C"C#C$C%C&C'C(C)C*C+C,C-C.C/C0C1C2C3C4C5C6C7C8C9C:C;CC?C@CACBCCCDCECFCGCHCICJCKCLCMCNCOCPCQCRCSCTCUCVCWCXCYCZC[C\C]C^C_C`CaCbCcCdCeCfCgChCiCjCkClCmCnCoCpCqCrCsCtCuCvCwCxCyCzC{C|C}C~C + [0x194a0ac] ECEcAIFc,{U1JN34rHGcPOHcd 0 + [0x271f6e8] /dumpDecoder/ + [0x271fc00] C:\__w\1\s\CoreEngine\Native\TextRecognizer\ArgMaxDecoder.cpp + [0x271fcd8] Invalid Decoder phone table, token is found. + [0x271fd98] Invalid Decoder phone table, token not found. + [0x271fde0] Invalid Decoder phone table, token not found. + [0x271fe68] ArgMaxDecoder is not initialized. + [0x271ff50] ARGMAX_LINE decoder is deprecated. This will break Arabic logical reordering. + [0x2720020] C:\__w\1\s\CoreEngine\Native\TextRecognizer\CharacterMap\Sentence.cpp + [0x27204d0] C:\__w\1\s\CoreEngine\Native\TextRecognizer\CharacterMap\CharacterMapper.cpp + [0x27209d0] C:\__w\1\s\CoreEngine\Native\TextRecognizer\LatMBRAdapter.cpp + [0x2720c08] C:\__w\1\s\CoreEngine\Native\TextRecognizer/SparseMatrix.h + [0x2720cb0] C:\__w\1\s\CoreEngine\Native\TextRecognizer\XnnResult.cpp + [0x2720d00] C:\__w\1\s\CoreEngine\Native\TextRecognizer\ConfidenceProcessor.cpp + [0x2720dc0] C:\__w\1\s\CoreEngine\Native\TextRecognizer\DbLstm.cpp + [0x27210a0] C:\__w\1\s\CoreEngine\Native\TextRecognizer\DbLstmTiered.cpp + [0x2721120] C:\__w\1\s\CoreEngine\Native\TextRecognizer\RejectionProcessor.cpp + [0x2721400] C:\__w\1\s\CoreEngine\Native\TextNormalizer\ConcatTextLines.cpp + [0x2721528] C:\__w\1\s\CoreEngine\Native\TextNormalizer\BaseNormalizer.cpp + [0x2721620] C:\__w\1\s\CoreEngine\Native\TextNormalizer\TextLocationMapper.cpp + [0x27216e0] C:\__w\1\s\CoreEngine\Native\TextNormalizer/TextLocationMapper.h + [0x27217c0] C:\__w\1\s\CoreEngine\Native\TextDetector\TextLinePolygon.cpp + [0x2721898] segments.size() >= 2 + [0x27219e0] C:\__w\1\s\CoreEngine\Native\TextDetector\PolygonIntersectionCache.cpp + [0x2721b38] C:\__w\1\s\CoreEngine\Native\TextDetector\PolyFitting.cpp + [0x2721bc0] Detector model count mismatched. + [0x2721c10] C:\__w\1\s\CoreEngine\Native\TextDetector\TextDetectorImpl.cpp + [0x2721c50] Do not support detector type: + [0x2721c88] Detector mode " + [0x2721e50] C:\__w\1\s\CoreEngine\Native\TextDetector\RelationRCNNRpn2FixedSize.cpp + [0x27220d8] _crop_detected_adaptive.jpg + [0x27220f8] _crop_detected_original.jpg + [0x2722118] _crop_detected_adaptive_keep.jpg + [0x27221e8] C:\__w\1\s\CoreEngine\Native\TextDetector\AdaptiveScaling.cpp + [0x27226a8] C:\__w\1\s\CoreEngine\Native\TextDetector/BaseRCNN.h + [0x27227d8] imgCount == preprocessOutput.imageCount + [0x2722828] C:\__w\1\s\CoreEngine\Native\TextDetector\BaseRCNN.cpp + [0x2722890] rawImages.size() == preprocessOutput.imageCount + [0x27228c0] Input image count doesn't match with detector output count. + [0x27229c8] C:\__w\1\s\CoreEngine\Native\TextDetector\RelationRCNN.cpp + [0x2722ac0] C:\__w\1\s\CoreEngine\Native\TextDetector/DQDETR.h + [0x2722b08] C:\__w\1\s\CoreEngine\Native\TextDetector\DQDETR.cpp + [0x2722c40] C:\__w\1\s\CoreEngine\Native\TextDetector\RelationRCNNRpn2.cpp + [0x2722c80] C:\__w\1\s\CoreEngine\Native\TextDetector/SeglinkGroup.h + [0x2722f08] C:\__w\1\s\CoreEngine\Native\TextDetector\BarcodePolygon.cpp + [0x2722ff0] C:\__w\1\s\CoreEngine\Native\TextDetector\SeglinkProposal.cpp + [0x27231e8] GetResizeDims failed: width = + [0x2723208] GetResizeDims failed: height = + [0x2723aa8] K_of_detections_after_nms + [0x2723ac8] K_of_detections + [0x2723bf8] CornerNetDecode + [0x2724dd8] Memory management error in CLatStrRepo detected. + [0x2725450] C:\__w\1\s\CoreEngine\Native\LatticeDecoder\latmbr\quantized_wfst.cpp + [0x27257b0] C:\__w\1\s\CoreEngine\Native\LatticeDecoder\latmbr\wfst_v2.cpp + [0x27258e0] C:\__w\1\s\CoreEngine\Native\LatticeDecoder\latmbr\quantization.cpp + [0x2725e10] proto.ocr_mode_to_decoder_path().size() > 0ull + [0x2725f48] m_ocrModeToDecoderPath.count(ocrmode) > 0 + [0x2726290] collectComments + [0x27264f8] cvImgResized.rows == nImageHeight + [0x2726538] cvImgResized.cols == nImageWidth + [0x2726e20] OneOCR.DetectorProto.TextlineConfThresholdEntry.key + [0x2726eb8] OneOCR.PipelineProto.RuntimeOption.RuntimeOptionEntry.value + [0x2726ef8] OneOCR.PipelineProto.RuntimeOption.RuntimeOptionEntry.key + [0x2726f58] OneOCR.DecoderProto.name + [0x2727190] OneOCR.DetectorProto.checkbox_calib_map_path + [0x27271e0] OneOCR.DecoderProto.quantization_param_path + [0x2727210] OneOCR.DetectorProto.name + [0x2727230] OneOCR.DecoderProto.word_path + [0x2727250] OneOCR.DecoderProto.lm_path + [0x2727270] OneOCR.DecoderProto.wfst_path + [0x2727290] OneOCR.DecoderProto.phone_path + [0x27272b0] OneOCR.TableDetectorProto.name + [0x27272d0] OneOCR.FormDetectorProto.name + [0x27272f0] OneOCR.CheckboxDetectorProto.name + [0x2727318] OneOCR.CheckboxDetectorProto.checkbox_calib_map_path + [0x2727718] OneOCR.TableRecognizerProto.name + [0x2727760] OneOCR.PipelineProto.text_embedding_model_dir + [0x2727790] OneOCR.PipelineProto.entity_classifier_model_dir + [0x27277c8] OneOCR.PipelineProto.pod_region_grouping_model_dir + [0x2727800] OneOCR.PipelineProto.pod_reading_order_model_dir + [0x2727838] OneOCR.PipelineProto.lang_id_model_dir + [0x2727860] OneOCR.PipelineProto.pod_backbone_model_dir + [0x2727890] OneOCR.PipelineProto.table_reco_model_dir + [0x27278c0] OneOCR.PipelineProto.aux_mlt_cls_model_dir + [0x27278f0] OneOCR.PipelineProto.line_layout_cls_model_dir + [0x2727920] OneOCR.PipelineProto.table_det_model_dir + [0x2727950] OneOCR.PipelineProto.conf_model_dir + [0x2727978] OneOCR.PipelineProto.checkbox_det_model_dir + [0x27279a8] OneOCR.PipelineProto.dec_model_dir + [0x27279d0] OneOCR.PipelineProto.rej_model_dir + [0x27279f8] OneOCR.PipelineProto.det_model_dir + [0x2727a20] OneOCR.PipelineProto.char_model_dir + [0x2727a48] OneOCR.PipelineProto.toc_model_dir + [0x2727a70] OneOCR.PipelineProto.mathfm_paragraph_model_dir + [0x2727aa0] OneOCR.PipelineProto.form_det_model_dir + [0x2727ac8] OneOCR.PipelineProto.mathfm_line_dec_model_dir + [0x2727af8] OneOCR.PipelineProto.font_cls_model_dir + [0x2727b20] OneOCR.PipelineProto.mathfm_line_rej_model_dir + [0x2727b50] OneOCR.PipelineProto.mathfm_line_attn_model_dir + [0x2727b80] OneOCR.PipelineProto.mathfm_det_model_dir + [0x2727bb0] OneOCR.PipelineProto.mathfm_line_enc_model_dir + [0x2727be0] OneOCR.PipelineProto.custom_fst_model_dir + [0x2727c10] OneOCR.PipelineProto.enums_map_file + [0x272ada8] Formula Line Decoder vocabulary file + [0x272af60] Detector model dir + [0x272b000] Table recognizer model dir + [0x272b050] Table detector model dir + [0x272b0a8] Checkbox detector model dir + [0x272b178] Decoder model dir + [0x272b430] Form detector model dir + [0x272b670] Math formula line decoder model dir + [0x272b6d0] MathFormula detector model dir + [0x27ee6c2] CreateOcrPipeline + [0x27ee7cc] OcrProcessOptionsGetMaxRecognitionLineCount + [0x27ee7f8] OcrProcessOptionsGetResizeResolution + [0x27ee81d] OcrProcessOptionsSetMaxRecognitionLineCount + [0x27ee849] OcrProcessOptionsSetResizeResolution + [0x27ee884] ReleaseOcrPipeline + [0x27ee8c1] RunOcrPipeline + [0x27ef8f4] DecodePointer diff --git a/_archive/temp/re_output/08_error_strings.txt b/_archive/temp/re_output/08_error_strings.txt new file mode 100644 index 0000000000000000000000000000000000000000..0ccf7734523abcf00ab4a2e34cc2043837035048 --- /dev/null +++ b/_archive/temp/re_output/08_error_strings.txt @@ -0,0 +1,62 @@ +ERROR/DEBUG MESSAGES +============================================================ + [0x831be0] Raw image encoder error: + [0x832e28] ): failed TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &wdth) + [0x832ea0] OpenCV TIFF: failed TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &wdth) + [0x832ee8] ): failed TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &hght) + [0x832f20] OpenCV TIFF: failed TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &hght) + [0x833000] Invalid bitsperpixel value read from TIFF header! Must be 1, 8, 10, 12, 14, 16, 32 or 64. + [0x833d78] ): failed TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width) + [0x833db0] OpenCV TIFF: failed TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width) + [0x833df8] ): failed TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height) + [0x833e40] OpenCV TIFF: failed TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height) + [0x834198] ): failed TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, channels) + [0x8341e0] OpenCV TIFF: failed TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, channels) + [0x834648] ): failed TIFFWriteScanline(tif, buffer, y, 0) == 1 + [0x834680] OpenCV TIFF: failed TIFFWriteScanline(tif, buffer, y, 0) == 1 + [0x834740] ): failed TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3) + [0x834780] OpenCV TIFF: failed TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3) + [0x8450a8] Invalid number of channels in input image + [0x845120] Invalid number of channels in output image + [0x866036] #error "(nimages <= 2) should be true" + [0x8e91e0] OpenCV(%s) Error: %s (%s) in %s, file %s, line %d + [0x8eeb98] CL_INVALID_IMAGE_FORMAT_DESCRIPTOR + [0x8eebc0] CL_INVALID_IMAGE_SIZE + [0x8eee60] CL_INVALID_IMAGE_DESCRIPTOR + [0x96f590] Invalid image width in IHDR + [0x96f5f8] Invalid image height in IHDR + [0x96f797] Cinvalid after png_start_read_image or png_read_update_info + [0x9708f8] invalid user transform pixel depth + [0x970a88] Invalid bit depth for grayscale image + [0x970ab0] Invalid bit depth for RGB image + [0x970ad0] Invalid bit depth for paletted image + [0x970af8] Invalid bit depth for grayscale+alpha image + [0x970b28] Invalid bit depth for RGBA image + [0x970b50] Invalid image color type specified + [0x970d08] iCCP: invalid keyword + [0x970d20] sPLT: invalid keyword + [0x970f10] tEXt: invalid keyword + [0x970f60] zTXt: invalid keyword + [0x970f78] iTXt: invalid keyword + [0x971030] pCAL: invalid keyword + [0x972778] Invalid td_samplesperpixel value + [0x973658] Seek error at scanline %lu + [0x9736a8] Write error at scanline %lu + [0x9740d0] Read error at scanline %u; got %lld bytes, expected %lld + [0x974198] Seek error at scanline %u, strip %u + [0x9741c0] Read error at scanline %u, strip %u; got %lld bytes, expected %lld + [0x97b108] Invalid data for scanline %u + [0x97c340] Decoding error at scanline %lu, %s + [0x97c6c8] Decoding error at scanline %u, %s + [0x97d5f0] Encoding error at scanline %u, %s + [0x2078631] ASSERTIONMODELSTRUEFORCES + [0x271cd90] OneOCR.Interop.TextRecognitionResult.errorInfo + [0x271cdf0] OneOCR.Interop.BarcodeResult.error_info + [0x271ce70] OneOCR.Interop.FormulaResult.error_info + [0x271ce98] OneOCR.Interop.CheckboxResult.error_info + [0x271cf00] OneOCR.Interop.LangIDResult.error_info + [0x2723580] Encounter error inside Ort while creating inference session from ONNX model + [0x27240e8] Invalid dimension for SizeFromDimension. Tensor has + [0x2724dd8] Memory management error in CLatStrRepo detected. + [0x2725ad0] ONEOCR_INSTALL_FAILURES_SIGNAL_HANDLER + [0x27263a0] Invalid size for image diff --git a/_archive/temp/re_output/09_constants.txt b/_archive/temp/re_output/09_constants.txt new file mode 100644 index 0000000000000000000000000000000000000000..7d3bea7c512341ec8f5871f1ddf71a478420b015 --- /dev/null +++ b/_archive/temp/re_output/09_constants.txt @@ -0,0 +1,62 @@ +FLOAT CONSTANTS IN .rdata +============================================================ + float: 0.001 @ ['0x81b9e4', '0x81bd44', '0x81bd94', '0x81be34', '0x81be70'] + float: 0.01 @ ['0x81f9b8', '0x8200d0', '0x8200e4', '0x82a868', '0x82b100'] + float: 0.05 @ ['0x820224', '0x8404a8', '0x8bc228', '0x8e16e0', '0x8e4dbc'] + float: 0.1 @ ['0x844c4c', '0x8f6638', '0x97daa0', '0x97daa8', '0x97dab0'] + float: 0.15 @ ['0x97d9e0', '0x97d9e8', '0x9ef9b8', '0xa53d9c', '0xa5455c'] + float: 0.2 @ ['0x97d948', '0x9efa74', '0xa53a64', '0xa75c84', '0xa84720'] + float: 0.25 @ ['0x83f730', '0x83f734', '0x83f738', '0x83f73c', '0x83fc0c'] + float: 0.3 @ ['0x8f4e0c', '0xa767cc', '0xc418c0', '0x18e72b4', '0x1bb9dc4'] + float: 0.4 @ ['0xbe6144', '0xca8e60', '0x104eca0', '0x170ba28', '0x18e731c'] + float: 0.45 @ ['0xa8d6f4', '0x16806ac', '0x1e74f80', '0x1f30908'] + float: 0.5 @ ['0x824668', '0x82a0e8', '0x841ef8', '0x8420d8', '0x842498'] + float: 0.55 @ ['0x1d82014', '0x1d92a4c', '0x1db12c4', '0x1dca69c', '0x1e0b844'] + float: 0.6 @ ['0x999168', '0xb34670', '0xd6a600', '0x272ca5c'] + float: 0.65 @ ['0x168072c', '0x185f4b0', '0x1d0eca8', '0x207f240', '0x207f2b0'] + float: 0.7 @ ['0x1736d54', '0x185f4ec', '0x18e73e8', '0x19479b4', '0x22ea9a4'] + float: 0.75 @ ['0x81b9f8', '0x81c04c', '0xdb70a8', '0x1680760', '0x16be7cc'] + float: 0.8 @ ['0x1f00668', '0x27045ec', '0x27047ec'] + float: 0.85 @ ['0xcf96e0', '0x1b5f594', '0x270459c'] + float: 0.88 @ ['0xdb69dc', '0x1739d48', '0x185f600', '0x18e7444', '0x194a9a8'] + float: 0.9 @ ['0x97e1cc', '0x9ef1a0', '0xd84c90', '0x16807ac', '0x1bb9f3c'] + float: 0.92 @ ['0x841f8c', '0x842044', '0x84252c', '0x1731d4c', '0x194296c'] + float: 0.95 @ ['0xd1ee7c', '0xd320dc', '0x1646b30', '0x169fe64', '0x172f8e0'] + float: 0.99 @ ['0x841fc8', '0x842008', '0x842568', '0xcb88d8', '0x185f6b0'] + float: 2.0 @ ['0x81b9d4', '0x81b9fc', '0x81ba38', '0x81bb78', '0x81bbdc'] + float: 3.0 @ ['0x847df0', '0x847df4', '0x847df8', '0x847dfc', '0x8c5c6c'] + float: 4.0 @ ['0x821a4c', '0x822898', '0x840860', '0x849a30', '0x849a34'] + float: 6.0 @ ['0x83f69c', '0x849a40', '0x849a44', '0x849a48', '0x849a4c'] + float: 8.0 @ ['0x847bd0', '0x847e10', '0x847e14', '0x847e18', '0x847e1c'] + float: 16.0 @ ['0x847bd8', '0x847e30', '0x847e34', '0x847e38', '0x847e3c'] + float: 32.0 @ ['0x82316c', '0x840874', '0x8408d0', '0x8408d4', '0x8408d8'] + float: 60.0 @ ['0x8499a8', '0x849a50', '0x849a54', '0x849a58', '0x849a5c'] + float: 75.0 @ ['0x8c5d8c', '0x91ce8c', '0x22224f8'] + float: 100.0 @ ['0x847be0', '0x8c5df0', '0x8c6638', '0x8c6688', '0x91cef0'] + float: 128.0 @ ['0x847be8', '0x8c5e60', '0x91cf60', '0x9f2754', '0x1593df0'] + float: 200.0 @ ['0x847bf0', '0x847e70', '0x847e74', '0x847e78', '0x847e7c'] + float: 255.0 @ ['0x847bf4', '0x847e80', '0x847e84', '0x847e88', '0x847e8c'] + float: 256.0 @ ['0x847bf8', '0x8c6060', '0x8c6620', '0x8c66a0', '0x8f6674'] + float: 320.0 @ ['0x81d12c', '0x821a60', '0x8c6160'] + float: 400.0 @ ['0x8c62a0', '0x8c6610', '0x8c66b0'] + float: 640.0 @ ['0x23d33d4'] + float: 800.0 @ ['0x1963330'] + float: 1600.0 @ ['0x8c65c0', '0x8c6700'] + + +DOUBLE CONSTANTS IN .rdata +============================================================ + double: 0.1 @ ['0x272ca90'] + double: 0.15 @ ['0x27011b8'] + double: 0.25 @ ['0x83f690', '0x2703960', '0x2706780', '0x2706d20'] + double: 0.3 @ ['0x272caa0'] + double: 0.4 @ ['0x272caa8'] + double: 0.5 @ ['0x8e4c78', '0x8f2638', '0x2703920', '0x2703940', '0x2704ae0'] + double: 0.8 @ ['0x8e4088', '0x8f1a48', '0x272cac8'] + double: 0.92 @ ['0x1054bd8'] + double: 0.95 @ ['0x272cad0'] + double: 1.0 @ ['0x83dca0', '0x83dcc8', '0x83fc10', '0x8e3c88', '0x8f1440'] + double: 2.0 @ ['0x81b9d0', '0x81b9f8', '0x81bbd8', '0x81bc50', '0x81bdb8'] + double: 60.0 @ ['0x272cb80'] + double: 200.0 @ ['0x1737518', '0x272ccd0'] + double: 255.0 @ ['0x8e7a00', '0x272cbb0', '0x272ccf0', '0x272d030', '0x272d040'] diff --git a/_archive/temp/re_output/10_disassembly.txt b/_archive/temp/re_output/10_disassembly.txt new file mode 100644 index 0000000000000000000000000000000000000000..abfb8a00c3468b8c41493faf8c0f73c8b374c620 --- /dev/null +++ b/_archive/temp/re_output/10_disassembly.txt @@ -0,0 +1,594 @@ +DISASSEMBLY OF KEY EXPORTS +============================================================ + +============================================================ +RunOcrPipeline @ RVA 0x29150, file offset 0x28550 +============================================================ + 0x29150 push rbx + 0x29152 push rsi + 0x29153 push rdi + 0x29154 push r14 + 0x29156 push r15 + 0x29158 sub rsp, 0x340 + 0x2915f mov rax, qword ptr [rip + 0x27d2cda] + 0x29166 xor rax, rsp + 0x29169 mov qword ptr [rsp + 0x330], rax + 0x29171 mov rdi, r9 + 0x29174 mov r14, r8 + 0x29177 mov rbx, rdx + 0x2917a mov rsi, rcx + 0x2917d xor r15d, r15d + 0x29180 test rcx, rcx + 0x29183 je 0x29704 + 0x29189 test rdx, rdx + 0x2918c je 0x29704 + 0x29192 test r9, r9 + 0x29195 je 0x29704 + 0x2919b cmp qword ptr [rdx + 0x18], r15 + 0x2919f jne 0x291ab + 0x291a1 mov eax, 2 + 0x291a6 jmp 0x29709 + 0x291ab mov eax, dword ptr [rdx + 4] + 0x291ae sub eax, 0x32 + 0x291b1 cmp eax, 0x26de + 0x291b6 ja 0x296fd + 0x291bc mov eax, dword ptr [rdx + 8] + 0x291bf sub eax, 0x32 + 0x291c2 cmp eax, 0x26de + 0x291c7 ja 0x296fd + 0x291cd xorps xmm0, xmm0 + 0x291d0 movups xmmword ptr [rsp + 0xd0], xmm0 + 0x291d8 movups xmmword ptr [rsp + 0xe0], xmm0 + 0x291e0 movups xmmword ptr [rsp + 0xf0], xmm0 + 0x291e8 movups xmmword ptr [rsp + 0x100], xmm0 + 0x291f0 movups xmmword ptr [rsp + 0x110], xmm0 + 0x291f8 movups xmmword ptr [rsp + 0x120], xmm0 + 0x29200 lea rcx, [rsp + 0xd0] + 0x29208 call 0x4a5b10 + 0x2920d nop + 0x2920e mov rcx, qword ptr [rbx + 0x18] + 0x29212 mov eax, dword ptr [rbx] + 0x29214 test eax, eax + 0x29216 jne 0x29251 + 0x29218 mov rax, qword ptr [rbx + 0x10] + 0x2921c mov qword ptr [rsp + 0x28], rax + 0x29221 mov qword ptr [rsp + 0x20], rcx + 0x29226 xor r9d, r9d + 0x29229 mov r8d, dword ptr [rbx + 4] + 0x2922d mov edx, dword ptr [rbx + 8] + 0x29230 lea rcx, [rsp + 0x70] + 0x29235 call 0x4a5540 + 0x2923a nop + 0x2923b mov rdx, rax + 0x2923e lea rcx, [rsp + 0xd0] + 0x29246 call 0x4a5bf0 + 0x2924b nop + 0x2924c jmp 0x2937a + 0x29251 cmp eax, 1 + 0x29254 jne 0x292fc + 0x2925a xorps xmm0, xmm0 + 0x2925d movups xmmword ptr [rsp + 0x70], xmm0 + 0x29262 movups xmmword ptr [rsp + 0x80], xmm0 + 0x2926a movups xmmword ptr [rsp + 0x90], xmm0 + 0x29272 movups xmmword ptr [rsp + 0xa0], xmm0 + 0x2927a movups xmmword ptr [rsp + 0xb0], xmm0 + 0x29282 movups xmmword ptr [rsp + 0xc0], xmm0 + 0x2928a mov rax, qword ptr [rbx + 0x10] + 0x2928e mov qword ptr [rsp + 0x28], rax + 0x29293 mov qword ptr [rsp + 0x20], rcx + 0x29298 mov r9d, 0x10 + 0x2929e mov r8d, dword ptr [rbx + 4] + 0x292a2 mov edx, dword ptr [rbx + 8] + 0x292a5 lea rcx, [rsp + 0x70] + 0x292aa call 0x4a5540 + 0x292af nop + 0x292b0 mov qword ptr [rsp + 0x48], r15 + 0x292b5 mov dword ptr [rsp + 0x38], 0x2010000 + 0x292bd lea rax, [rsp + 0xd0] + 0x292c5 mov qword ptr [rsp + 0x40], rax + 0x292ca mov qword ptr [rsp + 0x60], r15 + 0x292cf mov dword ptr [rsp + 0x50], 0x1010000 + 0x292d7 lea rax, [rsp + 0x70] + 0x292dc mov qword ptr [rsp + 0x58], rax + 0x292e1 xor r9d, r9d + 0x292e4 mov r8d, 4 + 0x292ea lea rdx, [rsp + 0x38] + 0x292ef lea rcx, [rsp + 0x50] + 0x292f4 call 0x2c9ae0 + 0x292f9 nop + 0x292fa jmp 0x2937a + 0x292fc cmp eax, 2 + 0x292ff jne 0x2933a + 0x29301 mov rax, qword ptr [rbx + 0x10] + 0x29305 mov qword ptr [rsp + 0x28], rax + 0x2930a mov qword ptr [rsp + 0x20], rcx + 0x2930f mov r9d, 0x10 + 0x29315 mov r8d, dword ptr [rbx + 4] + 0x29319 mov edx, dword ptr [rbx + 8] + 0x2931c lea rcx, [rsp + 0x70] + 0x29321 call 0x4a5540 + 0x29326 nop + 0x29327 mov rdx, rax + 0x2932a lea rcx, [rsp + 0xd0] + 0x29332 call 0x4a5bf0 + 0x29337 nop + 0x29338 jmp 0x2937a + 0x2933a cmp eax, 3 + 0x2933d jne 0x296e2 + 0x29343 mov rax, qword ptr [rbx + 0x10] + 0x29347 mov qword ptr [rsp + 0x28], rax + 0x2934c mov qword ptr [rsp + 0x20], rcx + 0x29351 mov r9d, 0x18 + 0x29357 mov r8d, dword ptr [rbx + 4] + 0x2935b mov edx, dword ptr [rbx + 8] + 0x2935e lea rcx, [rsp + 0x70] + 0x29363 call 0x4a5540 + 0x29368 nop + 0x29369 mov rdx, rax + 0x2936c lea rcx, [rsp + 0xd0] + 0x29374 call 0x4a5bf0 + 0x29379 nop + 0x2937a lea rcx, [rsp + 0x70] + 0x2937f call 0x4a5bb0 + 0x29384 lea rcx, [rsp + 0x130] + 0x2938c test r14, r14 + 0x2938f je 0x294f0 + 0x29395 mov rdx, r14 + 0x29398 call 0x28410 + 0x2939d mov rbx, rax + 0x293a0 mov qword ptr [rsp + 0x30], rax + 0x293a5 xorps xmm0, xmm0 + 0x293a8 movups xmmword ptr [rsp + 0x70], xmm0 + 0x293ad movups xmmword ptr [rsp + 0x80], xmm0 + 0x293b5 movups xmmword ptr [rsp + 0x90], xmm0 + 0x293bd movups xmmword ptr [rsp + 0xa0], xmm0 + 0x293c5 movups xmmword ptr [rsp + 0xb0], xmm0 + 0x293cd movups xmmword ptr [rsp + 0xc0], xmm0 + 0x293d5 mov r8, rax + 0x293d8 lea rdx, [rsp + 0xd0] + 0x293e0 lea rcx, [rsp + 0x70] + 0x293e5 call 0x28230 + 0x293ea nop + 0x293eb mov rax, qword ptr [rsi] + 0x293ee xor r9d, r9d + 0x293f1 lea r8, [rsp + 0x70] + 0x293f6 lea rdx, [rsp + 0x1d0] + 0x293fe mov rcx, rsi + 0x29401 mov rax, qword ptr [rax + 0x10] + 0x29405 call qword ptr [rip + 0x7f126d] + 0x2940b nop + 0x2940c lea rcx, [rsp + 0xb8] + 0x29414 call 0x2a370 + 0x29419 lea rcx, [rsp + 0xa0] + 0x29421 call 0x29b50 + 0x29426 lea rcx, [rsp + 0x88] + 0x2942e call 0x2a430 + 0x29433 lea rcx, [rsp + 0x70] + 0x29438 call 0x2a430 + 0x2943d nop + 0x2943e lea rcx, [rbx + 0x38] + 0x29442 call 0x2a560 + 0x29447 lea rcx, [rbx + 0x10] + 0x2944b call 0x2a560 + 0x29450 lea rdx, [rip + 0x26d58fd] + 0x29457 mov ecx, 0x20 + 0x2945c call 0x78efac + 0x29461 test rax, rax + 0x29464 je 0x294b1 + 0x29466 mov r8, qword ptr [rsp + 0x1e0] + 0x2946e mov qword ptr [rsp + 0x1e0], r15 + 0x29476 mov rdx, qword ptr [rsp + 0x1d8] + 0x2947e mov qword ptr [rsp + 0x1d8], r15 + 0x29486 mov rcx, qword ptr [rsp + 0x1d0] + 0x2948e mov qword ptr [rsp + 0x1d0], r15 + 0x29496 mov qword ptr [rax], rcx + 0x29499 mov qword ptr [rax + 8], rdx + 0x2949d mov qword ptr [rax + 0x10], r8 + 0x294a1 movss xmm0, dword ptr [rsp + 0x1e8] + 0x294aa movss dword ptr [rax + 0x18], xmm0 + 0x294af jmp 0x294b4 + 0x294b1 mov rax, r15 + 0x294b4 mov qword ptr [rdi], rax + 0x294b7 lea rcx, [rsp + 0x260] + 0x294bf call 0x29a60 + 0x294c4 lea rcx, [rsp + 0x228] + 0x294cc call 0x40370 + 0x294d1 lea rcx, [rsp + 0x1f0] + 0x294d9 call 0x3d750 + 0x294de lea rcx, [rsp + 0x1d0] + 0x294e6 call 0x2a2a0 + 0x294eb jmp 0x296be + 0x294f0 call 0x28a50 + 0x294f5 nop + 0x294f6 mov dword ptr [rsp + 0x194], 1 + 0x29501 mov word ptr [rsp + 0x198], 0 + 0x2950b mov dword ptr [rsp + 0x1b4], 0x64 + 0x29516 mov dword ptr [rsp + 0x1b8], 0xbb8 + ... (truncated at 200 instructions) + +============================================================ +CreateOcrPipeline @ RVA 0x28bb0, file offset 0x27fb0 +============================================================ + 0x28bb0 push rbx + 0x28bb2 push rsi + 0x28bb3 push rdi + 0x28bb4 push r12 + 0x28bb6 push r13 + 0x28bb8 push r14 + 0x28bba push r15 + 0x28bbc sub rsp, 0x460 + 0x28bc3 mov rax, qword ptr [rip + 0x27d3276] + 0x28bca xor rax, rsp + 0x28bcd mov qword ptr [rsp + 0x450], rax + 0x28bd5 mov r12, r9 + 0x28bd8 mov r15, r8 + 0x28bdb mov r14, rdx + 0x28bde mov rsi, rcx + 0x28be1 xor r13d, r13d + 0x28be4 test rcx, rcx + 0x28be7 je 0x28f3e + 0x28bed test r9, r9 + 0x28bf0 je 0x28f3e + 0x28bf6 mov qword ptr [rsp + 0x30], rcx + 0x28bfb mov rdi, 0xffffffffffffffff + 0x28c02 mov rax, rdi + 0x28c05 inc rax + 0x28c08 cmp byte ptr [rcx + rax], r13b + 0x28c0c jne 0x28c05 + 0x28c0e mov qword ptr [rsp + 0x38], rax + 0x28c13 movaps xmm0, xmmword ptr [rsp + 0x30] + 0x28c18 movdqa xmmword ptr [rsp + 0x30], xmm0 + 0x28c1e lea rdx, [rsp + 0x30] + 0x28c23 lea rcx, [rsp + 0x50] + 0x28c28 call 0x2b0c0 + 0x28c2d nop + 0x28c2e lea rdx, [rsp + 0x50] + 0x28c33 lea rcx, [rsp + 0x70] + 0x28c38 call 0x28970 + 0x28c3d movsd xmm0, qword ptr [rax] + 0x28c41 movsd qword ptr [rsp + 0x30], xmm0 + 0x28c47 mov ecx, dword ptr [rax + 8] + 0x28c4a mov dword ptr [rsp + 0x70], ecx + 0x28c4e lea rax, [rip + 0x27d3edb] + 0x28c55 mov qword ptr [rsp + 0x78], rax + 0x28c5a movaps xmm0, xmmword ptr [rsp + 0x70] + 0x28c5f movdqa xmmword ptr [rsp + 0x70], xmm0 + 0x28c65 mov eax, dword ptr [rsp + 0x30] + 0x28c69 test eax, eax + 0x28c6b je 0x28c8b + 0x28c6d cmp eax, 1 + 0x28c70 sete bl + 0x28c73 lea rcx, [rsp + 0x50] + 0x28c78 call 0x2a4f0 + 0x28c7d test bl, bl + 0x28c7f je 0x28c97 + 0x28c81 mov eax, 5 + 0x28c86 jmp 0x28f43 + 0x28c8b mov bl, 1 + 0x28c8d test ecx, ecx + 0x28c8f jne 0x28f66 + 0x28c95 jmp 0x28c73 + 0x28c97 mov qword ptr [rsp + 0x70], r13 + 0x28c9c mov ecx, 0x60 + 0x28ca1 call 0x78ef70 + 0x28ca6 mov qword ptr [rsp + 0x30], rax + 0x28cab test r15, r15 + 0x28cae jne 0x28ce2 + 0x28cb0 mov word ptr [rsp + 0x20], r15w + 0x28cb6 xorps xmm0, xmm0 + 0x28cb9 movups xmmword ptr [rax], xmm0 + 0x28cbc movups xmmword ptr [rax + 0x10], xmm0 + 0x28cc0 movups xmmword ptr [rax + 0x20], xmm0 + 0x28cc4 movups xmmword ptr [rax + 0x30], xmm0 + 0x28cc8 movups xmmword ptr [rax + 0x40], xmm0 + 0x28ccc movups xmmword ptr [rax + 0x50], xmm0 + 0x28cd0 lea rdx, [rsp + 0x20] + 0x28cd5 mov rcx, rax + 0x28cd8 call 0x59830 + 0x28cdd mov rbx, rax + 0x28ce0 jmp 0x28d0a + 0x28ce2 xorps xmm0, xmm0 + 0x28ce5 movups xmmword ptr [rax], xmm0 + 0x28ce8 movups xmmword ptr [rax + 0x10], xmm0 + 0x28cec movups xmmword ptr [rax + 0x20], xmm0 + 0x28cf0 movups xmmword ptr [rax + 0x30], xmm0 + 0x28cf4 movups xmmword ptr [rax + 0x40], xmm0 + 0x28cf8 movups xmmword ptr [rax + 0x50], xmm0 + 0x28cfc mov rdx, r15 + 0x28cff mov rcx, rax + 0x28d02 call 0x59830 + 0x28d07 mov rbx, rax + 0x28d0a mov qword ptr [rsp + 0x70], rax + 0x28d0f xorps xmm0, xmm0 + 0x28d12 test r14, r14 + 0x28d15 jne 0x28e14 + 0x28d1b movups xmmword ptr [rsp + 0x50], xmm0 + 0x28d20 mov qword ptr [rsp + 0x60], r13 + 0x28d25 mov qword ptr [rsp + 0x68], r13 + 0x28d2a xor r8d, r8d + 0x28d2d lea rdx, [rip + 0x26e853b] + 0x28d34 lea rcx, [rsp + 0x50] + 0x28d39 call 0x2aad0 + 0x28d3e nop + 0x28d3f xorps xmm0, xmm0 + 0x28d42 movups xmmword ptr [rsp + 0x30], xmm0 + 0x28d47 mov qword ptr [rsp + 0x40], r13 + 0x28d4c mov qword ptr [rsp + 0x48], r13 + 0x28d51 inc rdi + 0x28d54 cmp byte ptr [rsi + rdi], 0 + 0x28d58 jne 0x28d51 + 0x28d5a mov r8, rdi + 0x28d5d mov rdx, rsi + 0x28d60 lea rcx, [rsp + 0x30] + 0x28d65 call 0x2aad0 + 0x28d6a nop + 0x28d6b xor edx, edx + 0x28d6d mov r8d, 0x3d0 + 0x28d73 lea rcx, [rsp + 0x80] + 0x28d7b call 0x7e3e70 + 0x28d80 lea r8, [rsp + 0x50] + 0x28d85 lea rdx, [rsp + 0x30] + 0x28d8a lea rcx, [rsp + 0x80] + 0x28d92 call 0x158140 + 0x28d97 nop + 0x28d98 mov rax, qword ptr [rbx] + 0x28d9b lea rdx, [rsp + 0x80] + 0x28da3 mov rcx, rbx + 0x28da6 mov rax, qword ptr [rax + 8] + 0x28daa call qword ptr [rip + 0x7f18c8] + 0x28db0 nop + 0x28db1 lea rcx, [rsp + 0x428] + 0x28db9 call 0x2a560 + 0x28dbe mov r8, qword ptr [rsp + 0x418] + 0x28dc6 mov r8, qword ptr [r8 + 8] + 0x28dca lea rdx, [rsp + 0x418] + 0x28dd2 lea rcx, [rsp + 0x418] + 0x28dda call 0x80d40 + 0x28ddf mov edx, 0x58 + 0x28de4 mov rcx, qword ptr [rsp + 0x418] + 0x28dec call 0x78f090 + 0x28df1 lea rcx, [rsp + 0x80] + 0x28df9 call 0x1c87b0 + 0x28dfe nop + 0x28dff lea rcx, [rsp + 0x30] + 0x28e04 call 0x2a560 + 0x28e09 nop + 0x28e0a lea rcx, [rsp + 0x50] + 0x28e0f jmp 0x28f0e + 0x28e14 movups xmmword ptr [rsp + 0x30], xmm0 + 0x28e19 mov qword ptr [rsp + 0x40], r13 + 0x28e1e mov qword ptr [rsp + 0x48], r13 + 0x28e23 mov r8, rdi + 0x28e26 inc r8 + 0x28e29 cmp byte ptr [r14 + r8], 0 + 0x28e2e jne 0x28e26 + 0x28e30 mov rdx, r14 + 0x28e33 lea rcx, [rsp + 0x30] + 0x28e38 call 0x2aad0 + 0x28e3d nop + 0x28e3e xorps xmm0, xmm0 + 0x28e41 movups xmmword ptr [rsp + 0x50], xmm0 + 0x28e46 mov qword ptr [rsp + 0x60], r13 + 0x28e4b mov qword ptr [rsp + 0x68], r13 + 0x28e50 inc rdi + 0x28e53 cmp byte ptr [rsi + rdi], 0 + 0x28e57 jne 0x28e50 + 0x28e59 mov r8, rdi + 0x28e5c mov rdx, rsi + 0x28e5f lea rcx, [rsp + 0x50] + 0x28e64 call 0x2aad0 + 0x28e69 nop + 0x28e6a xor edx, edx + 0x28e6c mov r8d, 0x3d0 + 0x28e72 lea rcx, [rsp + 0x80] + 0x28e7a call 0x7e3e70 + 0x28e7f lea r8, [rsp + 0x30] + 0x28e84 lea rdx, [rsp + 0x50] + 0x28e89 lea rcx, [rsp + 0x80] + 0x28e91 call 0x158140 + 0x28e96 nop + 0x28e97 mov rax, qword ptr [rbx] + 0x28e9a lea rdx, [rsp + 0x80] + 0x28ea2 mov rcx, rbx + 0x28ea5 mov rax, qword ptr [rax + 8] + 0x28ea9 call qword ptr [rip + 0x7f17c9] + 0x28eaf nop + 0x28eb0 lea rcx, [rsp + 0x428] + 0x28eb8 call 0x2a560 + 0x28ebd mov r8, qword ptr [rsp + 0x418] + 0x28ec5 mov r8, qword ptr [r8 + 8] + 0x28ec9 lea rdx, [rsp + 0x418] + 0x28ed1 lea rcx, [rsp + 0x418] + 0x28ed9 call 0x80d40 + 0x28ede mov edx, 0x58 + 0x28ee3 mov rcx, qword ptr [rsp + 0x418] + 0x28eeb call 0x78f090 + 0x28ef0 lea rcx, [rsp + 0x80] + 0x28ef8 call 0x1c87b0 + 0x28efd nop + 0x28efe lea rcx, [rsp + 0x50] + 0x28f03 call 0x2a560 + 0x28f08 nop + ... (truncated at 200 instructions) + +============================================================ +GetOcrLineCount @ RVA 0x29750, file offset 0x28b50 +============================================================ + 0x29750 mov r9, rdx + 0x29753 test rcx, rcx + 0x29756 je 0x2979e + 0x29758 test rdx, rdx + 0x2975b je 0x2979e + 0x2975d mov r8, qword ptr [rcx] + 0x29760 mov rax, qword ptr [rcx + 8] + 0x29764 sub rax, r8 + 0x29767 and rax, 0xffffffffffffff00 + 0x2976d cmp rax, 0x100 + 0x29773 jne 0x2979e + 0x29775 mov rcx, qword ptr [r8 + 0x28] + 0x29779 movabs rax, 0x6bca1af286bca1b + 0x29783 sub rcx, qword ptr [r8 + 0x20] + 0x29787 imul rcx + 0x2978a sar rdx, 2 + 0x2978e mov rax, rdx + 0x29791 shr rax, 0x3f + 0x29795 add rdx, rax + 0x29798 mov qword ptr [r9], rdx + 0x2979b xor eax, eax + 0x2979d ret + +============================================================ +GetOcrLine @ RVA 0x297b0, file offset 0x28bb0 +============================================================ + 0x297b0 mov r10, rdx + 0x297b3 test rcx, rcx + 0x297b6 je 0x29810 + 0x297b8 test r8, r8 + 0x297bb je 0x29810 + 0x297bd mov r9, qword ptr [rcx] + 0x297c0 mov rax, qword ptr [rcx + 8] + 0x297c4 sub rax, r9 + 0x297c7 and rax, 0xffffffffffffff00 + 0x297cd cmp rax, 0x100 + 0x297d3 jne 0x29810 + 0x297d5 mov r11, qword ptr [r9 + 0x20] + 0x297d9 movabs rax, 0x6bca1af286bca1b + 0x297e3 mov rcx, qword ptr [r9 + 0x28] + 0x297e7 sub rcx, r11 + 0x297ea imul rcx + 0x297ed sar rdx, 2 + 0x297f1 mov rax, rdx + 0x297f4 shr rax, 0x3f + 0x297f8 add rdx, rax + 0x297fb cmp r10, rdx + 0x297fe jae 0x29810 + 0x29800 imul rax, r10, 0x98 + 0x29807 add rax, r11 + 0x2980a mov qword ptr [r8], rax + 0x2980d xor eax, eax + 0x2980f ret + +============================================================ +GetOcrLineContent @ RVA 0x29840, file offset 0x28c40 +============================================================ + 0x29840 test rcx, rcx + 0x29843 je 0x29865 + 0x29845 test rdx, rdx + 0x29848 je 0x29865 + 0x2984a mov rax, qword ptr [rcx + 0x28] + 0x2984e cmp qword ptr [rax + 0x10], 0 + 0x29853 je 0x29865 + 0x29855 cmp qword ptr [rax + 0x18], 0xf + 0x2985a jbe 0x2985f + 0x2985c mov rax, qword ptr [rax] + 0x2985f mov qword ptr [rdx], rax + 0x29862 xor eax, eax + 0x29864 ret + +============================================================ +GetOcrLineBoundingBox @ RVA 0x29820, file offset 0x28c20 +============================================================ + 0x29820 test rcx, rcx + 0x29823 je 0x29834 + 0x29825 test rdx, rdx + 0x29828 je 0x29834 + 0x2982a lea rax, [rcx + 8] + 0x2982e mov qword ptr [rdx], rax + 0x29831 xor eax, eax + 0x29833 ret + +============================================================ +GetOcrLineWordCount @ RVA 0x298a0, file offset 0x28ca0 +============================================================ + 0x298a0 mov r8, rdx + 0x298a3 mov rax, rcx + 0x298a6 test rcx, rcx + 0x298a9 je 0x298d9 + 0x298ab test rdx, rdx + 0x298ae je 0x298d9 + 0x298b0 mov rcx, qword ptr [rcx + 0x48] + 0x298b4 sub rcx, qword ptr [rax + 0x40] + 0x298b8 movabs rax, 0x4924924924924925 + 0x298c2 imul rcx + 0x298c5 sar rdx, 6 + 0x298c9 mov rax, rdx + 0x298cc shr rax, 0x3f + 0x298d0 add rdx, rax + 0x298d3 mov qword ptr [r8], rdx + 0x298d6 xor eax, eax + 0x298d8 ret + +============================================================ +GetOcrWord @ RVA 0x298e0, file offset 0x28ce0 +============================================================ + 0x298e0 mov r9, rdx + 0x298e3 test rcx, rcx + 0x298e6 je 0x29928 + 0x298e8 test r8, r8 + 0x298eb je 0x29928 + 0x298ed mov r10, qword ptr [rcx + 0x40] + 0x298f1 movabs rax, 0x4924924924924925 + 0x298fb mov rcx, qword ptr [rcx + 0x48] + 0x298ff sub rcx, r10 + 0x29902 imul rcx + 0x29905 sar rdx, 6 + 0x29909 mov rax, rdx + 0x2990c shr rax, 0x3f + 0x29910 add rdx, rax + 0x29913 cmp r9, rdx + 0x29916 jae 0x29928 + 0x29918 imul rax, r9, 0xe0 + 0x2991f add rax, r10 + 0x29922 mov qword ptr [r8], rax + 0x29925 xor eax, eax + 0x29927 ret + +============================================================ +GetOcrWordContent @ RVA 0x29950, file offset 0x28d50 +============================================================ + 0x29950 test rcx, rcx + 0x29953 je 0x29971 + 0x29955 test rdx, rdx + 0x29958 je 0x29971 + 0x2995a lea rax, [rcx + 0x80] + 0x29961 cmp qword ptr [rax + 0x18], 0xf + 0x29966 jbe 0x2996b + 0x29968 mov rax, qword ptr [rax] + 0x2996b mov qword ptr [rdx], rax + 0x2996e xor eax, eax + 0x29970 ret + +============================================================ +GetOcrWordBoundingBox @ RVA 0x29930, file offset 0x28d30 +============================================================ + 0x29930 test rcx, rcx + 0x29933 je 0x29940 + 0x29935 test rdx, rdx + 0x29938 je 0x29940 + 0x2993a mov qword ptr [rdx], rcx + 0x2993d xor eax, eax + 0x2993f ret + +============================================================ +GetOcrWordConfidence @ RVA 0x29980, file offset 0x28d80 +============================================================ + 0x29980 test rcx, rcx + 0x29983 je 0x29995 + 0x29985 test rdx, rdx + 0x29988 je 0x29995 + 0x2998a mov eax, dword ptr [rcx + 0xa0] + 0x29990 mov dword ptr [rdx], eax + 0x29992 xor eax, eax + 0x29994 ret + +============================================================ +GetImageAngle @ RVA 0x29730, file offset 0x28b30 +============================================================ + 0x29730 test rcx, rcx + 0x29733 je 0x29742 + 0x29735 test rdx, rdx + 0x29738 je 0x29742 + 0x2973a mov eax, dword ptr [rcx + 0x18] + 0x2973d mov dword ptr [rdx], eax + 0x2973f xor eax, eax + 0x29741 ret diff --git a/_archive/temp/re_output/11_pipeline_calls.txt b/_archive/temp/re_output/11_pipeline_calls.txt new file mode 100644 index 0000000000000000000000000000000000000000..273b6d16f8c7ad9c59d715d3de960b9c0724c0a3 --- /dev/null +++ b/_archive/temp/re_output/11_pipeline_calls.txt @@ -0,0 +1,77 @@ +CALLS FROM RunOcrPipeline +============================================================ + 0x29208: call 0x4a5b10 + 0x29235: call 0x4a5540 + 0x29246: call 0x4a5bf0 + 0x292aa: call 0x4a5540 + 0x292f4: call 0x2c9ae0 + 0x29321: call 0x4a5540 + 0x29332: call 0x4a5bf0 + 0x29363: call 0x4a5540 + 0x29374: call 0x4a5bf0 + 0x2937f: call 0x4a5bb0 + 0x29398: call 0x28410 + 0x293e5: call 0x28230 + 0x29414: call 0x2a370 + 0x29421: call 0x29b50 + 0x2942e: call 0x2a430 + 0x29438: call 0x2a430 + 0x29442: call 0x2a560 + 0x2944b: call 0x2a560 + 0x2945c: call 0x78efac + 0x294bf: call 0x29a60 + 0x294cc: call 0x40370 + 0x294d9: call 0x3d750 + 0x294e6: call 0x2a2a0 + 0x294f0: call 0x28a50 + 0x2954f: call 0x28410 + 0x2959c: call 0x28230 + 0x295cb: call 0x2a370 + 0x295d8: call 0x29b50 + 0x295e5: call 0x2a430 + 0x295ef: call 0x2a430 + 0x295f9: call 0x2a560 + 0x29602: call 0x2a560 + 0x29613: call 0x78efac + 0x29676: call 0x29a60 + 0x29683: call 0x40370 + 0x29690: call 0x3d750 + 0x2969d: call 0x2a2a0 + 0x296ab: call 0x2a560 + 0x296b8: call 0x2a560 + 0x296cc: call 0x4a5bb0 + 0x296d8: call 0x4a5bb0 + 0x296ea: call 0x4a5bb0 + 0x29714: call 0x78ef50 + +BRANCHES +============================================================ + 0x29183: je 0x29704 + 0x2918c: je 0x29704 + 0x29195: je 0x29704 + 0x2919f: jne 0x291ab + 0x291a6: jmp 0x29709 + 0x291b6: ja 0x296fd + 0x291c7: ja 0x296fd + 0x29216: jne 0x29251 + 0x2924c: jmp 0x2937a + 0x29254: jne 0x292fc + 0x292fa: jmp 0x2937a + 0x292ff: jne 0x2933a + 0x29338: jmp 0x2937a + 0x2933d: jne 0x296e2 + 0x2938f: je 0x294f0 + 0x29464: je 0x294b1 + 0x294af: jmp 0x294b4 + 0x294eb: jmp 0x296be + 0x2961b: je 0x29668 + 0x29666: jmp 0x2966b + 0x296ca: jne 0x296d8 + 0x296d6: jmp 0x29709 + 0x296e0: jmp 0x29709 + 0x296f4: jmp 0x29709 + 0x296fb: jmp 0x29709 + 0x29702: jmp 0x29709 + +STRING REFERENCES +============================================================ diff --git a/_archive/temp/re_output/12_all_relevant_strings.txt b/_archive/temp/re_output/12_all_relevant_strings.txt new file mode 100644 index 0000000000000000000000000000000000000000..33522cfde4fe19e42ef14813beb41f28d160e9b1 --- /dev/null +++ b/_archive/temp/re_output/12_all_relevant_strings.txt @@ -0,0 +1,2182 @@ +ALL RELEVANT STRINGS (OneOCR/Pipeline/Model/Tensor) +============================================================ + [0x823dd0] C:\__t\vcpkg\buildtrees\protobuf\src\v3.21.8-b162a26f57.clean\src\google/protobuf/descriptor.h + [0x823ff0] C:\__t\vcpkg\buildtrees\protobuf\src\v3.21.8-b162a26f57.clean\src\google\protobuf\descriptor.cc + [0x824350] CHECK failed: GeneratedDatabase()->Add(encoded_file_descriptor, size): + [0x824610] Invalid proto descriptor for file " + [0x8249e0] Missing field: FileDescriptorProto.name. + [0x824a10] Unrecognized syntax: + [0x824e70] FieldDescriptorProto.extendee not set for extension field. + [0x824eb0] FieldDescriptorProto.oneof_index should not be set for extensions. + [0x824ef8] FieldDescriptorProto.extendee set for non-extension field. + [0x824f40] FieldDescriptorProto.oneof_index $0 is out of range for type "$1". + [0x826250] Some options could not be correctly parsed using the proto descriptors compiled into this binary. + [0x826328] CHECK failed: options_descriptor: + [0x826a40] CHECK failed: (option_field->type()) == (FieldDescriptor::TYPE_GROUP): + [0x826bf0] CHECK failed: !descriptor_: + [0x827310] "). Note that the exact same class is required; not just the same descriptor. + [0x8279c0] CHECK failed: field->cpp_type() == cpp_type || (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM && cpp_type == FieldDescriptor::CPPTYPE_INT32): + [0x8283a8] Invalid descriptor + [0x8289d0] CHECK failed: (from.GetDescriptor()) == (descriptor): + [0x82aa71] google/protobuf/descriptor.proto + [0x82aaa7] FileDescriptorSet + [0x82aac6] 2$.google.protobuf.FileDescriptorProto" + [0x82aaf1] FileDescriptorProto + [0x82ab81] 2 .google.protobuf.DescriptorProto + [0x82abb6] 2$.google.protobuf.EnumDescriptorProto + [0x82abed] 2'.google.protobuf.ServiceDescriptorProto + [0x82ac29] 2%.google.protobuf.FieldDescriptorProto + [0x82accf] DescriptorProto + [0x82ade5] 2/.google.protobuf.DescriptorProto.ExtensionRange + [0x82ae2a] 2%.google.protobuf.OneofDescriptorProto + [0x82ae9b] 2..google.protobuf.DescriptorProto.ReservedRange + [0x82afe4] FieldDescriptorProto + [0x82b025] 2+.google.protobuf.FieldDescriptorProto.Label + [0x82b060] 2*.google.protobuf.FieldDescriptorProto.Type + [0x82b2bb] OneofDescriptorProto + [0x82b312] EnumDescriptorProto + [0x82b342] 2).google.protobuf.EnumValueDescriptorProto + [0x82b3b4] 26.google.protobuf.EnumDescriptorProto.EnumReservedRange + [0x82b438] EnumValueDescriptorProto + [0x82b4a7] ServiceDescriptorProto + [0x82b4db] 2&.google.protobuf.MethodDescriptorProto + [0x82b53a] MethodDescriptorProto + [0x82b960] no_standard_descriptor_accessor + [0x82c1c7] DescriptorProtosH + [0x82c1d9] Z-google.golang.org/protobuf/types/descriptorpb + [0x82c3a0] google/protobuf/descriptor.proto + [0x82db40] C:\__t\vcpkg\buildtrees\protobuf\src\v3.21.8-b162a26f57.clean\src\google\protobuf\descriptor_database.cc + [0x82dbb0] Invalid file descriptor data passed to EncodedDescriptorDatabase::Add(). + [0x82ec58] CHECK failed: (to->GetDescriptor()) == (descriptor): + [0x82ec90] Tried to merge messages of different types + [0x82ecc0] (merge + [0x82f0f0] stderrthreshold + [0x82f530] If specified, logfiles are written into this directory instead of the default logging directory. + [0x82f5b0] Put additional links to the log files in this directory + [0x831e20] cv::BmpDecoder::readHeader + [0x831ea8] cv::BmpDecoder::readData + [0x831f90] Windows bitmap (*.bmp;*.dib) + [0x832158] cv::SunRasterDecoder::readHeader + [0x8321a0] cv::SunRasterDecoder::readData + [0x832480] cv::PxMDecoder::readHeader + [0x8324e0] cv::PxMDecoder::readData + [0x832660] Portable bitmap(.pgm) expects gray image + [0x832690] Portable bitmap(.ppm) expects BGR image + [0x8326b8] For portable bitmap(.pbm) type must be CV_8UC1 + [0x832860] cv::PFMDecoder::readHeader + [0x832908] cv::PFMDecoder::readData + [0x832950] fabs(m_scale_factor) > 0.0f + [0x832b40] int __cdecl cv::TiffDecoder::normalizeChannelsNumber(int) const + [0x832c60] bool __cdecl cv::TiffDecoder::readHeader(void) + [0x832e78] cv::TiffDecoder::readHeader + [0x833090] bool __cdecl cv::TiffDecoder::readData(class cv::Mat &) + [0x833368] cv::TiffDecoder::readData + [0x8346c0] ): failed TIFFWriteDirectory(tif) + [0x8346e8] OpenCV TIFF: failed TIFFWriteDirectory(tif) + [0x834d00] cv::PngDecoder::readDataFromBuf + [0x834d20] decoder + [0x835264] GRAYSCALE + [0x835384] GRAYSCALE_ALPHA + [0x8358a0] bool __cdecl cv::PAMDecoder::readHeader(void) + [0x835980] cv::PAMDecoder::readHeader + [0x8359e8] cv::PAMDecoder::readData + [0x8362c8] anchor.inside(Rect(0, 0, ksize.width, ksize.height)) + [0x836c40] shape == MORPH_RECT || shape == MORPH_CROSS || shape == MORPH_ELLIPSE + [0x836df0] BORDER_CONSTANT + [0x836e00] BORDER_REPLICATE + [0x836e18] BORDER_REFLECT + [0x836e28] BORDER_REFLECT_101 + [0x836e60] BORDER_ISOLATED + [0x836e70] NO_BORDER_ISOLATED + [0x83cd50] C:\__t\vcpkg\buildtrees\opencv4\src\4.6.0-9a95a1b699.clean\modules\imgproc\src\resize.cpp + [0x83cdb0] cv::ResizeAreaFastVec_SIMD_8u::operator () + [0x83cde8] cv::ResizeAreaFastVec_SIMD_16u::operator () + [0x83ce18] cv::ResizeAreaFastVec_SIMD_16s::operator () + [0x83ce48] cv::computeResizeAreaTab + [0x83cec8] resizeSampler + [0x83ced8] resizeLN + [0x83cef0] -D INTER_LINEAR -D depth=%d -D T=%s -D T1=%s -D WT=%s -D convertToWT=%s -D convertToDT=%s -D cn=%d -D INTER_RESIZE_COEF_BITS=%d + [0x83cfa0] resizeNN + [0x83d000] -D convertToT=%s -D WT2V=%s -D convertToWT2V=%s -D INTER_AREA_FAST -D XSCALE=%d -D YSCALE=%d -D SCALE=%ff + [0x83d070] resizeAREA_FAST + [0x83d098] resizeAREA + [0x83d0d0] void __cdecl cv::hal::resize(int,const unsigned char *,unsigned __int64,int,int,unsigned char *,unsigned __int64,int,int,double,double,int) + [0x83d160] cv::hal::resize + [0x83d170] (dst_width > 0 && dst_height > 0) || (inv_scale_x > 0 && inv_scale_y > 0) + [0x83d250] void __cdecl cv::resize(const class cv::_InputArray &,const class cv::_OutputArray &,class cv::Size_,double,double,int) + [0x83d2d0] cv::resize + [0x83d2f0] inv_scale_x > 0 + [0x83d300] inv_scale_y > 0 + [0x83d710] cv::resizeGeneric_Invoker,struct cv::VResizeLanczos4,struct cv::VResizeNoVec> >::resizeGeneric_Invoker + [0x83d800] cv::resizeGeneric_Invoker,struct cv::VResizeLanczos4,struct cv::VResizeLanczos4Vec_32f> >::resizeGeneric_Invoker + [0x83d8d0] cv::resizeGeneric_Invoker,struct cv::VResizeLanczos4,struct cv::VResizeLanczos4Vec_32f16s> >::resizeGeneric_Invoker + [0x83d9b0] cv::resizeGeneric_Invoker,struct cv::VResizeLanczos4,struct cv::VResizeLanczos4Vec_32f16u> >::resizeGeneric_Invoker + [0x83daa0] cv::resizeGeneric_Invoker,struct cv::VResizeLanczos4,struct cv::VResizeNoVec> >::resizeGeneric_Invoker + [0x83db80] cv::resizeGeneric_Invoker,struct cv::VResizeCubic,struct cv::VResizeNoVec> >::resizeGeneric_Invoker + [0x83dc50] cv::resizeGeneric_Invoker,struct cv::VResizeCubic,struct cv::VResizeCubicVec_32f> >::resizeGeneric_Invoker + [0x83dd20] cv::resizeGeneric_Invoker,struct cv::VResizeCubic,struct cv::VResizeCubicVec_32f16s> >::resizeGeneric_Invoker + [0x83ddf0] cv::resizeGeneric_Invoker,struct cv::VResizeCubic,struct cv::VResizeCubicVec_32f16u> >::resizeGeneric_Invoker + [0x83dee0] cv::resizeGeneric_Invoker,struct cv::VResizeCubic,struct cv::VResizeCubicVec_32s8u> >::resizeGeneric_Invoker + [0x83dfd0] cv::resizeGeneric_Invoker,struct cv::VResizeLinear,struct cv::VResizeNoVec> >::resizeGeneric_Invoker + [0x83e0b0] cv::resizeGeneric_Invoker >,struct cv::VResizeLinear,struct cv::VResizeLinearVec_32f> >::resizeGeneric_Invoker + [0x83e1e0] cv::resizeGeneric_Invoker >,struct cv::VResizeLinear,struct cv::VResizeLinearVec_32f16s> >::resizeGeneric_Invoker + [0x83e310] cv::resizeGeneric_Invoker >,struct cv::VResizeLinear,struct cv::VResizeLinearVec_32f16u> >::resizeGeneric_Invoker + [0x83e460] cv::resizeGeneric_Invoker,struct cv::VResizeLinear,struct cv::VResizeLinearVec_32s8u> >::resizeGeneric_Invoker + [0x83e570] cv::ResizeAreaFastVec::operator () + [0x83e5c0] cv::ResizeAreaFastVec::operator () + [0x83e620] cv::ResizeAreaFastVec::operator () + [0x83e8b8] threshold + [0x83e8f0] double __cdecl cv::threshold(const class cv::_InputArray &,const class cv::_OutputArray &,double,double,int) + [0x83e9e8] cv::threshold + [0x83e9f8] automatic_thresh != (CV_THRESH_OTSU | CV_THRESH_TRIANGLE) + [0x83ea60] void __cdecl cv::adaptiveThreshold(const class cv::_InputArray &,const class cv::_OutputArray &,double,int,int,int,double) + [0x83eae0] cv::adaptiveThreshold + [0x83eb20] Unknown/unsupported adaptive threshold method + [0x83eb50] Unknown/unsupported threshold type + [0x83eb78] cvThreshold + [0x83ed60] class cv::RotatedRect __cdecl cv::minAreaRect(const class cv::_InputArray &) + [0x83edb0] C:\__t\vcpkg\buildtrees\opencv4\src\4.6.0-9a95a1b699.clean\modules\imgproc\src\imgwarp.cpp + [0x83ef18] BORDER_WRAP + [0x83ef28] BORDER_TRANSPARENT + [0x83f2f8] cv::ocl_warpTransform_cols4 + [0x83f318] op_type == OCL_OP_AFFINE || op_type == OCL_OP_PERSPECTIVE + [0x83f354] Affine + [0x83f388] warp%s_%s_8u + [0x83f408] cv::ocl_warpTransform + [0x83f438] warpAffine + [0x83f448] warpPerspective + [0x83f560] void __cdecl cv::warpAffine(const class cv::_InputArray &,const class cv::_OutputArray &,const class cv::_InputArray &,class cv::Size_,int,int,const class cv::Scalar_ &) + [0x83f618] cv::warpAffine + [0x83f720] class cv::Matx __cdecl cv::getRotationMatrix2D_(class cv::Point_,double,double) + [0x83f788] cv::invertAffineTransform + [0x83f7d0] cv::getAffineTransform + [0x83f970] double __cdecl cv::pointPolygonTest(const class cv::_InputArray &,class cv::Point_,bool) + [0x83f9d0] cv::pointPolygonTest + [0x841ba0] pts && npts && ncontours >= 0 && 0 <= shift && shift <= XY_SHIFT + [0x841cd0] pts && npts && ncontours >= 0 && 0 <= thickness && thickness <= MAX_THICKNESS && 0 <= shift && shift <= XY_SHIFT + [0x8421a8] cv::pointSetBoundingRect + [0x8421c8] cv::maskBoundingRect + [0x842230] class cv::Rect_ __cdecl cv::boundingRect(const class cv::_InputArray &) + [0x8422a0] cvBoundingRect + [0x842370] C:\__t\vcpkg\buildtrees\opencv4\src\4.6.0-9a95a1b699.clean\modules\imgproc\src\contours.cpp + [0x8423e8] cvStartFindContours_Impl + [0x842410] [Start]FindContours supports only CV_8UC1 images when mode != CV_RETR_FLOODFILL otherwise supports CV_32SC1 images only + [0x8424b0] icvFetchContour + [0x8424e0] icvTraceContour + [0x8424f0] icvFetchContourEx + [0x842508] icvTraceContour_32s + [0x842520] icvFetchContourEx_32s + [0x842538] cvFindNextContour + [0x8425a0] cvEndFindContours + [0x8425b8] icvFindContoursInInterval + [0x842610] Contour header size must be >= sizeof(CvContour) + [0x842670] cvFindContours_Impl + [0x8426e0] void __cdecl cv::findContours(const class cv::_InputArray &,const class cv::_OutputArray &,const class cv::_OutputArray &,int,int,class cv::Point_) + [0x842780] cv::findContours + [0x8427a0] (_contours.kind() == _InputArray::STD_VECTOR_VECTOR || _contours.kind() == _InputArray::STD_VECTOR_MAT || _contours.kind() == _InputArray::STD_VECTOR_UMAT) + [0x842840] _contours.empty() || (_contours.channels() == 2 && _contours.depth() == CV_32S) + [0x8428d0] void __cdecl cv::findContours(const class cv::_InputArray &,const class cv::_OutputArray &,int,int,class cv::Point_) + [0x8439b0] src.depth() == DataType::depth && ((borderType & BORDER_ISOLATED) || !src.isSubmatrix()) + [0x8479c0] -D dcn=%d -D bidx=%d -D hrange=%d -D hscale=%ff + [0x847a00] -D hscale=%ff -D bidx=%d -D dcn=3 + [0x8510c0] columnBorderType != BORDER_WRAP + [0x851780] cv::preprocess2DKernel + [0x86307b] #ifdef BORDER_CONSTANT + [0x863092] #elif defined BORDER_REPLICATE + [0x863131] #elif defined BORDER_WRAP + [0x86322f] #elif defined(BORDER_REFLECT) || defined(BORDER_REFLECT_101) + [0x863424] #ifdef BORDER_REFLECT + [0x86349a] #elif defined(BORDER_REFLECT_101) + [0x8635c7] struct RectCoords + [0x8635f2] inline WT readSrcPixel(int2 pos, __global const uchar * srcptr, int src_step, const struct RectCoords srcCoords) + [0x863665] #ifdef BORDER_ISOLATED + [0x863a4e] const struct RectCoords srcCoords = { srcOffsetX, srcOffsetY, srcEndX, srcEndY }; + [0x86443f] #elif defined BORDER_REFLECT_101 + [0x8644f4] #elif defined (BORDER_REPLICATE) || defined(BORDER_REFLECT) + [0x8656be] __global int * lut, float scale, __constant float * ranges) + [0x8658c2] lut[x] = (int)convert_uchar_sat_rte(hist[0] * scale); + [0x865d9c] __constant int * lut, float scale, + [0x865fe1] mad24(hist_step, bin1, hist_offset + bin2 * (int)sizeof(float))) * scale); + [0x868734] const int clipLimit, const float lutScale) + [0x868b49] uint ires = (uint)convert_int_rte(lutScale * lutVal); + [0x8693bb] #define CV_DESCALE(x,n) (((x) + (1 << ((n)-1))) >> (n)) + [0x869469] #ifndef hscale + [0x869478] #define hscale 0 + [0x869ce1] h *= hscale; + [0x86a3cb] dst[0] = h*hscale; + [0x86ad55] dst[dst_index] = convert_uchar_sat_rte(h*hscale); + [0x86c4c4] int x = CV_DESCALE(mad24(r, coeffs[0], mad24(g, coeffs[1], b * coeffs[2])), xyz_shift); + [0x86c51c] int y = CV_DESCALE(mad24(r, coeffs[3], mad24(g, coeffs[4], b * coeffs[5])), xyz_shift); + [0x86c574] int z = CV_DESCALE(mad24(r, coeffs[6], mad24(g, coeffs[7], b * coeffs[8])), xyz_shift); + [0x86ca08] int b = CV_DESCALE(mad24(x, coeffs[0], mad24(y, coeffs[1], z * coeffs[2])), xyz_shift); + [0x86ca60] int g = CV_DESCALE(mad24(x, coeffs[3], mad24(y, coeffs[4], z * coeffs[5])), xyz_shift); + [0x86cab8] int r = CV_DESCALE(mad24(x, coeffs[6], mad24(y, coeffs[7], z * coeffs[8])), xyz_shift); + [0x86ccf1] #define GammaTabScale (float)GAMMA_TAB_SIZE + [0x86cedd] __constant int * coeffs, int Lscale, int Lshift) + [0x86d19a] int fX = LabCbrtTab_b[CV_DESCALE(mad24(R, C0, mad24(G, C1, B*C2)), lab_shift)]; + [0x86d1ea] int fY = LabCbrtTab_b[CV_DESCALE(mad24(R, C3, mad24(G, C4, B*C5)), lab_shift)]; + [0x86d23a] int fZ = LabCbrtTab_b[CV_DESCALE(mad24(R, C6, mad24(G, C7, B*C8)), lab_shift)]; + [0x86d28a] int L = CV_DESCALE( Lscale*fY + Lshift, lab_shift2 ); + [0x86d2c0] int a = CV_DESCALE( mad24(500, fX - fY, 128*(1 << lab_shift2)), lab_shift2 ); + [0x86d30e] int b = CV_DESCALE( mad24(200, fY - fZ, 128*(1 << lab_shift2)), lab_shift2 ); + [0x86d7eb] R = splineInterpolate(R * GammaTabScale, gammaTab, GAMMA_TAB_SIZE); + [0x86d82f] G = splineInterpolate(G * GammaTabScale, gammaTab, GAMMA_TAB_SIZE); + [0x86d873] B = splineInterpolate(B * GammaTabScale, gammaTab, GAMMA_TAB_SIZE); + [0x86de86] ro = splineInterpolate(ro * GammaTabScale, gammaTab, GAMMA_TAB_SIZE); + [0x86decc] go = splineInterpolate(go * GammaTabScale, gammaTab, GAMMA_TAB_SIZE); + [0x86df12] bo = splineInterpolate(bo * GammaTabScale, gammaTab, GAMMA_TAB_SIZE); + [0x86e94c] __constant float LabCbrtTabScale = LAB_CBRT_TAB_SIZE/1.5f; + [0x86ecea] R = splineInterpolate(R*GammaTabScale, gammaTab, GAMMA_TAB_SIZE); + [0x86ed2c] G = splineInterpolate(G*GammaTabScale, gammaTab, GAMMA_TAB_SIZE); + [0x86ed6e] B = splineInterpolate(B*GammaTabScale, gammaTab, GAMMA_TAB_SIZE); + [0x86ee6e] float L = splineInterpolate(Y*LabCbrtTabScale, LabCbrtTab, LAB_CBRT_TAB_SIZE); + [0x86f203] float scale = 1.0f / 255.0f; + [0x86f220] float R = src[0]*scale, G = src[1]*scale, B = src[2]*scale; + [0x870a9f] dst[0] = (DATA_TYPE)CV_DESCALE(mad24(src_pix.B_COMP, BY15, mad24(src_pix.G_COMP, GY15, mul24(src_pix.R_COMP, RY15))), gray_shift); + [0x871c7c] dst[dst_index] = (uchar)CV_DESCALE(mad24((t << 3) & 0xf8, BY15, mad24((t >> 3) & 0xfc, GY15, ((t >> 8) & 0xf8) * RY15)), gray_shift); + [0x871d08] dst[dst_index] = (uchar)CV_DESCALE(mad24((t << 3) & 0xf8, BY15, mad24((t >> 2) & 0xf8, GY15, ((t >> 7) & 0xf8) * RY15)), gray_shift); + [0x873301] const int Y = CV_DESCALE(mad24(b, coeffs[0], mad24(g, coeffs[1], mul24(r, coeffs[2]))), yuv_shift); + [0x873365] const int U = CV_DESCALE(mad24(b - Y, coeffs[3], delta), yuv_shift); + [0x8733aa] const int V = CV_DESCALE(mad24(r - Y, coeffs[4], delta), yuv_shift); + [0x8738d6] const int r = Y + CV_DESCALE(mul24(V - HALF_MAX_NUM, coeffs[3]), yuv_shift); + [0x873923] const int g = Y + CV_DESCALE(mad24(V - HALF_MAX_NUM, coeffs[2], mul24(U - HALF_MAX_NUM, coeffs[1])), yuv_shift); + [0x873994] const int b = Y + CV_DESCALE(mul24(U - HALF_MAX_NUM, coeffs[0]), yuv_shift); + [0x876bd3] int Y = CV_DESCALE(mad24(b, coeffs[2], mad24(g, coeffs[1], mul24(r, coeffs[0]))), yuv_shift); + [0x876c32] int Cr = CV_DESCALE(mad24(r - Y, coeffs[3], delta), yuv_shift); + [0x876c72] int Cb = CV_DESCALE(mad24(b - Y, coeffs[4], delta), yuv_shift); + [0x8771b2] int r = yp + CV_DESCALE(coeff[0] * (cr - HALF_MAX_NUM), yuv_shift); + [0x8771f6] int g = yp + CV_DESCALE(mad24(coeff[1], cr - HALF_MAX_NUM, coeff[2] * (cb - HALF_MAX_NUM)), yuv_shift); + [0x87725e] int b = yp + CV_DESCALE(coeff[3] * (cb - HALF_MAX_NUM), yuv_shift); + [0x8774ac] #elif defined(BORDER_REFLECT) || defined(BORDER_REFLECT101) + [0x8788bb] #elif defined BORDER_REFLECT + [0x878938] #elif defined BORDER_REFLECT_101 || defined BORDER_REFLECT101 + [0x878bbc] #define INIT_AND_READ_LOCAL_SOURCE(width, height, fill_const, kernel_border) \ + [0x878c0b] int srcX = x + srcOffsetX - (kernel_border); \ + [0x878c3a] int srcY = y + srcOffsetY - (kernel_border); \ + [0x878d0c] if(lix < ((kernel_border)*2)) \ + [0x878db0] if(liy< ((kernel_border)*2)) \ + [0x878e55] if(lix<((kernel_border)*2) && liy<((kernel_border)*2)) \ + [0x879031] int height, int width, float scale) + [0x879270] DSTX(x,y) = mad(10.0f, m3 - m1, 3.0f * (u3 - u1 + b3 - b1)) * scale; + [0x8792b5] DSTY(x,y) = mad(10.0f, b2 - u2, 3.0f * (b1 - u1 + b3 - u3)) * scale; + [0x879300] DSTX(x,y) = mad(2.0f, m3 - m1, u3 - u1 + b3 - b1) * scale; + [0x87933b] DSTY(x,y) = mad(2.0f, b2 - u2, b1 - u1 + b3 - u3) * scale; + [0x879890] DSTX(x,y) = scale * + [0x87993f] DSTY(x,y) = scale * + [0x87b860] #ifdef BORDER_REPLICATE + [0x87bb00] #ifdef BORDER_REFLECT_101 + [0x87bc6f] #ifdef BORDER_WRAP + [0x87c251] #elif defined(BORDER_REFLECT_101) || defined(BORDER_REFLECT101) + [0x87c770] inline bool isBorder(const struct RectCoords bounds, int2 coord, int numPixels) + [0x87c8f5] inline WT getBorderPixel(const struct RectCoords bounds, int2 coord, + [0x87cb10] int srcstep, const struct RectCoords srcCoords) + [0x87cb42] if (!isBorder(srcCoords, pos, 1)) + [0x87cbdf] return getBorderPixel(srcCoords, pos, srcptr, srcstep); + [0x87d5e3] if (!isBorder(srcCoords, srcPos, PX_LOAD_NUM_PX)) + [0x885d52] #if defined BORDER_CONSTANT || defined BORDER_REPLICATE + [0x885fdf] #elif BORDER_REFLECT + [0x886248] #elif BORDER_REFLECT_101 + [0x887375] __constant float * threshold, int max_corners) + [0x8874ed] if (val > threshold[0]) + [0x887f55] __kernel void merge_histogram(__global const int * ghist, __global uchar * histptr, int hist_step, int hist_offset) + [0x88826e] __local float scale; + [0x888466] scale = 1; + [0x8884a9] scale = 255.f / (total - sumhist[i]); + [0x888575] dst[i]= convert_uchar_sat_rte(convert_float(sumhist[i]) * scale); + [0x888a7d] int total_points, float irho, float theta, int numrho, int numangle) + [0x888c68] if (theta_idx < numangle) + [0x888ee8] if (theta_idx > 0 && theta_idx < numangle + 1) + [0x889217] else if (theta_idx < numangle + 2) + [0x8893cc] int linesMax, int threshold, float rho, float theta) + [0x8895a1] if (curVote > threshold && curVote > ACCUM(accum - sizeof(int)) && curVote >= ACCUM(accum + sizeof(int)) && + [0x8896cd] float angle = y * theta; + [0x8896e6] lines[index] = (float2)(radius, angle); + [0x889891] int linesMax, int threshold, int lineLength, int lineGap, float rho, float theta) + [0x889a30] if (curVote >= threshold && + [0x889bfc] const float angle = y * theta; + [0x889c27] float sina = sincos(angle, &cosa); + [0x88cab6] coeffT scale, coeffT delta) + [0x88ccfe] dst[0] = convertToDT( mad24((WT)(scale), convertToWT(src1[0]) + convertToWT(src2[0]), (WT)(delta)) ); + [0x88cd6a] dst[0] = convertToDT( mad((WT)(scale), convertToWT(src1[0]) + convertToWT(src2[0]), (WT)(delta)) ); + [0x88d3f5] WT1 scale, WT1 delta) + [0x88d693] WT scale_v = (WT)scale; + [0x88d941] WT sum = mad(scale_v, (sum1 + sum2), delta_v); + [0x88dca2] __kernel void computeAngleRadius(__global float2* cp_sp, __global float* r, float maxRadius_width, float PI2_height, unsigned width, unsigned height) + [0x88dd71] float angle = gid * PI2_height; + [0x88dd91] float2 angle_tri=(float2)(cos(angle), sin(angle)); + [0x88ddc4] cp_sp[gid] = angle_tri; + [0x88e13e] __kernel void linearPolar(__global float* mx, __global float* my, float ascale, float pscale, float cx, float cy, int angle_border, unsigned width, unsigned height) + [0x88e2b6] float angle = atan2(dy, dx); + [0x88e2d3] if (angle < 0) + [0x88e2e2] angle = angle + CV_2PI; + [0x88e2fa] mx[g_id] = mag*pscale; + [0x88e311] my[g_id] = (angle*ascale) + angle_border; + [0x88e3c2] __kernel void computeAngleRadius(__global float2* cp_sp, __global float* r, float m, float PI2_height, unsigned width, unsigned height) + [0x88e4a1] float2 angle_tri = (float2)(cos(angle), sin(angle)); + [0x88e848] __kernel void logPolar(__global float* mx, __global float* my, float ascale, float m, float cx, float cy, int angle_border, unsigned width, unsigned height) + [0x898eb0] precornerdetect + [0x898ec0] __kernel void preCornerDetect(__global const uchar * Dxptr, int dx_step, int dx_offset, + [0x8994fb] #if defined BORDER_REPLICATE + [0x89e834] #ifndef BORDER_CONSTANT + [0x8a086e] #if defined BORDER_CONSTANT + [0x8a1c44] resize + [0x8a2067] #define RESULT_SCALE 255.0f + [0x8a2097] #define RESULT_SCALE 127.0f + [0x8a20c7] #define RESULT_SCALE 65535.0f + [0x8a20f9] #define RESULT_SCALE 32767.0f + [0x8a2120] #define RESULT_SCALE 1.0f + [0x8a2144] __kernel void resizeSampler(__read_only image2d_t srcImage, + [0x8a231a] T uval = convertToDT(round(intermediate * RESULT_SCALE)); + [0x8a235a] T uval = convertToDT(intermediate * RESULT_SCALE); + [0x8a2421] __kernel void resizeLN(__global const uchar * srcptr, int src_step, int src_offset, int src_rows, int src_cols, + [0x8a2bd9] #define INTER_RESIZE_COEF_SCALE (1 << INTER_RESIZE_COEF_BITS) + [0x8a2c17] #define CAST_BITS (INTER_RESIZE_COEF_BITS << 1) + [0x8a2c47] u = u * INTER_RESIZE_COEF_SCALE; + [0x8a2c68] v = v * INTER_RESIZE_COEF_SCALE; + [0x8a2cab] int U1 = rint(INTER_RESIZE_COEF_SCALE - u); + [0x8a2cd7] int V1 = rint(INTER_RESIZE_COEF_SCALE - v); + [0x8a31ae] __kernel void resizeNN(__global const uchar * srcptr, int src_step, int src_offset, int src_rows, int src_cols, + [0x8a3430] __kernel void resizeAREA_FAST(__global const uchar * src, int src_step, int src_offset, int src_rows, int src_cols, + [0x8a3583] int sx = XSCALE * dx; + [0x8a3599] int sy = YSCALE * dy; + [0x8a35d2] for (int py = 0; py < YSCALE; ++py) + [0x8a365b] for (int px = 0; px < XSCALE; ++px) + [0x8a36e2] storepix(convertToT(convertToWT2V(sum) * (WT2V)(SCALE)), dst + mad24(dx, TSIZE, dst_index)); + [0x8a3749] __kernel void resizeAREA(__global const uchar * src, int src_step, int src_offset, int src_rows, int src_cols, + [0x8a515b] __kernel void threshold(__global const uchar * srcptr, int src_step, int src_offset, + [0x8a55a8] warp_affine + [0x8a56a9] #define INTER_SCALE 1.f/INTER_TAB_SIZE + [0x8a56f9] #define AB_SCALE (1 << AB_BITS) + [0x8a573a] #define INTER_REMAP_COEF_SCALE (1 << INTER_REMAP_COEF_BITS) + [0x8a59d9] __kernel void warpAffine(__global const uchar * srcptr, int src_step, int src_offset, int src_rows, int src_cols, + [0x8a5b17] int round_delta = (AB_SCALE >> 1); + [0x8a5b3a] int X0_ = rint(M[0] * dx * AB_SCALE); + [0x8a5b60] int Y0_ = rint(M[3] * dx * AB_SCALE); + [0x8a5c2e] int X0 = X0_ + rint(fma(M[1], (CT)dy, M[2]) * AB_SCALE) + round_delta; + [0x8a5c75] int Y0 = Y0_ + rint(fma(M[4], (CT)dy, M[5]) * AB_SCALE) + round_delta; + [0x8a62dc] int X0 = X0_ + rint(fma(M[1], (CT)dy, M[2]) * AB_SCALE) + ROUND_DELTA; + [0x8a6323] int Y0 = Y0_ + rint(fma(M[4], (CT)dy, M[5]) * AB_SCALE) + ROUND_DELTA; + [0x8a6795] int itab0 = convert_short_sat_rte( (1.0f-taby)*(1.0f-tabx) * INTER_REMAP_COEF_SCALE ); + [0x8a67ec] int itab1 = convert_short_sat_rte( (1.0f-taby)*tabx * INTER_REMAP_COEF_SCALE ); + [0x8a683c] int itab2 = convert_short_sat_rte( taby*(1.0f-tabx) * INTER_REMAP_COEF_SCALE ); + [0x8a688c] int itab3 = convert_short_sat_rte( taby*tabx * INTER_REMAP_COEF_SCALE ); + [0x8a7755] int X0 = rint(M[0] * tmp) + rint(fma(M[1], (CT)dy, M[2]) * AB_SCALE) + ROUND_DELTA; + [0x8a77a9] int Y0 = rint(M[3] * tmp) + rint(fma(M[4], (CT)dy, M[5]) * AB_SCALE) + ROUND_DELTA; + [0x8a7a7f] float ayy = INTER_SCALE * ay; + [0x8a7a9d] float axx = INTER_SCALE * ax; + [0x8a7b97] itab[i] = rint(tab1y[(i>>2)] * tab1x[(i&3)] * INTER_REMAP_COEF_SCALE); + [0x8a81b0] warp_perspective + [0x8a82b9] #define INTER_SCALE 1.f / INTER_TAB_SIZE + [0x8a85b5] __kernel void warpPerspective(__global const uchar * srcptr, int src_step, int src_offset, int src_rows, int src_cols, + [0x8a99e8] warp_transform + [0x8a9ab4] __kernel void warpAffine_nearest_8u(__global const uchar * src, int src_step, int src_offset, int src_rows, int src_cols, + [0x8aa094] __kernel void warpAffine_linear_8u(__global const uchar * src, int src_step, int src_offset, int src_rows, int src_cols, + [0x8aaeb6] __kernel void warpAffine_cubic_8u(__global const uchar * src, int src_step, int src_offset, int src_rows, int src_cols, + [0x8ab87e] __kernel void warpPerspective_nearest_8u(__global const uchar * src, int src_step, int src_offset, int src_rows, int src_cols, + [0x8abcec] __kernel void warpPerspective_linear_8u(__global const uchar * src, int src_step, int src_offset, int src_rows, int src_cols, + [0x8ac45a] __kernel void warpPerspective_cubic_8u(__global const uchar * src, int src_step, int src_offset, int src_rows, int src_cols, + [0x8ade18] -D BORDER_ISOLATED + [0x8b0a50] LYOEOFNFNEODQCTCVDWFVHTIQJOKNMNP TCUDVFUHTI NOONPNSOVOWN PNSPVPWNWM MRXR OVOWNWNVOUQTTTVUWWVYTZ TTUUVWUYTZ RZTZV[W]W^V`TaQaO`N_N^O^O_ TZU[V]V^U`Ta + [0x8b0af0] LYOEOFNFNEODQCTCVDWFVHTI TCUDVFUHTI RITIVJWLWMVOTPQPOONNNMOMON TIUJVLVMUOTP MRXR QTOUNWOYQZTZVYWWVUTTQT QTPUOWPYQZ TZUYVWUUTT QZO[N]N^O`QaTaV`W^W]V[TZ QZP[O]O^P`Qa TaU`V^V]U[TZ + [0x8b0db0] LYOEOFNFNEODQCTCVDWFVHTI TCUDVFUHTI RITIVJWLWMVOTPQPOONNNMOMON TIUJVLVMUOTP MRXR SVSa TTTa TTM]X] QaVa + [0x8b3ba0] AcPALBJCGEEGCJBLAPATBXCZE]G_JaLbPcTcXbZa]__]aZbXcTcPbLaJ_G]EZCXBTAPA + [0x8bdfe0] F^KFK[ LFL[ XFX[ YFY[ HFOF UF\F XHLY H[O[ U[\[ N@N?M?M@NBPCTCVBW@ + [0x8c0960] LXQFQHSHSFQF RFRH QGSG QMQ[ RNRZ NMSMS[ N[V[ OMQN PMQO QZO[ QYP[ SYT[ SZU[ + [0x8c0e40] I[LMR[ MMRY NMSY XNSYR[ JMQM TMZM KMNO PMNN VMXN YMXN + [0x8c0f30] H[LMR[ MMRY NMSY XNSYP_NaLbJbIaI_K_KaJaJ` JMQM TMZM KMNO PMNN VMXN YMXN + [0x8c1d90] F^GQHOJMLMMNNPNSL[ MNMSK[ MPLTJ[L[ NSPPRNTMVMXNYPYSWX XNXRWVWZ XPVUVXWZX[Z[\Y]W + [0x8c22f0] H\QFNGLJKOKRLWNZQ[S[VZXWYRYOXJVGSFQF NHMJLNLSMWNY VYWWXSXNWJVH QFOGNIMNMSNXOZQ[ S[UZVXWSWNVIUGSF LPXQ LQXP + [0x8c2430] H\QFNGLJKOKRLWNZQ[S[VZXWYRYOXJVGSFQF NHMJLNLSMWNY VYWWXSXNWJVH QFOGNIMNMSNXOZQ[ S[UZVXWSWNVIUGSF + [0x8c3668] arr != 0 && contour_header != 0 && block != 0 + [0x8c3828] CV_IS_SEQ_CHAIN_CONTOUR( chain ) + [0x8c3850] header_size >= (int)sizeof(CvContour) + [0x8db580] cv::Mat::resize + [0x8e0448] cv::borderInterpolate + [0x8e0460] Unknown/unsupported border type + [0x8e04c0] copyMakeBorder + [0x8e04f0] void __cdecl cv::copyMakeBorder(const class cv::_InputArray &,const class cv::_OutputArray &,int,int,int,int,int,const class cv::Scalar_ &) + [0x8e0588] cv::copyMakeBorder + [0x8e0880] void __cdecl cv::hal::cpu_baseline::merge8u(const unsigned char **,unsigned char *,int,int) + [0x8e08e0] C:\__t\vcpkg\buildtrees\opencv4\src\4.6.0-9a95a1b699.clean\modules\core\src\merge.simd.hpp + [0x8e0960] void __cdecl cv::hal::cpu_baseline::merge16u(const unsigned short **,unsigned short *,int,int) + [0x8e09e0] void __cdecl cv::hal::cpu_baseline::merge32s(const int **,int *,int,int) + [0x8e0a50] void __cdecl cv::hal::cpu_baseline::merge64s(const __int64 **,__int64 *,int,int) + [0x8e0ad0] void __cdecl cv::hal::merge8u(const unsigned char **,unsigned char *,int,int) + [0x8e0b20] C:\__t\vcpkg\buildtrees\opencv4\src\4.6.0-9a95a1b699.clean\modules\core\src\merge.dispatch.cpp + [0x8e0ba0] void __cdecl cv::hal::merge16u(const unsigned short **,unsigned short *,int,int) + [0x8e0c18] void __cdecl cv::hal::merge32s(const int **,int *,int,int) + [0x8e0c80] void __cdecl cv::hal::merge64s(const __int64 **,__int64 *,int,int) + [0x8e0cf0] void __cdecl cv::merge(const class cv::Mat *,unsigned __int64,const class cv::_OutputArray &) + [0x8e0d50] cv::merge + [0x8e0dc8] cv::ocl_merge + [0x8e0e60] -D OP_MERGE -D cn=%d -D T=%s -D DECLARE_SRC_PARAMS_N=%s -D DECLARE_INDEX_N=%s -D PROCESS_ELEMS_N=%s%s + [0x8e0ef0] void __cdecl cv::merge(const class cv::_InputArray &,const class cv::_OutputArray &) + [0x8e0f48] cv::hal::cpu_baseline::vecmerge_ + [0x8e5a68] OP_MUL_SCALE + [0x8e5a78] OP_DIV_SCALE + [0x8e5a88] OP_RECIP_SCALE + [0x8e5ad0] OP_RDIV_SCALE + [0x8e61e0] -D %s%s -D %s -D srcT1=%s -D srcT1_C1=%s -D srcT2=%s -D srcT2_C1=%s -D dstT=%s -D DEPTH_dst=%d -D dstT_C1=%s -D workT=%s -D workST=%s -D scaleT=%s -D wdepth=%d -D convertToWT1=%s -D convertToWT2=%s -D convertToDT=%s%s -D cn=%d -D rowsPerWI=%d -D convertFromU=%s + [0x8e7150] void __cdecl cv::extractChannel(const class cv::_InputArray &,const class cv::_OutputArray &,int) + [0x8e71b8] cv::extractChannel + [0x8e8a36] To be built: calib3d core features2d flann freetype highgui imgcodecs imgproc ml objdetect photo stitching video videoio + [0x8e8ea3] DirectShow: YES + [0x8e9300] Incorrect size of input array + [0x8ea378] #description: OpenCV trace file + [0x8ea968] OPENCV_OPENCL_DISABLE_BUFFER_RECT_OPERATIONS + [0x8eacc0] Can't use OpenCL cache directory: + [0x8eae20] Initialized OpenCL cache directory, but interprocess synchronization lock is not available. Consider to disable OpenCL cache: OPENCV_OPENCL_CACHE_DIR=disabled + [0x8eaec0] Successfully initialized OpenCL cache directory: + [0x8eaf30] cv::ocl::OpenCLBinaryCacheConfigurator::prepareCacheDirectoryForContext + [0x8eaf78] Can't create directory: + [0x8eaf98] Can't create OpenCL program cache directory for context: + [0x8eafe0] We assume that these directories are obsolete after OpenCL runtime/drivers upgrade. + [0x8eb040] Detected OpenCL cache directory for other version of OpenCL device. + [0x8eb090] Detected OpenCL cache directories for other versions of OpenCL device. + [0x8eb0d8] Trying to remove these directories... + [0x8eb178] Exception during removal of obsolete OpenCL cache directory: + [0x8eb1b8] Can't check for obsolete OpenCL cache directories + [0x8eb388] sourceSignatureSize_ > 0 + [0x8eb498] fileSourceSignatureSize > 0 + [0x8eb530] fileSourceSignatureSize == sourceSignatureSize_ + [0x8ee070] clEnqueueReadBufferRect(q, (cl_mem)u->handle, CL_TRUE, new_srcofs, new_dstofs, new_sz, new_srcstep[0], 0, new_dststep[0], 0, ptr, 0, 0, 0) + [0x8ee2b0] clEnqueueWriteBufferRect(q, (cl_mem)u->handle, CL_TRUE, new_dstofs, new_srcofs, new_sz, new_dststep[0], 0, new_srcstep[0], 0, ptr, 0, 0, 0) + [0x8ee510] retval = clEnqueueCopyBufferRect(q, (cl_mem)src->handle, (cl_mem)dst->handle, new_srcofs, new_dstofs, new_sz, new_srcstep[0], 0, new_dststep[0], 0, 0, 0, 0) + [0x8eeb98] CL_INVALID_IMAGE_FORMAT_DESCRIPTOR + [0x8eee60] CL_INVALID_IMAGE_DESCRIPTOR + [0x8ef368] Incorrect UMat, handle is null + [0x8ef3f0] clEnqueueCopyBufferRect(queue, (cl_mem)src.handle(ACCESS_READ), devData, origin, origin, roi, src.step, 0, src.cols * src.elemSize(), 0, 0, NULL, NULL) + [0x8efb10] -D NO_SCALE + [0x8f22f0] cv::cpu_baseline::getScaleAddFunc + [0x8f2bd0] -D OP_SCALE_ADD -D BINARY_OP -D dstT=%s -D DEPTH_dst=%d -D workT=%s -D convertToWT1=%s -D srcT1=dstT -D srcT2=dstT -D convertToDT=%s -D workT1=%s -D wdepth=%d%s -D rowsPerWI=%d + [0x8f2cb0] void (__cdecl *__cdecl cv::getScaleAddFunc(int))(const unsigned char *,const unsigned char *,unsigned char *,int,const void *) + [0x8f2d50] void __cdecl cv::scaleAdd(const class cv::_InputArray &,double,const class cv::_InputArray &,const class cv::_OutputArray &) + [0x8f2dd0] cv::scaleAdd + [0x8f30b0] Unrecognized or unsupported array type + [0x8f663f] #elif defined OP_MUL_SCALE + [0x8f667e] #define EXTRA_PARAMS , workST srcelem2_, scaleT scale + [0x8f66e5] #define EXTRA_PARAMS , scaleT scale + [0x8f6710] #define PROCESS_ELEM storedst(convertToDT(srcelem1 * scale * srcelem2)) + [0x8f6865] #elif defined OP_DIV_SCALE + [0x8f6995] storedst(convertToDT(e2 == zero ? zero : (srcelem1 * (workT)(scale) / e2))) + [0x8f6a15] storedst(convertToDT(srcelem1 * (workT)(scale) / e2)) + [0x8f6a52] #elif defined OP_RDIV_SCALE + [0x8f6b83] storedst(convertToDT(e1 == zero ? zero : (srcelem2 * (workT)(scale) / e1))) + [0x8f6c03] storedst(convertToDT(srcelem2 * (workT)(scale) / e1)) + [0x8f6c40] #elif defined OP_RECIP_SCALE + [0x8f6cf4] storedst(convertToDT(e1 != zero ? scale / e1 : zero)) + [0x8f6d5e] storedst(convertToDT(scale / e1)) + [0x8f6db1] #define EXTRA_PARAMS , scaleT alpha, scaleT beta, scaleT gamma + [0x8f7324] #elif defined OP_CONVERT_SCALE_ABS + [0x8f749a] #elif defined OP_SCALE_ADD + [0x8f7fd6] #if !(defined(OP_RECIP_SCALE) || defined(OP_NOT)) + [0x8f8c25] #ifndef NO_SCALE + [0x8f8e4a] #ifdef NO_SCALE + [0x8f8ef8] copymakeborder + [0x8f9432] __kernel void copyMakeBorder(__global const uchar * srcptr, int src_step, int src_offset, int src_rows, int src_cols, + [0x8fa49a] static const __constant float CV_8U_SCALE = 1.0f / 255.0f; + [0x8fae5a] float4 src_pix1 = convert_float4(vload4(0, pSrcRow1 + 0*NCHANNELS)) * CV_8U_SCALE; + [0x8faead] float4 src_pix2 = convert_float4(vload4(0, pSrcRow1 + 1*NCHANNELS)) * CV_8U_SCALE; + [0x8faf00] float4 src_pix3 = convert_float4(vload4(0, pSrcRow2 + 0*NCHANNELS)) * CV_8U_SCALE; + [0x8faf53] float4 src_pix4 = convert_float4(vload4(0, pSrcRow2 + 1*NCHANNELS)) * CV_8U_SCALE; + [0x8fe39a] #ifdef DFT_SCALE + [0x8fe3ab] #define SCALE_VAL(x, scale) x*scale + [0x8fe3d5] #define SCALE_VAL(x, scale) x + [0x8fe630] FT scale = (FT) 1/dst_cols; + [0x8fe652] FT scale = (FT) 1/(dst_cols*dst_rows); + [0x8fe962] dst[i] = SCALE_VAL(smem[i], scale); + [0x8fe9ef] dst[dst_cols-i] = (CT)(SCALE_VAL(smem[i].x, scale), SCALE_VAL(-smem[i].y, scale)); + [0x8feb02] dst[i+1] = SCALE_VAL(smem_1cn[i+2], scale); + [0x8feb3a] dst[0] = SCALE_VAL(smem_1cn[0], scale); + [0x8fef05] FT scale = 1.f/(dst_rows*dst_cols); + [0x8ff06c] *((__global CT*)(dst + i*block_size*dst_step)) = SCALE_VAL(smem[y + i*block_size], scale); + [0x8ff18d] *((__global FT*) dst) = SCALE_VAL(smem_1cn[i+2], scale); + [0x8ff1d2] *((__global FT*) (dst_ptr + dst_offset)) = SCALE_VAL(smem_1cn[0], scale); + [0x8ff359] *((__global FT*) (dst_ptr + mad24(dst_cols-1, (int)sizeof(FT), dst_offset))) = SCALE_VAL(smem_1cn[0], scale); + [0x8ff491] vstore2(SCALE_VAL(smem[i], scale), 0, (__global FT*) dst); + [0x8ff67e] const FT scale = (FT) 1/dst_cols; + [0x8ff6a6] const FT scale = (FT) 1/(dst_cols*dst_rows); + [0x8ffd5e] dst[i*block_size].x = SCALE_VAL(smem[x + i*block_size].x, scale); + [0x8ffda0] dst[i*block_size].y = SCALE_VAL(-smem[x + i*block_size].y, scale); + [0x8ffe82] dst[i*block_size] = SCALE_VAL(smem[x + i*block_size].x, scale); + [0x904830] int border = -(group_y * LWG_HEIGHT * TILE_M + local_y * TILE_M); + [0x904872] int row0 = mad24(global_y, TILE_M, 0) < M ? 0 : border; + [0x9048aa] int row1 = mad24(global_y, TILE_M, 1) < M ? 1 : border; + [0x9048e2] int row2 = mad24(global_y, TILE_M, 2) < M ? 2 : border; + [0x90491a] int row3 = mad24(global_y, TILE_M, 3) < M ? 3 : border; + [0x904952] int row4 = mad24(global_y, TILE_M, 4) < M ? 4 : border; + [0x90498a] int row5 = mad24(global_y, TILE_M, 5) < M ? 5 : border; + [0x9049c2] int row6 = mad24(global_y, TILE_M, 6) < M ? 6 : border; + [0x9049fa] int row7 = mad24(global_y, TILE_M, 7) < M ? 7 : border; + [0x910cf2] __kernel void mulAndScaleSpectrums(__global const uchar * src1ptr, int src1_step, int src1_offset, + [0x911488] #ifdef HAVE_SCALE + [0x91149a] , float scale + [0x9116f2] value = fma(value, (workT)(scale), (workT)(delta)); + [0x91172c] value *= (workT)(scale); + [0x915d70] , float fscale + [0x9162cc] dst[c] = convertToDT(convertToWT(tmp[c]) * fscale); + [0x91667d] dst[c] = convertToDT0(convertToWT(tmp[c]) * fscale); + [0x91739c] #error "Incorrect combination of cn && kercn" + [0x917400] split_merge + [0x917410] #ifdef OP_MERGE + [0x9175ec] __kernel void merge(DECLARE_SRC_PARAMS_N + [0x918580] C:\__t\vcpkg\buildtrees\opencv4\src\4.6.0-9a95a1b699.clean\modules\core\src\convert_scale.dispatch.cpp + [0x918610] void (__cdecl *__cdecl cv::getConvertScaleFunc(int,int))(const unsigned char *,unsigned __int64,const unsigned char *,unsigned __int64,unsigned char *,unsigned __int64,class cv::Size_,void *) + [0x91c890] void __cdecl cv::hal::opt_AVX2::merge8u(const unsigned char **,unsigned char *,int,int) + [0x91c8f0] C:/__t/vcpkg/buildtrees/opencv4/src/4.6.0-9a95a1b699.clean/modules/core/src/merge.simd.hpp + [0x91c970] void __cdecl cv::hal::opt_AVX2::merge16u(const unsigned short **,unsigned short *,int,int) + [0x91c9f0] void __cdecl cv::hal::opt_AVX2::merge32s(const int **,int *,int,int) + [0x91ca60] void __cdecl cv::hal::opt_AVX2::merge64s(const __int64 **,__int64 *,int,int) + [0x91cab0] cv::hal::opt_AVX2::vecmerge_ + [0x924c38] Can't remove directory: + [0x924cb0] bool __cdecl cv::utils::fs::createDirectory(const class std::basic_string,class std::allocator > &) + [0x924ea0] Creating new OpenCV cache directory: + [0x924ec8] cv::utils::fs::getCacheDirectory + [0x924ef0] There are several neighbour directories, probably created by old OpenCV versions. + [0x924f48] Feel free to cleanup these unused directories: + [0x924fa8] Can't find default cache directory (does it exist?): + [0x924fe0] Specified non-existed directory, creating OpenCV sub-directory for caching purposes: + [0x925038] Can't create OpenCV cache sub-directory: + [0x925068] cache_path.empty() || utils::fs::isDirectory(cache_path) + [0x925220] bool __cdecl cv::utils::fs::isDirectory(const class std::basic_string,class std::allocator > &) + [0x925318] could not open directory: %s + [0x925998] clEnqueueWriteBufferRect + [0x925db0] clEnqueueReadBufferRect + [0x925f60] clEnqueueCopyBufferRect + [0x9273f0] cv::opt_SSE4_1::getScaleAddFunc + [0x927870] cv::opt_AVX2::getScaleAddFunc + [0x927d18] cv::opt_AVX512_SKX::getScaleAddFunc + [0x9300e0] Invalid component ID %d in SOS + [0x9302a0] Invalid progressive parameters at scan script entry %d + [0x9302f0] Invalid scan script at entry %d + [0x930428] Too many color components: %d, max %d + [0x9306c0] Scan script does not transmit all data + [0x930858] Cannot quantize more than %d color components + [0x930fa0] Start Of Frame 0x%02x: width=%u, height=%u, components=%d + [0x930fe0] Component %d: %dhx%dv q=%d + [0x931010] Start Of Scan: %d components + [0x931030] Component %d: dc=%d ac=%d + [0x931170] Unrecognized component IDs %d %d %d, assuming YCbCr + [0x931200] Inconsistent progression sequence for component %d coefficient %d + [0x931288] Corrupt JPEG data: premature end of data segment + [0x9313d0] Invalid crop request + [0x931460] Component index %d: mismatching sampling ratio %d:%d, %d:%d, %c + [0x96f308] RGB color space not permitted on grayscale PNG + [0x96f400] unrecognized ICC profile class + [0x96f490] known incorrect sRGB profile + [0x96f4e0] Not recognizing known sRGB profile that has been edited + [0x970470] ignored in grayscale PNG + [0x970618] incorrect byte-order specifier + [0x970650] unrecognized equation type + [0x970a88] Invalid bit depth for grayscale image + [0x970af8] Invalid bit depth for grayscale+alpha image + [0x970c10] Ignoring request to write a PLTE chunk in grayscale PNG + [0x970fd8] Unrecognized unit type for oFFs chunk + [0x971000] Unrecognized equation type for pCAL chunk + [0x971070] Unrecognized unit type for pHYs chunk + [0x9710e0] TIFFAdvanceDirectory + [0x9710f8] TIFFNumberOfDirectories + [0x971110] TIFFUnlinkDirectory + [0x971648] Error fetching directory count + [0x971668] Error fetching directory link + [0x971688] Error writing directory link + [0x9716a8] TIFFReadDirectory + [0x9716c0] TIFFReadDirectoryCheckOrder + [0x9716e0] TIFFReadCustomDirectory + [0x971720] TIFFFetchDirectory + [0x971840] Incorrect count for "%s" + [0x9718a0] Incorrect value for "%s" + [0x971948] Incorrect count for "%s"; tag ignored + [0x9719c8] Incorrect value for "%s"; tag ignored + [0x971a98] Failed to read directory at offset %llu + [0x971b40] Planarconfig tag value assumed incorrect, assuming data is contig instead of chunky + [0x971c70] Photometric tag value assumed incorrect, assuming data is YCbCr instead of RGB + [0x971d00] SamplesPerPixel tag is missing, assuming correct SamplesPerPixel value is 3 + [0x971d50] SamplesPerPixel tag is missing, applying correct SamplesPerPixel value of 3 + [0x971f00] TIFF directory is missing required "StripByteCounts" field, calculating from imagelength + [0x972068] Invalid TIFF directory; tags are not sorted in ascending order + [0x9720f8] TIFF directory is missing required "%s" field + [0x972128] Cannot handle more than 65535 TIFF directories + [0x972180] %s: Seek error accessing TIFF directory + [0x9721a8] %s: Can not read TIFF directory count + [0x9721d0] Sanity check on directory count failed, this is probably not a valid IFD offset + [0x972220] to read TIFF directory + [0x972238] %.100s: Can not read TIFF directory + [0x972260] Can not read TIFF directory count + [0x972290] Sanity check on directory count failed, zero tag directories not supported + [0x9722e0] Can not read TIFF directory + [0x972340] ASCII value for tag "%s" contains null byte in value; value incorrectly truncated during reading due to implementation limitations + [0x972400] incorrect count for field "%s", expected 2, got %llu + [0x972438] incorrect count for field "%s", expected %d, got %llu + [0x9724c0] LIBTIFF_STRILE_ARRAY_MAX_RESIZE_COUNT + [0x9729a8] TIFFRewriteDirectory + [0x9729c0] TIFFWriteDirectorySec + [0x9729d8] TIFFWriteDirectoryTagSampleformatArray + [0x972a00] TIFFWriteDirectoryTagShortPerSample + [0x972a28] TIFFWriteDirectoryTagLongLong8Array + [0x972a50] TIFFWriteDirectoryTagIfdIfd8Array + [0x972a78] TIFFWriteDirectoryTagColormap + [0x972a98] TIFFWriteDirectoryTagTransferfunction + [0x972ac0] TIFFWriteDirectoryTagSubifd + [0x972ae0] TIFFWriteDirectoryTagCheckedRational + [0x972b08] TIFFWriteDirectoryTagCheckedRationalArray + [0x972b38] TIFFWriteDirectoryTagCheckedSrationalArray + [0x972b68] TIFFWriteDirectoryTagCheckedRationalDoubleArray + [0x972b98] TIFFWriteDirectoryTagCheckedSrationalDoubleArray + [0x972bd0] TIFFWriteDirectoryTagData + [0x972bf0] TIFFLinkDirectory + [0x972cd0] Error post-encoding before directory write + [0x972d00] Error flushing data before directory write + [0x972db8] TIFFLib: _TIFFWriteDirectorySec() + [0x972e18] IO error writing directory + [0x972f50] TIFFWriteDirectoryTagCheckedLong8Array + [0x972fa0] TIFFWriteDirectoryTagCheckedSlong8Array + [0x9731a8] Error writing SubIFD directory link + [0x973210] Attempt to reset field on directory not already on disk. + [0x973250] %s: Can not read TIFF directory entry. + [0x973330] %s: Can not write TIFF directory entry. + [0x973bf8] Invalid vertical YCbCr subsampling + [0x9744a8] _TIFFMergeFields + [0x9776e8] TIFFMergeFieldInfo + [0x9777c8] ImageDescription + [0x977d18] UniqueCameraModel + [0x977d30] LocalizedCameraModel + [0x977de8] DefaultScale + [0x977df8] BestQualityScale + [0x977e10] DefaultCropOrigin + [0x977e28] DefaultCropSize + [0x977fa8] ShadowScale + [0x978144] Decode + [0x978310] ComponentsConfiguration + [0x9784a0] CameraElevationAngle + [0x978698] DeviceSettingDescription + [0x978730] LensModel + [0x978898] ImgDirectionRef + [0x9788a8] ImgDirection + [0x978998] HorizontalPositioningError + [0x978a78] Directory has not yet been written + [0x978aa0] Directory has changes other than the strile arrays. TIFFRewriteDirectory() should be called instead + [0x9791b8] JPEGPreDecode + [0x979300] Unable to allocate memory for auto-correcting of subsampling values; auto-correcting skipped + [0x979360] Unable to auto-correct subsampling values, likely corrupt JPEG compressed data in first strip/tile; auto-correcting skipped + [0x9793e0] Subsampling values inside JPEG compressed data have no TIFF equivalent, auto-correction of TIFF subsampling values failed + [0x979460] Auto-corrected former TIFF subsampling values [%hu,%hu] to match subsampling values inside JPEG compressed data [%hhu,%hhu] + [0x9794f8] JPEGSetupDecode + [0x9795f0] Improper JPEG component count + [0x979694] libtiff should be able to decode it, but it might cause compatibility issues with other readers + [0x979720] Reading this image would require libjpeg to allocate at least %llu bytes. This is disabled since above the %ld threshold. You may override this restriction by defining the LIBTIFF_ALLOW_LARGE_LIBJPEG_MEM_ALLOC environment variable, or setting the JPEGMEM environment variable to a value greater or equal to '%lluM' + [0x9799d0] JPEGDecodeRaw + [0x979a30] mozjpeg library likely detected. Disable emission of Huffman tables in JpegTables tag, and use optimize_coding to avoid potential issues + [0x979ac0] Invalig horizontal/vertical sampling value + [0x97a028] DumpModeDecode + [0x97a0b0] PackBitsDecode + [0x97a0f0] Terminating PackBitsDecode due to lack of data. + [0x97a660] Fax3Decode1D + [0x97a670] Fax3Decode2D + [0x97aa80] Fax4Decode + [0x97aaa0] Fax3DecodeRLE + [0x97ade8] %sEOL padding + [0x97ae38] uncorrected errors + [0x97af50] Buffer overrun detected : %lld bytes available, %d bits needed + [0x97b010] ThunderSetupDecode + [0x97b028] ThunderDecode + [0x97b038] ThunderDecodeRow + [0x97b050] Wrong bitspersample value (%d), Thunder decoder only supports 4bits per sample. + [0x97b0e8] NeXTDecode + [0x97b0f8] NeXTPreDecode + [0x97b148] LZWSetupDecode + [0x97b158] LZWPreDecode + [0x97b168] LZWDecode + [0x97b178] LZWDecodeCompat + [0x97b248] LZWDecode: Strip %u not terminated with EOI code + [0x97b2a0] LZWDecode: Corrupted LZW table at scanline %u + [0x97b300] Wrong length of decoded string: data probably corrupted at scanline %u + [0x97b4e0] OJPEGSetupDecode + [0x97b4f8] OJPEGPreDecodeSkipScanlines + [0x97b518] OJPEGDecode + [0x97b528] OJPEGDecodeRaw + [0x97b538] OJPEGDecodeScanlines + [0x97b598] OJPEGSubsamplingCorrect + [0x97b7f0] JpegQTables tag has incorrect count + [0x97b818] JpegDcTables tag has incorrect count + [0x97b840] JpegAcTables tag has incorrect count + [0x97b9b0] Cannot decode: decoder not correctly initialized + [0x97b9e8] Cannot decode: libjpeg_session_active == 0 + [0x97bae0] Subsampling tag is not set, yet subsampling inside JPEG data [%hhu,%hhu] does not match default values [2,2]; assuming subsampling inside JPEG data is correct + [0x97bb80] Subsampling inside JPEG data [%hhu,%hhu] does not match subsampling tag values [%hhu,%hhu]; assuming subsampling inside JPEG data is correct + [0x97bc10] Subsampling tag is not set, yet subsampling inside JPEG data does not match default values [2,2] (nor any other values allowed in TIFF); assuming subsampling inside JPEG data is correct and desubsampling inside JPEG decompression + [0x97bd00] Subsampling inside JPEG data does not match subsampling tag values [%hhu,%hhu] (nor any other values allowed in TIFF); assuming subsampling inside JPEG data is correct and desubsampling inside JPEG decompression + [0x97be70] Incompatible vertical subsampling and image strip/tile length + [0x97c270] ZIPSetupDecode + [0x97c280] ZIPDecode + [0x97c4c0] PixarLogSetupDecode + [0x97c4d8] PixarLogPreDecode + [0x97c4f0] PixarLogDecode + [0x97c870] LogL16Decode + [0x97c880] LogLuvDecode24 + [0x97c890] LogLuvDecode32 + [0x97ce08] LogLuvSetupDecode + [0x97d2b0] LZMAPreDecode + [0x97d2c0] LZMADecode + [0x97d468] file format not recognized + [0x97d560] Error initializing the stream decoder, %s + [0x995af0] Horizontal differencing "Predictor" not supported with %hu-bit samples + [0x995ca8] PredictorDecodeTile + [0x995dd0] horizontal differencing + [0x99cdf8] incorrect header check + [0x99cfd8] incorrect data check + [0x99cff0] incorrect length check + [0x9c3b84] script + [0x9d7f88] Languages + [0x9d7f98] Scripts + [0x9d7fa0] Scripts%stand-alone + [0x9dd1ae] tasubscript + [0x9dd356] pdirectional + [0x9dd7d7] ptsandsubscriptss + [0x9dda3d] acterrecognition + [0x9ddec5] tansmallscript + [0x9e0819] Iota_Subscript + [0x9e0b7e] Segment_Starter + [0x9e0d20] Emoji_Component + [0x9e0f60] Segment_Separator + [0x9e101d] Pop_Directional_Format + [0x9e10b3] Pop_Directional_Isolate + [0x9e1465] Superscripts_And_Subscripts + [0x9e15ca] Optical_Character_Recognition + [0x9e1705] Ideographic_Description_Characters + [0x9e2230] Vertical_Forms + [0x9e2686] Inscriptional_Parthian + [0x9e26b5] Inscriptional_Pahlavi + [0x9e307c] Tangut_Components + [0x9e344a] Khitan_Small_Script + [0x9e3795] Vertical + [0x9e4379] Vertical_Tail + [0x9e46e1] Script + [0x9e5bc3] Vertical_Orientation + [0x9e5df5] Script_Extensions + [0x9e6798] U_MISMATCHED_SEGMENT_DELIMITERS + [0x9e6828] U_MISSING_SEGMENT_CLOSE + [0x9e68b0] U_UNDEFINED_SEGMENT_REFERENCE + [0x9e69c0] U_UNCLOSED_SEGMENT + [0x9e69d8] U_ILLEGAL_CHAR_IN_SEGMENT + [0x9e7178] U_BRK_UNRECOGNIZED_OPTION + [0xda0269] c9cKcJcc?c@cAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc[c\c]c^c_c`cacbcccdc + [0x105d36b] bHb2c;cecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczc{c|c}c~c + [0x142fb65] c)c*c-c5c6c9cC?C@CACBCCCDCECFCGCHCICJCKCLCMCNCOCPCQCRCSCTCUCVCWCXCYCZC[C\C]C^C_C`CaCbCcCdCeCfCgChCiCjCkClCmCnCoCpCqCrCsCtCuCvCwCxCyCzC{C|C}C~C + [0x1505bed] c&c'c)c,c-c.c0c1c3c4c5c6c7c8c;cc?c@cAcDcGcHcJcQcRcScTcVcWcXcYcZc[c\c]c`cdcecfchcjckclcocpcrcsctcucxcyc|c}c~c + [0x153d56f] component + [0x15c5f92] ACBCCCDCECFCGCHCICJCKCLCMCNCOCPCQCRCSCTCUCVCWCXCYCZC[C\C]C^C_C`CaCbCcCdCeCfCgChCiCjC + [0x15eaf82] KSpnMS + [0x1678781] c&c'c)c,c-c.c0c1c3c4c5c6c7c8c;cc?c@cAcDcGcHcJcQcRcScTcVcWcXcYcZc[c\c]c`cdcecfchcjckclcocpcrcsctcucxcyc|c + [0x167ff1d] C C!C"C#C$C%C&C'C(C)C*C+C,C-C.C/C0C1C2C3C4C5C6C8C9C:C;CC?C@CACBCCCDCECFCGCHCICJCKCLCMCNCOCPCQCRCSCTCUCVCWCXCYCZC[C\C]C^C_C`CaCbCcCdCeCfCgChCiCjCkClCmCnCoCpCqCrCsCtCuCvCwCxCyCzC{C|C}C~C + [0x1734702] |coc(7wctc + [0x173948c] PcKQQcRcScTcVQUc{2;@Vc + [0x189b62c] RcScTcXc[cecfclc + [0x18e6bc3] C C!C"C#C$C%C&C'C(C)C*C+C,C-C.C/C0C1C2C3C4C5C6C7C8C9C:C;CC?C@CACBCCCDCECFCGCHCICJCKCLCMCNCOCPCQCRCSCTCUCVCWCXCYCZC[C\C]C^C_C`CaCbCcCdCeCfCgChCiCjCkClCmCnCoCpCqCrCsCtCuCvCwCxCyCzC{C|C}C~C + [0x194a0ac] ECEcAIFc,{U1JN34rHGcPOHcdPGPNPWP_PWPGPfPnPvP~P + [0x1cb19f7] superscriptingExponent + [0x1cb1c5f] african_scripts + [0x1cb1c6f] american_scripts + [0x1cb1d4a] european_scripts + [0x1cb1e16] historic_scripts + [0x1cb1ebe] middle_eastern_scripts + [0x1cb1ee3] modern_scripts + [0x1cb1fa9] south_asian_scripts + [0x1cb1fbd] southeast_asian_scripts + [0x1cb2030] western_asian_scripts + [0x1cb27c2] languages + [0x1f09f33] languageData + [0x1f0a92e] languageMatchingInfo + [0x1f0a985] languageMatchingNew + [0x1f76db6] direction + [0x20416f3] nmszs( + [0x2063bd0] COMPONENT- + [0x2063c50] SCRIPT + [0x2063d6b] VERTICAL + [0x2063f39] HORIZONTAL + [0x2064047] INSCRIPTIONAL + [0x206411d] TRIANGLE- + [0x20642a5] ACROPHONIC + [0x20642da] HORIZONTAL- + [0x2064395] TRIANGLE + [0x2064448] TRIANGLE + [0x2064457] VERTICAL- + [0x2064500] SUBSCRIPT + [0x20645c3] ANGLE + [0x20645ea] SUPERSCRIPT + [0x2064820] ROTATION- + [0x2064a08] HORIZONTAL + [0x2064d22] DESCRIPTION + [0x2064d56] QUADRANT + [0x2064dd7] ROTATION + [0x2064f7e] QUADRUPLE + [0x20650a0] SEGMENTED + [0x20650e4] VERTICAL + [0x20654b6] VERTICALLY + [0x20658a5] QUADRANT + [0x2065918] UNION + [0x2065a63] SEMIDIRECT + [0x2065ec9] RECTANGLE + [0x20660b6] ANGLED + [0x2066181] DIRECTION + [0x20661e1] COMPONENT + [0x20661f7] RECTANGLE + [0x2066b27] BEAMED + [0x2066e02] CONTOUR + [0x20672b5] DIRECT + [0x2067433] RECTANGULAR + [0x206744d] DIRECTIONAL + [0x20674b5] RECTILINEAR + [0x2067557] SEGMENT + [0x2067d9f] MICROPHONE + [0x2067e96] ROTATIONS + [0x2067f0e] DIRECTLY + [0x206d84c] PHORIZONTALLY + [0x2075aa9] )DIAERESIZED U + [0x20776b3] 5ASTERISKS ALIGNED VERTICALLY + [0x2077b85] RPRESCRIPTION TAKE + [0x2078631] ASSERTIONMODELSTRUEFORCES + [0x2078aeb] I-BEAM + [0x207a48f] AESCULAPIUSSCALESALEMBIC + [0x207a5b3] LILITHSEXTILESEMISEXTILEQUINCUNXSESQUIQUADRATESOCCER + [0x207a6c2] 6|pLANE MERGE + [0x207a6d0] pLANE MERGEDRIVE SLOW + [0x207bfda] CONTOURED OUTLINEINCREASES ASSHUFFLE + [0x207d9c3] DINDIRECT + [0x207e71a] ?SCRIPT + [0x207f9b7] CORRECT> + [0x208033b] `POSSESSION + [0x2090789] POSSESSION + [0x209297e] QUADCOLON + [0x209d5f0] ?BEAM' + [0x209d9a3] PORRECTUS' + [0x209d9ae] PORRECTUS FLEXUS' + [0x209fb32] ANGLED + [0x20a0494] UROTATION + [0x20a422f] TRUMPETVIOLIN'SCORE + [0x20a95bb] LANGUAGE TAGETUDUDFdUUUUUDuu + [0x25ceaa1] meta:Reunion + [0x26fe540] already connected + [0x26fe598] bad file descriptor + [0x26fe688] directory not empty + [0x26fe7c0] is a directory + [0x26fe900] no such file or directory + [0x26fe930] not a directory + [0x26fe960] not connected + [0x26ff378] TargetOversubscriptionFactor + [0x2701428] Type Descriptor' + [0x2701440] Base Class Descriptor at ( + [0x2701478] Class Hierarchy Descriptor' + [0x2708078] No such file or directory + [0x2708130] Bad file descriptor + [0x2708218] Not a directory + [0x2708228] Is a directory + [0x27083b8] Directory not empty + [0x2710288] invalid vector subscript + [0x2711662] oneocr_interop.proto + [0x2711678] OneOCR.Interop" + [0x27116aa] Quadrangle + [0x27116c8] .OneOCR.Interop.Point + [0x271174b] .OneOCR.Interop.Point" + [0x271176e] ConfidenceClass + [0x271183e] TextScript + [0x271184c] ScriptUnknown + [0x27118f4] Read_Horizontal + [0x2711909] Read_Vertical + [0x2711a1d] BarcodeRecognizerMetrics + [0x2711a4b] image_crop_total_ms + [0x2711a68] recognize_total_ms + [0x2711a84] detected_barcode_count + [0x2711aa4] recognized_barcode_count + [0x2711aee] PipelineMetrics + [0x2711b01] detected_line_count + [0x2711b1e] line_count + [0x2711b44] native_img_decode_ms + [0x2711b62] detector_metrics + [0x2711b78] 2/.OneOCR.Interop.PipelineMetrics.DetectorMetrics + [0x2711bc5] 2!.OneOCR.Interop.NormalizerMetrics + [0x2711c02] 20.OneOCR.Interop.PipelineMetrics.AnalyzerMetrices + [0x2711c38] recognizer_metrics + [0x2711c50] 21.OneOCR.Interop.PipelineMetrics.RecognizerMetrics + [0x2711c87] script_metrics + [0x2711c9b] 22.OneOCR.Interop.PipelineMetrics.ScriptMetricsEntry + [0x2711ce9] 2/.OneOCR.Interop.PipelineMetrics.DispatchMetrics + [0x2711d33] 2(.OneOCR.Interop.BarcodeRecognizerMetrics + [0x2711d7c] 24.OneOCR.Interop.PipelineMetrics.PostAnalyzerMetrices + [0x2711dcf] 2*.OneOCR.Interop.MathFormulaPipelineMetrics + [0x2711dff] word_nms_ms + [0x2711e2d] DetectorMetrics + [0x2711e52] inference_model_ms + [0x2711e8a] polygon_nms_ms + [0x2711f18] detected_polygon_count + [0x2711f38] resize_image_ms + [0x2711fc3] barcode_postprocess_ms + [0x2711fe3] checkbox_postprocess_ms + [0x2712004] image_feature_postprocess_ms + [0x27120be] color_detection_ms + [0x271211c] RecognizerMetrics + [0x27121a7] accumulated_cnnLstm_model_ms + [0x27121f3] accumulated_decoder_ms + [0x2712255] accumulated_confidence_ms + [0x27122c1] accumulated_space_detection_ms + [0x2712351] entity_textline_count + [0x27123a6] entity_first_recognize_ms + [0x27123c9] entity_second_recognize_ms + [0x27123ed] ScriptMetricsEntry + [0x2712446] detector_ms + [0x2712457] 21.OneOCR.Interop.TableMetrics.TableDetectorMetrics + [0x271248e] recognizer_ms + [0x27124a1] 23.OneOCR.Interop.TableMetrics.TableRecognizerMetrics + [0x271253c] TableDetectorMetrics + [0x2712566] image_rotation_ms + [0x2712581] image_resize_ms + [0x271259a] preprocess_ms + [0x27125b1] model_ms + [0x27125f5] TableRecognizerMetrics + [0x2712645] accumulated_image_resize_ms + [0x271266a] accumulated_model_ms + [0x2712731] preprocess_bbox_ms + [0x2712767] 2-.OneOCR.Interop.PODMetrics.PODBackboneMetrics + [0x27127bb] 23.OneOCR.Interop.PODMetrics.PODRegionGroupingMetrics + [0x2712813] 21.OneOCR.Interop.PODMetrics.PODReadingOrderMetrics + [0x2712863] post_process_bbox_ms + [0x27128c9] 2&.OneOCR.Interop.PODMetrics.FormMetrics + [0x2712b52] MathFormulaPipelineMetrics + [0x2712b8d] recoged_line_count + [0x2712ba9] rejected_line_count + [0x2712c4b] 2:.OneOCR.Interop.MathFormulaPipelineMetrics.DetectorMetrics + [0x2712ca2] 2;.OneOCR.Interop.MathFormulaPipelineMetrics.ParagraphMetrics + [0x2712cfb] 2<.OneOCR.Interop.MathFormulaPipelineMetrics.RecognizerMetrics + [0x2712ec1] accumulated_decoder_run_count + [0x2712f6d] TextRecognitionResult + [0x2712f93] 2,.OneOCR.Interop.TextRecognitionResult.Region + [0x2712fc5] image_rotate_angle + [0x2712fff] bounding_box + [0x2713013] .OneOCR.Interop.Quadrangle + [0x271303c] 2*.OneOCR.Interop.TextRecognitionResult.Line + [0x2713099] confidence_score + [0x27130b3] confidence + [0x27130c3] 2%.OneOCR.Interop.Enums.ConfidenceClass + [0x2713139] 23.OneOCR.Interop.TextRecognitionResult.WordCandidate + [0x2713261] font_name_confidence + [0x2713290] is_bold_confidence + [0x27132bf] is_italic_confidence + [0x27132e9] .OneOCR.Interop.Enums.WordType + [0x271337a] 23.OneOCR.Interop.TextRecognitionResult.LineCandidate + [0x27133be] 2*.OneOCR.Interop.TextRecognitionResult.Word + [0x27133ee] text_angle + [0x2713433] 2".OneOCR.Interop.Enums.TextCategory + [0x271346b] 2/.OneOCR.Interop.TextRecognitionResult.DebugInfo + [0x27134a0] category_score + [0x27134c4] 2 .OneOCR.Interop.Enums.TextScript + [0x27134f9] .OneOCR.Interop.Enums.LangID + [0x2713519] lang_id_score + [0x2713560] word_level_scores + [0x2713595] text_line_weighted_scores + [0x27135b8] lattice_decoder_confidence + [0x271360d] 2%.OneOCR.Interop.BarcodeResult.Barcode + [0x2713667] .OneOCR.Interop.BarcodeStandard + [0x27136ed] 2%.OneOCR.Interop.FormulaResult.Formula + [0x27137a0] 2#.OneOCR.Interop.FormulaResult.Style + [0x27137e3] 2".OneOCR.Interop.FormulaResult.Line + [0x271383d] bounding_box_with_formula_num + [0x2713894] 2".OneOCR.Interop.FormulaResult.Line"" + [0x27138e1] PipelineResult + [0x27138f3] textRecognitionResult + [0x271390e] 2%.OneOCR.Interop.TextRecognitionResult + [0x271394e] .OneOCR.Interop.BarcodeResult + [0x2713985] .OneOCR.Interop.CheckboxResult + [0x27139c0] .OneOCR.Interop.FormulaResult" + [0x2713a04] 2'.OneOCR.Interop.CheckboxResult.Checkbox + [0x2713aa4] .OneOCR.Interop.CheckboxType + [0x2713b21] resized_image_height + [0x2713b3f] resized_image_width + [0x2713bf8] 2!.OneOCR.Interop.TableResult.Table + [0x2713c9a] .OneOCR.Interop.TableType + [0x2713cc8] 2%.OneOCR.Interop.TableResult.TableCell + [0x2713d1c] .OneOCR.Interop.TableGeometry + [0x2713df2] bounding_poly + [0x2713e43] 2#.OneOCR.Interop.FigureResult.Figure + [0x2713ec8] .OneOCR.Interop.FigureType"D + [0x2713f0b] .OneOCR.Interop.TableGeometry" + [0x2713f48] 2!.OneOCR.Interop.LangIDResult.Line + [0x2714002] pipelineResult + [0x2714018] .OneOCR.Interop.PipelineResult + [0x271404d] .OneOCR.Interop.TableResult + [0x2714080] .OneOCR.Interop.FigureResult" + [0x27140c6] 2%.OneOCR.Interop.PODResult.PageObjects + [0x2714132] 20.OneOCR.Interop.PODResult.PageObjects.PageObject + [0x27141a9] region_grouping_score + [0x2714237] textline_ids + [0x271426a] reading_order_score + [0x27143ca] 2+.OneOCR.Interop.LatticeResult.WordCandidate + [0x2714452] .OneOCR.Interop.Sentence.Word + [0x2714473] is_textline + [0x2714536] TextLine + [0x2714542] image_detect + [0x2714558] textline_polygon + [0x2714570] .OneOCR.Interop.LinePolygon + [0x27145b4] 2%.OneOCR.Interop.Enums.TextOrientation + [0x27145f2] .OneOCR.Interop.XnnResult + [0x271461f] .OneOCR.Interop.Sentence + [0x2714651] .OneOCR.Interop.LatticeResult + [0x27146f5] .OneOCR.Interop.Enums.TextRead + [0x271473e] LinePolygon + [0x271475c] is_horizontal + [0x27147e2] pipeline_result + [0x2714832] .OneOCR.Interop.CheckboxResult" + [0x2714875] 2/.OneOCR.Interop.KeyValuePairResult.KeyValuePair + [0x27148e2] 2'.OneOCR.Interop.KeyValuePairElementType + [0x2714929] 2+.OneOCR.Interop.KeyValuePairResult.Position + [0x27149e5] 2-.OneOCR.Interop.KeyValuePairMetrics.QAMetrics + [0x2714b0b] word_count + [0x27151d0] MaxRecognitionLineCountStrategy + [0x2716062] oneocr.proto + [0x2716070] OneOCR + [0x2716078] oneocr_interop.proto" + [0x2716090] ONNXProto + [0x271609d] model_path + [0x27160b1] ModelPack + [0x27160ca] .OneOCR.ONNXProto"G + [0x27160df] TieredModelPack + [0x2716101] model_pack + [0x2716113] .OneOCR.ModelPack" + [0x271614e] custom_fst_scale + [0x27161a0] 2*.OneOCR.CustomScenarioProto.GrammarLmEntry + [0x27161d0] base_fst_scale + [0x271623a] acoustic_scale + [0x2716252] decoder_beam + [0x271627a] .OneOCR.CustomScenarioProto" + [0x271629a] DecoderProto + [0x27162c2] 2 .OneOCR.DecoderProto.DecoderType + [0x2716361] max_active_beam + [0x271637a] min_active_beam + [0x2716393] lattice_beam + [0x271642d] DecoderType + [0x271645a] DetectorProto + [0x2716483] 2'.OneOCR.DetectorProto.DetectorModelType + [0x27164c2] .OneOCR.ModelPack + [0x27164d7] image_resize_factor + [0x27164f4] max_resize_multiple + [0x2716511] use_floor_resize + [0x271652b] line_merge_threshold + [0x2716549] segment_conf_threshold + [0x2716569] textline_conf_threshold + [0x2716586] 20.OneOCR.DetectorProto.TextlineConfThresholdEntry + [0x27165bc] textline_nms_threshold + [0x27165dc] textline_onverlap_threshold + [0x2716622] relation_conf_threshold + [0x2716660] ambiguous_nms_threshold + [0x2716681] ambiguous_overlap_threshold + [0x27166a6] ambiguous_save_threshold + [0x2716722] checkbox_nms_thres + [0x2716772] 2".OneOCR.DetectorProto.DQDETRConfig + [0x27167bf] text_confidence_threshold + [0x27167e2] textline_overlap_threshold + [0x2716806] textline_height_close_threshold + [0x271682f] textline_hardnms_iou_threshold + [0x2716856] &textline_groupnms_span_ratio_threshold + [0x2716887] checkbox_inference_threshold + [0x27168ad] barcode_inference_threshold + [0x27168d2] notline_overlap_threshold + [0x27168f5] checkbox_merge_threshold + [0x2716917] TextlineConfThresholdEntry + [0x2716956] DetectorModelType + [0x2716a51] script_threshold + [0x2716b03] !hwpc_consecutive_frames_threshold + [0x2716b2e] #script_consecutive_frames_threshold + [0x2716b58] 2<.OneOCR.AuxMltClsProto.ScriptConsecutiveFramesThresholdEntry + [0x2716b9a] non_text_script_threshold + [0x2716bc7] 2).OneOCR.AuxMltClsProto.AuxMltClsModelType + [0x2716c10] .OneOCR.LineLayoutClsProto + [0x2716c41] %ScriptConsecutiveFramesThresholdEntry + [0x2716c8c] AuxMltClsModelType + [0x2716ca2] SCRIPT_HWPC_FLIP + [0x2716cb8] SCRIPT_HWPC_FLIP_BATCH + [0x2716cd3] !SCRIPT_HWPC_FLIP_LINELAYOUT_BATCH + [0x2716cfb] SCRIPT_HWPC_FLIP_FIXEDWIDTH + [0x2716edb] char_script_path + [0x2716f78] .OneOCR.CharProto.CharModelType + [0x271707a] prior_scale + [0x27170e8] blank_threshold + [0x2717101] char_threshold + [0x2717150] tiered_models + [0x2717165] .OneOCR.TieredModelPack" + [0x2717181] CharModelType + [0x2717250] ConfidenceProto + [0x2717298] word_class_threshold + [0x2717329] CheckboxDetectorProto + [0x2717377] boxes_threshold + [0x27173b2] TableDetectorProto + [0x27173fd] tables_threshold + [0x271742c] figure_threshold + [0x2717462] FormDetectorProto + [0x2717497] .OneOCR.ModelPack"i + [0x27174ac] TableRecognizerProto + [0x27174f9] cell_merge_threshold + [0x2717637] .OneOCR.ModelPack"K + [0x27176c8] 21.OneOCR.TextEmbeddingProto.TextEmbeddingModelType + [0x2717751] TextEmbeddingModelType + [0x27177f3] .OneOCR.ModelPack"E + [0x2717887] .OneOCR.ModelPack"? + [0x27178ea] text_script_to_ocr_mode + [0x2717907] 2,.OneOCR.EnumsMap.TextScriptToOcrModeMapEntry + [0x2717938] text_script_category_to_ocr_mode + [0x271795f] 28.OneOCR.EnumsMap.TextScriptTextCategoryToOcrModeMapEntry + [0x27179bc] 2..OneOCR.EnumsMap.OcrModeToTextCategoryMapEntry + [0x27179f0] ocr_mode_to_text_script + [0x2717a0d] 2,.OneOCR.EnumsMap.OcrModeToTextScriptMapEntry + [0x2717a3f] ocr_mode_to_char_model_path + [0x2717a60] 2&.OneOCR.EnumsMap.OcrModeToPathMapEntry + [0x2717a8c] ocr_mode_to_decoder_path + [0x2717b21] TextScriptToOcrModeMapEntry + [0x2717b7e] .OneOCR.Interop.OCRMode + [0x2717b99] 'TextScriptTextCategoryToOcrModeMapEntry + [0x2717cd2] OcrModeToTextScriptMapEntry + [0x2717d96] .OneOCR.Interop.OCRMode"I + [0x2717de7] .OneOCR.ModelPack"f + [0x2717e47] rejection_threshold + [0x2717e9b] .OneOCR.ModelPack"u + [0x2717f28] PipelineProto + [0x2717f39] det_model + [0x2717f4a] .OneOCR.DetectorProto + [0x2717f63] det_model_dir + [0x2717f7a] char_model + [0x2717f8c] .OneOCR.CharProto + [0x2717fa1] char_model_dir + [0x2717fb9] dec_model + [0x2717fca] .OneOCR.DecoderProto + [0x2717fe2] dec_model_dir + [0x2717ff9] rej_model + [0x271800a] .OneOCR.RejectionProto + [0x2718024] rej_model_dir + [0x271803b] conf_model + [0x271804d] .OneOCR.ConfidenceProto + [0x2718068] conf_model_dir + [0x2718080] checkbox_det_model + [0x271809a] .OneOCR.CheckboxDetectorProto + [0x27180bb] checkbox_det_model_dir + [0x27180db] line_layout_cls_model + [0x2718116] line_layout_cls_model_dir + [0x2718139] table_det_model + [0x2718150] .OneOCR.TableDetectorProto + [0x271816e] table_det_model_dir + [0x271818b] table_reco_model + [0x27181a3] .OneOCR.TableRecognizerProto + [0x27181c3] table_reco_model_dir + [0x27181e1] aux_mlt_cls_model + [0x27181fa] .OneOCR.AuxMltClsProto + [0x2718214] aux_mlt_cls_model_dir + [0x2718241] .OneOCR.PipelineProto.Engine + [0x2718271] 2 .OneOCR.PipelineProto.Scheduling + [0x27182ad] 2%.OneOCR.PipelineProto.RejectionOption + [0x2718300] 2".OneOCR.PipelineProto.EngineOption + [0x2718328] lang_id_model + [0x271833d] .OneOCR.LangIDProto + [0x2718354] lang_id_model_dir + [0x271836f] pod_backbone_model + [0x2718389] .OneOCR.PODBackboneProto + [0x27183a5] pod_backbone_model_dir + [0x27183c5] pod_region_grouping_model + [0x27183e6] .OneOCR.PODRegionGroupingProto + [0x2718408] pod_region_grouping_model_dir + [0x271842f] pod_reading_order_model + [0x271844e] .OneOCR.PODReadingOrderProto + [0x271846e] pod_reading_order_model_dir + [0x2718493] text_embedding_model + [0x27184af] .OneOCR.TextEmbeddingProto + [0x27184cd] text_embedding_model_dir + [0x27184ef] entity_classifier_model + [0x271850e] .OneOCR.EntityClassifierProto + [0x271852f] entity_classifier_model_dir + [0x2718554] custom_fst_model + [0x271856c] .OneOCR.CustomFstProto + [0x2718586] custom_fst_model_dir + [0x27185b5] .OneOCR.EnumsMap + [0x27185e1] mathfm_det_model + [0x27185f9] .OneOCR.MathFmDetProto + [0x2718613] mathfm_det_model_dir + [0x2718631] mathfm_line_enc_model + [0x271864e] .OneOCR.MathFmLineEncProto + [0x271866c] mathfm_line_enc_model_dir + [0x271868f] mathfm_line_rej_model + [0x27186ac] .OneOCR.MathFmLineRejProto + [0x27186ca] mathfm_line_rej_model_dir + [0x27186ed] mathfm_line_attn_model + [0x271870b] .OneOCR.MathFmLineAttnProto + [0x271872a] mathfm_line_attn_model_dir + [0x271874e] mathfm_line_dec_model + [0x271876b] .OneOCR.MathFmLineDecProto + [0x2718789] mathfm_line_dec_model_dir + [0x27187ac] font_cls_model + [0x27187c2] .OneOCR.FontClsProto + [0x27187da] font_cls_model_dir + [0x27187f6] textline_images_batcher + [0x2718813] 2+.OneOCR.PipelineProto.TextlineImagesBatcher + [0x2718844] mathfm_paragraph_model + [0x2718862] .OneOCR.MathFmParagraphProto + [0x2718882] mathfm_paragraph_model_dir + [0x27188a6] form_det_model + [0x27188bc] .OneOCR.FormDetectorProto + [0x27188d9] form_det_model_dir + [0x27188f5] toc_model + [0x2718906] .OneOCR.TOCProto + [0x271891a] toc_model_dir + [0x2718931] enable_wordnms + [0x2718963] 2 .OneOCR.PipelineProto.EngineType + [0x2718fb1] 26.OneOCR.PipelineProto.RuntimeOption.RuntimeOptionEntry + [0x2719043] 2#.OneOCR.PipelineProto.RuntimeOption + [0x2719691] TextlineImagesBatcher + [0x27196aa] max_recognize_line_width + [0x27196cc] recognizer_chunk_width + [0x27196ec] max_recognize_chunk_count + [0x271977d] TensorMapProto + [0x271978f] tensors + [0x271979c] 2#.OneOCR.TensorMapProto.TensorsEntry + [0x27197c6] Tensor + [0x27197da] 2!.OneOCR.TensorMapProto.TensorType + [0x271985e] TensorsEntry + [0x2719888] .OneOCR.TensorMapProto.Tensor: + [0x27198ad] TensorType + [0x271cc28] OneOCR.Interop.PipelineMetrics.ScriptMetricsEntry.key + [0x271cc78] OneOCR.Interop.TextRecognitionResult.Region.json + [0x271ccb0] OneOCR.Interop.TextRecognitionResult.WordCandidate.text + [0x271cce8] OneOCR.Interop.TextRecognitionResult.Word.text + [0x271cd18] OneOCR.Interop.TextRecognitionResult.LineCandidate.text + [0x271cd50] OneOCR.Interop.TextRecognitionResult.DebugInfo.word_lab_strings + [0x271cd90] OneOCR.Interop.TextRecognitionResult.errorInfo + [0x271cdc0] OneOCR.Interop.BarcodeResult.Barcode.content + [0x271cdf0] OneOCR.Interop.BarcodeResult.error_info + [0x271ce18] OneOCR.Interop.FormulaResult.Line.value + [0x271ce40] OneOCR.Interop.FormulaResult.Formula.value + [0x271ce70] OneOCR.Interop.FormulaResult.error_info + [0x271ce98] OneOCR.Interop.CheckboxResult.error_info + [0x271cec8] OneOCR.Interop.TableResult.Table.json_debug_info + [0x271cf00] OneOCR.Interop.LangIDResult.error_info + [0x271cf28] OneOCR.Interop.LangIDInput.texts + [0x271cf50] OneOCR.Interop.PODResult.PageObjects.PageObject.object_type_name + [0x271cfa0] OneOCR.Interop.PODResult.PageObjects.PageObject.object_role_name + [0x271cff0] OneOCR.Interop.PODResult.PageObjects.PageObject.reading_order_label_name + [0x271d040] OneOCR.Interop.LatticeResult.WordCandidate.text + [0x271d070] OneOCR.Interop.Sentence.Word.lab + [0x271d098] OneOCR.Interop.TextLine.text + [0x271d7c8] create_directories + [0x271d7e0] TextPipelineDevImpl::Recognize only supports single image input. + [0x271d840] processOption.Feature != CoreEngineFeature::None + [0x271d880] C:\__w\1\s\CoreEngine\Native\TextPipeline\TextPipelineDevImpl.cpp + [0x271d900] CoreEngine Feature can't be None + [0x271d928] BatchRecognize API only supports on GPU enabled engine. + [0x271d9a0] BatchDetect API only supports on GPU enabled engine. + [0x271da10] IsHorizontal: + [0x271da28] fLanguageScoreY: + [0x271da40] fLanguageScoreX: + [0x271da58] fConfidenceScoreY: + [0x271da70] fConfidenceScoreX: + [0x271dac8] MAX_LINE_COUNT_BATCH_SIZE_RATIO + [0x271dae8] Unknown recognition strategy + [0x271db08] ONEOCR_CONCURRENCY + [0x271db78] C:\__w\1\s\CoreEngine\Native\Common/CollectionUtility.h + [0x271dc20] C:\__w\1\s\CoreEngine\Native\Common/thread_pool.h + [0x271df20] C:\__w\1\s\CoreEngine\Native\TextPipeline\FilterXY.cpp + [0x271dff8] C:\__w\1\s\CoreEngine\Native\Common/EnumUtility.h + [0x271e040] Horizontal + [0x271e050] Unknown TextScript " + [0x271e068] textscript_string_routing_table.count(script) > 0 + [0x271e0d8] Unknown TextLineLayout " + [0x271e1e0] opt.line_layout_cls_model().size() > 0 + [0x271e220] Unsupported value in aux_mlt_cls_model.type() + [0x271e250] C:\__w\1\s\CoreEngine\Native\TextAnalyzer\TextAnalyzerImpl.cpp + [0x271e2c8] m_aux_mlt_cls.size() == opt.aux_mlt_cls_model().size() + [0x271e330] m_line_layout_cls.size() == opt.line_layout_cls_model().size() + [0x271e398] m_font_cls.size() == opt.font_cls_model().size() + [0x271e3d0] scriptLineCntsVec.size() == static_cast(TextScript::ScriptCnt) + [0x271e418] scriptClsSoftmaxVec.size() == scriptOutDim + [0x271e468] Script: + [0x271e498] .detector.png + [0x271e8b8] Unknown string for TextScript " + [0x271e8d8] string_textscript_routing_table.count(str) > 0 + [0x271e908] script_id_score + [0x271e918] hwpc_score + [0x271e928] script_id_perframe_predict + [0x271e948] flip_score + [0x271e970] score.size() == GetScriptOutputDim() + [0x271e9c0] indexToScript.size() > 1 + [0x271e9e0] C:\__w\1\s\CoreEngine\Native\TextAnalyzer\AuxMltClsClassifier.cpp + [0x271ea28] perFrameData.size() % nScript == 0 + [0x271eb60] scriptPerFrame.dims[1] == 1 + [0x271eb80] scriptPerFrame.dims[2] == scriptCount + [0x271eba8] scriptPerFrame.dims.size() == 3 + [0x271ebd0] C:\__w\1\s\CoreEngine\Native\TextAnalyzer\AuxMltClsClassifierFixedWidth.cpp + [0x271ed88] C:\__w\1\s\CoreEngine\Native\Common/INNFramework.h + [0x271edd0] Tensor already exists. + [0x271ee40] C:\__w\1\s\CoreEngine\Native\Common/ImageUtility.h + [0x271eed0] invalid array subscript + [0x271ef08] line_layout_score + [0x271ef50] font_weight_score + [0x271ef68] font_style_score + [0x271ef80] font_softmax_score + [0x271f000] C:\__w\1\s\CoreEngine\Native\TextAnalyzer\AuxMltClsClassifierBatch.cpp + [0x271f118] C:\__w\1\s\CoreEngine\Native\TextAnalyzer\BaseClassifier.cpp + [0x271f1c0] ONEOCR_USE_MODEL_DELAYLOAD + [0x271f1e0] opt.rej_model().size() >= 1 + [0x271f200] C:\__w\1\s\CoreEngine\Native\TextRecognizer\TextLineRecognizerImpl.cpp + [0x271f248] Missing character model. + [0x271f268] opt.char_model().size() >= 1 + [0x271f288] m_upXnnNet.size() == opt.char_model().size() + [0x271f2b8] Confidence model enabled but not provided. + [0x271f2e8] opt.conf_model().size() >= 1 + [0x271f308] Rejection model enabled but not provided. + [0x271f338] m_upLattice.size() == opt.dec_model().size() + [0x271f368] Decoder count mismatched. + [0x271f388] m_upDecoder.size() == opt.dec_model().size() + [0x271f3b8] Char model count mismatched. + [0x271f3d8] m_confidenceModel.size() == opt.conf_model().size() + [0x271f410] Rejection model count mismatched. + [0x271f438] m_rejectionModel.size() == opt.rej_model().size() + [0x271f490] Only LatMBRAdapter is supported as decoder for CustomFSTs! + [0x271f4d0] proto.type() == DecoderProto_DecoderType_LATMBR + [0x271f528] Confidence model count mismatched. + [0x271f588] Text recognizer not initialized yet. + [0x271f5e8] Decoder " + [0x271f5f8] m_upDecoder.count(route_dec) > 0 + [0x271f620] Char model " + [0x271f6c0] m_rejectionModel.count(route_rej) == 1 + [0x271f6e8] /dumpDecoder/ + [0x271f710] concatTextLines.Script().size() == batchSize + [0x271f778] C:\__w\1\s\CoreEngine\Native\Common/DelayLoadPtr.h + [0x271fc00] C:\__w\1\s\CoreEngine\Native\TextRecognizer\ArgMaxDecoder.cpp + [0x271fcd8] Invalid Decoder phone table, token is found. + [0x271fd98] Invalid Decoder phone table, token not found. + [0x271fde0] Invalid Decoder phone table, token not found. + [0x271fe68] ArgMaxDecoder is not initialized. + [0x271ff50] ARGMAX_LINE decoder is deprecated. This will break Arabic logical reordering. + [0x2720020] C:\__w\1\s\CoreEngine\Native\TextRecognizer\CharacterMap\Sentence.cpp + [0x27204d0] C:\__w\1\s\CoreEngine\Native\TextRecognizer\CharacterMap\CharacterMapper.cpp + [0x27209d0] C:\__w\1\s\CoreEngine\Native\TextRecognizer\LatMBRAdapter.cpp + [0x2720c08] C:\__w\1\s\CoreEngine\Native\TextRecognizer/SparseMatrix.h + [0x2720c78] Bad memory access when building physical scores. + [0x2720cb0] C:\__w\1\s\CoreEngine\Native\TextRecognizer\XnnResult.cpp + [0x2720d00] C:\__w\1\s\CoreEngine\Native\TextRecognizer\ConfidenceProcessor.cpp + [0x2720dc0] C:\__w\1\s\CoreEngine\Native\TextRecognizer\DbLstm.cpp + [0x2720f28] For this model with width + [0x2721030] Char model line width mismatched + [0x2721060] tieredModel->InputLineImageWidth() == m_tieredModels[idx].first + [0x27210a0] C:\__w\1\s\CoreEngine\Native\TextRecognizer\DbLstmTiered.cpp + [0x2721120] C:\__w\1\s\CoreEngine\Native\TextRecognizer\RejectionProcessor.cpp + [0x2721330] tensor.dims.size() == 4 && tensor.dims[0] == 1 && tensor.dims[3] == 3 + [0x2721400] C:\__w\1\s\CoreEngine\Native\TextNormalizer\ConcatTextLines.cpp + [0x2721440] m_sequenceLengths.size() == m_isHorizontal.size() + [0x2721480] tensor.dims.size() == 4 && tensor.dims[0] == 1 && tensor.dims[1] == 3 + [0x2721508] fScale > 0.f + [0x2721528] C:\__w\1\s\CoreEngine\Native\TextNormalizer\BaseNormalizer.cpp + [0x2721620] C:\__w\1\s\CoreEngine\Native\TextNormalizer\TextLocationMapper.cpp + [0x27216e0] C:\__w\1\s\CoreEngine\Native\TextNormalizer/TextLocationMapper.h + [0x2721750] Size of TransformData is not correct! + [0x27217c0] C:\__w\1\s\CoreEngine\Native\TextDetector\TextLinePolygon.cpp + [0x2721850] Polygon points' number need to be even. + [0x2721878] vPolygonPoints.size() % 2 == 0 + [0x2721898] segments.size() >= 2 + [0x27219e0] C:\__w\1\s\CoreEngine\Native\TextDetector\PolygonIntersectionCache.cpp + [0x2721b38] C:\__w\1\s\CoreEngine\Native\TextDetector\PolyFitting.cpp + [0x2721bc0] Detector model count mismatched. + [0x2721be8] m_det.size() == opt.det_model().size() + [0x2721c10] C:\__w\1\s\CoreEngine\Native\TextDetector\TextDetectorImpl.cpp + [0x2721c50] Do not support detector type: + [0x2721c88] Detector mode " + [0x2721e50] C:\__w\1\s\CoreEngine\Native\TextDetector\RelationRCNNRpn2FixedSize.cpp + [0x2722038] bbox_deltas_ + [0x2722048] link_scores_ + [0x2722058] scores_ + [0x27220c8] contours + [0x27220d8] _crop_detected_adaptive.jpg + [0x27220f8] _crop_detected_original.jpg + [0x2722118] _crop_detected_adaptive_keep.jpg + [0x2722140] AS_LARGE_TEXT_THRESHOLD + [0x27221a0] !procOpt.WorkingDirectory.empty() + [0x27221c8] Working directory is empty + [0x27221e8] C:\__w\1\s\CoreEngine\Native\TextDetector\AdaptiveScaling.cpp + [0x2722280] small_contours.jpg + [0x2722298] small_text_bbox.jpg + [0x27222c0] small_contour_bbox.jpg + [0x2722618] fpnlvl_featmap_routing_table.count(fpnlvl) > 0 + [0x2722648] Invalid FpnLvl for FeatMap " + [0x27226a8] C:\__w\1\s\CoreEngine\Native\TextDetector/BaseRCNN.h + [0x27226e8] rpn_rois_fpn + [0x2722780] checkbox_scores + [0x2722790] checkbox_bbox_reg + [0x27227d8] imgCount == preprocessOutput.imageCount + [0x2722800] Model doesn't support batch input + [0x2722828] C:\__w\1\s\CoreEngine\Native\TextDetector\BaseRCNN.cpp + [0x2722890] rawImages.size() == preprocessOutput.imageCount + [0x27228c0] Input image count doesn't match with detector output count. + [0x2722930] hori_fpn + [0x2722950] vert_fpn + [0x2722990] relPairsTensor.dims[0] == relClsProbTensor.dims[0] + [0x27229c8] C:\__w\1\s\CoreEngine\Native\TextDetector\RelationRCNN.cpp + [0x2722ab4] scores + [0x2722ac0] C:\__w\1\s\CoreEngine\Native\TextDetector/DQDETR.h + [0x2722afc] bboxes + [0x2722b08] C:\__w\1\s\CoreEngine\Native\TextDetector\DQDETR.cpp + [0x2722b58] obj_scores + [0x2722bb8] obj_bboxes + [0x2722bc8] scores.dims[0] == num + [0x2722be0] bboxes.dims[1] == pointsCount * 2 + [0x2722c40] C:\__w\1\s\CoreEngine\Native\TextDetector\RelationRCNNRpn2.cpp + [0x2722c80] C:\__w\1\s\CoreEngine\Native\TextDetector/SeglinkGroup.h + [0x2722ce8] scores_concat_compress + [0x2722d10] link_scores_concat_compress + [0x2722d30] bbox_deltas_concat_compress + [0x2722ef8] scaleY > 0.0f + [0x2722f08] C:\__w\1\s\CoreEngine\Native\TextDetector\BarcodePolygon.cpp + [0x2722f48] Scale should > 0.0 + [0x2722f60] scaleX > 0.0f + [0x2722ff0] C:\__w\1\s\CoreEngine\Native\TextDetector\SeglinkProposal.cpp + [0x2723068] levelCount == TensorNames.size() + [0x2723110] rpn_rois_fpn3 + [0x2723120] rpn_rois_fpn4 + [0x2723148] rpn_rois_fpn2 + [0x27231e8] GetResizeDims failed: width = + [0x2723208] GetResizeDims failed: height = + [0x2723228] C:\__w\1\s\CoreEngine\Native\ModelInferencer\CommonRCNN.cpp + [0x27232a0] C:\__w\1\s\CoreEngine\Native\CommonInference\NNFrameworkFactory.cpp + [0x2723370] C:\__w\1\s\CoreEngine\Native\CustomOps/onnxruntime/PackImageToSeqOp.h + [0x27233d0] C:\__w\1\s\CoreEngine\Native\CustomOps/onnxruntime/SplitFromSequenceOp.h + [0x2723438] Model_QDQ + [0x2723448] Missing ONNX model file + [0x2723468] C:\__w\1\s\CoreEngine\Native\OrtInference\OrtQnnFramework.cpp + [0x2723530] modelParser.IsFileExist(modelPath) + [0x2723580] Encounter error inside Ort while creating inference session from ONNX model + [0x2723738] ORT_TENSORRT_CACHE_PATH + [0x2723750] ONEOCR_ORT_TRT_ENABLE_FP16 + [0x2723770] ONEOCR_ORT_TRT_MIN_SUBGRAPH_SIZE + [0x27239d8] OneOCRFeatureExtract + [0x2723a38] min_box_height_before_scaleback + [0x2723a58] input_scale_ratio + [0x2723a70] corner_score_threshold + [0x2723a88] OneOCRXYSeglinkProposals + [0x2723aa8] K_of_detections_after_nms + [0x2723ac8] K_of_detections + [0x2723ae8] min_box_width_before_scaleback + [0x2723b50] OneOCRSeglinkProposals + [0x2723b78] session.disable_quant_qdq + [0x2723b98] Size of tensor names and values must be the same. + [0x2723bf8] CornerNetDecode + [0x2723c08] nms_iou_threshold + [0x2723c20] session.use_env_allocators + [0x2723c58] C:\__w\1\s\CoreEngine\Native\OrtInference/OrtTensorMapView.h + [0x2723c98] session.intra_op.allow_spinning + [0x2723cd0] C:\__w\1\s\CoreEngine\Native\OrtInference\OrtFramework.cpp + [0x2723d10] com.microsoft.oneocr + [0x2723d68] ONEOCR_ORT_INTRA_OP_THREADS + [0x2723d88] ONEOCR_ORT_GRAPH_OPT + [0x2723da0] ONEOCR_ORT_USE_SESSION_THREADPOOL + [0x2723dc8] ONEOCR_ORT_DISABLE_QUANTQDQ + [0x2723de8] ONEOCR_ORT_SHARE_ALLOCATOR + [0x2723e08] ONEOCR_ORT_USE_ARENA + [0x2723e20] ONEOCR_ORT_USE_MEM_PATTERN + [0x2723e40] ONEOCR_ORT_ALLOW_INTRA_OP_SPINNING + [0x2723e68] onnxruntime-node + [0x2723e80] C:\__w\1\s\CoreEngine\Native\OrtInference\OrtEnvironment.cpp + [0x2723ef8] onnxruntime + [0x2723f58] ONEOCR_ORT_GLOBALSPIN + [0x2724000] C:\__w\1\s\CoreEngine\Native\CustomOps\onnxruntime\SeglinkProposalsOp.cpp + [0x2724050] scores.Shape().NumDimensions() == 4 + [0x2724078] group_seg_nms_thresh + [0x27240a8] C:\__w\1\s\CoreEngine\Native\CustomOps/onnxruntime/OrtTensor.h + [0x27240e8] Invalid dimension for SizeFromDimension. Tensor has + [0x2724180] C:\__w\1\s\CoreEngine\Native\CustomOps\onnxruntime\GenerateRelatedCellPairsOp.cpp + [0x27241d8] input_tensor.Shape().NumDimensions() == 3 + [0x2724220] C:\__w\1\s\CoreEngine\Native\CustomOps\onnxruntime\LeftPoolingOp.cpp + [0x2724268] input_tensor.Shape().NumDimensions() == 4 + [0x27242a0] C:\__w\1\s\CoreEngine\Native\CustomOps\onnxruntime\FeatureExtractOp.cpp + [0x27243a0] Model mismatch. + [0x2724480] C:\__w\1\s\CoreEngine\Native\CustomOps\onnxruntime\XYSeglinkProposalsOp.cpp + [0x27244d0] scores_vert.Shape().NumDimensions() == 4 + [0x2724510] C:\__w\1\s\CoreEngine\Native\CustomOps\onnxruntime\RightPoolingOp.cpp + [0x2724560] C:\__w\1\s\CoreEngine\Native\CustomOps\onnxruntime\BottomPoolingOp.cpp + [0x27245b0] ../../CoreEngine/UnitTests/Resources/UnitTests/Table/sample_cell_pairs.json + [0x2724640] C:\__w\1\s\CoreEngine\Native\CustomOps\onnxruntime\SVDSoftmaxOp.cpp + [0x2724730] C:\__w\1\s\CoreEngine\Native\CustomOps\onnxruntime\TopPoolingOp.cpp + [0x2724778] row_line_mask_tensor.Shape() == col_line_mask_tensor.Shape() + [0x27247d0] C:\__w\1\s\CoreEngine\Native\CustomOps\onnxruntime\GenerateSLPOp.cpp + [0x2724818] row_line_mask_tensor.Shape().NumDimensions() == 2 + [0x2724850] col_line_mask_tensor.Shape().NumDimensions() == 2 + [0x2724888] bIsHorizon == static_cast(vQuadLabel[indexs[i]]) + [0x27248c0] C:\__w\1\s\CoreEngine\Native\CustomOps\common\XYSeglinkProposalsOpBase.cpp + [0x2724940] 1 == quad_labels.cols() + [0x2724990] C:\__w\1\s\CoreEngine\Native\CustomOps/common/SeglinkProposalsOpUtilsBox.h + [0x2724a00] boxes.rows() == quad_labels.rows() + [0x2724a30] C:\__w\1\s\CoreEngine\Native\CustomOps\common\SeglinkProposalsOpBase.cpp + [0x2724a80] C:\__w\1\s\CoreEngine\Native\ModelParser\ModelParser.cpp + [0x2724ac0] Model file not exit: + [0x2724c08] C:\__w\1\s\CoreEngine\Native\ModelParser\Crypto.cpp + [0x2724c60] Copyright @ OneOCR, Microsoft. + [0x2724dd8] Memory management error in CLatStrRepo detected. + [0x27250b8] words.size(): %lu != confidences.size(): %lu + [0x2725450] C:\__w\1\s\CoreEngine\Native\LatticeDecoder\latmbr\quantized_wfst.cpp + [0x27257b0] C:\__w\1\s\CoreEngine\Native\LatticeDecoder\latmbr\wfst_v2.cpp + [0x27258e0] C:\__w\1\s\CoreEngine\Native\LatticeDecoder\latmbr\quantization.cpp + [0x27259f8] C:\__w\1\s\CoreEngine\Native\Common\ImageList.cpp + [0x2725ad0] ONEOCR_INSTALL_FAILURES_SIGNAL_HANDLER + [0x2725b88] C:\__w\1\s\CoreEngine\Native\Common\init.cpp + [0x2725db0] proto.ocr_mode_to_text_script().size() > 0ull + [0x2725e10] proto.ocr_mode_to_decoder_path().size() > 0ull + [0x2725e40] proto.ocr_mode_to_char_model_path().size() > 0ull + [0x2725e88] C:\__w\1\s\CoreEngine\Native\Common\EnumMapper.cpp + [0x2725ec0] proto.text_script_category_to_ocr_mode().size() > 0ull + [0x2725f10] proto.text_script_to_ocr_mode().size() > 0ull + [0x2725f48] m_ocrModeToDecoderPath.count(ocrmode) > 0 + [0x2725fe0] m_textScriptTextCategoryToOcrMode.count(script_category_pair) > 0 + [0x2726028] m_ocrModeToCharModelPath.count(ocrmode) > 0 + [0x2726088] m_textScriptToOcrMode.count(script) > 0 + [0x27260f8] m_ocrModeToTextScript.count(ocrmode) > 0 + [0x2726290] collectComments + [0x27262a0] C:\__w\1\s\CoreEngine\Native\Common\JsonUtility.cpp + [0x2726480] C:\__w\1\s\CoreEngine\Native\Common\ImageUtility.cpp + [0x27264f8] cvImgResized.rows == nImageHeight + [0x2726538] cvImgResized.cols == nImageWidth + [0x2726608] C:\__w\1\s\CoreEngine\Native\Common\PolygonIntersection.cpp + [0x2726700] C:\__w\1\s\CoreEngine\Native\Common\ImageFeature.cpp + [0x2726738] C:\__w\1\s\CoreEngine\Native\Common\FileUtility.cpp + [0x27267f8] componentIdx + [0x2726de0] OneOCR.AuxMltClsProto.ScriptConsecutiveFramesThresholdEntry.key + [0x2726e20] OneOCR.DetectorProto.TextlineConfThresholdEntry.key + [0x2726e58] OneOCR.CustomScenarioProto.GrammarLmEntry.value + [0x2726e88] OneOCR.CustomScenarioProto.GrammarLmEntry.key + [0x2726eb8] OneOCR.PipelineProto.RuntimeOption.RuntimeOptionEntry.value + [0x2726ef8] OneOCR.PipelineProto.RuntimeOption.RuntimeOptionEntry.key + [0x2726f38] OneOCR.CustomFstProto.name + [0x2726f58] OneOCR.DecoderProto.name + [0x2726f78] OneOCR.CustomScenarioProto.lm_path + [0x2726fa0] OneOCR.CustomScenarioProto.manifest_path + [0x2726fd0] OneOCR.ONNXProto.model_path + [0x2726ff0] OneOCR.CustomScenarioProto.name + [0x2727020] OneOCR.TensorMapProto.TensorsEntry.key + [0x2727048] OneOCR.LangIDProto.name + [0x2727060] OneOCR.LangIDProto.char_mapping_path + [0x2727088] OneOCR.FontClsProto.font_weight_calib_map_path + [0x27270b8] OneOCR.FontClsProto.font_style_calib_map_path + [0x27270e8] OneOCR.FontClsProto.name + [0x2727108] OneOCR.FontClsProto.font_name_calib_map_path + [0x2727138] OneOCR.AuxMltClsProto.hwpc_handwritten_calib_map_path + [0x2727170] OneOCR.LineLayoutClsProto.name + [0x2727190] OneOCR.DetectorProto.checkbox_calib_map_path + [0x27271c0] OneOCR.AuxMltClsProto.name + [0x27271e0] OneOCR.DecoderProto.quantization_param_path + [0x2727210] OneOCR.DetectorProto.name + [0x2727230] OneOCR.DecoderProto.word_path + [0x2727250] OneOCR.DecoderProto.lm_path + [0x2727270] OneOCR.DecoderProto.wfst_path + [0x2727290] OneOCR.DecoderProto.phone_path + [0x27272b0] OneOCR.TableDetectorProto.name + [0x27272d0] OneOCR.FormDetectorProto.name + [0x27272f0] OneOCR.CheckboxDetectorProto.name + [0x2727318] OneOCR.CheckboxDetectorProto.checkbox_calib_map_path + [0x2727350] OneOCR.ConfidenceProto.name + [0x2727370] OneOCR.RejectionProto.name + [0x2727390] OneOCR.CharProto.char_log_to_phy_path + [0x27273b8] OneOCR.CharProto.composite_chars_map_path + [0x27273e8] OneOCR.CharProto.rnn_info_path + [0x2727408] OneOCR.CharProto.phone_to_idx_path + [0x2727430] OneOCR.LangIDProto.calibration_mapping_path + [0x2727460] OneOCR.CharProto.name + [0x2727478] OneOCR.LangIDProto.id_to_name_mapping_path + [0x27274a8] OneOCR.LangIDProto.lang_mask_path + [0x27274d0] OneOCR.LangIDProto.feature_config_path + [0x27274f8] OneOCR.LangIDProto.char_script_path + [0x2727520] OneOCR.MathFmLineDecProto.vocab_path + [0x2727548] OneOCR.MathFmLineDecProto.calib_map_path + [0x2727578] OneOCR.MathFmLineAttnProto.name + [0x2727598] OneOCR.MathFmLineDecProto.name + [0x27275b8] OneOCR.MathFmLineEncProto.name + [0x27275d8] OneOCR.MathFmLineRejProto.name + [0x27275f8] OneOCR.MathFmParagraphProto.name + [0x2727620] OneOCR.TOCProto.name + [0x2727638] OneOCR.EntityClassifierProto.name + [0x2727660] OneOCR.MathFmDetProto.name + [0x2727680] OneOCR.TextEmbeddingProto.name + [0x27276a0] OneOCR.TextEmbeddingProto.vocab_path + [0x27276c8] OneOCR.PODRegionGroupingProto.name + [0x27276f0] OneOCR.PODReadingOrderProto.name + [0x2727718] OneOCR.TableRecognizerProto.name + [0x2727740] OneOCR.PODBackboneProto.name + [0x2727760] OneOCR.PipelineProto.text_embedding_model_dir + [0x2727790] OneOCR.PipelineProto.entity_classifier_model_dir + [0x27277c8] OneOCR.PipelineProto.pod_region_grouping_model_dir + [0x2727800] OneOCR.PipelineProto.pod_reading_order_model_dir + [0x2727838] OneOCR.PipelineProto.lang_id_model_dir + [0x2727860] OneOCR.PipelineProto.pod_backbone_model_dir + [0x2727890] OneOCR.PipelineProto.table_reco_model_dir + [0x27278c0] OneOCR.PipelineProto.aux_mlt_cls_model_dir + [0x27278f0] OneOCR.PipelineProto.line_layout_cls_model_dir + [0x2727920] OneOCR.PipelineProto.table_det_model_dir + [0x2727950] OneOCR.PipelineProto.conf_model_dir + [0x2727978] OneOCR.PipelineProto.checkbox_det_model_dir + [0x27279a8] OneOCR.PipelineProto.dec_model_dir + [0x27279d0] OneOCR.PipelineProto.rej_model_dir + [0x27279f8] OneOCR.PipelineProto.det_model_dir + [0x2727a20] OneOCR.PipelineProto.char_model_dir + [0x2727a48] OneOCR.PipelineProto.toc_model_dir + [0x2727a70] OneOCR.PipelineProto.mathfm_paragraph_model_dir + [0x2727aa0] OneOCR.PipelineProto.form_det_model_dir + [0x2727ac8] OneOCR.PipelineProto.mathfm_line_dec_model_dir + [0x2727af8] OneOCR.PipelineProto.font_cls_model_dir + [0x2727b20] OneOCR.PipelineProto.mathfm_line_rej_model_dir + [0x2727b50] OneOCR.PipelineProto.mathfm_line_attn_model_dir + [0x2727b80] OneOCR.PipelineProto.mathfm_det_model_dir + [0x2727bb0] OneOCR.PipelineProto.mathfm_line_enc_model_dir + [0x2727be0] OneOCR.PipelineProto.custom_fst_model_dir + [0x2727c10] OneOCR.PipelineProto.enums_map_file + [0x272a400] recursive_directory_iterator::operator++ + [0x272a430] recursive_directory_iterator::recursive_directory_iterator + [0x272a568] C:\__w\1\s\CoreEngine\proto\proto_utils.cpp + [0x272a6c8] proto.model_pack().onnx().model_path() != "" + [0x272a730] Handwritten score calibration map file + [0x272a758] ONNX model + [0x272a770] fs::is_regular_file(proto.tiered_models(idx).model_pack().onnx().model_path()) + [0x272a800] fs::exists(proto.tiered_models(idx).model_pack().onnx().model_path()) + [0x272a9b8] LangID language mask file not found + [0x272aa18] LangID confidence calibration mapping file not found + [0x272ab08] fs::is_regular_file(proto.char_script_path()) + [0x272ab38] LangID char script file not found + [0x272ab88] proto.char_script_path() != "" + [0x272ac18] Font style score calibration map file + [0x272ac40] Font weight score calibration map file + [0x272ad38] Font name score calibration map file + [0x272ada8] Formula Line Decoder vocabulary file + [0x272ae40] fs::is_directory(proto.font_cls_model_dir()) + [0x272ae88] fs::is_directory(proto.line_layout_cls_model_dir()) + [0x272aee0] fs::is_directory(proto.aux_mlt_cls_model_dir()) + [0x272af38] fs::is_directory(proto.det_model_dir()) + [0x272af60] Detector model dir + [0x272af88] fs::is_directory(proto.lang_id_model_dir()) + [0x272afb8] Lang ID model dir + [0x272afd0] fs::is_directory(proto.table_reco_model_dir()) + [0x272b000] Table recognizer model dir + [0x272b020] fs::is_directory(proto.table_det_model_dir()) + [0x272b050] Table detector model dir + [0x272b070] fs::is_directory(proto.checkbox_det_model_dir()) + [0x272b0a8] Checkbox detector model dir + [0x272b0c8] fs::is_directory(proto.conf_model_dir()) + [0x272b0f8] Confidence model dir + [0x272b110] fs::is_directory(proto.rej_model_dir()) + [0x272b138] Rejection model dir + [0x272b150] fs::is_directory(proto.dec_model_dir()) + [0x272b178] Decoder model dir + [0x272b190] fs::is_directory(proto.char_model_dir()) + [0x272b1c0] Char model dir + [0x272b1e0] fs::is_directory(proto.mathfm_det_model_dir()) + [0x272b210] Custom FSTs model dir + [0x272b250] fs::is_directory(proto.entity_classifier_model_dir()) + [0x272b288] Entity classifier model dir + [0x272b2a8] fs::is_directory(proto.text_embedding_model_dir()) + [0x272b2e0] Text embedding model dir + [0x272b300] fs::is_directory(proto.pod_reading_order_model_dir()) + [0x272b338] POD reading_order model dir + [0x272b358] fs::is_directory(proto.pod_region_grouping_model_dir()) + [0x272b390] POD region_grouping model dir + [0x272b3b0] fs::is_directory(proto.pod_backbone_model_dir()) + [0x272b3e8] POD backbone model dir + [0x272b400] fs::is_directory(proto.form_det_model_dir()) + [0x272b430] Form detector model dir + [0x272b450] fs::is_regular_file(proto.model_pack().onnx().model_path()) + [0x272b4b0] TOC model dir + [0x272b4c0] fs::exists(proto.model_pack().onnx().model_path()) + [0x272b4f8] Math formula Paragraph model dir + [0x272b520] fs::is_directory(proto.toc_model_dir()) + [0x272b548] Math formula line encoder model dir + [0x272b570] fs::is_directory(proto.mathfm_paragraph_model_dir()) + [0x272b5a8] Math formula line encoder attention model dir + [0x272b5d8] fs::is_directory(proto.mathfm_line_enc_model_dir()) + [0x272b610] Math formula line rejection model dir + [0x272b638] fs::is_directory(proto.mathfm_line_attn_model_dir()) + [0x272b670] Math formula line decoder model dir + [0x272b698] fs::is_directory(proto.mathfm_line_rej_model_dir()) + [0x272b6d0] MathFormula detector model dir + [0x272b6f0] fs::is_directory(proto.mathfm_line_dec_model_dir()) + [0x272b990] Model-scan root + [0x272b9b0] fs::is_directory(dir) + [0x272b9c8] is not a directory. + [0x275fedc] C:\__w\1\s\CoreEngine\build\bin\Release\oneocr.pdb + [0x27ee6a2] oneocr.dll + [0x27ee6c2] CreateOcrPipeline + [0x27ee6ec] GetImageAngle + [0x27ee705] GetOcrLineBoundingBox + [0x27ee76c] GetOcrWordBoundingBox + [0x27ee782] GetOcrWordConfidence + [0x27ee7a9] OcrInitOptionsSetUseModelDelayLoad + [0x27ee7cc] OcrProcessOptionsGetMaxRecognitionLineCount + [0x27ee7f8] OcrProcessOptionsGetResizeResolution + [0x27ee81d] OcrProcessOptionsSetMaxRecognitionLineCount + [0x27ee849] OcrProcessOptionsSetResizeResolution + [0x27ee884] ReleaseOcrPipeline + [0x27ee8c1] RunOcrPipeline + [0x27eefa8] onnxruntime.dll + [0x27ef12c] GetCurrentDirectoryW + [0x27ef280] GetWindowsDirectoryA + [0x27ef61a] CreateDirectoryW + [0x27ef8f4] DecodePointer + [0x27eff0c] RemoveDirectoryW + [0x27fdf98] .?AVFileDescriptorSet@protobuf@google@@ + [0x27fdfd0] .?AVFileDescriptorProto@protobuf@google@@ + [0x27fe010] .?AVDescriptorProto_ExtensionRange@protobuf@google@@ + [0x27fe060] .?AVDescriptorProto_ReservedRange@protobuf@google@@ + [0x27fe0a8] .?AVDescriptorProto@protobuf@google@@ + [0x27fe120] .?AVFieldDescriptorProto@protobuf@google@@ + [0x27fe160] .?AVOneofDescriptorProto@protobuf@google@@ + [0x27fe1a0] .?AVEnumDescriptorProto_EnumReservedRange@protobuf@google@@ + [0x27fe1f0] .?AVEnumDescriptorProto@protobuf@google@@ + [0x27fe230] .?AVEnumValueDescriptorProto@protobuf@google@@ + [0x27fe270] .?AVServiceDescriptorProto@protobuf@google@@ + [0x27fe2b0] .?AVMethodDescriptorProto@protobuf@google@@ + [0x27fee70] .?AV@?1??SimpleParallelFor@ThreadPool@concurrency@onnxruntime@@AEAAX_JAEBV?$function@$$A6AX_J@Z@std@@@Z@ + [0x27fef00] .?AV@?M@??ParallelForFixedBlockSizeScheduling@ThreadPool@concurrency@onnxruntime@@AEAAX_J0AEBV?$function@$$A6AX_J0@Z@std@@@Z@ + [0x27fefa0] .?AV@?9??ParallelForFixedBlockSizeScheduling@ThreadPool@concurrency@onnxruntime@@AEAAX_J0AEBV?$function@$$A6AX_J0@Z@std@@@Z@ + [0x27ff610] .?AVTextRecognitionResult_DebugInfo@Interop@OneOCR@@ + [0x27ff660] .?AVPipelineMetrics_PostAnalyzerMetrices@Interop@OneOCR@@ + [0x27ff6b0] .?AVMathFormulaPipelineMetrics_DetectorMetrics@Interop@OneOCR@@ + [0x27ff700] .?AVTextRecognitionResult@Interop@OneOCR@@ + [0x27ff740] .?AVTableResult_SolidLineBlock@Interop@OneOCR@@ + [0x27ff780] .?AVPipelineMetrics_DetectorMetrics@Interop@OneOCR@@ + [0x27ff7d0] .?AVPipelineMetrics_RecognizerMetrics@Interop@OneOCR@@ + [0x27ff830] .?AVLatticeResult_WordCandidate@Interop@OneOCR@@ + [0x27ff880] .?AVMathFormulaPipelineMetrics_ParagraphMetrics@Interop@OneOCR@@ + [0x27ff8e0] .?AVMathFormulaPipelineMetrics_RecognizerMetrics@Interop@OneOCR@@ + [0x27ff938] .?AVBarcodeResult_Barcode@Interop@OneOCR@@ + [0x27ff978] .?AVTableGeometries@Interop@OneOCR@@ + [0x27ff9b0] .?AVQuadrangle@Interop@OneOCR@@ + [0x27ff9e0] .?AVNormalizerMetrics@Interop@OneOCR@@ + [0x27ffa18] .?AVCheckboxResult_Checkbox@Interop@OneOCR@@ + [0x27ffa60] .?AVTextRecognitionResult_Region@Interop@OneOCR@@ + [0x27ffaa8] .?AVTableResult_SolidLine@Interop@OneOCR@@ + [0x27ffaf0] .?AVPODMetrics_PODRegionGroupingMetrics@Interop@OneOCR@@ + [0x27ffb40] .?AVSectionLevels@Interop@OneOCR@@ + [0x27ffb78] .?AVPipelineMetrics@Interop@OneOCR@@ + [0x27ffbb0] .?AVTextRecognitionResult_WordCandidate@Interop@OneOCR@@ + [0x27ffc00] .?AVTextRecognitionResult_LineCandidate@Interop@OneOCR@@ + [0x27ffc50] .?AVBarcodeRecognizerMetrics@Interop@OneOCR@@ + [0x27ffc90] .?AVLangIDInput@Interop@OneOCR@@ + [0x27ffcc8] .?AVRawPageObjects@Interop@OneOCR@@ + [0x27ffe80] .?AVMathFormulaPipelineMetrics@Interop@OneOCR@@ + [0x27ffec0] .?AVPoint@Interop@OneOCR@@ + [0x27ffef0] .?AVSentence@Interop@OneOCR@@ + [0x27fff20] .?AVPODMetrics_PODBackboneMetrics@Interop@OneOCR@@ + [0x27fff70] .?AVPipelineMetrics_AnalyzerMetrices@Interop@OneOCR@@ + [0x27fffb8] .?AVTableResult@Interop@OneOCR@@ + [0x27ffff0] .?AVTextRecognitionResult_Word@Interop@OneOCR@@ + [0x2800030] .?AVFigureResult@Interop@OneOCR@@ + [0x2800068] .?AVPipelineResult@Interop@OneOCR@@ + [0x28000f8] .?AVPODMetrics@Interop@OneOCR@@ + [0x2800128] .?AVLangIDResult_Line@Interop@OneOCR@@ + [0x2800160] .?AVFormulaResult@Interop@OneOCR@@ + [0x2800198] .?AVBarcodeResult@Interop@OneOCR@@ + [0x28001d0] .?AVPODResult_PageObjects_PageObject@Interop@OneOCR@@ + [0x2800218] .?AVFigureResult_Figure@Interop@OneOCR@@ + [0x2800258] .?AVPODMetrics_FormMetrics@Interop@OneOCR@@ + [0x28002a0] .?AVPipelineMetrics_DispatchMetrics@Interop@OneOCR@@ + [0x28002e8] .?AVTOCMetrics@Interop@OneOCR@@ + [0x2800320] .?AVKeyValuePairResult_Position@Interop@OneOCR@@ + [0x2800368] .?AVCheckboxResult@Interop@OneOCR@@ + [0x28003a0] .?AVTableMetrics@Interop@OneOCR@@ + [0x28003d8] .?AVPODResult@Interop@OneOCR@@ + [0x2800410] .?AVTableMetrics_TableRecognizerMetrics@Interop@OneOCR@@ + [0x2800460] .?AVSentence_Word@Interop@OneOCR@@ + [0x2800498] .?AVEnums@Interop@OneOCR@@ + [0x28004c8] .?AVFormulaResult_Formula@Interop@OneOCR@@ + [0x2800510] .?AVPipelineMetrics_ScriptMetricsEntry_DoNotUse@Interop@OneOCR@@ + [0x2800568] .?AVLangIDResult@Interop@OneOCR@@ + [0x28005a0] .?AVTableGeometry@Interop@OneOCR@@ + [0x28005e0] .?AVKeyValuePairResult_KeyValuePair@Interop@OneOCR@@ + [0x2800628] .?AVKeyValuePairResult@Interop@OneOCR@@ + [0x2800660] .?AVLatticeResult@Interop@OneOCR@@ + [0x2800698] .?AVFormulaResult_Line@Interop@OneOCR@@ + [0x28006d0] .?AVKeyValuePairInput@Interop@OneOCR@@ + [0x2800708] .?AVLinePolygon@Interop@OneOCR@@ + [0x2800740] .?AVPODResult_PageObjects@Interop@OneOCR@@ + [0x2800780] .?AVKeyValuePairMetrics_QAMetrics@Interop@OneOCR@@ + [0x28007c8] .?AVXnnResult@Interop@OneOCR@@ + [0x2800800] .?AVPODMetrics_PODReadingOrderMetrics@Interop@OneOCR@@ + [0x28008c0] .?AVTextLine@Interop@OneOCR@@ + [0x28008f0] .?AVTableResult_TableCell@Interop@OneOCR@@ + [0x2800930] .?AVTableMetrics_TableDetectorMetrics@Interop@OneOCR@@ + [0x2800978] .?AVTableResult_Table@Interop@OneOCR@@ + [0x28009b0] .?AVTextRecognitionResult_Line@Interop@OneOCR@@ + [0x28009f0] .?AVKeyValuePairMetrics@Interop@OneOCR@@ + [0x2800a30] .?AVHierarchyAnalyzerInput@Interop@OneOCR@@ + [0x2800a70] .?AV@?M@??RecognizeTextLines@TextPipelineDevImpl@OneOCR@@UEBA?AUTextRecognitionResult@3@AEAV?$vector@V?$unique_ptr@VTextLine@OneOCR@@U?$default_delete@VTextLine@OneOCR@@@std@@@std@@V?$allocator@V?$unique_ptr@VTextLine@OneOCR@@U?$default_delete@VTextLine@OneOCR@@@std@@@std@@@2@@std@@AEBUProcessOption@3@QEAVPipelineMetrics@Interop@3@V?$optional@V?$reference_wrapper@VImageFeature@OneOCR@@@std@@@6@@Z@ + [0x2800f70] .?AV@?0???0ThreadPool@OneOCR@@QEAA@_K@Z@ + [0x2800fc0] .?AV@?3???R@?3??alloc@ThreadPool@OneOCR@@QEAA?AVContext@34@_K@Z@QEBA@XZ@ + [0x2801600] .?AV@?4??Analyze@TextAnalyzerImpl@OneOCR@@UEBAXAEAV?$vector@V?$unique_ptr@VTextLine@OneOCR@@U?$default_delete@VTextLine@OneOCR@@@std@@@std@@V?$allocator@V?$unique_ptr@VTextLine@OneOCR@@U?$default_delete@VTextLine@OneOCR@@@std@@@std@@@2@@std@@AEBUProcessOption@3@AEAVPipelineMetrics_AnalyzerMetrices@Interop@3@@Z@ + [0x2801758] .?AVAuxMltClsClassifierBatch@OneOCR@@ + [0x2802368] .?AVAuxMltClsClassifier@OneOCR@@ + [0x2803c40] .?AV?$_Binder@U_Unforced@std@@V?$_Mem_fn@P8TextLineRecognizerImpl@OneOCR@@EAAPEAVILattice@2@AEBVDecoderProto@2@AEBVModelParser@2@@Z@2@PEAVTextLineRecognizerImpl@OneOCR@@AEBVDecoderProto@5@AEAVModelParser@5@@std@@ + [0x2803d30] .?AV@?1??Recognize@TextLineRecognizerImpl@OneOCR@@UEBA?AURecognizerTextLineResult@3@AEAVTextLine@3@AEBUProcessOption@3@AEAUAtomicRecognizerMetrics@3@@Z@ + [0x2803df0] .?AV@?1??RecognizeWithTextLineFeature@TextLineRecognizerImpl@OneOCR@@UEBA?AURecognizerTextLineResult@3@AEBUTextLineFeature@3@AEAVTextLine@3@AEBUProcessOption@3@AEAUAtomicRecognizerMetrics@3@@Z@ + [0x2803ed0] .?AV@?1??BatchRecognize@TextLineRecognizerImpl@OneOCR@@UEBA?AV?$vector@URecognizerTextLineResult@OneOCR@@V?$allocator@URecognizerTextLineResult@OneOCR@@@std@@@std@@AEBVConcatTextLines@3@AEBUProcessOption@3@AEAUAtomicRecognizerMetrics@3@PEAVThreadPool@3@@Z@ + [0x2803ff0] .?AV?$_Binder@U_Unforced@std@@V?$_Mem_fn@P8TextLineRecognizerImpl@OneOCR@@EAAPEAVCnnDbLstm@2@AEBVCharProto@2@AEBVModelParser@2@@Z@2@PEAVTextLineRecognizerImpl@OneOCR@@AEBVCharProto@5@AEAVModelParser@5@@std@@ + [0x28040d0] .?AVDec@LatMBRAdapter@OneOCR@@ + [0x2804350] .?AV?$_Binder@U_Unforced@std@@V?$_Mem_fn@P8TextLineRecognizerImpl@OneOCR@@EAAPEAVConfidenceProcessor@2@AEBVConfidenceProto@2@AEBVModelParser@2@@Z@2@PEAVTextLineRecognizerImpl@OneOCR@@AEBVConfidenceProto@5@AEAVModelParser@5@@std@@ + [0x2804450] .?AV?$_Binder@U_Unforced@std@@V?$_Mem_fn@P8TextLineRecognizerImpl@OneOCR@@EAAPEAVRejectionProcessor@2@AEBVRejectionProto@2@AEBVModelParser@2@@Z@2@PEAVTextLineRecognizerImpl@OneOCR@@AEBVRejectionProto@5@AEAVModelParser@5@@std@@ + [0x2804550] .?AV?$_Binder@U_Unforced@std@@V?$_Mem_fn@P8TextLineRecognizerImpl@OneOCR@@EAAPEAVIDecoder@2@AEBVDecoderProto@2@AEBVModelParser@2@V?$optional@V?$reference_wrapper@VCustomFstProto@OneOCR@@@std@@@std@@@Z@2@PEAVTextLineRecognizerImpl@OneOCR@@AEBVDecoderProto@5@AEAVModelParser@5@AEAV?$optional@V?$reference_wrapper@VCustomFstProto@OneOCR@@@std@@@2@@std@@ + [0x28046c0] .?AV@?7??ProcessLogSoftmaxScores@TextLineRecognizerImpl@OneOCR@@IEBA?AURecognizerTextLineResult@3@AEBVCscMatrixView@3@AEBVTextLine@3@_NPEBVCharacterMapper@CharacterMap@3@PEBVCnnDbLstm@3@PEBVIDecoder@3@PEBVILattice@3@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@77AEBUProcessOption@3@AEAUAtomicRecognizerMetrics@3@@Z@ + [0x2804828] .?AVIDecoder@OneOCR@@ + [0x2804a60] .?AV@?1??InitCompositeCharMap@CharacterMapper@CharacterMap@OneOCR@@IEAAXAEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEBVModelParser@4@@Z@ + [0x2804d30] .?AV@?1??LoadPhoneMap@CharacterMapper@CharacterMap@OneOCR@@IEBA?AV?$vector@HV?$allocator@H@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@6@AEBVModelParser@4@@Z@ + [0x2804e10] .?AU?$default_delete@$$BY0A@UCharToken@CharacterMap@OneOCR@@@std@@ + [0x2805090] .?AV@?1??Process@Lat@LatMBRAdapter@OneOCR@@UEBA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEAUDecoderResult@4@AEAV?$vector@ULatticeResult@OneOCR@@V?$allocator@ULatticeResult@OneOCR@@@std@@@6@AEBUProcessOption@4@H@Z@ + [0x28051a0] .?AV@?1??Process@Lat@LatMBRAdapter@OneOCR@@UEBA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEAUDecoderResult@4@AEAV?$vector@ULatticeResult@OneOCR@@V?$allocator@ULatticeResult@OneOCR@@@std@@@6@AEBUProcessOption@4@H@Z@ + [0x2805320] .?AV?$_Binder@U_Unforced@std@@V?$_Mem_fn@P8CnnDbLstmTiered@OneOCR@@EAAPEAVCnnDbLstm@2@AEBVCharProto@2@AEBVTieredModelPack@2@AEBVModelParser@2@W4PipelineProto_EngineType@2@@Z@2@PEAVCnnDbLstmTiered@OneOCR@@AEBVCharProto@5@AEBVTieredModelPack@5@AEBVModelParser@5@AEAW4PipelineProto_EngineType@5@@std@@ + [0x2805af0] .?AU?$default_delete@VDQDETR@OneOCR@@@std@@ + [0x28073c0] .?AV@?1??RunInference@BaseRCNN@OneOCR@@MEBA?AV?$unique_ptr@VITensorMapView@OneOCR@@U?$default_delete@VITensorMapView@OneOCR@@@std@@@std@@AEBVSimpleTensorMap@3@AEAVPipelineMetrics_DetectorMetrics@Interop@3@AEBUProcessOption@3@_N@Z@ + [0x2807aa0] .?AV@?1??RunInference@DQDETR@OneOCR@@MEBA?AV?$unique_ptr@VITensorMapView@OneOCR@@U?$default_delete@VITensorMapView@OneOCR@@@std@@@std@@AEBVSimpleTensorMap@3@AEAVPipelineMetrics_DetectorMetrics@Interop@3@AEBUProcessOption@3@_N@Z@ + [0x2807ba0] .?AU?$default_delete@VTextLinePolygon@OneOCR@@@std@@ + [0x2809340] .?AV@?1??Cipher@OneOCR@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEBV34@0_N1@Z@ + [0x28093d0] .?AV@?1??SHA256Hash@OneOCR@@YA?AV?$array@W4byte@std@@$0CA@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@4@@Z@ + [0x2809470] .?AV@?1??Cipher@OneOCR@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEBV34@0_N1@Z@ + [0x2809500] .?AV@?1??SHA256Hash@OneOCR@@YA?AV?$array@W4byte@std@@$0CA@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@4@@Z@ + [0x28098e0] .?AVRingPolygon@OneOCR@@ + [0x2809958] .?AVPolygon@OneOCR@@ + [0x28099e0] .?AV@?1??ConvertTextV2L_ICU@Utility@OneOCR@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEBV45@AEAV?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@5@AEAV?$vector@_KV?$allocator@_K@std@@@5@AEAV?$vector@U?$pair@_K_K@std@@V?$allocator@U?$pair@_K_K@std@@@2@@5@@Z@ + [0x2809ba8] .?AVConfidenceProto@OneOCR@@ + [0x2809bd8] .?AVDetectorProto@OneOCR@@ + [0x2809c08] .?AVTieredModelPack@OneOCR@@ + [0x2809c38] .?AVFormDetectorProto@OneOCR@@ + [0x2809c68] .?AVPipelineProto_Scheduling@OneOCR@@ + [0x2809ca0] .?AVFontClsProto@OneOCR@@ + [0x2809cd0] .?AVTableDetectorProto@OneOCR@@ + [0x2809d00] .?AVCharProto@OneOCR@@ + [0x2809d28] .?AVTOCProto@OneOCR@@ + [0x2809d50] .?AVEnumsMap_OcrModeToTextCategoryMapEntry@OneOCR@@ + [0x2809d98] .?AVEntityClassifierProto@OneOCR@@ + [0x2809dd0] .?AVAuxMltClsProto_ScriptConsecutiveFramesThresholdEntry_DoNotUse@OneOCR@@ + [0x2809e30] .?AVLineLayoutClsProto@OneOCR@@ + [0x2809e60] .?AVTensorMapProto@OneOCR@@ + [0x2809e90] .?AVPipelineProto_EngineOption@OneOCR@@ + [0x2809ec8] .?AVPipelineProto@OneOCR@@ + [0x2809ef8] .?AVCustomFstProto@OneOCR@@ + [0x2809f30] .?AVEnumsMap_OcrModeToTextScriptMapEntry@OneOCR@@ + [0x2809f78] .?AVMathFmLineEncProto@OneOCR@@ + [0x2809fa8] .?AVEnumsMap@OneOCR@@ + [0x2809fd0] .?AVEnumsMap_OcrModeToPathMapEntry@OneOCR@@ + [0x280a010] .?AVLangIDProto@OneOCR@@ + [0x280a040] .?AVPipelineProto_Engine@OneOCR@@ + [0x280a078] .?AVPODRegionGroupingProto@OneOCR@@ + [0x280a0b0] .?AVDecoderProto@OneOCR@@ + [0x280a0e0] .?AVModelPack@OneOCR@@ + [0x280a108] .?AVTensorMapProto_Tensor@OneOCR@@ + [0x280a140] .?AVMathFmParagraphProto@OneOCR@@ + [0x280a180] .?AVEnumsMap_TextScriptToOcrModeMapEntry@OneOCR@@ + [0x280a1c8] .?AVMathFmLineAttnProto@OneOCR@@ + [0x280a200] .?AVPODReadingOrderProto@OneOCR@@ + [0x280a240] .?AVDetectorProto_TextlineConfThresholdEntry_DoNotUse@OneOCR@@ + [0x280a290] .?AVCheckboxDetectorProto@OneOCR@@ + [0x280a2c8] .?AVRejectionProto@OneOCR@@ + [0x280a2f8] .?AVCustomScenarioProto@OneOCR@@ + [0x280a330] .?AVMathFmDetProto@OneOCR@@ + [0x280a360] .?AVONNXProto@OneOCR@@ + [0x280a388] .?AVPipelineProto_RejectionOption@OneOCR@@ + [0x280a3c8] .?AVMathFmLineRejProto@OneOCR@@ + [0x280a400] .?AVTensorMapProto_TensorsEntry_DoNotUse@OneOCR@@ + [0x280a450] .?AVCustomScenarioProto_GrammarLmEntry_DoNotUse@OneOCR@@ + [0x280a4a0] .?AVPODBackboneProto@OneOCR@@ + [0x280a4d0] .?AVTableRecognizerProto@OneOCR@@ + [0x280a508] .?AVMathFmLineDecProto@OneOCR@@ + [0x280a540] .?AVPipelineProto_TextlineImagesBatcher@OneOCR@@ + [0x280a588] .?AVTextEmbeddingProto@OneOCR@@ + [0x280a5b8] .?AVDetectorProto_DQDETRConfig@OneOCR@@ + [0x280a5f0] .?AVPipelineProto_RuntimeOption@OneOCR@@ + [0x280a630] .?AVEnumsMap_TextScriptTextCategoryToOcrModeMapEntry@OneOCR@@ + [0x280a680] .?AVPipelineProto_RuntimeOption_RuntimeOptionEntry_DoNotUse@OneOCR@@ + [0x280a6d8] .?AVAuxMltClsProto@OneOCR@@ + [0x280a710] .?AV@?3??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280a770] .?AV@?8??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280a7d0] .?AV@?N@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280a840] .?AV@?BD@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280a8b0] .?AV@?L@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280a920] .?AV@?BJ@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280a990] .?AV@?9??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280a9f0] .?AV@?BB@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280aa60] .?AV@?6??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280aac0] .?AV@?BM@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280ab30] .?AV@?BA@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280aba0] .?AV@?BF@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280ac10] .?AV@?O@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280ac80] .?AV@?5??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280ace0] .?AV@?BE@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280ad50] .?AV@?BH@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280adc0] .?AV@?2??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280ae20] .?AV@?BK@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280ae90] .?AV@?BC@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280af00] .?AV@?P@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280af70] .?AV@?7??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280afd0] .?AV@?BL@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280b040] .?AV@?BG@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280b0b0] .?AV@?M@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280b120] .?AV@?4??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280b180] .?AV@?BI@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280b320] .?AVAggregateOptionFinder@OptionInterpreter@DescriptorBuilder@protobuf@google@@ + [0x280be98] .?AVDescriptorDatabase@protobuf@google@@ + [0x280bee0] .?AVEncodedDescriptorDatabase@protobuf@google@@ + [0x280c0f8] .?AV?$_Ref_count_obj2@VPFMDecoder@cv@@@std@@ + [0x280c178] .?AV?$_Ref_count_obj2@VBmpDecoder@cv@@@std@@ + [0x280c1f8] .?AV?$_Ref_count_obj2@VHdrDecoder@cv@@@std@@ + [0x280c278] .?AV?$_Ref_count_obj2@VJpegDecoder@cv@@@std@@ + [0x280c300] .?AV?$_Ref_count_obj2@VSunRasterDecoder@cv@@@std@@ + [0x280c398] .?AV?$_Ref_count_obj2@VPxMDecoder@cv@@@std@@ + [0x280c3d8] .?AV?$_Ref_count_obj2@VPAMDecoder@cv@@@std@@ + [0x280c458] .?AV?$_Ref_count_obj2@VTiffDecoder@cv@@@std@@ + [0x280c4d8] .?AV?$_Ref_count_obj2@VPngDecoder@cv@@@std@@ + [0x280c558] .?AVBaseImageDecoder@cv@@ + [0x280c658] .?AVBmpDecoder@cv@@ + [0x280c6f8] .?AVSunRasterDecoder@cv@@ + [0x280c758] .?AVJpegDecoder@cv@@ + [0x280c7a8] .?AVPxMDecoder@cv@@ + [0x280c7f8] .?AVPFMDecoder@cv@@ + [0x280c848] .?AVTiffDecoder@cv@@ + [0x280c900] .?AVPngDecoder@cv@@ + [0x280c950] .?AVHdrDecoder@cv@@ + [0x280c9a0] .?AVPAMDecoder@cv@@ + [0x280fa78] .?AVresizeNNInvoker@cv@@ + [0x280faa8] .?AVresizeNN_bitexactInvoker@cv@@ + [0x280fae0] .?AV?$resizeGeneric_Invoker@U?$HResizeLinear@EHF$0IAA@UHResizeLinearVecU8_X4@cv@@@cv@@U?$VResizeLinear@EHFU?$FixedPtCast@HE$0BG@@cv@@UVResizeLinearVec_32s8u@2@@2@@cv@@ + [0x280fba0] .?AV?$resizeGeneric_Invoker@U?$HResizeLinear@GMM$00U?$HResizeLinearVec_X4@GMMUv_float32x4@hal_baseline@cv@@@cv@@@cv@@U?$VResizeLinear@GMMU?$Cast@MG@cv@@UVResizeLinearVec_32f16u@2@@2@@cv@@ + [0x280fc70] .?AV?$resizeGeneric_Invoker@U?$HResizeLinear@FMM$00U?$HResizeLinearVec_X4@FMMUv_float32x4@hal_baseline@cv@@@cv@@@cv@@U?$VResizeLinear@FMMU?$Cast@MF@cv@@UVResizeLinearVec_32f16s@2@@2@@cv@@ + [0x280fd40] .?AV?$resizeGeneric_Invoker@U?$HResizeLinear@MMM$00U?$HResizeLinearVec_X4@MMMUv_float32x4@hal_baseline@cv@@@cv@@@cv@@U?$VResizeLinear@MMMU?$Cast@MM@cv@@UVResizeLinearVec_32f@2@@2@@cv@@ + [0x280fe10] .?AV?$resizeGeneric_Invoker@U?$HResizeLinear@NNM$00UHResizeNoVec@cv@@@cv@@U?$VResizeLinear@NNMU?$Cast@NN@cv@@UVResizeNoVec@2@@2@@cv@@ + [0x280feb0] .?AV?$resizeGeneric_Invoker@U?$HResizeCubic@EHF@cv@@U?$VResizeCubic@EHFU?$FixedPtCast@HE$0BG@@cv@@UVResizeCubicVec_32s8u@2@@2@@cv@@ + [0x280ff50] .?AV?$resizeGeneric_Invoker@U?$HResizeCubic@GMM@cv@@U?$VResizeCubic@GMMU?$Cast@MG@cv@@UVResizeCubicVec_32f16u@2@@2@@cv@@ + [0x280ffe0] .?AV?$resizeGeneric_Invoker@U?$HResizeCubic@FMM@cv@@U?$VResizeCubic@FMMU?$Cast@MF@cv@@UVResizeCubicVec_32f16s@2@@2@@cv@@ + [0x2810070] .?AV?$resizeGeneric_Invoker@U?$HResizeCubic@MMM@cv@@U?$VResizeCubic@MMMU?$Cast@MM@cv@@UVResizeCubicVec_32f@2@@2@@cv@@ + [0x2810100] .?AV?$resizeGeneric_Invoker@U?$HResizeCubic@NNM@cv@@U?$VResizeCubic@NNMU?$Cast@NN@cv@@UVResizeNoVec@2@@2@@cv@@ + [0x2810180] .?AV?$resizeGeneric_Invoker@U?$HResizeLanczos4@EHF@cv@@U?$VResizeLanczos4@EHFU?$FixedPtCast@HE$0BG@@cv@@UVResizeNoVec@2@@2@@cv@@ + [0x2810220] .?AV?$resizeGeneric_Invoker@U?$HResizeLanczos4@GMM@cv@@U?$VResizeLanczos4@GMMU?$Cast@MG@cv@@UVResizeLanczos4Vec_32f16u@2@@2@@cv@@ + [0x28102c0] .?AV?$resizeGeneric_Invoker@U?$HResizeLanczos4@FMM@cv@@U?$VResizeLanczos4@FMMU?$Cast@MF@cv@@UVResizeLanczos4Vec_32f16s@2@@2@@cv@@ + [0x2810360] .?AV?$resizeGeneric_Invoker@U?$HResizeLanczos4@MMM@cv@@U?$VResizeLanczos4@MMMU?$Cast@MM@cv@@UVResizeLanczos4Vec_32f@2@@2@@cv@@ + [0x28103f0] .?AV?$resizeGeneric_Invoker@U?$HResizeLanczos4@NNM@cv@@U?$VResizeLanczos4@NNMU?$Cast@NN@cv@@UVResizeNoVec@2@@2@@cv@@ + [0x2810480] .?AV?$resizeAreaFast_Invoker@EHU?$ResizeAreaFastVec@EVResizeAreaFastVec_SIMD_8u@cv@@@cv@@@cv@@ + [0x28104f0] .?AV?$resizeAreaFast_Invoker@GMU?$ResizeAreaFastVec@GVResizeAreaFastVec_SIMD_16u@cv@@@cv@@@cv@@ + [0x2810560] .?AV?$resizeAreaFast_Invoker@FMU?$ResizeAreaFastVec@FVResizeAreaFastVec_SIMD_16s@cv@@@cv@@@cv@@ + [0x28105d0] .?AV?$resizeAreaFast_Invoker@MMUResizeAreaFastVec_SIMD_32f@cv@@@cv@@ + [0x2810630] .?AV?$resizeAreaFast_Invoker@NNU?$ResizeAreaFastNoVec@NN@cv@@@cv@@ + [0x2810688] .?AV?$ResizeArea_Invoker@EM@cv@@ + [0x28106c0] .?AV?$ResizeArea_Invoker@GM@cv@@ + [0x28106f8] .?AV?$ResizeArea_Invoker@FM@cv@@ + [0x2810730] .?AV?$ResizeArea_Invoker@MM@cv@@ + [0x2810768] .?AV?$ResizeArea_Invoker@NN@cv@@ + [0x28107a0] .?AV?$resize_bitExactInvoker@EVufixedpoint16@?A0x9e38116f@@$01@?A0x9e38116f@@ + [0x2810800] .?AV?$resize_bitExactInvoker@CVfixedpoint32@?A0x9e38116f@@$01@?A0x9e38116f@@ + [0x2810860] .?AV?$resize_bitExactInvoker@GVufixedpoint32@?A0x9e38116f@@$01@?A0x9e38116f@@ + [0x28108c0] .?AV?$resize_bitExactInvoker@FVfixedpoint32@?A0x9e38116f@@$01@?A0x9e38116f@@ + [0x2810920] .?AV?$resize_bitExactInvoker@HVfixedpoint64@?A0x9e38116f@@$01@?A0x9e38116f@@ + [0x2810980] .?AVThresholdRunner@cv@@ + [0x28109d8] .?AVWarpAffineInvoker@cv@@ + [0x281a900] .?AVresizeNNInvokerAVX4@opt_AVX2@cv@@ + [0x281a938] .?AVresizeNNInvokerAVX2@opt_AVX2@cv@@ + [0x281a970] .?AVresizeNNInvokerSSE2@opt_SSE4_1@cv@@ + [0x281a9a8] .?AVresizeNNInvokerSSE4@opt_SSE4_1@cv@@ + [0x2826028] .?AVLanguageBreakEngine@icu_71@@ + [0x2826060] .?AVLanguageBreakFactory@icu_71@@ + [0x28260c8] .?AVICULanguageBreakFactory@icu_71@@ + [0x2826e80] .?AV?$_Func_impl_no_alloc@V@?9??ParallelForFixedBlockSizeScheduling@ThreadPool@concurrency@onnxruntime@@AEAAX_J0AEBV?$function@$$A6AX_J0@Z@std@@@Z@XI@std@@ + [0x2826f40] .?AV?$_Func_impl_no_alloc@V@?M@??ParallelForFixedBlockSizeScheduling@ThreadPool@concurrency@onnxruntime@@AEAAX_J0AEBV?$function@$$A6AX_J0@Z@std@@@Z@XI@std@@ + [0x2827000] .?AV?$_Func_impl_no_alloc@V@?1??SimpleParallelFor@ThreadPool@concurrency@onnxruntime@@AEAAX_JAEBV?$function@$$A6AX_J@Z@std@@@Z@X_J_J@std@@ + [0x2827330] .?AVCacheLocalScheduleGroupSegment@details@Concurrency@@ + [0x2827380] .?AVScheduleGroupSegmentBase@details@Concurrency@@ + [0x28273d0] .?AVFairScheduleGroupSegment@details@Concurrency@@ + [0x2828070] .?AV?$MapEntryImpl@VPipelineMetrics_ScriptMetricsEntry_DoNotUse@Interop@OneOCR@@VMessage@protobuf@google@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@H$08$04@internal@protobuf@google@@ + [0x2828180] .?AV?$MapEntry@VPipelineMetrics_ScriptMetricsEntry_DoNotUse@Interop@OneOCR@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@H$08$04@internal@protobuf@google@@ + [0x28282d0] .?AV?$MapField@VPipelineMetrics_ScriptMetricsEntry_DoNotUse@Interop@OneOCR@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@H$08$04@internal@protobuf@google@@ + [0x2828410] .?AV?$TensorMapBase@U?$pair@V?$variant@V?$vector@MV?$allocator@M@std@@@std@@V?$vector@HV?$allocator@H@std@@@2@V?$vector@_JV?$allocator@_J@std@@@2@V?$vector@EV?$allocator@E@std@@@2@V?$vector@DV?$allocator@D@std@@@2@V?$vector@GV?$allocator@G@std@@@2@@std@@V?$vector@_JV?$allocator@_J@std@@@2@@std@@@OneOCR@@ + [0x28285c0] .?AVSimpleTensorMap@OneOCR@@ + [0x2828670] .?AVTextPipelineDevImpl@OneOCR@@ + [0x2828710] .?AV?$_Ref_count_obj2@VEnumMapper@OneOCR@@@std@@ + [0x2828760] .?AV?$_Func_impl_no_alloc@V@?0???0ThreadPool@OneOCR@@QEAA@_K@Z@X$$V@std@@ + [0x2828b10] .?AV?$_Ref_count_obj2@VTextLine@OneOCR@@@std@@ + [0x2828c60] .?AV?$_Func_impl_no_alloc@V@?M@??RecognizeTextLines@TextPipelineDevImpl@OneOCR@@UEBA?AUTextRecognitionResult@4@AEAV?$vector@V?$unique_ptr@VTextLine@OneOCR@@U?$default_delete@VTextLine@OneOCR@@@std@@@std@@V?$allocator@V?$unique_ptr@VTextLine@OneOCR@@U?$default_delete@VTextLine@OneOCR@@@std@@@std@@@2@@std@@AEBUProcessOption@4@QEAVPipelineMetrics@Interop@4@V?$optional@V?$reference_wrapper@VImageFeature@OneOCR@@@std@@@7@@Z@_NAEB_KAEB_K@std@@ + [0x2828f68] .?AVTextPipelineDev@OneOCR@@ + [0x2828fc0] .?AVITensorMapView@OneOCR@@ + [0x2829038] .?AUTextLineDebugInfo@OneOCR@@ + [0x2829068] .?AVPipeline@OneOCR@@ + [0x28290b8] .?AVTextPipeline@OneOCR@@ + [0x28290e8] .?AV?$SingleThreadPool@$0A@@OneOCR@@ + [0x2829120] .?AVRawConcatTextLines@OneOCR@@ + [0x28291b0] .?AV?$_Func_impl_no_alloc@V@?3???R@?3??alloc@ThreadPool@OneOCR@@QEAA?AVContext@45@_K@Z@QEBA@XZ@X$$V@std@@ + [0x28292a8] .?AVTextAnalyzerImpl@OneOCR@@ + [0x28292d8] .?AVTextAnalyzer@OneOCR@@ + [0x2829648] .?AVBaseClassifier@OneOCR@@ + [0x2829fa8] .?AVLineLayoutInterface@OneOCR@@ + [0x282ac40] .?AV?$_Func_impl_no_alloc@V@?4??Analyze@TextAnalyzerImpl@OneOCR@@UEBAXAEAV?$vector@V?$unique_ptr@VTextLine@OneOCR@@U?$default_delete@VTextLine@OneOCR@@@std@@@std@@V?$allocator@V?$unique_ptr@VTextLine@OneOCR@@U?$default_delete@VTextLine@OneOCR@@@std@@@std@@@2@@std@@AEBUProcessOption@4@AEAVPipelineMetrics_AnalyzerMetrices@Interop@4@@Z@W4TextLineLayout@4@_K@std@@ + [0x282add0] .?AV?$_Func_base@W4TextLineLayout@OneOCR@@_K@std@@ + [0x282b158] .?AVAuxMltClsClassifierFixedWidth@OneOCR@@ + [0x282bdb0] .?AVUnownedTensorMap@OneOCR@@ + [0x282c178] .?AVLineLayoutClassifier@OneOCR@@ + [0x282c1b0] .?AVFontClassifier@OneOCR@@ + [0x282c1e0] .?AV?$_Func_base@PEAVILattice@OneOCR@@$$V@std@@ + [0x282c220] .?AV?$_Func_base@PEAVConfidenceProcessor@OneOCR@@$$V@std@@ + [0x282c270] .?AV?$_Func_impl_no_alloc@V?$_Binder@U_Unforced@std@@V?$_Mem_fn@P8TextLineRecognizerImpl@OneOCR@@EAAPEAVCnnDbLstm@2@AEBVCharProto@2@AEBVModelParser@2@@Z@2@PEAVTextLineRecognizerImpl@OneOCR@@AEBVCharProto@5@AEAVModelParser@5@@std@@PEAVCnnDbLstm@OneOCR@@$$V@std@@ + [0x282c388] .?AVTextLineRecognizer@OneOCR@@ + [0x282c3b8] .?AVArgMaxDecoder@OneOCR@@ + [0x282c410] .?AV?$_Func_impl_no_alloc@V@?1??BatchRecognize@TextLineRecognizerImpl@OneOCR@@UEBA?AV?$vector@URecognizerTextLineResult@OneOCR@@V?$allocator@URecognizerTextLineResult@OneOCR@@@std@@@std@@AEBVConcatTextLines@4@AEBUProcessOption@4@AEAUAtomicRecognizerMetrics@4@PEAVThreadPool@4@@Z@X$$V@std@@ + [0x282c550] .?AV?$_Func_impl_no_alloc@V@?1??Recognize@TextLineRecognizerImpl@OneOCR@@UEBA?AURecognizerTextLineResult@4@AEAVTextLine@4@AEBUProcessOption@4@AEAUAtomicRecognizerMetrics@4@@Z@X$$V@std@@ + [0x282c628] .?AVAutoGlobalInit@OneOCR@@ + [0x282c660] .?AV?$_Func_base@PEAVIDecoder@OneOCR@@$$V@std@@ + [0x282c6a0] .?AV?$_Func_impl_no_alloc@V?$_Binder@U_Unforced@std@@V?$_Mem_fn@P8TextLineRecognizerImpl@OneOCR@@EAAPEAVILattice@2@AEBVDecoderProto@2@AEBVModelParser@2@@Z@2@PEAVTextLineRecognizerImpl@OneOCR@@AEBVDecoderProto@5@AEAVModelParser@5@@std@@PEAVILattice@OneOCR@@$$V@std@@ + [0x282c7c0] .?AVTextLineRecognizerImpl@OneOCR@@ + [0x282c800] .?AV?$_Func_impl_no_alloc@V@?1??RecognizeWithTextLineFeature@TextLineRecognizerImpl@OneOCR@@UEBA?AURecognizerTextLineResult@4@AEBUTextLineFeature@4@AEAVTextLine@4@AEBUProcessOption@4@AEAUAtomicRecognizerMetrics@4@@Z@X$$V@std@@ + [0x282c900] .?AV?$_Func_base@PEAVCnnDbLstm@OneOCR@@$$V@std@@ + [0x282c950] .?AV?$_Ref_count_obj2@VCscMatrix@OneOCR@@@std@@ + [0x282c990] .?AVCnnDbLstm@OneOCR@@ + [0x282c9c0] .?AV?$_Func_impl_no_alloc@V?$_Binder@U_Unforced@std@@V?$_Mem_fn@P8TextLineRecognizerImpl@OneOCR@@EAAPEAVConfidenceProcessor@2@AEBVConfidenceProto@2@AEBVModelParser@2@@Z@2@PEAVTextLineRecognizerImpl@OneOCR@@AEBVConfidenceProto@5@AEAVModelParser@5@@std@@PEAVConfidenceProcessor@OneOCR@@$$V@std@@ + [0x282caf8] .?AURecognizerTextLineDebugInfo@OneOCR@@ + [0x282cb38] .?AVILattice@OneOCR@@ + [0x282cb60] .?AV?$_Func_base@PEAVRejectionProcessor@OneOCR@@$$V@std@@ + [0x282cbb0] .?AV?$_Func_impl_no_alloc@V@?7??ProcessLogSoftmaxScores@TextLineRecognizerImpl@OneOCR@@IEBA?AURecognizerTextLineResult@4@AEBVCscMatrixView@4@AEBVTextLine@4@_NPEBVCharacterMapper@CharacterMap@4@PEBVCnnDbLstm@4@PEBVIDecoder@4@PEBVILattice@4@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@77AEBUProcessOption@4@AEAUAtomicRecognizerMetrics@4@@Z@X$$V@std@@ + [0x282cfb0] .?AVCnnDbLstmTiered@OneOCR@@ + [0x282cfe0] .?AV?$_Ref_count_obj2@VXnnResult@OneOCR@@@std@@ + [0x282d020] .?AVLat@LatMBRAdapter@OneOCR@@ + [0x282d050] .?AV?$_Func_impl_no_alloc@V?$_Binder@U_Unforced@std@@V?$_Mem_fn@P8TextLineRecognizerImpl@OneOCR@@EAAPEAVRejectionProcessor@2@AEBVRejectionProto@2@AEBVModelParser@2@@Z@2@PEAVTextLineRecognizerImpl@OneOCR@@AEBVRejectionProto@5@AEAVModelParser@5@@std@@PEAVRejectionProcessor@OneOCR@@$$V@std@@ + [0x282d190] .?AV?$_Func_impl_no_alloc@V?$_Binder@U_Unforced@std@@V?$_Mem_fn@P8TextLineRecognizerImpl@OneOCR@@EAAPEAVIDecoder@2@AEBVDecoderProto@2@AEBVModelParser@2@V?$optional@V?$reference_wrapper@VCustomFstProto@OneOCR@@@std@@@std@@@Z@2@PEAVTextLineRecognizerImpl@OneOCR@@AEBVDecoderProto@5@AEAVModelParser@5@AEAV?$optional@V?$reference_wrapper@VCustomFstProto@OneOCR@@@std@@@2@@std@@PEAVIDecoder@OneOCR@@$$V@std@@ + [0x282d550] .?AVArgMaxLattice@OneOCR@@ + [0x282d930] .?AV?$_Func_impl_no_alloc@V@?1??LoadPhoneMap@CharacterMapper@CharacterMap@OneOCR@@IEBA?AV?$vector@HV?$allocator@H@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@7@AEBVModelParser@5@@Z@XAEAV87@@std@@ + [0x282da30] .?AV?$_Ref_count_resource@PEAUCharToken@CharacterMap@OneOCR@@U?$default_delete@$$BY0A@UCharToken@CharacterMap@OneOCR@@@std@@@std@@ + [0x282dfa0] .?AV?$_Func_impl_no_alloc@V@?1??InitCompositeCharMap@CharacterMapper@CharacterMap@OneOCR@@IEAAXAEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEBVModelParser@5@@Z@XAEAV67@@std@@ + [0x282e190] .?AV?$_Func_impl_no_alloc@V@?1??Process@Lat@LatMBRAdapter@OneOCR@@UEBA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEAUDecoderResult@5@AEAV?$vector@ULatticeResult@OneOCR@@V?$allocator@ULatticeResult@OneOCR@@@std@@@7@AEBUProcessOption@5@H@Z@XHHAEBV67@MAEBV?$vector@U?$pair@HH@std@@V?$allocator@U?$pair@HH@std@@@2@@7@@std@@ + [0x282e300] .?AVCDynamicCacheDecode@LatDec@@ + [0x282e338] .?AVCDecode@LatDec@@ + [0x282e3f0] .?AV?$_Func_impl_no_alloc@V@?1??Process@Lat@LatMBRAdapter@OneOCR@@UEBA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEAUDecoderResult@5@AEAV?$vector@ULatticeResult@OneOCR@@V?$allocator@ULatticeResult@OneOCR@@@std@@@7@AEBUProcessOption@5@H@Z@XHHAEBV67@MAEBV?$vector@U?$pair@HH@std@@V?$allocator@U?$pair@HH@std@@@2@@7@@std@@ + [0x282e610] .?AV?$_Func_impl_no_alloc@V?$_Binder@U_Unforced@std@@V?$_Mem_fn@P8CnnDbLstmTiered@OneOCR@@EAAPEAVCnnDbLstm@2@AEBVCharProto@2@AEBVTieredModelPack@2@AEBVModelParser@2@W4PipelineProto_EngineType@2@@Z@2@PEAVCnnDbLstmTiered@OneOCR@@AEBVCharProto@5@AEBVTieredModelPack@5@AEBVModelParser@5@AEAW4PipelineProto_EngineType@5@@std@@PEAVCnnDbLstm@OneOCR@@$$V@std@@ + [0x282e7c0] .?AVTextNormalizer@OneOCR@@ + [0x282e7f0] .?AVBaseNormalizer@OneOCR@@ + [0x282eeb8] .?AVTextDetector@OneOCR@@ + [0x282eee8] .?AVIModelInferencer@OneOCR@@ + [0x282ef18] .?AVTextDetectorImpl@OneOCR@@ + [0x282ef48] .?AVDQDETR@OneOCR@@ + [0x282ef70] .?AV?$_Ref_count@VRelationRCNN@OneOCR@@@std@@ + [0x282efb0] .?AV?$_Ref_count@VRelationRCNNRpn@OneOCR@@@std@@ + [0x282eff8] .?AVCommonNN@OneOCR@@ + [0x282f020] .?AVCommonRCNN@OneOCR@@ + [0x282f050] .?AV?$_Ref_count_resource@PEAVDQDETR@OneOCR@@U?$default_delete@VDQDETR@OneOCR@@@std@@@std@@ + [0x282f0c0] .?AVBaseRCNN@OneOCR@@ + [0x282f0f0] .?AV?$_Ref_count@VRelationRCNNRpn2FixedSize@OneOCR@@@std@@ + [0x282f140] .?AV?$_Ref_count@VBaseRCNN@OneOCR@@@std@@ + [0x282f180] .?AV?$_Ref_count@VRelationRCNNRpn2@OneOCR@@@std@@ + [0x282f1c8] .?AVRelationRCNN@OneOCR@@ + [0x282f1f8] .?AVRelationRCNNRpn2FixedSize@OneOCR@@ + [0x282f230] .?AVRelationRCNNRpn2@OneOCR@@ + [0x282f260] .?AVRelationRCNNRpn@OneOCR@@ + [0x282f6b0] .?AV?$_Ref_count@VTextLinePolygon@OneOCR@@@std@@ + [0x282f700] .?AV?$_Ref_count_obj2@VTextLinePolygon@OneOCR@@@std@@ + [0x28302e0] .?AV?$_Ref_count_obj2@UBarcodePolygon@OneOCR@@@std@@ + [0x28308b0] .?AV?$_Func_impl_no_alloc@V@?1??RunInference@BaseRCNN@OneOCR@@MEBA?AV?$unique_ptr@VITensorMapView@OneOCR@@U?$default_delete@VITensorMapView@OneOCR@@@std@@@std@@AEBVSimpleTensorMap@4@AEAVPipelineMetrics_DetectorMetrics@Interop@4@AEBUProcessOption@4@_N@Z@X$$V@std@@ + [0x2830fe0] .?AV?$_Ref_count_obj2@VCheckboxResult_Checkbox@Interop@OneOCR@@@std@@ + [0x28314d0] .?AV?$_Func_impl_no_alloc@V@?1??RunInference@DQDETR@OneOCR@@MEBA?AV?$unique_ptr@VITensorMapView@OneOCR@@U?$default_delete@VITensorMapView@OneOCR@@@std@@@std@@AEBVSimpleTensorMap@4@AEAVPipelineMetrics_DetectorMetrics@Interop@4@AEBUProcessOption@4@_N@Z@X$$V@std@@ + [0x28315f0] .?AV?$_Ref_count_resource@PEAVTextLinePolygon@OneOCR@@U?$default_delete@VTextLinePolygon@OneOCR@@@std@@@std@@ + [0x2832e20] .?AVINNFramework@OneOCR@@ + [0x2832e50] .?AVOrtQnnFramework@OneOCR@@ + [0x2832e80] .?AVOrtFramework@OneOCR@@ + [0x2832eb0] .?AVOrtCudaFramework@OneOCR@@ + [0x2832ee0] .?AVOrtTensorRTFramework@OneOCR@@ + [0x2832f18] .?AVOrtTensorMapView@OrtInference@@ + [0x2832f50] .?AV?$TensorMapBase@UValue@Ort@@@OneOCR@@ + [0x2833170] .?AV?$_Func_impl_no_alloc@V@?1??Cipher@OneOCR@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEBV45@0_N1@Z@X$$V@std@@ + [0x2833220] .?AV?$_Func_impl_no_alloc@V@?1??Cipher@OneOCR@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEBV45@0_N1@Z@X$$V@std@@ + [0x28332d0] .?AV?$_Func_impl_no_alloc@V@?1??SHA256Hash@OneOCR@@YA?AV?$array@W4byte@std@@$0CA@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@@Z@X$$V@std@@ + [0x2833390] .?AV?$_Func_impl_no_alloc@V@?1??SHA256Hash@OneOCR@@YA?AV?$array@W4byte@std@@$0CA@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@@Z@X$$V@std@@ + [0x28339f0] .?AVCodec@Utility@OneOCR@@ + [0x2833b70] .?AV?$_Func_impl_no_alloc@V@?1??ConvertTextV2L_ICU@Utility@OneOCR@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEBV56@AEAV?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@6@AEAV?$vector@_KV?$allocator@_K@std@@@6@AEAV?$vector@U?$pair@_K_K@std@@V?$allocator@U?$pair@_K_K@std@@@2@@6@@Z@X$$V@std@@ + [0x2833d30] .?AV?$MapEntry@VPipelineProto_RuntimeOption_RuntimeOptionEntry_DoNotUse@OneOCR@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V34@$08$08@internal@protobuf@google@@ + [0x2833e00] .?AV?$MapEntry@VDetectorProto_TextlineConfThresholdEntry_DoNotUse@OneOCR@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@M$08$01@internal@protobuf@google@@ + [0x2833ec0] .?AV?$MapEntry@VAuxMltClsProto_ScriptConsecutiveFramesThresholdEntry_DoNotUse@OneOCR@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@_J$08$02@internal@protobuf@google@@ + [0x2833f90] .?AV?$MapEntryImpl@VAuxMltClsProto_ScriptConsecutiveFramesThresholdEntry_DoNotUse@OneOCR@@VMessage@protobuf@google@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@_J$08$02@internal@protobuf@google@@ + [0x2834080] .?AV?$MapEntryImpl@VCustomScenarioProto_GrammarLmEntry_DoNotUse@OneOCR@@VMessage@protobuf@google@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V67@$08$08@internal@protobuf@google@@ + [0x2834160] .?AV?$MapField@VCustomScenarioProto_GrammarLmEntry_DoNotUse@OneOCR@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V34@$08$08@internal@protobuf@google@@ + [0x2834220] .?AV?$MapEntryImpl@VDetectorProto_TextlineConfThresholdEntry_DoNotUse@OneOCR@@VMessage@protobuf@google@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@M$08$01@internal@protobuf@google@@ + [0x2834300] .?AV?$MapEntry@VCustomScenarioProto_GrammarLmEntry_DoNotUse@OneOCR@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V34@$08$08@internal@protobuf@google@@ + [0x28343c0] .?AV?$MapEntry@VTensorMapProto_TensorsEntry_DoNotUse@OneOCR@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@VTensorMapProto_Tensor@2@$08$0L@@internal@protobuf@google@@ + [0x2834490] .?AV?$TypeDefinedMapFieldBase@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@VTensorMapProto_Tensor@OneOCR@@@internal@protobuf@google@@ + [0x2834540] .?AV?$MapEntryImpl@VPipelineProto_RuntimeOption_RuntimeOptionEntry_DoNotUse@OneOCR@@VMessage@protobuf@google@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V67@$08$08@internal@protobuf@google@@ + [0x28347e0] .?AV?$MapField@VDetectorProto_TextlineConfThresholdEntry_DoNotUse@OneOCR@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@M$08$01@internal@protobuf@google@@ + [0x28348a0] .?AV?$MapField@VAuxMltClsProto_ScriptConsecutiveFramesThresholdEntry_DoNotUse@OneOCR@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@_J$08$02@internal@protobuf@google@@ + [0x2834970] .?AV?$MapField@VPipelineProto_RuntimeOption_RuntimeOptionEntry_DoNotUse@OneOCR@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V34@$08$08@internal@protobuf@google@@ + [0x2834a40] .?AV?$MapField@VTensorMapProto_TensorsEntry_DoNotUse@OneOCR@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@VTensorMapProto_Tensor@2@$08$0L@@internal@protobuf@google@@ + [0x2834b10] .?AV?$MapEntryImpl@VTensorMapProto_TensorsEntry_DoNotUse@OneOCR@@VMessage@protobuf@google@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@VTensorMapProto_Tensor@2@$08$0L@@internal@protobuf@google@@ + [0x2834c00] .?AV?$_Func_base@X$$QEAVMathFmParagraphProto@OneOCR@@@std@@ + [0x2834c50] .?AV?$_Func_base@X$$QEAVDetectorProto@OneOCR@@@std@@ + [0x2834ca0] .?AV?$_Func_impl_no_alloc@V@?N@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVTableRecognizerProto@3@@std@@ + [0x2834d40] .?AV?$_Func_impl_no_alloc@V@?BJ@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVMathFmLineAttnProto@3@@std@@ + [0x2834de0] .?AV?$_Func_base@X$$QEAVMathFmLineDecProto@OneOCR@@@std@@ + [0x2834e30] .?AV?$_Func_base@X$$QEAVMathFmLineEncProto@OneOCR@@@std@@ + [0x2834e80] .?AV?$_Func_base@X$$QEAVRejectionProto@OneOCR@@@std@@ + [0x2834ed0] .?AV?$_Func_base@X$$QEAVPODRegionGroupingProto@OneOCR@@@std@@ + [0x2834f20] .?AV?$_Func_base@X$$QEAVMathFmLineRejProto@OneOCR@@@std@@ + [0x2834f70] .?AV?$_Func_impl_no_alloc@V@?3??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVAuxMltClsProto@3@@std@@ + [0x2835010] .?AV?$_Func_impl_no_alloc@V@?BD@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVTextEmbeddingProto@3@@std@@ + [0x28350b0] .?AV?$_Func_base@X$$QEAVTableRecognizerProto@OneOCR@@@std@@ + [0x2835100] .?AV?$_Func_base@X$$QEAVFontClsProto@OneOCR@@@std@@ + [0x2835150] .?AV?$_Func_base@X$$QEAVPODReadingOrderProto@OneOCR@@@std@@ + [0x28351a0] .?AV?$_Func_impl_no_alloc@V@?BM@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVTOCProto@3@@std@@ + [0x2835240] .?AV?$_Func_impl_no_alloc@V@?L@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVCheckboxDetectorProto@3@@std@@ + [0x28352e0] .?AV?$_Func_base@X$$QEAVLangIDProto@OneOCR@@@std@@ + [0x2835330] .?AV?$_Func_impl_no_alloc@V@?9??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVConfidenceProto@3@@std@@ + [0x28353d0] .?AV?$_Func_base@X$$QEAVAuxMltClsProto@OneOCR@@@std@@ + [0x2835420] .?AV?$_Func_impl_no_alloc@V@?BL@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVMathFmParagraphProto@3@@std@@ + [0x28354c0] .?AV?$_Func_base@X$$QEAVMathFmLineAttnProto@OneOCR@@@std@@ + [0x2835510] .?AV?$_Func_base@X$$QEAVCharProto@OneOCR@@@std@@ + [0x2835560] .?AV?$_Func_base@X$$QEAVPODBackboneProto@OneOCR@@@std@@ + [0x28355b0] .?AV?$_Func_impl_no_alloc@V@?8??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVRejectionProto@3@@std@@ + [0x2835650] .?AV?$_Func_impl_no_alloc@V@?2??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVDetectorProto@3@@std@@ + [0x28356f0] .?AV?$_Func_impl_no_alloc@V@?BC@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVPODReadingOrderProto@3@@std@@ + [0x2835790] .?AV?$_Func_impl_no_alloc@V@?BF@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVCustomFstProto@3@@std@@ + [0x2835830] .?AV?$_Func_base@X$$QEAVMathFmDetProto@OneOCR@@@std@@ + [0x2835880] .?AV?$_Func_base@X$$QEAVCheckboxDetectorProto@OneOCR@@@std@@ + [0x28358d0] .?AV?$_Func_impl_no_alloc@V@?O@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVLangIDProto@3@@std@@ + [0x2835970] .?AV?$_Func_impl_no_alloc@V@?7??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVDecoderProto@3@@std@@ + [0x2835a10] .?AV?$_Func_base@X$$QEAVTextEmbeddingProto@OneOCR@@@std@@ + [0x2835a60] .?AV?$_Func_impl_no_alloc@V@?BB@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVPODRegionGroupingProto@3@@std@@ + [0x2835b60] .?AV?$_Func_impl_no_alloc@V@?BH@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVMathFmLineDecProto@3@@std@@ + [0x2835c00] .?AV?$_Func_base@X$$QEAVTOCProto@OneOCR@@@std@@ + [0x2835c40] .?AV?$_Func_base@X$$QEAVEntityClassifierProto@OneOCR@@@std@@ + [0x2835c90] .?AV?$_Func_impl_no_alloc@V@?BG@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVMathFmDetProto@3@@std@@ + [0x2835d30] .?AV?$_Func_base@X$$QEAVFormDetectorProto@OneOCR@@@std@@ + [0x2835d80] .?AV?$_Func_base@X$$QEAVLineLayoutClsProto@OneOCR@@@std@@ + [0x2835dd0] .?AV?$_Func_base@X$$QEAVDecoderProto@OneOCR@@@std@@ + [0x2835e20] .?AV?$_Func_base@X$$QEAVConfidenceProto@OneOCR@@@std@@ + [0x2835e70] .?AV?$_Func_base@X$$QEAVTableDetectorProto@OneOCR@@@std@@ + [0x2835ec0] .?AV?$_Func_impl_no_alloc@V@?4??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVLineLayoutClsProto@3@@std@@ + [0x2835f60] .?AV?$_Func_impl_no_alloc@V@?5??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVFontClsProto@3@@std@@ + [0x2836000] .?AV?$_Func_impl_no_alloc@V@?BI@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVMathFmLineRejProto@3@@std@@ + [0x28360a0] .?AV?$_Func_impl_no_alloc@V@?BA@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVPODBackboneProto@3@@std@@ + [0x2836140] .?AV?$_Func_impl_no_alloc@V@?P@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVFormDetectorProto@3@@std@@ + [0x28361e0] .?AV?$_Func_impl_no_alloc@V@?BE@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVEntityClassifierProto@3@@std@@ + [0x2836280] .?AV?$_Func_impl_no_alloc@V@?BK@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVMathFmLineEncProto@3@@std@@ + [0x2836320] .?AV?$_Func_base@X$$QEAVCustomFstProto@OneOCR@@@std@@ + [0x2836370] .?AV?$_Func_impl_no_alloc@V@?6??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVCharProto@3@@std@@ + [0x2836400] .?AV?$_Func_impl_no_alloc@V@?M@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVTableDetectorProto@3@@std@@ + +Total: 2178 relevant strings diff --git a/_archive/temp/re_output/13_mangled_names.txt b/_archive/temp/re_output/13_mangled_names.txt new file mode 100644 index 0000000000000000000000000000000000000000..a87e77a4030a2ee22abbfd6da0c55a2fb620b66d --- /dev/null +++ b/_archive/temp/re_output/13_mangled_names.txt @@ -0,0 +1,603 @@ +ALL OneOCR MANGLED NAMES (raw) +============================================================ + [0x2711678] OneOCR.Interop" + [0x27116c8] .OneOCR.Interop.Point + [0x271174b] .OneOCR.Interop.Point" + [0x2711b78] 2/.OneOCR.Interop.PipelineMetrics.DetectorMetrics + [0x2711bc5] 2!.OneOCR.Interop.NormalizerMetrics + [0x2711c02] 20.OneOCR.Interop.PipelineMetrics.AnalyzerMetrices + [0x2711c50] 21.OneOCR.Interop.PipelineMetrics.RecognizerMetrics + [0x2711c9b] 22.OneOCR.Interop.PipelineMetrics.ScriptMetricsEntry + [0x2711ce9] 2/.OneOCR.Interop.PipelineMetrics.DispatchMetrics + [0x2711d33] 2(.OneOCR.Interop.BarcodeRecognizerMetrics + [0x2711d7c] 24.OneOCR.Interop.PipelineMetrics.PostAnalyzerMetrices + [0x2711dcf] 2*.OneOCR.Interop.MathFormulaPipelineMetrics + [0x2712457] 21.OneOCR.Interop.TableMetrics.TableDetectorMetrics + [0x27124a1] 23.OneOCR.Interop.TableMetrics.TableRecognizerMetrics + [0x2712767] 2-.OneOCR.Interop.PODMetrics.PODBackboneMetrics + [0x27127bb] 23.OneOCR.Interop.PODMetrics.PODRegionGroupingMetrics + [0x2712813] 21.OneOCR.Interop.PODMetrics.PODReadingOrderMetrics + [0x27128c9] 2&.OneOCR.Interop.PODMetrics.FormMetrics + [0x2712c4b] 2:.OneOCR.Interop.MathFormulaPipelineMetrics.DetectorMetrics + [0x2712ca2] 2;.OneOCR.Interop.MathFormulaPipelineMetrics.ParagraphMetrics + [0x2712cfb] 2<.OneOCR.Interop.MathFormulaPipelineMetrics.RecognizerMetrics + [0x2712f93] 2,.OneOCR.Interop.TextRecognitionResult.Region + [0x2713013] .OneOCR.Interop.Quadrangle + [0x271303c] 2*.OneOCR.Interop.TextRecognitionResult.Line + [0x27130c3] 2%.OneOCR.Interop.Enums.ConfidenceClass + [0x2713139] 23.OneOCR.Interop.TextRecognitionResult.WordCandidate + [0x27132e9] .OneOCR.Interop.Enums.WordType + [0x271337a] 23.OneOCR.Interop.TextRecognitionResult.LineCandidate + [0x27133be] 2*.OneOCR.Interop.TextRecognitionResult.Word + [0x2713433] 2".OneOCR.Interop.Enums.TextCategory + [0x271346b] 2/.OneOCR.Interop.TextRecognitionResult.DebugInfo + [0x27134c4] 2 .OneOCR.Interop.Enums.TextScript + [0x27134f9] .OneOCR.Interop.Enums.LangID + [0x271360d] 2%.OneOCR.Interop.BarcodeResult.Barcode + [0x2713667] .OneOCR.Interop.BarcodeStandard + [0x27136ed] 2%.OneOCR.Interop.FormulaResult.Formula + [0x27137a0] 2#.OneOCR.Interop.FormulaResult.Style + [0x27137e3] 2".OneOCR.Interop.FormulaResult.Line + [0x2713894] 2".OneOCR.Interop.FormulaResult.Line"" + [0x271390e] 2%.OneOCR.Interop.TextRecognitionResult + [0x271394e] .OneOCR.Interop.BarcodeResult + [0x2713985] .OneOCR.Interop.CheckboxResult + [0x27139c0] .OneOCR.Interop.FormulaResult" + [0x2713a04] 2'.OneOCR.Interop.CheckboxResult.Checkbox + [0x2713aa4] .OneOCR.Interop.CheckboxType + [0x2713bf8] 2!.OneOCR.Interop.TableResult.Table + [0x2713c9a] .OneOCR.Interop.TableType + [0x2713cc8] 2%.OneOCR.Interop.TableResult.TableCell + [0x2713d1c] .OneOCR.Interop.TableGeometry + [0x2713e43] 2#.OneOCR.Interop.FigureResult.Figure + [0x2713ec8] .OneOCR.Interop.FigureType"D + [0x2713f0b] .OneOCR.Interop.TableGeometry" + [0x2713f48] 2!.OneOCR.Interop.LangIDResult.Line + [0x2714018] .OneOCR.Interop.PipelineResult + [0x271404d] .OneOCR.Interop.TableResult + [0x2714080] .OneOCR.Interop.FigureResult" + [0x27140c6] 2%.OneOCR.Interop.PODResult.PageObjects + [0x2714132] 20.OneOCR.Interop.PODResult.PageObjects.PageObject + [0x27143ca] 2+.OneOCR.Interop.LatticeResult.WordCandidate + [0x2714452] .OneOCR.Interop.Sentence.Word + [0x2714570] .OneOCR.Interop.LinePolygon + [0x27145b4] 2%.OneOCR.Interop.Enums.TextOrientation + [0x27145f2] .OneOCR.Interop.XnnResult + [0x271461f] .OneOCR.Interop.Sentence + [0x2714651] .OneOCR.Interop.LatticeResult + [0x27146f5] .OneOCR.Interop.Enums.TextRead + [0x2714832] .OneOCR.Interop.CheckboxResult" + [0x2714875] 2/.OneOCR.Interop.KeyValuePairResult.KeyValuePair + [0x27148e2] 2'.OneOCR.Interop.KeyValuePairElementType + [0x2714929] 2+.OneOCR.Interop.KeyValuePairResult.Position + [0x27149e5] 2-.OneOCR.Interop.KeyValuePairMetrics.QAMetrics + [0x2716070] OneOCR + [0x27160ca] .OneOCR.ONNXProto"G + [0x2716113] .OneOCR.ModelPack" + [0x27161a0] 2*.OneOCR.CustomScenarioProto.GrammarLmEntry + [0x271627a] .OneOCR.CustomScenarioProto" + [0x27162c2] 2 .OneOCR.DecoderProto.DecoderType + [0x2716483] 2'.OneOCR.DetectorProto.DetectorModelType + [0x27164c2] .OneOCR.ModelPack + [0x2716586] 20.OneOCR.DetectorProto.TextlineConfThresholdEntry + [0x2716772] 2".OneOCR.DetectorProto.DQDETRConfig + [0x2716b58] 2<.OneOCR.AuxMltClsProto.ScriptConsecutiveFramesThresholdEntry + [0x2716bc7] 2).OneOCR.AuxMltClsProto.AuxMltClsModelType + [0x2716c10] .OneOCR.LineLayoutClsProto + [0x2716f78] .OneOCR.CharProto.CharModelType + [0x2717165] .OneOCR.TieredModelPack" + [0x2717497] .OneOCR.ModelPack"i + [0x2717637] .OneOCR.ModelPack"K + [0x27176c8] 21.OneOCR.TextEmbeddingProto.TextEmbeddingModelType + [0x27177f3] .OneOCR.ModelPack"E + [0x2717887] .OneOCR.ModelPack"? + [0x2717907] 2,.OneOCR.EnumsMap.TextScriptToOcrModeMapEntry + [0x271795f] 28.OneOCR.EnumsMap.TextScriptTextCategoryToOcrModeMapEntry + [0x27179bc] 2..OneOCR.EnumsMap.OcrModeToTextCategoryMapEntry + [0x2717a0d] 2,.OneOCR.EnumsMap.OcrModeToTextScriptMapEntry + [0x2717a60] 2&.OneOCR.EnumsMap.OcrModeToPathMapEntry + [0x2717b7e] .OneOCR.Interop.OCRMode + [0x2717d96] .OneOCR.Interop.OCRMode"I + [0x2717de7] .OneOCR.ModelPack"f + [0x2717e9b] .OneOCR.ModelPack"u + [0x2717f4a] .OneOCR.DetectorProto + [0x2717f8c] .OneOCR.CharProto + [0x2717fca] .OneOCR.DecoderProto + [0x271800a] .OneOCR.RejectionProto + [0x271804d] .OneOCR.ConfidenceProto + [0x271809a] .OneOCR.CheckboxDetectorProto + [0x2718150] .OneOCR.TableDetectorProto + [0x27181a3] .OneOCR.TableRecognizerProto + [0x27181fa] .OneOCR.AuxMltClsProto + [0x2718241] .OneOCR.PipelineProto.Engine + [0x2718271] 2 .OneOCR.PipelineProto.Scheduling + [0x27182ad] 2%.OneOCR.PipelineProto.RejectionOption + [0x2718300] 2".OneOCR.PipelineProto.EngineOption + [0x271833d] .OneOCR.LangIDProto + [0x2718389] .OneOCR.PODBackboneProto + [0x27183e6] .OneOCR.PODRegionGroupingProto + [0x271844e] .OneOCR.PODReadingOrderProto + [0x27184af] .OneOCR.TextEmbeddingProto + [0x271850e] .OneOCR.EntityClassifierProto + [0x271856c] .OneOCR.CustomFstProto + [0x27185b5] .OneOCR.EnumsMap + [0x27185f9] .OneOCR.MathFmDetProto + [0x271864e] .OneOCR.MathFmLineEncProto + [0x27186ac] .OneOCR.MathFmLineRejProto + [0x271870b] .OneOCR.MathFmLineAttnProto + [0x271876b] .OneOCR.MathFmLineDecProto + [0x27187c2] .OneOCR.FontClsProto + [0x2718813] 2+.OneOCR.PipelineProto.TextlineImagesBatcher + [0x2718862] .OneOCR.MathFmParagraphProto + [0x27188bc] .OneOCR.FormDetectorProto + [0x2718906] .OneOCR.TOCProto + [0x2718963] 2 .OneOCR.PipelineProto.EngineType + [0x2718fb1] 26.OneOCR.PipelineProto.RuntimeOption.RuntimeOptionEntry + [0x2719043] 2#.OneOCR.PipelineProto.RuntimeOption + [0x271979c] 2#.OneOCR.TensorMapProto.TensorsEntry + [0x27197da] 2!.OneOCR.TensorMapProto.TensorType + [0x2719888] .OneOCR.TensorMapProto.Tensor: + [0x271cc28] OneOCR.Interop.PipelineMetrics.ScriptMetricsEntry.key + [0x271cc78] OneOCR.Interop.TextRecognitionResult.Region.json + [0x271ccb0] OneOCR.Interop.TextRecognitionResult.WordCandidate.text + [0x271cce8] OneOCR.Interop.TextRecognitionResult.Word.text + [0x271cd18] OneOCR.Interop.TextRecognitionResult.LineCandidate.text + [0x271cd50] OneOCR.Interop.TextRecognitionResult.DebugInfo.word_lab_strings + [0x271cd90] OneOCR.Interop.TextRecognitionResult.errorInfo + [0x271cdc0] OneOCR.Interop.BarcodeResult.Barcode.content + [0x271cdf0] OneOCR.Interop.BarcodeResult.error_info + [0x271ce18] OneOCR.Interop.FormulaResult.Line.value + [0x271ce40] OneOCR.Interop.FormulaResult.Formula.value + [0x271ce70] OneOCR.Interop.FormulaResult.error_info + [0x271ce98] OneOCR.Interop.CheckboxResult.error_info + [0x271cec8] OneOCR.Interop.TableResult.Table.json_debug_info + [0x271cf00] OneOCR.Interop.LangIDResult.error_info + [0x271cf28] OneOCR.Interop.LangIDInput.texts + [0x271cf50] OneOCR.Interop.PODResult.PageObjects.PageObject.object_type_name + [0x271cfa0] OneOCR.Interop.PODResult.PageObjects.PageObject.object_role_name + [0x271cff0] OneOCR.Interop.PODResult.PageObjects.PageObject.reading_order_label_name + [0x271d040] OneOCR.Interop.LatticeResult.WordCandidate.text + [0x271d070] OneOCR.Interop.Sentence.Word.lab + [0x271d098] OneOCR.Interop.TextLine.text + [0x27239d8] OneOCRFeatureExtract + [0x2723a88] OneOCRXYSeglinkProposals + [0x2723b50] OneOCRSeglinkProposals + [0x2724c60] Copyright @ OneOCR, Microsoft. + [0x2726de0] OneOCR.AuxMltClsProto.ScriptConsecutiveFramesThresholdEntry.key + [0x2726e20] OneOCR.DetectorProto.TextlineConfThresholdEntry.key + [0x2726e58] OneOCR.CustomScenarioProto.GrammarLmEntry.value + [0x2726e88] OneOCR.CustomScenarioProto.GrammarLmEntry.key + [0x2726eb8] OneOCR.PipelineProto.RuntimeOption.RuntimeOptionEntry.value + [0x2726ef8] OneOCR.PipelineProto.RuntimeOption.RuntimeOptionEntry.key + [0x2726f38] OneOCR.CustomFstProto.name + [0x2726f58] OneOCR.DecoderProto.name + [0x2726f78] OneOCR.CustomScenarioProto.lm_path + [0x2726fa0] OneOCR.CustomScenarioProto.manifest_path + [0x2726fd0] OneOCR.ONNXProto.model_path + [0x2726ff0] OneOCR.CustomScenarioProto.name + [0x2727020] OneOCR.TensorMapProto.TensorsEntry.key + [0x2727048] OneOCR.LangIDProto.name + [0x2727060] OneOCR.LangIDProto.char_mapping_path + [0x2727088] OneOCR.FontClsProto.font_weight_calib_map_path + [0x27270b8] OneOCR.FontClsProto.font_style_calib_map_path + [0x27270e8] OneOCR.FontClsProto.name + [0x2727108] OneOCR.FontClsProto.font_name_calib_map_path + [0x2727138] OneOCR.AuxMltClsProto.hwpc_handwritten_calib_map_path + [0x2727170] OneOCR.LineLayoutClsProto.name + [0x2727190] OneOCR.DetectorProto.checkbox_calib_map_path + [0x27271c0] OneOCR.AuxMltClsProto.name + [0x27271e0] OneOCR.DecoderProto.quantization_param_path + [0x2727210] OneOCR.DetectorProto.name + [0x2727230] OneOCR.DecoderProto.word_path + [0x2727250] OneOCR.DecoderProto.lm_path + [0x2727270] OneOCR.DecoderProto.wfst_path + [0x2727290] OneOCR.DecoderProto.phone_path + [0x27272b0] OneOCR.TableDetectorProto.name + [0x27272d0] OneOCR.FormDetectorProto.name + [0x27272f0] OneOCR.CheckboxDetectorProto.name + [0x2727318] OneOCR.CheckboxDetectorProto.checkbox_calib_map_path + [0x2727350] OneOCR.ConfidenceProto.name + [0x2727370] OneOCR.RejectionProto.name + [0x2727390] OneOCR.CharProto.char_log_to_phy_path + [0x27273b8] OneOCR.CharProto.composite_chars_map_path + [0x27273e8] OneOCR.CharProto.rnn_info_path + [0x2727408] OneOCR.CharProto.phone_to_idx_path + [0x2727430] OneOCR.LangIDProto.calibration_mapping_path + [0x2727460] OneOCR.CharProto.name + [0x2727478] OneOCR.LangIDProto.id_to_name_mapping_path + [0x27274a8] OneOCR.LangIDProto.lang_mask_path + [0x27274d0] OneOCR.LangIDProto.feature_config_path + [0x27274f8] OneOCR.LangIDProto.char_script_path + [0x2727520] OneOCR.MathFmLineDecProto.vocab_path + [0x2727548] OneOCR.MathFmLineDecProto.calib_map_path + [0x2727578] OneOCR.MathFmLineAttnProto.name + [0x2727598] OneOCR.MathFmLineDecProto.name + [0x27275b8] OneOCR.MathFmLineEncProto.name + [0x27275d8] OneOCR.MathFmLineRejProto.name + [0x27275f8] OneOCR.MathFmParagraphProto.name + [0x2727620] OneOCR.TOCProto.name + [0x2727638] OneOCR.EntityClassifierProto.name + [0x2727660] OneOCR.MathFmDetProto.name + [0x2727680] OneOCR.TextEmbeddingProto.name + [0x27276a0] OneOCR.TextEmbeddingProto.vocab_path + [0x27276c8] OneOCR.PODRegionGroupingProto.name + [0x27276f0] OneOCR.PODReadingOrderProto.name + [0x2727718] OneOCR.TableRecognizerProto.name + [0x2727740] OneOCR.PODBackboneProto.name + [0x2727760] OneOCR.PipelineProto.text_embedding_model_dir + [0x2727790] OneOCR.PipelineProto.entity_classifier_model_dir + [0x27277c8] OneOCR.PipelineProto.pod_region_grouping_model_dir + [0x2727800] OneOCR.PipelineProto.pod_reading_order_model_dir + [0x2727838] OneOCR.PipelineProto.lang_id_model_dir + [0x2727860] OneOCR.PipelineProto.pod_backbone_model_dir + [0x2727890] OneOCR.PipelineProto.table_reco_model_dir + [0x27278c0] OneOCR.PipelineProto.aux_mlt_cls_model_dir + [0x27278f0] OneOCR.PipelineProto.line_layout_cls_model_dir + [0x2727920] OneOCR.PipelineProto.table_det_model_dir + [0x2727950] OneOCR.PipelineProto.conf_model_dir + [0x2727978] OneOCR.PipelineProto.checkbox_det_model_dir + [0x27279a8] OneOCR.PipelineProto.dec_model_dir + [0x27279d0] OneOCR.PipelineProto.rej_model_dir + [0x27279f8] OneOCR.PipelineProto.det_model_dir + [0x2727a20] OneOCR.PipelineProto.char_model_dir + [0x2727a48] OneOCR.PipelineProto.toc_model_dir + [0x2727a70] OneOCR.PipelineProto.mathfm_paragraph_model_dir + [0x2727aa0] OneOCR.PipelineProto.form_det_model_dir + [0x2727ac8] OneOCR.PipelineProto.mathfm_line_dec_model_dir + [0x2727af8] OneOCR.PipelineProto.font_cls_model_dir + [0x2727b20] OneOCR.PipelineProto.mathfm_line_rej_model_dir + [0x2727b50] OneOCR.PipelineProto.mathfm_line_attn_model_dir + [0x2727b80] OneOCR.PipelineProto.mathfm_det_model_dir + [0x2727bb0] OneOCR.PipelineProto.mathfm_line_enc_model_dir + [0x2727be0] OneOCR.PipelineProto.custom_fst_model_dir + [0x2727c10] OneOCR.PipelineProto.enums_map_file + [0x27ff610] .?AVTextRecognitionResult_DebugInfo@Interop@OneOCR@@ + [0x27ff660] .?AVPipelineMetrics_PostAnalyzerMetrices@Interop@OneOCR@@ + [0x27ff6b0] .?AVMathFormulaPipelineMetrics_DetectorMetrics@Interop@OneOCR@@ + [0x27ff700] .?AVTextRecognitionResult@Interop@OneOCR@@ + [0x27ff740] .?AVTableResult_SolidLineBlock@Interop@OneOCR@@ + [0x27ff780] .?AVPipelineMetrics_DetectorMetrics@Interop@OneOCR@@ + [0x27ff7d0] .?AVPipelineMetrics_RecognizerMetrics@Interop@OneOCR@@ + [0x27ff830] .?AVLatticeResult_WordCandidate@Interop@OneOCR@@ + [0x27ff880] .?AVMathFormulaPipelineMetrics_ParagraphMetrics@Interop@OneOCR@@ + [0x27ff8e0] .?AVMathFormulaPipelineMetrics_RecognizerMetrics@Interop@OneOCR@@ + [0x27ff938] .?AVBarcodeResult_Barcode@Interop@OneOCR@@ + [0x27ff978] .?AVTableGeometries@Interop@OneOCR@@ + [0x27ff9b0] .?AVQuadrangle@Interop@OneOCR@@ + [0x27ff9e0] .?AVNormalizerMetrics@Interop@OneOCR@@ + [0x27ffa18] .?AVCheckboxResult_Checkbox@Interop@OneOCR@@ + [0x27ffa60] .?AVTextRecognitionResult_Region@Interop@OneOCR@@ + [0x27ffaa8] .?AVTableResult_SolidLine@Interop@OneOCR@@ + [0x27ffaf0] .?AVPODMetrics_PODRegionGroupingMetrics@Interop@OneOCR@@ + [0x27ffb40] .?AVSectionLevels@Interop@OneOCR@@ + [0x27ffb78] .?AVPipelineMetrics@Interop@OneOCR@@ + [0x27ffbb0] .?AVTextRecognitionResult_WordCandidate@Interop@OneOCR@@ + [0x27ffc00] .?AVTextRecognitionResult_LineCandidate@Interop@OneOCR@@ + [0x27ffc50] .?AVBarcodeRecognizerMetrics@Interop@OneOCR@@ + [0x27ffc90] .?AVLangIDInput@Interop@OneOCR@@ + [0x27ffcc8] .?AVRawPageObjects@Interop@OneOCR@@ + [0x27ffe80] .?AVMathFormulaPipelineMetrics@Interop@OneOCR@@ + [0x27ffec0] .?AVPoint@Interop@OneOCR@@ + [0x27ffef0] .?AVSentence@Interop@OneOCR@@ + [0x27fff20] .?AVPODMetrics_PODBackboneMetrics@Interop@OneOCR@@ + [0x27fff70] .?AVPipelineMetrics_AnalyzerMetrices@Interop@OneOCR@@ + [0x27fffb8] .?AVTableResult@Interop@OneOCR@@ + [0x27ffff0] .?AVTextRecognitionResult_Word@Interop@OneOCR@@ + [0x2800030] .?AVFigureResult@Interop@OneOCR@@ + [0x2800068] .?AVPipelineResult@Interop@OneOCR@@ + [0x28000f8] .?AVPODMetrics@Interop@OneOCR@@ + [0x2800128] .?AVLangIDResult_Line@Interop@OneOCR@@ + [0x2800160] .?AVFormulaResult@Interop@OneOCR@@ + [0x2800198] .?AVBarcodeResult@Interop@OneOCR@@ + [0x28001d0] .?AVPODResult_PageObjects_PageObject@Interop@OneOCR@@ + [0x2800218] .?AVFigureResult_Figure@Interop@OneOCR@@ + [0x2800258] .?AVPODMetrics_FormMetrics@Interop@OneOCR@@ + [0x28002a0] .?AVPipelineMetrics_DispatchMetrics@Interop@OneOCR@@ + [0x28002e8] .?AVTOCMetrics@Interop@OneOCR@@ + [0x2800320] .?AVKeyValuePairResult_Position@Interop@OneOCR@@ + [0x2800368] .?AVCheckboxResult@Interop@OneOCR@@ + [0x28003a0] .?AVTableMetrics@Interop@OneOCR@@ + [0x28003d8] .?AVPODResult@Interop@OneOCR@@ + [0x2800410] .?AVTableMetrics_TableRecognizerMetrics@Interop@OneOCR@@ + [0x2800460] .?AVSentence_Word@Interop@OneOCR@@ + [0x2800498] .?AVEnums@Interop@OneOCR@@ + [0x28004c8] .?AVFormulaResult_Formula@Interop@OneOCR@@ + [0x2800510] .?AVPipelineMetrics_ScriptMetricsEntry_DoNotUse@Interop@OneOCR@@ + [0x2800568] .?AVLangIDResult@Interop@OneOCR@@ + [0x28005a0] .?AVTableGeometry@Interop@OneOCR@@ + [0x28005e0] .?AVKeyValuePairResult_KeyValuePair@Interop@OneOCR@@ + [0x2800628] .?AVKeyValuePairResult@Interop@OneOCR@@ + [0x2800660] .?AVLatticeResult@Interop@OneOCR@@ + [0x2800698] .?AVFormulaResult_Line@Interop@OneOCR@@ + [0x28006d0] .?AVKeyValuePairInput@Interop@OneOCR@@ + [0x2800708] .?AVLinePolygon@Interop@OneOCR@@ + [0x2800740] .?AVPODResult_PageObjects@Interop@OneOCR@@ + [0x2800780] .?AVKeyValuePairMetrics_QAMetrics@Interop@OneOCR@@ + [0x28007c8] .?AVXnnResult@Interop@OneOCR@@ + [0x2800800] .?AVPODMetrics_PODReadingOrderMetrics@Interop@OneOCR@@ + [0x28008c0] .?AVTextLine@Interop@OneOCR@@ + [0x28008f0] .?AVTableResult_TableCell@Interop@OneOCR@@ + [0x2800930] .?AVTableMetrics_TableDetectorMetrics@Interop@OneOCR@@ + [0x2800978] .?AVTableResult_Table@Interop@OneOCR@@ + [0x28009b0] .?AVTextRecognitionResult_Line@Interop@OneOCR@@ + [0x28009f0] .?AVKeyValuePairMetrics@Interop@OneOCR@@ + [0x2800a30] .?AVHierarchyAnalyzerInput@Interop@OneOCR@@ + [0x2800a70] .?AV@?M@??RecognizeTextLines@TextPipelineDevImpl@OneOCR@@UEBA?AUTextRecognitionResult@3@AEAV?$vector@V?$unique_ptr@VTextLine@OneOCR@@U?$default_delete@VTextLine@OneOCR@@@std@@@std@@V?$allocator@V?$unique_ptr@VTextLine@OneOCR@@U?$default_delete@VTextLine@OneOCR@@@std@@@std@@@2@@std@@AEBUProcessOption@3@QEAVPipelineMetrics@Interop@3@V?$optional@V?$reference_wrapper@VImageFeature@OneOCR@@@std@@@6@@Z@ + [0x2800f70] .?AV@?0???0ThreadPool@OneOCR@@QEAA@_K@Z@ + [0x2800fc0] .?AV@?3???R@?3??alloc@ThreadPool@OneOCR@@QEAA?AVContext@34@_K@Z@QEBA@XZ@ + [0x2801600] .?AV@?4??Analyze@TextAnalyzerImpl@OneOCR@@UEBAXAEAV?$vector@V?$unique_ptr@VTextLine@OneOCR@@U?$default_delete@VTextLine@OneOCR@@@std@@@std@@V?$allocator@V?$unique_ptr@VTextLine@OneOCR@@U?$default_delete@VTextLine@OneOCR@@@std@@@std@@@2@@std@@AEBUProcessOption@3@AEAVPipelineMetrics_AnalyzerMetrices@Interop@3@@Z@ + [0x2801758] .?AVAuxMltClsClassifierBatch@OneOCR@@ + [0x2802368] .?AVAuxMltClsClassifier@OneOCR@@ + [0x2803c40] .?AV?$_Binder@U_Unforced@std@@V?$_Mem_fn@P8TextLineRecognizerImpl@OneOCR@@EAAPEAVILattice@2@AEBVDecoderProto@2@AEBVModelParser@2@@Z@2@PEAVTextLineRecognizerImpl@OneOCR@@AEBVDecoderProto@5@AEAVModelParser@5@@std@@ + [0x2803d30] .?AV@?1??Recognize@TextLineRecognizerImpl@OneOCR@@UEBA?AURecognizerTextLineResult@3@AEAVTextLine@3@AEBUProcessOption@3@AEAUAtomicRecognizerMetrics@3@@Z@ + [0x2803df0] .?AV@?1??RecognizeWithTextLineFeature@TextLineRecognizerImpl@OneOCR@@UEBA?AURecognizerTextLineResult@3@AEBUTextLineFeature@3@AEAVTextLine@3@AEBUProcessOption@3@AEAUAtomicRecognizerMetrics@3@@Z@ + [0x2803ed0] .?AV@?1??BatchRecognize@TextLineRecognizerImpl@OneOCR@@UEBA?AV?$vector@URecognizerTextLineResult@OneOCR@@V?$allocator@URecognizerTextLineResult@OneOCR@@@std@@@std@@AEBVConcatTextLines@3@AEBUProcessOption@3@AEAUAtomicRecognizerMetrics@3@PEAVThreadPool@3@@Z@ + [0x2803ff0] .?AV?$_Binder@U_Unforced@std@@V?$_Mem_fn@P8TextLineRecognizerImpl@OneOCR@@EAAPEAVCnnDbLstm@2@AEBVCharProto@2@AEBVModelParser@2@@Z@2@PEAVTextLineRecognizerImpl@OneOCR@@AEBVCharProto@5@AEAVModelParser@5@@std@@ + [0x28040d0] .?AVDec@LatMBRAdapter@OneOCR@@ + [0x2804350] .?AV?$_Binder@U_Unforced@std@@V?$_Mem_fn@P8TextLineRecognizerImpl@OneOCR@@EAAPEAVConfidenceProcessor@2@AEBVConfidenceProto@2@AEBVModelParser@2@@Z@2@PEAVTextLineRecognizerImpl@OneOCR@@AEBVConfidenceProto@5@AEAVModelParser@5@@std@@ + [0x2804450] .?AV?$_Binder@U_Unforced@std@@V?$_Mem_fn@P8TextLineRecognizerImpl@OneOCR@@EAAPEAVRejectionProcessor@2@AEBVRejectionProto@2@AEBVModelParser@2@@Z@2@PEAVTextLineRecognizerImpl@OneOCR@@AEBVRejectionProto@5@AEAVModelParser@5@@std@@ + [0x2804550] .?AV?$_Binder@U_Unforced@std@@V?$_Mem_fn@P8TextLineRecognizerImpl@OneOCR@@EAAPEAVIDecoder@2@AEBVDecoderProto@2@AEBVModelParser@2@V?$optional@V?$reference_wrapper@VCustomFstProto@OneOCR@@@std@@@std@@@Z@2@PEAVTextLineRecognizerImpl@OneOCR@@AEBVDecoderProto@5@AEAVModelParser@5@AEAV?$optional@V?$reference_wrapper@VCustomFstProto@OneOCR@@@std@@@2@@std@@ + [0x28046c0] .?AV@?7??ProcessLogSoftmaxScores@TextLineRecognizerImpl@OneOCR@@IEBA?AURecognizerTextLineResult@3@AEBVCscMatrixView@3@AEBVTextLine@3@_NPEBVCharacterMapper@CharacterMap@3@PEBVCnnDbLstm@3@PEBVIDecoder@3@PEBVILattice@3@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@77AEBUProcessOption@3@AEAUAtomicRecognizerMetrics@3@@Z@ + [0x2804828] .?AVIDecoder@OneOCR@@ + [0x2804a60] .?AV@?1??InitCompositeCharMap@CharacterMapper@CharacterMap@OneOCR@@IEAAXAEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEBVModelParser@4@@Z@ + [0x2804d30] .?AV@?1??LoadPhoneMap@CharacterMapper@CharacterMap@OneOCR@@IEBA?AV?$vector@HV?$allocator@H@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@6@AEBVModelParser@4@@Z@ + [0x2804e10] .?AU?$default_delete@$$BY0A@UCharToken@CharacterMap@OneOCR@@@std@@ + [0x2805090] .?AV@?1??Process@Lat@LatMBRAdapter@OneOCR@@UEBA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEAUDecoderResult@4@AEAV?$vector@ULatticeResult@OneOCR@@V?$allocator@ULatticeResult@OneOCR@@@std@@@6@AEBUProcessOption@4@H@Z@ + [0x28051a0] .?AV@?1??Process@Lat@LatMBRAdapter@OneOCR@@UEBA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEAUDecoderResult@4@AEAV?$vector@ULatticeResult@OneOCR@@V?$allocator@ULatticeResult@OneOCR@@@std@@@6@AEBUProcessOption@4@H@Z@ + [0x2805320] .?AV?$_Binder@U_Unforced@std@@V?$_Mem_fn@P8CnnDbLstmTiered@OneOCR@@EAAPEAVCnnDbLstm@2@AEBVCharProto@2@AEBVTieredModelPack@2@AEBVModelParser@2@W4PipelineProto_EngineType@2@@Z@2@PEAVCnnDbLstmTiered@OneOCR@@AEBVCharProto@5@AEBVTieredModelPack@5@AEBVModelParser@5@AEAW4PipelineProto_EngineType@5@@std@@ + [0x2805af0] .?AU?$default_delete@VDQDETR@OneOCR@@@std@@ + [0x28073c0] .?AV@?1??RunInference@BaseRCNN@OneOCR@@MEBA?AV?$unique_ptr@VITensorMapView@OneOCR@@U?$default_delete@VITensorMapView@OneOCR@@@std@@@std@@AEBVSimpleTensorMap@3@AEAVPipelineMetrics_DetectorMetrics@Interop@3@AEBUProcessOption@3@_N@Z@ + [0x2807aa0] .?AV@?1??RunInference@DQDETR@OneOCR@@MEBA?AV?$unique_ptr@VITensorMapView@OneOCR@@U?$default_delete@VITensorMapView@OneOCR@@@std@@@std@@AEBVSimpleTensorMap@3@AEAVPipelineMetrics_DetectorMetrics@Interop@3@AEBUProcessOption@3@_N@Z@ + [0x2807ba0] .?AU?$default_delete@VTextLinePolygon@OneOCR@@@std@@ + [0x2809340] .?AV@?1??Cipher@OneOCR@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEBV34@0_N1@Z@ + [0x28093d0] .?AV@?1??SHA256Hash@OneOCR@@YA?AV?$array@W4byte@std@@$0CA@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@4@@Z@ + [0x2809470] .?AV@?1??Cipher@OneOCR@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEBV34@0_N1@Z@ + [0x2809500] .?AV@?1??SHA256Hash@OneOCR@@YA?AV?$array@W4byte@std@@$0CA@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@4@@Z@ + [0x28098e0] .?AVRingPolygon@OneOCR@@ + [0x2809958] .?AVPolygon@OneOCR@@ + [0x28099e0] .?AV@?1??ConvertTextV2L_ICU@Utility@OneOCR@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEBV45@AEAV?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@5@AEAV?$vector@_KV?$allocator@_K@std@@@5@AEAV?$vector@U?$pair@_K_K@std@@V?$allocator@U?$pair@_K_K@std@@@2@@5@@Z@ + [0x2809ba8] .?AVConfidenceProto@OneOCR@@ + [0x2809bd8] .?AVDetectorProto@OneOCR@@ + [0x2809c08] .?AVTieredModelPack@OneOCR@@ + [0x2809c38] .?AVFormDetectorProto@OneOCR@@ + [0x2809c68] .?AVPipelineProto_Scheduling@OneOCR@@ + [0x2809ca0] .?AVFontClsProto@OneOCR@@ + [0x2809cd0] .?AVTableDetectorProto@OneOCR@@ + [0x2809d00] .?AVCharProto@OneOCR@@ + [0x2809d28] .?AVTOCProto@OneOCR@@ + [0x2809d50] .?AVEnumsMap_OcrModeToTextCategoryMapEntry@OneOCR@@ + [0x2809d98] .?AVEntityClassifierProto@OneOCR@@ + [0x2809dd0] .?AVAuxMltClsProto_ScriptConsecutiveFramesThresholdEntry_DoNotUse@OneOCR@@ + [0x2809e30] .?AVLineLayoutClsProto@OneOCR@@ + [0x2809e60] .?AVTensorMapProto@OneOCR@@ + [0x2809e90] .?AVPipelineProto_EngineOption@OneOCR@@ + [0x2809ec8] .?AVPipelineProto@OneOCR@@ + [0x2809ef8] .?AVCustomFstProto@OneOCR@@ + [0x2809f30] .?AVEnumsMap_OcrModeToTextScriptMapEntry@OneOCR@@ + [0x2809f78] .?AVMathFmLineEncProto@OneOCR@@ + [0x2809fa8] .?AVEnumsMap@OneOCR@@ + [0x2809fd0] .?AVEnumsMap_OcrModeToPathMapEntry@OneOCR@@ + [0x280a010] .?AVLangIDProto@OneOCR@@ + [0x280a040] .?AVPipelineProto_Engine@OneOCR@@ + [0x280a078] .?AVPODRegionGroupingProto@OneOCR@@ + [0x280a0b0] .?AVDecoderProto@OneOCR@@ + [0x280a0e0] .?AVModelPack@OneOCR@@ + [0x280a108] .?AVTensorMapProto_Tensor@OneOCR@@ + [0x280a140] .?AVMathFmParagraphProto@OneOCR@@ + [0x280a180] .?AVEnumsMap_TextScriptToOcrModeMapEntry@OneOCR@@ + [0x280a1c8] .?AVMathFmLineAttnProto@OneOCR@@ + [0x280a200] .?AVPODReadingOrderProto@OneOCR@@ + [0x280a240] .?AVDetectorProto_TextlineConfThresholdEntry_DoNotUse@OneOCR@@ + [0x280a290] .?AVCheckboxDetectorProto@OneOCR@@ + [0x280a2c8] .?AVRejectionProto@OneOCR@@ + [0x280a2f8] .?AVCustomScenarioProto@OneOCR@@ + [0x280a330] .?AVMathFmDetProto@OneOCR@@ + [0x280a360] .?AVONNXProto@OneOCR@@ + [0x280a388] .?AVPipelineProto_RejectionOption@OneOCR@@ + [0x280a3c8] .?AVMathFmLineRejProto@OneOCR@@ + [0x280a400] .?AVTensorMapProto_TensorsEntry_DoNotUse@OneOCR@@ + [0x280a450] .?AVCustomScenarioProto_GrammarLmEntry_DoNotUse@OneOCR@@ + [0x280a4a0] .?AVPODBackboneProto@OneOCR@@ + [0x280a4d0] .?AVTableRecognizerProto@OneOCR@@ + [0x280a508] .?AVMathFmLineDecProto@OneOCR@@ + [0x280a540] .?AVPipelineProto_TextlineImagesBatcher@OneOCR@@ + [0x280a588] .?AVTextEmbeddingProto@OneOCR@@ + [0x280a5b8] .?AVDetectorProto_DQDETRConfig@OneOCR@@ + [0x280a5f0] .?AVPipelineProto_RuntimeOption@OneOCR@@ + [0x280a630] .?AVEnumsMap_TextScriptTextCategoryToOcrModeMapEntry@OneOCR@@ + [0x280a680] .?AVPipelineProto_RuntimeOption_RuntimeOptionEntry_DoNotUse@OneOCR@@ + [0x280a6d8] .?AVAuxMltClsProto@OneOCR@@ + [0x280a710] .?AV@?3??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280a770] .?AV@?8??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280a7d0] .?AV@?N@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280a840] .?AV@?BD@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280a8b0] .?AV@?L@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280a920] .?AV@?BJ@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280a990] .?AV@?9??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280a9f0] .?AV@?BB@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280aa60] .?AV@?6??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280aac0] .?AV@?BM@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280ab30] .?AV@?BA@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280aba0] .?AV@?BF@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280ac10] .?AV@?O@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280ac80] .?AV@?5??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280ace0] .?AV@?BE@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280ad50] .?AV@?BH@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280adc0] .?AV@?2??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280ae20] .?AV@?BK@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280ae90] .?AV@?BC@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280af00] .?AV@?P@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280af70] .?AV@?7??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280afd0] .?AV@?BL@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280b040] .?AV@?BG@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280b0b0] .?AV@?M@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280b120] .?AV@?4??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x280b180] .?AV@?BI@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@2@AEAV32@@Z@ + [0x2828070] .?AV?$MapEntryImpl@VPipelineMetrics_ScriptMetricsEntry_DoNotUse@Interop@OneOCR@@VMessage@protobuf@google@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@H$08$04@internal@protobuf@google@@ + [0x2828180] .?AV?$MapEntry@VPipelineMetrics_ScriptMetricsEntry_DoNotUse@Interop@OneOCR@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@H$08$04@internal@protobuf@google@@ + [0x28282d0] .?AV?$MapField@VPipelineMetrics_ScriptMetricsEntry_DoNotUse@Interop@OneOCR@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@H$08$04@internal@protobuf@google@@ + [0x2828410] .?AV?$TensorMapBase@U?$pair@V?$variant@V?$vector@MV?$allocator@M@std@@@std@@V?$vector@HV?$allocator@H@std@@@2@V?$vector@_JV?$allocator@_J@std@@@2@V?$vector@EV?$allocator@E@std@@@2@V?$vector@DV?$allocator@D@std@@@2@V?$vector@GV?$allocator@G@std@@@2@@std@@V?$vector@_JV?$allocator@_J@std@@@2@@std@@@OneOCR@@ + [0x28285c0] .?AVSimpleTensorMap@OneOCR@@ + [0x2828670] .?AVTextPipelineDevImpl@OneOCR@@ + [0x2828710] .?AV?$_Ref_count_obj2@VEnumMapper@OneOCR@@@std@@ + [0x2828760] .?AV?$_Func_impl_no_alloc@V@?0???0ThreadPool@OneOCR@@QEAA@_K@Z@X$$V@std@@ + [0x2828b10] .?AV?$_Ref_count_obj2@VTextLine@OneOCR@@@std@@ + [0x2828c60] .?AV?$_Func_impl_no_alloc@V@?M@??RecognizeTextLines@TextPipelineDevImpl@OneOCR@@UEBA?AUTextRecognitionResult@4@AEAV?$vector@V?$unique_ptr@VTextLine@OneOCR@@U?$default_delete@VTextLine@OneOCR@@@std@@@std@@V?$allocator@V?$unique_ptr@VTextLine@OneOCR@@U?$default_delete@VTextLine@OneOCR@@@std@@@std@@@2@@std@@AEBUProcessOption@4@QEAVPipelineMetrics@Interop@4@V?$optional@V?$reference_wrapper@VImageFeature@OneOCR@@@std@@@7@@Z@_NAEB_KAEB_K@std@@ + [0x2828f68] .?AVTextPipelineDev@OneOCR@@ + [0x2828fc0] .?AVITensorMapView@OneOCR@@ + [0x2829038] .?AUTextLineDebugInfo@OneOCR@@ + [0x2829068] .?AVPipeline@OneOCR@@ + [0x28290b8] .?AVTextPipeline@OneOCR@@ + [0x28290e8] .?AV?$SingleThreadPool@$0A@@OneOCR@@ + [0x2829120] .?AVRawConcatTextLines@OneOCR@@ + [0x28291b0] .?AV?$_Func_impl_no_alloc@V@?3???R@?3??alloc@ThreadPool@OneOCR@@QEAA?AVContext@45@_K@Z@QEBA@XZ@X$$V@std@@ + [0x28292a8] .?AVTextAnalyzerImpl@OneOCR@@ + [0x28292d8] .?AVTextAnalyzer@OneOCR@@ + [0x2829648] .?AVBaseClassifier@OneOCR@@ + [0x2829fa8] .?AVLineLayoutInterface@OneOCR@@ + [0x282ac40] .?AV?$_Func_impl_no_alloc@V@?4??Analyze@TextAnalyzerImpl@OneOCR@@UEBAXAEAV?$vector@V?$unique_ptr@VTextLine@OneOCR@@U?$default_delete@VTextLine@OneOCR@@@std@@@std@@V?$allocator@V?$unique_ptr@VTextLine@OneOCR@@U?$default_delete@VTextLine@OneOCR@@@std@@@std@@@2@@std@@AEBUProcessOption@4@AEAVPipelineMetrics_AnalyzerMetrices@Interop@4@@Z@W4TextLineLayout@4@_K@std@@ + [0x282add0] .?AV?$_Func_base@W4TextLineLayout@OneOCR@@_K@std@@ + [0x282b158] .?AVAuxMltClsClassifierFixedWidth@OneOCR@@ + [0x282bdb0] .?AVUnownedTensorMap@OneOCR@@ + [0x282c178] .?AVLineLayoutClassifier@OneOCR@@ + [0x282c1b0] .?AVFontClassifier@OneOCR@@ + [0x282c1e0] .?AV?$_Func_base@PEAVILattice@OneOCR@@$$V@std@@ + [0x282c220] .?AV?$_Func_base@PEAVConfidenceProcessor@OneOCR@@$$V@std@@ + [0x282c270] .?AV?$_Func_impl_no_alloc@V?$_Binder@U_Unforced@std@@V?$_Mem_fn@P8TextLineRecognizerImpl@OneOCR@@EAAPEAVCnnDbLstm@2@AEBVCharProto@2@AEBVModelParser@2@@Z@2@PEAVTextLineRecognizerImpl@OneOCR@@AEBVCharProto@5@AEAVModelParser@5@@std@@PEAVCnnDbLstm@OneOCR@@$$V@std@@ + [0x282c388] .?AVTextLineRecognizer@OneOCR@@ + [0x282c3b8] .?AVArgMaxDecoder@OneOCR@@ + [0x282c410] .?AV?$_Func_impl_no_alloc@V@?1??BatchRecognize@TextLineRecognizerImpl@OneOCR@@UEBA?AV?$vector@URecognizerTextLineResult@OneOCR@@V?$allocator@URecognizerTextLineResult@OneOCR@@@std@@@std@@AEBVConcatTextLines@4@AEBUProcessOption@4@AEAUAtomicRecognizerMetrics@4@PEAVThreadPool@4@@Z@X$$V@std@@ + [0x282c550] .?AV?$_Func_impl_no_alloc@V@?1??Recognize@TextLineRecognizerImpl@OneOCR@@UEBA?AURecognizerTextLineResult@4@AEAVTextLine@4@AEBUProcessOption@4@AEAUAtomicRecognizerMetrics@4@@Z@X$$V@std@@ + [0x282c628] .?AVAutoGlobalInit@OneOCR@@ + [0x282c660] .?AV?$_Func_base@PEAVIDecoder@OneOCR@@$$V@std@@ + [0x282c6a0] .?AV?$_Func_impl_no_alloc@V?$_Binder@U_Unforced@std@@V?$_Mem_fn@P8TextLineRecognizerImpl@OneOCR@@EAAPEAVILattice@2@AEBVDecoderProto@2@AEBVModelParser@2@@Z@2@PEAVTextLineRecognizerImpl@OneOCR@@AEBVDecoderProto@5@AEAVModelParser@5@@std@@PEAVILattice@OneOCR@@$$V@std@@ + [0x282c7c0] .?AVTextLineRecognizerImpl@OneOCR@@ + [0x282c800] .?AV?$_Func_impl_no_alloc@V@?1??RecognizeWithTextLineFeature@TextLineRecognizerImpl@OneOCR@@UEBA?AURecognizerTextLineResult@4@AEBUTextLineFeature@4@AEAVTextLine@4@AEBUProcessOption@4@AEAUAtomicRecognizerMetrics@4@@Z@X$$V@std@@ + [0x282c900] .?AV?$_Func_base@PEAVCnnDbLstm@OneOCR@@$$V@std@@ + [0x282c950] .?AV?$_Ref_count_obj2@VCscMatrix@OneOCR@@@std@@ + [0x282c990] .?AVCnnDbLstm@OneOCR@@ + [0x282c9c0] .?AV?$_Func_impl_no_alloc@V?$_Binder@U_Unforced@std@@V?$_Mem_fn@P8TextLineRecognizerImpl@OneOCR@@EAAPEAVConfidenceProcessor@2@AEBVConfidenceProto@2@AEBVModelParser@2@@Z@2@PEAVTextLineRecognizerImpl@OneOCR@@AEBVConfidenceProto@5@AEAVModelParser@5@@std@@PEAVConfidenceProcessor@OneOCR@@$$V@std@@ + [0x282caf8] .?AURecognizerTextLineDebugInfo@OneOCR@@ + [0x282cb38] .?AVILattice@OneOCR@@ + [0x282cb60] .?AV?$_Func_base@PEAVRejectionProcessor@OneOCR@@$$V@std@@ + [0x282cbb0] .?AV?$_Func_impl_no_alloc@V@?7??ProcessLogSoftmaxScores@TextLineRecognizerImpl@OneOCR@@IEBA?AURecognizerTextLineResult@4@AEBVCscMatrixView@4@AEBVTextLine@4@_NPEBVCharacterMapper@CharacterMap@4@PEBVCnnDbLstm@4@PEBVIDecoder@4@PEBVILattice@4@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@77AEBUProcessOption@4@AEAUAtomicRecognizerMetrics@4@@Z@X$$V@std@@ + [0x282cfb0] .?AVCnnDbLstmTiered@OneOCR@@ + [0x282cfe0] .?AV?$_Ref_count_obj2@VXnnResult@OneOCR@@@std@@ + [0x282d020] .?AVLat@LatMBRAdapter@OneOCR@@ + [0x282d050] .?AV?$_Func_impl_no_alloc@V?$_Binder@U_Unforced@std@@V?$_Mem_fn@P8TextLineRecognizerImpl@OneOCR@@EAAPEAVRejectionProcessor@2@AEBVRejectionProto@2@AEBVModelParser@2@@Z@2@PEAVTextLineRecognizerImpl@OneOCR@@AEBVRejectionProto@5@AEAVModelParser@5@@std@@PEAVRejectionProcessor@OneOCR@@$$V@std@@ + [0x282d190] .?AV?$_Func_impl_no_alloc@V?$_Binder@U_Unforced@std@@V?$_Mem_fn@P8TextLineRecognizerImpl@OneOCR@@EAAPEAVIDecoder@2@AEBVDecoderProto@2@AEBVModelParser@2@V?$optional@V?$reference_wrapper@VCustomFstProto@OneOCR@@@std@@@std@@@Z@2@PEAVTextLineRecognizerImpl@OneOCR@@AEBVDecoderProto@5@AEAVModelParser@5@AEAV?$optional@V?$reference_wrapper@VCustomFstProto@OneOCR@@@std@@@2@@std@@PEAVIDecoder@OneOCR@@$$V@std@@ + [0x282d550] .?AVArgMaxLattice@OneOCR@@ + [0x282d930] .?AV?$_Func_impl_no_alloc@V@?1??LoadPhoneMap@CharacterMapper@CharacterMap@OneOCR@@IEBA?AV?$vector@HV?$allocator@H@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@7@AEBVModelParser@5@@Z@XAEAV87@@std@@ + [0x282da30] .?AV?$_Ref_count_resource@PEAUCharToken@CharacterMap@OneOCR@@U?$default_delete@$$BY0A@UCharToken@CharacterMap@OneOCR@@@std@@@std@@ + [0x282dfa0] .?AV?$_Func_impl_no_alloc@V@?1??InitCompositeCharMap@CharacterMapper@CharacterMap@OneOCR@@IEAAXAEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEBVModelParser@5@@Z@XAEAV67@@std@@ + [0x282e190] .?AV?$_Func_impl_no_alloc@V@?1??Process@Lat@LatMBRAdapter@OneOCR@@UEBA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEAUDecoderResult@5@AEAV?$vector@ULatticeResult@OneOCR@@V?$allocator@ULatticeResult@OneOCR@@@std@@@7@AEBUProcessOption@5@H@Z@XHHAEBV67@MAEBV?$vector@U?$pair@HH@std@@V?$allocator@U?$pair@HH@std@@@2@@7@@std@@ + [0x282e3f0] .?AV?$_Func_impl_no_alloc@V@?1??Process@Lat@LatMBRAdapter@OneOCR@@UEBA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEAUDecoderResult@5@AEAV?$vector@ULatticeResult@OneOCR@@V?$allocator@ULatticeResult@OneOCR@@@std@@@7@AEBUProcessOption@5@H@Z@XHHAEBV67@MAEBV?$vector@U?$pair@HH@std@@V?$allocator@U?$pair@HH@std@@@2@@7@@std@@ + [0x282e610] .?AV?$_Func_impl_no_alloc@V?$_Binder@U_Unforced@std@@V?$_Mem_fn@P8CnnDbLstmTiered@OneOCR@@EAAPEAVCnnDbLstm@2@AEBVCharProto@2@AEBVTieredModelPack@2@AEBVModelParser@2@W4PipelineProto_EngineType@2@@Z@2@PEAVCnnDbLstmTiered@OneOCR@@AEBVCharProto@5@AEBVTieredModelPack@5@AEBVModelParser@5@AEAW4PipelineProto_EngineType@5@@std@@PEAVCnnDbLstm@OneOCR@@$$V@std@@ + [0x282e7c0] .?AVTextNormalizer@OneOCR@@ + [0x282e7f0] .?AVBaseNormalizer@OneOCR@@ + [0x282eeb8] .?AVTextDetector@OneOCR@@ + [0x282eee8] .?AVIModelInferencer@OneOCR@@ + [0x282ef18] .?AVTextDetectorImpl@OneOCR@@ + [0x282ef48] .?AVDQDETR@OneOCR@@ + [0x282ef70] .?AV?$_Ref_count@VRelationRCNN@OneOCR@@@std@@ + [0x282efb0] .?AV?$_Ref_count@VRelationRCNNRpn@OneOCR@@@std@@ + [0x282eff8] .?AVCommonNN@OneOCR@@ + [0x282f020] .?AVCommonRCNN@OneOCR@@ + [0x282f050] .?AV?$_Ref_count_resource@PEAVDQDETR@OneOCR@@U?$default_delete@VDQDETR@OneOCR@@@std@@@std@@ + [0x282f0c0] .?AVBaseRCNN@OneOCR@@ + [0x282f0f0] .?AV?$_Ref_count@VRelationRCNNRpn2FixedSize@OneOCR@@@std@@ + [0x282f140] .?AV?$_Ref_count@VBaseRCNN@OneOCR@@@std@@ + [0x282f180] .?AV?$_Ref_count@VRelationRCNNRpn2@OneOCR@@@std@@ + [0x282f1c8] .?AVRelationRCNN@OneOCR@@ + [0x282f1f8] .?AVRelationRCNNRpn2FixedSize@OneOCR@@ + [0x282f230] .?AVRelationRCNNRpn2@OneOCR@@ + [0x282f260] .?AVRelationRCNNRpn@OneOCR@@ + [0x282f6b0] .?AV?$_Ref_count@VTextLinePolygon@OneOCR@@@std@@ + [0x282f700] .?AV?$_Ref_count_obj2@VTextLinePolygon@OneOCR@@@std@@ + [0x28302e0] .?AV?$_Ref_count_obj2@UBarcodePolygon@OneOCR@@@std@@ + [0x28308b0] .?AV?$_Func_impl_no_alloc@V@?1??RunInference@BaseRCNN@OneOCR@@MEBA?AV?$unique_ptr@VITensorMapView@OneOCR@@U?$default_delete@VITensorMapView@OneOCR@@@std@@@std@@AEBVSimpleTensorMap@4@AEAVPipelineMetrics_DetectorMetrics@Interop@4@AEBUProcessOption@4@_N@Z@X$$V@std@@ + [0x2830fe0] .?AV?$_Ref_count_obj2@VCheckboxResult_Checkbox@Interop@OneOCR@@@std@@ + [0x28314d0] .?AV?$_Func_impl_no_alloc@V@?1??RunInference@DQDETR@OneOCR@@MEBA?AV?$unique_ptr@VITensorMapView@OneOCR@@U?$default_delete@VITensorMapView@OneOCR@@@std@@@std@@AEBVSimpleTensorMap@4@AEAVPipelineMetrics_DetectorMetrics@Interop@4@AEBUProcessOption@4@_N@Z@X$$V@std@@ + [0x28315f0] .?AV?$_Ref_count_resource@PEAVTextLinePolygon@OneOCR@@U?$default_delete@VTextLinePolygon@OneOCR@@@std@@@std@@ + [0x2832e20] .?AVINNFramework@OneOCR@@ + [0x2832e50] .?AVOrtQnnFramework@OneOCR@@ + [0x2832e80] .?AVOrtFramework@OneOCR@@ + [0x2832eb0] .?AVOrtCudaFramework@OneOCR@@ + [0x2832ee0] .?AVOrtTensorRTFramework@OneOCR@@ + [0x2832f50] .?AV?$TensorMapBase@UValue@Ort@@@OneOCR@@ + [0x2833170] .?AV?$_Func_impl_no_alloc@V@?1??Cipher@OneOCR@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEBV45@0_N1@Z@X$$V@std@@ + [0x2833220] .?AV?$_Func_impl_no_alloc@V@?1??Cipher@OneOCR@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEBV45@0_N1@Z@X$$V@std@@ + [0x28332d0] .?AV?$_Func_impl_no_alloc@V@?1??SHA256Hash@OneOCR@@YA?AV?$array@W4byte@std@@$0CA@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@@Z@X$$V@std@@ + [0x2833390] .?AV?$_Func_impl_no_alloc@V@?1??SHA256Hash@OneOCR@@YA?AV?$array@W4byte@std@@$0CA@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@@Z@X$$V@std@@ + [0x28339f0] .?AVCodec@Utility@OneOCR@@ + [0x2833b70] .?AV?$_Func_impl_no_alloc@V@?1??ConvertTextV2L_ICU@Utility@OneOCR@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEBV56@AEAV?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@6@AEAV?$vector@_KV?$allocator@_K@std@@@6@AEAV?$vector@U?$pair@_K_K@std@@V?$allocator@U?$pair@_K_K@std@@@2@@6@@Z@X$$V@std@@ + [0x2833d30] .?AV?$MapEntry@VPipelineProto_RuntimeOption_RuntimeOptionEntry_DoNotUse@OneOCR@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V34@$08$08@internal@protobuf@google@@ + [0x2833e00] .?AV?$MapEntry@VDetectorProto_TextlineConfThresholdEntry_DoNotUse@OneOCR@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@M$08$01@internal@protobuf@google@@ + [0x2833ec0] .?AV?$MapEntry@VAuxMltClsProto_ScriptConsecutiveFramesThresholdEntry_DoNotUse@OneOCR@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@_J$08$02@internal@protobuf@google@@ + [0x2833f90] .?AV?$MapEntryImpl@VAuxMltClsProto_ScriptConsecutiveFramesThresholdEntry_DoNotUse@OneOCR@@VMessage@protobuf@google@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@_J$08$02@internal@protobuf@google@@ + [0x2834080] .?AV?$MapEntryImpl@VCustomScenarioProto_GrammarLmEntry_DoNotUse@OneOCR@@VMessage@protobuf@google@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V67@$08$08@internal@protobuf@google@@ + [0x2834160] .?AV?$MapField@VCustomScenarioProto_GrammarLmEntry_DoNotUse@OneOCR@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V34@$08$08@internal@protobuf@google@@ + [0x2834220] .?AV?$MapEntryImpl@VDetectorProto_TextlineConfThresholdEntry_DoNotUse@OneOCR@@VMessage@protobuf@google@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@M$08$01@internal@protobuf@google@@ + [0x2834300] .?AV?$MapEntry@VCustomScenarioProto_GrammarLmEntry_DoNotUse@OneOCR@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V34@$08$08@internal@protobuf@google@@ + [0x28343c0] .?AV?$MapEntry@VTensorMapProto_TensorsEntry_DoNotUse@OneOCR@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@VTensorMapProto_Tensor@2@$08$0L@@internal@protobuf@google@@ + [0x2834490] .?AV?$TypeDefinedMapFieldBase@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@VTensorMapProto_Tensor@OneOCR@@@internal@protobuf@google@@ + [0x2834540] .?AV?$MapEntryImpl@VPipelineProto_RuntimeOption_RuntimeOptionEntry_DoNotUse@OneOCR@@VMessage@protobuf@google@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V67@$08$08@internal@protobuf@google@@ + [0x28347e0] .?AV?$MapField@VDetectorProto_TextlineConfThresholdEntry_DoNotUse@OneOCR@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@M$08$01@internal@protobuf@google@@ + [0x28348a0] .?AV?$MapField@VAuxMltClsProto_ScriptConsecutiveFramesThresholdEntry_DoNotUse@OneOCR@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@_J$08$02@internal@protobuf@google@@ + [0x2834970] .?AV?$MapField@VPipelineProto_RuntimeOption_RuntimeOptionEntry_DoNotUse@OneOCR@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V34@$08$08@internal@protobuf@google@@ + [0x2834a40] .?AV?$MapField@VTensorMapProto_TensorsEntry_DoNotUse@OneOCR@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@VTensorMapProto_Tensor@2@$08$0L@@internal@protobuf@google@@ + [0x2834b10] .?AV?$MapEntryImpl@VTensorMapProto_TensorsEntry_DoNotUse@OneOCR@@VMessage@protobuf@google@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@VTensorMapProto_Tensor@2@$08$0L@@internal@protobuf@google@@ + [0x2834c00] .?AV?$_Func_base@X$$QEAVMathFmParagraphProto@OneOCR@@@std@@ + [0x2834c50] .?AV?$_Func_base@X$$QEAVDetectorProto@OneOCR@@@std@@ + [0x2834ca0] .?AV?$_Func_impl_no_alloc@V@?N@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVTableRecognizerProto@3@@std@@ + [0x2834d40] .?AV?$_Func_impl_no_alloc@V@?BJ@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVMathFmLineAttnProto@3@@std@@ + [0x2834de0] .?AV?$_Func_base@X$$QEAVMathFmLineDecProto@OneOCR@@@std@@ + [0x2834e30] .?AV?$_Func_base@X$$QEAVMathFmLineEncProto@OneOCR@@@std@@ + [0x2834e80] .?AV?$_Func_base@X$$QEAVRejectionProto@OneOCR@@@std@@ + [0x2834ed0] .?AV?$_Func_base@X$$QEAVPODRegionGroupingProto@OneOCR@@@std@@ + [0x2834f20] .?AV?$_Func_base@X$$QEAVMathFmLineRejProto@OneOCR@@@std@@ + [0x2834f70] .?AV?$_Func_impl_no_alloc@V@?3??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVAuxMltClsProto@3@@std@@ + [0x2835010] .?AV?$_Func_impl_no_alloc@V@?BD@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVTextEmbeddingProto@3@@std@@ + [0x28350b0] .?AV?$_Func_base@X$$QEAVTableRecognizerProto@OneOCR@@@std@@ + [0x2835100] .?AV?$_Func_base@X$$QEAVFontClsProto@OneOCR@@@std@@ + [0x2835150] .?AV?$_Func_base@X$$QEAVPODReadingOrderProto@OneOCR@@@std@@ + [0x28351a0] .?AV?$_Func_impl_no_alloc@V@?BM@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVTOCProto@3@@std@@ + [0x2835240] .?AV?$_Func_impl_no_alloc@V@?L@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVCheckboxDetectorProto@3@@std@@ + [0x28352e0] .?AV?$_Func_base@X$$QEAVLangIDProto@OneOCR@@@std@@ + [0x2835330] .?AV?$_Func_impl_no_alloc@V@?9??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVConfidenceProto@3@@std@@ + [0x28353d0] .?AV?$_Func_base@X$$QEAVAuxMltClsProto@OneOCR@@@std@@ + [0x2835420] .?AV?$_Func_impl_no_alloc@V@?BL@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVMathFmParagraphProto@3@@std@@ + [0x28354c0] .?AV?$_Func_base@X$$QEAVMathFmLineAttnProto@OneOCR@@@std@@ + [0x2835510] .?AV?$_Func_base@X$$QEAVCharProto@OneOCR@@@std@@ + [0x2835560] .?AV?$_Func_base@X$$QEAVPODBackboneProto@OneOCR@@@std@@ + [0x28355b0] .?AV?$_Func_impl_no_alloc@V@?8??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVRejectionProto@3@@std@@ + [0x2835650] .?AV?$_Func_impl_no_alloc@V@?2??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVDetectorProto@3@@std@@ + [0x28356f0] .?AV?$_Func_impl_no_alloc@V@?BC@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVPODReadingOrderProto@3@@std@@ + [0x2835790] .?AV?$_Func_impl_no_alloc@V@?BF@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVCustomFstProto@3@@std@@ + [0x2835830] .?AV?$_Func_base@X$$QEAVMathFmDetProto@OneOCR@@@std@@ + [0x2835880] .?AV?$_Func_base@X$$QEAVCheckboxDetectorProto@OneOCR@@@std@@ + [0x28358d0] .?AV?$_Func_impl_no_alloc@V@?O@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVLangIDProto@3@@std@@ + [0x2835970] .?AV?$_Func_impl_no_alloc@V@?7??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVDecoderProto@3@@std@@ + [0x2835a10] .?AV?$_Func_base@X$$QEAVTextEmbeddingProto@OneOCR@@@std@@ + [0x2835a60] .?AV?$_Func_impl_no_alloc@V@?BB@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVPODRegionGroupingProto@3@@std@@ + [0x2835b60] .?AV?$_Func_impl_no_alloc@V@?BH@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVMathFmLineDecProto@3@@std@@ + [0x2835c00] .?AV?$_Func_base@X$$QEAVTOCProto@OneOCR@@@std@@ + [0x2835c40] .?AV?$_Func_base@X$$QEAVEntityClassifierProto@OneOCR@@@std@@ + [0x2835c90] .?AV?$_Func_impl_no_alloc@V@?BG@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVMathFmDetProto@3@@std@@ + [0x2835d30] .?AV?$_Func_base@X$$QEAVFormDetectorProto@OneOCR@@@std@@ + [0x2835d80] .?AV?$_Func_base@X$$QEAVLineLayoutClsProto@OneOCR@@@std@@ + [0x2835dd0] .?AV?$_Func_base@X$$QEAVDecoderProto@OneOCR@@@std@@ + [0x2835e20] .?AV?$_Func_base@X$$QEAVConfidenceProto@OneOCR@@@std@@ + [0x2835e70] .?AV?$_Func_base@X$$QEAVTableDetectorProto@OneOCR@@@std@@ + [0x2835ec0] .?AV?$_Func_impl_no_alloc@V@?4??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVLineLayoutClsProto@3@@std@@ + [0x2835f60] .?AV?$_Func_impl_no_alloc@V@?5??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVFontClsProto@3@@std@@ + [0x2836000] .?AV?$_Func_impl_no_alloc@V@?BI@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVMathFmLineRejProto@3@@std@@ + [0x28360a0] .?AV?$_Func_impl_no_alloc@V@?BA@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVPODBackboneProto@3@@std@@ + [0x2836140] .?AV?$_Func_impl_no_alloc@V@?P@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVFormDetectorProto@3@@std@@ + [0x28361e0] .?AV?$_Func_impl_no_alloc@V@?BE@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVEntityClassifierProto@3@@std@@ + [0x2836280] .?AV?$_Func_impl_no_alloc@V@?BK@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVMathFmLineEncProto@3@@std@@ + [0x2836320] .?AV?$_Func_base@X$$QEAVCustomFstProto@OneOCR@@@std@@ + [0x2836370] .?AV?$_Func_impl_no_alloc@V@?6??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVCharProto@3@@std@@ + [0x2836400] .?AV?$_Func_impl_no_alloc@V@?M@??ReloadPipelineProto@OneOCR@@YAAEAVPipelineProto@3@AEAV43@@Z@X$$QEAVTableDetectorProto@3@@std@@ + +Total: 599 diff --git a/_archive/temp/re_output/14_demangled.txt b/_archive/temp/re_output/14_demangled.txt new file mode 100644 index 0000000000000000000000000000000000000000..f86907de6a3ef1e11a962dbf1c3d198472d720bf --- /dev/null +++ b/_archive/temp/re_output/14_demangled.txt @@ -0,0 +1,2 @@ +DEMANGLED OneOCR NAMES +============================================================ diff --git a/_archive/temp/re_output/15_manifest_decoded.txt b/_archive/temp/re_output/15_manifest_decoded.txt new file mode 100644 index 0000000000000000000000000000000000000000..490b4adfe4536872061c84fc5b8c3e26f46db0c2 --- /dev/null +++ b/_archive/temp/re_output/15_manifest_decoded.txt @@ -0,0 +1,1181 @@ +Manifest size: 11903 bytes +============================================================ +DECODED PROTOBUF +============================================================ +Field 1 (message, 326 bytes): + Field 1 (string): "Universal" + Field 2 (varint): 2 + Field 3 (string): " +z +x\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Detector\Universal\ONNX\b512-SyncBN-x4_rpn_batch_quant_if.onnx" + Field 8 (32-bit/float): 0.699999988079071 (int: 1060320051) + Field 9 (message, 9 bytes): + Field 1 (string): "P2" + Field 2 (32-bit/float): 0.699999988079071 (int: 1060320051) + Field 9 (message, 9 bytes): + Field 1 (string): "P3" + Field 2 (32-bit/float): 0.800000011920929 (int: 1061997773) + Field 9 (message, 9 bytes): + Field 1 (string): "P4" + Field 2 (32-bit/float): 0.800000011920929 (int: 1061997773) + Field 10 (32-bit/float): 0.20000000298023224 (int: 1045220557) + Field 11 (32-bit/float): 0.4000000059604645 (int: 1053609165) + Field 13 (32-bit/float): 0.800000011920929 (int: 1061997773) + Field 14 (varint): 1 + Field 15 (32-bit/float): 0.30000001192092896 (int: 1050253722) + Field 16 (32-bit/float): 0.5 (int: 1056964608) + Field 17 (32-bit/float): 0.4000000059604645 (int: 1053609165) + Field 18 (bytes, 1): 00 + Field 19 (varint): 4 + Field 20 (32-bit/float): 0.3199999928474426 (int: 1050924810) + Field 21 (32-bit/float): 0.30000001192092896 (int: 1050253722) + Field 22 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Detector\Universal\checkbox_cal.txt" +Field 3 (message, 448 bytes): + Field 1 (string): "ArabicMixed" + Field 2 (varint): 3 + Field 3 (string): " +p +n\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\ArabicMixed\ONNX\checkpoint.075_quant.onnx" + Field 4 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\ArabicMixed\rnn.info" + Field 5 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\ArabicMixed\char2ind.txt" + Field 6 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\ArabicMixed\char2inschar.txt" + Field 7 (varint): 4 + Field 8 (varint): 12 + Field 9 (varint): 18446744073709551594 + Field 10 (varint): 11 + Field 13 (32-bit/float): 9.999999747378752e-05 (int: 953267991) + Field 14 (varint): 30 + Field 15 (32-bit/float): 0.9900000095367432 (int: 1065185444) + Field 16 (32-bit/float): 0.05000000074505806 (int: 1028443341) +Field 3 (message, 443 bytes): + Field 1 (string): "CJKPrinted" + Field 2 (varint): 1 + Field 3 (string): " +o +m\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\CJKPrinted\ONNX\checkpoint.075_quant.onnx" + Field 4 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\CJKPrinted\rnn.info" + Field 5 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\CJKPrinted\char2ind.txt" + Field 6 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\CJKPrinted\char2inschar.txt" + Field 7 (varint): 8 + Field 8 (varint): 1 + Field 9 (varint): 18446744073709551610 + Field 10 (varint): 33 + Field 13 (32-bit/float): 9.999999747378752e-05 (int: 953267991) + Field 14 (varint): 30 + Field 15 (32-bit/float): 0.9900000095367432 (int: 1065185444) + Field 16 (32-bit/float): 0.05000000074505806 (int: 1028443341) +Field 3 (message, 561 bytes): + Field 1 (string): "CyrillicMixed" + Field 2 (varint): 2 + Field 3 (string): " +r +p\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\CyrillicMixed\ONNX\checkpoint.075_quant.onnx" + Field 4 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\CyrillicMixed\rnn.info" + Field 5 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\CyrillicMixed\char2ind.txt" + Field 6 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\CyrillicMixed\char2inschar.txt" + Field 7 (varint): 8 + Field 8 (varint): 12 + Field 9 (varint): 18446744073709551602 + Field 10 (varint): 14 + Field 12 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\CyrillicMixed\composite_chars_map" + Field 13 (32-bit/float): 9.999999747378752e-05 (int: 953267991) + Field 14 (varint): 30 + Field 15 (32-bit/float): 0.9900000095367432 (int: 1065185444) + Field 16 (32-bit/float): 0.05000000074505806 (int: 1028443341) +Field 3 (message, 468 bytes): + Field 1 (string): "DevanagariMixed" + Field 2 (varint): 4 + Field 3 (string): " +t +r\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\DevanagariMixed\ONNX\checkpoint.075_quant.onnx" + Field 4 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\DevanagariMixed\rnn.info" + Field 5 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\DevanagariMixed\char2ind.txt" + Field 6 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\DevanagariMixed\char2inschar.txt" + Field 7 (varint): 4 + Field 8 (varint): 12 + Field 9 (varint): 18446744073709551608 + Field 10 (varint): 19 + Field 13 (32-bit/float): 9.999999747378752e-05 (int: 953267991) + Field 14 (varint): 30 + Field 15 (32-bit/float): 0.9900000095367432 (int: 1065185444) + Field 16 (32-bit/float): 0.05000000074505806 (int: 1028443341) +Field 3 (message, 443 bytes): + Field 1 (string): "GreekMixed" + Field 2 (varint): 5 + Field 3 (string): " +o +m\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\GreekMixed\ONNX\checkpoint.075_quant.onnx" + Field 4 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\GreekMixed\rnn.info" + Field 5 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\GreekMixed\char2ind.txt" + Field 6 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\GreekMixed\char2inschar.txt" + Field 7 (varint): 4 + Field 8 (varint): 12 + Field 9 (varint): 18446744073709551601 + Field 10 (varint): 18 + Field 13 (32-bit/float): 9.999999747378752e-05 (int: 953267991) + Field 14 (varint): 30 + Field 15 (32-bit/float): 0.9900000095367432 (int: 1065185444) + Field 16 (32-bit/float): 0.05000000074505806 (int: 1028443341) +Field 3 (message, 561 bytes): + Field 1 (string): "HebrewPrinted" + Field 2 (varint): 7 + Field 3 (string): " +r +p\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\HebrewPrinted\ONNX\checkpoint.075_quant.onnx" + Field 4 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\HebrewPrinted\rnn.info" + Field 5 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\HebrewPrinted\char2ind.txt" + Field 6 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\HebrewPrinted\char2inschar.txt" + Field 7 (varint): 4 + Field 8 (varint): 12 + Field 9 (varint): 18446744073709551588 + Field 10 (varint): 8 + Field 12 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\HebrewPrinted\composite_chars_map" + Field 13 (32-bit/float): 9.999999747378752e-05 (int: 953267991) + Field 14 (varint): 30 + Field 15 (32-bit/float): 0.9900000095367432 (int: 1065185444) + Field 16 (32-bit/float): 0.05000000074505806 (int: 1028443341) +Field 3 (message, 565 bytes): + Field 1 (string): "LatinPrintedV2" + Field 3 (string): " +s +q\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\LatinPrintedV2\ONNX\checkpoint.075_quant.onnx" + Field 4 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\LatinPrintedV2\rnn.info" + Field 5 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\LatinPrintedV2\char2ind.txt" + Field 6 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\LatinPrintedV2\char2inschar.txt" + Field 7 (varint): 4 + Field 8 (varint): 12 + Field 9 (varint): 18446744073709551606 + Field 10 (varint): 21 + Field 12 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\LatinPrintedV2\composite_chars_map" + Field 13 (32-bit/float): 9.999999747378752e-05 (int: 953267991) + Field 14 (varint): 30 + Field 15 (32-bit/float): 0.9900000095367432 (int: 1065185444) + Field 16 (32-bit/float): 0.05000000074505806 (int: 1028443341) +Field 3 (message, 453 bytes): + Field 1 (string): "TamilPrinted" + Field 2 (varint): 8 + Field 3 (string): " +q +o\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\TamilPrinted\ONNX\checkpoint.075_quant.onnx" + Field 4 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\TamilPrinted\rnn.info" + Field 5 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\TamilPrinted\char2ind.txt" + Field 6 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\TamilPrinted\char2inschar.txt" + Field 7 (varint): 4 + Field 8 (varint): 12 + Field 9 (varint): 18446744073709551608 + Field 10 (varint): 13 + Field 13 (32-bit/float): 9.999999747378752e-05 (int: 953267991) + Field 14 (varint): 30 + Field 15 (32-bit/float): 0.9900000095367432 (int: 1065185444) + Field 16 (32-bit/float): 0.05000000074505806 (int: 1028443341) +Field 3 (message, 427 bytes): + Field 1 (string): "ThaiMixed" + Field 2 (varint): 6 + Field 3 (string): " +n +l\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\ThaiMixed\ONNX\checkpoint.075_quant.onnx" + Field 4 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\ThaiMixed\rnn.info" + Field 5 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\ThaiMixed\char2ind.txt" + Field 6 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Character\ThaiMixed\char2inschar.txt" + Field 7 (varint): 4 + Field 8 (varint): 1 + Field 10 (varint): 18 + Field 13 (32-bit/float): 9.999999747378752e-05 (int: 953267991) + Field 14 (varint): 30 + Field 15 (32-bit/float): 0.9900000095367432 (int: 1065185444) + Field 16 (32-bit/float): 0.05000000074505806 (int: 1028443341) +Field 7 (message, 175 bytes): + Field 1 (string): "ArabicMixedDummy" + Field 2 (message, 136 bytes): + Field 1 (message, 133 bytes): + Field 1 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Rejection\ArabicMixedDummy\ONNX\rejection_model_2023_11_07_17_52_40.onnx" + Field 3 (64-bit/double): 0.2911 + Field 4 (64-bit/double): 0.2911 +Field 7 (message, 168 bytes): + Field 1 (string): "CJKMixedDummy" + Field 2 (message, 132 bytes): + Field 1 (message, 129 bytes): + Field 1 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Rejection\CJKMixedDummy\ONNX\rejection_model_2023_09_01_14_00_33.onnx" + Field 3 (64-bit/double): 0.2548 + Field 4 (64-bit/double): 0.2548 +Field 7 (message, 173 bytes): + Field 1 (string): "CJKPrintedDummy" + Field 2 (message, 135 bytes): + Field 1 (message, 132 bytes): + Field 1 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Rejection\CJKPrintedDummy\ONNX\rejection_model_2023_10_13_22_18_19.onnx" + Field 3 (64-bit/double): 0.3136 + Field 4 (64-bit/double): 0.3136 +Field 7 (message, 179 bytes): + Field 1 (string): "CyrillicMixedDummy" + Field 2 (message, 138 bytes): + Field 1 (message, 135 bytes): + Field 1 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Rejection\CyrillicMixedDummy\ONNX\rejection_model_2023_12_20_08_37_34.onnx" + Field 3 (64-bit/double): 0.2088 + Field 4 (64-bit/double): 0.2088 +Field 7 (message, 183 bytes): + Field 1 (string): "DevanagariMixedDummy" + Field 2 (message, 140 bytes): + Field 1 (message, 137 bytes): + Field 1 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Rejection\DevanagariMixedDummy\ONNX\rejection_model_2023_11_09_11_20_46.onnx" + Field 3 (64-bit/double): 0.228 + Field 4 (64-bit/double): 0.228 +Field 7 (message, 173 bytes): + Field 1 (string): "GreekMixedDummy" + Field 2 (message, 135 bytes): + Field 1 (message, 132 bytes): + Field 1 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Rejection\GreekMixedDummy\ONNX\rejection_model_2023_10_17_00_59_30.onnx" + Field 3 (64-bit/double): 0.3124 + Field 4 (64-bit/double): 0.3124 +Field 7 (message, 179 bytes): + Field 1 (string): "HebrewPrintedDummy" + Field 2 (message, 138 bytes): + Field 1 (message, 135 bytes): + Field 1 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Rejection\HebrewPrintedDummy\ONNX\rejection_model_2023_09_19_13_43_18.onnx" + Field 3 (64-bit/double): 0.1042 + Field 4 (64-bit/double): 0.1042 +Field 7 (message, 177 bytes): + Field 1 (string): "LatinMixedV2Dummy" + Field 2 (message, 137 bytes): + Field 1 (message, 134 bytes): + Field 1 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Rejection\LatinMixedV2Dummy\ONNX\rejection_model_2024_05_22_15_26_18.onnx" + Field 3 (64-bit/double): 0.161 + Field 4 (64-bit/double): 0.0881 +Field 7 (message, 181 bytes): + Field 1 (string): "LatinPrintedV2Dummy" + Field 2 (message, 139 bytes): + Field 1 (message, 136 bytes): + Field 1 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Rejection\LatinPrintedV2Dummy\ONNX\rejection_model_2024_05_11_09_59_43.onnx" + Field 3 (64-bit/double): 0.3516 + Field 4 (64-bit/double): 0.0552 +Field 7 (message, 177 bytes): + Field 1 (string): "TamilPrintedDummy" + Field 2 (message, 137 bytes): + Field 1 (message, 134 bytes): + Field 1 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Rejection\TamilPrintedDummy\ONNX\rejection_model_2023_09_23_03_16_05.onnx" + Field 3 (64-bit/double): 0.0443 + Field 4 (64-bit/double): 0.0443 +Field 7 (message, 171 bytes): + Field 1 (string): "ThaiMixedDummy" + Field 2 (message, 134 bytes): + Field 1 (message, 131 bytes): + Field 1 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Rejection\ThaiMixedDummy\ONNX\rejection_model_2023_12_20_02_48_57.onnx" + Field 3 (64-bit/double): 0.3371 + Field 4 (64-bit/double): 0.3371 +Field 9 (message, 174 bytes): + Field 1 (string): "ArabicMixedDummy" + Field 2 (message, 144 bytes): + Field 1 (message, 141 bytes): + Field 1 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Confidence\ArabicMixedDummy\confidence_model_calibrated_2023_11_08_01_38_34.onnx" + Field 3 (64-bit/double): 0.5 +Field 9 (message, 168 bytes): + Field 1 (string): "CJKMixedDummy" + Field 2 (message, 141 bytes): + Field 1 (message, 138 bytes): + Field 1 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Confidence\CJKMixedDummy\confidence_model_calibrated_2023_09_03_02_20_39.onnx" + Field 3 (64-bit/double): 0.5 +Field 9 (message, 172 bytes): + Field 1 (string): "CJKPrintedDummy" + Field 2 (message, 143 bytes): + Field 1 (message, 140 bytes): + Field 1 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Confidence\CJKPrintedDummy\confidence_model_calibrated_2023_10_14_08_04_58.onnx" + Field 3 (64-bit/double): 0.5 +Field 9 (message, 178 bytes): + Field 1 (string): "CyrillicMixedDummy" + Field 2 (message, 146 bytes): + Field 1 (message, 143 bytes): + Field 1 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Confidence\CyrillicMixedDummy\confidence_model_calibrated_2023_12_20_16_40_47.onnx" + Field 3 (64-bit/double): 0.5 +Field 9 (message, 182 bytes): + Field 1 (string): "DevanagariMixedDummy" + Field 2 (message, 148 bytes): + Field 1 (message, 145 bytes): + Field 1 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Confidence\DevanagariMixedDummy\confidence_model_calibrated_2023_11_09_19_08_44.onnx" + Field 3 (64-bit/double): 0.5 +Field 9 (message, 172 bytes): + Field 1 (string): "GreekMixedDummy" + Field 2 (message, 143 bytes): + Field 1 (message, 140 bytes): + Field 1 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Confidence\GreekMixedDummy\confidence_model_calibrated_2023_10_17_08_51_21.onnx" + Field 3 (64-bit/double): 0.5 +Field 9 (message, 178 bytes): + Field 1 (string): "HebrewPrintedDummy" + Field 2 (message, 146 bytes): + Field 1 (message, 143 bytes): + Field 1 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Confidence\HebrewPrintedDummy\confidence_model_calibrated_2023_09_19_21_37_42.onnx" + Field 3 (64-bit/double): 0.5 +Field 9 (message, 176 bytes): + Field 1 (string): "LatinMixedV2Dummy" + Field 2 (message, 145 bytes): + Field 1 (message, 142 bytes): + Field 1 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Confidence\LatinMixedV2Dummy\confidence_model_calibrated_2024_05_22_21_36_00.onnx" + Field 3 (64-bit/double): 0.5 +Field 9 (message, 180 bytes): + Field 1 (string): "LatinPrintedV2Dummy" + Field 2 (message, 147 bytes): + Field 1 (message, 144 bytes): + Field 1 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Confidence\LatinPrintedV2Dummy\confidence_model_calibrated_2024_05_11_17_44_41.onnx" + Field 3 (64-bit/double): 0.5 +Field 9 (message, 176 bytes): + Field 1 (string): "TamilPrintedDummy" + Field 2 (message, 145 bytes): + Field 1 (message, 142 bytes): + Field 1 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Confidence\TamilPrintedDummy\confidence_model_calibrated_2023_09_23_11_04_27.onnx" + Field 3 (64-bit/double): 0.5 +Field 9 (message, 170 bytes): + Field 1 (string): "ThaiMixedDummy" + Field 2 (message, 142 bytes): + Field 1 (message, 139 bytes): + Field 1 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Confidence\ThaiMixedDummy\confidence_model_calibrated_2023_12_20_11_14_35.onnx" + Field 3 (64-bit/double): 0.5 +Field 13 (message, 126 bytes): + Field 1 (string): "CJK" + Field 2 (string): " +c +a\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\LineLayout\CJK\ONNX\checkpoint.040.onnx" + Field 3 (64-bit/double): 2.85 + Field 4 (64-bit/double): 3.1 +Field 20 (message, 360 bytes): + Field 1 (string): "AuxMltCls" + Field 2 (string): " +^ +\\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\AuxMltCls\ONNX\checkpoint.040.onnx" + Field 3 (64-bit/double): 4.1 + Field 4 (64-bit/double): -2.0 + Field 6 (64-bit/double): -5.0 + Field 7 (64-bit/double): 5.0 + Field 8 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\AuxMltCls\handwritten_calibration_map.txt" + Field 9 (varint): 3 + Field 10 (message, 14 bytes): + Field 1 (string): "Devanagari" + Field 2 (varint): 2 + Field 10 (message, 9 bytes): + Field 1 (string): "Tamil" + Field 2 (varint): 3 + Field 10 (message, 8 bytes): + Field 1 (string): "Thai" + Field 2 (varint): 3 + Field 10 (message, 7 bytes): + Field 1 (string): "CJK" + Field 2 (varint): 3 + Field 10 (message, 12 bytes): + Field 1 (string): "Cyrillic" + Field 2 (varint): 1 + Field 10 (message, 9 bytes): + Field 1 (string): "Greek" + Field 2 (varint): 3 + Field 10 (message, 10 bytes): + Field 1 (string): "Hebrew" + Field 2 (varint): 3 + Field 11 (64-bit/double): 5.0 + Field 13 (message, 18 bytes): + Field 3 (64-bit/double): 2.85 + Field 4 (64-bit/double): 3.1 +Field 22 (message, 12 bytes): + Field 1 (varint): 1 + Field 2 (varint): 1 + Field 3 (varint): 1 + Field 4 (varint): 1 + Field 8 (varint): 1 + Field 9 (varint): 1 +Field 23 (message, 8 bytes): + Field 1 (varint): 1 + Field 2 (varint): 1 + Field 3 (varint): 1 + Field 4 (varint): 1 +Field 24 (message, 4 bytes): + Field 1 (varint): 1 + Field 2 (varint): 1 +Field 25 (varint): 1 +Field 26 (message, 815 bytes): + Field 1 (message, 88 bytes): + Field 1 (message, 43 bytes): + Field 1 (string): "ONEOCR_ORT_ALLOW_INTRA_OP_SPINNING" + Field 2 (string): "false" + Field 1 (message, 41 bytes): + Field 1 (string): "ONEOCR_ORT_USE_SESSION_THREADPOOL" + Field 2 (string): "true" + Field 2 (message, 156 bytes): + Field 1 (message, 43 bytes): + Field 1 (string): "ONEOCR_ORT_ALLOW_INTRA_OP_SPINNING" + Field 2 (string): "false" + Field 1 (message, 32 bytes): + Field 1 (string): "ONEOCR_ORT_INTRA_OP_THREADS" + Field 2 (string): "1" + Field 1 (message, 41 bytes): + Field 1 (string): "ONEOCR_ORT_USE_SESSION_THREADPOOL" + Field 2 (string): "true" + Field 1 (message, 32 bytes): + Field 1 (string): "ONEOCR_ORT_DISABLE_QUANTQDQ" + Field 2 (string): "1" + Field 3 (message, 122 bytes): + Field 1 (message, 32 bytes): + Field 1 (string): "ONEOCR_ORT_INTRA_OP_THREADS" + Field 2 (string): "1" + Field 1 (message, 43 bytes): + Field 1 (string): "ONEOCR_ORT_ALLOW_INTRA_OP_SPINNING" + Field 2 (string): "false" + Field 1 (message, 41 bytes): + Field 1 (string): "ONEOCR_ORT_USE_SESSION_THREADPOOL" + Field 2 (string): "true" + Field 4 (message, 122 bytes): + Field 1 (message, 43 bytes): + Field 1 (string): "ONEOCR_ORT_ALLOW_INTRA_OP_SPINNING" + Field 2 (string): "false" + Field 1 (message, 41 bytes): + Field 1 (string): "ONEOCR_ORT_USE_SESSION_THREADPOOL" + Field 2 (string): "true" + Field 1 (message, 32 bytes): + Field 1 (string): "ONEOCR_ORT_INTRA_OP_THREADS" + Field 2 (string): "1" + Field 8 (message, 156 bytes): + Field 1 (message, 43 bytes): + Field 1 (string): "ONEOCR_ORT_ALLOW_INTRA_OP_SPINNING" + Field 2 (string): "false" + Field 1 (message, 41 bytes): + Field 1 (string): "ONEOCR_ORT_USE_SESSION_THREADPOOL" + Field 2 (string): "true" + Field 1 (message, 32 bytes): + Field 1 (string): "ONEOCR_ORT_INTRA_OP_THREADS" + Field 2 (string): "1" + Field 1 (message, 32 bytes): + Field 1 (string): "ONEOCR_ORT_DISABLE_QUANTQDQ" + Field 2 (string): "1" + Field 9 (message, 156 bytes): + Field 1 (message, 32 bytes): + Field 1 (string): "ONEOCR_ORT_DISABLE_QUANTQDQ" + Field 2 (string): "1" + Field 1 (message, 43 bytes): + Field 1 (string): "ONEOCR_ORT_ALLOW_INTRA_OP_SPINNING" + Field 2 (string): "false" + Field 1 (message, 32 bytes): + Field 1 (string): "ONEOCR_ORT_INTRA_OP_THREADS" + Field 2 (string): "1" + Field 1 (message, 41 bytes): + Field 1 (string): "ONEOCR_ORT_USE_SESSION_THREADPOOL" + Field 2 (string): "true" +Field 41 (message, 1813 bytes): + Field 1 (message, 3 bytes): + Field 2 (varint): 1109 + Field 1 (message, 5 bytes): + Field 1 (varint): 3 + Field 2 (varint): 1109 + Field 1 (message, 5 bytes): + Field 1 (varint): 2 + Field 2 (varint): 1403 + Field 1 (message, 5 bytes): + Field 1 (varint): 4 + Field 2 (varint): 1500 + Field 1 (message, 5 bytes): + Field 1 (varint): 5 + Field 2 (varint): 1600 + Field 1 (message, 5 bytes): + Field 1 (varint): 6 + Field 2 (varint): 1700 + Field 1 (message, 5 bytes): + Field 1 (varint): 7 + Field 2 (varint): 1800 + Field 1 (message, 5 bytes): + Field 1 (varint): 8 + Field 2 (varint): 1900 + Field 1 (message, 5 bytes): + Field 1 (varint): 9 + Field 2 (varint): 2000 + Field 1 (message, 5 bytes): + Field 1 (varint): 10 + Field 2 (varint): 2100 + Field 2 (message, 7 bytes): + Field 1 (varint): 3 + Field 2 (varint): 2 + Field 3 (varint): 1107 + Field 2 (message, 7 bytes): + Field 1 (varint): 3 + Field 2 (varint): 1 + Field 3 (varint): 1106 + Field 2 (message, 5 bytes): + Field 1 (varint): 3 + Field 3 (varint): 1107 + Field 2 (message, 7 bytes): + Field 1 (varint): 2 + Field 2 (varint): 2 + Field 3 (varint): 1402 + Field 2 (message, 7 bytes): + Field 1 (varint): 2 + Field 2 (varint): 1 + Field 3 (varint): 1401 + Field 2 (message, 5 bytes): + Field 1 (varint): 2 + Field 3 (varint): 1402 + Field 2 (message, 7 bytes): + Field 1 (varint): 4 + Field 2 (varint): 2 + Field 3 (varint): 1502 + Field 2 (message, 7 bytes): + Field 1 (varint): 4 + Field 2 (varint): 1 + Field 3 (varint): 1502 + Field 2 (message, 5 bytes): + Field 1 (varint): 4 + Field 3 (varint): 1502 + Field 2 (message, 7 bytes): + Field 1 (varint): 5 + Field 2 (varint): 2 + Field 3 (varint): 1602 + Field 2 (message, 7 bytes): + Field 1 (varint): 5 + Field 2 (varint): 1 + Field 3 (varint): 1602 + Field 2 (message, 5 bytes): + Field 1 (varint): 5 + Field 3 (varint): 1602 + Field 2 (message, 7 bytes): + Field 1 (varint): 6 + Field 2 (varint): 2 + Field 3 (varint): 1702 + Field 2 (message, 7 bytes): + Field 1 (varint): 6 + Field 2 (varint): 1 + Field 3 (varint): 1702 + Field 2 (message, 5 bytes): + Field 1 (varint): 6 + Field 3 (varint): 1702 + Field 2 (message, 7 bytes): + Field 1 (varint): 7 + Field 2 (varint): 2 + Field 3 (varint): 1802 + Field 2 (message, 7 bytes): + Field 1 (varint): 7 + Field 2 (varint): 1 + Field 3 (varint): 1802 + Field 2 (message, 5 bytes): + Field 1 (varint): 7 + Field 3 (varint): 1802 + Field 2 (message, 7 bytes): + Field 1 (varint): 8 + Field 2 (varint): 2 + Field 3 (varint): 1902 + Field 2 (message, 7 bytes): + Field 1 (varint): 8 + Field 2 (varint): 1 + Field 3 (varint): 1902 + Field 2 (message, 5 bytes): + Field 1 (varint): 8 + Field 3 (varint): 1902 + Field 2 (message, 7 bytes): + Field 1 (varint): 9 + Field 2 (varint): 2 + Field 3 (varint): 2001 + Field 2 (message, 7 bytes): + Field 1 (varint): 9 + Field 2 (varint): 1 + Field 3 (varint): 2001 + Field 2 (message, 5 bytes): + Field 1 (varint): 9 + Field 3 (varint): 2001 + Field 2 (message, 7 bytes): + Field 1 (varint): 10 + Field 2 (varint): 2 + Field 3 (varint): 2101 + Field 2 (message, 7 bytes): + Field 1 (varint): 10 + Field 2 (varint): 1 + Field 3 (varint): 2101 + Field 2 (message, 5 bytes): + Field 1 (varint): 10 + Field 3 (varint): 2101 + Field 3 (message, 5 bytes): + Field 1 (varint): 1001 + Field 2 (varint): 1 + Field 3 (message, 5 bytes): + Field 1 (varint): 1106 + Field 2 (varint): 1 + Field 3 (message, 3 bytes): + Field 1 (varint): 1107 + Field 3 (message, 5 bytes): + Field 1 (varint): 1108 + Field 2 (varint): 1 + Field 3 (message, 5 bytes): + Field 1 (varint): 1109 + Field 2 (varint): 1 + Field 3 (message, 5 bytes): + Field 1 (varint): 1401 + Field 2 (varint): 1 + Field 3 (message, 3 bytes): + Field 1 (varint): 1402 + Field 3 (message, 5 bytes): + Field 1 (varint): 1403 + Field 2 (varint): 1 + Field 3 (message, 3 bytes): + Field 1 (varint): 1500 + Field 3 (message, 5 bytes): + Field 1 (varint): 1501 + Field 2 (varint): 1 + Field 3 (message, 3 bytes): + Field 1 (varint): 1502 + Field 3 (message, 5 bytes): + Field 1 (varint): 1503 + Field 2 (varint): 1 + Field 3 (message, 3 bytes): + Field 1 (varint): 1504 + Field 3 (message, 3 bytes): + Field 1 (varint): 1600 + Field 3 (message, 5 bytes): + Field 1 (varint): 1601 + Field 2 (varint): 1 + Field 3 (message, 3 bytes): + Field 1 (varint): 1602 + Field 3 (message, 5 bytes): + Field 1 (varint): 1603 + Field 2 (varint): 1 + Field 3 (message, 3 bytes): + Field 1 (varint): 1604 + Field 3 (message, 3 bytes): + Field 1 (varint): 1700 + Field 3 (message, 5 bytes): + Field 1 (varint): 1701 + Field 2 (varint): 1 + Field 3 (message, 3 bytes): + Field 1 (varint): 1702 + Field 3 (message, 5 bytes): + Field 1 (varint): 1703 + Field 2 (varint): 1 + Field 3 (message, 3 bytes): + Field 1 (varint): 1704 + Field 3 (message, 3 bytes): + Field 1 (varint): 1800 + Field 3 (message, 5 bytes): + Field 1 (varint): 1801 + Field 2 (varint): 1 + Field 3 (message, 3 bytes): + Field 1 (varint): 1802 + Field 3 (message, 5 bytes): + Field 1 (varint): 1803 + Field 2 (varint): 1 + Field 3 (message, 3 bytes): + Field 1 (varint): 1804 + Field 3 (message, 3 bytes): + Field 1 (varint): 1900 + Field 3 (message, 5 bytes): + Field 1 (varint): 1901 + Field 2 (varint): 1 + Field 3 (message, 3 bytes): + Field 1 (varint): 1902 + Field 3 (message, 5 bytes): + Field 1 (varint): 1903 + Field 2 (varint): 1 + Field 3 (message, 3 bytes): + Field 1 (varint): 1904 + Field 3 (message, 5 bytes): + Field 1 (varint): 2000 + Field 2 (varint): 1 + Field 3 (message, 5 bytes): + Field 1 (varint): 2001 + Field 2 (varint): 1 + Field 3 (message, 3 bytes): + Field 1 (varint): 2002 + Field 3 (message, 5 bytes): + Field 1 (varint): 2003 + Field 2 (varint): 1 + Field 3 (message, 5 bytes): + Field 1 (varint): 2100 + Field 2 (varint): 1 + Field 3 (message, 5 bytes): + Field 1 (varint): 2101 + Field 2 (varint): 1 + Field 3 (message, 3 bytes): + Field 1 (varint): 2102 + Field 3 (message, 5 bytes): + Field 1 (varint): 2103 + Field 2 (varint): 1 + Field 4 (message, 5 bytes): + Field 1 (varint): 1001 + Field 2 (varint): 3 + Field 4 (message, 5 bytes): + Field 1 (varint): 1106 + Field 2 (varint): 3 + Field 4 (message, 5 bytes): + Field 1 (varint): 1107 + Field 2 (varint): 3 + Field 4 (message, 5 bytes): + Field 1 (varint): 1109 + Field 2 (varint): 3 + Field 4 (message, 5 bytes): + Field 1 (varint): 1108 + Field 2 (varint): 3 + Field 4 (message, 5 bytes): + Field 1 (varint): 1401 + Field 2 (varint): 2 + Field 4 (message, 5 bytes): + Field 1 (varint): 1402 + Field 2 (varint): 2 + Field 4 (message, 5 bytes): + Field 1 (varint): 1403 + Field 2 (varint): 2 + Field 4 (message, 5 bytes): + Field 1 (varint): 1501 + Field 2 (varint): 4 + Field 4 (message, 5 bytes): + Field 1 (varint): 1502 + Field 2 (varint): 4 + Field 4 (message, 5 bytes): + Field 1 (varint): 1500 + Field 2 (varint): 4 + Field 4 (message, 5 bytes): + Field 1 (varint): 1503 + Field 2 (varint): 4 + Field 4 (message, 5 bytes): + Field 1 (varint): 1504 + Field 2 (varint): 4 + Field 4 (message, 5 bytes): + Field 1 (varint): 1601 + Field 2 (varint): 5 + Field 4 (message, 5 bytes): + Field 1 (varint): 1602 + Field 2 (varint): 5 + Field 4 (message, 5 bytes): + Field 1 (varint): 1600 + Field 2 (varint): 5 + Field 4 (message, 5 bytes): + Field 1 (varint): 1603 + Field 2 (varint): 5 + Field 4 (message, 5 bytes): + Field 1 (varint): 1604 + Field 2 (varint): 5 + Field 4 (message, 5 bytes): + Field 1 (varint): 1701 + Field 2 (varint): 6 + Field 4 (message, 5 bytes): + Field 1 (varint): 1702 + Field 2 (varint): 6 + Field 4 (message, 5 bytes): + Field 1 (varint): 1700 + Field 2 (varint): 6 + Field 4 (message, 5 bytes): + Field 1 (varint): 1703 + Field 2 (varint): 6 + Field 4 (message, 5 bytes): + Field 1 (varint): 1704 + Field 2 (varint): 6 + Field 4 (message, 5 bytes): + Field 1 (varint): 1801 + Field 2 (varint): 7 + Field 4 (message, 5 bytes): + Field 1 (varint): 1802 + Field 2 (varint): 7 + Field 4 (message, 5 bytes): + Field 1 (varint): 1800 + Field 2 (varint): 7 + Field 4 (message, 5 bytes): + Field 1 (varint): 1803 + Field 2 (varint): 7 + Field 4 (message, 5 bytes): + Field 1 (varint): 1804 + Field 2 (varint): 7 + Field 4 (message, 5 bytes): + Field 1 (varint): 1901 + Field 2 (varint): 8 + Field 4 (message, 5 bytes): + Field 1 (varint): 1902 + Field 2 (varint): 8 + Field 4 (message, 5 bytes): + Field 1 (varint): 1900 + Field 2 (varint): 8 + Field 4 (message, 5 bytes): + Field 1 (varint): 1903 + Field 2 (varint): 8 + Field 4 (message, 5 bytes): + Field 1 (varint): 1904 + Field 2 (varint): 8 + Field 4 (message, 5 bytes): + Field 1 (varint): 2001 + Field 2 (varint): 9 + Field 4 (message, 5 bytes): + Field 1 (varint): 2002 + Field 2 (varint): 9 + Field 4 (message, 5 bytes): + Field 1 (varint): 2000 + Field 2 (varint): 9 + Field 4 (message, 5 bytes): + Field 1 (varint): 2003 + Field 2 (varint): 9 + Field 4 (message, 5 bytes): + Field 1 (varint): 2101 + Field 2 (varint): 10 + Field 4 (message, 5 bytes): + Field 1 (varint): 2102 + Field 2 (varint): 10 + Field 4 (message, 5 bytes): + Field 1 (varint): 2100 + Field 2 (varint): 10 + Field 4 (message, 5 bytes): + Field 1 (varint): 2103 + Field 2 (varint): 10 + Field 5 (message, 6 bytes): + Field 1 (varint): 1001 + Field 2 (varint): 1106 + Field 5 (message, 6 bytes): + Field 1 (varint): 1106 + Field 2 (varint): 1106 + Field 5 (message, 6 bytes): + Field 1 (varint): 1107 + Field 2 (varint): 1106 + Field 5 (message, 6 bytes): + Field 1 (varint): 1108 + Field 2 (varint): 1106 + Field 5 (message, 6 bytes): + Field 1 (varint): 1109 + Field 2 (varint): 1106 + Field 5 (message, 6 bytes): + Field 1 (varint): 1401 + Field 2 (varint): 1401 + Field 5 (message, 6 bytes): + Field 1 (varint): 1402 + Field 2 (varint): 1401 + Field 5 (message, 6 bytes): + Field 1 (varint): 1403 + Field 2 (varint): 1401 + Field 5 (message, 6 bytes): + Field 1 (varint): 1500 + Field 2 (varint): 1502 + Field 5 (message, 6 bytes): + Field 1 (varint): 1501 + Field 2 (varint): 1502 + Field 5 (message, 6 bytes): + Field 1 (varint): 1502 + Field 2 (varint): 1502 + Field 5 (message, 6 bytes): + Field 1 (varint): 1503 + Field 2 (varint): 1502 + Field 5 (message, 6 bytes): + Field 1 (varint): 1504 + Field 2 (varint): 1502 + Field 5 (message, 6 bytes): + Field 1 (varint): 1600 + Field 2 (varint): 1602 + Field 5 (message, 6 bytes): + Field 1 (varint): 1601 + Field 2 (varint): 1602 + Field 5 (message, 6 bytes): + Field 1 (varint): 1602 + Field 2 (varint): 1602 + Field 5 (message, 6 bytes): + Field 1 (varint): 1603 + Field 2 (varint): 1602 + Field 5 (message, 6 bytes): + Field 1 (varint): 1604 + Field 2 (varint): 1602 + Field 5 (message, 6 bytes): + Field 1 (varint): 1700 + Field 2 (varint): 1702 + Field 5 (message, 6 bytes): + Field 1 (varint): 1701 + Field 2 (varint): 1702 + Field 5 (message, 6 bytes): + Field 1 (varint): 1702 + Field 2 (varint): 1702 + Field 5 (message, 6 bytes): + Field 1 (varint): 1703 + Field 2 (varint): 1702 + Field 5 (message, 6 bytes): + Field 1 (varint): 1704 + Field 2 (varint): 1702 + Field 5 (message, 6 bytes): + Field 1 (varint): 1800 + Field 2 (varint): 1802 + Field 5 (message, 6 bytes): + Field 1 (varint): 1801 + Field 2 (varint): 1802 + Field 5 (message, 6 bytes): + Field 1 (varint): 1802 + Field 2 (varint): 1802 + Field 5 (message, 6 bytes): + Field 1 (varint): 1803 + Field 2 (varint): 1802 + Field 5 (message, 6 bytes): + Field 1 (varint): 1804 + Field 2 (varint): 1802 + Field 5 (message, 6 bytes): + Field 1 (varint): 1900 + Field 2 (varint): 1902 + Field 5 (message, 6 bytes): + Field 1 (varint): 1901 + Field 2 (varint): 1902 + Field 5 (message, 6 bytes): + Field 1 (varint): 1902 + Field 2 (varint): 1902 + Field 5 (message, 6 bytes): + Field 1 (varint): 1903 + Field 2 (varint): 1902 + Field 5 (message, 6 bytes): + Field 1 (varint): 1904 + Field 2 (varint): 1902 + Field 5 (message, 6 bytes): + Field 1 (varint): 2000 + Field 2 (varint): 2001 + Field 5 (message, 6 bytes): + Field 1 (varint): 2001 + Field 2 (varint): 2001 + Field 5 (message, 6 bytes): + Field 1 (varint): 2002 + Field 2 (varint): 2001 + Field 5 (message, 6 bytes): + Field 1 (varint): 2003 + Field 2 (varint): 2001 + Field 5 (message, 6 bytes): + Field 1 (varint): 2100 + Field 2 (varint): 2101 + Field 5 (message, 6 bytes): + Field 1 (varint): 2101 + Field 2 (varint): 2101 + Field 5 (message, 6 bytes): + Field 1 (varint): 2102 + Field 2 (varint): 2101 + Field 5 (message, 6 bytes): + Field 1 (varint): 2103 + Field 2 (varint): 2101 + Field 6 (message, 6 bytes): + Field 1 (varint): 1001 + Field 2 (varint): 1106 + Field 6 (message, 6 bytes): + Field 1 (varint): 1106 + Field 2 (varint): 1106 + Field 6 (message, 6 bytes): + Field 1 (varint): 1107 + Field 2 (varint): 1107 + Field 6 (message, 6 bytes): + Field 1 (varint): 1108 + Field 2 (varint): 1108 + Field 6 (message, 6 bytes): + Field 1 (varint): 1109 + Field 2 (varint): 1106 + Field 6 (message, 6 bytes): + Field 1 (varint): 1401 + Field 2 (varint): 1401 + Field 6 (message, 6 bytes): + Field 1 (varint): 1402 + Field 2 (varint): 1402 + Field 6 (message, 6 bytes): + Field 1 (varint): 1403 + Field 2 (varint): 1401 + Field 6 (message, 6 bytes): + Field 1 (varint): 1500 + Field 2 (varint): 1502 + Field 6 (message, 6 bytes): + Field 1 (varint): 1501 + Field 2 (varint): 1502 + Field 6 (message, 6 bytes): + Field 1 (varint): 1502 + Field 2 (varint): 1502 + Field 6 (message, 6 bytes): + Field 1 (varint): 1503 + Field 2 (varint): 1504 + Field 6 (message, 6 bytes): + Field 1 (varint): 1504 + Field 2 (varint): 1504 + Field 6 (message, 6 bytes): + Field 1 (varint): 1600 + Field 2 (varint): 1602 + Field 6 (message, 6 bytes): + Field 1 (varint): 1601 + Field 2 (varint): 1602 + Field 6 (message, 6 bytes): + Field 1 (varint): 1602 + Field 2 (varint): 1602 + Field 6 (message, 6 bytes): + Field 1 (varint): 1603 + Field 2 (varint): 1604 + Field 6 (message, 6 bytes): + Field 1 (varint): 1604 + Field 2 (varint): 1604 + Field 6 (message, 6 bytes): + Field 1 (varint): 1700 + Field 2 (varint): 1702 + Field 6 (message, 6 bytes): + Field 1 (varint): 1701 + Field 2 (varint): 1702 + Field 6 (message, 6 bytes): + Field 1 (varint): 1702 + Field 2 (varint): 1702 + Field 6 (message, 6 bytes): + Field 1 (varint): 1703 + Field 2 (varint): 1704 + Field 6 (message, 6 bytes): + Field 1 (varint): 1704 + Field 2 (varint): 1704 + Field 6 (message, 6 bytes): + Field 1 (varint): 1800 + Field 2 (varint): 1802 + Field 6 (message, 6 bytes): + Field 1 (varint): 1801 + Field 2 (varint): 1802 + Field 6 (message, 6 bytes): + Field 1 (varint): 1802 + Field 2 (varint): 1802 + Field 6 (message, 6 bytes): + Field 1 (varint): 1803 + Field 2 (varint): 1804 + Field 6 (message, 6 bytes): + Field 1 (varint): 1804 + Field 2 (varint): 1804 + Field 6 (message, 6 bytes): + Field 1 (varint): 1900 + Field 2 (varint): 1902 + Field 6 (message, 6 bytes): + Field 1 (varint): 1901 + Field 2 (varint): 1902 + Field 6 (message, 6 bytes): + Field 1 (varint): 1902 + Field 2 (varint): 1902 + Field 6 (message, 6 bytes): + Field 1 (varint): 1903 + Field 2 (varint): 1904 + Field 6 (message, 6 bytes): + Field 1 (varint): 1904 + Field 2 (varint): 1904 + Field 6 (message, 6 bytes): + Field 1 (varint): 2000 + Field 2 (varint): 2001 + Field 6 (message, 6 bytes): + Field 1 (varint): 2001 + Field 2 (varint): 2001 + Field 6 (message, 6 bytes): + Field 1 (varint): 2002 + Field 2 (varint): 2001 + Field 6 (message, 6 bytes): + Field 1 (varint): 2003 + Field 2 (varint): 2003 + Field 6 (message, 6 bytes): + Field 1 (varint): 2100 + Field 2 (varint): 2101 + Field 6 (message, 6 bytes): + Field 1 (varint): 2101 + Field 2 (varint): 2101 + Field 6 (message, 6 bytes): + Field 1 (varint): 2102 + Field 2 (varint): 2101 + Field 6 (message, 6 bytes): + Field 1 (varint): 2103 + Field 2 (varint): 2103 + Field 7 (message, 6 bytes): + Field 1 (varint): 1001 + Field 2 (varint): 1106 + Field 7 (message, 6 bytes): + Field 1 (varint): 1106 + Field 2 (varint): 1106 + Field 7 (message, 6 bytes): + Field 1 (varint): 1107 + Field 2 (varint): 1106 + Field 7 (message, 6 bytes): + Field 1 (varint): 1108 + Field 2 (varint): 1108 + Field 7 (message, 6 bytes): + Field 1 (varint): 1109 + Field 2 (varint): 1106 + Field 7 (message, 6 bytes): + Field 1 (varint): 1401 + Field 2 (varint): 1401 + Field 7 (message, 6 bytes): + Field 1 (varint): 1402 + Field 2 (varint): 1401 + Field 7 (message, 6 bytes): + Field 1 (varint): 1403 + Field 2 (varint): 1401 + Field 7 (message, 6 bytes): + Field 1 (varint): 1500 + Field 2 (varint): 1502 + Field 7 (message, 6 bytes): + Field 1 (varint): 1501 + Field 2 (varint): 1502 + Field 7 (message, 6 bytes): + Field 1 (varint): 1502 + Field 2 (varint): 1502 + Field 7 (message, 6 bytes): + Field 1 (varint): 1503 + Field 2 (varint): 1504 + Field 7 (message, 6 bytes): + Field 1 (varint): 1504 + Field 2 (varint): 1504 + Field 7 (message, 6 bytes): + Field 1 (varint): 1600 + Field 2 (varint): 1602 + Field 7 (message, 6 bytes): + Field 1 (varint): 1601 + Field 2 (varint): 1602 + Field 7 (message, 6 bytes): + Field 1 (varint): 1602 + Field 2 (varint): 1602 + Field 7 (message, 6 bytes): + Field 1 (varint): 1603 + Field 2 (varint): 1604 + Field 7 (message, 6 bytes): + Field 1 (varint): 1604 + Field 2 (varint): 1604 + Field 7 (message, 6 bytes): + Field 1 (varint): 1700 + Field 2 (varint): 1702 + Field 7 (message, 6 bytes): + Field 1 (varint): 1701 + Field 2 (varint): 1702 + Field 7 (message, 6 bytes): + Field 1 (varint): 1702 + Field 2 (varint): 1702 + Field 7 (message, 6 bytes): + Field 1 (varint): 1703 + Field 2 (varint): 1704 + Field 7 (message, 6 bytes): + Field 1 (varint): 1704 + Field 2 (varint): 1704 + Field 7 (message, 6 bytes): + Field 1 (varint): 1800 + Field 2 (varint): 1802 + Field 7 (message, 6 bytes): + Field 1 (varint): 1801 + Field 2 (varint): 1802 + Field 7 (message, 6 bytes): + Field 1 (varint): 1802 + Field 2 (varint): 1802 + Field 7 (message, 6 bytes): + Field 1 (varint): 1803 + Field 2 (varint): 1804 + Field 7 (message, 6 bytes): + Field 1 (varint): 1804 + Field 2 (varint): 1804 + Field 7 (message, 6 bytes): + Field 1 (varint): 1900 + Field 2 (varint): 1902 + Field 7 (message, 6 bytes): + Field 1 (varint): 1901 + Field 2 (varint): 1902 + Field 7 (message, 6 bytes): + Field 1 (varint): 1902 + Field 2 (varint): 1902 + Field 7 (message, 6 bytes): + Field 1 (varint): 1903 + Field 2 (varint): 1904 + Field 7 (message, 6 bytes): + Field 1 (varint): 1904 + Field 2 (varint): 1904 + Field 7 (message, 6 bytes): + Field 1 (varint): 2000 + Field 2 (varint): 2001 + Field 7 (message, 6 bytes): + Field 1 (varint): 2001 + Field 2 (varint): 2001 + Field 7 (message, 6 bytes): + Field 1 (varint): 2002 + Field 2 (varint): 2001 + Field 7 (message, 6 bytes): + Field 1 (varint): 2003 + Field 2 (varint): 2003 + Field 7 (message, 6 bytes): + Field 1 (varint): 2100 + Field 2 (varint): 2101 + Field 7 (message, 6 bytes): + Field 1 (varint): 2101 + Field 2 (varint): 2101 + Field 7 (message, 6 bytes): + Field 1 (varint): 2102 + Field 2 (varint): 2101 + Field 7 (message, 6 bytes): + Field 1 (varint): 2103 + Field 2 (varint): 2103 +Field 42 (string): "\\?\C:\__w\1\s\CoreEngine\build\Models\Package\Model_Edge\Enums\enums.edge.prototxt" diff --git a/_archive/test_compare.py b/_archive/test_compare.py new file mode 100644 index 0000000000000000000000000000000000000000..53bc732b3406745410c397bd2ef7603b16f51f30 --- /dev/null +++ b/_archive/test_compare.py @@ -0,0 +1,274 @@ +"""Compare ONNX engine vs original DLL engine on all images in working_space/input/. + +Outputs a detailed comparison report and saves results side-by-side. +""" +import sys +import time +from difflib import SequenceMatcher +from pathlib import Path + +from PIL import Image + +sys.path.insert(0, str(Path(__file__).parent.parent)) + +from ocr.engine import OcrEngine +from ocr.engine_onnx import OcrEngineOnnx +from ocr.models import OcrResult + + +def fmt_result(r: OcrResult) -> dict: + """Extract structured info from OcrResult for comparison.""" + lines_info = [] + for line in r.lines: + words_info = [] + for w in line.words: + words_info.append({ + "text": w.text, + "conf": round(w.confidence, 3), + "bbox": ( + f"({w.bounding_rect.x1:.0f},{w.bounding_rect.y1:.0f})" + f"->({w.bounding_rect.x3:.0f},{w.bounding_rect.y3:.0f})" + ) if w.bounding_rect else "none", + }) + lines_info.append({ + "text": line.text, + "words": words_info, + }) + return { + "text": r.text, + "n_lines": len(r.lines), + "n_words": sum(len(l.words) for l in r.lines), + "avg_conf": round(r.average_confidence, 3), + "angle": r.text_angle, + "lines": lines_info, + "error": r.error, + } + + +def compare_texts(dll_text: str, onnx_text: str) -> tuple[bool, str, float]: + """Compare two OCR texts, return (match, diff_description, similarity).""" + if dll_text == onnx_text: + return True, "IDENTICAL", 1.0 + + # Normalize whitespace for soft match + dll_norm = " ".join(dll_text.split()) + onnx_norm = " ".join(onnx_text.split()) + if dll_norm == onnx_norm: + return True, "MATCH (whitespace diff only)", 1.0 + + # Calculate char-level similarity + ratio = SequenceMatcher(None, dll_norm, onnx_norm).ratio() + + # Case-insensitive + if dll_norm.lower() == onnx_norm.lower(): + return False, f"CASE DIFF ONLY ({ratio:.1%})", ratio + + return False, f"MISMATCH ({ratio:.1%} similar)", ratio + + +def main(): + input_dir = Path("working_space/input") + output_dir = Path("working_space/output") + output_dir.mkdir(parents=True, exist_ok=True) + + # Collect all image files + image_files = sorted(input_dir.glob("*.png")) + if not image_files: + print("No images found in working_space/input/") + return + + print("=" * 80) + print(" ONEOCR: ONNX vs DLL ENGINE COMPARISON") + print(f" Images: {len(image_files)} from {input_dir}") + print("=" * 80) + + # Initialize engines + print("\n Initializing engines...") + dll_engine = OcrEngine() + print(" ✓ DLL engine ready") + onnx_engine = OcrEngineOnnx() + print(" ✓ ONNX engine ready") + + # Results accumulator + results = [] + match_count = 0 + total_count = 0 + + report_lines = [ + "# ONEOCR: ONNX vs DLL Comparison Report", + "", + f"**Date:** 2026-02-11", + f"**Images:** {len(image_files)}", + "", + "---", + "", + ] + + for img_path in image_files: + total_count += 1 + img = Image.open(img_path) + name = img_path.name + w_img, h_img = img.size + + print(f"\n{'─' * 70}") + print(f" [{total_count}/{len(image_files)}] {name} ({w_img}×{h_img})") + print(f"{'─' * 70}") + + # DLL + t0 = time.perf_counter() + dll_result = dll_engine.recognize_pil(img) + t_dll = (time.perf_counter() - t0) * 1000 + + # ONNX + t0 = time.perf_counter() + onnx_result = onnx_engine.recognize_pil(img) + t_onnx = (time.perf_counter() - t0) * 1000 + + dll_info = fmt_result(dll_result) + onnx_info = fmt_result(onnx_result) + + match, diff_desc, similarity = compare_texts(dll_result.text, onnx_result.text) + if match: + match_count += 1 + status = "✅ MATCH" + else: + status = f"❌ {diff_desc}" + + dll_text_short = dll_result.text.replace('\n', ' ↵ ')[:80] + onnx_text_short = onnx_result.text.replace('\n', ' ↵ ')[:80] + + print(f" DLL: \"{dll_text_short}\"") + print(f" Lines={dll_info['n_lines']}, Words={dll_info['n_words']}, " + f"Conf={dll_info['avg_conf']:.1%}, Time={t_dll:.0f}ms") + print(f" ONNX: \"{onnx_text_short}\"") + print(f" Lines={onnx_info['n_lines']}, Words={onnx_info['n_words']}, " + f"Conf={onnx_info['avg_conf']:.1%}, Time={t_onnx:.0f}ms") + print(f" Status: {status}") + + # Per-word comparison + dll_words = [w.text for l in dll_result.lines for w in l.words] + onnx_words = [w.text for l in onnx_result.lines for w in l.words] + + if not match: + print(f" DLL words: {dll_words[:15]}{'...' if len(dll_words) > 15 else ''}") + print(f" ONNX words: {onnx_words[:15]}{'...' if len(onnx_words) > 15 else ''}") + + # Report + dll_text_esc = dll_result.text.replace('|', '\\|').replace('\n', ' ↵ ') + onnx_text_esc = onnx_result.text.replace('|', '\\|').replace('\n', ' ↵ ') + + report_lines.append(f"## {total_count}. {name} ({w_img}×{h_img})") + report_lines.append(f"**Status:** {status}") + report_lines.append("") + report_lines.append("| | DLL (Original) | ONNX (Our) |") + report_lines.append("|---|---|---|") + report_lines.append(f"| Text | `{dll_text_esc}` | `{onnx_text_esc}` |") + report_lines.append(f"| Lines | {dll_info['n_lines']} | {onnx_info['n_lines']} |") + report_lines.append(f"| Words | {dll_info['n_words']} | {onnx_info['n_words']} |") + report_lines.append(f"| Avg Conf | {dll_info['avg_conf']:.1%} | {onnx_info['avg_conf']:.1%} |") + report_lines.append(f"| Angle | {dll_info['angle']} | {onnx_info['angle']} |") + report_lines.append(f"| Time | {t_dll:.0f}ms | {t_onnx:.0f}ms |") + report_lines.append("") + + # Word diff if mismatch + if not match: + report_lines.append("**Word-level diff:**") + report_lines.append(f"- DLL: `{' | '.join(dll_words)}`") + report_lines.append(f"- ONNX: `{' | '.join(onnx_words)}`") + report_lines.append("") + + # Per-line comparison + max_lines = max(dll_info['n_lines'], onnx_info['n_lines']) + if max_lines > 0: + report_lines.append("**Per-line:**") + report_lines.append("| Line | DLL | ONNX | Match |") + report_lines.append("|---|---|---|---|") + for li in range(max_lines): + dll_lt = dll_info['lines'][li]['text'] if li < len(dll_info['lines']) else "(missing)" + onnx_lt = onnx_info['lines'][li]['text'] if li < len(onnx_info['lines']) else "(missing)" + line_match = "✅" if dll_lt == onnx_lt else "❌" + dll_lt_esc = dll_lt.replace('|', '\\|') + onnx_lt_esc = onnx_lt.replace('|', '\\|') + report_lines.append(f"| L{li} | `{dll_lt_esc}` | `{onnx_lt_esc}` | {line_match} |") + report_lines.append("") + + report_lines.append("---") + report_lines.append("") + + results.append({ + "name": name, + "match": match, + "diff": diff_desc, + "similarity": similarity, + "dll_text": dll_result.text, + "onnx_text": onnx_result.text, + "dll_words": dll_words, + "onnx_words": onnx_words, + "dll_n_lines": dll_info['n_lines'], + "onnx_n_lines": onnx_info['n_lines'], + }) + + # Summary + print(f"\n{'=' * 80}") + print(f" SUMMARY: {match_count}/{total_count} images match " + f"({match_count/total_count:.0%})") + print(f"{'=' * 80}") + + mismatches = [r for r in results if not r['match']] + if mismatches: + avg_sim = sum(r['similarity'] for r in mismatches) / len(mismatches) + print(f"\n MISMATCHES ({len(mismatches)}), avg similarity: {avg_sim:.1%}:") + for r in mismatches: + dll_short = r['dll_text'].replace('\n', ' ↵ ')[:50] + onnx_short = r['onnx_text'].replace('\n', ' ↵ ')[:50] + print(f" ❌ {r['name']}: {r['diff']}") + print(f" DLL: \"{dll_short}\"") + print(f" ONNX: \"{onnx_short}\"") + + # Append summary to report + report_lines.append(f"## Summary") + report_lines.append("") + report_lines.append(f"- **Total images:** {total_count}") + report_lines.append(f"- **Matches:** {match_count}") + report_lines.append(f"- **Mismatches:** {total_count - match_count}") + report_lines.append(f"- **Match rate:** {match_count/total_count:.0%}") + report_lines.append("") + + if mismatches: + avg_sim = sum(r['similarity'] for r in mismatches) / len(mismatches) + report_lines.append(f"### Avg mismatch similarity: {avg_sim:.1%}") + report_lines.append("") + report_lines.append("### Mismatched images") + report_lines.append("| # | Image | DLL Text | ONNX Text | Similarity |") + report_lines.append("|---|---|---|---|---|") + for i, r in enumerate(mismatches): + dll_s = r['dll_text'].replace('\n', ' ↵ ').replace('|', '\\|')[:40] + onnx_s = r['onnx_text'].replace('\n', ' ↵ ').replace('|', '\\|')[:40] + report_lines.append( + f"| {i+1} | {r['name']} | `{dll_s}` | `{onnx_s}` | {r['similarity']:.1%} |" + ) + report_lines.append("") + + # Common issues analysis + report_lines.append("### Common Issue Patterns") + report_lines.append("") + + # Categorize mismatches + extra_lines_onnx = sum(1 for r in mismatches if r['onnx_n_lines'] > r['dll_n_lines']) + fewer_lines_onnx = sum(1 for r in mismatches if r['onnx_n_lines'] < r['dll_n_lines']) + same_lines = sum(1 for r in mismatches if r['onnx_n_lines'] == r['dll_n_lines']) + + report_lines.append(f"- ONNX detects MORE lines than DLL: {extra_lines_onnx} cases") + report_lines.append(f"- ONNX detects FEWER lines than DLL: {fewer_lines_onnx} cases") + report_lines.append(f"- Same line count but different text: {same_lines} cases") + + # Insert match rate at top + report_lines.insert(4, f"**Match Rate:** {match_count}/{total_count} ({match_count/total_count:.0%})") + + report_path = output_dir / "comparison_report.md" + report_path.write_text("\n".join(report_lines), encoding="utf-8") + print(f"\n Report saved: {report_path}") + + +if __name__ == "__main__": + main() diff --git a/_archive/test_ocr.py b/_archive/test_ocr.py new file mode 100644 index 0000000000000000000000000000000000000000..05be666f8c579b51eaa38e314ea9d14c7d919eff --- /dev/null +++ b/_archive/test_ocr.py @@ -0,0 +1,272 @@ +""" +Test OneOCR Engine — standalone test bez zależności od struktury src/ +Uruchamia oneocr.dll na obrazie testowym i weryfikuje wynik OCR. +""" + +from __future__ import annotations + +import ctypes +import os +import sys +from ctypes import ( + POINTER, + Structure, + byref, + c_char_p, + c_float, + c_int32, + c_int64, + c_ubyte, +) +from pathlib import Path +from contextlib import contextmanager + +from PIL import Image + +# ── Stałe (normalnie z src.config.constants) ── +OCR_DLL_NAME = "oneocr.dll" +OCR_MODEL_NAME = "oneocr.onemodel" +OCR_MODEL_KEY = b'kj)TGtrK>f]b[Piow.gU+nC@s""""""4' +OCR_MAX_LINES = 1000 + +# ── Typy C ── +c_int64_p = POINTER(c_int64) +c_float_p = POINTER(c_float) +c_ubyte_p = POINTER(c_ubyte) + + +class _ImageStructure(Structure): + _fields_ = [ + ("type", c_int32), + ("width", c_int32), + ("height", c_int32), + ("_reserved", c_int32), + ("step_size", c_int64), + ("data_ptr", c_ubyte_p), + ] + + +class _BoundingBox(Structure): + _fields_ = [ + ("x1", c_float), ("y1", c_float), + ("x2", c_float), ("y2", c_float), + ("x3", c_float), ("y3", c_float), + ("x4", c_float), ("y4", c_float), + ] + + +_BoundingBox_p = POINTER(_BoundingBox) + +_DLL_FUNCTIONS = [ + ("CreateOcrInitOptions", [c_int64_p], c_int64), + ("OcrInitOptionsSetUseModelDelayLoad", [c_int64, ctypes.c_char], c_int64), + ("CreateOcrPipeline", [c_char_p, c_char_p, c_int64, c_int64_p], c_int64), + ("CreateOcrProcessOptions", [c_int64_p], c_int64), + ("OcrProcessOptionsSetMaxRecognitionLineCount", [c_int64, c_int64], c_int64), + ("RunOcrPipeline", [c_int64, POINTER(_ImageStructure), c_int64, c_int64_p], c_int64), + ("GetImageAngle", [c_int64, c_float_p], c_int64), + ("GetOcrLineCount", [c_int64, c_int64_p], c_int64), + ("GetOcrLine", [c_int64, c_int64, c_int64_p], c_int64), + ("GetOcrLineContent", [c_int64, POINTER(c_char_p)], c_int64), + ("GetOcrLineBoundingBox", [c_int64, POINTER(_BoundingBox_p)], c_int64), + ("GetOcrLineWordCount", [c_int64, c_int64_p], c_int64), + ("GetOcrWord", [c_int64, c_int64, c_int64_p], c_int64), + ("GetOcrWordContent", [c_int64, POINTER(c_char_p)], c_int64), + ("GetOcrWordBoundingBox", [c_int64, POINTER(_BoundingBox_p)], c_int64), + ("GetOcrWordConfidence", [c_int64, c_float_p], c_int64), + ("ReleaseOcrResult", [c_int64], None), + ("ReleaseOcrInitOptions", [c_int64], None), + ("ReleaseOcrPipeline", [c_int64], None), + ("ReleaseOcrProcessOptions", [c_int64], None), +] + + +@contextmanager +def _suppress_output(): + """Suppress stdout/stderr during DLL initialization.""" + devnull = os.open(os.devnull, os.O_WRONLY) + original_stdout = os.dup(1) + original_stderr = os.dup(2) + os.dup2(devnull, 1) + os.dup2(devnull, 2) + try: + yield + finally: + os.dup2(original_stdout, 1) + os.dup2(original_stderr, 2) + os.close(original_stdout) + os.close(original_stderr) + os.close(devnull) + + +def run_ocr_test(image_path: str, ocr_data_dir: str) -> str: + """Run OCR on image and return recognized text.""" + + # 1. Load DLL + kernel32 = ctypes.WinDLL("kernel32", use_last_error=True) + if hasattr(kernel32, "SetDllDirectoryW"): + kernel32.SetDllDirectoryW(ocr_data_dir) + + dll_path = os.path.join(ocr_data_dir, OCR_DLL_NAME) + if not os.path.exists(dll_path): + raise FileNotFoundError(f"DLL not found: {dll_path}") + + dll = ctypes.WinDLL(dll_path) + + for name, argtypes, restype in _DLL_FUNCTIONS: + func = getattr(dll, name) + func.argtypes = argtypes + func.restype = restype + + # 2. Initialize pipeline + init_options = c_int64() + pipeline = c_int64() + process_options = c_int64() + + result = dll.CreateOcrInitOptions(byref(init_options)) + assert result == 0, f"CreateOcrInitOptions failed: {result}" + + result = dll.OcrInitOptionsSetUseModelDelayLoad(init_options, 0) + assert result == 0, f"OcrInitOptionsSetUseModelDelayLoad failed: {result}" + + model_path = os.path.join(ocr_data_dir, OCR_MODEL_NAME) + model_buf = ctypes.create_string_buffer(model_path.encode()) + key_buf = ctypes.create_string_buffer(OCR_MODEL_KEY) + + print(f"Loading model from: {model_path}") + with _suppress_output(): + result = dll.CreateOcrPipeline(model_buf, key_buf, init_options, byref(pipeline)) + assert result == 0, f"CreateOcrPipeline failed: {result} (wrong key or corrupted model?)" + print("Model loaded successfully!") + + result = dll.CreateOcrProcessOptions(byref(process_options)) + assert result == 0, f"CreateOcrProcessOptions failed: {result}" + + result = dll.OcrProcessOptionsSetMaxRecognitionLineCount(process_options, OCR_MAX_LINES) + assert result == 0, f"OcrProcessOptionsSetMaxRecognitionLineCount failed: {result}" + + # 3. Load and convert image + image = Image.open(image_path) + if image.mode != "RGBA": + image = image.convert("RGBA") + + # RGB(A) → BGRA + r, g, b, a = image.split() + bgra_image = Image.merge("RGBA", (b, g, r, a)) + + width = bgra_image.width + height = bgra_image.height + step = width * 4 + data = bgra_image.tobytes() + + data_ptr = (c_ubyte * len(data)).from_buffer_copy(data) + + img_struct = _ImageStructure( + type=3, + width=width, + height=height, + _reserved=0, + step_size=step, + data_ptr=data_ptr, + ) + + # 4. Run OCR + ocr_result = c_int64() + result = dll.RunOcrPipeline(pipeline, byref(img_struct), process_options, byref(ocr_result)) + assert result == 0, f"RunOcrPipeline failed: {result}" + + # 5. Parse results + line_count = c_int64() + result = dll.GetOcrLineCount(ocr_result, byref(line_count)) + assert result == 0, f"GetOcrLineCount failed: {result}" + + lines = [] + for i in range(line_count.value): + line_handle = c_int64() + if dll.GetOcrLine(ocr_result, i, byref(line_handle)) != 0: + continue + if not line_handle.value: + continue + + content = c_char_p() + if dll.GetOcrLineContent(line_handle, byref(content)) == 0 and content.value: + line_text = content.value.decode("utf-8", errors="ignore") + lines.append(line_text) + + # Get word details + word_count = c_int64() + if dll.GetOcrLineWordCount(line_handle, byref(word_count)) == 0: + for wi in range(word_count.value): + word_handle = c_int64() + if dll.GetOcrWord(line_handle, wi, byref(word_handle)) != 0: + continue + word_content = c_char_p() + if dll.GetOcrWordContent(word_handle, byref(word_content)) == 0 and word_content.value: + word_text = word_content.value.decode("utf-8", errors="ignore") + conf_val = c_float() + confidence = 0.0 + if dll.GetOcrWordConfidence(word_handle, byref(conf_val)) == 0: + confidence = conf_val.value + print(f" Word: '{word_text}' (confidence: {confidence:.2f})") + + # 6. Cleanup + dll.ReleaseOcrResult(ocr_result) + dll.ReleaseOcrProcessOptions(process_options) + dll.ReleaseOcrPipeline(pipeline) + dll.ReleaseOcrInitOptions(init_options) + + full_text = "\n".join(lines) + return full_text + + +def main(): + project_root = Path(__file__).resolve().parent + ocr_data_dir = str(project_root / "ocr_data") + image_path = str(project_root / "image.png") + + if not os.path.exists(image_path): + print(f"ERROR: Image not found: {image_path}") + print("Creating test image...") + # Create a simple test image + img = Image.new("RGB", (600, 150), color="white") + from PIL import ImageDraw, ImageFont + draw = ImageDraw.Draw(img) + try: + font = ImageFont.truetype("C:/Windows/Fonts/arial.ttf", 48) + except OSError: + font = ImageFont.load_default() + draw.text((30, 40), "ONE OCR DZIALA!", fill="black", font=font) + img.save(image_path) + print(f"Created: {image_path}") + + print("=" * 50) + print(" OneOCR Test — Standalone Engine Test") + print("=" * 50) + print(f"OCR Data: {ocr_data_dir}") + print(f"Image: {image_path}") + print() + + try: + text = run_ocr_test(image_path, ocr_data_dir) + print() + print("=" * 50) + print(f" OCR Result: {text}") + print("=" * 50) + + if "ONE" in text.upper() and "OCR" in text.upper() and "DZIALA" in text.upper(): + print() + print("✅ ONE OCR DZIAŁA!") + else: + print() + print(f"⚠️ Rozpoznany tekst: '{text}'") + print(" (może wymagać lepszego obrazu testowego)") + + except Exception as e: + print(f"❌ ERROR: {e}") + import traceback + traceback.print_exc() + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/_archive/test_onnx_inference.py b/_archive/test_onnx_inference.py new file mode 100644 index 0000000000000000000000000000000000000000..9e03a382dfeea3e809700e8433c5c88466c74df4 --- /dev/null +++ b/_archive/test_onnx_inference.py @@ -0,0 +1,212 @@ +""" +Test extracted ONNX models on image.png — pure onnxruntime inference. +No Windows DLL needed — runs on any platform with onnxruntime + Pillow. + +Pipeline: + 1. model_00 (detector) — finds text regions via PixelLink FPN + 2. model_01 (script ID) — identifies writing script (Latin, CJK, etc.) + 3. model_02..10 (recognizers) — CTC character recognition per script + 4. char2ind.txt → decode character indices to text + +Preprocessing: RGB, height=60px, pixels / 255.0 (range [0, 1]) +Postprocessing: CTC greedy decode with token removal +""" +import sys +from pathlib import Path + +import numpy as np +import onnxruntime as ort +from PIL import Image + +MODELS_DIR = Path("oneocr_extracted/onnx_models") +CONFIG_DIR = Path("oneocr_extracted/config_data") + +# ─── Model registry ───────────────────────────────────────────────────────── +# model_idx -> (role, script, char2ind_file) +MODEL_REGISTRY: dict[int, tuple[str, str, str | None]] = { + 0: ("detector", "universal", None), + 1: ("script_id", "universal", None), + 2: ("recognizer", "Latin", "chunk_37_char2ind.char2ind.txt"), + 3: ("recognizer", "CJK", "chunk_40_char2ind.char2ind.txt"), + 4: ("recognizer", "Arabic", "chunk_43_char2ind.char2ind.txt"), + 5: ("recognizer", "Cyrillic", "chunk_47_char2ind.char2ind.txt"), + 6: ("recognizer", "Devanagari", "chunk_50_char2ind.char2ind.txt"), + 7: ("recognizer", "Greek", "chunk_53_char2ind.char2ind.txt"), + 8: ("recognizer", "Hebrew", "chunk_57_char2ind.char2ind.txt"), + 9: ("recognizer", "Tamil", "chunk_61_char2ind.char2ind.txt"), + 10: ("recognizer", "Thai", "chunk_64_char2ind.char2ind.txt"), +} + + +def load_char_map(path: str) -> tuple[dict[int, str], int]: + """Load char2ind.txt -> (idx->char mapping, blank_index). + Format: ' ' per line. Special: =space, =CTC blank.""" + idx2char = {} + blank_idx = 0 + with open(path, "r", encoding="utf-8") as f: + for line in f: + line = line.rstrip("\n") + if not line: + continue + sp = line.rfind(" ") + if sp <= 0: + continue + char, idx = line[:sp], int(line[sp + 1 :]) + if char == "": + blank_idx = idx + elif char == "": + idx2char[idx] = " " + else: + idx2char[idx] = char + return idx2char, blank_idx + + +def ctc_greedy_decode(logprobs: np.ndarray, idx2char: dict, blank_idx: int) -> str: + """CTC greedy decode: argmax per timestep, merge repeats, remove blanks.""" + if logprobs.ndim == 3: + logprobs = logprobs[:, 0, :] if logprobs.shape[1] == 1 else logprobs[0] + + indices = np.argmax(logprobs, axis=-1) + chars = [] + prev = -1 + for idx in indices: + if idx != prev and idx != blank_idx: + chars.append(idx2char.get(int(idx), f"[{idx}]")) + prev = idx + return "".join(chars) + + +def preprocess_for_recognizer(img: Image.Image, target_h: int = 60) -> tuple[np.ndarray, np.ndarray]: + """Preprocess image for recognizer model. + Returns (data[1,3,H,W], seq_lengths[1]).""" + w, h = img.size + scale = target_h / h + new_w = max(int(w * scale), 32) + new_w = (new_w + 3) // 4 * 4 # align to 4 + + img_r = img.resize((new_w, target_h), Image.LANCZOS) + arr = np.array(img_r, dtype=np.float32) / 255.0 # KEY: just /255, no ImageNet + data = arr.transpose(2, 0, 1)[np.newaxis] # HWC -> NCHW + seq_lengths = np.array([new_w // 4], dtype=np.int32) + return data, seq_lengths + + +def run_recognizer( + model_path: str, data: np.ndarray, seq_lengths: np.ndarray, + idx2char: dict, blank_idx: int +) -> tuple[str, float]: + """Run recognizer and decode text. Returns (text, avg_confidence).""" + sess = ort.InferenceSession(model_path, providers=["CPUExecutionProvider"]) + logprobs = sess.run(None, {"data": data, "seq_lengths": seq_lengths})[0] + text = ctc_greedy_decode(logprobs, idx2char, blank_idx) + + probs = np.exp(logprobs[:, 0, :]) + max_prob = probs.max(axis=-1) + non_blank = np.argmax(logprobs[:, 0, :], axis=-1) != blank_idx + conf = max_prob[non_blank].mean() if non_blank.any() else 0.0 + return text, float(conf) + + +def find_model_file(model_idx: int) -> str | None: + """Find ONNX model file by index.""" + matches = list(MODELS_DIR.glob(f"model_{model_idx:02d}_*")) + return str(matches[0]) if matches else None + + +def main(): + image_path = sys.argv[1] if len(sys.argv) > 1 else "image.png" + print(f"{'=' * 70}") + print(f" ONEOCR Cross-Platform ONNX Inference Test") + print(f" Image: {image_path}") + print(f"{'=' * 70}\n") + + img = Image.open(image_path).convert("RGB") + w, h = img.size + print(f" Image size: {w}x{h}\n") + + # ── Test 1: Detector ───────────────────────────────────────────────── + print("[1/3] DETECTOR (model_00)") + det_path = find_model_file(0) + if det_path: + try: + sess = ort.InferenceSession(det_path, providers=["CPUExecutionProvider"]) + scale = 800 / max(h, w) + dh = (int(h * scale) + 31) // 32 * 32 + dw = (int(w * scale) + 31) // 32 * 32 + img_d = img.resize((dw, dh), Image.LANCZOS) + arr_d = np.array(img_d, dtype=np.float32) + arr_d = arr_d[:, :, ::-1] - [102.9801, 115.9465, 122.7717] + data_d = arr_d.transpose(2, 0, 1)[np.newaxis].astype(np.float32) + im_info = np.array([[dh, dw, scale]], dtype=np.float32) + + outputs = sess.run(None, {"data": data_d, "im_info": im_info}) + scores = 1.0 / (1.0 + np.exp(-outputs[0])) + max_score = scores.max() + hot = (scores > 0.5).sum() + print(f" FPN2 scores: shape={scores.shape}, max={max_score:.3f}, hot_pixels={hot}") + print(f" OK - detector runs on onnxruntime\n") + except Exception as e: + print(f" ERROR: {e}\n") + + # ── Test 2: All Recognizers ────────────────────────────────────────── + print("[2/3] RECOGNIZERS (model_02..10) on full image") + data, seq_lengths = preprocess_for_recognizer(img) + print(f" Input: {data.shape}, seq_lengths={seq_lengths}\n") + + results = [] + for model_idx in range(2, 11): + info = MODEL_REGISTRY.get(model_idx) + if not info: + continue + _, script, char_file = info + model_path = find_model_file(model_idx) + char_path = CONFIG_DIR / char_file if char_file else None + + if not model_path or not char_path or not char_path.exists(): + print(f" model_{model_idx:02d} ({script:12s}): SKIP - files missing") + continue + + try: + idx2char, blank_idx = load_char_map(str(char_path)) + text, conf = run_recognizer(model_path, data, seq_lengths, idx2char, blank_idx) + mark = "OK" if conf > 0.8 else "LOW" if conf > 0.5 else "--" + print(f" model_{model_idx:02d} ({script:12s}): [{mark}] conf={conf:.3f} \"{text}\"") + results.append((model_idx, script, text, conf)) + except Exception as e: + print(f" model_{model_idx:02d} ({script:12s}): ERR {e}") + + # ── Best result ────────────────────────────────────────────────────── + print(f"\n[3/3] RESULT") + if results: + best = max(results, key=lambda x: x[3]) + print(f" Best: {best[1]} (model_{best[0]:02d}), conf={best[3]:.1%}") + print(f" Text: \"{best[2]}\"") + + # ── Summary ────────────────────────────────────────────────────────── + print(f""" +{'=' * 70} + ONEOCR MODEL SUMMARY +{'=' * 70} + Extracted: 34 ONNX models from oneocr.onemodel + + Cross-platform (onnxruntime): + model_00 Detector (PixelLink FPN, 11MB) + model_01 Script ID predictor (3.3MB) + model_02..10 Character recognizers (1.7-13MB each) + = 12 models, core OCR pipeline works on Linux/Mac/Windows + + Needs custom ops (com.microsoft.oneocr): + model_11..32 Language models (26-28KB each) + model_33 Line layout predictor (857KB) + = 23 models use DynamicQuantizeLSTM custom op + + Preprocessing: RGB -> resize H=60 -> /255 -> NCHW float32 + Postprocessing: CTC greedy decode with char2ind mapping + + Files: oneocr_extracted/onnx_models/ (34 .onnx) + oneocr_extracted/config_data/ (33 configs) +""") + + +if __name__ == "__main__": + main() diff --git a/_archive/test_pipeline.py b/_archive/test_pipeline.py new file mode 100644 index 0000000000000000000000000000000000000000..a14a1f564ee8c97ea6947fcfe9614ceb35777571 --- /dev/null +++ b/_archive/test_pipeline.py @@ -0,0 +1,82 @@ +"""Test the cross-platform ONNX OCR engine.""" +import sys +import time +from pathlib import Path +from PIL import Image + +# Add project root to path +sys.path.insert(0, str(Path(__file__).parent)) + +from ocr.engine_onnx import OcrEngineOnnx + + +def main(): + image_path = sys.argv[1] if len(sys.argv) > 1 else "image.png" + + print("=" * 70) + print(" ONEOCR Cross-Platform Pipeline Test") + print(f" Image: {image_path}") + print("=" * 70) + + # Load image + img = Image.open(image_path) + print(f"\n Image size: {img.size[0]}x{img.size[1]}, mode: {img.mode}") + + # Create engine + print("\n[1/2] Loading ONNX engine...") + t0 = time.perf_counter() + engine = OcrEngineOnnx() + t_load = time.perf_counter() - t0 + print(f" Engine loaded in {t_load:.2f}s") + + # Run OCR + print("\n[2/2] Running full pipeline...") + t0 = time.perf_counter() + result = engine.recognize_pil(img) + t_ocr = time.perf_counter() - t0 + print(f" Pipeline completed in {t_ocr:.2f}s") + + # Display results + print("\n" + "=" * 70) + print(" RESULTS") + print("=" * 70) + + if result.error: + print(f"\n ERROR: {result.error}") + return + + print(f"\n Text angle: {result.text_angle:.1f}°") + print(f" Lines detected: {len(result.lines)}") + print(f" Avg confidence: {result.average_confidence:.1%}") + + print(f"\n Full text:") + print(f" {'─' * 50}") + for line in result.lines: + print(f" {line.text}") + print(f" {'─' * 50}") + + # Detailed word-level output + print(f"\n Word-level details:") + for i, line in enumerate(result.lines): + print(f"\n Line {i+1}: \"{line.text}\"") + if line.bounding_rect: + b = line.bounding_rect + print(f" bbox: ({b.x1:.0f},{b.y1:.0f}) → ({b.x3:.0f},{b.y3:.0f})") + for j, word in enumerate(line.words): + conf_bar = "█" * int(word.confidence * 20) + "░" * (20 - int(word.confidence * 20)) + bbox_str = "" + if word.bounding_rect: + b = word.bounding_rect + bbox_str = f" @ ({b.x1:.0f},{b.y1:.0f})→({b.x3:.0f},{b.y3:.0f})" + print(f" [{j}] \"{word.text}\" conf={word.confidence:.3f} {conf_bar}{bbox_str}") + + print(f"\n{'=' * 70}") + print(f" Summary: {len(result.lines)} lines, " + f"{sum(len(l.words) for l in result.lines)} words, " + f"conf={result.average_confidence:.1%}, " + f"time={t_ocr:.2f}s") + print(f"{'=' * 70}") + + +if __name__ == "__main__": + main() diff --git a/_archive/unlock_model33.py b/_archive/unlock_model33.py new file mode 100644 index 0000000000000000000000000000000000000000..b8d67faacf98d463f2623c5422faf9070f46a0c9 --- /dev/null +++ b/_archive/unlock_model33.py @@ -0,0 +1,180 @@ +"""Unlock model_33 (LineLayout) — replace OneOCRFeatureExtract with Conv 1x1. + +Model 33 architecture: + data[1,3,60,W] → CNN(conv1-conv5, 256ch) → OneOCRFeatureExtract(256→16ch) + → Transpose → Reshape → MLP(64→32→2) → line_layout predictions + +The config blob (16548 bytes) structure (big-endian float32): + W[256×16] = 4096 floats (stored as [in_ch, out_ch] or [out_ch, in_ch]) + b[16] = 16 floats + metadata[25] = remaining floats +""" +import onnx +from onnx import numpy_helper, helper, TensorProto +import numpy as np +from pathlib import Path +import copy +import onnxruntime as ort + +models_dir = Path("oneocr_extracted/onnx_models") +output_dir = Path("oneocr_extracted/onnx_models_unlocked") +output_dir.mkdir(exist_ok=True) + +model_path = list(models_dir.glob("model_33_*"))[0] +model = onnx.load(str(model_path)) + +# Extract config blob +for init in model.graph.initializer: + if init.name == "feature/config": + blob = bytes(init.string_data[0] if init.string_data else init.raw_data) + break + +be_arr = np.frombuffer(blob, dtype='>f4').copy() +print(f"Config blob: {len(be_arr)} big-endian float32 values") + +# Extract W[256×16] and b[16] +# Pattern: first 4096 = W, next 16 = b, remaining = metadata +in_ch = 256 +out_ch = 16 + +W_flat = be_arr[:in_ch * out_ch] +b = be_arr[in_ch * out_ch:in_ch * out_ch + out_ch] +metadata = be_arr[in_ch * out_ch + out_ch:] + +print(f"W: {in_ch*out_ch} floats, range=[{W_flat.min():.4f}, {W_flat.max():.4f}]") +print(f"b: {out_ch} floats, range=[{b.min():.4f}, {b.max():.4f}]") +print(f"Metadata: {len(metadata)} floats") +print(f"Metadata: {metadata}") + +# Check dimension markers in metadata +for i, v in enumerate(metadata): + if v > 10 or v < -10: + print(f" metadata[{i}] = {v}") + +# Try both weight arrangements with Conv 1x1 +# Conv weight shape in ONNX: [out_ch, in_ch, kH, kW] +for arrangement_name, W_conv in [ + ("W[out,in]=[16,256]", W_flat.reshape(out_ch, in_ch, 1, 1)), + ("W[in,out]=[256,16]→T", W_flat.reshape(in_ch, out_ch).T.reshape(out_ch, in_ch, 1, 1)), +]: + print(f"\n--- Testing {arrangement_name} ---") + + new_model = copy.deepcopy(model) + + # Replace initializers + new_inits = [init for init in new_model.graph.initializer if init.name != "feature/config"] + new_inits.append(numpy_helper.from_array(W_conv.astype(np.float32), name="fe_conv_weight")) + new_inits.append(numpy_helper.from_array(b.astype(np.float32), name="fe_conv_bias")) + del new_model.graph.initializer[:] + new_model.graph.initializer.extend(new_inits) + + # Replace OneOCRFeatureExtract with Conv + fe_node = None + for node in new_model.graph.node: + if node.op_type == "OneOCRFeatureExtract": + fe_node = node + break + + fe_input = fe_node.input[0] # 'conv5_2_relu' + fe_output = fe_node.output[0] # 'oneocr_feature' + + new_nodes = [] + for node in new_model.graph.node: + if node.op_type == "OneOCRFeatureExtract": + conv_node = helper.make_node( + "Conv", + inputs=[fe_input, "fe_conv_weight", "fe_conv_bias"], + outputs=[fe_output], + kernel_shape=[1, 1], + strides=[1, 1], + pads=[0, 0, 0, 0], + ) + new_nodes.append(conv_node) + else: + new_nodes.append(node) + del new_model.graph.node[:] + new_model.graph.node.extend(new_nodes) + + # Clean up + new_inputs = [inp for inp in new_model.graph.input if inp.name != "feature/config"] + del new_model.graph.input[:] + new_model.graph.input.extend(new_inputs) + + new_opsets = [op for op in new_model.opset_import if op.domain != "com.microsoft.oneocr"] + del new_model.opset_import[:] + new_model.opset_import.extend(new_opsets) + + # Save and test + out_name = f"model_33_{arrangement_name.split('[')[0].strip()}.onnx" + out_path = output_dir / out_name + onnx.save(new_model, str(out_path)) + + try: + sess = ort.InferenceSession(str(out_path)) + # Test with 60×100 image (width=100) + test_data = np.random.randn(1, 3, 60, 100).astype(np.float32) * 0.1 + + outputs = sess.run(None, {"data": test_data}) + output_names = [o.name for o in sess.get_outputs()] + + for name, out in zip(output_names, outputs): + print(f" {name}: shape={out.shape}, range=[{out.min():.4f}, {out.max():.4f}]") + + # Also test with width=200 + test_data2 = np.random.randn(1, 3, 60, 200).astype(np.float32) * 0.1 + outputs2 = sess.run(None, {"data": test_data2}) + for name, out in zip(output_names, outputs2): + print(f" (w=200) {name}: shape={out.shape}") + + except Exception as e: + print(f" FAILED: {e}") + import traceback + traceback.print_exc() + +# Save the best working version as the official unlocked model +print(f"\n--- Saving official unlocked model ---") +# Use W[in,out]=[256,16]→T arrangement (gives reasonable output ranges) +W_conv = W_flat.reshape(in_ch, out_ch).T.reshape(out_ch, in_ch, 1, 1) +new_model = copy.deepcopy(model) + +new_inits = [init for init in new_model.graph.initializer if init.name != "feature/config"] +new_inits.append(numpy_helper.from_array(W_conv.astype(np.float32), name="fe_conv_weight")) +new_inits.append(numpy_helper.from_array(b.astype(np.float32), name="fe_conv_bias")) +del new_model.graph.initializer[:] +new_model.graph.initializer.extend(new_inits) + +new_nodes = [] +for node in new_model.graph.node: + if node.op_type == "OneOCRFeatureExtract": + conv_node = helper.make_node( + "Conv", + inputs=["conv5_2_relu", "fe_conv_weight", "fe_conv_bias"], + outputs=["oneocr_feature"], + kernel_shape=[1, 1], + ) + new_nodes.append(conv_node) + else: + new_nodes.append(node) +del new_model.graph.node[:] +new_model.graph.node.extend(new_nodes) + +new_inputs = [inp for inp in new_model.graph.input if inp.name != "feature/config"] +del new_model.graph.input[:] +new_model.graph.input.extend(new_inputs) + +new_opsets = [op for op in new_model.opset_import if op.domain != "com.microsoft.oneocr"] +del new_model.opset_import[:] +new_model.opset_import.extend(new_opsets) + +final_path = output_dir / "model_33_ir7_unknown_857KB_unlocked.onnx" +onnx.save(new_model, str(final_path)) +print(f"Saved: {final_path}") + +try: + sess = ort.InferenceSession(str(final_path)) + test = np.random.randn(1, 3, 60, 100).astype(np.float32) * 0.1 + outs = sess.run(None, {"data": test}) + for name, out in zip([o.name for o in sess.get_outputs()], outs): + print(f" ✓ {name}: {out.shape}") +except Exception as e: + print(f" ✗ {e}") diff --git a/_archive/unlock_models.py b/_archive/unlock_models.py new file mode 100644 index 0000000000000000000000000000000000000000..e3f6827bf41e7e397ac3f4a20a93f611a43b7f5c --- /dev/null +++ b/_archive/unlock_models.py @@ -0,0 +1,272 @@ +""" +Unlock ALL OneOCRFeatureExtract models (11-33). + +Replaces the custom `OneOCRFeatureExtract` op (domain: com.microsoft.oneocr) +with a standard ONNX `Gemm` node. The weights are extracted from the +big-endian float32 config blob stored as a STRING tensor. + +Config blob structure (for small/medium LM models 11-32): + - W[input_dim × output_dim] as big-endian float32 + - b[output_dim] as big-endian float32 + - metadata[remaining] containing dimensions, flags, etc. + +Usage: + python unlock_models.py # unlock all 11-33 + python unlock_models.py 11 22 33 # unlock specific models +""" + +import onnx +from onnx import numpy_helper, helper +import numpy as np +from pathlib import Path +import copy +import sys + + +def extract_fe_weights(model: onnx.ModelProto) -> tuple[np.ndarray, np.ndarray, dict]: + """Extract weights from OneOCRFeatureExtract config blob. + + The config blob is stored as big-endian float32: + W[in_dim × out_dim] + b[out_dim] + metadata + + The metadata tail contains the dimensions as float values. + + Returns: + (weight_matrix, bias, metadata_dict) + """ + # Find the feature/config initializer + config_blob = None + for init in model.graph.initializer: + if init.name == "feature/config": + config_blob = bytes(init.string_data[0]) if init.string_data else bytes(init.raw_data) + break + + if config_blob is None: + raise ValueError("No feature/config initializer found") + + # Parse as big-endian float32 + be_arr = np.frombuffer(config_blob, dtype='>f4').copy() + + # Find the OneOCRFeatureExtract node to determine input/output dimensions + fe_node = None + for node in model.graph.node: + if node.op_type == "OneOCRFeatureExtract": + fe_node = node + break + + if fe_node is None: + raise ValueError("No OneOCRFeatureExtract node found") + + # Get input/output dimensions from the graph + # Input comes from a normalization pipeline, output goes to Gemm + in_dim = None + out_dim = None + + # Try to get dims from metadata at the end of blob + # Pattern: [..., in_dim, out_dim, num_classes, ...] near the end + for i in range(len(be_arr) - 10, len(be_arr)): + val = be_arr[i] + if val == 21.0 and i + 1 < len(be_arr) and be_arr[i + 1] in [50.0, 51.0]: + in_dim = int(val) + out_dim = int(be_arr[i + 1]) + break + + # Fallback: infer from graph inputs + if in_dim is None: + for graph_input in model.graph.input: + if graph_input.name == "data": + shape = [d.dim_value for d in graph_input.type.tensor_type.shape.dim] + if len(shape) >= 2: + in_dim = shape[1] if shape[1] > 0 else 21 + break + + if out_dim is None: + # Find the Gemm after OneOCRFeatureExtract output + fe_output = fe_node.output[0] + for node in model.graph.node: + if node.op_type == "Gemm" and fe_output in node.input: + # The Gemm's weight tells us the output dim + weight_name = node.input[1] + for init in model.graph.initializer: + if init.name == weight_name: + W = numpy_helper.to_array(init) + out_dim = W.shape[0] if len(W.shape) == 2 else W.shape[1] + break + break + + if in_dim is None or out_dim is None: + raise ValueError(f"Could not determine dimensions: in={in_dim}, out={out_dim}") + + # Extract weights: first in_dim*out_dim floats = W, next out_dim = b + n_weights = in_dim * out_dim + n_bias = out_dim + + if len(be_arr) < n_weights + n_bias: + raise ValueError(f"Config blob too small: {len(be_arr)} < {n_weights + n_bias}") + + W = be_arr[:n_weights].reshape(in_dim, out_dim).astype(np.float32) + b = be_arr[n_weights:n_weights + n_bias].astype(np.float32) + metadata = be_arr[n_weights + n_bias:] + + meta_dict = { + "in_dim": in_dim, + "out_dim": out_dim, + "total_floats": len(be_arr), + "metadata_floats": len(metadata), + "metadata_values": metadata.tolist(), + } + + return W, b, meta_dict + + +def unlock_model(model_path: Path, output_dir: Path) -> Path: + """Replace OneOCRFeatureExtract with standard Gemm in an ONNX model. + + Args: + model_path: Path to the original ONNX model. + output_dir: Directory to save the modified model. + + Returns: + Path to the modified model. + """ + model = onnx.load(str(model_path)) + + # Check if model uses OneOCRFeatureExtract + has_custom_op = any( + node.op_type == "OneOCRFeatureExtract" + for node in model.graph.node + ) + if not has_custom_op: + print(f" {model_path.name}: No OneOCRFeatureExtract — skipping") + return model_path + + # Extract weights + try: + W, b, meta = extract_fe_weights(model) + except Exception as e: + print(f" {model_path.name}: Failed to extract weights: {e}") + return model_path + + print(f" {model_path.name}: W[{meta['in_dim']}×{meta['out_dim']}] + b[{meta['out_dim']}] " + f"(metadata: {meta['metadata_floats']} floats)") + + # Modify the model + new_model = copy.deepcopy(model) + + # Find the OneOCRFeatureExtract node + fe_node = None + for node in new_model.graph.node: + if node.op_type == "OneOCRFeatureExtract": + fe_node = node + break + + fe_input = fe_node.input[0] + fe_output = fe_node.output[0] + + # Replace initializers: remove feature/config, add W and b + new_inits = [init for init in new_model.graph.initializer if init.name != "feature/config"] + new_inits.append(numpy_helper.from_array(W.T, name="fe_weight")) # [out, in] for transB=1 + new_inits.append(numpy_helper.from_array(b, name="fe_bias")) + del new_model.graph.initializer[:] + new_model.graph.initializer.extend(new_inits) + + # Replace the custom op node with Gemm + new_nodes = [] + for node in new_model.graph.node: + if node.op_type == "OneOCRFeatureExtract": + gemm_node = helper.make_node( + "Gemm", + inputs=[fe_input, "fe_weight", "fe_bias"], + outputs=[fe_output], + alpha=1.0, + beta=1.0, + transB=1, + ) + new_nodes.append(gemm_node) + else: + new_nodes.append(node) + del new_model.graph.node[:] + new_model.graph.node.extend(new_nodes) + + # Clean up inputs (remove feature/config) + new_inputs = [inp for inp in new_model.graph.input if inp.name != "feature/config"] + del new_model.graph.input[:] + new_model.graph.input.extend(new_inputs) + + # Remove custom opset domain + new_opsets = [op for op in new_model.opset_import if op.domain != "com.microsoft.oneocr"] + del new_model.opset_import[:] + new_model.opset_import.extend(new_opsets) + + # Save + output_dir.mkdir(parents=True, exist_ok=True) + out_name = model_path.stem + "_unlocked.onnx" + out_path = output_dir / out_name + onnx.save(new_model, str(out_path)) + + # Verify it loads in onnxruntime + try: + import onnxruntime as ort + sess = ort.InferenceSession(str(out_path)) + + # Quick test with zero input + input_info = sess.get_inputs() + feeds = {} + for inp in input_info: + shape = [d if isinstance(d, int) and d > 0 else 1 for d in inp.shape] + feeds[inp.name] = np.zeros(shape, dtype=np.float32) + + result = sess.run(None, feeds) + print(f" ✓ Inference OK — output shapes: {[r.shape for r in result]}") + + except Exception as e: + print(f" ✗ Inference failed: {e}") + + return out_path + + +def main(): + models_dir = Path("oneocr_extracted/onnx_models") + output_dir = Path("oneocr_extracted/onnx_models_unlocked") + + # Determine which models to process + if len(sys.argv) > 1: + indices = [int(x) for x in sys.argv[1:]] + else: + indices = list(range(11, 34)) # models 11-33 + + print(f"Unlocking {len(indices)} models...") + print(f"Source: {models_dir}") + print(f"Output: {output_dir}") + print() + + results = {"success": [], "skip": [], "fail": []} + + for idx in indices: + matches = list(models_dir.glob(f"model_{idx:02d}_*")) + if not matches: + print(f" model_{idx:02d}: NOT FOUND") + results["fail"].append(idx) + continue + + model_path = matches[0] + try: + out = unlock_model(model_path, output_dir) + if out == model_path: + results["skip"].append(idx) + else: + results["success"].append(idx) + except Exception as e: + print(f" model_{idx:02d}: ERROR — {e}") + results["fail"].append(idx) + + # Summary + print(f"\n{'='*60}") + print(f"Results:") + print(f" Unlocked: {len(results['success'])} — {results['success']}") + print(f" Skipped: {len(results['skip'])} — {results['skip']}") + print(f" Failed: {len(results['fail'])} — {results['fail']}") + + +if __name__ == "__main__": + main() diff --git a/_archive/validate_config.py b/_archive/validate_config.py new file mode 100644 index 0000000000000000000000000000000000000000..f5c194bf9080ba24f900b34c5f3770428d9b2b0d --- /dev/null +++ b/_archive/validate_config.py @@ -0,0 +1,123 @@ +"""Validate the cracked OneOCRFeatureExtract structure by replacing the op with standard Gemm.""" +import onnx +from onnx import numpy_helper, TensorProto +import numpy as np +from pathlib import Path +import onnxruntime as ort + +models_dir = Path("oneocr_extracted/onnx_models") + +# Load model_11 +model_path = list(models_dir.glob("model_11_*"))[0] +model = onnx.load(str(model_path)) + +# Get config blob (big-endian float32) +for init in model.graph.initializer: + if init.name == "feature/config": + blob = bytes(init.string_data[0]) + break + +be_arr = np.frombuffer(blob, dtype='>f4').copy() # big-endian → native +print(f"Config blob: {len(be_arr)} floats total") +print(f"First 30 values: {be_arr[:30]}") + +# Let's analyze the structure systematically +# The OneOCRFeatureExtract takes 21-dim input and produces 50-dim output +# So we expect a 21→50 transformation + +# Method 1: Try W[21×50] + b[50] starting from the beginning (no header) +# 21*50 = 1050, 1050+50 = 1100, remaining = 23 +W_0 = be_arr[:1050].reshape(21, 50) +b_0 = be_arr[1050:1100] +tail = be_arr[1100:] +print(f"\n--- No header: W[21×50] + b[50] + tail[{len(tail)}] ---") +print(f" W: range=[{W_0.min():.4f}, {W_0.max():.4f}], mean={W_0.mean():.4f}, std={W_0.std():.4f}") +print(f" b: range=[{b_0.min():.4f}, {b_0.max():.4f}], mean={b_0.mean():.4f}") +print(f" tail: {tail}") + +# Method 2: Try W[50×21] (transposed) + b[50] +W_t = be_arr[:1050].reshape(50, 21) +b_t = be_arr[1050:1100] +print(f"\n--- No header: W[50×21] + b[50] + tail[{len(tail)}] ---") +print(f" W: range=[{W_t.min():.4f}, {W_t.max():.4f}], mean={W_t.mean():.4f}, std={W_t.std():.4f}") +print(f" b: range=[{b_t.min():.4f}, {b_t.max():.4f}], mean={b_t.mean():.4f}") + +# Method 3: header=23 + W[21×50] + b[50] +header = be_arr[:23] +W_h = be_arr[23:23+1050].reshape(21, 50) +b_h = be_arr[23+1050:] +print(f"\n--- Header=23: W[21×50] + b[50] ---") +print(f" Header: {header}") +print(f" W: range=[{W_h.min():.4f}, {W_h.max():.4f}], mean={W_h.mean():.4f}, std={W_h.std():.4f}") +print(f" b: range=[{b_h.min():.4f}, {b_h.max():.4f}], mean={b_h.mean():.4f}") + +# Check where the large values are +print(f"\n--- Values > 10 ---") +for i, v in enumerate(be_arr): + if abs(v) > 10: + print(f" [{i}] = {v}") + +# Check if tail/header might be something meaningful +# 23 values: could be normalization params (21 dim + 2 extras?) +# Or dimensions metadata + +# Now try to build a replacement model +# The original graph: +# data[1,21,1,1] → Reshape → Slice[0:21] → Add(offset) → Div(scale) → OneOCRFeatureExtract → [50] +# → Gemm(50,50) → Relu → Gemm(50,50) → Relu → Gemm(50,2) → Softmax + +# We'll replace OneOCRFeatureExtract with a standard Gemm +# Let's try all 3 weight interpretations + +# Get normalization constants +add_const = None +div_const = None +for node in model.graph.node: + if node.op_type == "Constant": + name = node.output[0] + for attr in node.attribute: + if attr.type == 4: + t = attr.t + data = numpy_helper.to_array(t) + if name == '26': # Add constant + add_const = data + elif name == '28': # Div constant + div_const = data + +print(f"\nNormalization: add={add_const.shape}, div={div_const.shape}") + +# Test with sample input +test_input = np.random.randn(1, 21, 1, 1).astype(np.float32) + +# Simulate the preprocessing +x = test_input.reshape(1, 21)[:, :21] # Slice +x = (x + add_const) / div_const # Normalize + +# Apply feature extraction for each method +for name, W, b in [("no_header_21x50", W_0, b_0), + ("no_header_50x21_T", W_t.T, b_t), + ("header23_21x50", W_h, b_h)]: + feat = x @ W + b # [1, 50] + print(f"\n{name}:") + print(f" Feature output: range=[{feat.min():.4f}, {feat.max():.4f}], mean={feat.mean():.4f}") + + # Continue through the MLP + for init in model.graph.initializer: + if init.name == "learned_2": + W2 = numpy_helper.to_array(init) + elif init.name == "learned_3": + b2 = numpy_helper.to_array(init) + elif init.name == "1.layers.5.weight": + W5 = numpy_helper.to_array(init) + elif init.name == "1.layers.5.bias": + b5 = numpy_helper.to_array(init) + elif init.name == "1.layers.7.weight": + W7 = numpy_helper.to_array(init) + elif init.name == "1.layers.7.bias": + b7 = numpy_helper.to_array(init) + + h1 = np.maximum(0, feat @ W2.T + b2) # Gemm + Relu + h2 = np.maximum(0, h1 @ W5.T + b5) # Gemm + Relu + logits = h2 @ W7.T + b7 # Gemm + probs = np.exp(logits) / np.exp(logits).sum(axis=1, keepdims=True) # Softmax + print(f" Final softmax: {probs}") diff --git a/main.py b/main.py new file mode 100644 index 0000000000000000000000000000000000000000..f968cb55c5a0443f9b396d6cbf2b4fe4aef2f58e --- /dev/null +++ b/main.py @@ -0,0 +1,66 @@ +""" +OneOCR — Cross-platform OCR using extracted Microsoft OneOCR models. + +Quick example showing both available engines: + - OcrEngine: Windows-only DLL wrapper (100% accuracy, fastest) + - OcrEngineOnnx: Cross-platform ONNX reimplementation (~53% match rate) + +Usage: + python main.py + python main.py # uses test.png +""" + +import sys +from pathlib import Path +from PIL import Image + + +def main(): + image_path = sys.argv[1] if len(sys.argv) > 1 else "test.png" + + if not Path(image_path).exists(): + print(f"Image not found: {image_path}") + print(f"Usage: python main.py ") + sys.exit(1) + + img = Image.open(image_path) + print(f"Image: {image_path} ({img.size[0]}x{img.size[1]})") + print() + + # Try ONNX engine first (cross-platform) + try: + from ocr.engine_onnx import OcrEngineOnnx + engine = OcrEngineOnnx() + result = engine.recognize_pil(img) + + print("=== ONNX Engine (cross-platform) ===") + print(f"Text: {result.text}") + print(f"Lines: {len(result.lines)}, Confidence: {result.average_confidence:.1%}") + print(f"Angle: {result.text_angle:.1f}") + print() + + for i, line in enumerate(result.lines): + words = " | ".join( + f"{w.text} ({w.confidence:.0%})" for w in line.words + ) + print(f" L{i}: {words}") + except Exception as e: + print(f"ONNX engine error: {e}") + + # Try DLL engine if on Windows + try: + from ocr.engine import OcrEngine + engine = OcrEngine() + result = engine.recognize_pil(img) + + print() + print("=== DLL Engine (Windows only) ===") + print(f"Text: {result.text}") + print(f"Lines: {len(result.lines)}, Confidence: {result.average_confidence:.1%}") + print() + except (ImportError, OSError) as e: + print(f"\nDLL engine not available: {e}") + + +if __name__ == "__main__": + main() diff --git a/ocr/__init__.py b/ocr/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..edf5b97d537f7512142231f9a8a2e12cd11410fa --- /dev/null +++ b/ocr/__init__.py @@ -0,0 +1,18 @@ +"""OCR package — text detection & recognition using ONNX models.""" + +from ocr.models import BoundingRect, OcrLine, OcrResult, OcrWord + +try: + from ocr.engine import OcrEngine +except (ImportError, OSError): + OcrEngine = None # type: ignore[assignment, misc] + +try: + from ocr.engine_onnx import OcrEngineOnnx +except ImportError: + OcrEngineOnnx = None # type: ignore[assignment, misc] + +__all__ = [ + "OcrEngine", "OcrEngineOnnx", + "OcrResult", "OcrLine", "OcrWord", "BoundingRect", +] diff --git a/ocr/engine.py b/ocr/engine.py new file mode 100644 index 0000000000000000000000000000000000000000..af45c748a5fedf1836c4afbf7284ea1f7709a9a3 --- /dev/null +++ b/ocr/engine.py @@ -0,0 +1,373 @@ +"""OCR engine — ctypes wrapper for Windows 11 SnippingTool's oneocr.dll. + +Provides offline OCR capability using Microsoft's AI model from Snipping Tool. +Requires oneocr.dll, oneocr.onemodel, and onnxruntime.dll in ocr_data/ directory. + +Usage: + from src.services.ocr.engine import OcrEngine + engine = OcrEngine() + result = engine.recognize_pil(pil_image) + print(result.text) +""" + +from __future__ import annotations + +import ctypes +import os +from contextlib import contextmanager +from ctypes import ( + POINTER, + Structure, + byref, + c_char_p, + c_float, + c_int32, + c_int64, + c_ubyte, +) +from pathlib import Path +from typing import TYPE_CHECKING + +from ocr.models import BoundingRect, OcrLine, OcrResult, OcrWord + +# Constants (previously imported from src.config.constants) +OCR_DLL_NAME = "oneocr.dll" +OCR_MODEL_NAME = "oneocr.onemodel" +OCR_MODEL_KEY = b'kj)TGtrK>f]b[Piow.gU+nC@s""""""4' +OCR_MAX_LINES = 200 + +if TYPE_CHECKING: + from PIL import Image + +c_int64_p = POINTER(c_int64) +c_float_p = POINTER(c_float) +c_ubyte_p = POINTER(c_ubyte) + + +class _ImageStructure(Structure): + """Image data structure for oneocr.dll (CV_8UC4 format).""" + + _fields_ = [ + ("type", c_int32), + ("width", c_int32), + ("height", c_int32), + ("_reserved", c_int32), + ("step_size", c_int64), + ("data_ptr", c_ubyte_p), + ] + + +class _BoundingBox(Structure): + """Bounding box coordinates from DLL.""" + + _fields_ = [ + ("x1", c_float), ("y1", c_float), + ("x2", c_float), ("y2", c_float), + ("x3", c_float), ("y3", c_float), + ("x4", c_float), ("y4", c_float), + ] + + +_BoundingBox_p = POINTER(_BoundingBox) + +# DLL function signatures: (name, argtypes, restype) +_DLL_FUNCTIONS: list[tuple[str, list[type], type | None]] = [ + ("CreateOcrInitOptions", [c_int64_p], c_int64), + ("OcrInitOptionsSetUseModelDelayLoad", [c_int64, ctypes.c_char], c_int64), + ("CreateOcrPipeline", [c_char_p, c_char_p, c_int64, c_int64_p], c_int64), + ("CreateOcrProcessOptions", [c_int64_p], c_int64), + ("OcrProcessOptionsSetMaxRecognitionLineCount", [c_int64, c_int64], c_int64), + ("RunOcrPipeline", [c_int64, POINTER(_ImageStructure), c_int64, c_int64_p], c_int64), + ("GetImageAngle", [c_int64, c_float_p], c_int64), + ("GetOcrLineCount", [c_int64, c_int64_p], c_int64), + ("GetOcrLine", [c_int64, c_int64, c_int64_p], c_int64), + ("GetOcrLineContent", [c_int64, POINTER(c_char_p)], c_int64), + ("GetOcrLineBoundingBox", [c_int64, POINTER(_BoundingBox_p)], c_int64), + ("GetOcrLineWordCount", [c_int64, c_int64_p], c_int64), + ("GetOcrWord", [c_int64, c_int64, c_int64_p], c_int64), + ("GetOcrWordContent", [c_int64, POINTER(c_char_p)], c_int64), + ("GetOcrWordBoundingBox", [c_int64, POINTER(_BoundingBox_p)], c_int64), + ("GetOcrWordConfidence", [c_int64, c_float_p], c_int64), + ("ReleaseOcrResult", [c_int64], None), + ("ReleaseOcrInitOptions", [c_int64], None), + ("ReleaseOcrPipeline", [c_int64], None), + ("ReleaseOcrProcessOptions", [c_int64], None), +] + + +@contextmanager +def _suppress_output(): + """Suppress stdout/stderr during DLL initialization (it prints to console).""" + devnull = os.open(os.devnull, os.O_WRONLY) + original_stdout = os.dup(1) + original_stderr = os.dup(2) + os.dup2(devnull, 1) + os.dup2(devnull, 2) + try: + yield + finally: + os.dup2(original_stdout, 1) + os.dup2(original_stderr, 2) + os.close(original_stdout) + os.close(original_stderr) + os.close(devnull) + + +class OcrEngine: + """Offline OCR engine using Windows 11 SnippingTool's oneocr.dll. + + Args: + ocr_data_dir: Path to directory containing oneocr.dll, oneocr.onemodel, onnxruntime.dll. + Defaults to PROJECT_ROOT/ocr_data/. + """ + + def __init__(self, ocr_data_dir: str | Path | None = None) -> None: + if ocr_data_dir is None: + ocr_data_dir = Path(__file__).resolve().parent.parent / "ocr_data" + self._data_dir = str(Path(ocr_data_dir).resolve()) + + self._dll: ctypes.WinDLL | None = None # type: ignore[name-defined] + self._init_options = c_int64() + self._pipeline = c_int64() + self._process_options = c_int64() + + self._load_dll() + self._initialize_pipeline() + + def __del__(self) -> None: + if self._dll: + try: + self._dll.ReleaseOcrProcessOptions(self._process_options) + self._dll.ReleaseOcrPipeline(self._pipeline) + self._dll.ReleaseOcrInitOptions(self._init_options) + except Exception: + pass + + # --- Public API --- + + def recognize_pil(self, image: Image.Image) -> OcrResult: + """Run OCR on a PIL Image. + + Args: + image: PIL Image object (any mode — will be converted to RGBA/BGRA). + + Returns: + OcrResult with recognized text, lines, words, and confidence values. + """ + if any(x < 50 or x > 10000 for x in image.size): + return OcrResult(error="Unsupported image size (must be 50-10000px)") + + if image.mode != "RGBA": + image = image.convert("RGBA") + + # Convert RGB(A) → BGRA (DLL expects BGRA channel order) + r, g, b, a = image.split() + from PIL import Image as PILImage + bgra_image = PILImage.merge("RGBA", (b, g, r, a)) + + return self._process_image( + width=bgra_image.width, + height=bgra_image.height, + step=bgra_image.width * 4, + data=bgra_image.tobytes(), + ) + + def recognize_bytes(self, image_bytes: bytes) -> OcrResult: + """Run OCR on raw image bytes (PNG/JPEG/etc). + + Args: + image_bytes: Raw image file bytes. + + Returns: + OcrResult. + """ + from io import BytesIO + + from PIL import Image + + img = Image.open(BytesIO(image_bytes)) + return self.recognize_pil(img) + + # --- Internal --- + + def _load_dll(self) -> None: + """Load oneocr.dll and bind function signatures.""" + try: + kernel32 = ctypes.WinDLL("kernel32", use_last_error=True) # type: ignore[attr-defined] + if hasattr(kernel32, "SetDllDirectoryW"): + kernel32.SetDllDirectoryW(self._data_dir) + + dll_path = os.path.join(self._data_dir, OCR_DLL_NAME) + if not os.path.exists(dll_path): + raise FileNotFoundError(f"OCR DLL not found: {dll_path}") + + self._dll = ctypes.WinDLL(dll_path) # type: ignore[attr-defined] + + for name, argtypes, restype in _DLL_FUNCTIONS: + func = getattr(self._dll, name) + func.argtypes = argtypes + func.restype = restype + + except (OSError, RuntimeError) as e: + raise RuntimeError(f"Failed to load OCR DLL from {self._data_dir}: {e}") from e + + def _initialize_pipeline(self) -> None: + """Create OCR init options, pipeline, and process options.""" + assert self._dll is not None + + # Init options + self._check( + self._dll.CreateOcrInitOptions(byref(self._init_options)), + "CreateOcrInitOptions failed", + ) + self._check( + self._dll.OcrInitOptionsSetUseModelDelayLoad(self._init_options, 0), + "OcrInitOptionsSetUseModelDelayLoad failed", + ) + + # Pipeline (loads AI model — suppress DLL stdout noise) + model_path = os.path.join(self._data_dir, OCR_MODEL_NAME) + if not os.path.exists(model_path): + raise FileNotFoundError(f"OCR model not found: {model_path}") + + model_buf = ctypes.create_string_buffer(model_path.encode()) + key_buf = ctypes.create_string_buffer(OCR_MODEL_KEY) + + with _suppress_output(): + result = self._dll.CreateOcrPipeline( + model_buf, key_buf, self._init_options, byref(self._pipeline) + ) + self._check(result, "CreateOcrPipeline failed (wrong key or corrupted model?)") + + # Process options + self._check( + self._dll.CreateOcrProcessOptions(byref(self._process_options)), + "CreateOcrProcessOptions failed", + ) + self._check( + self._dll.OcrProcessOptionsSetMaxRecognitionLineCount( + self._process_options, OCR_MAX_LINES + ), + "OcrProcessOptionsSetMaxRecognitionLineCount failed", + ) + + def _process_image(self, width: int, height: int, step: int, data: bytes) -> OcrResult: + """Create image structure and run OCR pipeline.""" + assert self._dll is not None + + data_ptr = (c_ubyte * len(data)).from_buffer_copy(data) + + img_struct = _ImageStructure( + type=3, + width=width, + height=height, + _reserved=0, + step_size=step, + data_ptr=data_ptr, + ) + + ocr_result = c_int64() + if self._dll.RunOcrPipeline( + self._pipeline, byref(img_struct), self._process_options, byref(ocr_result) + ) != 0: + return OcrResult(error="RunOcrPipeline returned non-zero") + + parsed = self._parse_results(ocr_result) + self._dll.ReleaseOcrResult(ocr_result) + return parsed + + def _parse_results(self, ocr_result: c_int64) -> OcrResult: + """Extract text, lines, words from DLL result handle.""" + assert self._dll is not None + + line_count = c_int64() + if self._dll.GetOcrLineCount(ocr_result, byref(line_count)) != 0: + return OcrResult(error="GetOcrLineCount failed") + + lines: list[OcrLine] = [] + for idx in range(line_count.value): + line = self._parse_line(ocr_result, idx) + if line: + lines.append(line) + + # Text angle + text_angle_val = c_float() + text_angle: float | None = None + if self._dll.GetImageAngle(ocr_result, byref(text_angle_val)) == 0: + text_angle = text_angle_val.value + + full_text = "\n".join(line.text for line in lines if line.text) + + return OcrResult(text=full_text, text_angle=text_angle, lines=lines) + + def _parse_line(self, ocr_result: c_int64, line_index: int) -> OcrLine | None: + """Parse a single line from OCR result.""" + assert self._dll is not None + + line_handle = c_int64() + if self._dll.GetOcrLine(ocr_result, line_index, byref(line_handle)) != 0: + return None + if not line_handle.value: + return None + + # Line text + content = c_char_p() + line_text = "" + if self._dll.GetOcrLineContent(line_handle, byref(content)) == 0 and content.value: + line_text = content.value.decode("utf-8", errors="ignore") + + # Line bounding box + line_bbox = self._get_bbox(line_handle, self._dll.GetOcrLineBoundingBox) + + # Words + word_count = c_int64() + words: list[OcrWord] = [] + if self._dll.GetOcrLineWordCount(line_handle, byref(word_count)) == 0: + for wi in range(word_count.value): + word = self._parse_word(line_handle, wi) + if word: + words.append(word) + + return OcrLine(text=line_text, bounding_rect=line_bbox, words=words) + + def _parse_word(self, line_handle: c_int64, word_index: int) -> OcrWord | None: + """Parse a single word.""" + assert self._dll is not None + + word_handle = c_int64() + if self._dll.GetOcrWord(line_handle, word_index, byref(word_handle)) != 0: + return None + + # Word text + content = c_char_p() + word_text = "" + if self._dll.GetOcrWordContent(word_handle, byref(content)) == 0 and content.value: + word_text = content.value.decode("utf-8", errors="ignore") + + # Word bounding box + word_bbox = self._get_bbox(word_handle, self._dll.GetOcrWordBoundingBox) + + # Word confidence + confidence_val = c_float() + confidence = 0.0 + if self._dll.GetOcrWordConfidence(word_handle, byref(confidence_val)) == 0: + confidence = confidence_val.value + + return OcrWord(text=word_text, bounding_rect=word_bbox, confidence=confidence) + + @staticmethod + def _get_bbox(handle: c_int64, bbox_fn: object) -> BoundingRect | None: + """Extract bounding box from a handle.""" + bbox_ptr = _BoundingBox_p() + if bbox_fn(handle, byref(bbox_ptr)) == 0 and bbox_ptr: # type: ignore[operator] + bb = bbox_ptr.contents + return BoundingRect( + x1=bb.x1, y1=bb.y1, x2=bb.x2, y2=bb.y2, + x3=bb.x3, y3=bb.y3, x4=bb.x4, y4=bb.y4, + ) + return None + + @staticmethod + def _check(result_code: int, msg: str) -> None: + if result_code != 0: + raise RuntimeError(f"{msg} (code: {result_code})") diff --git a/ocr/engine_onnx.py b/ocr/engine_onnx.py new file mode 100644 index 0000000000000000000000000000000000000000..86c017fba94c44ad573a9fcf2b8756281da8046f --- /dev/null +++ b/ocr/engine_onnx.py @@ -0,0 +1,1101 @@ +""" +Cross-platform OneOCR engine — pure Python/ONNX implementation. + +Reimplements the full OneOCR DLL pipeline using extracted ONNX models: + 1. Detector (model_00): PixelLink FPN text detection → bounding boxes + 2. ScriptID (model_01): Script/handwriting/flip classification + 3. Recognizers (02-10): Per-script CTC character recognition + 4. Line grouping: Heuristic grouping of words into lines + +Preprocessing: + - Detector: BGR, mean-subtracted [102.98, 115.95, 122.77], NCHW + - Recognizers: RGB / 255.0, height=60px, NCHW + - ScriptID: Same as recognizers + +Output format matches the DLL: OcrResult with BoundingRect, OcrLine, OcrWord. + +Usage: + from ocr.engine_onnx import OcrEngineOnnx + engine = OcrEngineOnnx() + result = engine.recognize_pil(pil_image) + print(result.text) +""" + +from __future__ import annotations + +import math +import os +from pathlib import Path +from typing import TYPE_CHECKING + +import cv2 +import numpy as np +import onnxruntime as ort + +from ocr.models import BoundingRect, OcrLine, OcrResult, OcrWord + +if TYPE_CHECKING: + from PIL import Image + +# ─── Constants ─────────────────────────────────────────────────────────────── + +# BGR mean values for detector (ImageNet-style) +_DET_MEAN = np.array([102.9801, 115.9465, 122.7717], dtype=np.float32) + +# Detector thresholds (from DLL protobuf config — segment_conf_threshold) +_PIXEL_SCORE_THRESH = 0.7 # text/non-text pixel threshold (DLL: field 8 = 0.7) +_LINK_SCORE_THRESH = 0.5 # neighbor link threshold +_MIN_AREA = 50 # minimum text region area (pixels) +_MIN_HEIGHT = 5 # minimum text region height +_MIN_WIDTH = 4 # minimum text region width + +# Detector scaling (Faster R-CNN / FPN style — short side target, long side cap) +_DET_TARGET_SHORT = 800 # scale shortest side to this +_DET_MAX_LONG = 1333 # cap longest side (Faster R-CNN standard) + +# NMS thresholds (from DLL protobuf config) +_NMS_IOU_THRESH = 0.2 # textline_nms_threshold (DLL: field 10 = 0.2) + +# Recognizer settings +_REC_TARGET_H = 60 # target height for recognizer input +_REC_MIN_WIDTH = 32 # minimum width after resize + +# Line grouping +_LINE_IOU_Y_THRESH = 0.5 # Y-overlap threshold for same-line grouping +_LINE_MERGE_GAP = 2.0 # max gap between words on same line (as ratio of avg char height) + +# Script names for ScriptID output (10 classes) +SCRIPT_NAMES = [ + "Latin", "CJK", "Arabic", "Cyrillic", "Devanagari", + "Greek", "Hebrew", "Thai", "Tamil", "Unknown" +] + +# Model index → (role, script, char2ind_file, rnn_info_file) +MODEL_REGISTRY: dict[int, tuple[str, str, str | None]] = { + 0: ("detector", "universal", None), + 1: ("script_id", "universal", None), + 2: ("recognizer", "Latin", "chunk_37_char2ind.char2ind.txt"), + 3: ("recognizer", "CJK", "chunk_40_char2ind.char2ind.txt"), + 4: ("recognizer", "Arabic", "chunk_43_char2ind.char2ind.txt"), + 5: ("recognizer", "Cyrillic", "chunk_47_char2ind.char2ind.txt"), + 6: ("recognizer", "Devanagari", "chunk_50_char2ind.char2ind.txt"), + 7: ("recognizer", "Greek", "chunk_53_char2ind.char2ind.txt"), + 8: ("recognizer", "Hebrew", "chunk_57_char2ind.char2ind.txt"), + 9: ("recognizer", "Tamil", "chunk_61_char2ind.char2ind.txt"), + 10: ("recognizer", "Thai", "chunk_64_char2ind.char2ind.txt"), +} + +# Script name → recognizer model index +SCRIPT_TO_MODEL: dict[str, int] = { + "Latin": 2, "CJK": 3, "Arabic": 4, "Cyrillic": 5, + "Devanagari": 6, "Greek": 7, "Hebrew": 8, "Tamil": 9, "Thai": 10, +} + + +# ─── Helper: Character map ────────────────────────────────────────────────── + +def load_char_map(path: str | Path) -> tuple[dict[int, str], int]: + """Load char2ind.txt → (idx→char map, blank_index). + + Format: ' ' per line. + Special tokens: =space char, =CTC blank. + """ + idx2char: dict[int, str] = {} + blank_idx = 0 + with open(path, "r", encoding="utf-8") as f: + for raw_line in f: + line = raw_line.rstrip("\n") + if not line: + continue + sp = line.rfind(" ") + if sp <= 0: + continue + char_str, idx_str = line[:sp], line[sp + 1:] + idx = int(idx_str) + if char_str == "": + blank_idx = idx + elif char_str == "": + idx2char[idx] = " " + else: + idx2char[idx] = char_str + return idx2char, blank_idx + + +# ─── PixelLink Post-Processing ────────────────────────────────────────────── + +# 8-connected neighbors: (dy, dx) for N, NE, E, SE, S, SW, W, NW +_NEIGHBOR_OFFSETS = [(-1, 0), (-1, 1), (0, 1), (1, 1), + (1, 0), (1, -1), (0, -1), (-1, -1)] + + +class _UnionFind: + """Union-Find (Disjoint Set) for connected component labeling.""" + + __slots__ = ("parent", "rank") + + def __init__(self, n: int): + self.parent = list(range(n)) + self.rank = [0] * n + + def find(self, x: int) -> int: + while self.parent[x] != x: + self.parent[x] = self.parent[self.parent[x]] + x = self.parent[x] + return x + + def union(self, a: int, b: int) -> None: + ra, rb = self.find(a), self.find(b) + if ra == rb: + return + if self.rank[ra] < self.rank[rb]: + ra, rb = rb, ra + self.parent[rb] = ra + if self.rank[ra] == self.rank[rb]: + self.rank[ra] += 1 + + +def _pixellink_decode( + pixel_scores: np.ndarray, + link_scores: np.ndarray, + bbox_deltas: np.ndarray, + stride: int, + pixel_thresh: float = _PIXEL_SCORE_THRESH, + link_thresh: float = _LINK_SCORE_THRESH, + min_area: float = _MIN_AREA, + min_component_pixels: int = 3, +) -> list[np.ndarray]: + """Decode PixelLink outputs into oriented bounding boxes. + + Uses connected-component labeling with Union-Find for linked text pixels, + then refines box positions using bbox_deltas regression (matching DLL behavior). + + Each text pixel predicts 4 corner offsets (as fraction of stride) via + bbox_deltas[8, H, W] = [TL.x, TL.y, TR.x, TR.y, BR.x, BR.y, BL.x, BL.y]. + The actual corner position for pixel (r, c) is: + corner = (pixel_coord + delta) * stride + + For a connected component, the bounding box corners are computed by taking + the extremes of all per-pixel predictions (min TL, max BR). + + Args: + pixel_scores: [H, W] text/non-text scores (already sigmoid'd) + link_scores: [8, H, W] neighbor link scores (already sigmoid'd) + bbox_deltas: [8, H, W] corner offsets — 4 corners × 2 coords (x, y) + stride: FPN stride (4, 8, or 16) + min_area: minimum box area in detector-image pixels + min_component_pixels: minimum number of pixels in a connected component + + Returns: + List of (4, 2) arrays — quadrilateral corners in detector-image coordinates. + """ + h, w = pixel_scores.shape + + # Step 1: Threshold pixels + text_mask = pixel_scores > pixel_thresh + text_pixels = np.argwhere(text_mask) # (N, 2) — (row, col) pairs + + if len(text_pixels) == 0: + return [] + + # Step 2: Build pixel index map for quick lookup + pixel_map = np.full((h, w), -1, dtype=np.int32) + for i, (r, c) in enumerate(text_pixels): + pixel_map[r, c] = i + + # Step 3: Union-Find to group linked pixels + uf = _UnionFind(len(text_pixels)) + + for i, (r, c) in enumerate(text_pixels): + for ni, (dy, dx) in enumerate(_NEIGHBOR_OFFSETS): + nr, nc = r + dy, c + dx + if 0 <= nr < h and 0 <= nc < w: + j = pixel_map[nr, nc] + if j >= 0 and link_scores[ni, r, c] > link_thresh: + uf.union(i, j) + + # Step 4: Group pixels by component + components: dict[int, list[int]] = {} + for i in range(len(text_pixels)): + root = uf.find(i) + if root not in components: + components[root] = [] + components[root].append(i) + + # Step 5: For each component, compute bbox using delta regression + quads: list[np.ndarray] = [] + + for indices in components.values(): + if len(indices) < min_component_pixels: + continue + + # Compute per-pixel corner predictions using bbox_deltas + # Each pixel at (r, c) predicts 4 corners: + # TL = ((c + d0) * stride, (r + d1) * stride) + # TR = ((c + d2) * stride, (r + d3) * stride) + # BR = ((c + d4) * stride, (r + d5) * stride) + # BL = ((c + d6) * stride, (r + d7) * stride) + tl_x_min = float("inf") + tl_y_min = float("inf") + br_x_max = float("-inf") + br_y_max = float("-inf") + + for idx in indices: + r, c = int(text_pixels[idx][0]), int(text_pixels[idx][1]) + # TL corner + tl_x = (c + float(bbox_deltas[0, r, c])) * stride + tl_y = (r + float(bbox_deltas[1, r, c])) * stride + # TR corner + tr_x = (c + float(bbox_deltas[2, r, c])) * stride + # BR corner + br_x = (c + float(bbox_deltas[4, r, c])) * stride + br_y = (r + float(bbox_deltas[5, r, c])) * stride + # BL corner + bl_y = (r + float(bbox_deltas[7, r, c])) * stride + + tl_x_min = min(tl_x_min, tl_x) + tl_y_min = min(tl_y_min, tl_y, (r + float(bbox_deltas[3, r, c])) * stride) + br_x_max = max(br_x_max, br_x, tr_x) + br_y_max = max(br_y_max, br_y, bl_y) + + # Clamp to positive coordinates + x1 = max(0.0, tl_x_min) + y1 = max(0.0, tl_y_min) + x2 = br_x_max + y2 = br_y_max + + box_w = x2 - x1 + box_h = y2 - y1 + area = box_w * box_h + + if area < min_area: + continue + if box_h < _MIN_HEIGHT: + continue + if box_w < _MIN_WIDTH: + continue + + # Create axis-aligned quad (TL, TR, BR, BL) + quad = np.array([ + [x1, y1], + [x2, y1], + [x2, y2], + [x1, y2], + ], dtype=np.float32) + quads.append(quad) + + return quads + + +def _order_corners(pts: np.ndarray) -> np.ndarray: + """Order 4 corners as: top-left, top-right, bottom-right, bottom-left.""" + # Sort by y first, then by x + s = pts.sum(axis=1) + d = np.diff(pts, axis=1).ravel() + + ordered = np.zeros((4, 2), dtype=np.float32) + ordered[0] = pts[np.argmin(s)] # top-left: smallest sum + ordered[2] = pts[np.argmax(s)] # bottom-right: largest sum + ordered[1] = pts[np.argmin(d)] # top-right: smallest diff + ordered[3] = pts[np.argmax(d)] # bottom-left: largest diff + return ordered + + +def _nms_quads(quads: list[np.ndarray], iou_thresh: float = 0.3) -> list[np.ndarray]: + """Non-maximum suppression on quadrilateral boxes using contour IoU.""" + if len(quads) <= 1: + return quads + + # Sort by area (largest first) + areas = [cv2.contourArea(q) for q in quads] + order = np.argsort(areas)[::-1] + + keep: list[np.ndarray] = [] + used = set() + + for i in order: + if i in used: + continue + keep.append(quads[i]) + used.add(i) + + for j in order: + if j in used: + continue + # Compute IoU between quads[i] and quads[j] + iou = _quad_iou(quads[i], quads[j]) + if iou > iou_thresh: + # Merge: keep the larger one + used.add(j) + + return keep + + +def _quad_iou(q1: np.ndarray, q2: np.ndarray) -> float: + """Compute IoU between two quadrilaterals.""" + try: + ret, region = cv2.intersectConvexConvex( + q1.astype(np.float32), q2.astype(np.float32) + ) + if ret <= 0: + return 0.0 + inter = cv2.contourArea(region) + a1 = cv2.contourArea(q1) + a2 = cv2.contourArea(q2) + union = a1 + a2 - inter + return inter / union if union > 0 else 0.0 + except Exception: + return 0.0 + + +# ─── CTC Decoding ─────────────────────────────────────────────────────────── + +def ctc_greedy_decode( + logprobs: np.ndarray, + idx2char: dict[int, str], + blank_idx: int, +) -> tuple[str, float, list[float]]: + """CTC greedy decode: argmax per timestep, merge repeats, remove blanks. + + Returns (decoded_text, average_confidence, per_char_confidences). + """ + if logprobs.ndim == 3: + logprobs = logprobs[:, 0, :] + + indices = np.argmax(logprobs, axis=-1) + probs = np.exp(logprobs) + max_probs = probs[np.arange(len(indices)), indices] + + chars: list[str] = [] + char_probs: list[float] = [] + prev = -1 + + for t, idx in enumerate(indices): + if idx != prev and idx != blank_idx: + chars.append(idx2char.get(int(idx), f"[{idx}]")) + char_probs.append(float(max_probs[t])) + prev = idx + + text = "".join(chars) + confidence = float(np.mean(char_probs)) if char_probs else 0.0 + return text, confidence, char_probs + + +# ─── Line Grouping ────────────────────────────────────────────────────────── + +def _group_words_into_lines( + words: list[tuple[str, np.ndarray, float]], +) -> list[list[tuple[str, np.ndarray, float]]]: + """Group detected words into lines based on Y-overlap. + + Args: + words: List of (text, quad[4,2], confidence). + + Returns: + List of line groups, each a list of (text, quad, conf) tuples. + """ + if not words: + return [] + + # Sort by center Y + words_with_cy = [] + for w in words: + _, quad, _ = w + cy = quad[:, 1].mean() + words_with_cy.append((cy, w)) + words_with_cy.sort(key=lambda x: x[0]) + + lines: list[list[tuple[str, np.ndarray, float]]] = [] + used = set() + + for i, (cy_i, w_i) in enumerate(words_with_cy): + if i in used: + continue + + _, qi, _ = w_i + y_min_i = qi[:, 1].min() + y_max_i = qi[:, 1].max() + h_i = y_max_i - y_min_i + + line = [w_i] + used.add(i) + + for j in range(i + 1, len(words_with_cy)): + if j in used: + continue + _, w_j = words_with_cy[j] + _, qj, _ = w_j + y_min_j = qj[:, 1].min() + y_max_j = qj[:, 1].max() + + # Check Y overlap + overlap = min(y_max_i, y_max_j) - max(y_min_i, y_min_j) + min_height = min(y_max_i - y_min_i, y_max_j - y_min_j) + if min_height > 0 and overlap / min_height > _LINE_IOU_Y_THRESH: + line.append(w_j) + used.add(j) + # Expand y range + y_min_i = min(y_min_i, y_min_j) + y_max_i = max(y_max_i, y_max_j) + + # Sort line words by X position (left to right) + line.sort(key=lambda w: w[1][:, 0].min()) + lines.append(line) + + return lines + + +# ─── Image Angle Detection ────────────────────────────────────────────────── + +def _estimate_image_angle(quads: list[np.ndarray]) -> float: + """Estimate overall text angle from detected quads. + + Uses the average angle of the top edges of all boxes. + """ + if not quads: + return 0.0 + + angles = [] + for q in quads: + # Top edge: q[0] → q[1] + dx = q[1][0] - q[0][0] + dy = q[1][1] - q[0][1] + if abs(dx) < 1: + continue + angle = math.degrees(math.atan2(dy, dx)) + angles.append(angle) + + if not angles: + return 0.0 + + return float(np.median(angles)) + + +# ═══════════════════════════════════════════════════════════════════════════ +# Main Engine +# ═══════════════════════════════════════════════════════════════════════════ + +class OcrEngineOnnx: + """Cross-platform OCR engine using extracted ONNX models. + + Provides the same API as OcrEngine (DLL version) but runs on any OS. + + Args: + models_dir: Path to extracted ONNX models directory. + config_dir: Path to extracted config data directory. + providers: ONNX Runtime providers (default: CPU only). + """ + + def __init__( + self, + models_dir: str | Path | None = None, + config_dir: str | Path | None = None, + providers: list[str] | None = None, + ) -> None: + base = Path(__file__).resolve().parent.parent + self._models_dir = Path(models_dir) if models_dir else base / "oneocr_extracted" / "onnx_models" + self._config_dir = Path(config_dir) if config_dir else base / "oneocr_extracted" / "config_data" + self._unlocked_dir = self._models_dir.parent / "onnx_models_unlocked" + self._providers = providers or ["CPUExecutionProvider"] + + # Optimized session options (matching DLL's ORT configuration) + self._sess_opts = ort.SessionOptions() + self._sess_opts.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL + self._sess_opts.intra_op_num_threads = max(1, (os.cpu_count() or 4) // 2) + self._sess_opts.inter_op_num_threads = 2 + self._sess_opts.enable_mem_pattern = True + self._sess_opts.enable_cpu_mem_arena = True + + # Lazy-loaded sessions + self._detector: ort.InferenceSession | None = None + self._script_id: ort.InferenceSession | None = None + self._recognizers: dict[int, ort.InferenceSession] = {} + self._char_maps: dict[int, tuple[dict[int, str], int]] = {} + self._line_layout: ort.InferenceSession | None = None + + # Validate paths exist + if not self._models_dir.exists(): + raise FileNotFoundError(f"Models directory not found: {self._models_dir}") + if not self._config_dir.exists(): + raise FileNotFoundError(f"Config directory not found: {self._config_dir}") + + # ─── Public API ─────────────────────────────────────────────────────── + + def recognize_pil(self, image: "Image.Image") -> OcrResult: + """Run OCR on a PIL Image. + + Args: + image: PIL Image (any mode — will be converted to RGB). + + Returns: + OcrResult with recognized text, lines, words, bounding boxes, + confidence values, and detected text angle. + """ + if any(x < 10 or x > 10000 for x in image.size): + return OcrResult(error="Unsupported image size (must be 10-10000px)") + + img_rgb = image.convert("RGB") + img_arr = np.array(img_rgb) + + try: + return self._run_pipeline(img_arr) + except Exception as e: + return OcrResult(error=f"Pipeline error: {e}") + + def recognize_bytes(self, image_bytes: bytes) -> OcrResult: + """Run OCR on raw image bytes (PNG/JPEG/etc).""" + from io import BytesIO + from PIL import Image as PILImage + img = PILImage.open(BytesIO(image_bytes)) + return self.recognize_pil(img) + + def recognize_numpy(self, img_rgb: np.ndarray) -> OcrResult: + """Run OCR on a numpy array (H, W, 3) in RGB format.""" + if img_rgb.ndim != 3 or img_rgb.shape[2] != 3: + return OcrResult(error="Expected (H, W, 3) RGB array") + try: + return self._run_pipeline(img_rgb) + except Exception as e: + return OcrResult(error=f"Pipeline error: {e}") + + # ─── Pipeline ───────────────────────────────────────────────────────── + + def _run_pipeline(self, img_rgb: np.ndarray) -> OcrResult: + """Full OCR pipeline: detect → crop → scriptID → recognize → group.""" + h, w = img_rgb.shape[:2] + + # Step 1: Detect text regions + quads, scale = self._detect(img_rgb) + + if not quads: + return OcrResult(text="", text_angle=0.0, lines=[]) + + # Step 2: Estimate image angle + text_angle = _estimate_image_angle(quads) + + # Step 3: For each detected region (line), crop and recognize + line_results: list[tuple[str, np.ndarray, float, list[float]]] = [] + + for quad in quads: + # Crop text region from original image + crop = self._crop_quad(img_rgb, quad) + if crop is None or crop.shape[0] < 5 or crop.shape[1] < 5: + continue + + # Detect vertical text: if crop is much taller than wide, rotate 90° CCW + ch, cw = crop.shape[:2] + is_vertical = ch > cw * 2 + + rec_crop = crop + if is_vertical: + rec_crop = cv2.rotate(crop, cv2.ROTATE_90_COUNTERCLOCKWISE) + + # ScriptID (on properly oriented crop) + script_idx = self._identify_script(rec_crop) + script_name = SCRIPT_NAMES[script_idx] if script_idx < len(SCRIPT_NAMES) else "Latin" + + # Map to recognizer + model_idx = SCRIPT_TO_MODEL.get(script_name, 2) # default Latin + + # Recognize full line + text, conf, char_confs = self._recognize(rec_crop, model_idx) + + # For vertical text fallback: if confidence is low, try CJK recognizer + if is_vertical and conf < 0.7 and model_idx != 3: + text_cjk, conf_cjk, char_confs_cjk = self._recognize(rec_crop, 3) + if conf_cjk > conf: + text, conf, char_confs = text_cjk, conf_cjk, char_confs_cjk + + if text.strip(): + # Graded confidence filter. + # Short noise detections from FPN2 (single chars like "1", "C") + # typically have lower confidence than genuine text like "I", "A". + text_stripped = text.strip() + n_chars = len(text_stripped) + if n_chars <= 1 and conf < 0.35: + continue # single char needs some confidence + elif conf < 0.3: + continue # very low confidence = noise + + line_results.append((text, quad, conf, char_confs)) + + if not line_results: + return OcrResult(text="", text_angle=text_angle, lines=[]) + + # Step 4: Build OcrResult — split recognized text into words + lines: list[OcrLine] = [] + for line_text, quad, conf, char_confs in line_results: + # Split text by spaces to get words + word_texts = line_text.split() + if not word_texts: + continue + + # Estimate per-word bounding boxes and confidence by distributing + # quad width and char confidences proportionally to words + words = self._split_into_words(word_texts, quad, conf, char_confs) + + line_bbox = BoundingRect( + x1=float(quad[0][0]), y1=float(quad[0][1]), + x2=float(quad[1][0]), y2=float(quad[1][1]), + x3=float(quad[2][0]), y3=float(quad[2][1]), + x4=float(quad[3][0]), y4=float(quad[3][1]), + ) + + full_line_text = " ".join(w.text for w in words) + lines.append(OcrLine(text=full_line_text, bounding_rect=line_bbox, words=words)) + + # Sort lines top-to-bottom by center Y coordinate + lines.sort(key=lambda l: ( + (l.bounding_rect.y1 + l.bounding_rect.y3) / 2 + if l.bounding_rect else 0 + )) + + full_text = "\n".join(line.text for line in lines) + + return OcrResult(text=full_text, text_angle=text_angle, lines=lines) + + # ─── Detection ──────────────────────────────────────────────────────── + + def _detect(self, img_rgb: np.ndarray) -> tuple[list[np.ndarray], float]: + """Run PixelLink detector and decode bounding boxes. + + Scaling: FPN-style — scale shortest side to 800, cap longest at 1333. + Two-phase detection: + - Phase 1: FPN3 (stride=8) + FPN4 (stride=16) — primary detections + - Phase 2: FPN2 (stride=4) — supplementary for small text ("I", "...") + Only keeps novel FPN2 detections that don't overlap with primary. + NMS: IoU threshold 0.2 (from DLL protobuf config). + + Returns (list_of_quads, scale_factor). + """ + h, w = img_rgb.shape[:2] + + # FPN-style scaling: target short side = 800, cap long side at 1333 + short_side = min(h, w) + long_side = max(h, w) + scale = _DET_TARGET_SHORT / short_side + if long_side * scale > _DET_MAX_LONG: + scale = _DET_MAX_LONG / long_side + scale = min(scale, 6.0) + + dh = (int(h * scale) + 31) // 32 * 32 + dw = (int(w * scale) + 31) // 32 * 32 + + img_resized = cv2.resize(img_rgb, (dw, dh), interpolation=cv2.INTER_LINEAR) + + # BGR + mean subtraction (ImageNet-style, matching DLL) + img_bgr = img_resized[:, :, ::-1].astype(np.float32) - _DET_MEAN + data = img_bgr.transpose(2, 0, 1)[np.newaxis] + im_info = np.array([[dh, dw, scale]], dtype=np.float32) + + # Run detector + sess = self._get_detector() + outputs = sess.run(None, {"data": data, "im_info": im_info}) + output_names = [o.name for o in sess.get_outputs()] + out_dict = dict(zip(output_names, outputs)) + + # ── Phase 1: Primary detections from FPN3 + FPN4 ── + primary_quads: list[np.ndarray] = [] + + for level, stride in [("fpn3", 8), ("fpn4", 16)]: + min_area_scaled = _MIN_AREA * (scale ** 2) + + for orientation in ("hori", "vert"): + scores_key = f"scores_{orientation}_{level}" + links_key = f"link_scores_{orientation}_{level}" + deltas_key = f"bbox_deltas_{orientation}_{level}" + + if scores_key not in out_dict: + continue + + pixel_scores = out_dict[scores_key][0, 0] + if orientation == "vert" and pixel_scores.max() <= _PIXEL_SCORE_THRESH: + continue + + link_scores = out_dict[links_key][0] + bbox_deltas = out_dict[deltas_key][0] + + quads = _pixellink_decode( + pixel_scores, link_scores, bbox_deltas, stride, + pixel_thresh=_PIXEL_SCORE_THRESH, + min_area=min_area_scaled, + ) + primary_quads.extend(quads) + + primary_quads = _nms_quads(primary_quads, iou_thresh=_NMS_IOU_THRESH) + + # ── Phase 2: FPN2 supplementary detections ── + # Higher threshold (0.85) to reduce false positives from panel borders. + # Only keep novel detections that don't overlap with primary. + fpn2_quads: list[np.ndarray] = [] + min_area_scaled = _MIN_AREA * (scale ** 2) + + for orientation in ("hori", "vert"): + scores_key = f"scores_{orientation}_fpn2" + links_key = f"link_scores_{orientation}_fpn2" + deltas_key = f"bbox_deltas_{orientation}_fpn2" + + if scores_key not in out_dict: + continue + + pixel_scores = out_dict[scores_key][0, 0] + if pixel_scores.max() <= 0.85: + continue + + link_scores = out_dict[links_key][0] + bbox_deltas = out_dict[deltas_key][0] + + quads = _pixellink_decode( + pixel_scores, link_scores, bbox_deltas, 4, + pixel_thresh=0.85, + min_area=min_area_scaled, + min_component_pixels=5, + ) + + for q in quads: + # Only keep if not overlapping with primary detections + overlaps = any(_quad_iou(q, p) > 0.1 for p in primary_quads) + if not overlaps: + fpn2_quads.append(q) + + # Combine and final NMS + all_quads = primary_quads + fpn2_quads + if fpn2_quads: + all_quads = _nms_quads(all_quads, iou_thresh=_NMS_IOU_THRESH) + + # Scale quads back to original image coordinates + for i in range(len(all_quads)): + all_quads[i] = all_quads[i] / scale + + return all_quads, scale + + # ─── Script Identification ──────────────────────────────────────────── + + def _identify_script(self, crop_rgb: np.ndarray) -> int: + """Identify script of a cropped text region. + + Returns script index (0=Latin, 1=CJK, ..., 9=Unknown). + """ + sess = self._get_script_id() + + # Preprocess: RGB -> height=60 -> /255 -> NCHW + data = self._preprocess_recognizer(crop_rgb) + + outputs = sess.run(None, {"data": data}) + # Output: script_id_score [1, 1, 10] + script_scores = outputs[3] # script_id_score + script_idx = int(np.argmax(script_scores.flatten()[:10])) + return script_idx + + # ─── Recognition ────────────────────────────────────────────────────── + + def _recognize( + self, crop_rgb: np.ndarray, model_idx: int + ) -> tuple[str, float, list[float]]: + """Recognize text in a cropped region using the specified model. + + Returns (text, confidence, per_char_confidences). + """ + sess = self._get_recognizer(model_idx) + idx2char, blank_idx = self._get_char_map(model_idx) + + data = self._preprocess_recognizer(crop_rgb) + h, w = data.shape[2], data.shape[3] + seq_lengths = np.array([w // 4], dtype=np.int32) + + logprobs = sess.run(None, {"data": data, "seq_lengths": seq_lengths})[0] + text, conf, char_confs = ctc_greedy_decode(logprobs, idx2char, blank_idx) + return text, conf, char_confs + + # ─── Word splitting ───────────────────────────────────────────────── + + @staticmethod + def _split_into_words( + word_texts: list[str], + quad: np.ndarray, + confidence: float, + char_confs: list[float] | None = None, + ) -> list[OcrWord]: + """Split a line into word-level OcrWord objects with estimated bboxes. + + Distributes the line quad proportionally by character count. + Per-word confidence is computed from character-level CTC confidences. + """ + if not word_texts: + return [] + + # Include spaces in character counting for positioning + total_chars = sum(len(w) for w in word_texts) + len(word_texts) - 1 + if total_chars <= 0: + total_chars = 1 + + # Build per-word confidence from char_confs + word_confidences: list[float] = [] + if char_confs and len(char_confs) >= sum(len(w) for w in word_texts): + idx = 0 + for word_text in word_texts: + wc = char_confs[idx:idx + len(word_text)] + word_confidences.append(float(np.mean(wc)) if wc else confidence) + idx += len(word_text) + # Skip space character confidence (if present in the list) + if idx < len(char_confs): + idx += 1 # skip space + else: + word_confidences = [confidence] * len(word_texts) + + # Interpolate along top edge (q0→q1) and bottom edge (q3→q2) + top_start, top_end = quad[0], quad[1] + bot_start, bot_end = quad[3], quad[2] + + words: list[OcrWord] = [] + char_pos = 0 + + for i, word_text in enumerate(word_texts): + t_start = char_pos / total_chars + t_end = (char_pos + len(word_text)) / total_chars + + # Interpolate corners + tl = top_start + (top_end - top_start) * t_start + tr = top_start + (top_end - top_start) * t_end + bl = bot_start + (bot_end - bot_start) * t_start + br = bot_start + (bot_end - bot_start) * t_end + + bbox = BoundingRect( + x1=float(tl[0]), y1=float(tl[1]), + x2=float(tr[0]), y2=float(tr[1]), + x3=float(br[0]), y3=float(br[1]), + x4=float(bl[0]), y4=float(bl[1]), + ) + words.append(OcrWord( + text=word_text, + bounding_rect=bbox, + confidence=word_confidences[i], + )) + + char_pos += len(word_text) + 1 # +1 for space + + return words + + # ─── Preprocessing ──────────────────────────────────────────────────── + + @staticmethod + def _preprocess_recognizer(img_rgb: np.ndarray) -> np.ndarray: + """Preprocess image for recognizer/scriptID input. + + Process: Resize height to 60px → RGB / 255.0 → NCHW float32. + """ + h, w = img_rgb.shape[:2] + target_h = _REC_TARGET_H + scale = target_h / h + new_w = max(int(w * scale), _REC_MIN_WIDTH) + new_w = (new_w + 3) // 4 * 4 # align to 4 + + resized = cv2.resize(img_rgb, (new_w, target_h), interpolation=cv2.INTER_LINEAR) + data = resized.astype(np.float32) / 255.0 + data = data.transpose(2, 0, 1)[np.newaxis] # HWC → NCHW + return data + + # ─── Crop ───────────────────────────────────────────────────────────── + + @staticmethod + def _crop_quad( + img_rgb: np.ndarray, + quad: np.ndarray, + padding_ratio: float = 0.15, + ) -> np.ndarray | None: + """Crop a text region from the image using the bounding quad. + + Uses axis-aligned rectangle crop with padding (matching DLL behavior). + Falls back to perspective transform only for heavily rotated text (>15°). + + Args: + img_rgb: Source image (H, W, 3). + quad: 4 corners as (4, 2) array. + padding_ratio: How much to expand (fraction of height). + + Returns: + Cropped RGB image or None. + """ + try: + img_h, img_w = img_rgb.shape[:2] + + # Check rotation angle of top edge + dx = quad[1][0] - quad[0][0] + dy = quad[1][1] - quad[0][1] + angle = abs(math.atan2(dy, dx)) * 180 / math.pi + + # For near-horizontal text (<15°), use simple axis-aligned rectangle + if angle < 15: + # Axis-aligned bounding box from quad + x_min = float(quad[:, 0].min()) + x_max = float(quad[:, 0].max()) + y_min = float(quad[:, 1].min()) + y_max = float(quad[:, 1].max()) + + box_h = y_max - y_min + box_w = x_max - x_min + + if box_h < 3 or box_w < 5: + return None + + # Apply padding (use height-proportional padding on ALL sides) + # Minimum 3px padding for very small text regions + pad_h = max(box_h * padding_ratio, 3) + pad_w = max(box_h * 0.25, 3) # wider horizontal padding for stride alignment + + y1 = max(0, int(y_min - pad_h)) + y2 = min(img_h, int(y_max + pad_h)) + x1 = max(0, int(x_min - pad_w)) + x2 = min(img_w, int(x_max + pad_w)) + + if y2 - y1 < 3 or x2 - x1 < 5: + return None + + return img_rgb[y1:y2, x1:x2].copy() + + # For rotated text, use perspective transform + w1 = np.linalg.norm(quad[1] - quad[0]) + w2 = np.linalg.norm(quad[2] - quad[3]) + h1 = np.linalg.norm(quad[3] - quad[0]) + h2 = np.linalg.norm(quad[2] - quad[1]) + + target_w = int(max(w1, w2)) + target_h = int(max(h1, h2)) + + if target_w < 5 or target_h < 3: + return None + + # Expand the quad by padding + pad = max(h1, h2) * padding_ratio + + top_dir = quad[0] - quad[3] + if np.linalg.norm(top_dir) > 0: + top_dir = top_dir / np.linalg.norm(top_dir) + else: + top_dir = np.array([0, -1], dtype=np.float32) + + left_dir = quad[0] - quad[1] + if np.linalg.norm(left_dir) > 0: + left_dir = left_dir / np.linalg.norm(left_dir) + else: + left_dir = np.array([-1, 0], dtype=np.float32) + + expanded = quad.copy().astype(np.float32) + expanded[0] = quad[0] + top_dir * pad + left_dir * pad * 0.3 + expanded[1] = quad[1] + top_dir * pad - left_dir * pad * 0.3 + expanded[2] = quad[2] - top_dir * pad - left_dir * pad * 0.3 + expanded[3] = quad[3] - top_dir * pad + left_dir * pad * 0.3 + + expanded[:, 0] = np.clip(expanded[:, 0], 0, img_w - 1) + expanded[:, 1] = np.clip(expanded[:, 1], 0, img_h - 1) + + w1 = np.linalg.norm(expanded[1] - expanded[0]) + w2 = np.linalg.norm(expanded[2] - expanded[3]) + h1 = np.linalg.norm(expanded[3] - expanded[0]) + h2 = np.linalg.norm(expanded[2] - expanded[1]) + target_w = int(max(w1, w2)) + target_h = int(max(h1, h2)) + + if target_w < 5 or target_h < 3: + return None + + dst = np.array([ + [0, 0], + [target_w - 1, 0], + [target_w - 1, target_h - 1], + [0, target_h - 1], + ], dtype=np.float32) + + M = cv2.getPerspectiveTransform(expanded.astype(np.float32), dst) + crop = cv2.warpPerspective( + img_rgb, M, (target_w, target_h), + flags=cv2.INTER_LINEAR, + borderMode=cv2.BORDER_REPLICATE, + ) + return crop + except Exception: + return None + + # ─── Model Loading ──────────────────────────────────────────────────── + + def _find_model(self, model_idx: int) -> Path: + """Find ONNX model file by index. Checks unlocked dir first for models 11-33.""" + if model_idx >= 11 and self._unlocked_dir.exists(): + matches = list(self._unlocked_dir.glob(f"model_{model_idx:02d}_*")) + if matches: + return matches[0] + matches = list(self._models_dir.glob(f"model_{model_idx:02d}_*")) + if not matches: + raise FileNotFoundError(f"Model file not found for index {model_idx}") + return matches[0] + + def _get_detector(self) -> ort.InferenceSession: + """Get or create detector session.""" + if self._detector is None: + path = self._find_model(0) + self._detector = ort.InferenceSession( + str(path), sess_options=self._sess_opts, providers=self._providers + ) + return self._detector + + def _get_script_id(self) -> ort.InferenceSession: + """Get or create ScriptID session.""" + if self._script_id is None: + path = self._find_model(1) + self._script_id = ort.InferenceSession( + str(path), sess_options=self._sess_opts, providers=self._providers + ) + return self._script_id + + def _get_recognizer(self, model_idx: int) -> ort.InferenceSession: + """Get or create recognizer session.""" + if model_idx not in self._recognizers: + path = self._find_model(model_idx) + self._recognizers[model_idx] = ort.InferenceSession( + str(path), sess_options=self._sess_opts, providers=self._providers + ) + return self._recognizers[model_idx] + + def _get_char_map(self, model_idx: int) -> tuple[dict[int, str], int]: + """Get or load character map for model.""" + if model_idx not in self._char_maps: + info = MODEL_REGISTRY.get(model_idx) + if not info or not info[2]: + raise ValueError(f"No char2ind file for model {model_idx}") + char_path = self._config_dir / info[2] + self._char_maps[model_idx] = load_char_map(char_path) + return self._char_maps[model_idx] + + def _get_line_layout(self) -> ort.InferenceSession | None: + """Get or create LineLayout session (model 33). Returns None if unavailable.""" + if self._line_layout is None: + try: + path = self._find_model(33) + self._line_layout = ort.InferenceSession( + str(path), sess_options=self._sess_opts, providers=self._providers + ) + except FileNotFoundError: + return None + return self._line_layout + + def _run_line_layout(self, crop_rgb: np.ndarray) -> float | None: + """Run LineLayout model to get line boundary score. + + Args: + crop_rgb: Cropped text line image. + + Returns: + Line layout score (higher = more confident this is a complete line), + or None if LineLayout model unavailable. + """ + sess = self._get_line_layout() + if sess is None: + return None + + try: + data = self._preprocess_recognizer(crop_rgb) + outputs = sess.run(None, {"data": data}) + # output[1] = line_layout_score [1, 1, 1] + score = float(outputs[1].flatten()[0]) + return score + except Exception: + return None diff --git a/ocr/models.py b/ocr/models.py new file mode 100644 index 0000000000000000000000000000000000000000..563a861fc2f75ac31cf5a62df058d7eaf3f6360c --- /dev/null +++ b/ocr/models.py @@ -0,0 +1,55 @@ +"""OCR result data models.""" + +from __future__ import annotations + +from dataclasses import dataclass, field + + +@dataclass +class BoundingRect: + """Quadrilateral bounding box (4 corners).""" + x1: float = 0.0 + y1: float = 0.0 + x2: float = 0.0 + y2: float = 0.0 + x3: float = 0.0 + y3: float = 0.0 + x4: float = 0.0 + y4: float = 0.0 + + +@dataclass +class OcrWord: + """Single recognized word with position and confidence.""" + text: str + bounding_rect: BoundingRect | None = None + confidence: float = 0.0 + + +@dataclass +class OcrLine: + """Single line of recognized text.""" + text: str + bounding_rect: BoundingRect | None = None + words: list[OcrWord] = field(default_factory=list) + + +@dataclass +class OcrResult: + """Complete OCR recognition result.""" + text: str = "" + text_angle: float | None = None + lines: list[OcrLine] = field(default_factory=list) + error: str | None = None + + @property + def is_empty(self) -> bool: + return not self.text.strip() + + @property + def average_confidence(self) -> float: + """Average word-level confidence across all lines.""" + all_words = [w for line in self.lines for w in line.words if w.confidence > 0] + if not all_words: + return 0.0 + return sum(w.confidence for w in all_words) / len(all_words) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000000000000000000000000000000000000..1e629dacc33c5c619d5c25317377f7ae113d94e1 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "oneocr" +version = "0.2.0" +description = "Reverse-engineered cross-platform OCR pipeline from Microsoft OneOCR" +readme = "README.md" +requires-python = ">=3.12" +dependencies = [ + "pillow>=12.1.0", + "numpy>=1.26.0", + "opencv-python-headless>=4.8.0", + "onnxruntime>=1.16.0", +] + +[project.optional-dependencies] +extract = [ + "pycryptodome>=3.19.0", + "onnx>=1.15.0", +] +screen = [ + "mss>=9.0.0", +] +dev = [ + "pycryptodome>=3.19.0", + "onnx>=1.15.0", + "mss>=9.0.0", +] diff --git a/tools/extract_pipeline.py b/tools/extract_pipeline.py new file mode 100644 index 0000000000000000000000000000000000000000..fd8a5df7d56d98fbdc98a465d3f43fd81d388ee8 --- /dev/null +++ b/tools/extract_pipeline.py @@ -0,0 +1,590 @@ +#!/usr/bin/env python3 +""" +OneOCR Extraction Pipeline — Complete end-to-end extraction tool. +================================================================= + +Single script that performs the entire extraction process: + 1. Decrypt .onemodel container (AES-256-CFB128) + 2. Extract 34 ONNX models + config data + 3. Unlock models 11-33 (replace OneOCRFeatureExtract custom op) + 4. Verify all models load in onnxruntime + +Usage: + python tools/extract_pipeline.py # defaults + python tools/extract_pipeline.py path/to/oneocr.onemodel # custom input + python tools/extract_pipeline.py --verify-only # just verify + +Requirements: + pip install pycryptodome onnx onnxruntime numpy + +Output structure: + oneocr_extracted/ + ├── onnx_models/ # 34 raw ONNX models (11-33 have custom ops) + ├── onnx_models_unlocked/ # 23 unlocked models (11-33, standard ops) + └── config_data/ # char maps, rnn_info, manifest, configs +""" + +from __future__ import annotations + +import argparse +import copy +import hashlib +import struct +import sys +import time +from pathlib import Path + +import numpy as np + +try: + from Crypto.Cipher import AES +except ImportError: + print("ERROR: pycryptodome is required.") + print(" pip install pycryptodome") + sys.exit(1) + +try: + import onnx + from onnx import helper, numpy_helper +except ImportError: + print("ERROR: onnx is required.") + print(" pip install onnx") + sys.exit(1) + +try: + import onnxruntime as ort +except ImportError: + ort = None + print("WARNING: onnxruntime not installed — will skip runtime verification.") + + +# ═══════════════════════════════════════════════════════════════════════════════ +# CONSTANTS +# ═══════════════════════════════════════════════════════════════════════════════ + +MASTER_KEY = b'kj)TGtrK>f]b[Piow.gU+nC@s""""""4' +IV = b"Copyright @ OneO" +CONTAINER_MAGIC = bytes.fromhex("4a1a082b25000000") + + +# ═══════════════════════════════════════════════════════════════════════════════ +# STEP 1: DECRYPTION +# ═══════════════════════════════════════════════════════════════════════════════ + +def aes_cfb128_decrypt(key: bytes, data: bytes) -> bytes: + """Decrypt with AES-256-CFB128.""" + return AES.new(key, AES.MODE_CFB, iv=IV, segment_size=128).decrypt(data) + + +def derive_key(sha_input: bytes) -> bytes: + """SHA256 key derivation.""" + return hashlib.sha256(sha_input).digest() + + +def read_varint(data: bytes, pos: int) -> tuple[int, int]: + """Read protobuf varint.""" + val = shift = 0 + while pos < len(data): + b = data[pos]; pos += 1 + val |= (b & 0x7F) << shift + if not (b & 0x80): break + shift += 7 + return val, pos + + +def measure_protobuf(data: bytes) -> int: + """Measure valid ONNX ModelProto protobuf length.""" + VALID = {1, 2, 3, 4, 5, 6, 7, 8, 9, 14, 20} + pos = 0 + while pos < len(data): + start = pos + tag, pos = read_varint(data, pos) + if pos > len(data): return start + field, wire = tag >> 3, tag & 7 + if field not in VALID: return start + if wire == 0: _, pos = read_varint(data, pos) + elif wire == 1: pos += 8 + elif wire == 2: l, pos = read_varint(data, pos); pos += l + elif wire == 5: pos += 4 + else: return start + if pos > len(data): return start + return pos + + +class OneModelFile: + """Parser for .onemodel encrypted containers.""" + + def __init__(self, filepath: str | Path): + self.filepath = Path(filepath) + self.data = self.filepath.read_bytes() + self.H = struct.unpack_from(" bytes: + key = derive_key(MASTER_KEY + self.file_hash) + return aes_cfb128_decrypt(key, self.data[self.dx_offset:self.dx_offset + self.dx_size]) + + def decrypt_config(self, dx: bytes) -> bytes: + key = derive_key(dx[48:64] + dx[32:48]) + s1 = struct.unpack_from(" len(self.data): break + enc_size = s1 + 8 + data_off = off + 32 + if data_off + enc_size > len(self.data): break + key = derive_key(self.data[off + 16:off + 32] + checksum) + dec = aes_cfb128_decrypt(key, self.data[data_off:data_off + enc_size]) + if dec[:8] == CONTAINER_MAGIC: + yield idx, dec[8:] + else: + print(f" WARNING: chunk#{idx} magic mismatch — skipping") + off = data_off + enc_size + idx += 1 + + +def classify_chunk(payload: bytes) -> str: + """Classify decrypted chunk type.""" + if len(payload) > 100 and payload[0] == 0x08 and payload[1] in (0x06, 0x07): + return "onnx" + try: + sample = payload[:100].decode("ascii") + if all(c.isprintable() or c in "\n\r\t" for c in sample): + if "" in sample: return "rnn_info" + if sample.startswith("! ") or sample.startswith('" '): + return "char2ind" if any(c.isdigit() for c in sample[:20]) else "char2inschar" + if sample.startswith("0."): return "score_calibration" + if "text_script" in sample: return "ocr_config" + if "//" in sample[:5]: return "composite_chars" + return "text_data" + except (UnicodeDecodeError, ValueError): + pass + return "binary_data" + + +def decrypt_and_extract(input_file: Path, output_dir: Path) -> dict: + """Step 1: Decrypt .onemodel and extract all chunks. + + Returns dict with 'onnx_models' and 'config_files' lists. + """ + print("=" * 70) + print(" STEP 1: DECRYPT & EXTRACT") + print("=" * 70) + + model_file = OneModelFile(input_file) + print(f" Input: {input_file} ({len(model_file.data):,} bytes)") + print(f" Output: {output_dir}") + + # Decrypt DX index + dx = model_file.decrypt_dx() + assert dx[:2] == b"DX", "DX magic mismatch!" + print(f" DX index decrypted ({len(dx):,} bytes)") + + # Decrypt manifest config + config_dec = model_file.decrypt_config(dx) + assert config_dec[:8] == CONTAINER_MAGIC + config_payload = config_dec[8:] + + # Prepare output + onnx_dir = output_dir / "onnx_models" + config_dir = output_dir / "config_data" + onnx_dir.mkdir(parents=True, exist_ok=True) + config_dir.mkdir(parents=True, exist_ok=True) + + # Save manifest + manifest_path = config_dir / "manifest.bin" + manifest_path.write_bytes(config_payload) + print(f" Manifest: {len(config_payload):,} bytes") + + # Extract chunks + onnx_models = [] + config_files = [manifest_path] + + EXT_MAP = { + "rnn_info": ".rnn_info", "char2ind": ".char2ind.txt", + "char2inschar": ".char2inschar.txt", "score_calibration": ".calibration.txt", + "ocr_config": ".config.txt", "composite_chars": ".composite.txt", + "text_data": ".txt", "binary_data": ".bin", + } + + print(f"\n {'#':>4} {'Type':18s} {'Size':>12} {'Filename'}") + print(f" {'-'*66}") + + for idx, payload in model_file.iter_chunks(): + chunk_type = classify_chunk(payload) + + if chunk_type == "onnx": + exact_size = measure_protobuf(payload) + onnx_data = payload[:exact_size] + info = _get_onnx_info(onnx_data) + ir = info.get("ir_version", "?") + prod = info.get("producer_version", "unknown") + size_kb = len(onnx_data) // 1024 + onnx_idx = len(onnx_models) + fname = f"model_{onnx_idx:02d}_ir{ir}_{prod}_{size_kb}KB.onnx" + (onnx_dir / fname).write_bytes(onnx_data) + onnx_models.append(onnx_dir / fname) + print(f" {idx:4d} {'ONNX':18s} {len(onnx_data):12,} {fname}") + else: + ext = EXT_MAP.get(chunk_type, ".bin") + fname = f"chunk_{idx:02d}_{chunk_type}{ext}" + (config_dir / fname).write_bytes(payload) + config_files.append(config_dir / fname) + print(f" {idx:4d} {chunk_type:18s} {len(payload):12,} {fname}") + + print(f"\n Extracted: {len(onnx_models)} ONNX models, {len(config_files)} config files") + return {"onnx_models": onnx_models, "config_files": config_files} + + +def _get_onnx_info(data: bytes) -> dict: + """Extract basic ONNX info from protobuf header.""" + info = {}; pos = 0 + while pos < min(len(data), 500): + tag, pos = read_varint(data, pos) + field, wire = tag >> 3, tag & 7 + if wire == 0: + val, pos = read_varint(data, pos) + if field == 1: info["ir_version"] = val + elif wire == 2: + l, pos = read_varint(data, pos) + raw = data[pos:pos + l]; pos += l + try: + if field == 4: info["producer_version"] = raw.decode() + except: pass + elif wire == 5: pos += 4 + elif wire == 1: pos += 8 + else: break + if "ir_version" in info and "producer_version" in info: break + return info + + +# ═══════════════════════════════════════════════════════════════════════════════ +# STEP 2: UNLOCK MODELS +# ═══════════════════════════════════════════════════════════════════════════════ + +def _extract_fe_weights(model) -> tuple[np.ndarray, np.ndarray, int, int]: + """Extract W, b from OneOCRFeatureExtract config blob.""" + config_blob = None + for init in model.graph.initializer: + if init.name == "feature/config": + config_blob = bytes(init.string_data[0] if init.string_data else init.raw_data) + break + if config_blob is None: + raise ValueError("No feature/config initializer") + + be_arr = np.frombuffer(config_blob, dtype='>f4').copy() + + # Find dimensions from metadata or graph + fe_node = next((n for n in model.graph.node if n.op_type == "OneOCRFeatureExtract"), None) + if fe_node is None: + raise ValueError("No OneOCRFeatureExtract node") + + in_dim = out_dim = None + for i in range(len(be_arr) - 10, len(be_arr)): + val = be_arr[i] + if val == 21.0 and i + 1 < len(be_arr) and be_arr[i + 1] in [50.0, 51.0]: + in_dim, out_dim = 21, int(be_arr[i + 1]) + break + + if in_dim is None: + for gi in model.graph.input: + if gi.name == "data": + shape = [d.dim_value for d in gi.type.tensor_type.shape.dim] + if len(shape) >= 2 and shape[1] > 0: + in_dim = shape[1] + break + + if out_dim is None: + fe_out = fe_node.output[0] + for node in model.graph.node: + if node.op_type == "Gemm" and fe_out in node.input: + wn = node.input[1] + for init in model.graph.initializer: + if init.name == wn: + W = numpy_helper.to_array(init) + out_dim = W.shape[0] if len(W.shape) == 2 else W.shape[1] + break + + if in_dim is None or out_dim is None: + raise ValueError(f"Cannot determine dims: in={in_dim}, out={out_dim}") + + W = be_arr[:in_dim * out_dim].reshape(in_dim, out_dim).astype(np.float32) + b = be_arr[in_dim * out_dim:in_dim * out_dim + out_dim].astype(np.float32) + return W, b, in_dim, out_dim + + +def unlock_gemm_model(model_path: Path, output_dir: Path) -> Path | None: + """Unlock models 11-32: OneOCRFeatureExtract → Gemm.""" + model = onnx.load(str(model_path)) + if not any(n.op_type == "OneOCRFeatureExtract" for n in model.graph.node): + return None + + W, b, in_dim, out_dim = _extract_fe_weights(model) + new_model = copy.deepcopy(model) + + # Replace initializers + new_inits = [i for i in new_model.graph.initializer if i.name != "feature/config"] + new_inits.append(numpy_helper.from_array(W.T, name="fe_weight")) + new_inits.append(numpy_helper.from_array(b, name="fe_bias")) + del new_model.graph.initializer[:] + new_model.graph.initializer.extend(new_inits) + + # Replace node + fe_node = next(n for n in new_model.graph.node if n.op_type == "OneOCRFeatureExtract") + fe_in, fe_out = fe_node.input[0], fe_node.output[0] + new_nodes = [] + for node in new_model.graph.node: + if node.op_type == "OneOCRFeatureExtract": + new_nodes.append(helper.make_node("Gemm", [fe_in, "fe_weight", "fe_bias"], + [fe_out], alpha=1.0, beta=1.0, transB=1)) + else: + new_nodes.append(node) + del new_model.graph.node[:] + new_model.graph.node.extend(new_nodes) + + # Cleanup + del new_model.graph.input[:] + new_model.graph.input.extend([i for i in model.graph.input if i.name != "feature/config"]) + new_opsets = [op for op in new_model.opset_import if op.domain != "com.microsoft.oneocr"] + del new_model.opset_import[:] + new_model.opset_import.extend(new_opsets) + + out_path = output_dir / (model_path.stem + "_unlocked.onnx") + onnx.save(new_model, str(out_path)) + return out_path + + +def unlock_conv_model(model_path: Path, output_dir: Path) -> Path | None: + """Unlock model 33 (LineLayout): OneOCRFeatureExtract → Conv1x1.""" + model = onnx.load(str(model_path)) + if not any(n.op_type == "OneOCRFeatureExtract" for n in model.graph.node): + return None + + # Model 33: in_ch=256, out_ch=16 + config_blob = None + for init in model.graph.initializer: + if init.name == "feature/config": + config_blob = bytes(init.string_data[0] if init.string_data else init.raw_data) + break + if config_blob is None: + return None + + be_arr = np.frombuffer(config_blob, dtype='>f4').copy() + in_ch, out_ch = 256, 16 + W = be_arr[:in_ch * out_ch].reshape(in_ch, out_ch).T.reshape(out_ch, in_ch, 1, 1).astype(np.float32) + b = be_arr[in_ch * out_ch:in_ch * out_ch + out_ch].astype(np.float32) + + new_model = copy.deepcopy(model) + new_inits = [i for i in new_model.graph.initializer if i.name != "feature/config"] + new_inits.append(numpy_helper.from_array(W, name="fe_conv_weight")) + new_inits.append(numpy_helper.from_array(b, name="fe_conv_bias")) + del new_model.graph.initializer[:] + new_model.graph.initializer.extend(new_inits) + + fe_node = next(n for n in new_model.graph.node if n.op_type == "OneOCRFeatureExtract") + fe_in, fe_out = fe_node.input[0], fe_node.output[0] + new_nodes = [] + for node in new_model.graph.node: + if node.op_type == "OneOCRFeatureExtract": + new_nodes.append(helper.make_node("Conv", [fe_in, "fe_conv_weight", "fe_conv_bias"], + [fe_out], kernel_shape=[1, 1], strides=[1, 1], + pads=[0, 0, 0, 0])) + else: + new_nodes.append(node) + del new_model.graph.node[:] + new_model.graph.node.extend(new_nodes) + + del new_model.graph.input[:] + new_model.graph.input.extend([i for i in model.graph.input if i.name != "feature/config"]) + new_opsets = [op for op in new_model.opset_import if op.domain != "com.microsoft.oneocr"] + del new_model.opset_import[:] + new_model.opset_import.extend(new_opsets) + + out_path = output_dir / (model_path.stem + "_unlocked.onnx") + onnx.save(new_model, str(out_path)) + return out_path + + +def unlock_all_models(onnx_dir: Path, output_dir: Path) -> dict: + """Step 2: Unlock models 11-33 (replace custom ops). + + Returns dict with 'unlocked', 'skipped', 'failed' lists. + """ + print("\n" + "=" * 70) + print(" STEP 2: UNLOCK MODELS (replace OneOCRFeatureExtract)") + print("=" * 70) + + output_dir.mkdir(parents=True, exist_ok=True) + results = {"unlocked": [], "skipped": [], "failed": []} + + for idx in range(11, 34): + matches = list(onnx_dir.glob(f"model_{idx:02d}_*")) + if not matches: + print(f" model_{idx:02d}: NOT FOUND") + results["failed"].append(idx) + continue + + model_path = matches[0] + try: + if idx == 33: + out = unlock_conv_model(model_path, output_dir) + else: + out = unlock_gemm_model(model_path, output_dir) + + if out is None: + results["skipped"].append(idx) + print(f" model_{idx:02d}: skipped (no custom op)") + else: + results["unlocked"].append(idx) + print(f" model_{idx:02d}: ✓ unlocked → {out.name}") + except Exception as e: + results["failed"].append(idx) + print(f" model_{idx:02d}: ✗ FAILED — {e}") + + n = len(results["unlocked"]) + print(f"\n Unlocked: {n}/23 models") + return results + + +# ═══════════════════════════════════════════════════════════════════════════════ +# STEP 3: VERIFY +# ═══════════════════════════════════════════════════════════════════════════════ + +def verify_models(onnx_dir: Path, unlocked_dir: Path) -> dict: + """Step 3: Verify all models load in onnxruntime. + + Returns dict with verification results. + """ + print("\n" + "=" * 70) + print(" STEP 3: VERIFY (onnxruntime inference test)") + print("=" * 70) + + if ort is None: + print(" ⚠ onnxruntime not installed — skipping verification") + return {"status": "skipped"} + + results = {"ok": [], "custom_op": [], "failed": []} + + # Verify core models (0-10) + print("\n Core models (0-10):") + for idx in range(11): + matches = list(onnx_dir.glob(f"model_{idx:02d}_*")) + if not matches: continue + try: + sess = ort.InferenceSession(str(matches[0]), + providers=["CPUExecutionProvider"]) + inputs = sess.get_inputs() + shapes = {i.name: i.shape for i in inputs} + results["ok"].append(idx) + print(f" model_{idx:02d}: ✓ inputs={shapes}") + except Exception as e: + err = str(e)[:60] + if "custom ops" in err.lower() or "oneocr" in err.lower(): + results["custom_op"].append(idx) + print(f" model_{idx:02d}: ⚠ custom_op ({err})") + else: + results["failed"].append(idx) + print(f" model_{idx:02d}: ✗ {err}") + + # Verify unlocked models (11-33) + print("\n Unlocked models (11-33):") + for idx in range(11, 34): + matches = list(unlocked_dir.glob(f"model_{idx:02d}_*")) + if not matches: continue + try: + sess = ort.InferenceSession(str(matches[0]), + providers=["CPUExecutionProvider"]) + # Quick zero-input test + feeds = {} + for inp in sess.get_inputs(): + shape = [d if isinstance(d, int) and d > 0 else 1 for d in inp.shape] + feeds[inp.name] = np.zeros(shape, dtype=np.float32) + out = sess.run(None, feeds) + results["ok"].append(idx) + print(f" model_{idx:02d}: ✓ output_shapes={[o.shape for o in out]}") + except Exception as e: + results["failed"].append(idx) + print(f" model_{idx:02d}: ✗ {str(e)[:60]}") + + ok = len(results["ok"]) + total = ok + len(results["custom_op"]) + len(results["failed"]) + print(f"\n Verification: {ok}/{total} models OK") + return results + + +# ═══════════════════════════════════════════════════════════════════════════════ +# MAIN +# ═══════════════════════════════════════════════════════════════════════════════ + +def main(): + parser = argparse.ArgumentParser( + description="OneOCR extraction pipeline: decrypt → extract → unlock → verify") + parser.add_argument("input", nargs="?", default="ocr_data/oneocr.onemodel", + help="Path to .onemodel file (default: ocr_data/oneocr.onemodel)") + parser.add_argument("--output", "-o", default="oneocr_extracted", + help="Output directory (default: oneocr_extracted)") + parser.add_argument("--verify-only", action="store_true", + help="Only verify existing extracted models") + parser.add_argument("--skip-unlock", action="store_true", + help="Skip model unlocking step") + parser.add_argument("--skip-verify", action="store_true", + help="Skip verification step") + args = parser.parse_args() + + input_file = Path(args.input) + output_dir = Path(args.output) + onnx_dir = output_dir / "onnx_models" + unlocked_dir = output_dir / "onnx_models_unlocked" + + print() + print("╔══════════════════════════════════════════════════════════════════════╗") + print("║ OneOCR Extraction Pipeline ║") + print("║ Decrypt → Extract → Unlock → Verify ║") + print("╚══════════════════════════════════════════════════════════════════════╝") + + t_start = time.perf_counter() + + if args.verify_only: + verify_models(onnx_dir, unlocked_dir) + else: + # Step 1: Decrypt & Extract + if not input_file.exists(): + print(f"\n ERROR: Input file not found: {input_file}") + print(f" Place oneocr.onemodel in ocr_data/ directory") + sys.exit(1) + + extract_result = decrypt_and_extract(input_file, output_dir) + + # Step 2: Unlock + if not args.skip_unlock: + unlock_result = unlock_all_models(onnx_dir, unlocked_dir) + else: + print("\n (Skipping unlock step)") + + # Step 3: Verify + if not args.skip_verify: + verify_result = verify_models(onnx_dir, unlocked_dir) + else: + print("\n (Skipping verification)") + + elapsed = time.perf_counter() - t_start + print(f"\n{'=' * 70}") + print(f" DONE in {elapsed:.1f}s") + print(f" Models: {onnx_dir}") + print(f" Unlocked: {unlocked_dir}") + print(f" Config: {output_dir / 'config_data'}") + print(f"{'=' * 70}") + + +if __name__ == "__main__": + main() diff --git a/tools/test_quick.py b/tools/test_quick.py new file mode 100644 index 0000000000000000000000000000000000000000..80fc67e379eb7041c6c3a102cf0b6ea8f0a4e100 --- /dev/null +++ b/tools/test_quick.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +""" +Quick OCR test — verify the ONNX engine works on sample images. + +Usage: + python tools/test_quick.py # test all images in working_space/input/ + python tools/test_quick.py path/to/image.png # test single image +""" + +import sys +import time +from pathlib import Path + +from PIL import Image + +sys.path.insert(0, str(Path(__file__).parent.parent)) +from ocr.engine_onnx import OcrEngineOnnx + + +def test_image(engine: OcrEngineOnnx, path: Path) -> bool: + """Run OCR on one image and print results.""" + img = Image.open(path) + t0 = time.perf_counter() + result = engine.recognize_pil(img) + elapsed = (time.perf_counter() - t0) * 1000 + + status = "OK" if result.text.strip() else "EMPTY" + text_short = result.text.replace("\n", " | ")[:80] + + print(f" [{status}] {path.name:30s} {elapsed:6.0f}ms " + f"L={len(result.lines):2d} C={result.average_confidence:.0%} " + f'"{text_short}"') + return bool(result.text.strip()) + + +def main(): + if len(sys.argv) > 1: + paths = [Path(p) for p in sys.argv[1:]] + else: + input_dir = Path("working_space/input") + if not input_dir.exists(): + print(f"No images found. Place .png files in {input_dir}") + return + paths = sorted(input_dir.glob("*.png")) + + if not paths: + print("No images to test.") + return + + print(f"Testing {len(paths)} image(s)...\n") + engine = OcrEngineOnnx() + + ok = sum(test_image(engine, p) for p in paths) + print(f"\n Result: {ok}/{len(paths)} images produced text") + + +if __name__ == "__main__": + main() diff --git a/tools/visualize_ocr.py b/tools/visualize_ocr.py new file mode 100644 index 0000000000000000000000000000000000000000..332c744d43bfd2f2610af3dff3843168f6037c30 --- /dev/null +++ b/tools/visualize_ocr.py @@ -0,0 +1,268 @@ +"""Visualize OCR results — overlay recognized text directly on detected regions. + +Features: + - Text overlaid on word bounding boxes, scaled to fit + - Semi-transparent background behind text for readability + - Color-coded line bounding boxes + - Confidence heat-map coloring (green=high, red=low) + - Summary panel with statistics +""" +import sys +import time +from pathlib import Path + +import numpy as np +from PIL import Image, ImageDraw, ImageFont + +sys.path.insert(0, str(Path(__file__).parent.parent)) + +from ocr.engine_onnx import OcrEngineOnnx +from ocr.models import BoundingRect + + +# ─── Color helpers ──────────────────────────────────────────────────────── + +def _conf_color(conf: float) -> tuple[int, int, int]: + """Map confidence 0..1 → red..yellow..green.""" + if conf >= 0.85: + return (40, 180, 40) + elif conf >= 0.6: + t = (conf - 0.6) / 0.25 + return (int(220 * (1 - t)), int(180 * t + 100), 40) + else: + return (220, 60, 40) + + +_LINE_COLORS = [ + (70, 130, 255), (255, 100, 70), (50, 200, 100), (255, 180, 40), + (180, 80, 255), (40, 200, 200), (255, 80, 180), (160, 200, 60), +] + + +# ─── Font helpers ──────────────────────────────────────────────────────── + +def _load_font(size: int) -> ImageFont.FreeTypeFont | ImageFont.ImageFont: + """Try to load TrueType font, fallback to default.""" + for name in ("arial.ttf", "Arial.ttf", "segoeui.ttf", "msyh.ttc", + "NotoSansCJK-Regular.ttc", "DejaVuSans.ttf"): + try: + return ImageFont.truetype(name, size) + except Exception: + pass + return ImageFont.load_default() + + +def _fit_font_size( + text: str, box_w: float, box_h: float, + min_size: int = 8, max_size: int = 120, +) -> int: + """Binary search for font size that fits text into box_w × box_h.""" + lo, hi = min_size, max_size + best = min_size + while lo <= hi: + mid = (lo + hi) // 2 + font = _load_font(mid) + bbox = font.getbbox(text) + tw, th = bbox[2] - bbox[0], bbox[3] - bbox[1] + if tw <= box_w * 0.95 and th <= box_h * 0.88: + best = mid + lo = mid + 1 + else: + hi = mid - 1 + return best + + +# ─── Drawing helpers ───────────────────────────────────────────────────── + +def _draw_quad( + draw: ImageDraw.ImageDraw, b: BoundingRect, + color: tuple, width: int = 2, +) -> None: + """Draw a quadrilateral outline.""" + pts = [(b.x1, b.y1), (b.x2, b.y2), (b.x3, b.y3), (b.x4, b.y4)] + draw.polygon(pts, outline=color, width=width) + + +def _overlay_text_on_word( + overlay: Image.Image, + word_text: str, + b: BoundingRect, + conf: float, +) -> None: + """Draw text overlaid inside the word bounding box with semi-transparent bg.""" + xs = [b.x1, b.x2, b.x3, b.x4] + ys = [b.y1, b.y2, b.y3, b.y4] + x_min, x_max = min(xs), max(xs) + y_min, y_max = min(ys), max(ys) + box_w = x_max - x_min + box_h = y_max - y_min + + if box_w < 3 or box_h < 3: + return + + # Fit font to box + font_size = _fit_font_size(word_text, box_w, box_h) + font = _load_font(font_size) + + # Measure text + bbox = font.getbbox(word_text) + tw, th = bbox[2] - bbox[0], bbox[3] - bbox[1] + + # Center text in box + tx = x_min + (box_w - tw) / 2 + ty = y_min + (box_h - th) / 2 - bbox[1] + + # Semi-transparent white background behind text + bg = Image.new("RGBA", overlay.size, (0, 0, 0, 0)) + bg_draw = ImageDraw.Draw(bg) + pad = 2 + bg_draw.rectangle( + [tx - pad, y_min + (box_h - th) / 2 - pad, + tx + tw + pad, y_min + (box_h + th) / 2 + pad], + fill=(255, 255, 255, 170), + ) + overlay.alpha_composite(bg) + + # Text color based on confidence + text_color = _conf_color(conf) + draw = ImageDraw.Draw(overlay) + draw.text((tx, ty), word_text, fill=(*text_color, 255), font=font) + + +# ─── Summary panel ─────────────────────────────────────────────────────── + +def _draw_summary( + overlay: Image.Image, + n_lines: int, n_words: int, avg_conf: float, + angle: float, elapsed: float, img_size: tuple[int, int], +) -> None: + """Draw summary statistics panel at the top of the image.""" + font = _load_font(16) + stats = ( + f"Lines: {n_lines} | Words: {n_words} | " + f"Conf: {avg_conf:.1%} | Angle: {angle:.1f}\u00b0 | " + f"Time: {elapsed:.0f}ms | {img_size[0]}\u00d7{img_size[1]}" + ) + + bbox = font.getbbox(stats) + th = bbox[3] - bbox[1] + panel_h = th + 12 + + # Semi-transparent dark panel + bg = Image.new("RGBA", overlay.size, (0, 0, 0, 0)) + bg_draw = ImageDraw.Draw(bg) + bg_draw.rectangle([0, 0, overlay.width, panel_h], fill=(0, 0, 0, 180)) + overlay.alpha_composite(bg) + + draw = ImageDraw.Draw(overlay) + draw.text((8, 4), stats, fill=(255, 255, 255, 255), font=font) + + +# ═══════════════════════════════════════════════════════════════════════════ +# Main visualization +# ═══════════════════════════════════════════════════════════════════════════ + +def visualize( + image_path: str, + output_path: str = "result_ocr.png", + show_word_boxes: bool = True, + show_line_boxes: bool = True, + show_text_overlay: bool = True, + show_confidence: bool = True, +) -> None: + """Run OCR and visualize results with text overlay. + + Args: + image_path: Input image path. + output_path: Output path for annotated image. + show_word_boxes: Draw word-level bounding boxes. + show_line_boxes: Draw line-level bounding boxes. + show_text_overlay: Overlay recognized text on words. + show_confidence: Show confidence % below words. + """ + img = Image.open(image_path).convert("RGBA") + engine = OcrEngineOnnx() + + t0 = time.perf_counter() + result = engine.recognize_pil(img.convert("RGB")) + elapsed_ms = (time.perf_counter() - t0) * 1000 + + if result.error: + print(f"Error: {result.error}") + return + + overlay = img.copy() + draw = ImageDraw.Draw(overlay) + n_words = sum(len(l.words) for l in result.lines) + + for i, line in enumerate(result.lines): + lc = _LINE_COLORS[i % len(_LINE_COLORS)] + + # Line-level bounding box (thicker) + if show_line_boxes and line.bounding_rect: + _draw_quad(draw, line.bounding_rect, color=lc, width=3) + + for word in line.words: + if not word.bounding_rect: + continue + b = word.bounding_rect + + # Word-level bounding box (confidence-colored) + if show_word_boxes: + wc = _conf_color(word.confidence) + _draw_quad(draw, b, color=wc, width=2) + + # Overlay text inside the word box + if show_text_overlay: + _overlay_text_on_word(overlay, word.text, b, word.confidence) + draw = ImageDraw.Draw(overlay) # refresh after alpha_composite + + # Confidence label below word box + if show_confidence: + xs = [b.x1, b.x2, b.x3, b.x4] + ys = [b.y1, b.y2, b.y3, b.y4] + cx = sum(xs) / 4 + y_bot = max(ys) + 2 + conf_font = _load_font(11) + label = f"{word.confidence:.0%}" + lbbox = conf_font.getbbox(label) + lw = lbbox[2] - lbbox[0] + draw.text( + (cx - lw / 2, y_bot), + label, + fill=(*_conf_color(word.confidence), 220), + font=conf_font, + ) + + # Summary panel + _draw_summary( + overlay, + n_lines=len(result.lines), + n_words=n_words, + avg_conf=result.average_confidence, + angle=result.text_angle or 0.0, + elapsed=elapsed_ms, + img_size=(img.width, img.height), + ) + + # Save as RGB + final = Image.new("RGB", overlay.size, (255, 255, 255)) + final.paste(overlay, mask=overlay.split()[3]) + final.save(output_path, quality=95) + + print(f"\nSaved: {output_path}") + print(f"Text: \"{result.text}\"") + print(f"Lines: {len(result.lines)}, Words: {n_words}, " + f"Conf: {result.average_confidence:.1%}, Time: {elapsed_ms:.0f}ms") + + for i, line in enumerate(result.lines): + words_info = " ".join( + f'"{w.text}"({w.confidence:.0%})' for w in line.words + ) + print(f" L{i}: {words_info}") + + +if __name__ == "__main__": + image_path = sys.argv[1] if len(sys.argv) > 1 else "test3.png" + output_path = sys.argv[2] if len(sys.argv) > 2 else "result_ocr.png" + visualize(image_path, output_path)