Asosiy qismga o'tish

Preprocessing — OpenCV bilan Rasmni Tayyorlash

3-bob 5 kod bloki 867 so'z

Sifatning yarmi shu yerda

OCR loyihalarida eng ko'p uchraydigan xato: "model yomon ishlayapti" deb model almashtirish, vaholanki muammo rasmda. Qoida oddiy:

matn1 qator
Yomon rasm + zo'r model   <   Yaxshi rasm + oddiy model

OpenCV kursida o'rgangan usullaringiz (threshold, blur, morfologiya) aynan shu yerda ishga tushadi. OCR — OpenCV bilimlaringizning eng amaliy qo'llanish joylaridan biri.

Asosiy uchlik: kulrang, shovqin, threshold

Deyarli har doim kerak bo'ladigan uch qadam:

python17 qator
import cv2
import numpy as np

def preprocess_basic(image_path):
    img = cv2.imread(image_path)

    # 1. Kulrang — OCR ga rang kerak emas, faqat xalaqit beradi
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # 2. Shovqinni olib tashlash — skaner donachalari, JPEG artefaktlari
    denoised = cv2.fastNlMeansDenoising(gray, h=10)

    # 3. Otsu threshold — matnni (qora) fondan (oq) keskin ajratish
    #    Otsu chegarani o'zi topadi, qo'lda tanlash shart emas
    _, binary = cv2.threshold(denoised, 0, 255,
                              cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    return binary

Nega threshold muhim: OCR modellari "qora matn, oq fon" da o'qitilgan. Sarg'aygan qog'oz, soya, notekis yoritish — hammasi aniqlikni tushiradi. Threshold rasmni ideal "kitob sahifasi" ko'rinishiga keltiradi.

Notekis yoritish: adaptive threshold

Telefon kamerasida olingan hujjatda tez-tez bir tomoni yorug', bir tomoni soyada bo'ladi. Otsu bitta chegara tanlaydi — soyali qismda matn "yo'qolib" qoladi. Yechim — har kichik hudud uchun alohida chegara:

python7 qator
binary = cv2.adaptiveThreshold(
    gray, 255,
    cv2.ADAPTIVE_THRESH_GAUSSIAN_C,   # chegara = hudud o'rtachasi (gauss og'irlikli)
    cv2.THRESH_BINARY,
    blockSize=31,                     # hudud kattaligi (toq son)
    C=15,                             # o'rtachadan ayiriladigan siljish
)

Qoida: skaner rasmi → Otsu, telefon surati → adaptive.

Qiyshiqlikni to'g'rilash (deskew)

Skanerga qiyshiq qo'yilgan hujjat — 2-3 daraja qiyshiqlik ham aniqlikni sezilarli tushiradi, chunki CTC "qatorlar gorizontal" deb kutadi:

python20 qator
def deskew(binary):
    # Matn (qora) piksellarining koordinatalari — (x, y) tartibida
    coords = cv2.findNonZero(255 - binary)

    # Ularni o'rab turgan eng kichik burchakli to'rtburchak
    angle = cv2.minAreaRect(coords)[-1]

    # OpenCV 4.5+ burchakni [0, 90) da beradi, eski versiyalar [-90, 0) da.
    # Ikkalasini ham (-45, 45] oralig'iga keltiramiz — qiyshiqlik shu yerda
    if angle > 45:
        angle -= 90
    elif angle < -45:
        angle += 90

    # Shu burchakka buramiz (musbat = soat miliga teskari)
    (h, w) = binary.shape
    M = cv2.getRotationMatrix2D((w // 2, h // 2), angle, 1.0)
    return cv2.warpAffine(binary, M, (w, h),
                          flags=cv2.INTER_CUBIC,
                          borderMode=cv2.BORDER_REPLICATE)

Bu OpenCV 4-qismida ko'rgan minAreaRect va warpAffine ning aynan o'zi — kontur topish o'rniga matn piksellariga qo'llayapmiz.

Ikki nozik joy: np.where (satr, ustun) beradi, minAreaRect esa (x, y) kutadi — shuning uchun findNonZero. Va minAreaRect burchak konvensiyasi OpenCV 4.5 da o'zgargan: eski kod (if angle < -45) yangi versiyada sahifani teskari tomonga burab, qiyshiqlikni ikki baravar qiladi. Tekshirish oson: 3° qiyshaytirilgan sinov rasmida funksiyadan keyin qatorlar gorizontal bo'lishi kerak.

O'lcham va DPI

OCR modellari belgilar balandligi 20-40 piksel bo'lganda eng yaxshi ishlaydi:

  • Skanerlash: kamida 300 DPI. 150 DPI arxiv skanlari — past aniqlik sababi #1
  • Kichik shrift: rasmni kattalashtiring — cv2.resize(img, None, fx=2, fy=2, interpolation=cv2.INTER_CUBIC)
  • Juda katta rasm ham yomon: 600+ DPI da shovqin ham "kattalashadi", tezlik tushadi

Muammo → Yechim jadvali

Muammo Belgisi Yechim
Past aniqlik Harflar g'ira-shira 300 DPI da qayta skanerlash yoki 2x resize
Qiyshiq sahifa Qatorlar og'gan minAreaRect deskew
Dog' va donachalar Tuz-qalampir shovqin fastNlMeansDenoising yoki medianBlur(3)
Notekis yoritish Bir tomon soyada Adaptive threshold
Sarg'aygan qog'oz Fon kulrang-sariq Otsu threshold
Orqa tomon ko'rinishi Xira "teskari" matn Threshold + morphologyEx(MORPH_OPEN)

To'liq preprocessing funksiyasi

Hammasini birlashtiramiz — bu funksiya 10-bobdagi production modulda ishlatiladi:

python20 qator
def preprocess_for_ocr(image_path, scanned=True):
    img = cv2.imread(image_path)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # Kichik rasmni kattalashtirish (belgi balandligi ~30px bo'lsin)
    if gray.shape[0] < 1000:
        gray = cv2.resize(gray, None, fx=2, fy=2,
                          interpolation=cv2.INTER_CUBIC)

    denoised = cv2.fastNlMeansDenoising(gray, h=10)

    if scanned:   # skaner: bir tekis yoritilgan
        _, binary = cv2.threshold(denoised, 0, 255,
                                  cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    else:         # telefon surati: notekis yorug'lik
        binary = cv2.adaptiveThreshold(denoised, 255,
                                       cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
                                       cv2.THRESH_BINARY, 31, 15)

    return deskew(binary)

Xulosa

Tushuncha Asosiy fikr
Qoida Sifatning ~50% i preprocessing da — avval rasmni tuzating, keyin model almashtiring
Uchlik Kulrang → denoise → threshold: deyarli har doim kerak
Otsu vs Adaptive Skaner → Otsu; telefon surati → adaptive
Deskew 2-3° qiyshiqlik ham zarar — minAreaRect bilan to'g'rilang
DPI 300 DPI standart; belgi balandligi 20-40px bo'lsin

Bu bobni bepul o'qidingiz.

Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.

Telegramda yozish Narxlar