Trích xuất văn bản máy đọc được từ tài liệu giấy quét, hóa đơn, thẻ căn cước và hình ảnh chụp thực tế là một năng lực nền tảng trong kỹ thuật xử lý tài liệu. Trước đây, nhận dạng ký tự quang học (OCR) chỉ được thực hiện độc quyền bởi các tiện ích desktop gốc hoặc các API thị giác đám mây đòi hỏi phải tải tài liệu thô lên mạng.
Các môi trường thực thi trình duyệt hiện đại, được hỗ trợ bởi WebAssembly (WASM), Web Workers và khả năng tăng tốc phần cứng SIMD, có thể thực thi các quy trình thị giác máy tính và deep learning phức tạp cục bộ ngay trên thiết bị client.
Tuy nhiên, việc chạy OCR trong trình duyệt web đòi hỏi nhiều hơn là chỉ biên dịch một mô hình suy luận. Để trích xuất văn bản với độ chính xác cao, hệ thống cần tiền xử lý hình ảnh ngay trong trình duyệt, nhị phân hóa thích ứng Otsu, các thuật toán phát hiện góc nghiêng, phân tích bố cục hình học và xây dựng Cây cú pháp trừu tượng tài liệu phân cấp (hAST) để ánh xạ các ký tự trực tiếp vào không gian tọa độ canvas.
1. Tiền xử lý hình ảnh trong trình duyệt: Toán học Canvas và thị giác máy tính
Độ chính xác của bất kỳ mô hình nhận dạng nơ-ron nào ở hạ nguồn đều phụ thuộc lớn vào chất lượng của hình ảnh đầu vào. Các tài liệu quét và ảnh chụp từ camera điện thoại thường gặp hiện tượng ánh sáng không đều, nhiễu cảm biến, biến dạng phối cảnh quang học và các góc xoay bị nghiêng.
Trước khi đưa các buffer pixel vào công cụ OCR, trình duyệt phải thực thi một chuỗi các phép biến đổi thị giác máy tính trực tiếp trên cấu trúc dữ liệu thô ImageData thông qua HTML5 Canvas.
+-----------------------------------------------------------------------+
| In-Browser Computer Vision Preprocessing |
+-----------------------------------------------------------------------+
| Raw Image (JPEG, PNG, WebP) |
| | |
| v |
| [ HTML5 OffscreenCanvas: 32-bit RGBA Byte Buffer ] |
| | |
| v |
| [ Grayscale Luminance Conversion: Y = 0.299R + 0.587G + 0.114B ] |
| | |
| v |
| [ Otsu's Adaptive Thresholding: Maximizing Inter-Class Variance ] |
| | |
| v |
| [ Skew Angle Calculation: Radon / Hough Transform Line Accumulation] |
| | |
| v |
| [ 2D Matrix Rotation Interpolation (Bilinear Filtering) ] |
| | |
| v |
| Clean, Deskewed, Binarized 1-Bit Buffer Passed to Inference Engine |
+-----------------------------------------------------------------------+Chuyển đổi ảnh xám sử dụng độ chói cảm nhận
Một hình ảnh màu chưa nén được biểu diễn trong bộ nhớ canvas dưới dạng một mảng phẳng Uint8ClampedArray định dạng các byte xen kẽ 32-bit [R, G, B, A].
Việc chuyển đổi không gian màu này thành một kênh đơn 8-bit đòi hỏi phải áp dụng trọng số độ sáng cảm nhận ITU-R BT.601, có tính đến độ nhạy cao hơn của hệ thống thị giác con người đối với các bước sóng xanh lá:
Thực hiện phép tính này trong JavaScript trên một bức ảnh 12 megapixel đòi hỏi 12 triệu vòng lặp. Bằng cách cấu trúc việc truy cập mảng bằng các khung nhìn số nguyên không dấu 32-bit (Uint32Array), các phép dịch bit sẽ thay thế các thao tác truy cập thuộc tính tốn kém:
// High-performance grayscale conversion over raw Canvas buffer
export function convertToGrayscale(imageData: ImageData): Uint8Array {
const { width, height, data } = imageData;
const pixelCount = width * height;
const grayscaleBuffer = new Uint8Array(pixelCount);
// Read data buffer through 32-bit words for memory efficiency
const uint32View = new Uint32Array(data.buffer);
for (let i = 0; i < pixelCount; i++) {
const pixel = uint32View[i];
// Extract channels from 0xAABBGGRR little-endian integer representation
const r = pixel & 0xff;
const g = (pixel >> 8) & 0xff;
const b = (pixel >> 16) & 0xff;
grayscaleBuffer[i] = (r * 77 + g * 150 + b * 29) >> 8; // Integer approximation
}
return grayscaleBuffer;
}Thuật toán nhị phân hóa toàn cục Otsu
Các mô hình nhận dạng văn bản nơ-ron hoạt động hiệu quả nhất trên các hình ảnh được nhị phân hóa sạch sẽ, nơi mực văn bản được biểu diễn bằng 1 (đen) và nền giấy được biểu diễn bằng 0 (trắng). Ngưỡng cố định sẽ thất bại khi xuất hiện bóng râm, ánh sáng đèn flash không đồng đều hoặc giấy bị ố vàng.
Thuật toán Otsu tính toán ngưỡng toàn cục tối ưu để phân chia các pixel thành hai lớp thống kê: nền (cường độ ) và tiền cảnh (cường độ ). Thuật toán đạt được điều này bằng cách tìm ra ngưỡng tối đa hóa phương sai giữa các lớp :
Trong đó:
- là xác suất tích lũy của lớp .
- là xác suất tích lũy của lớp .
- là cường độ trung bình của lớp .
- là cường độ trung bình của lớp .
- là biểu đồ tần suất chuẩn hóa của pixel có cường độ .
// Fast Otsu threshold calculator running in browser RAM
export function calculateOtsuThreshold(gray: Uint8Array): number {
const histogram = new Int32Array(256);
const totalPixels = gray.length;
for (let i = 0; i < totalPixels; i++) {
histogram[gray[i]]++;
}
let sumAll = 0;
for (let t = 0; t < 256; t++) {
sumAll += t * histogram[t];
}
let sumBack = 0;
let weightBack = 0;
let maximumVariance = 0;
let optimalThreshold = 128;
for (let t = 0; t < 256; t++) {
weightBack += histogram[t];
if (weightBack === 0) continue;
const weightFore = totalPixels - weightBack;
if (weightFore === 0) break;
sumBack += t * histogram[t];
const meanBack = sumBack / weightBack;
const meanFore = (sumAll - sumBack) / weightFore;
const varianceBetween = weightBack * weightFore * Math.pow(meanBack - meanFore, 2);
if (varianceBetween > maximumVariance) {
maximumVariance = varianceBetween;
optimalThreshold = t;
}
}
return optimalThreshold;
}Phát hiện góc nghiêng thông qua phép biến đổi Radon và Hough
Khi tài liệu giấy được quét theo một góc lệch, các đường cơ sở văn bản sẽ bị nghiêng, gây phức tạp cho quá trình phân đoạn dòng ngang. Sử dụng phép biến đổi Hough hoặc các phép chiếu Radon rời rạc, bộ tiền xử lý sẽ đánh giá các phép chiếu đường thẳng qua các góc từ đến với các khoảng cách .
Góc chiếu tạo ra phương sai cường độ cao nhất dọc theo biên dạng chiếu của nó sẽ tương ứng với góc đường cơ sở của văn bản. Sau khi được tính toán, canvas sẽ được xoay một góc bằng phương pháp nội suy song tuyến (bilinear interpolation) để tạo ra các dòng văn bản nằm ngang chuẩn xác.
2. Thực thi mạng nơ-ron trong WebAssembly: Tesseract so với các kiến trúc hiện đại
Khi hình ảnh đã được làm sạch, cắt gọn và nhị phân hóa, buffer pixel sẽ được chuyển đến quy trình suy luận nơ-ron WebAssembly.
+-----------------------------------------------------------------------+
| Tesseract WASM Inference Pipeline |
+-----------------------------------------------------------------------+
| Binarized Image Buffer (Web Worker) |
| | |
| v |
| [ Line Finding & Baseline Fitting Engine ] |
| | |
| v |
| [ Text Line Normalization: 32px Vertical Image Slices ] |
| | |
| v |
| [ Bidirectional LSTM Network (WASM + SIMD128) ] |
| - Input: Sequence of vertical pixel column feature vectors |
| - Forward LSTM Pass + Backward LSTM Pass |
| - Softmax Output Matrix: Probability distribution over character set|
| | |
| v |
| [ CTC (Connectionist Temporal Classification) Decoder ] |
| - Collapse repeated character predictions |
| - Strip blank non-emission tokens |
| | |
| v |
| Recognized Character Sequence + Confidence Probabilities |
+-----------------------------------------------------------------------+Kiến trúc mô hình LSTM của Tesseract
Tesseract hiện đại (v4 và v5) đã thay thế các bộ phân loại ký tự tô pô kế thừa bằng một mạng nơ-ron hồi quy sâu sử dụng các ô Long Short-Term Memory (LSTM).
Quy trình nhận dạng văn bản hoạt động qua các giai đoạn riêng biệt:
- Chuẩn hóa dòng (Line Normalization): Các dòng văn bản đã phân đoạn được chia tỷ lệ về chiều cao cố định 32 hoặc 48 pixel trong khi vẫn giữ nguyên tỷ lệ khung hình tự nhiên.
- Trích xuất đặc trưng (Feature Extraction): Lát cắt hình ảnh đã chuẩn hóa được quét từ trái sang phải dưới dạng một chuỗi có thứ tự gồm các cửa sổ đặc trưng cột dọc hẹp.
- Lan truyền LSTM hai chiều (Bidirectional LSTM Propagation): Hai lớp hồi quy (một lớp quét từ trái sang phải, một lớp quét từ phải sang trái) duy trì các trạng thái ô nội bộ để nắm bắt ngữ cảnh chuỗi ký tự, nâng cao độ chính xác cho các hình dạng chữ cái mơ hồ.
- Giải mã CTC (CTC Decoding): Vì độ rộng của các ký tự thay đổi đáng kể (ví dụ, chữ "m" trải dài qua nhiều cột pixel hơn chữ "l"), mạng sẽ xuất ra một chuỗi các vector xác suất theo các lát cắt thời gian bằng cách sử dụng Connectionist Temporal Classification (CTC). Bộ giải mã sẽ gộp các kết quả phát lặp lại và loại bỏ các token rỗng để tạo ra chuỗi ký tự cuối cùng.
Tăng tốc phần cứng qua WebAssembly SIMD
Việc tính toán hàng nghìn phép nhân ma trận - vector cho mỗi ký tự bằng JavaScript thuần túy sẽ gây ra độ trễ xử lý đáng kể. Các trình duyệt hiện đại đã hỗ trợ WebAssembly 128-bit SIMD (Single Instruction, Multiple Data).
Việc biên dịch Tesseract với cờ -msimd128 chỉ định cho Clang vector hóa các vòng lặp bên trong trên các thanh ghi 128-bit (chẳng hạn như v128), thực thi bốn phép nhân dấu phẩy động 32-bit hoặc mười sáu tích vô hướng số nguyên 8-bit chỉ trong một chu kỳ CPU duy nhất:
// Vectorized SIMD dot-product loop in WebAssembly C++ core
v128_t acc = wasm_f32x4_splat(0.0f);
for (int i = 0; i < vectorLength; i += 4) {
v128_t w = wasm_v128_load(&weights[i]);
v128_t in = wasm_v128_load(&inputs[i]);
acc = wasm_f32x4_add(acc, wasm_f32x4_mul(w, in));
}Kỹ thuật vector hóa SIMD giúp giảm tổng thời gian suy luận nơ-ron từ 60% đến 75% so với các bản dựng WebAssembly cơ bản, cho phép chuyển đổi văn bản trên trang gần như tức thì.
Bộ nhớ đệm trọng số nơ-ron qua IndexedDB
Các mô hình ngôn ngữ được huấn luyện sẵn cho OCR (eng.traineddata, deu.traineddata) có kích thước dao động từ 4 MB đến 25 MB. Việc tải lại các tệp nhị phân mô hình này trong mỗi lần truy cập trang sẽ tạo ra chi phí mạng không cần thiết.
Hệ thống xử lý trên trình duyệt sử dụng một tầng bộ nhớ đệm IndexedDB để lưu trữ các buffer mô hình đã biên dịch cục bộ. Trong các lần chạy tiếp theo, trọng số mô hình được tải trực tiếp từ bộ lưu trữ liên tục của trình duyệt chỉ trong vài mili giây.
3. Phân tích bố cục tài liệu và phân đoạn hình học
Một chuỗi văn bản phi cấu trúc bị tước bỏ ngữ cảnh không gian sẽ cung cấp rất ít tiện ích cho việc xử lý hạ nguồn. Kỹ thuật tài liệu hiện đại đòi hỏi phải phân tích bố cục vật lý để xác định phân cấp tài liệu, thứ tự đọc và ranh giới bảng biểu.
+-----------------------------------------------------------------------+
| Hierarchical Physical Document Segmentation |
+-----------------------------------------------------------------------+
| Input Binarized Page (1-Bit Bitmap) |
| | |
| v |
| [ Connected Component Analysis (CCA): 8-Way Pixel Neighborhoods ] |
| | |
| v |
| [ Bounding Box Generation for Discrete Ink Blobs ] |
| | |
| v |
| [ Anisotropic Morphological Dilation: Rectangular Structuring Element]|
| - Horizontal Kernel: Bridges inter-character gaps into words |
| - Extended Horizontal: Bridges word gaps into complete text lines |
| - Vertical Kernel: Detects column breaks and paragraph gutters |
| | |
| v |
| [ Geometric Classification ] |
| - Aspect Ratio & Density -> Paragraphs, Tabular Grids, Images |
+-----------------------------------------------------------------------+Phân tích thành phần liên thông (CCA)
Phân đoạn vật lý bắt đầu bằng việc xác định các thành phần liên thông (các vùng pixel đen liền kề nhau). Sử dụng tính liên thông 8 hướng, thuật toán sẽ quét qua bitmap nhị phân và gắn nhãn cho từng ký tự rời rạc:
// Two-pass connected component labeling with disjoint-set union
export interface BoundingBox {
x0: number;
y0: number;
x1: number;
y1: number;
}
export function extractConnectedComponents(binary: Uint8Array, width: number, height: number): BoundingBox[] {
// Label matrix tracking component membership
const labels = new Int32Array(width * height);
const parent = [0];
let currentLabel = 1;
function find(i: number): number {
let root = i;
while (root !== parent[root]) root = parent[root];
let curr = i;
while (curr !== root) {
const next = parent[curr];
parent[curr] = root;
curr = next;
}
return root;
}
function union(i: number, j: number): void {
const rootI = find(i);
const rootJ = find(j);
if (rootI !== rootJ) parent[rootI] = rootJ;
}
// First pass: Assign initial labels and record equivalences
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const idx = y * width + x;
if (binary[idx] === 0) continue; // Background pixel
const left = x > 0 ? labels[idx - 1] : 0;
const top = y > 0 ? labels[idx - width] : 0;
if (left === 0 && top === 0) {
labels[idx] = currentLabel;
parent[currentLabel] = currentLabel;
currentLabel++;
} else if (left !== 0 && top === 0) {
labels[idx] = left;
} else if (left === 0 && top !== 0) {
labels[idx] = top;
} else {
labels[idx] = left;
if (left !== top) union(left, top);
}
}
}
// Second pass: Consolidate equivalent labels into bounding boxes
const boxes = new Map<number, BoundingBox>();
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const idx = y * width + x;
const rawLabel = labels[idx];
if (rawLabel === 0) continue;
const rootLabel = find(rawLabel);
let box = boxes.get(rootLabel);
if (!box) {
box = { x0: x, y0: y, x1: x, y1: y };
boxes.set(rootLabel, box);
} else {
if (x < box.x0) box.x0 = x;
if (y < box.y0) box.y0 = y;
if (x > box.x1) box.x1 = x;
if (y > box.y1) box.y1 = y;
}
}
}
return Array.from(boxes.values());
}Giãn nở hình thái học và gom cụm khối văn bản
Khi các bounding box của từng ký tự riêng lẻ đã được thiết lập, công cụ sẽ gom cụm chúng thành các khối đọc bằng toán thái học (mathematical morphology). Bằng cách áp dụng một phần tử cấu trúc chữ nhật dị hướng (kéo dài theo chiều ngang rộng hơn chiều dọc), các khung bao ký tự sẽ được làm giãn nở thành các dải dòng liền mạch.
Việc phân tích các biên dạng chiếu khoảng trắng (cắt lát hình chiếu ngang và dọc) sẽ cô lập được bố cục văn bản nhiều cột, các ô trong bảng và các phần tử tiêu đề tách biệt.
4. Xây dựng Cây cú pháp trừu tượng tài liệu phân cấp (hAST)
Để kết quả OCR có thể thao tác và lập trình được, hệ thống sẽ chuyển đổi đầu ra nhận dạng phẳng thành Cây cú pháp trừu tượng tài liệu phân cấp (hAST).
+-----------------------------------------------------------------------+
| Document hAST Object Hierarchy |
+-----------------------------------------------------------------------+
| DocumentNode (Root) |
| | |
| +-- PageNode [pageNumber: 1, width: 2480, height: 3508] |
| | |
| +-- BlockNode [type: 'paragraph', bbox: { x0, y0, x1, y1 }] |
| | |
| +-- LineNode [baseline: { y0, y1 }, bbox: { ... }] |
| | |
| +-- WordNode [text: "PetexSpace", confidence: 0.985] |
| | |
| +-- SymbolNode [char: 'P', bbox: { ... }] |
| +-- SymbolNode [char: 'e', bbox: { ... }] |
| +-- SymbolNode [char: 't', bbox: { ... }] |
| ... |
+-----------------------------------------------------------------------+Định nghĩa Schema cho hAST
Mỗi nút trong cây đều theo dõi phân loại ngữ nghĩa, tọa độ bounding box được chuẩn hóa theo kích thước hình ảnh gốc và điểm tin cậy nhận dạng:
// TypeScript schema for hierarchical OCR Abstract Syntax Tree
export interface DocumentNode {
type: 'document';
version: '1.0';
pages: PageNode[];
}
export interface PageNode {
type: 'page';
pageNumber: number;
width: number;
height: number;
blocks: BlockNode[];
}
export interface BlockNode {
type: 'paragraph' | 'heading' | 'table' | 'figure';
bbox: BoundingBox;
confidence: number;
lines: LineNode[];
}
export interface LineNode {
type: 'line';
bbox: BoundingBox;
baseline: { slope: number; intercept: number };
words: WordNode[];
}
export interface WordNode {
type: 'word';
text: string;
confidence: number;
bbox: BoundingBox;
symbols: SymbolNode[];
}
export interface SymbolNode {
type: 'symbol';
char: string;
confidence: number;
bbox: BoundingBox;
}Chuẩn hóa Unicode và tách chữ ghép
Dự đoán nơ-ron thô thường chứa các chữ ghép in ấn (chẳng hạn như "fi", "fl", "ffi" hoặc các nguyên âm đôi) hoặc các chuỗi dấu thanh bị phân rã.
Trình tạo AST áp dụng Unicode Normalization Form C (NFC) thông qua String.prototype.normalize('NFC') để đảm bảo khả năng tìm kiếm nhất quán. Nó cũng xử lý các ngắt dòng có dấu gạch nối ở cuối dòng bằng cách kiểm tra xem ký tự cuối cùng có phải là dấu gạch nối hay không và từ tiếp theo có tạo thành một mục từ điển hợp lệ hay không.
5. Công cụ OCR của PetexSpace: Lớp phủ Canvas tương tác và quyền riêng tư
Công cụ trích xuất văn bản bằng OCR trong trình duyệt của PetexSpace minh chứng cho cách WebAssembly, toán học thị giác máy tính và việc tạo AST phân cấp kết hợp với nhau để mang lại khả năng nhận dạng văn bản bảo vệ quyền riêng tư. Bạn cũng có thể tiền xử lý tài liệu hình ảnh cục bộ để tối ưu hóa bản quét trước khi nhận dạng.
+-----------------------------------------------------------------------+
| PetexSpace OCR Interactive Architecture |
+-----------------------------------------------------------------------+
| User Image Drag-and-Drop |
| | |
| v |
| [ Dedicated Dedicated Worker: In-Browser Preprocessing & WASM ] |
| | |
| +--> Emit hAST Payload + Normalized Coordinates |
| |
| Main UI Viewport: Multi-Layer Canvas Stacking |
| +-----------------------------------------------------------------+ |
| | Layer 3: Invisible, Selectable Transparent Text DOM Spans | |
| | Layer 2: Canvas Bounding Box Highlight Overlay (Active Cursor) | |
| | Layer 1: Hardware-Accelerated High-DPI Source Image Render | |
| +-----------------------------------------------------------------+ |
+-----------------------------------------------------------------------+Lớp chọn văn bản vô hình
Một hạn chế phổ biến của các công cụ OCR dựa trên trình duyệt là chỉ cung cấp một vùng textarea tách biệt chứa văn bản thô được trích xuất. PetexSpace giải quyết vấn đề này bằng cách kết xuất một giao diện đa lớp tương tác trực tiếp phía trên bản xem trước tài liệu:
- Lớp cơ sở (Base Layer): Kết xuất ảnh chụp tài liệu gốc trên HTML5 canvas DPI cao.
- Lớp phủ (Overlay Layer): Vẽ các bounding box động xung quanh các từ khi người dùng di chuột qua tài liệu.
- Lớp chọn (Selection Layer): Định vị các phần tử HTML
<span>trong suốt nằm ngay phía trên các từ tương ứng trên canvas bằng các phép biến đổi CSS:
// Mounting transparent DOM spans mapped to hAST coordinates
export function mountSelectableTextLayer(container: HTMLElement, page: PageNode, scale: number): void {
container.innerHTML = '';
container.style.position = 'relative';
for (const block of page.blocks) {
for (const line of block.lines) {
for (const word of line.words) {
const span = document.createElement('span');
span.textContent = word.text;
span.className = 'ocr-selectable-word';
// Exact pixel positioning matching canvas scale
span.style.position = 'absolute';
span.style.left = `${word.bbox.x0 * scale}px`;
span.style.top = `${word.bbox.y0 * scale}px`;
span.style.width = `${(word.bbox.x1 - word.bbox.x0) * scale}px`;
span.style.height = `${(word.bbox.y1 - word.bbox.y0) * scale}px`;
// Render completely invisible while preserving browser text selection
span.style.color = 'transparent';
span.style.fontSize = `${(word.bbox.y1 - word.bbox.y0) * scale * 0.85}px`;
span.style.userSelect = 'text';
container.appendChild(span);
}
}
}
}Kiến trúc này cho phép người dùng nhấp, bôi đen, sao chép và tìm kiếm văn bản trực tiếp trong ngữ cảnh tài liệu trực quan ban đầu.
Quyền riêng tư dữ liệu tuyệt đối thông qua thực thi cục bộ
Các tài liệu quét thường chứa dữ liệu cá nhân nhạy cảm: hộ chiếu, thẻ căn cước công dân, hồ sơ thuế cá nhân, bệnh án y tế và các thỏa thuận pháp lý. Việc gửi các hình ảnh này đến các API đám mây từ xa tiềm ẩn các rủi ro về lưu giữ dữ liệu, vi phạm bảo mật và không tuân thủ quy định.
PetexSpace thực thi việc cô lập dữ liệu toàn diện. Mọi bộ lọc tiền xử lý, lượt suy luận nơ-ron và bước tạo AST đều chạy hoàn toàn bên trong bộ nhớ trình duyệt cục bộ. Không có buffer pixel, gói tin mạng hay token tài liệu nào bị truyền ra ngoài qua mạng.
Bằng cách thực thi OCR hoàn toàn bên trong runtime trình duyệt, các hồ sơ nhạy cảm luôn được giữ kín đáo và an toàn ngay trên thiết bị của người dùng.