OpenCV-Python中的简单数字识别OCR?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (3)
  • 关注 (0)
  • 查看 (2782)

我试图在OpenCV-Python(CV2)中实现一个“数字识别OCR”。。我想知道OpenCV中的KNeest和SVM特性。

我有每一个数字的100个样本(图像)。我想训练它们。

有一个样本letter_recog.py这是OpenCV样本提供的。但我不知道怎么使用它。

import numpy as np
import cv2

fn = 'letter-recognition.data'
a = np.loadtxt(fn, np.float32, delimiter=',', converters={ 0 : lambda ch : ord(ch)-ord('A') })
samples, responses = a[:,1:], a[:,0]

model = cv2.KNearest()
retval = model.train(samples,responses)
retval, results, neigh_resp, dists = model.find_nearest(samples, k = 10)
print results.ravel()

它创建了一个20000纬度的数组,我不知道它的用途是什么。

问题:

1)什么是 letter_recognition.data数据文件?如何使用我的数据构造这个文件?

2)results.reval()是什么?

3)如何编写一个简单的数字识别工具(用KNest还是SVM)?

提问于
用户回答回答于

我使用OpenCV中的KNeest或SVM特性来实现简单的文字识别OCR。下面是我实现的步骤,学习学习

1)我的第一个问题是关于OpenCV示例附带的数据文件。我想知道文件里有什么。

它包含一个字母,以及该字母的16个特征。

this SOF帮我找到了。本文对这16个特征进行了说明。使用Holland分类器进行字母识别

2)如果不了解这些特性,就很难做。所以能实现就好,我没有太关注性能

以下是我的训练数据图:

(训练数据量较少。所有的字母都是相同的字体和大小)。

我用OpenCV编写了一个小代码处理数据:

a)加载图像。

(B)选择数字(是通过轮廓查找并对字母的面积和高度施加约束来避免错误检测)。

(C)给字母绘制边框,并自己按数字键与图中一致

(D)一旦按下相应的数字键,它将该框调整为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)

现在进入训练和测试部分。

在测试部分,我使用了下面的图像,它的字母类型是一样的

关于训练

(A)加载我们前面已经保存的txt文件

(B)创建分类器实例(在这里,它是KNeest)

(C)然后使用KNearest.TRANS函数对数据进行训练。

关于测试

(A)我们加载用于测试的图像

(B)像以前一样处理图像,并使用轮廓法提取每一个数字。

c)为其绘制边框,然后调整大小为10x10,并像前面所做的那样将其像素值存储在数组中。

(D)然后我们使用 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%

用户回答回答于

如果你对机器学习的最新状况感兴趣,你可以深入学习。您应该有一个深度学习的环境,或者在AmazonWeb服务上使用GPU。

Google Udacity有一个很好Tensorflow的教程教你如何训练手写体数字得到你自己的分类器。在测试集上使用卷积网络,精度超过97%。

用户回答回答于

下面是用C++来实现的

该算法的过程与上述相同,但该算法只使用第一层次的等高线,因此算法只对每一个数字使用相同的外部轮廓。

创建示例和标签数据的代码

//Process image to extract contour
Mat thr,gray,con;
Mat src=imread("digit.png",1);
cvtColor(src,gray,CV_BGR2GRAY);
threshold(gray,thr,200,255,THRESH_BINARY_INV); //Threshold to find contour
thr.copyTo(con);

// Create sample and label data
vector< vector <Point> > contours; // Vector for storing contour
vector< Vec4i > hierarchy;
Mat sample;
Mat response_array;  
findContours( con, contours, hierarchy,CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE ); //Find contour

for( int i = 0; i< contours.size(); i=hierarchy[i][0] ) // iterate through first hierarchy level contours
{
    Rect r= boundingRect(contours[i]); //Find bounding rect for each contour
    rectangle(src,Point(r.x,r.y), Point(r.x+r.width,r.y+r.height), Scalar(0,0,255),2,8,0);
    Mat ROI = thr(r); //Crop the image
    Mat tmp1, tmp2;
    resize(ROI,tmp1, Size(10,10), 0,0,INTER_LINEAR ); //resize to 10X10
    tmp1.convertTo(tmp2,CV_32FC1); //convert to float
    sample.push_back(tmp2.reshape(1,1)); // Store  sample data
    imshow("src",src);
    int c=waitKey(0); // Read corresponding label for contour from keyoard
    c-=0x30;     // Convert ascii to intiger value
    response_array.push_back(c); // Store label to a mat
    rectangle(src,Point(r.x,r.y), Point(r.x+r.width,r.y+r.height), Scalar(0,255,0),2,8,0);    
}

// Store the data to file
Mat response,tmp;
tmp=response_array.reshape(1,1); //make continuous
tmp.convertTo(response,CV_32FC1); // Convert  to float

FileStorage Data("TrainingData.yml",FileStorage::WRITE); // Store the sample data in a file
Data << "data" << sample;
Data.release();

FileStorage Label("LabelData.yml",FileStorage::WRITE); // Store the label data in a file
Label << "label" << response;
Label.release();
cout<<"Training and Label data created successfully....!! "<<endl;

imshow("src",src);
waitKey();

训练和测试

Mat thr,gray,con;
Mat src=imread("dig.png",1);
cvtColor(src,gray,CV_BGR2GRAY);
threshold(gray,thr,200,255,THRESH_BINARY_INV); // Threshold to create input
thr.copyTo(con);


// Read stored sample and label for training
Mat sample;
Mat response,tmp;
FileStorage Data("TrainingData.yml",FileStorage::READ); // Read traing data to a Mat
Data["data"] >> sample;
Data.release();

FileStorage Label("LabelData.yml",FileStorage::READ); // Read label data to a Mat
Label["label"] >> response;
Label.release();


KNearest knn;
knn.train(sample,response); // Train with sample and responses
cout<<"Training compleated.....!!"<<endl;

vector< vector <Point> > contours; // Vector for storing contour
vector< Vec4i > hierarchy;

//Create input sample by contour finding and cropping
findContours( con, contours, hierarchy,CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
Mat dst(src.rows,src.cols,CV_8UC3,Scalar::all(0));

for( int i = 0; i< contours.size(); i=hierarchy[i][0] ) // iterate through each contour for first hierarchy level .
{
    Rect r= boundingRect(contours[i]);
    Mat ROI = thr(r);
    Mat tmp1, tmp2;
    resize(ROI,tmp1, Size(10,10), 0,0,INTER_LINEAR );
    tmp1.convertTo(tmp2,CV_32FC1);
    float p=knn.find_nearest(tmp2.reshape(1,1), 1);
    char name[4];
    sprintf(name,"%d",(int)p);
    putText( dst,name,Point(r.x,r.y+r.height) ,0,1, Scalar(0, 255, 0), 2, 8 );
}

imshow("src",src);
imshow("dst",dst);
imwrite("dest.jpg",dst);
waitKey();

结果

结果,第一行中的点被检测为8,而我们还没有对点进行训练。此外,我也考虑了每一个等高线在第一层次作为样本输入,用户可以通过计算面积避免它。

扫码关注云+社区

领取腾讯云代金券