Локален OCR на стари македонски печатени материјали со Google Vision AI

Ова упатство објаснува како да поставите систем за оптичко препознавање на знаци (OCR) кој користи Google Vision AI за читање на сложени, стари кирилични текстови. Резултатот е Searchable PDF (PDF со невидлив текстуален слој кој може да се пребарува преку Ctrl+F и да се копира), притоа зачувувајќи го оригиналниот изглед на скенираниот документ.

Зошто го направивме ова: Оваа локална скрипта е создадена како директен одговор на неможноста на стандардните комерцијални софтвери и бесплатни онлајн алатки прецизно да го прочитаат стариот македонски кириличен слог и да ја задржат сложената структура на весниците. Со поврзување на компјутерскиот вид на Google Vision во локална Python околина, го решивме проблемот со уништениот прелом на колоните и лошото препознавање. Резултатот е алатка која генерира перфектно пребарлив PDF (Searchable PDF) директно на вашиот компјутер, заобиколувајќи ги скапите лиценци и сложените cloud инфраструктури.

Важна напомена за Cloud Storage (Buckets): Стандардната процедура на Google за процесирање на цели PDF фајлови бара креирање на Google Cloud Storage Buckets и асинхроно праќање на податоците. За да го поедноставиме процесот за крајниот корисник, оваа скрипта е дизајнирана да ги заобиколи Buckets. Таа го чита PDF-от локално, страница по страница, и комуницира со Google само за препознавање на текстот. Целиот фајл останува и се креира на вашиот компјутер.

Фаза 1: подготовка на Google Cloud (Моторот)

За скриптата да може да го користи визуелниот алгоритам на Google, потребен ви е сервисен клуч (Service Account Key).

  1. Креирање проект:
    • Одете на Google Cloud Console.
    • Најавете се со вашата Google сметка.
    • Во горниот лев агол, кликнете на паѓачкото мени за проекти и одберете New Project.
    • Крстете го проектот (пр. Arno-OCR-Archive) и кликнете Create.
  2. Овозможување на Billing (Наплата), не грижете се – бесплатно е!:
    • За да се користат API услугите, Google бара да имате внесено платежна картичка (Billing Account).
    • Одете во делот Billing од главното мени и поврзете сметка.
    • Забелешка: Google Vision нуди 1000 бесплатни страници месечно. За лични и мали архивски проекти, нема да ви биде наплатено ништо, но картичката е задолжителна за верификација.
  3. Активирање на Vision API:
    • Во лентата за пребарување горе, напишете Cloud Vision API.
    • Кликнете на резултатот и притиснете го синото копче Enable.
  4. Вадење на сервисен клуч (JSON):
    • Од главното мени лево, одете во IAM & Admin > Service Accounts.
    • Кликнете Create Service Account (горе).
    • Ставете име (пр. ocr-bot) и кликнете Create and Continue, па Done.
    • Во листата ќе го видите новиот Service Account. Кликнете на трите точки од десната страна под Actions и одберете Manage keys.
    • Кликнете Add Key > Create new key.
    • Одберете формат JSON и кликнете Create.
    • Фајлот автоматски ќе се симне на вашиот компјутер. Прекрстете го во kluc.json.
Фаза 2: локална околина (Python)

За да ја извршите скриптата, потребен ви е инсталиран Python и три дополнителни библиотеки.

  1. Инсталација на Python:
    • Симнете ја најновата верзија од python.org и инсталирајте ја.
    • Клучно: При инсталацијата, задолжително штиклирајте ја опцијата Add Python to PATH (на првиот прозорец).
  2. Инсталација на библиотеките:
    • Отворете го терминалот на вашиот компјутер (На Windows: отворете Start, напишете cmd и притиснете Enter. На Mac: отворете Terminal).
    • Внесете ја следнава команда и притиснете Enter: pip install PyMuPDF google-cloud-vision tkinterdnd2
    • Почекајте да заврши инсталацијата.
Фаза 3: работен фолдер и скрипта
  1. Направете нов фолдер на вашиот компјутер каде што ќе работите (на пр. C:\OCR_Arhiva).
  2. Преместете го фајлот kluc.json во овој фолдер.
  3. Отворете Notepad (или било кој текстуален уредувач), залепете го кодот подолу и зачувајте го во истиот фолдер како Arno_OCR_App.py.

Кодот на скриптата (ocr_skripta.py)


import warnings
warnings.filterwarnings("ignore", category=FutureWarning)

import os
import fitz
from google.cloud import vision
import threading
import tkinter as tk
from tkinter import messagebox
from tkinterdnd2 import DND_FILES, TkinterDnD

os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "kluc.json"
font_path = r"C:\Windows\Fonts\arial.ttf"

def spasi_arhiva_logicka(vlezni_podatoci, izlezni_podatoci, status_label):
try:
status_label.config(text="[*] Се поврзувам со Google Vision...", fg="blue")
client = vision.ImageAnnotatorClient()
doc = fitz.open(vlezni_podatoci)

for page_num in range(len(doc)):
status_label.config(text=f"[*] Процесирам страница {page_num + 1} од {len(doc)}...")
page = doc[page_num]

try:
page.insert_font(fontname="cyrillic", fontfile=font_path)
except Exception:
pass

zoom = 300 / 72.0
mat = fitz.Matrix(zoom, zoom)
pix = page.get_pixmap(matrix=mat)
img_bytes = pix.tobytes("jpeg")

image = vision.Image(content=img_bytes)
response = client.document_text_detection(image=image)

if response.error.message:
status_label.config(text=f"[!] Грешка: {response.error.message}", fg="red")
continue

if response.full_text_annotation:
word_buffer = ""
delayed_text = ""
delayed_x0 = 0
delayed_y1 = 0
delayed_fontsize = 0

for page_info in response.full_text_annotation.pages:
for block in page_info.blocks:
for paragraph in block.paragraphs:
for word in paragraph.words:
current_word_text = ""
has_hyphen_break = False

for symbol in word.symbols:
current_word_text += symbol.text

if symbol.property and symbol.property.detected_break:
if symbol.property.detected_break.type_ == vision.TextAnnotation.DetectedBreak.BreakType.HYPHEN:
has_hyphen_break = True

if has_hyphen_break:
word_buffer += current_word_text.rstrip('-')
else:
final_word_text = word_buffer + current_word_text
word_buffer = ""

vertices = word.bounding_box.vertices
try:
# БЕЗБЕДНО ФОРМАТИРАЊЕ ЗА ДА НЕ СЕ ПРЕСЕЧЕ КОДОТ
x_coords = [v.x for v in vertices]
y_coords = [v.y for v in vertices]
x0 = min(x_coords) / zoom
y1 = max(y_coords) / zoom
font_size = max(4, y1 - min(y_coords) / zoom)

clean_word = final_word_text.strip()

if clean_word in [',', '.', '!', '?', ':', ';', '”', '’', ')', ']', '}']:
delayed_text += clean_word
else:
if delayed_text != "":
page.insert_text(fitz.Point(delayed_x0, delayed_y1), delayed_text, fontsize=delayed_fontsize, fontname="cyrillic", render_mode=3)

delayed_text = clean_word
delayed_x0 = x0
delayed_y1 = y1
delayed_fontsize = font_size
except Exception:
pass

if delayed_text != "":
try:
page.insert_text(fitz.Point(delayed_x0, delayed_y1), delayed_text, fontsize=delayed_fontsize, fontname="cyrillic", render_mode=3)
except Exception:
pass

doc.save(izlezni_podatoci)
status_label.config(text=f"[+] УСПЕШНО!\nЗачувано како:\n{os.path.basename(izlezni_podatoci)}", fg="green")

except Exception as e:
status_label.config(text=f"[!] СИСТЕМСКА ГРЕШКА:\n{str(e)}", fg="red")

def drop_event(event):
file_path = event.data
if file_path.startswith('{') and file_path.endswith('}'):
file_path = file_path[1:-1]

if not file_path.lower().endswith('.pdf'):
messagebox.showwarning("Грешка", "Ве молиме внесете само PDF фајлови!")
return

if not os.path.exists("kluc.json"):
messagebox.showerror("Нема клуч", "Фајлот 'kluc.json' не е пронајден во фолдерот!")
return

base_name, extension = os.path.splitext(file_path)
izlez_pdf = f"{base_name}-finished{extension}"

threading.Thread(target=spasi_arhiva_logicka, args=(file_path, izlez_pdf, lbl_status), daemon=True).start()

root = TkinterDnD.Tk()
root.title("Дигитален Археолог - OCR")
root.geometry("450x300")
root.configure(bg="#f0f0f0")

lbl_title = tk.Label(root, text="АРНО.МК OCR АЛАТКА", font=("Arial", 16, "bold"), bg="#f0f0f0")
lbl_title.pack(pady=20)

lbl_drop = tk.Label(root, text="Повлечи и пушти (Drag & Drop)\nстариот PDF тука",
font=("Arial", 12), bg="#e0e0e0", width=40, height=5, relief="solid", bd=2)
lbl_drop.pack(pady=10)

lbl_drop.drop_target_register(DND_FILES)
lbl_drop.dnd_bind('<<Drop>>', drop_event)

lbl_status = tk.Label(root, text="Спремно за работа.", font=("Arial", 10), bg="#f0f0f0")
lbl_status.pack(pady=15)

root.mainloop()

Фаза 4: Стартување на процесот
  1. Вашата папка сега треба да изгледа вака:
    📄 kluc.json
    📄 Arno_OCR_App.py
  2. Отворете го терминалот (Command Prompt).
  3. Навигирајте до вашиот фолдер користејќи ја командата cd (на пример, cd C:\OCR_Arhiva). Алтернативно, во Windows Explorer, одете во фолдерот, кликнете на лентата за адреси горе, избришете ја патеката, напишете cmd и притиснете Enter.
  4. Внесете ја следнава команда за да ја стартувате апликацијата:
    python Arno_OCR_App.py
  5. На екранот ќе се отвори графички прозорец.
  6. Едноставно фатете го PDF документот што сакате да го дигитализирате (од каде било на вашиот компјутер) и пуштете го (Drag & Drop) во сивата зона на прозорецот.
  7. Следете го статусот во живо. Откако процесот ќе заврши, во истиот фолдер каде што ви се наоѓа оригиналниот PDF фајл, ќе се појави нов фајл со наставка -finished.pdf.
  8. Отворете го новиот фајл. Навидум изгледа исто како стариот скениран документ, но обидете се да селектирате текст со глувчето или да пребарате збор преку Ctrl+F.

That’s all folks!

Напишете коментар

Вашата адреса за е-пошта нема да биде објавена. Задолжителните полиња се означени со *