Opencv人工神经网络实现字母与数字识别流程

2024-06-17 16:38

本文主要是介绍Opencv人工神经网络实现字母与数字识别流程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • 1 人工神经网络简介
    • 1.1 人工神经元/神经网络模型
  • 2 字符特征提取
  • 3 Opencv的神经网络
    • 3.1 创建一个网络
    • 3.2 网络参数设置
    • 3.3 识别
  • 4 字体样本下载

人工神经网络简介

人工神经网络(Artificial Neural Network,ANN)简称神经网络(NN),是基于生物学中神经网络的基本原理,在理解和抽象了人脑结构和外界刺激响应机制后,以网络拓扑知识为理论基础,模拟人脑的神经系统对复杂信息的处理机制的一种数学模型。神经网络是一种运算模型,由大量的节点(或称神经元)之间相互联接构成。每个节点代表一种特定的输出函数,称为激活函数(activation function)。每两个节点间的连接都代表一个对于通过该连接信号的加权值,称之为权重(weight),神经网络就是通过这种方式来模拟人类的记忆。网络的输出则取决于网络的结构、网络的连接方式、权重和激活函数。

人工神经元/神经网络模型

神经元1.png神经元2.png


左边几个灰底圆中所标字母w代表浮点数,称为权重(weight,或权值,权数)。进入人工神经细胞的每一个input(输入)都与一个权重w相联系,正是这些权重将决定神经网络的整体活跃性。你现在暂时可以设想所有这些权重都被设置到了-1和1之间的一个随机小数。因为权重可正可负,故能对与它关联的输入施加不同的影响,如果权重为正,就会有激发(excitory)作用,权重为负,则会有抑制(inhibitory)作用。当输入信号进入神经细胞时,它们的值将与它们对应的权重相乘,作为图中大圆的输入。大圆的‘核’是一个函数,叫激励函数(activation function),它把所有这些新的、经过权重调整后的输入全部加起来,形成单个的激励值(activation value)。激励值也是一浮点数,且同样可正可负。然后,再根据激励值来产生函数的输出也即神经细胞的输出:如果激励值超过某个阀值(作为例子我们假设阀值为1.0),就会产生一个值为1的信号输出;如果激励值小于阀值1.0,则输出一个0。这是人工神经细胞激励函数的一种最简单的类型。在这里,从激励值产生输出值是一个阶跃函数.

字符特征提取

在深度学习(将特征提取作为训练的一部分)这个概念引入之前,一般在准备分类器进行识别之前都需要进行特征提取。因为一幅图像包含的内容太多,有些信息能区分差异性,而有些信息却代表了共性。所以我们要进行适当的特征提取把它们之间的差异性特征提取出来。

这里面我们计算二种简单的字符特征:梯度分布特征、灰度统计特征。这两个特征只是配合本篇文章来说明神经网络的普遍用法,实际中进行字符识别需要考虑的字符特征远远要比这复杂,还包括相似字特征的选取等,也由于工作上的原因,这一部分并不深入的介绍。

1,首先是梯度分布特征,该特征计算图像水平方向和竖直方向的梯度图像,然后通过给梯度图像分划不同的区域,进行梯度图像每个区域亮度值的统计,以下是算法步骤:

<1>将字符由RGB转化为灰度,然后将图像归一化到16*8。

<2>定义soble水平检测算子: 和竖直方向梯度检测算子 。

<3>对图像分别用 和 进行图像滤波得到 和 ,下图分别代表原图像、 和 。

<4>对滤波后的图像,计算图像总的像素和,然后划分4*2的网络,计算每个网格内的像素值的总和。

<5>将每个网络内总灰度值占整个图像的百分比统计在一起写入一个向量,将两个方向各自得到的向量并在一起,组成特征向量。

2,第二个特征非常简单,只需要将图像归一化到特定的大小,然后将图像每个点的灰度值作为特征即可。

<1>将图像由RGB图像转换为灰度图像;

<2>将图像归一化大小为 ,并将图像展开为一行,组成特征向量。

Sample Code (以下代码使用的是 Opencv 3.0环境)

float sumMatValue(const Mat & image){float sumValue = 0;int r = image.rows;int c = image.cols;if(image.isContinuous()){c = r*c;r = 1;	}for(int i = 0; i < r; i++){const uchar *linePtr = image.ptr<uchar>(i);for (int j = 0; j < c; j++){sumValue += linePtr[j];}	}return sumValue;
}
void calcGradientFeat(Mat & imgSrc, vector<float> & feat){Mat image;cvtColor(imgSrc, image, CV_BGR2GRAY);resize(image, image, Size(8,16));float mask[3][3] = {{1,2,1},{0,0,0},{-1,-2,-1}};      Mat y_mask = Mat(3,3, CV_32F, mask) / 8;Mat x_mask = y_mask.t(); // 转置Mat sobelX, sobelY;filter2D(image, sobelX, CV_32F, x_mask); filter2D(image, sobelY, CV_32F, y_mask);sobelX = abs(sobelX);sobelY = abs(sobelY);float totleValueX = sumMatValue(sobelX);float totleValueY = sumMatValue(sobelY);for(int i = 0; i < image.rows; i = i +4){for( int j = 0; j < image.cols; j = j + 4){Mat subImageX = sobelX(Rect(j, i, 4, 4));feat.push_back(sumMatValue(subImageX) / totleValueX);Mat subImageY= sobelY(Rect(j, i, 4, 4)); feat.push_back(sumMatValue(subImageY) / totleValueY); }	   	}	Mat img2;resize(image, img2, Size(4,8));int r = img2.rows;int c = img2.cols;if(img2.isContinuous()){c = r*c;r = 1;	}for(int i = 0; i < r; i++){const uchar *linePtr = img2.ptr<uchar>(i);for (int j = 0; j < c; j++){feat.push_back(linePtr[j]);}	}	
}

Opencv的神经网络

CvANN_MLP是OpenCV中提供的一个神经网络的类,正如它的名字一样(multi-layer perceptrons),它是一个多层感知网络,它有一个输入层,一个输出层以及1或多个隐藏层。

创建一个网络

Ptr<StatModel> buildMLPClassifier(Mat & input , Mat & output){Ptr<ANN_MLP> model;//train classifier;int layer_sz[] = {input.cols, 100 , output.cols};int nlayers = (int)(sizeof(layer_sz)/ sizeof(layer_sz[0]));Mat layer_sizes(1,nlayers,CV_32S, layer_sz);int method;double method_param;int max_iter;if(1){method = ANN_MLP::BACKPROP;method_param = 0.0001;max_iter = 1000;}else{method = ANN_MLP::RPROP;method_param = 0.1;max_iter = 1000;}Ptr<TrainData> tData = TrainData::create(input,ROW_SAMPLE,output);model = ANN_MLP::create();model->setLayerSizes(layer_sizes);model->setActivationFunction(ANN_MLP::SIGMOID_SYM, 0, 0);model->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, max_iter, FLT_EPSILON));//setIterCondition(max_iter, 0);model->setTrainMethod(method, method_param);model->train(tData);model->save("mlp1.xml");return model;
}
}
layerSizes:一个整型的数组,这里面用Mat存储。它是一个1*N的Mat,N代表神经网络的层数,第 列的值表示第 层的结点数。这里需要注意的是,在创建这个Mat时,一定要是整型的,uchar和float型都会报错。

比如我们要创建一个3层的神经网络,其中第一层结点数为 ,第二层结点数为 ,第三层结点数为 ,则layerSizes可以采用如下定义:

1 Mat layerSizes=(Mat_<int>(1,3)<<x1,x2,x3);

或者用一个数组来初始化:

1 int ar[]={x1,x2,x3}; 2 Mat layerSizes(1,3,CV_32S,ar);

activateFunc:这个参数用于指定激活函数,不熟悉的可以去看我博客里的这篇文章《神经网络:感知器与梯度下降》,一般情况下我们用SIGMOID函数就可以了,当然你也可以选择正切函数或高斯函数作为激活函数。OpenCV里提供了三种激活函数,线性函数(CvANN_MLP::IDENTITY)、sigmoid函数(CvANN_MLP::SIGMOID_SYM)和高斯激活函数(CvANN_MLP::GAUSSIAN)。

后面两个参数则是SIGMOID激活函数中的两个参数 和 ,默认情况下会都被设置为1。

网络参数设置

神经网络训练参数的类型存放在CvANN_MLP_TrainParams这个类里,它提供了一个默认的构造函数,我们可以直接调用,也可以一项一项去设。

 1 CvANN_MLP_TrainParams::CvANN_MLP_TrainParams() 2 { 3     term_crit = cvTermCriteria( CV_TERMCRIT_ITER + CV_TERMCRIT_EPS, 1000, 0.01 ); 4     train_method = RPROP; 5     bp_dw_scale = bp_moment_scale = 0.1; 6     rp_dw0 = 0.1; rp_dw_plus = 1.2; rp_dw_minus = 0.5; 7     rp_dw_min = FLT_EPSILON; rp_dw_max = 50.; 8 }

它的参数大概包括以下几项。

term_crit:终止条件,它包括了两项,迭代次数(CV_TERMCRIT_ITER)和误差最小值(CV_TERMCRIT_EPS),一旦有一个达到条件就终止训练。

train_method:训练方法,OpenCV里提供了两个方法一个是很经典的反向传播算法BACKPROP,另一个是弹性反馈算法RPROP,对第二种训练方法,没有仔细去研究过,这里我们运用第一种方法。

剩下就是关于每种训练方法的相关参数,针对于反向传播法,主要是两个参数,一个是权值更新率bp_dw_scale和权值更新冲量bp_moment_scale。这两个量一般情况设置为0.1就行了;太小了网络收敛速度会很慢,太大了可能会让网络越过最小值点。

我们一般先运用它的默认构造函数,然后根据需要再修改相应的参数就可以了。如下面代码所示,我们将迭代次数改为了5000次。

1 CvANN_MLP_TRainParams param; 2 param.term_crit=cvTermCriteria(CV_TerMCrIT_ITER+CV_TERMCRIT_EPS,5000,0.01);

inputs:输入矩阵。它存储了所有训练样本的特征。假设所有样本总数为nSamples,而我们提取的特征维数为ndims,则inputs是一个 的矩阵,我们可以这样创建它。

1 Mat inputs(nSamples,ndims,CV_32FC1); //CV_32FC1说明它储存的数据是float型的。

我们需要将我们的训练集,经过特征提取把得到的特征向量存储在inputs中,每个样本的特征占一行。

outputs:输出矩阵。我们实际在训练中,我们知道每个样本所属的种类,假设一共有nClass类。那么我们将outputs设置为一个nSample行nClass列的矩阵,每一行表示一个样本的预期输出结果,该样本所属的那类对应的列设置为1,其他都为0。比如我们需要识别0-9这10个数字,则总的类数为10类,那么样本数字“3”的预期输出为[0,0,1,0,0,0,0,0,0,0];

sampleWeights:一个在使用RPROP方法训练时才需要的数据,所以这里我们不设置,直接设置为Mat()即可。

sampleIdx:相当于一个遮罩,它指定哪些行的数据参与训练。如果设置为Mat(),则所有行都参与。

params:这个在刚才已经说过了,是训练相关的参数。

flag:它提供了3个可选项参数,用来指定数据处理的方式,我们可以用逻辑符号去组合它们。UPDATE_WEIGHTS指定用一定的算法去初始化权值矩阵而不是用随机的方法。NO_INPUT_SCALE和NO_OUTPUT_SCALE分别用于禁止输入与输出矩阵的归一化。

一切都准备好后,直接开始训练吧!

识别

Ptr<StatModel> model = buildMLPClassifier(input, output);//Ptr<StatModel> model = loadMLPClassifiler();float response = model->predict(test, test1);cout<<"response = "<<response<<endl;for(int i = 0; i < test1.size(); i++){cout<<"test1 = "<<test1[i]<<endl;	}
识别返回的response 就是预测的值,test1 里面存放的是每个字母的可能概率

完整代码:

  int main(){Mat image;vector<float>feats;vector<float>test,test1;string path = "code/python_image_learn/identfying_code_recognize/charSamples/";int num = 0;int classfilternum = 34;int modlenum = 30;for(int i = 0 ; i < classfilternum ; i++){for(int j = 0; j < modlenum; j++){ostringstream oss;oss<<path<<i<<"/"<<j<<".png";//cout<<oss.str()<<endl;image=imread(oss.str());calcGradientFeat(image, feats);num++;if(i == 10 && j == 10){ostringstream oss; oss<<path<<i<<"/"<<(j+1)<<".png";//cout<<oss.str()<<endl;image=imread(oss.str());calcGradientFeat(image, test);			}	}}	Mat input, output;	input = Mat(classfilternum*modlenum, 48, CV_32F);output = Mat(classfilternum*modlenum, classfilternum, CV_32F, Scalar(0));int r = input.rows;int c = input.cols;if(input.isContinuous()){c = r*c;r = 1;}for(int i = 0; i < r; i++){float *linePtr = input.ptr<float>(i);for (int j = 0; j < c; j++){linePtr[j] = feats[c*i + j];}	}for(int i = 0; i < output.rows; i++){float *lineoutput = output.ptr<float>(i);lineoutput[i/modlenum] = 1;}	//if(Ptr<StatModel> model = buildMLPClassifier(input, output);//Ptr<StatModel> model = loadMLPClassifiler();float response = model->predict(test, test1);cout<<"response = "<<response<<endl;for(int i = 0; i < test1.size(); i++){cout<<"test1 = "<<test1[i]<<endl;	}//cout<<input<<endl;//cout<<"rows = "<<input.rows<<"col = "<<input.cols<<endl;//cout<<output<<endl;
//	waitKey();                    //等待按键return 0;}

字符样本的下载

链接:http://pan.baidu.com/s/1pLPeZkZ 密码:26eb


这篇关于Opencv人工神经网络实现字母与数字识别流程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1069984

相关文章

Security OAuth2 单点登录流程

单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,但是又是各自独立的软件系统,提供访问控制的属性。当拥有这项属性时,当用户登录时,就可以获取所有系统的访问权限,不用对每个单一系统都逐一登录。这项功能通常是以轻型目录访问协议(LDAP)来实现,在服务器上会将用户信息存储到LDAP数据库中。相同的,单一注销(single sign-off)就是指

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

从去中心化到智能化:Web3如何与AI共同塑造数字生态

在数字时代的演进中,Web3和人工智能(AI)正成为塑造未来互联网的两大核心力量。Web3的去中心化理念与AI的智能化技术,正相互交织,共同推动数字生态的变革。本文将探讨Web3与AI的融合如何改变数字世界,并展望这一新兴组合如何重塑我们的在线体验。 Web3的去中心化愿景 Web3代表了互联网的第三代发展,它基于去中心化的区块链技术,旨在创建一个开放、透明且用户主导的数字生态。不同于传统

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

阿里开源语音识别SenseVoiceWindows环境部署

SenseVoice介绍 SenseVoice 专注于高精度多语言语音识别、情感辨识和音频事件检测多语言识别: 采用超过 40 万小时数据训练,支持超过 50 种语言,识别效果上优于 Whisper 模型。富文本识别:具备优秀的情感识别,能够在测试数据上达到和超过目前最佳情感识别模型的效果。支持声音事件检测能力,支持音乐、掌声、笑声、哭声、咳嗽、喷嚏等多种常见人机交互事件进行检测。高效推

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo