欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++編程模板匹配超詳細(xì)的識別手寫數(shù)字實現(xiàn)示例

 更新時間:2021年10月16日 11:06:27   作者:偷偷寫代碼  
大家好!本篇文章是關(guān)于手寫數(shù)字識別的,接下來我將在這里記錄我的手寫數(shù)字識別的從零到有,我在這里把我自己的寫代碼過程發(fā)出來,希望能幫到和我一樣努力求知的人

首先,本篇文章用到的方法是模板匹配,而不是基于神經(jīng)網(wǎng)絡(luò)的,還請各位注意了?。0迤ヅ溥€請自行了解,站上有很多介紹)我剛開始做實驗的時候只有一點c++基礎(chǔ),對于文件和opencv我一點都不了解,所以導(dǎo)致了我剛開始迷茫了很久,直到后來才漸漸做起來。廢話不多說,讓我們開始吧!

過程很簡單,如下:

匹配成功:存在一個最小距離(這些距離相等),且為一個數(shù)字;存在多個最小距離,且為同一個數(shù)字。

拒絕識別:存在多個最小距離,且為不同數(shù)字。

識別錯誤:存在一個最小距離,但與被測數(shù)字不是相同的數(shù)字。

也許乍一看看不明白,我在這里解釋一下,明白的可以繞過。我們這里假設(shè)1,2,3(注意,他們的樣本都有多個)為訓(xùn)練集,d為測試樣本。匹配時匹配到d與1距離最小且只與1距離最小,(可能與多個1的樣本距離最小或者只有一個)那么匹配成功;匹配時匹配到d與1和2的某個樣本都有最小距離,那么拒絕匹配;匹配時匹配到d(假如d是1的樣本)與2有最小距離,那么識別錯誤。

因為圖片處理不是本文章的主要內(nèi)容,我們跳過圖像處理步驟(有興趣的可以去看圖像處理這門課),直接給處理好的圖片。那么我們該如何構(gòu)建訓(xùn)練庫,又該如何讓計算機(jī)能夠識別我們的圖片呢?接下來我們來看看如何實現(xiàn)構(gòu)建訓(xùn)練庫。

我的實驗中有1000張訓(xùn)練樣本(200張測試樣本),既然要讓計算機(jī)能夠識別,那當(dāng)然是把圖片數(shù)字化。在圖像處理的步驟里,我們得到的訓(xùn)練樣本都是28*28像素點的圖片,可以想到28*28是一個不小的數(shù)量,為了提高處理速度,我們把圖片壓縮成7*7大小的,這樣即提高了處理速度,也方便我們寫代碼,因為7*7和4*4都是正方形。如下圖:

壓縮圖片:我們縱向遍歷7*7的方格,將里面像素大于127的小格子進(jìn)行計數(shù),當(dāng)其數(shù)量超過6(有的同學(xué)會覺得應(yīng)該是8,因為8是一半,但是8最終得到的正確率太低了,所以我找了一個合適的參數(shù))我們就把大格子對應(yīng)的7*7的二維數(shù)組的相應(yīng)位置設(shè)置為1,反之為0;然后再將數(shù)組轉(zhuǎn)換成字符串,這樣下來我們就會得到一個長度為49的字符串,這個字符串就是我們計算機(jī)匹配的核心。

另外,我是先把訓(xùn)練集和測試集分別數(shù)據(jù)化,再依次取出來作比較。也可以采用一邊遍歷測試集和處理,一遍作比較,我沒有輸出文件名,因為我采用的方式比較笨,代碼量也很多,主要是因為我之前寫完之后有很多bug,導(dǎo)致我不能成功運(yùn)行,所以我采用這種簡單代碼來避免錯誤,小伙伴們大可不必用這種方式!

值得注意的是,文件流的打開和關(guān)閉的時機(jī)也會很大程度上影響代碼運(yùn)行,這個問題困擾了我很久,希望大家引以為戒,代碼中具體位置我已經(jīng)標(biāo)出來了。(標(biāo)***的位置)另外,大家對于讀文件寫文件的文件流自己去了解,讀文件是ofstream,寫文件是ifstream,每次訪問文件都要打開文件和關(guān)閉文件。getline函數(shù)每次依次取一行數(shù)據(jù),所以我們在遍歷完一個文檔之前不會關(guān)閉文檔,也就不會再打開文檔。

最后我對我字符串比較做一個解釋,我是采用了一個標(biāo)志refused來標(biāo)志當(dāng)前字符串有沒有被拒絕識別,當(dāng)發(fā)現(xiàn)相似度(代碼中用total表示的)小于49的就把它賦值給相似度,并且把拒絕識別設(shè)置為假,直到找到最小的,當(dāng)找到最小的之后又找到了另一個相同相似度的,則判斷兩個樣本數(shù)字是不是相同的,不是的話就把refused設(shè)置為真,即在后面直接輸出拒絕識別。

我判斷兩個樣本是否為同一個數(shù)字是通過范圍比對,簡單地來說就是訓(xùn)練樣本的第0——99個對應(yīng)測試樣本的第0——19個,這是一個偷懶的辦法,我沒時間改代碼了所以就這樣代替了別人那種文本帶文件名的。(帶文件名比對時還需要去文件名)

其他的解釋我放在代碼里,有助于大家更直接的理解!

#include<iostream>
#include<fstream>
#include<opencv2/opencv.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/core.hpp>
#include<io.h>                          //api和結(jié)構(gòu)體
#include<string.h>
#include<string>
using namespace std;
using namespace cv;
void ergodicTest(string filename, string name);    //遍歷函數(shù)
string Image_Compression(string imgpath);          //壓縮圖片并返回字符串
int distance(string str1, string str2);            //對比函數(shù)不一樣的位數(shù)
void compare();
int turn(char a);
void main()
{
	const char* filepath = "E:\\learn\\vsfile\\c++project\\pictureData\\train-images";     
	ergodicTest(filepath,"train_num.txt");         //處理訓(xùn)練集
	const char* test_path= "E:\\learn\\vsfile\\c++project\\pictureData\\test-images";
	ergodicTest(test_path, "test_num.txt");
	compare();   
}
 
void ergodicTest(string filename,string name)       //遍歷并把路徑存到files
{
	string firstfilename = filename + "\\*.bmp";
	struct _finddata_t fileinfo;
	intptr_t handle;            //不能用long,因為精度問題會導(dǎo)致訪問沖突,longlong也可
	string rout = "E:\\learn\\vsfile\\c++project\\pictureData\\" + name;
	ofstream file;
	file.open(rout, ios::out);
	handle = _findfirst(firstfilename.c_str(), &fileinfo);
	if ( _findfirst(firstfilename.c_str(), &fileinfo) != -1)
	{
		do
		{
			file << fileinfo.name << ":" << Image_Compression(filename + "\\" + fileinfo.name) << endl;
		} while (!_findnext(handle, &fileinfo));
		file.close();
		_findclose(handle);
	}
}
string Image_Compression(string imgpath)   //輸入圖片地址返回圖片二值像素字符
{
	Mat Image = imread(imgpath);               //輸入的圖片
	cvtColor(Image, Image, COLOR_BGR2GRAY);
	int Matrix[28][28];                        //將digitization轉(zhuǎn)化為字符串類型
	for (int row = 0; row < Image.rows; row++)  //把圖片的像素點傳給數(shù)組
		for (int col = 0; col < Image.cols; col++)
		{
			Matrix[row][col] = Image.at<uchar>(row, col);
		}
	string img_str = "";                   //用來存儲結(jié)果字符串
	int x = 0, y = 0;
	for (int k = 1; k < 50; k++)
	{
		int total = 0;
		for (int q = 0; q < 4; q++)
			for (int p = 0; p < 4; p++)
				if (Matrix[x + q][y + p] > 127) total += 1;
		y = (y + 4) % 28;
		if (total >= 6) img_str += '1';    //將28*28的圖片轉(zhuǎn)化為7*7即壓縮
		else img_str += '0';
		if (k % 7 == 0)
		{
			x += 4;
			y = 0;
		}
	}
	return img_str;
}
 
int distance(string str1, string str2)  //比對兩個字符串有多少個不一樣
{
	int counts=0;
	for (int i = 0; i < str1.length(); i++)
	{
		if (str1[i] == str2[i]) continue;
		else counts++; 
	}
	return counts;
}
int turn(char a)
{
	stringstream str;
	int f = 1;
	str << a;
	str >> f;
	str.clear();
	return f;
}
 
void compare()
{
	ifstream train_data;//建立讀文件流
	ifstream test_data;
	string tmp1 = "";         //從train中取數(shù)據(jù)存在tmp1
	string tmp11 = "";
	string tmp2 = "";         //從test中取
	string tmp22 = "";
	bool refused = false; //拒絕識別標(biāo)志
	int tr_num = 0;       //用來存儲最小值的文件名(訓(xùn)練集)
	int num_refused = 0;   //拒絕識別個數(shù)
	int num_false = 0;     //識別錯誤個數(shù)
	int num_true = 0;      //正確識別個數(shù)
	test_data.open("E:\\learn\\vsfile\\c++project\\pictureData\\test_num.txt");
	for (int p = 0; p < 200; p++)
	{
		int total = 49;      //方便比大小,設(shè)置初值為49
		getline(test_data, tmp2);
		tmp22 = tmp2;    //在切割字符串之前保留,以便后面知曉該字符串是哪個數(shù)字的
		if(tmp2.length()==57) tmp2.erase(0,8); //erase函數(shù)是用來切割字符串的,這里是切割第0位的后面8位,存剩余的其他位
		else tmp2.erase(0,9);
		train_data.open("E:\\learn\\vsfile\\c++project\\pictureData\\train_num.txt");
		for (int j = 0; j < 1000; j++)         //一個測試樣本和所有訓(xùn)練樣本對比
		{
			getline(train_data, tmp1);
			tmp11 = tmp1;
			if (tmp1.length() == 57) tmp1.erase(0, 8);
			else tmp1.erase(0, 9);
			if (distance(tmp1, tmp2) < total)  //取最相近的
			{
				refused = false;   //拒絕識別被設(shè)置為否,即識別沒有被拒絕
				total = distance(tmp1, tmp2);
				tr_num = turn(tmp11[0]);          //記錄數(shù)字
			}
			else if(distance(tmp1, tmp2) == total && tr_num!= turn(tmp11[0]))  //發(fā)現(xiàn)相同相似度,且兩者歸屬的數(shù)字不同
			{
				refused = true;   //拒絕識別
				continue;          //循環(huán)繼續(xù)
			}	
		}
		train_data.close();
 
		if (!refused)
		{
			if (tr_num == turn(tmp22[0]))
			{
				//cout << tmp2[0] << endl;
				num_true++;
				cout << "識別為:" << tr_num << endl;
			}
			else
			{
				num_false++;
				cout << "識別錯誤!" << endl;
			}
		}
		else
		{
			num_refused++;
			cout << "拒絕識別!" << endl;
		}
	}
	test_data.close();
	double t = num_true / 200.0, f = num_false / 200.0, r = num_refused / 200.0;
	cout << "正確率為:" << t << endl;
	cout << "錯誤率為:" << f << endl;
	cout << "拒絕識別率為:" << r << endl;
}

代碼中有很多//注釋,都是我調(diào)試代碼用的,不用管。

我把遍歷文件夾的參考鏈接放在這里://www.dbjr.com.cn/article/225454.htm

另外,如有錯誤歡迎大家指正!

以上就是C++編程模板匹配超詳細(xì)的識別手寫數(shù)字實現(xiàn)示例的詳細(xì)內(nèi)容,更多關(guān)于C++編程模板匹配識別手寫數(shù)字的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Qt/C++編寫視頻監(jiān)控系統(tǒng)之自定義音柱顯示功能

    Qt/C++編寫視頻監(jiān)控系統(tǒng)之自定義音柱顯示功能

    通過音柱控件實時展示當(dāng)前播放的聲音產(chǎn)生的振幅的大小,得益于音頻播放組件內(nèi)置了音頻振幅的計算,可以動態(tài)開啟和關(guān)閉,開啟后會對發(fā)送過來的要播放的聲音數(shù)據(jù),這篇文章主要介紹了Qt/C++編寫視頻監(jiān)控系統(tǒng)之自定義音柱顯示功能,需要的朋友可以參考下
    2024-01-01
  • Cocos2d-x學(xué)習(xí)筆記之CCLayerColor層的使用實例

    Cocos2d-x學(xué)習(xí)筆記之CCLayerColor層的使用實例

    這篇文章主要介紹了Cocos2d-x學(xué)習(xí)筆記之CCLayerColor層的使用實例,CCLayerColor是一個顏色布景層類,本文依然使用Hello World作為例子講解,需要的朋友可以參考下
    2014-09-09
  • C++實現(xiàn)添加桌面右鍵新建菜單

    C++實現(xiàn)添加桌面右鍵新建菜單

    本文給大家匯總了3個版本的C++實現(xiàn)添加桌面右鍵新建菜單的代碼,陸陸續(xù)續(xù)寫的,有需要的小伙伴可以根據(jù)自己的需求來選擇
    2016-01-01
  • C語言系統(tǒng)調(diào)用約定

    C語言系統(tǒng)調(diào)用約定

    這篇文章介紹了C語言系統(tǒng)調(diào)用約定,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值。需要的朋友可以收藏下,方便下次瀏覽觀看
    2021-12-12
  • C++實現(xiàn)N個骰子的點數(shù)算法

    C++實現(xiàn)N個骰子的點數(shù)算法

    這篇文章主要介紹了C++實現(xiàn)N個骰子的點數(shù)算法,用兩種方法實現(xiàn)了該功能,是非常實用的技巧,需要的朋友可以參考下
    2014-09-09
  • win32 api實現(xiàn)2048游戲示例

    win32 api實現(xiàn)2048游戲示例

    這篇文章主要介紹了win32 api實現(xiàn)2048游戲示例,需要的朋友可以參考下
    2014-05-05
  • C++中的函數(shù)知識點大全

    C++中的函數(shù)知識點大全

    這篇文章介紹了C++中的函數(shù)知識點,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • C語言中你容易忽略的知識點與技巧總結(jié)

    C語言中你容易忽略的知識點與技巧總結(jié)

    這篇文章主要給大家介紹了關(guān)于C語言中你容易忽略的知識點與技巧,文中通過實例代碼以及圖文介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2022-03-03
  • C++控制臺繪圖頭文件實例代碼

    C++控制臺繪圖頭文件實例代碼

    控制臺(console)是電腦的最基本交互接口,通常包括鍵盤(keyboard)和屏幕(screen),下面這篇文章主要給大家介紹了關(guān)于C++控制臺繪圖頭文件的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-01-01
  • C++使用宏函數(shù)實現(xiàn)單例模板詳解

    C++使用宏函數(shù)實現(xiàn)單例模板詳解

    在我們?nèi)粘i_發(fā)中,無可避免需要使用單例模式進(jìn)行設(shè)計類對象。這篇文章主要介紹了如何使用宏函數(shù)實現(xiàn)單例模板,感興趣的小伙伴可以了解一下
    2023-02-02

最新評論