OpenCV 2.4+ C++ SVM文字识别

预备知识

下面两个都不是必备知识,但是如果你想了解更多内容,可参考这两篇文章。

OpenCV 2.4+ C++ SVM介绍

OpenCV 2.4+ C++ SVM线性不可分处理

SVM划分的意义

到此,我们已经对SVM有一定的了解了。可是这有什么用呢?回到上一篇文章结果图:

Training data and decision regions given by the SVM

这个结果图的意义在于,他成功从二维划分了分类的区域。于是如果以后,有一个新的样本在绿色区域,那么我们就可以把他当成是绿色的点。

由于这可以像更高维度推广,所以如果我们能对样品映射成高维度空间的点,当有足够多的样品时,我们同样可以找到一个高维度的超平面划分,使得同一类样品的映射点在同一区域,于是当有新样品落在这些区域是,我们可以把它当成是这一类型的样本。

通俗一点

可能我们能更加通俗一点。比如我们来识别男性和女性。

我们发现男性和女性可能头发长度不一样,可能胸围不一样,于是我们对样本个体产生这样的一种映射:

人 —> (头发长度, 胸围)

于是我们将每个样品映射到二维平面,其中“头发的长度”和“胸围的长度”分别是x轴和y轴。我们把这些样品丢给SVM学习,则他会寻找出一个合理的x和y的区域来划分男性和女性。

当然,也有可能有些男的头发比女的还长,有的男性的胸围比女性还大,这些就是错分点,它们也影响着划分。

最后,当我们把一个人映射到这个二维空间时,SVM就可以根据以往的学习,猜一猜这个人到底是什么性别。

我们学到了什么呢?

好吧,特征要找准一点,否则可能遇到下面的悲剧……

OpenCV 2.4+ C++ SVM文字识别

如果这是老板,你可就死翘翘了……

简单的文字识别

当然计算机没那么厉害能看出你的胸围或者头发长短。他需要一些他能读懂的东西,特别计算机通常“看到”的是下面的这种东东……

A matrix of the mirror of a car

我们需要对文字找到他的特征,来映射到高维空间。

还记得小学时候练字的米字格么?这似乎暗示了我们,虽然每个人写的字千差万别,但是他们却具有一定的特点。

OpenCV 2.4+ C++ SVM文字识别

我们尝试这样做,取一个字,选取一个包含该字的正方形区域,将这个正方形区域分割成8*8个小格,统计每个小格中像素的数量,以这些数量为维度进行映射。

OK,明白了原理让我们开始吧。

被提醒了,那么补充一句:这个例子在实际中用来辨认是不可行的。

样本获取

由于通常文字样本都是白底黑字的,而手写也可以直接获取写入的数据而无视背景,所以我们并不需要对样本进行提取,但我们需要对他定位,并弄成合适的大小。

比如,你没法避免有人这么写字……

OpenCV 2.4+ C++ SVM文字识别

坑爹啊,好好的那么大地方你就躲在左上角……

开始定位

void getROI(Mat& src, Mat& dst){
    int left, right, top, bottom;
    left = src.cols;
    right = 0;
    top = src.rows;
    bottom = 0;

    //得到区域
    for(int i=0; i<src.rows; i++)
    {
        for(int j=0; j<src.cols; j++)
        {
            if(src.at<uchar>(i, j) > 0)
            {
                if(j<left) left = j;
                if(j>right) right = j;
                if(i<top) top = i;
                if(i>bottom) bottom = i;
            }
        }
    }

    int width = right - left;
    int height = bottom - top;

    //创建存储矩阵
    dst = Mat::zeros(width, height, CV_8UC1);

    Rect dstRect(left, top, width, height);
    dst(dstRect);
}

这段代码通过遍历所有图像矩阵的元素,来获取该样本的定位和大小。并把样本提取出来。

重新缩放

Mat dst = Mat::zeros(8, 8, CV_8UC1);resize(src, dst, dst.size());

进行缩放,把所有样本变成8*8的大小。为了简便,我们把像素多少变成了像素的灰度值。

resize的API:

调整图片大小

**C++:**voidresize(InputArray **src**, OutputArray **dst**, Size **dsize**, double **fx**=0, double **fy**=0, int **interpolation**=INTER_LINEAR)
参数 * **src** – 输入图像。
* **dst** – 输出图像;它有一个dsize(当其不为0时) 或者这个size由src.size(),fxfy算出dst的类型和src相同。
* **dsize** –

输出图像的大小,如果取值为0,则:

![texttt{dsize = Size(round(fx*src.cols), round(fy*src.rows))}](http://docs.opencv.org/_images/math/e1caf4dfaf20ce5569c6bb7fd8736f63263dace7.png)

dsize或者fxfy必须有一种大小决定方法不为0。

* **fx** –

水平轴缩放因子,当取值为0时,则为:

![texttt{(double)dsize.width/src.cols}](http://docs.opencv.org/_images/math/7ec52afa20807f7e640395d29f9a3a55d111aaac.png)

* **fy** –

垂直轴缩放因子,当取值为0时,则为:

![texttt{(double)dsize.height/src.rows}](http://docs.opencv.org/_images/math/d36ca0ad3e2c78f8c0f5c8c8bc6f368c87659c26.png)

* **interpolation** –

插值方法

* **INTER_NEAREST** - 最近邻值插入方法。
* **INTER_LINEAR** - 双线性插值(默认方式)。
* **INTER_AREA** -使用象素关系重采样。当图像缩小时候,该方法可以避免波纹出现。当图像放大时,类似于 CV_INTER_NN 方法。
* **INTER_CUBIC** -立方插值。
* **INTER_LANCZOS4** - 8x8的Lanczos插入方法。

准备样本数据

Mat data = Mat::zeros(total, 64, CV_32FC1);    //样本数据矩阵  
Mat res = Mat::zeros(total, 1, CV_32SC1);    //样本标签矩阵

res.at<double>(k, 1) = label;    //对第k个样本添加分类标签

//对第k个样本添加数据
for(int i = 0; i<8; i++)  {  
    for(int j = 0; j<8; j++)  {  
        res.at<double>(k, i * 8 + j) = dst.at<double>(i, j);  
    }  
}

将刚刚的结果,输入样本,并加上标签。

训练

CvSVM svm = CvSVM();   
CvSVMParams param;   
CvTermCriteria criteria;  

criteria= cvTermCriteria(CV_TERMCRIT_EPS, 1000,  FLT_EPSILON);   
param= CvSVMParams(CvSVM::C_SVC, CvSVM::RBF, 10.0, 8.0, 1.0, 10.0, 0.5, 0.1, NULL, criteria);   

svm.train(data, res, Mat(), Mat(), param);  
svm.save( "SVM_DATA.xml" );

开始训练并保存训练数据。

使用

CvSVM svm = CvSVM();   
svm.load( "SVM_DATA.xml" );
svm.predict(m);        //对样本向量m检测

参考资料

使用OPENCV训练手写数字识别分类器 . firefight .2011-05-28
原文链接: https://www.cnblogs.com/justany/archive/2012/11/27/2789767.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/70702

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月9日 下午2:28
下一篇 2023年2月9日 下午2:28

相关推荐