Ну, я решил потренироваться сам над своим вопросом, чтобы решить вышеуказанную проблему. Я хотел реализовать простое 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. Это делает следующие вещи:
- Он загружает изображение.
- Выбирает цифры (очевидно, путем поиска контура и применения ограничений на область и высоту букв, чтобы избежать ложных обнаружений).
- Рисует ограничивающий прямоугольник вокруг одной буквы и жду
key press manually
. На этот раз мы нажимаем цифровую клавишу, соответствующую букве в поле.
- Как только соответствующая цифровая клавиша нажата, она изменяет размер этого поля до 10x10 и сохраняет 100-пиксельные значения в массиве (здесь образцы) и соответствующую вручную введенную цифру в другом массиве (здесь ответы)
- Затем сохраните оба массива в отдельных текстовых файлах.
В конце ручной классификации цифр все цифры в данных поезда (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)
Теперь мы приступаем к обучению и тестированию.
Для тестирования части я использовал изображение ниже, которое имеет тот же тип букв, которые я использовал для обучения.
Для обучения мы делаем следующее :
- Загрузите текстовые файлы, которые мы уже сохранили ранее
- создайте экземпляр используемого классификатора (здесь это 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% точностью. Я предполагаю, что это потому, что все цифры имеют одинаковый вид и размер.
Но в любом случае, это хорошее начало для начинающих (я надеюсь, что так).