1. 程式人生 > >opencv 學習之 基於K近鄰的數字識別

opencv 學習之 基於K近鄰的數字識別

本文參考兩篇部落格,都對KNN思路做了詳細說明

(1) http://blog.csdn.net/wangyaninglm/article/details/17091901

(2) http://blog.csdn.net/xiaowei_cqu/article/details/23782561#

(3) http://download.csdn.net/download/hust_bochu_xuchao/9581796

個人對於K近鄰編碼實現的一點理解。主要基於第一篇,第三篇是將第一篇基於OpenCV2實現,可參考。

int  trainsamples;  每類樣本數

int  clesses;  樣本種類數

如數字識別,0-9計10個數字,則 clesses 為10,如果每個樣本庫中有100個樣本,如100個數字 0 樣本,則 trainsamples 為100.

Mat  traindata;  儲存樣本資料

mat  trainclass;  樣本標識

traindata = Mat(trainsamples*traincless,  templet_w*templet_h);

trainclass = Mat(trainsamples*traincless,  1);

將所有樣本資料儲存在 traindata 中,每個樣本轉換為 1*(w*h) 型矩陣,且二值化處理成只有 0 和 1 兩種畫素值模式

trainclass 儲存每類樣本標識,在 traindata 賦值過程中 賦值。如例 trainclass 為 1000*1 矩陣,那麼其前100行為0,最後100行為9

訓練直接呼叫 train() 函式即可

train(traindata, trainclass, Mat(), false, K);

Mat  testimg;  待測資料

float  result = CvKNearest::find_nearest(testimg, K)

上述為規模樣本採用K近鄰訓練識別的理解。

網上有一篇基於K近鄰的手寫字元識別,樣本是方形,實際中數字多為矩形。

第二篇部落格也同理

for (int i = 0; i < image.rows; ++i)
{  
	for (int j = 0; j < image.cols; ++j)
	{  
		const Mat sampleMat = (Mat_<float>(1,2) << i,j);  
		Mat response;  
		float result = knn.find_nearest(sampleMat,1);  
		if (result !=0)
		{  
			image.at<Vec3b>(j, i)  = green;  
		}  
		else    
		image.at<Vec3b>(j, i)  = blue;  
	}  
}

建立 512*512 大小的矩陣,生成10個樣本,實際為10對座標。

座標在0-256之間的,標籤為0,在256-512之間的,標籤為1.

將座標分類,非 0 類綠色,0 類藍色。


程式碼補充:

knnTest.h

#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <opencv2/ml/ml.hpp>

#include <iostream>

using namespace cv;
using namespace std;

class knnRec
{
public:
	knnRec();
	float digRec(Mat img);		//數字識別
	void  samTest();		//樣本訓練

private:
	char  folder[255];		//模板路徑
	int   sampl_num;		//每類樣本數
	int   class_num;		//樣本種類數
	Mat   trainData;		//樣本資料儲存矩陣
	Mat   trainClass;		//樣本類別儲存矩陣
	static const int K = 6;         //最大鄰居個數
	KNearest *	knn;
	void  getData();		//獲取樣本資料
	void  knnTrain();		//訓練
};


knnTest.cpp

#include "knnTest.h"

knnRec::knnRec()//建構函式
{
	sprintf(folder, "..\\pics\\Template\\");
	sampl_num = 10;	//訓練樣本,總共10個
	class_num = 10;	//暫時識別十個數字

	int samp_w = 14;	//模板的寬和高	
	int samp_h = 27;

	trainData.create(sampl_num*class_num, samp_w*samp_h, CV_32FC1);	//訓練資料的矩陣
	trainClass.create(sampl_num*class_num, 1, CV_32FC1);

	getData();
	knnTrain();
}

void knnRec::getData()
{
	char filepath[255];

	for (int i=0; i<class_num; i++)
	{
		for (int j=0; j<sampl_num; j++)
		{
			sprintf(filepath, "%s%d\\%d%d.bmp", folder, i,  i, j);

			Mat  sampl = imread(filepath, 0);
			if (sampl.empty())
			{
				printf("Error: Cant load image %s\n", filepath);
				return;
			}

			//將 MxN 矩陣 轉為 1x(MxN)
			Mat  templ = sampl.clone();
			sampl.release();
			sampl.create(1, templ.cols*templ.rows, CV_32FC1);
			//sampl 當前為1行,未初始化,templ 儲存 sampl 源資料
			float* data_sampl = sampl.ptr<float>(0);
			//確保模板均為二值圖,否則進行二值化
			for (int j = 0; j<templ.rows;  j++)
			{
				uchar * data_templ = templ.ptr<uchar>(j);
				for (int i = 0; i<templ.cols; i++)
				{
					if (data_templ[i] == 255) 
					{
						data_sampl[j*templ.rows + i] = 1;
					}
					else 
					{
						data_sampl[j*templ.rows + i] = 0;
					}
				}
			}

			//記錄模板資料
			float * data1 = trainData.ptr<float>(i*sampl_num+j);		//定位第 i 個類中第 j 個樣本
			float * data2 = sampl.ptr<float>(0);
			for (int k = 0; k < sampl.cols; k++)
			{
				data1[k] = data2[k];
			}

			//記錄模板標誌
			trainClass.at<float>(i*sampl_num+j, 0) = i;		//定位第 i 個類中第 j 個樣本,標為 i
		}
	}
}

void knnRec::knnTrain()
{    
	knn = new KNearest(trainData, trainClass, Mat(), false, K);
}

//數字識別,img 為數字區域
float knnRec::digRec(Mat src)
{	
	Mat knnImg; 
	knnImg.create(1, K, CV_32FC1);
		
	//處理輸入的影象
	Mat tmp = src.clone();
	src.release();
	src.create(1, tmp.cols*tmp.rows, CV_32FC1);
	float* data_src = src.ptr<float>(0);

	for (int j = 0; j<tmp.rows; j++)
	{
		uchar* data_tmp = tmp.ptr<uchar>(j);
		for (int i = 0; i<tmp.cols; i++)
		{
			if (data_tmp[i] == 255) 
			{
				data_src[j*tmp.rows + i] = 1;
			}
			else 
			{
					data_src[j*tmp.rows + i] = 0;
			}
		}
	}

	float result = knn->find_nearest(src, K, Mat(), knnImg, Mat());

	int checkNum = 0;
	for (int i = 0; i<K; i++)
	{
		if (knnImg.at<float>(0, i) == result)
		{
			checkNum++;
		}
	}
	float pre = 100 * ((float)checkNum / (float)K);

	return result;
}


說明:

呼叫之前,數字區域需完成處理,即完成裁剪、二值化等。

knnRec  rec;

double  result = rec.digRec(img);

相關推薦

opencv 學習 基於K近鄰數字識別

本文參考兩篇部落格,都對KNN思路做了詳細說明 (1) http://blog.csdn.net/wangyaninglm/article/details/17091901 (2) http://blog.csdn.net/xiaowei_cqu/article/detai

深度學習mnist手寫數字識別入門

使用tensorflow框架和python,學習實現簡單的神經網路,並進行調參,程式碼如下:   #! /usr/bin/python # -*- coding:utf-8 -*- """ a simple mnist classifier """ from __fut

【機器學習筆記】基於k-近鄰演算法的數字識別

更多詳細內容參考《機器學習實戰》 k-近鄰演算法簡介 簡單的說,k-近鄰演算法採用測量不同特徵值之間的距離方法進行分類。它的工作原理是:存在一個樣本資料集合,也稱作訓練樣本集,並且樣本集中每個資料都存在標籤,即我們知道樣本集中每個資料與所屬分類的對應關係。輸入沒

OpenCV手寫數字字元識別(基於k近鄰演算法)

公眾號:     老王和他的IT界朋友們 歡迎投稿:  [email protected] QQ交流群:  593683975 QQ群提供技術交流,CSDN資源,百度文庫等資源共享 加群問題:拋硬幣正面上的期望? 我們想用一段音樂,幾張圖片, 些

基於k近鄰(KNN)的手寫數字識別

作者:faaronzheng 轉載請註明出處! 最近再看Machine Learning in Action. k近鄰演算法這一章節提供了不少例子,本著Talk is cheap的原則,我們用手寫數字識別來實際測試一下。 簡單的介紹一下k近鄰演算法(KNN):給定測試樣本

OpenCV學習路——車牌識別車牌定位

pla sim srand oval 模糊 fault .html swa ide 去年七月份因為學校項目需要開始接觸圖像處理,但那時候只是到網上找車牌識別代碼,然後加入到自己的項目中,不清楚細節原理。 現在自己重新一步步實現車牌識別。 高斯模糊: 1 Mat Ga

K 近鄰演算法識別手寫數字(Numpy寫法)

在 Kaggle 上面的 Notebook 給可愛的學弟學妹們用於參考... 程式碼這個東西一定要自己多寫,我一邊聽著林宥嘉的《想自由》,一邊寫出了大致的實現。K 近鄰演算法大概做的是一件什麼事情呢?你去商店買衣服的時候,突然忘記了自己要買的衣服多大尺碼比較合適(S/M/L/XL 這種)。這個時候你就要找幾個

opencv——基於SVM的數字識別(3)

前兩篇文章寫了基於兩種特徵提取的SVM數字識別 https://blog.csdn.net/weixin_41721222/article/details/84953788 https://blog.csdn.net/weixin_41721222/article/details/84978

opencv學習四十三】K均值聚類演算法

K均值聚類演算法,在opencv中通過kmeans()函式實現;k均值通俗講:就是從一堆樣本中,隨便挑出幾個,比如3個吧,然後用樣本中的和這挑出來的比較,比較後排序,誰和挑出的那個接近就把他劃到那個類裡,比如樣A和挑1、挑2、挑3中,挑2最接近,則把樣A劃到挑2裡,當然還沒完

iOS開發opencv學習筆記四:使用feature2d識別圖片

使用過vuforia或者亮風臺的朋友應該知道,這兩個平臺對圖片的跟蹤的準備工作是很簡單的,只需要幾張樣本圖片就可以做了。 但是按照上篇的介紹,如果用CascadeClassifier進行物體跟蹤就需要非常非常多的樣本,那麼,要對圖片進行識別跟蹤就沒有像上面說的兩個平臺那樣

機器學習Tensorflow基於MNIST資料集識別自己的手寫數字(讀取和測試自己的模型)

更新: 以下為原博: 廢話不多說,先上效果圖 整體來看,效果是非常不錯的,模型的訓練,參照官方程式碼mnist_deep.py,準確率是高達99.2% 那麼,我是怎麼實現的呢? 一.讀懂卷積神經網路程式碼(至少得把程式跑通) 首先參照Tensorfl

opencv——基於SVM的數字識別(2)

上篇文章我們用的特徵是訓練樣本的所有畫素點值,雖然方便但不準確。 這篇文章主要介紹用SVM+HOG特徵對數字進行識別。 詳細請看上篇文章,它們主要區別在於訓練樣本HOG特徵的提取,其他基本一樣,所以我直接附上程式碼。 下面程式碼是opencv3和C++ 可以根據自己需要修改訓練樣本類

opencv——基於KNN的數字識別

KNN即K個最近鄰,網上有很多關於KNN的文章。我大概總結下核心:假設有A圖片,讓A與訓練樣本依次計算相似度(可用歐式距離),挑選出K個與A圖片相似度最大的圖片,這K個圖片中,哪種型別最多那麼定義A圖片也屬於該型別。 首先,需要有數字的訓練樣本 https://download.csdn.n

opencv——基於SVM的數字識別(1)

關於SVM的原理有很多優秀的視訊和資料,這裡我主要說下利用SVM對數字識別的具體應用 首先,需要有數字的訓練樣本 https://download.csdn.net/download/weixin_41721222/10784418 把0-9資料夾放入模版匹配樣本之中,自己可

opencv學習聚類與k均值聚類

在無監督學習中,資料不帶任何標籤。能找出資料內在分類規則,並分成獨立的點集(蔟),演算法稱為聚類演算法。 K均值聚類(K-means) K-均值是最普及的聚類演算法,演算法接受一個未標記的資料集,然

機器學習 使用python+OpenCV實現knn演算法手寫數字識別

基本上照搬了http://lib.csdn.net/article/opencv/30167的程式碼,只是改了一點bug和增加了一點功能輸入就是直接在一個512*512大小的白色畫布上畫黑線,然後轉化為01矩陣,用knn演算法找訓練資料中最相近的k個,現在應該是可以對所有字元

k-近鄰演算法--使用k-近鄰演算法識別手寫數字

listdir函式: os.listdir() 方法用於返回指定的資料夾包含的檔案或資料夾的名字的列表。返回指定路徑下的檔案和資料夾列表。 python文件: listdir(path=None)     Return a list containing the nam

【SVM理論到實踐4】基於OpenCv中的SVM的手寫體數字識別

//由於本人每天時間非常緊張,所以細節寫的不詳細,部落格僅供各位參考,裡面的程式碼都是執行過的,直接可以執行 本章的學習目標:      1)手寫體數字識別資料庫MNIST      2)基於SVM訓練的具體步驟   1)手寫體數字識別資料庫MNIST MNIST(Mixe

機器學習實戰精讀--------K-近鄰算法

機器學習 knn算法 k-近鄰算法對機器學習實戰的課本和代碼進行精讀,幫助自己進步。#coding:utf-8 from numpy import * import operator #運算符模塊 from os import listdir #os.listdir() 方法用於返回指定的文件夾包含的

機器學習實戰(一)k-近鄰算法

復雜 ssi bsp 體重 工具 等級 lap 問題 種類   轉載請註明源出處:http://www.cnblogs.com/lighten/p/7593656.html 1.原理   本章介紹機器學習實戰的第一個算法——k近鄰算法(k Nearest Neighbor