ดีฉันตัดสินใจที่จะออกกำลังกายกับคำถามของฉันเพื่อแก้ปัญหาข้างต้น สิ่งที่ฉันต้องการคือการใช้ OCR อย่างง่ายโดยใช้คุณสมบัติ KNearest หรือ SVM ใน OpenCV และด้านล่างเป็นสิ่งที่ฉันทำและอย่างไร (เป็นเพียงการเรียนรู้วิธีใช้ KNearest เพื่อวัตถุประสงค์ OCR แบบง่าย)
1)คำถามแรกของฉันเกี่ยวกับไฟล์ letter_recognition.data ที่มาพร้อมกับตัวอย่าง OpenCV ฉันอยากรู้ว่ามีอะไรอยู่ในไฟล์นั้น
มันมีตัวอักษรพร้อมกับ 16 คุณสมบัติของตัวอักษรนั้น
และthis SOF
ช่วยให้ฉันค้นหามัน 16 Letter Recognition Using Holland-Style Adaptive Classifiers
คุณลักษณะเหล่านี้จะอธิบายในกระดาษ (แม้ว่าฉันจะไม่เข้าใจคุณสมบัติบางอย่างในตอนท้าย)
2)เนื่องจากฉันรู้โดยไม่เข้าใจคุณลักษณะทั้งหมดเหล่านั้นจึงเป็นการยากที่จะทำวิธีนั้น ฉันลองใช้เอกสารอื่น ๆ แต่ก็ยากสำหรับผู้เริ่มต้น
So I just decided to take all the pixel values as my features.
(ฉันไม่ได้กังวลเกี่ยวกับความแม่นยำหรือประสิทธิภาพฉันแค่อยากให้มันทำงานอย่างน้อยก็มีความแม่นยำน้อยที่สุด)
ฉันเอาภาพด้านล่างสำหรับข้อมูลการฝึกอบรมของฉัน:
(ฉันรู้ว่าจำนวนข้อมูลการฝึกอบรมมีน้อยลง แต่เนื่องจากตัวอักษรทั้งหมดมีขนาดและตัวอักษรเท่ากันฉันจึงตัดสินใจลองทำ)
เพื่อเตรียมข้อมูลสำหรับการฝึกอบรมฉันได้ทำโค้ดขนาดเล็กใน OpenCV มันทำสิ่งต่อไปนี้:
- มันโหลดภาพ
- เลือกตัวเลข (เห็นได้ชัดโดยการค้นหารูปร่างและการใช้ข้อ จำกัด ในพื้นที่และความสูงของตัวอักษรเพื่อหลีกเลี่ยงการตรวจจับที่ผิดพลาด)
- ดึง bounding
key press manually
สี่เหลี่ยมรอบหนึ่งตัวอักษรและรอ เวลานี้เรากดปุ่มตัวเลขของเราเองที่สอดคล้องกับตัวอักษรในกล่อง
- เมื่อกดปุ่มตัวเลขที่สอดคล้องกันมันจะปรับขนาดกล่องนี้เป็น 10x10 และบันทึกค่า 100 พิกเซลในอาร์เรย์ (ที่นี่ตัวอย่าง) และตัวเลขที่ป้อนด้วยตนเองที่สอดคล้องกันในอาร์เรย์อื่น (ที่นี่การตอบกลับ)
- จากนั้นบันทึกทั้งสองอาร์เรย์ในไฟล์ txt แยกกัน
ในตอนท้ายของการจัดหมวดหมู่ของตัวเลขด้วยตนเองตัวเลขทั้งหมดในข้อมูลรถไฟ (train.png) จะมีป้ายกำกับด้วยตนเองด้วยตนเองภาพจะมีลักษณะดังนี้:
ด้านล่างนี้เป็นรหัสที่ฉันใช้เพื่อจุดประสงค์ด้านบน (แน่นอนไม่สะอาดมาก):
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)
ตอนนี้เราเข้าสู่ส่วนการฝึกอบรมและการทดสอบ
สำหรับการทดสอบฉันใช้ภาพด้านล่างซึ่งมีตัวอักษรประเภทเดียวกับที่ฉันเคยฝึก
สำหรับการฝึกอบรมเรามีดังนี้ :
- โหลดไฟล์ txt ที่เราบันทึกไว้ก่อนหน้านี้
- สร้างตัวอย่างของตัวจําแนกที่เราใช้ (ที่นี่คือ KNearest)
- จากนั้นเราใช้ฟังก์ชัน KNearest.train เพื่อฝึกอบรมข้อมูล
สำหรับวัตถุประสงค์ในการทดสอบเราทำดังต่อไปนี้:
- เราโหลดภาพที่ใช้สำหรับการทดสอบ
- ประมวลผลภาพก่อนหน้านี้และแยกแต่ละหลักโดยใช้วิธีการเส้น
- วาดขอบเขตของกล่องจากนั้นปรับขนาดเป็น 10x10 และเก็บค่าพิกเซลในอาร์เรย์ตามที่ทำไว้ก่อนหน้านี้
- จากนั้นเราใช้ฟังก์ชัน KNearest.find_nearest () เพื่อค้นหารายการที่ใกล้ที่สุดกับที่เราให้ (หากโชคดีระบบจะจดจำตัวเลขที่ถูกต้อง)
ฉันรวมสองขั้นตอนสุดท้าย (การฝึกอบรมและการทดสอบ) ในรหัสเดียวด้านล่าง:
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)
และทำงานได้ด้านล่างคือผลลัพธ์ที่ฉันได้รับ:
ที่นี่มันทำงานได้อย่างแม่นยำ 100% ฉันถือว่านี่เป็นเพราะตัวเลขทั้งหมดเป็นประเภทเดียวกันและขนาดเดียวกัน
แต่อย่างไรก็ตามนี่เป็นจุดเริ่มต้นที่ดีสำหรับผู้เริ่มต้น (ฉันหวังว่าอย่างนั้น)