欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

摄像头识别手写数字

程序员文章站 2024-03-07 20:45:19
...

          最近在做一个项目主要是团队要做一个机器人,其中有个功能就是机器人能够坐电梯。为了实现这个功能首先就得识别电梯上的按钮,并识别出上面的数字,以便选择楼层。

       首先我想到的是手写数字的识别,虽然电梯上的按钮的数字是印刷体,可是如果能够识别手写数字,印刷体自然不在话下。

       一开始着手时,我想到的是先给出样本模版,当给定一个数字时,在所给定的模版中逐一通过像素去比对,找出最相近的模版,并返回这个模版的数值标签,这个标签就是这个数字的值。事与愿违,由于手写数字千变万化,比如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.编写启动摄像头。完成。

摄像头识别手写数字

摄像头识别手写数字