Tutorial Doctr: Library OCR Deep Learning untuk Pemahaman Dokumen
Doctr (Document Text Recognition) adalah library open-source yang dikembangkan oleh Mindee untuk melakukan Optical Character Recognition (OCR) menggunakan model deep learning. Berbeda dengan library OCR tradisional seperti Tesseract yang mengandalkan pendekatan klasik, Doctr dibangun sepenuhnya di atas arsitektur neural network modern sehingga menghasilkan akurasi yang jauh lebih tinggi, terutama pada dokumen dengan layout kompleks.
Library ini mendukung dua backend deep learning utama: PyTorch dan TensorFlow, memberikan fleksibilitas bagi developer untuk memilih framework yang paling sesuai dengan ekosistem mereka. Doctr dirancang khusus untuk memproses dokumen bisnis seperti invoice, receipt, formulir, kontrak, dan berbagai jenis dokumen terstruktur lainnya.
Dalam tutorial ini, kita akan mempelajari cara menggunakan Doctr mulai dari instalasi, penggunaan dasar untuk ekstraksi teks, hingga teknik lanjutan seperti fine-tuning model dan integrasi ke dalam pipeline produksi.
Mengapa Memilih Doctr?
Sebelum masuk ke implementasi, penting untuk memahami keunggulan Doctr dibandingkan solusi OCR lainnya:
Arsitektur Two-Stage Pipeline: Doctr menggunakan pendekatan dua tahap yang terdiri dari text detection (menemukan lokasi teks dalam gambar) dan text recognition (membaca karakter dari area yang terdeteksi). Setiap tahap menggunakan model deep learning yang dioptimalkan secara independen. Pre-trained Models: Library ini menyediakan berbagai model pre-trained yang sudah dilatih pada dataset dokumen skala besar, sehingga bisa langsung digunakan tanpa training tambahan untuk sebagian besar kasus penggunaan. Output Terstruktur: Hasil OCR dari Doctr dikembalikan dalam format hierarkis yang terstruktur (Document > Page > Block > Line > Word), memudahkan untuk melakukan analisis layout dan ekstraksi informasi terstruktur. Dukungan Multi-Format: Doctr dapat memproses berbagai format input termasuk gambar (PNG, JPG, TIFF) dan dokumen PDF secara native.Instalasi
Instalasi Dasar dengan PyTorch Backend
pip install "python-doctr[torch]"
Instalasi Dasar dengan TensorFlow Backend
pip install "python-doctr[tf]"
Instalasi Lengkap (Semua Fitur)
pip install "python-doctr[torch,viz,html]"
Opsi tambahan:
viz: Untuk visualisasi hasil deteksi dan rekognisihtml: Untuk export hasil ke format HTMLcontrib: Untuk akses ke model-model kontribusi komunitas
Verifikasi Instalasi
import doctr
print(f"Doctr version: {doctr.version}")
from doctr.models import ocrpredictor
model = ocrpredictor(pretrained=True)
print("Model loaded successfully!")
Dependensi Sistem
Untuk memproses file PDF, Doctr membutuhkan library sistem tambahan:
# Ubuntu/Debian
sudo apt-get install poppler-utils
macOS
brew install poppler
Windows (via conda)
conda install -c conda-forge poppler
Penggunaan Dasar
Membaca Dokumen dari File
Langkah pertama adalah memuat dokumen yang ingin diproses. Doctr mendukung gambar dan PDF.
from doctr.io import DocumentFile
Memuat file PDF
pdfdoc = DocumentFile.frompdf("dokumencontoh.pdf")
print(f"Jumlah halaman: {len(pdfdoc)}")
Memuat file gambar
imgdoc = DocumentFile.fromimages("invoice.png")
print(f"Jumlah gambar: {len(imgdoc)}")
Memuat beberapa gambar sekaligus
multidoc = DocumentFile.fromimages([
"halaman1.png",
"halaman2.png",
"halaman3.jpg"
])
print(f"Total gambar: {len(multidoc)}")
Menjalankan OCR Predictor
OCR predictor adalah komponen utama yang menggabungkan text detection dan text recognition.
from doctr.models import ocrpredictor
Inisialisasi model dengan pre-trained weights
model = ocrpredictor(pretrained=True)
Jalankan OCR pada dokumen
result = model(pdfdoc)
Tampilkan hasil dalam format JSON
import json
output = result.export()
print(json.dumps(output, indent=2, ensureascii=False))
Mengekstrak Teks dari Hasil OCR
Hasil OCR dikembalikan dalam struktur hierarkis. Berikut cara mengakses teks pada setiap level:
from doctr.models import ocrpredictor
from doctr.io import DocumentFile
model = ocrpredictor(pretrained=True)
doc = DocumentFile.frompdf("invoice.pdf")
result = model(doc)
Ekstrak semua teks dari dokumen
fulltext = result.render()
print("=== Teks Lengkap ===")
print(fulltext)
Akses per halaman
for pageidx, page in enumerate(result.pages):
print(f"\n--- Halaman {pageidx + 1} ---")
for block in page.blocks:
for line in block.lines:
linetext = " ".join([word.value for word in line.words])
print(f" Line: {linetext}")
Akses per kata dengan confidence score
for page in result.pages:
for block in page.blocks:
for line in block.lines:
for word in line.words:
print(f"Kata: '{word.value}' | "
f"Confidence: {word.confidence:.4f} | "
f"Bounding Box: {word.geometry}")
Memahami Bounding Box
Setiap elemen yang terdeteksi memiliki informasi geometri berupa bounding box. Koordinat dinormalisasi antara 0 dan 1 relatif terhadap ukuran halaman.
for page in result.pages:
pagedims = page.dimensions # (height, width) dalam pixel
print(f"Dimensi halaman: {pagedims}")
for block in page.blocks:
# Geometry format: ((xmin, ymin), (xmax, ymax))
bbox = block.geometry
xmin, ymin = bbox[0]
xmax, ymax = bbox[1]
# Konversi ke pixel
pxxmin = int(xmin pagedims[1])
pxymin = int(ymin pagedims[0])
pxxmax = int(xmax pagedims[1])
pxymax = int(ymax pagedims[0])
print(f"Block bbox (normalized): {bbox}")
print(f"Block bbox (pixels): ({pxxmin}, {pxymin}) -> ({pxxmax}, {pxymax})")
Konfigurasi Model
Memilih Arsitektur Detection dan Recognition
Doctr menyediakan beberapa pilihan arsitektur model untuk detection dan recognition. Anda bisa memilih sesuai kebutuhan antara akurasi dan kecepatan.
from doctr.models import ocrpredictor
Model default (keseimbangan akurasi dan kecepatan)
model
default = ocrpredictor(pretrained=True)
Model dengan arsitektur spesifik
model
custom = ocrpredictor(
det
arch='dbresnet50', # Detection: DBNet dengan ResNet50
reco
arch='crnnvgg16bn', # Recognition: CRNN dengan VGG16
pretrained=True
)
Model ringan untuk kecepatan
modelfast = ocrpredictor(
detarch='dbmobilenetv3large',
recoarch='crnnmobilenetv3small',
pretrained=True
)
Arsitektur Detection yang Tersedia
| Arsitektur | Backbone | Kecepatan | Akurasi |
|-----------|----------|-----------|---------|
| dbresnet50 | ResNet-50 | Sedang | Tinggi |
| dbmobilenetv3large | MobileNetV3-L | Cepat | Sedang |
| linknetresnet18 | ResNet-18 | Cepat | Sedang |
| linknetresnet50 | ResNet-50 | Sedang | Tinggi |
Arsitektur Recognition yang Tersedia
| Arsitektur | Backbone | Kecepatan | Akurasi |
|-----------|----------|-----------|---------|
| crnnvgg16bn | VGG-16 BN | Sedang | Tinggi |
| crnnmobilenetv3small | MobileNetV3-S | Cepat | Sedang |
| crnnmobilenetv3large | MobileNetV3-L | Sedang | Tinggi |
| sarresnet31 | ResNet-31 | Lambat | Sangat Tinggi |
| master | - | Lambat | Sangat Tinggi |
| vitstrsmall | ViT-Small | Sedang | Tinggi |
Konfigurasi Parameter Tambahan
model = ocrpredictor(
pretrained=True,
assume
straightpages=True, # Asumsi halaman sudah lurus (lebih cepat)
straighten
pages=False, # Nonaktifkan koreksi orientasi
preserveaspectratio=True, # Pertahankan rasio aspek saat resize
symmetricpad=True, # Padding simetris
exportasstraightboxes=True, # Export bbox sebagai kotak lurus
)
Visualisasi Hasil
Visualisasi dengan Matplotlib
Doctr menyediakan utilitas bawaan untuk memvisualisasikan hasil deteksi.
from doctr.io import DocumentFile
from doctr.models import ocrpredictor
from doctr.utils.visualization import visualizepage
import matplotlib.pyplot as plt
model = ocrpredictor(pretrained=True)
doc = DocumentFile.fromimages("dokumen.png")
result = model(doc)
Visualisasi halaman pertama
pageresult = result.pages[0]
fig, ax = plt.subplots(1, 1, figsize=(12, 16))
visualizepage(pageresult.export(), doc[0], ax=ax, interactive=False)
plt.tightlayout()
plt.savefig("hasilocr.png", dpi=150)
plt.show()
Menggambar Bounding Box Manual
import cv2
import numpy as np
from doctr.io import DocumentFile
from doctr.models import ocrpredictor
model = ocrpredictor(pretrained=True)
doc = DocumentFile.fromimages("invoice.png")
result = model(doc)
Load gambar asli
image = cv2.imread("invoice.png")
h, w = image.shape[:2]
for page in result.pages:
for block in page.blocks:
for line in block.lines:
for word in line.words:
# Konversi koordinat normalisasi ke pixel
(x1, y1), (x2, y2) = word.geometry
pt1 = (int(x1 w), int(y1 h))
pt2 = (int(x2 w), int(y2 h))
# Gambar rectangle
cv2.rectangle(image, pt1, pt2, (0, 255, 0), 2)
# Tambahkan teks
cv2.putText(image, word.value,
(pt1[0], pt1[1] - 5),
cv2.FONTHERSHEYSIMPLEX, 0.4,
(0, 0, 255), 1)
cv2.imwrite("annotatedresult.png", image)
print("Hasil disimpan ke annotatedresult.png")
Export ke Format HTML
from doctr.io import DocumentFile
from doctr.models import ocrpredictor
from doctr.utils.reconstitution import synthesizepage
model = ocrpredictor(pretrained=True)
doc = DocumentFile.frompdf("dokumen.pdf")
result = model(doc)
Rekonstruksi halaman sebagai gambar sintetis
syntheticpages = result.synthesize()
for idx, pageimg in enumerate(syntheticpages):
import matplotlib.pyplot as plt
plt.imsave(f"syntheticpage{idx}.png", pageimg)
print(f"Halaman sintetis {idx} disimpan")
Penggunaan Lanjutan
Batch Processing untuk Banyak Dokumen
Ketika perlu memproses banyak dokumen sekaligus, gunakan pendekatan batch processing untuk efisiensi.
import os
import json
from doctr.io import DocumentFile
from doctr.models import ocrpredictor
model = ocrpredictor(pretrained=True)
def processdirectory(inputdir, outputdir):
os.makedirs(outputdir, existok=True)
supportedformats = ('.png', '.jpg', '.jpeg', '.tiff', '.pdf')
files = [f for f in os.listdir(inputdir)
if f.lower().endswith(supportedformats)]
results = {}
for filename in files:
filepath = os.path.join(inputdir, filename)
print(f"Memproses: {filename}")
if filename.lower().endswith('.pdf'):
doc = DocumentFile.frompdf(filepath)
else:
doc = DocumentFile.fromimages(filepath)
result = model(doc)
# Simpan teks lengkap
text = result.render()
textpath = os.path.join(outputdir, f"{filename}.txt")
with open(textpath, 'w', encoding='utf-8') as f:
f.write(text)
# Simpan hasil terstruktur
jsonpath = os.path.join(outputdir, f"{filename}.json")
with open(jsonpath, 'w', encoding='utf-8') as f:
json.dump(result.export(), f, indent=2, ensureascii=False)
results[filename] = {
'pages': len(result.pages),
'textlength': len(text),
'outputtext': textpath,
'outputjson': jsonpath
}
print(f" -> {len(result.pages)} halaman, {len(text)} karakter")
return results
Jalankan
summary = processdirectory("./documents", "./ocrresults")
print(f"\nTotal dokumen diproses: {len(summary)}")
Ekstraksi Informasi dari Invoice
Contoh praktis mengekstrak field-field penting dari invoice menggunakan Doctr dan post-processing sederhana.
import re
from doctr.io import DocumentFile
from doctr.models import ocrpredictor
model = ocrpredictor(pretrained=True)
def extractinvoicedata(pdfpath):
doc = DocumentFile.frompdf(pdfpath)
result = model(doc)
fulltext = result.render()
lines = fulltext.split('\n')
invoicedata = {
'invoicenumber': None,
'date': None,
'total': None,
'items': []
}
for line in lines:
line = line.strip()
# Cari nomor invoice
invmatch = re.search(r'(?:Invoice|INV|No)[.\s#:](\S+)', line, re.IGNORECASE)
if invmatch and not invoicedata['invoicenumber']:
invoicedata['invoicenumber'] = invmatch.group(1)
# Cari tanggal
datematch = re.search(
r'(\d{1,2}[/-]\d{1,2}[/-]\d{2,4}|\d{1,2}\s+\w+\s+\d{4})',
line
)
if datematch and not invoicedata['date']:
invoicedata['date'] = datematch.group(1)
# Cari total amount
totalmatch = re.search(
r'(?:Total|Grand Total|Amount Due)[:\s](?:Rp\.?|IDR|\$)?\s([\d.,]+)',
line, re.IGNORECASE
)
if totalmatch:
invoicedata['total'] = totalmatch.group(1)
# Ekstrak data terstruktur per halaman
for page in result.pages:
for block in page.blocks:
blocktext = ""
for line in block.lines:
linetext = " ".join([w.value for w in line.words])
blocktext += linetext + "\n"
if any(keyword in blocktext.lower()
for keyword in ['item', 'deskripsi', 'description', 'qty']):
invoicedata['items'].append(blocktext.strip())
return invoicedata
Penggunaan
data = extractinvoicedata("sampleinvoice.pdf")
print(f"Invoice Number: {data['invoicenumber']}")
print(f"Date: {data['date']}")
print(f"Total: {data['total']}")
print(f"Items found: {len(data['items'])}")
Menggunakan GPU untuk Percepatan
import torch
from doctr.models import ocrpredictor
Cek ketersediaan GPU
device = torch.device("cuda" if torch.cuda.isavailable() else "cpu")
print(f"Menggunakan device: {device}")
Model otomatis menggunakan GPU jika tersedia
model = ocrpredictor(pretrained=True).to(device)
Untuk TensorFlow backend
import tensorflow as tf
gpus = tf.config.listphysicaldevices('GPU')
print(f"GPU tersedia: {len(gpus)}")
Preprocessing Gambar untuk Hasil Lebih Baik
import cv2
import numpy as np
from doctr.io import DocumentFile
from doctr.models import ocrpredictor
def preprocessimage(imagepath):
img = cv2.imread(imagepath)
# Konversi ke grayscale
gray = cv2.cvtColor(img, cv2.COLORBGR2GRAY)
# Adaptive thresholding untuk menangani pencahayaan tidak merata
thresh = cv2.adaptiveThreshold(
gray, 255, cv2.ADAPTIVETHRESHGAUSSIANC,
cv2.THRESHBINARY, 11, 2
)
# Noise removal
kernel = np.ones((1, 1), np.uint8)
cleaned = cv2.morphologyEx(thresh, cv2.MORPHCLOSE, kernel)
# Deskew (koreksi kemiringan)
coords = np.columnstack(np.where(cleaned > 0))
angle = cv2.minAreaRect(coords)[-1]
if angle < -45:
angle = -(90 + angle)
else:
angle = -angle
(h, w) = cleaned.shape[:2]
center = (w // 2, h // 2)
M = cv2.getRotationMatrix2D(center, angle, 1.0)
rotated = cv2.warpAffine(
cleaned, M, (w, h),
flags=cv2.INTERCUBIC,
borderMode=cv2.BORDERREPLICATE
)
# Simpan hasil preprocessing
outputpath = "preprocessed" + imagepath.split("/")[-1]
cv2.imwrite(outputpath, rotated)
return outputpath
Gunakan gambar yang sudah dipreprocess
processedpath = preprocessimage("dokumenscan.png")
model = ocrpredictor(pretrained=True)
doc = DocumentFile.fromimages(processedpath)
result = model(doc)
print(result.render())
Integrasi dengan FastAPI
Membangun REST API untuk layanan OCR menggunakan FastAPI dan Doctr.
from fastapi import FastAPI, UploadFile, File
from fastapi.responses import JSONResponse
import tempfile
import os
from doctr.io import DocumentFile
from doctr.models import ocrpredictor
app = FastAPI(title="Doctr OCR API")
model = ocrpredictor(pretrained=True)
@app.post("/ocr/image")
async def ocrimage(file: UploadFile = File(...)):
with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as tmp:
content = await file.read()
tmp.write(content)
tmppath = tmp.name
try:
doc = DocumentFile.fromimages(tmppath)
result = model(doc)
output = {
"filename": file.filename,
"text": result.render(),
"pages": []
}
for pageidx, page in enumerate(result.pages):
pagedata = {
"pagenumber": pageidx + 1,
"dimensions": page.dimensions,
"words": []
}
for block in page.blocks:
for line in block.lines:
for word in line.words:
pagedata["words"].append({
"text": word.value,
"confidence": round(word.confidence, 4),
"bbox": word.geometry
})
output["pages"].append(pagedata)
return JSONResponse(content=output)
finally:
os.unlink(tmppath)
@app.post("/ocr/pdf")
async def ocrpdf(file: UploadFile = File(...)):
with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp:
content = await file.read()
tmp.write(content)
tmppath = tmp.name
try:
doc = DocumentFile.frompdf(tmppath)
result = model(doc)
return JSONResponse(content={
"filename": file.filename,
"text": result.render(),
"totalpages": len(result.pages),
"structured": result.export()
})
finally:
os.unlink(tmppath)
Jalankan server:
uvicorn ocrapi:app --host 0.0.0.0 --port 8000
Test endpoint:
curl -X POST "http://localhost:8000/ocr/image" \
-F "file=@invoice.png" | python -m json.tool
Fine-tuning Model Recognition
Jika model pre-trained tidak memberikan akurasi yang cukup untuk jenis dokumen tertentu, Anda bisa melakukan fine-tuning.
import torch
from doctr.datasets import CORD
from doctr.models import recognition
from doctr.transforms import Resize
from torch.utils.data import DataLoader
Siapkan dataset
traindataset = CORD(
train=True,
download=True,
recognitiontask=True,
imgtransforms=Resize((32, 128))
)
valdataset = CORD(
train=False,
download=True,
recognitiontask=True,
imgtransforms=Resize((32, 128))
)
trainloader = DataLoader(traindataset, batchsize=32, shuffle=True)
valloader = DataLoader(valdataset, batchsize=32, shuffle=False)
Inisialisasi model
model = recognition.crnnvgg16bn(pretrained=True)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)
Training loop
device = torch.device("cuda" if torch.cuda.isavailable() else "cpu")
model = model.to(device)
numepochs = 10
for epoch in range(numepochs):
model.train()
totalloss = 0
for batchidx, (images, targets) in enumerate(trainloader):
images = images.to(device)
output = model(images, targets)
loss = output["loss"]
optimizer.zerograd()
loss.backward()
optimizer.step()
totalloss += loss.item()
if batchidx % 50 == 0:
print(f"Epoch [{epoch+1}/{numepochs}], "
f"Batch [{batchidx}/{len(trainloader)}], "
f"Loss: {loss.item():.4f}")
avgloss = totalloss / len(trainloader)
print(f"Epoch [{epoch+1}/{numepochs}], Average Loss: {avgloss:.4f}")
Simpan model
torch.save(model.statedict(), "doctrfinetuned.pth")
print("Model disimpan!")
Menggunakan Model Custom
from doctr.models import ocrpredictor, recognition
Load model recognition yang sudah di-fine-tune
custom
reco = recognition.crnnvgg16bn(pretrained=False)
customreco.loadstatedict(torch.load("doctrfinetuned.pth"))
Gunakan dalam pipeline OCR
model = ocrpredictor(
detarch='dbresnet50',
recoarch=customreco,
pretrained=False
)
Best Practices
1. Optimasi Kualitas Input
Kualitas gambar input sangat mempengaruhi akurasi OCR. Berikut beberapa tips:
- Pastikan resolusi minimal 150 DPI, idealnya 300 DPI
- Hindari gambar yang terlalu gelap atau terlalu terang
- Koreksi kemiringan dokumen sebelum OCR
- Hapus noise dan artefak dari proses scanning
2. Pemilihan Model yang Tepat
- Untuk dokumen standar dengan teks horizontal, gunakan
assumestraightpages=Trueuntuk mempercepat inferensi - Untuk dokumen dengan orientasi beragam, gunakan
straightenpages=True - Untuk deployment di edge device, pilih arsitektur berbasis MobileNet
- Untuk akurasi maksimal, gunakan
sarresnet31ataumastersebagai recognition model
3. Manajemen Memori
import torch
from doctr.models import ocrpredictor
model = ocrpredictor(pretrained=True)
Gunakan torch.nograd() saat inferensi
with torch.nograd():
result = model(doc)
Bersihkan cache GPU setelah processing batch besar
if torch.cuda.isavailable():
torch.cuda.emptycache()
4. Post-processing Hasil OCR
Terapkan post-processing untuk meningkatkan kualitas output:
import re
def cleanocrtext(text):
# Gabungkan kata-kata yang terpisah oleh line break
text = re.sub(r'(\w)-\n(\w)', r'\1\2', text)
# Normalisasi spasi
text = re.sub(r'\s+', ' ', text)
# Perbaiki kesalahan umum OCR
corrections = {
'0': 'O', # Kontekstual: di awal kata
'l': '1', # Kontekstual: di antara angka
'rn': 'm', # Kesalahan umum
}
# Hapus karakter yang tidak valid
text = re.sub(r'[^\w\s.,;:!?@#$%&()\-+=\[\]{}\'"/\\]', '', text)
return text.strip()
Penggunaan
rawtext = result.render()
cleantext = cleanocrtext(rawtext)
print(cleantext)
5. Confidence Filtering
Filter kata-kata dengan confidence rendah untuk meningkatkan reliabilitas:
def filterlowconfidence(result, threshold=0.5):
filtered
words = []
lowconfidencewords = []
for page in result.pages:
for block in page.blocks:
for line in block.lines:
for word in line.words:
if word.confidence >= threshold:
filteredwords.append(word.value)
else:
lowconfidencewords.append(
(word.value, word.confidence)
)
print(f"Kata dengan confidence >= {threshold}: {len(filteredwords)}")
print(f"Kata dengan confidence < {threshold}: {len(lowconfidencewords)}")
if lowconfidencewords:
print("\nKata dengan confidence rendah:")
for word, conf in lowconfidencewords:
print(f" '{word}' -> {conf:.4f}")
return " ".join(filteredwords)
highqualitytext = filterlow_confidence(result, threshold=0.7)
Perbandingan dengan Library OCR Lain
| Fitur | Doctr | Tesseract | EasyOCR | PaddleOCR |
|-------|-------|-----------|---------|-----------|
| Backend | PyTorch/TF | C++ | PyTorch | PaddlePaddle |
| Deep Learning | Ya | Parsial | Ya | Ya |
| Output Terstruktur | Ya | Terbatas | Terbatas | Ya |
| Dukungan PDF | Native | Via wrapper | Tidak | Ya |
| Pre-trained Models | Banyak | Terbatas | Banyak | Banyak |
| Fine-tuning | Mudah | Sulit | Sedang | Sedang |
| Kecepatan GPU | Cepat | N/A | Sedang | Cepat |
| Bahasa Indonesia | Terbatas | Ya | Ya | Ya |
Kesimpulan
Doctr adalah pilihan yang sangat baik untuk proyek OCR yang membutuhkan akurasi tinggi pada dokumen bisnis. Dengan arsitektur two-stage pipeline yang modern, dukungan multi-backend (PyTorch dan TensorFlow), serta output terstruktur yang mudah diproses, Doctr menawarkan keseimbangan yang baik antara kemudahan penggunaan dan fleksibilitas.
Poin-poin penting yang perlu diingat:
- Gunakan model pre-trained untuk memulai dengan cepat
- Pilih arsitektur model sesuai kebutuhan: MobileNet untuk kecepatan, ResNet/ViT untuk akurasi
- Preprocessing gambar yang baik sangat mempengaruhi hasil akhir
- Manfaatkan output terstruktur (Document > Page > Block > Line > Word) untuk analisis layout
- Lakukan fine-tuning jika akurasi default tidak memadai untuk domain dokumen spesifik Anda
- Confidence score sangat berguna untuk filtering dan quality control
Dengan mengikuti panduan dan best practices dalam tutorial ini, Anda sudah memiliki fondasi yang kuat untuk membangun sistem OCR berbasis deep learning menggunakan Doctr, baik untuk eksperimen maupun deployment di lingkungan produksi.