Yah, saya memutuskan untuk melatih diri pada pertanyaan saya untuk menyelesaikan masalah di atas. Yang saya inginkan adalah mengimplementasikan OCR sederhana menggunakan fitur KNearest atau SVM di OpenCV. Dan di bawah ini adalah apa yang saya lakukan dan bagaimana caranya. (itu hanya untuk mempelajari cara menggunakan KNearest untuk tujuan OCR sederhana).
1) Pertanyaan pertama saya adalah tentang file letter_recognition.data yang datang dengan sampel OpenCV. Saya ingin tahu apa yang ada di dalam file itu.
Ini berisi surat, bersama dengan 16 fitur surat itu.
Dan this SOF
membantu saya menemukannya. 16 fitur ini dijelaskan di koran Letter Recognition Using Holland-Style Adaptive Classifiers
. (Meskipun saya tidak mengerti beberapa fitur pada akhirnya)
2) Karena saya tahu, tanpa memahami semua fitur itu, sulit untuk melakukan metode itu. Saya mencoba beberapa makalah lain, tetapi semuanya agak sulit bagi pemula.
So I just decided to take all the pixel values as my features.
(Saya tidak khawatir tentang akurasi atau kinerja, saya hanya ingin itu berfungsi, setidaknya dengan akurasi paling sedikit)
Saya mengambil gambar di bawah ini untuk data pelatihan saya:
(Saya tahu jumlah data pelatihan kurang. Tapi, karena semua huruf memiliki ukuran dan huruf yang sama, saya memutuskan untuk mencoba ini).
Untuk menyiapkan data untuk pelatihan, saya membuat kode kecil di OpenCV. Ia melakukan hal-hal berikut:
- Itu memuat gambar.
- Pilih digit (jelas dengan menemukan kontur dan menerapkan batasan pada area dan ketinggian huruf untuk menghindari deteksi palsu).
- Gambarlah persegi panjang pembatas di sekitar satu huruf dan tunggu
key press manually
. Kali ini kami menekan tombol angka sesuai dengan huruf dalam kotak.
- Setelah tombol angka yang sesuai ditekan, ia mengubah ukuran kotak ini menjadi 10x10 dan menyimpan nilai 100 piksel dalam array (di sini, sampel) dan angka yang dimasukkan secara manual dalam array lain (di sini, tanggapan).
- Kemudian simpan kedua array dalam file txt terpisah.
Di akhir klasifikasi manual angka, semua digit dalam data kereta (train.png) dilabeli secara manual oleh kami sendiri, gambar akan terlihat seperti di bawah ini:
Di bawah ini adalah kode yang saya gunakan untuk tujuan di atas (tentu saja, tidak begitu bersih):
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)
Sekarang kita masuk ke bagian pelatihan dan pengujian.
Untuk bagian pengujian saya menggunakan gambar di bawah ini, yang memiliki jenis huruf yang sama yang saya gunakan untuk melatih.
Untuk pelatihan kami lakukan sebagai berikut :
- Muat file txt yang sudah kami simpan sebelumnya
- buat instance classifier yang kami gunakan (di sini, ini KNearest)
- Kemudian kita menggunakan fungsi KNearest.train untuk melatih data
Untuk tujuan pengujian, kami lakukan sebagai berikut:
- Kami memuat gambar yang digunakan untuk pengujian
- memproses gambar seperti sebelumnya dan mengekstraksi setiap digit menggunakan metode kontur
- Gambar kotak pembatas untuknya, lalu ubah ukuran menjadi 10x10, dan simpan nilai pikselnya dalam array seperti yang dilakukan sebelumnya.
- Kemudian kami menggunakan fungsi KNearest.find_nearest () untuk menemukan item terdekat dengan yang kami berikan. (Jika beruntung, ia mengenali angka yang benar.)
Saya menyertakan dua langkah terakhir (pelatihan dan pengujian) dalam satu kode di bawah ini:
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)
Dan itu berhasil, di bawah ini adalah hasil yang saya dapatkan:
Di sini ia bekerja dengan akurasi 100%. Saya berasumsi ini karena semua digit memiliki jenis dan ukuran yang sama.
Tapi bagaimanapun juga, ini adalah awal yang baik untuk pemula (saya harap begitu).