摄像头识别手写数字
最近在做一个项目主要是团队要做一个机器人,其中有个功能就是机器人能够坐电梯。为了实现这个功能首先就得识别电梯上的按钮,并识别出上面的数字,以便选择楼层。
首先我想到的是手写数字的识别,虽然电梯上的按钮的数字是印刷体,可是如果能够识别手写数字,印刷体自然不在话下。
一开始着手时,我想到的是先给出样本模版,当给定一个数字时,在所给定的模版中逐一通过像素去比对,找出最相近的模版,并返回这个模版的数值标签,这个标签就是这个数字的值。事与愿违,由于手写数字千变万化,比如6,8,9这3个数字在进行像素比对时,所给测试数字由于大小形状问题,造成容易搞混的的情况。
在查找了许多资料后,发现有几个方法去实现。基本都是特征点加上分类器,或者神经网络去解决。
我选择了HOG特征+KNN的方法的实现这一功能。
结果还是不错的的,识别率在90%以上。如果改为印刷体我相信识别率可以很轻松达到99%,虽然我没有去测试印刷体,可是印刷体比较比较固定。
下面说说我实现的过程:
1.制作训练集,这个我就不用说的,网上可以找到手写数字的训练集,或者自己手动写,用手机拍照出来,反正我是后者。
2.找出图像可能是数字的部分,使用了findContours()这个函数找出图像中拥有外边框的图形,并用这些图形的外接矩形将这些图形抠出来,并进行大小判断,比如太小的排除掉,最后用一个容器保存起来。
vector<vector<Point>> contours;//点容器的容器,用于存放轮廓的点的容器的容器
vector<Vec4i> hierarchy;//点的指针容器
Mat cut_ROI(Mat src)
{
contours.clear();
hierarchy.clear();
Mat dst, tmp;
src.copyTo(dst);
blur(dst, dst, Size(3, 3));
//GaussianBlur(dst, dst, Size(3, 3), 0.5, 0.5);
//medianBlur(dst, dst, 3);
threshold(dst, tmp, 120, 255, CV_THRESH_BINARY_INV);
findContours(tmp, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
vector<vector<Point>>::iterator It;
for (It = contours.begin(); It < contours.end(); It++)
{ //画出可包围数字的最小矩形
rect = boundingRect(*It);
Mat roi = src(rect);
roi.copyTo(_roi);//深拷贝出来
weigth = rect.br().x - rect.tl().x;//宽
height = rect.br().y - rect.tl().y;//高
if ((weigth < height) && (height > 10))
{
rectangle(src, rect, Scalar(255, 255, 255), 2);
ROI.push_back(_roi);//保存,方便操作
ROIposition.push_back(rect);
Mat pre;
resize(_roi, pre, Size(128, 128));
}
}
return src;
}
3.KNN识别。KNN就是将训练集分类好,给出测试样本,求这个测试样本到其他训练集的欧几里德距离的一种算法,并求出在前K(一般是K=5)位的最近距离中占比最高的数据属于哪一个训练样本,返回训练样本的标签即可。比如测试样本中距离前5位最近的训练样本的标签是{5,6,5,5,6}那么这个可以得出结果就是这个测试样本是5.不懂的话可以看我上一篇博客。KNN邻近算法。4.在启动摄像头之前我们还需要对图像进行一些处理,比如模糊,降噪,二值化等等处理,其实这些处理要看具体情况具体选择,在这里我就不展开描述了。
5.编写启动摄像头。完成。
上一篇: 如何用PHP做到页面注册审核
下一篇: KNN实现手写数字识别