Vâng, tôi quyết định tự tập luyện theo câu hỏi của mình để giải quyết vấn đề trên. Điều tôi muốn là triển khai OCR đơn giản bằng các tính năng KNearest hoặc SVM trong OpenCV. Và dưới đây là những gì tôi đã làm và làm thế nào. (nó chỉ dành cho việc học cách sử dụng KNearest cho các mục đích OCR đơn giản).
1) Câu hỏi đầu tiên của tôi là về tệp letter_recognition.data đi kèm với các mẫu OpenCV. Tôi muốn biết những gì bên trong tập tin đó.
Nó chứa một chữ cái, cùng với 16 tính năng của bức thư đó.
Và this SOF
giúp tôi tìm thấy nó. 16 tính năng này được giải thích trong bài báo Letter Recognition Using Holland-Style Adaptive Classifiers
. (Mặc dù tôi không hiểu một số tính năng ở cuối)
2) Vì tôi biết, nếu không hiểu tất cả các tính năng đó, thật khó để thực hiện phương pháp đó. Tôi đã thử một số giấy tờ khác, nhưng tất cả đều hơi khó khăn cho người mới bắt đầu.
So I just decided to take all the pixel values as my features.
(Tôi không lo lắng về độ chính xác hoặc hiệu suất, tôi chỉ muốn nó hoạt động, ít nhất là với độ chính xác thấp nhất)
Tôi lấy hình ảnh dưới đây cho dữ liệu đào tạo của tôi:
(Tôi biết số lượng dữ liệu đào tạo ít hơn. Nhưng, vì tất cả các chữ cái có cùng phông chữ và kích thước, tôi quyết định thử về điều này).
Để chuẩn bị dữ liệu cho đào tạo, tôi đã tạo một mã nhỏ trong OpenCV. Nó làm những điều sau đây:
- Nó tải hình ảnh.
- Chọn các chữ số (rõ ràng bằng cách tìm đường viền và áp dụng các ràng buộc về diện tích và chiều cao của chữ cái để tránh phát hiện sai).
- Vẽ hình chữ nhật giới hạn xung quanh một chữ cái và chờ đợi
key press manually
. Lần này chúng ta tự bấm phím chữ số tương ứng với chữ cái trong hộp.
- Khi nhấn phím chữ số tương ứng, nó sẽ thay đổi kích thước hộp này thành 10 x 10 và lưu 100 giá trị pixel trong một mảng (ở đây, các mẫu) và chữ số được nhập thủ công tương ứng trong một mảng khác (ở đây, phản hồi).
- Sau đó lưu cả hai mảng trong các tệp txt riêng biệt.
Khi kết thúc phân loại thủ công các chữ số, tất cả các chữ số trong dữ liệu xe lửa (train.png) đều được chúng tôi dán nhãn thủ công, hình ảnh sẽ như sau:
Dưới đây là mã tôi đã sử dụng cho mục đích trên (tất nhiên, không quá rõ ràng):
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)
Bây giờ chúng tôi nhập vào để đào tạo và kiểm tra một phần.
Để kiểm tra phần tôi đã sử dụng bên dưới hình ảnh, có cùng loại chữ tôi đã sử dụng để đào tạo.
Đối với đào tạo, chúng tôi làm như sau :
- Tải các tệp txt mà chúng tôi đã lưu trước đó
- tạo một thể hiện của trình phân loại mà chúng ta đang sử dụng (ở đây, nó là KNearest)
- Sau đó, chúng tôi sử dụng hàm KNearest.train để đào tạo dữ liệu
Đối với mục đích thử nghiệm, chúng tôi làm như sau:
- Chúng tôi tải hình ảnh được sử dụng để thử nghiệm
- xử lý hình ảnh như trước đó và trích xuất từng chữ số bằng các phương pháp đường viền
- Vẽ hộp giới hạn cho nó, sau đó thay đổi kích thước thành 10 x 10 và lưu trữ các giá trị pixel của nó trong một mảng như được thực hiện trước đó.
- Sau đó, chúng tôi sử dụng hàm KNearest.find_nearest () để tìm mục gần nhất với mục chúng tôi đã cung cấp. (Nếu may mắn, nó nhận ra chữ số chính xác.)
Tôi đã bao gồm hai bước cuối cùng (đào tạo và kiểm tra) trong một mã dưới đây:
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)
Và nó đã hoạt động, dưới đây là kết quả tôi nhận được:
Ở đây nó hoạt động với độ chính xác 100%. Tôi cho rằng điều này là do tất cả các chữ số cùng loại và cùng kích cỡ.
Nhưng dù sao đi nữa, đây là một khởi đầu tốt cho người mới bắt đầu (tôi hy vọng vậy).