1. 程式人生 > >opencv數字識別

opencv數字識別

這是基於opencv寫的數字識別程式 對於記事本里的宋體常規數字能夠完美的識別

思路:   放大圖片→灰度化→二值化→開運算→尋找外輪廓→輪廓排序→遍歷畫素與模板匹配→得到數字

最後為了驗證識別率,讀入txt檔案與識別圖片後的輸出結果對比

總結:

1.圖片放大可以把各個數字分開一點,防止數字黏在一起導致找輪廓時出錯

2.開運算,進一步把各個數字分開  開運算(膨脹->腐蝕)//去除影象中較小區域

3.尋找外輪廓,必須是外輪廓,不可以找所有輪廓,這樣就可以等到各個數字

4.根據輪廓找出各個輪廓的最小矩形

5.根據最小矩形左上角的座標為各個矩形排序,這樣就可以知道各個字元輸出順序了

6,.把事先分割好的模板圖片進行匹配(把這個程式改改就可以成一個分割數字的程式了)

7.最後讀入txt檔案與圖片輸出結果對比

#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<iostream>

#include <fstream>
#include <cassert>
#include <string>
using namespace std;
using namespace cv;

const int NUM = 10000;
#define WINDOW_NAME "二值圖"
int g_nThreshold = 200;
static void on_Threshold(int, void*);
void getNumber();//分割字元
char getNumChar(Mat&);//識別單個字元圖片

Mat g_srcImage, gray, image_threshold;
Mat open;

char result_num[NUM];//txt檔案中的數字
char result_true[NUM];//識別後的數字

/*讀取txt檔案*/
void readTxt(string file)
{
	ifstream infile;
	infile.open(file.data());   //將檔案流物件與檔案連線起來 
	assert(infile.is_open());   //若失敗,則輸出錯誤訊息,並終止程式執行 
	int i = 0;
	char c;
	while (!infile.eof())
	{
		infile >> c;
		result_true[i] = c;
		result_true[i + 1] = '\0';
		i++;
	}
	infile.close();
}
int main()
{
	readTxt("123.txt");
	cout << "檔案值為:";
	for (unsigned int i = 0; i < strlen(result_true)-1; i++)//讀取txt輸出數字
	{
		cout << result_true[i];
	}
	cout << endl;
	g_srcImage = imread("1.png");
	//放大原圖,圖片太小數字可能會連在一起
	resize(g_srcImage, g_srcImage, Size(g_srcImage.cols * 2, g_srcImage.rows * 2), 0, 0, INTER_LINEAR);
	cvtColor(g_srcImage, gray, COLOR_BGR2GRAY);
	namedWindow(WINDOW_NAME, WINDOW_AUTOSIZE);
	createTrackbar("閾值", WINDOW_NAME, &g_nThreshold, 255, on_Threshold);
	on_Threshold(g_nThreshold, 0);
	waitKey(0);
	return 0;
}

/*閾值操作*/
static void on_Threshold(int, void*)
{
	threshold(gray, image_threshold, g_nThreshold, 255, 1);
	imshow(WINDOW_NAME, image_threshold);
	Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));
	morphologyEx(image_threshold, open, MORPH_OPEN, element);//開運算,防止圖片連在一起
	getNumber();
}

/*單字元識別*/
char getNumChar(Mat &temp)
{
	int min = 10000;
	int min_i = 0;
	int total = 0;
	for (int n = 0; n < 10; n++)//n對應圖片n.jpg
	{
		total = 0;
		char a[100];
		sprintf(a, "number/%d.jpg", n);//讀取number模板資料夾圖片,名字對應數字
		string name = a;
		Mat match = imread(name); 
		cvtColor(match, match, COLOR_BGR2GRAY);
		threshold(match, match, 254, 255, 1);
		resize(temp, temp, match.size(), 0, 0, INTER_LINEAR);//轉換圖片大小和模板圖片一樣
		for (int i = 0; i < match.rows; i++)//遍歷所有畫素與n.jpg對比
		{
			uchar *data_match = match.ptr<uchar>(i);
			uchar *data_temp = temp.ptr<uchar>(i);
			for (int j = 0; j < match.cols; j++)
			{
				if (*data_match == *data_temp)
				{
					total++;
				}
				*data_match++;
				*data_temp++;
			}
		}
		//讀入的圖片二值化後與原圖二值化相同畫素為0
		//讀入的圖片二值化與程式執行過程中二值化的產生圖片剛好相反
		//所以相同的畫素越少圖片相似度越高
		//在這裡match二值化後與temp二值化圖相反即黑白正好顛倒了
		if (total < min)
		{
			min = total;
			min_i = n;	
		}
	}
	char a = min_i+'0';
	return a;
}

/*字元分割*/
void getNumber()
{
	Mat image_threshold_clone = image_threshold.clone();
	vector<vector<Point>>contours;
	vector<Vec4i>hierarchy;
	findContours(image_threshold_clone, contours, hierarchy,
		CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);//找出圖片外輪廓,不要連內輪廓也找出來
	int contour_size = contours.size();
	int average_height = 0;
	int count = 0;
	Rect rc[NUM];
	int min_y =100000;
	int max_y = 0;
	//找出字元平均高度,最上方的數字的y,最下方的數字的y
	for (int i = 0; i < contour_size; i++)
	{
		rc[i] = boundingRect(contours.at(i));
		
		if (rc[i].y<min_y)
		{
			min_y = rc[i].y;
		}
		if (rc[i].y>max_y)
		{
			max_y = rc[i].y;
		}
		average_height += rc[i].height;
		
	}
	average_height /= contour_size;
	Rect sort_rc[NUM];
	Rect rc_y[NUM];
	int _t = 0;
	//由於輪廓順序不是字元順序所以要排序,主要根據矩形左上方座標排序
	//排序從上到下,從左到右,每隔一個字元高度獲取一次,當超出圖片邊界時停止
	for (int n = 0;; n++)
	{
		int t = 0;
		for (int i = 0; i < contour_size; i++)
		{
			if (min_y - average_height*0.5 < rc[i].y&& rc[i].y < min_y + average_height*0.5)
			{
				rc_y[t] = rc[i];
				t++;
			}
		}
		if (min_y>max_y)
		{
			break;
		}
		if (t == 0)
		{
			_t += t;
			min_y += average_height;
			continue;
		}
		for (int i = 0; i < t; i++)
		{
			for (int j = i+1; j < t; j++)
			{
				if (rc_y[i].x>rc_y[j].x)
				{
					Rect temp = rc_y[i];
					rc_y[i] = rc_y[j];
					rc_y[j] = temp;
				}
			}
		}
		for (int i = 0; i < t; i++)
		{
			sort_rc[i + _t] = rc_y[i];
		}
		_t += t;
		min_y += average_height;
	}
	//把排序後的圖片一一識別
	for (int i = 0; i < contour_size; i++)
	{
		Mat ROI = image_threshold(sort_rc[i]);
		resize(ROI, ROI, Size(40, 56), 0, 0, INTER_LINEAR);
		result_num[i] = getNumChar(ROI);
		result_num[i + 1] = '\0';
	}
	//與txt檔案的數字進行比較
	int equal_num = 0;
	cout << "結果值為:";
	for (unsigned int i = 0; i < strlen(result_num); i++)
	{
		cout << result_num[i];
		if (result_num[i] == result_true[i])
			equal_num++;
	}
	cout << "\n字元數為:" << contour_size << endl;
	cout << "正確率為:" << (double)equal_num / contour_size *100<<"%"<< endl;
}




以下為輸出結果:


當然識別數字後你想幹嘛 就是你自己的是了

相關推薦

opencv數字識別

這是基於opencv寫的數字識別程式 對於記事本里的宋體常規數字能夠完美的識別 思路:   放大圖片→灰度化→二值化→開運算→尋找外輪廓→輪廓排序→遍歷畫素與模板匹配→得到數字 最後為了驗證識別率,讀入txt檔案與識別圖片後的輸出結果對比 總結: 1.圖片放大可以把各個數字

Java基於opencv實現圖像數字識別(一)

binary oid ring 是把 sca pre 內存 還需要 自己 Java基於opencv實現圖像數字識別(一) 最近分到了一個任務,要做數字識別,我分配到的任務是把數字一個個的分開;當時一臉懵逼,直接百度java如何分割圖片中的數字,然後就百度到了用Buffere

Java基於opencv實現圖像數字識別(二)—基本流程

數字 都是 模型 PE 設計 category 理解 兩種 ace Java基於opencv實現圖像數字識別(二)—基本流程 做一個項目之前呢,我們應該有一個總體把握,或者是進度條;來一步步的督促著我們來完成這個項目,在我們正式開始前呢,我們先討論下流程。 我做的主要是表格

基於opencv數字識別

    最近學習了opencv,然後想通過其對圖片上的數字進行識別,參考了網上幾篇關於opencv數字識別的部落格,我自己也寫了一個程式玩玩。我是在vs2017和opencv3.4.1環境下實現的。     這裡先說一下我的思路和步驟:

OpenCV實現0到9數字識別OCR

使用OpenCV對0到9數字進行識別,實現簡單OCR功能,基於CA(輪廓)分析實現特徵提取,基於L1距離計算匹配實現數字識別。在排除干擾的基礎上,識別精度可以達到98%以上。整個演算法分為兩個部分,第一部分是特徵提取,提取的特徵實現了尺度不變性與輕微光照與變形干擾排除,第二部分基於特徵資料進行匹配實

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

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

OpenCV機器學習:SVM分類器實現MNIST手寫數字識別

0. 開發環境 最近機器學習隨著AI人工智慧的興起越來越火,博主想找一些ML的庫來練手。突然想起之前在看Opencv的doc時發現有ML的component,於是心血來潮就開始寫程式碼試試。話不多說,直接進正題。 以下我的開發環境配置: -Windows7

基於opencv的手寫數字識別(MFC,HOG,SVM)

因為本程式是提取HOG特徵,使用SVM進行分類的,所以大概瞭解下HOG的一些知識,其中我覺得怎麼計算影象HOG特徵的維度會對程式瞭解有幫助 關於HOG,我們可以參考: http://gz-ricky.blogbus.com/logs/85326

opencv svm 識別自己寫的手寫數字

int main() {     Mat src, gray,medblurImg,threImg;     Mat structElem,eroImg,dilateImg,cannyImg;     src = imread("test.jpg");     cvtColo

基於Tensorflow, OpenCV. 使用MNIST資料集訓練卷積神經網路模型,用於手寫數字識別

基於Tensorflow,OpenCV 使用MNIST資料集訓練卷積神經網路模型,用於手寫數字識別 一個單層的神經網路,使用MNIST訓練,識別準確率較低 兩層的卷積神經網路,使用MNIST訓練(模型使用MNIST測試集準確率高於99%

[機器學習]基於OpenCV實現最簡單的數字識別

http://blog.csdn.net/jinzhuojun/article/details/8579416 本文將基於OpenCV實現簡單的數字識別。這裡以遊戲Angry Birds為例,通過以下幾個主要步驟對其中右上角的分數部分進行自動識別。 1. 學習分類器 根據

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的數碼管數字識別

利用OpenCV可實現工業儀表裝置的讀數識別。儀表一般可分為兩:數字式儀表和指標式儀表,本博文主要介紹一下數字式儀表識別的關鍵技術。下圖是用軟體模擬的數碼管圖片,本文識別的也就是圖中的數字。 一、影象定位 在實際的應用場景中,拍攝到的儀表區域很有可能會包含多

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

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

Java應用OpenvCV指南其六:利用OpenCV實現的數字識別(驗證碼識別

  之前介紹了很多概念上的東西,這次讓我們來進行一次實際的應用。數字識別可以應用在許多領域,如數字型驗證碼的識別,車牌識別等領域。下面借我之前完成的一個數字驗證碼識別的小專案來簡單認識一下圖象識別領域的知識。   如果在閱讀這篇文章時有什麼疑問,可以參考一下之

OpenCV玩九宮格數獨(二):knn數字識別

前言 首先需要說明,這裡所說的數字識別不是手寫數字識別! 但凡對機器學習有所瞭解的人,相信看到數字識別的第一反應就是MNIST。MNIST是可以進行數字識別,但是那是手寫數字。我們現在要做的是要識別從九宮格圖片中提取出來的印刷體的數字。手寫數字集訓練出來的模

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

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

Opencv手寫數字識別_Opencv3.0+KNN+HOG特徵_原始碼_MAC_OS環境搭建視訊教程.

  寫在前面   最近在學習Opencv,本人android開發狗,對Opencv純屬興趣。一個破本科畢業的我,發現智商完全不夠用,書到用是方恨少,都怪自己數學太渣。好在Opencv封裝得比較好,如果只是使用的話,大概知道原理就知道該怎麼用。經過學習總結,寫了一個小Demo,