Opencv ile test sorusu çıkarma

Herkese merhaba
python’da opencv ile bir pdf dosyasından test soruları çıkarmak istiyorum.
Şıkları alt alta olan sorularda sorunsuz çalılşırken yan yana olan şıklı sorularda aradaki boşluklardan
sorun yaşanıyor. Şıklar algılanmıyor.


Çalışan bir kod parçası şu şekildedir:

import cv2

class DrawRectangel:

    def DrawRects(self,image_path,iter):
        # Load image, grayscale, Gaussian blur, Otsu's threshold
        image = cv2.imread(image_path)
        cnts = self.findConturs(image,iter)
        image2 = image.copy()

        for c in cnts:
            x, y, w, h = cv2.boundingRect(c)
            if image2.shape[1] // 4 < w < image2.shape[1] // 2 :
                cv2.rectangle(image2, (x, y),(x + w , y + h), (0, 0, 255),1)

        cv2.imshow('Paragarflar',image2)
        cv2.waitKey(0)
        cv2.destroyAllWindows()


    def findConturs(self,image,iter):
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        blur = cv2.GaussianBlur(gray, (7, 7), 0)
        thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

        # Create rectangular structuring element and dilate
        kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
        dilate = cv2.dilate(thresh, kernel, iterations=iter)

        # Find contours and draw rectangle
        cnts = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
        cnts = cnts[0] if len(cnts) == 2 else cnts[1]

        return cnts

DrawRectangel().DrawRects("soru2.png",4)

Bu örnekte iterasyonu arttırınca isteneni veriyor ama yaptığım gui de tam bir sayfa boyutlarında iterasyon arttırmak işe yaramadı. Bana yan yana şıklı soruları da düzgün şekilde çıkaracak bir algoritma lazım. Bunun da kontur seçimini belirleyen şurasında olacağını biliyorum

for c in cnts:
            x, y, w, h = cv2.boundingRect(c)
            if image2.shape[1] // 4 < w < image2.shape[1] // 2 :
                cv2.rectangle(image2, (x, y),(x + w , y + h), (0, 0, 255),1)

ama bulamadım.

Vakit ayıracaklara şimdiden teşekürler.

pytesseract araştır hocam muhtemelen işini görür.

Araştırdım, kurdum. paragraf kısmını iyi çıkarırken şıklara gelince su koyverdi.
B) → 93 , A) → AL gibi yanlış algılamalar yapıyor. image_to_string yerine image_to_data gibi metodları
var ama onlar konusunda da açıklayıcı şeyler bulamadım.

Merhaba.

Tresh uyguladığımızdaki görüntü.

Aşağıda dilate ettiğimizdeki görüntü.

Image ile pargrafları yakaladığımızda gördüğümüz kod.

Buraya yukarıdaki sonuçları çıkaran kodu bırakayım:

import cv2
import numpy as np

image = cv2.imread('test.jpeg')

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (7,7), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# Create rectangular structuring element and dilate
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
dilate = cv2.dilate(thresh, kernel, iterations=3)

# Find contours and draw rectangle
cnts = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]

for c in cnts:
    x,y,w,h = cv2.boundingRect(c)
    
    if w>40 : # Except thin lines
        cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 2)
        print(y,h)
# Resize Image For My Screen Resoulation. Remove befor run.        
thresh = cv2.resize(thresh, (0, 0), fx = 0.7, fy = 0.7) 
dilate = cv2.resize(dilate, (0, 0), fx = 0.7, fy = 0.7)
image = cv2.resize(image, (0, 0), fx = 0.7, fy = 0.7)

cv2.imshow('thresh', thresh)
cv2.imshow('dilate', dilate)
cv2.imshow('image', image)
cv2.waitKey()

Siz neyi paragraf olarak buldurmak isterseniz o kadarını paragraf olarak bulabilir kod.

 if w>40 : # Except thin lines
        cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 2)
        print(y,h)

Bu kısımda belirli bir genişliğin altındaki paragrafları görmezden gel demi oluyoruz. Deneme yanılma ile 40 vererek soru numaralarını hariç tuttum. Tarayacağınız dokümanda bu değerler değişebilir. Kendinize göre ayarlamalısınız. Çok büyük bir rakam kullanır ve şıkların genişliğine denk gelirse şıkları çerçeveleyemeybilirsiniz. Buradaki değerle oynayarak uygun değerleri bulabilirsiniz.

Gelelim bunun şıklarla ilintilenmesine;

Şimdi kodun içinde bir satır değiştireceğim. Sonuçlara beraber bakalım.

Tresh Değeri:

Dilate Değeri:

Image Sonuç:

Dikkat ettiyseniz bir önceki dilate görüntüsü ile sonraki değişmiş durumda.

Bu değişiklik şıklar ile soruyu bir biri ile dikey daha yaklaştırıyor.

Yani;

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,20))

satırında sadece, MORPH_RECT, değerinden sonra (5,5) yerine (5,20) verdim böylece, Y yönünde bir birleşme sağladım.

Tabi bu değerler bendeki resim üzeriden siz kendi resimleriniz için bunları deneyerek görerek ayarlamalısınız.

Bu durumda kodumız:

import cv2
import numpy as np

image = cv2.imread('test.jpeg')

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (7,7), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# Create rectangular structuring element and dilate
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,20))
dilate = cv2.dilate(thresh, kernel, iterations=3)

# Find contours and draw rectangle
cnts = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]

for c in cnts:
    x,y,w,h = cv2.boundingRect(c)
    
    if w>40 : # Except thin lines
        cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 2)
        print(y,h)
# Resize Image For My Screen Resoulation. Remove befor run.        
thresh = cv2.resize(thresh, (0, 0), fx = 0.7, fy = 0.7) 
dilate = cv2.resize(dilate, (0, 0), fx = 0.7, fy = 0.7)
image = cv2.resize(image, (0, 0), fx = 0.7, fy = 0.7)

cv2.imshow('thresh', thresh)
cv2.imshow('dilate', dilate)
cv2.imshow('image', image)
cv2.waitKey()

Şekline gelir.

# Resize Image For My Screen Resoulation. Remove befor run.        
thresh = cv2.resize(thresh, (0, 0), fx = 0.7, fy = 0.7) 
dilate = cv2.resize(dilate, (0, 0), fx = 0.7, fy = 0.7)
image = cv2.resize(image, (0, 0), fx = 0.7, fy = 0.7)

satırları ile görüntüyü %70’e ölçekledim. Ekran alıntısı yaparken tamamı ekranda biraz küçülsün diye, bu kod satırlarını kendi kodunuzda kaldırabilirsiniz.

Gelelim sizin kodunuza.

Yukarıda anlattığım üzere minik bir oynama gerekiyor.

Burada yine deneme yanılma ile;

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 15))

(5,5) değerini (5,15) olarak değiştirdim.

Sizde yine kullanacağınız görüntüye gere bu değerler değişebilir. Çünkü soruların aralıkları şıkların mesafeleri sorudan soruya değişebilir. Bunları ilk verdiğim kod üzerinde görsel görerek düzenleyebilir. Yada deneme yanılma bulabilirsiniz.

Kodunuzun değiştirilmiş hali:

import cv2

class DrawRectangel:

    def DrawRects(self,image_path,iter):
        # Load image, grayscale, Gaussian blur, Otsu's threshold
        image = cv2.imread(image_path)
        cnts = self.findConturs(image,iter)
        image2 = image.copy()

        for c in cnts:
            x, y, w, h = cv2.boundingRect(c)
            if image2.shape[1] // 4 < w < image2.shape[1] // 2 :
                cv2.rectangle(image2, (x, y),(x + w , y + h), (0, 0, 255),1)

        cv2.imshow('Paragarflar',image2)
        cv2.waitKey(0)
        cv2.destroyAllWindows()


    def findConturs(self,image,iter):
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        blur = cv2.GaussianBlur(gray, (7, 7), 0)
        thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

        # Create rectangular structuring element and dilate
        kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 15))
        dilate = cv2.dilate(thresh, kernel, iterations=iter)

        # Find contours and draw rectangle
        cnts = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
        cnts = cnts[0] if len(cnts) == 2 else cnts[1]

        return cnts

DrawRectangel().DrawRects("test.jpeg",4)

Not: Sizin resmi test.jpg olarak kaydedip kullandım.

İlgili kodlarda kullanacağınız resme göre bu kısımları değiştirebilirsiniz.

2 Beğeni

Teşekkür ederim. Bu yardımcı oldu.

1 Beğeni