攝像頭識別手寫數字

          最近在作一個項目主要是團隊要作一個機器人,其中有個功能就是機器人可以坐電梯。爲了實現這個功能首先就得識別電梯上的按鈕,並識別出上面的數字,以便選擇樓層。算法

       首先我想到的是手寫數字的識別,雖然電梯上的按鈕的數字是印刷體,但是若是可以識別手寫數字,印刷體天然不在話下。網絡

       一開始着手時,我想到的是先給出樣本模版,當給定一個數字時,在所給定的模版中逐一經過像素去比對,找出最相近的模版,並返回這個模版的數值標籤,這個標籤就是這個數字的值。事與願違,因爲手寫數字變幻無窮,好比6,8,9這3個數字在進行像素比對時,所給測試數字因爲大小形狀問題,形成容易搞混的的狀況。函數

       在查找了許多資料後,發現有幾個方法去實現。基本都是特徵點加上分類器,或者神經網絡去解決。測試

       我選擇了HOG特徵+KNN的方法的實現這一功能。spa

       結果仍是不錯的的,識別率在90%以上。若是改成印刷體我相信識別率能夠很輕鬆達到99%,雖然我沒有去測試印刷體,但是印刷體比較比較固定。.net

       下面說說我實現的過程:指針

      1.製做訓練集,這個我就不用說的,網上能夠找到手寫數字的訓練集,或者本身手動寫,用手機拍照出來,反正我是後者。code

      2.找出圖像多是數字的部分,使用了findContours()這個函數找出圖像中擁有外邊框的圖形,並用這些圖形的外接矩形將這些圖形摳出來,並進行大小判斷,好比過小的排除掉,最後用一個容器保存起來。blog

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.在啓動攝像頭以前咱們還須要對圖像進行一些處理,好比模糊,降噪,二值化等等處理,其實這些處理要看具體狀況具體選擇,在這裏我就不展開描述了。get

      5.編寫啓動攝像頭。完成。