2015-01-15 7 views
10

Ho questa immagine di una tabella (vedi sotto). E sto cercando di ottenere i dati dalla tabella, in modo simile a questa forma (prima riga sulla tabella di):Elaborazione di un'immagine di una tabella per ottenere dati da essa

rows[0] = [x,x, , , , ,x, ,x,x, ,x, ,x, , , , ,x, , , ,x,x,x, ,x, ,x, , , , ] 

mi serve il numero di x di così come il numero di spazi. Ci saranno anche altre immagini di tabelle simili a questa (tutte con x e lo stesso numero di colonne).

enter image description here

Finora, sono in grado di rilevare tutte le x che utilizzano l'immagine di un x. E posso in qualche modo rilevare le linee. Sto usando open cv2 per Python. Sto anche usando un houghTransform per rilevare le linee orizzontali e verticali (che funziona davvero bene).

Sto cercando di capire come posso andare riga per riga e memorizzare le informazioni in una lista.

Queste sono le immagini di addestramento: utilizzati per rilevare x (train1.png nel codice) enter image description here

utilizzato per rilevare le linee (train2.png nel codice) enter image description here

utilizzato per rilevare linee (train3.png nel codice) enter image description here

Questo è il codice che ho finora:

# process images 
from pytesser import * 
from PIL import Image 
from matplotlib import pyplot as plt 
import pytesseract 
import numpy as np 
import cv2 
import math 
import os 

# the table images 
images = ['table1.png', 'table2.png', 'table3.png', 'table4.png', 'table5.png'] 

# the template images used for training 
templates = ['train1.png', 'train2.png', 'train3.png'] 

def hough_transform(im): 
    img = cv2.imread('imgs/'+im) 
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 
    edges = cv2.Canny(gray, 50, 150, apertureSize=3) 

    lines = cv2.HoughLines(edges, 1, np.pi/180, 200) 

    i = 1 
    for rho, theta in lines[0]: 
     a = np.cos(theta) 
     b = np.sin(theta) 
     x0 = a*rho 
     y0 = b*rho 
     x1 = int(x0 + 1000*(-b)) 
     y1 = int(y0 + 1000*(a)) 
     x2 = int(x0 - 1000*(-b)) 
     y2 = int(y0 - 1000*(a)) 

     #print '%s - 0:(%s,%s) 1:(%s,%s), 2:(%s,%s)' % (i,x0,y0,x1,y1,x2,y2) 

     cv2.line(img, (x1,y1), (x2,y2), (0,0,255), 2) 
     i += 1 

    fn = os.path.splitext(im)[0]+'-lines' 
    cv2.imwrite('imgs/'+fn+'.png', img) 


def match_exes(im, te): 
    img_rgb = cv2.imread('imgs/'+im) 
    img_gry = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY) 
    template = cv2.imread('imgs/'+te, 0) 
    w, h = template.shape[::-1] 

    res = cv2.matchTemplate(img_gry, template, cv2.TM_CCOEFF_NORMED) 
    threshold = 0.71 
    loc = np.where(res >= threshold) 

    pts = [] 
    exes = [] 
    blanks = [] 
    for pt in zip(*loc[::-1]): 
     pts.append(pt) 
     cv2.rectangle(img_rgb, pt, (pt[0]+w, pt[1]+h), (0,0,255), 1) 


    fn = os.path.splitext(im)[0]+'-exes' 
    cv2.imwrite('imgs/'+fn+'.png', img_rgb) 

    return pts, exes, blanks 


def match_horizontal_lines(im, te, te2): 
    img_rgb = cv2.imread('imgs/'+im) 
    img_gry = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY) 
    template = cv2.imread('imgs/'+te, 0) 
    w1, h1 = template.shape[::-1] 
    template2 = cv2.imread('imgs/'+te2, 0) 
    w2, h2 = template2.shape[::-1] 

    # first line template (the downward facing line) 
    res1 = cv2.matchTemplate(img_gry, template, cv2.TM_CCOEFF_NORMED) 
    threshold1 = 0.8 
    loc1 = np.where(res1 >= threshold1) 

    # second line template (the upward facing line) 
    res2 = cv2.matchTemplate(img_gry, template2, cv2.TM_CCOEFF_NORMED) 
    threshold2 = 0.8 
    loc2 = np.where(res2 >= threshold2) 

    pts = [] 
    exes = [] 
    blanks = [] 

    # find first line template (the downward facing line) 
    for pt in zip(*loc1[::-1]): 
     pts.append(pt) 
     cv2.rectangle(img_rgb, pt, (pt[0]+w1, pt[1]+h1), (0,0,255), 1) 

    # find second line template (the upward facing line) 
    for pt in zip(*loc2[::-1]): 
     pts.append(pt) 
     cv2.rectangle(img_rgb, pt, (pt[0]+w2, pt[0]+h2), (0,0,255), 1) 

    fn = os.path.splitext(im)[0]+'-horiz' 
    cv2.imwrite('imgs/'+fn+'.png', img_rgb) 

    return pts, exes, blanks 


# process 
text = '' 
for img in images: 
    print 'processing %s' % img 
    hough_transform(img) 
    pts, exes, blanks = match_exes(img, templates[0]) 
    pts1, exes1, blanks1 = match_horizontal_lines(img, templates[1], templates[2]) 
    text += '%s: %s x\'s & %s horizontal lines\n' % (img, len(pts), len(pts1)) 

# statistics file 
outputFile = open('counts.txt', 'w') 
outputFile.write(text) 
outputFile.close() 

E, le immagini in uscita simile a questa (come si può vedere, tutte le x sono rilevati, ma non tutte le linee) di x enter image description here

linee orizzontali enter image description here

trasformata di Hough enter image description here

Come ho già detto, in realtà sto solo cercando di ottenere i dati dalla tabella, in modo simile a questo modulo (prima riga dell'immagine della tabella):

row a = [x,x, , , , ,x, ,x,x, ,x, ,x, , , , ,x, , , ,x,x,x, ,x, ,x, , , , ] 

Ho bisogno del numero di x e del numero di spazi. Ci saranno anche altre immagini di tabelle simili a questa (tutte con x e lo stesso numero di colonne e un diverso numero di righe).

Inoltre, sto usando Python 2.7

+1

Sembra che tu sia molto, molto vicino. Guardando le tue linee di Hough, dovresti essere in grado di trovare i limiti di, ad esempio, la prima cella (riga 0, colonna 0). Quindi controlla all'interno di quei limiti solo per un 'x' e aggiorna la tabella di conseguenza. Sfortunatamente il mio Python è abbastanza debole o vorrei pubblicare una risposta più concreta. – beaker

+0

Il problema che ho notato con la trasformazione di Hough è che disegna 2 linee per ogni riga sul tavolo. Ho impostato la larghezza della linea da 2 a 1 per vedere la differenza. In questo momento, sto cercando di mappare tutte le x utilizzando la corrispondenza dei modelli e vedere quali sono sulla stessa riga, ecc ... – user

+0

Le doppie linee potrebbero essere perché il "primo piano" è nero e lo "sfondo" è bianco. Prova ad invertire prima i colori. – beaker

risposta

2

Ok, ho capito. Ho usato il suggerimento fornito da @beaker di guardare tra le linee della griglia.

Prima di procedere dovevo rimuovere le righe duplicate dal codice di trasformazione di Hough. Quindi, ho ordinato le righe rimanenti in 2 elenchi, verticale e orizzontale. Da lì, ho potuto scorrere l'orizzontale e poi verticale e quindi creare un'immagine di regione di interesse (roi). Ogni immagine di roi rappresenta una "cella" nell'immagine principale della tabella. Ho controllato ciascuna di quelle celle per i contorni e ho notato che quando c'era una "x" nella cella, len(contours) >= 2. Quindi, qualsiasi len(contours) < 2 era uno spazio vuoto (ho fatto diversi programmi di test per capirlo).Ecco il codice che ho usato per farlo funzionare:

import cv2 
import numpy as np 
import os 

# the list of images (tables) 
images = ['table1.png', 'table2.png', 'table3.png', 'table4.png', 'table5.png'] 

# the list of templates (used for template matching) 
templates = ['train1.png'] 

def remove_duplicates(lines): 
    # remove duplicate lines (lines within 10 pixels of eachother) 
    for x1, y1, x2, y2 in lines: 
     for index, (x3, y3, x4, y4) in enumerate(lines): 
      if y1 == y2 and y3 == y4: 
       diff = abs(y1-y3) 
      elif x1 == x2 and x3 == x4: 
       diff = abs(x1-x3) 
      else: 
       diff = 0 
      if diff < 10 and diff is not 0: 
       del lines[index] 
    return lines 


def sort_line_list(lines): 
    # sort lines into horizontal and vertical 
    vertical = [] 
    horizontal = [] 
    for line in lines: 
     if line[0] == line[2]: 
      vertical.append(line) 
     elif line[1] == line[3]: 
      horizontal.append(line) 
    vertical.sort() 
    horizontal.sort(key=lambda x: x[1]) 
    return horizontal, vertical 


def hough_transform_p(image, template, tableCnt): 
    # open and process images 
    img = cv2.imread('imgs/'+image) 
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 
    edges = cv2.Canny(gray, 50, 150, apertureSize=3) 

    # probabilistic hough transform 
    lines = cv2.HoughLinesP(edges, 1, np.pi/180, 200, minLineLength=20, maxLineGap=999)[0].tolist() 

    # remove duplicates 
    lines = remove_duplicates(lines) 

    # draw image 
    for x1, y1, x2, y2 in lines: 
     cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 1) 

    # sort lines into vertical & horizontal lists 
    horizontal, vertical = sort_line_list(lines) 

    # go through each horizontal line (aka row) 
    rows = [] 
    for i, h in enumerate(horizontal): 
     if i < len(horizontal)-1: 
      row = [] 
      for j, v in enumerate(vertical): 
       if i < len(horizontal)-1 and j < len(vertical)-1: 
        # every cell before last cell 
        # get width & height 
        width = horizontal[i+1][1] - h[1] 
        height = vertical[j+1][0] - v[0] 

       else: 
        # last cell, width = cell start to end of image 
        # get width & height 
        width = tW 
        height = tH 
       tW = width 
       tH = height 

       # get roi (region of interest) to find an x 
       roi = img[h[1]:h[1]+width, v[0]:v[0]+height] 

       # save image (for testing) 
       dir = 'imgs/table%s' % (tableCnt+1) 
       if not os.path.exists(dir): 
        os.makedirs(dir) 
       fn = '%s/roi_r%s-c%s.png' % (dir, i, j) 
       cv2.imwrite(fn, roi) 

       # if roi contains an x, add x to array, else add _ 
       roi_gry = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY) 
       ret, thresh = cv2.threshold(roi_gry, 127, 255, 0) 
       contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) 

       if len(contours) > 1: 
        # there is an x for 2 or more contours 
        row.append('x') 
       else: 
        # there is no x when len(contours) is <= 1 
        row.append('_') 
      row.pop() 
      rows.append(row) 

    # save image (for testing) 
    fn = os.path.splitext(image)[0] + '-hough_p.png' 
    cv2.imwrite('imgs/'+fn, img) 


def process(): 
    for i, img in enumerate(images): 
     # perform probabilistic hough transform on each image 
     hough_transform_p(img, templates[0], i) 


if __name__ == '__main__': 
    process() 

Così, l'immagine del campione: enter image description here

E, l'uscita (codice per generare file di testo è stato cancellato per brevità): enter image description here

Come si può vedere, il file di testo contiene lo stesso numero di x nella stessa posizione dell'immagine. Ora che la parte difficile è finita, posso continuare con il mio incarico!

Problemi correlati