2010-01-01 10 views
27

Sono ancora un principiante ma voglio scrivere un programma di riconoscimento dei caratteri. Questo programma non è ancora pronto. E ho curato molto, quindi i commenti potrebbero non corrispondere esattamente. Userò la connettività 8 per l'etichettatura dei componenti collegati.Il mio programma OCR in Python

from PIL import Image 
import numpy as np 

im = Image.open("D:\\Python26\\PYTHON-PROGRAMME\\bild_schrift.jpg") 

w,h = im.size 
w = int(w) 
h = int(h) 

#2D-Array for area 
area = [] 
for x in range(w): 
    area.append([]) 
    for y in range(h): 
     area[x].append(2) #number 0 is white, number 1 is black 

#2D-Array for letter 
letter = [] 
for x in range(50): 
    letter.append([]) 
    for y in range(50): 
     letter[x].append(0) 

#2D-Array for label 
label = [] 
for x in range(50): 
    label.append([]) 
    for y in range(50): 
     label[x].append(0) 

#image to number conversion 
pix = im.load() 
threshold = 200 
for x in range(w): 
    for y in range(h): 
     aaa = pix[x, y] 
     bbb = aaa[0] + aaa[1] + aaa[2] #total value 
     if bbb<=threshold: 
      area[x][y] = 1 
     if bbb>threshold: 
      area[x][y] = 0 
np.set_printoptions(threshold='nan', linewidth=10) 

#matrix transponation 
ccc = np.array(area) 
area = ccc.T #better solution? 

#find all black pixel and set temporary label numbers 
i=1 
for x in range(40): # width (later) 
    for y in range(40): # heigth (later) 
     if area[x][y]==1: 
      letter[x][y]=1 
      label[x][y]=i 
      i += 1 

#connected components labeling 
for x in range(40): # width (later) 
    for y in range(40): # heigth (later) 
     if area[x][y]==1: 
      label[x][y]=i 
      #if pixel has neighbour: 
      if area[x][y+1]==1: 
       #pixel and neighbour get the lowest label    
       pass # tomorrows work 
      if area[x+1][y]==1: 
       #pixel and neighbour get the lowest label    
       pass # tomorrows work    
      #should i also compare pixel and left neighbour? 

#find width of the letter 
#find height of the letter 
#find the middle of the letter 
#middle = [width/2][height/2] #? 
#divide letter into 30 parts --> 5 x 6 array 

#model letter 
#letter A-Z, a-z, 0-9 (maybe more) 

#compare each of the 30 parts of the letter with all model letters 
#make a weighting 

#print(letter) 

im.save("D:\\Python26\\PYTHON-PROGRAMME\\bild2.jpg") 
print('done') 
+0

Hm ... il diavolo è nei dettagli. Per far sì che funzioni bene, penso che sia necessario caricare molti caratteri diversi. La mia impressione è che i programmi OCR passino in rassegna vari tipi di carattere finché non trovano quello che preferiscono. Ovviamente, ci sono molti articoli pubblicati sull'argomento. Perché vuoi implementarlo come una delle tue prime attività Python? –

+0

Il processo di confronto è la seconda parte. :) All'inizio voglio parlare di questo processo di ricerca delle lettere. - Voglio farlo, perché penso di poterlo fare. Penso che non sia così difficile. Ho anche fatto questo: http://kkaammee.blogspot.com/ Non è facile, almeno per me. – kame

+1

Altri chiarimenti: tutto va bene se il tuo codice è in bianco e nero. Tuttavia, cosa succede se alcune lettere/parole sono in grigio? Vuoi qualcosa come l'operazione "seleziona regione per colore dato soglia" di Gimp. Personalmente avrei iniziato calcolando la distribuzione dell'oscurità - oscurità media + std dell'immagine. Inizierei quindi da un punto "bianco" e continuerò a selezionare il bianco, finché non identificherò le isole non bianche: quelle sono le lettere potenziali. A proposito, non hai bisogno di casualità: una ricerca per ampiezza può aiutarti a localizzare tutti i pixel neri ... il trucco sta nel localizzare le isole. –

risposta

33

OCR non è un compito facile. Ecco perché i CAPTCHA di testo funzionano ancora :)

Per parlare solo dell'estrazione di lettere e non del riconoscimento di schemi, la tecnica che si sta utilizzando per separare le lettere è denominata Connected Component Labeling. Poiché stai chiedendo un modo più efficiente per farlo, prova ad implementare l'algoritmo a due passaggi descritto in questo articolo. Un'altra descrizione è disponibile nell'articolo Blob extraction.

EDIT: Ecco l'implementazione per l'algoritmo che ho suggerito:

import sys 
from PIL import Image, ImageDraw 

class Region(): 
    def __init__(self, x, y): 
     self._pixels = [(x, y)] 
     self._min_x = x 
     self._max_x = x 
     self._min_y = y 
     self._max_y = y 

    def add(self, x, y): 
     self._pixels.append((x, y)) 
     self._min_x = min(self._min_x, x) 
     self._max_x = max(self._max_x, x) 
     self._min_y = min(self._min_y, y) 
     self._max_y = max(self._max_y, y) 

    def box(self): 
     return [(self._min_x, self._min_y), (self._max_x, self._max_y)] 

def find_regions(im): 
    width, height = im.size 
    regions = {} 
    pixel_region = [[0 for y in range(height)] for x in range(width)] 
    equivalences = {} 
    n_regions = 0 
    #first pass. find regions. 
    for x in xrange(width): 
     for y in xrange(height): 
      #look for a black pixel 
      if im.getpixel((x, y)) == (0, 0, 0, 255): #BLACK 
       # get the region number from north or west 
       # or create new region 
       region_n = pixel_region[x-1][y] if x > 0 else 0 
       region_w = pixel_region[x][y-1] if y > 0 else 0 

       max_region = max(region_n, region_w) 

       if max_region > 0: 
        #a neighbour already has a region 
        #new region is the smallest > 0 
        new_region = min(filter(lambda i: i > 0, (region_n, region_w))) 
        #update equivalences 
        if max_region > new_region: 
         if max_region in equivalences: 
          equivalences[max_region].add(new_region) 
         else: 
          equivalences[max_region] = set((new_region,)) 
       else: 
        n_regions += 1 
        new_region = n_regions 

       pixel_region[x][y] = new_region 

    #Scan image again, assigning all equivalent regions the same region value. 
    for x in xrange(width): 
     for y in xrange(height): 
       r = pixel_region[x][y] 
       if r > 0: 
        while r in equivalences: 
         r = min(equivalences[r]) 

        if not r in regions: 
         regions[r] = Region(x, y) 
        else: 
         regions[r].add(x, y) 

    return list(regions.itervalues()) 

def main(): 
    im = Image.open(r"c:\users\personal\py\ocr\test.png") 
    regions = find_regions(im) 
    draw = ImageDraw.Draw(im) 
    for r in regions: 
     draw.rectangle(r.box(), outline=(255, 0, 0)) 
    del draw 
    #im.show() 
    output = file("output.png", "wb") 
    im.save(output) 
    output.close() 

if __name__ == "__main__": 
    main() 

E qui è il file di output:

Dead link

Non è perfetto al 100%, ma dal momento che lo stai facendo solo a scopo di apprendimento, potrebbe essere un buon punto di partenza Int. Con il riquadro di delimitazione di ciascun personaggio ora puoi usare una rete neurale come altri hanno suggerito qui.

+0

Ciao jbochi. Ho avuto l'idea di Connected Component Labeling prima di scrivermi. Lo userò nella mia versione più recente. – kame

+0

Ho fatto un errore. Ho guardato la linea per la linea. Dovrei guardare prima l'intera lettera e poi passare alla lettera successiva. come hai descritto prima. :) – kame

+1

ma perché pixel nord e ovest (quando si considera 4-connettività) e non pixel sud e ovest? Inizio nell'angolo in alto a sinistra e vado da sinistra a destra. – kame

7

OCR è molto, molto difficile. Anche con i personaggi generati dal computer, è piuttosto difficile se non si conosce il carattere e la dimensione del carattere in anticipo. Anche se combini esattamente i caratteri, non lo definirei un progetto di programmazione "iniziale"; è piuttosto sottile.

Se si desidera riconoscere i caratteri scansionati o scritti a mano, è ancora più difficile: è necessario utilizzare matematica avanzata, algoritmi e apprendimento automatico. Ci sono parecchi libri e migliaia di articoli scritti su questo argomento, quindi non è necessario reinventare la ruota.

Ammiro i tuoi sforzi, ma non penso che tu sia arrivato abbastanza lontano da colpire nessuna delle difficoltà attuali. Finora stai esplorando solo in modo casuale i pixel e copiandoli da una matrice all'altra. Non hai ancora fatto alcun confronto e non sono sicuro dello scopo della tua "passeggiata casuale".

  • Perché casuale? Scrivere algoritmi randomizzati corretti è piuttosto difficile. Consiglierei di iniziare con un algoritmo deterministico prima.
  • Perché si copia da un array all'altro? Perché non confrontare solo direttamente?

Quando si ottiene il confronto, si dovrà fare i conti con il fatto che l'immagine non è esattamente la stessa del "prototipo", e non è chiaro come la gestirai.

Sulla base del codice che hai scritto finora, tuttavia, ho un'idea per te: prova a scrivere un programma che si fa strada attraverso un "labirinto" in un'immagine. L'input sarebbe l'immagine, oltre al pixel iniziale e il pixel obiettivo. L'output è un percorso attraverso il labirinto dall'inizio alla meta. Questo è un problema molto più semplice dell'OCR - risolvere labirinti è qualcosa per cui i computer sono grandi - ma è comunque divertente e stimolante.

+0

Ciao dmazzoni. Nella versione più recente non uso casualità. Ora userò DFS o BFS./Copia da una matrice a un'altra? Perché voglio confrontare la lettera con le lettere modello./Non ho detto come voglio fare il confronto, ma ho un piano;) Anche la cosa con il labirinto è interessante, ma lo farò con l'OCR nonostante gli avvertimenti. :) – kame

4

OCR è molto, molto difficile! L'approccio da utilizzare per tentare l'OCR si baserà su ciò che si sta tentando di eseguire (scrittura manuale, lettura del testo generata dal computer, ecc.)

Tuttavia, per iniziare, consultare Neural Networks e OCR. Qui ci sono alcuni articoli di salto a destra-in sul tema:

http://www.codeproject.com/KB/cs/neural_network_ocr.aspx

http://www.codeproject.com/KB/dotnet/simple_ocr.aspx

utilizzare il motore di ricerca preferito per trovare le informazioni.

Buon divertimento!

+0

Ciao tgiphil! Molte grazie! – kame

5

Al giorno d'oggi la maggior parte degli algoritmi OCR si basa su algoritmi di rete neurali. Hopfield networks sono un buon punto di partenza. Sulla base del modello Hopfield disponibile here in C, ho costruito un algoritmo di riconoscimento delle immagini molto semplice in python simile a quello che descrivi. Ho pubblicato la fonte completa here. È un progetto giocattolo e non adatto per l'OCR reale, ma può farti iniziare nella giusta direzione.

Il modello Hopfield viene utilizzata come una memoria a autoassociativa memorizzare e richiamare una serie di immagini bitmap. Le immagini vengono memorizzate calcolando una corrispondente matrice di peso. Successivamente, partendo da una configurazione arbitraria, la memoria si sistemerà esattamente sull'immagine memorizzata, che è più vicina alla configurazione iniziale in termini di distanza di Hamming. Pertanto, in base a una versione incompleta o corrotta di un'immagine memorizzata, la rete è in grado di richiamare l'immagine originale corrispondente.

Un Java applet di giocare con un esempio può essere trovato here; la rete viene addestrata con ingressi di esempio per le cifre 0-9. Disegna nella casella a destra, fai clic su test e guarda i risultati dalla rete.

Non lasciare che la notazione matematica ti intimidisca, gli algoritmi sono semplici una volta arrivato al codice sorgente.

+0

Sono più intimidito dal codice di Python disordinato collegato alla notazione matematica. Posso suggerire di ripulirlo se hai intenzione di averlo come parte della tua risposta. –

Problemi correlati