글쎄, 나는 위의 문제를 해결하기 위해 내 질문에 스스로 운동하기로 결정했다. 내가 원하는 것은 OpenCV에서 KNearest 또는 SVM 기능을 사용하여 간단한 OCR을 구현하는 것입니다. 아래는 내가 한 일과 방법입니다. (단순한 OCR 목적으로 KNearest를 사용하는 방법을 배우기위한 것입니다).
1) 첫 번째 질문은 OpenCV 샘플과 함께 제공되는 letter_recognition.data 파일에 관한 것입니다. 그 파일 안에 무엇이 있는지 알고 싶었습니다.
그것은 그 편지의 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 개의 픽셀 값과 다른 배열 (여기서는 응답)에 수동으로 입력 한 숫자가 저장됩니다.
- 그런 다음 두 배열을 별도의 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 % 정확도로 작동했습니다. 나는 이것이 모든 숫자가 같은 종류와 같은 크기이기 때문에 가정합니다.
그러나 어쨌든 이것은 초보자에게 좋은 출발입니다 (그렇기를 바랍니다).