Bene, ho deciso di allenarmi sulla mia domanda per risolvere il problema sopra. Quello che volevo era implementare un OCR semplice usando le funzioni KNearest o SVM in OpenCV. E di seguito è quello che ho fatto e come. (è solo per imparare a usare KNearest per semplici scopi OCR).
1) La mia prima domanda riguardava il file letter_recognition.data fornito con gli esempi OpenCV. Volevo sapere cosa c'è dentro quel file.
Contiene una lettera, insieme a 16 caratteristiche di quella lettera.
E this SOF
mi ha aiutato a trovarlo. Queste 16 funzioni sono spiegate nel documento Letter Recognition Using Holland-Style Adaptive Classifiers
. (Anche se alla fine non ho capito alcune delle funzionalità)
2) Da quando ho saputo, senza capire tutte quelle caratteristiche, è difficile fare quel metodo. Ho provato alcuni altri documenti, ma erano tutti un po 'difficili per un principiante.
So I just decided to take all the pixel values as my features.
(Non ero preoccupato per l'accuratezza o le prestazioni, volevo solo che funzionasse, almeno con la minima precisione)
Ho preso l'immagine qui sotto per i miei dati di allenamento:
(So che la quantità di dati di allenamento è inferiore. Ma, dal momento che tutte le lettere hanno lo stesso carattere e le stesse dimensioni, ho deciso di provarlo).
Per preparare i dati per la formazione, ho creato un piccolo codice in OpenCV. Fa le seguenti cose:
- Carica l'immagine.
- Seleziona le cifre (ovviamente individuando i contorni e applicando vincoli su area e altezza delle lettere per evitare falsi rilevamenti).
- Disegna il rettangolo di delimitazione attorno a una lettera e attendi
key press manually
. Questa volta premiamo noi stessi il tasto numerico corrispondente alla lettera nella casella.
- Una volta premuto il tasto numerico corrispondente, ridimensiona questa casella su 10x10 e salva i valori di 100 pixel in un array (qui, i campioni) e la cifra immessa manualmente corrispondente in un altro array (qui, le risposte).
- Quindi salvare entrambi gli array in file txt separati.
Alla fine della classificazione manuale delle cifre, tutte le cifre nei dati del treno (train.png) sono etichettate manualmente da noi stessi, l'immagine apparirà come di seguito:
Di seguito è riportato il codice che ho usato per lo scopo sopra (ovviamente, non così pulito):
import sys
import numpy as np
import cv2
im = cv2.imread('pitrain.png')
im3 = im.copy()
gray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray,(5,5),0)
thresh = cv2.adaptiveThreshold(blur,255,1,1,11,2)
################# Now finding Contours ###################
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
samples = np.empty((0,100))
responses = []
keys = [i for i in range(48,58)]
for cnt in contours:
if cv2.contourArea(cnt)>50:
[x,y,w,h] = cv2.boundingRect(cnt)
if h>28:
cv2.rectangle(im,(x,y),(x+w,y+h),(0,0,255),2)
roi = thresh[y:y+h,x:x+w]
roismall = cv2.resize(roi,(10,10))
cv2.imshow('norm',im)
key = cv2.waitKey(0)
if key == 27: # (escape to quit)
sys.exit()
elif key in keys:
responses.append(int(chr(key)))
sample = roismall.reshape((1,100))
samples = np.append(samples,sample,0)
responses = np.array(responses,np.float32)
responses = responses.reshape((responses.size,1))
print "training complete"
np.savetxt('generalsamples.data',samples)
np.savetxt('generalresponses.data',responses)
Ora entriamo nella parte relativa alla formazione e ai test.
Per la parte di test che ho usato sotto l'immagine, che ha lo stesso tipo di lettere che ho usato per addestrare.
Per la formazione facciamo come segue :
- Carica i file txt che abbiamo già salvato in precedenza
- crea un'istanza di classificatore che stiamo usando (qui, è KNearest)
- Quindi usiamo la funzione KNearest.train per addestrare i dati
A scopo di test, facciamo come segue:
- Carichiamo l'immagine utilizzata per i test
- elaborare l'immagine come prima ed estrarre ogni cifra usando i metodi di contorno
- Disegna il riquadro di delimitazione per esso, quindi ridimensionalo a 10x10 e memorizza i suoi valori di pixel in un array come fatto in precedenza.
- Quindi usiamo la funzione KNearest.find_nearest () per trovare l'oggetto più vicino a quello che abbiamo dato. (Se fortunato, riconosce la cifra corretta.)
Ho incluso gli ultimi due passaggi (formazione e test) in un unico codice di seguito:
import cv2
import numpy as np
####### training part ###############
samples = np.loadtxt('generalsamples.data',np.float32)
responses = np.loadtxt('generalresponses.data',np.float32)
responses = responses.reshape((responses.size,1))
model = cv2.KNearest()
model.train(samples,responses)
############################# testing part #########################
im = cv2.imread('pi.png')
out = np.zeros(im.shape,np.uint8)
gray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
thresh = cv2.adaptiveThreshold(gray,255,1,1,11,2)
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
if cv2.contourArea(cnt)>50:
[x,y,w,h] = cv2.boundingRect(cnt)
if h>28:
cv2.rectangle(im,(x,y),(x+w,y+h),(0,255,0),2)
roi = thresh[y:y+h,x:x+w]
roismall = cv2.resize(roi,(10,10))
roismall = roismall.reshape((1,100))
roismall = np.float32(roismall)
retval, results, neigh_resp, dists = model.find_nearest(roismall, k = 1)
string = str(int((results[0][0])))
cv2.putText(out,string,(x,y+h),0,1,(0,255,0))
cv2.imshow('im',im)
cv2.imshow('out',out)
cv2.waitKey(0)
E ha funzionato, di seguito è il risultato che ho ottenuto:
Qui ha funzionato con una precisione del 100%. Suppongo che ciò avvenga perché tutte le cifre sono dello stesso tipo e delle stesse dimensioni.
Ad ogni modo, questo è un buon inizio per i principianti (lo spero).