OpenCV进阶之路:神经网络识别车牌字符

1. 关于OpenCV进阶之路

前段时间写过一些关于OpenCV基础知识方面的系列文章,主要内容是面向OpenCV初学者,介绍OpenCV中一些常用的函数的接口和调用方法,相关的内容在OpenCV的手册里都有更详细的解释,当时自己也是边学边写,权当为一种笔记的形式,所以难免有浅尝辄止的感觉,现在回头看来,很多地方描述上都存在不足,以后有时间,我会重新考虑每一篇文章,让成长系列对基础操作的介绍更加详细一些。

OpenCV进阶之路相比于成长系列,不会有太多的基础函数的介绍,相对来说会更偏向于工程实践,通过解决实际问题来说明某些较高级函数的用法和注意事项,主要内容会集中在特征提取、机器学习和目标跟踪几个方向。所以这个系列文章知识点没有先后顺序之分,根据个人平时工作学习中遇到的问题而定。

这篇文章主要介绍OpenCV中神经网络的用法,并通过车牌字符的识别来说明一些参数设置,函数调用顺序等,而关于神经网络的原理在博客机器学习分类里已经详细的讲解与实现了,所以本文中就不多加说明。

2. 车牌字符识别

车牌识别是计算机视觉在实际工程中一个非常成功的应用,虽然现在技术相对来说已经成熟,但是围绕着车牌定位、车牌二值化、车牌字符识别等方向,还是不时的有新的算法出现。通过学习车牌识别来提升自己在图像识别方面的工程经验是非常好的,因为它非常好的说明了计算机视觉的一般过程:

图像 预处理 图像分析 目标提取 目标识别

而整个车牌识别过程实际上相当于包含了两个上述过程:1,是车牌的识别;2,车牌字符的识别。

这篇文章其实主要是想介绍OpenCV中神经网络的用法,而不是介绍车牌识别技术。所以我们主要讨论的内容集中在车牌字符的识别上,关于定位、分割等不多加叙述叙述。

3. 字符特征提取

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

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

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

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

<2>定义soble水平检测算子: x_mask=[1,0,1;2,0,2;1,0,1] x_mask=[−1,0,1;−2,0,2;–1,0,1]和竖直方向梯度检测算子 y_mask=x_maskT y_mask=x_maskT

<3>对图像分别用 mask_x mask_x mask_y mask_y进行图像滤波得到 SobelX SobelX SobelY SobelY,下图分别代表原图像、 SobelX SobelX SobelY SobelY

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

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

 

 image     image     image

 1 void calcGradientFeat(const Mat& imgSrc, vector<float>& feat) 
 2 { 
 3     float sumMatValue(const Mat& image); // 计算图像中像素灰度值总和 
 4     
 5     Mat image; 
 6     cvtColor(imgSrc,image,CV_BGR2GRAY); 
 7     resize(image,image,Size(8,16)); 
 8     
 9     // 计算x方向和y方向上的滤波 
10     float mask[3][3] = { { 1, 2, 1 }, { 0, 0, 0 }, { -1, -2, -1 } };
11 
12     Mat y_mask = Mat(3, 3, CV_32F, mask) / 8; 
13     Mat x_mask = y_mask.t(); // 转置 
14     Mat sobelX, sobelY;
15 
16     filter2D(image, sobelX, CV_32F, x_mask); 
17     filter2D(image, sobelY, CV_32F, y_mask);
18 
19     sobelX = abs(sobelX); 
20     sobelY = abs(sobelY);
21 
22     float totleValueX = sumMatValue(sobelX); 
23     float totleValueY = sumMatValue(sobelY);
24 
25     // 将图像划分为4*2共8个格子,计算每个格子里灰度值总和的百分比 
26     for (int i = 0; i < image.rows; i = i + 4) 
27     { 
28         for (int j = 0; j < image.cols; j = j + 4) 
29         { 
30             Mat subImageX = sobelX(Rect(j, i, 4, 4)); 
31             feat.push_back(sumMatValue(subImageX) / totleValueX); 
32             Mat subImageY= sobelY(Rect(j, i, 4, 4)); 
33             feat.push_back(sumMatValue(subImageY) / totleValueY); 
34         } 
35     } 
36 } 
37 float sumMatValue(const Mat& image) 
38 { 
39     float sumValue = 0; 
40     int r = image.rows; 
41     int c = image.cols; 
42     if (image.isContinuous()) 
43     { 
44         c = r*c; 
45         r = 1;    
46     } 
47     for (int i = 0; i < r; i++) 
48     { 
49         const uchar* linePtr = image.ptr<uchar>(i); 
50         for (int j = 0; j < c; j++) 
51         { 
52             sumValue += linePtr[j]; 
53         } 
54     } 
55     return sumValue; 
56 }

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

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

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

4. OpenCV中的神经网络

关于神经网络的原理我的博客里已经写了两篇文章,并且给出了C++的实现,所以这里我就不提了,下面主要说明在OpenCV中怎么使用它提供的库函数。

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

4.1. 首先我们来创建一个网络,我们可以利用CvANN_MLP的构造函数或者create函数。

1 CvANN_MLP::CvANN_MLP(const Mat& layerSizes, int activateFunc=CvANN_MLP::SIGMOID_SYM, double fparam1=0, double fparam2=0 );
2 void CvANN_MLP::create(const Mat& layerSizes, int activateFunc=CvANN_MLP::SIGMOID_SYM, double fparam1=0, double fparam2=0 );

上面是分别是构造函数和cteate成员函数的接口,我们来分析各个形参的意思。

layerSizes:一个整型的数组,这里面用Mat存储。它是一个1*N的Mat,N代表神经网络的层数,第 i i列的值表示第 i i层的结点数。这里需要注意的是,在创建这个Mat时,一定要是整型的,uchar和float型都会报错。

比如我们要创建一个3层的神经网络,其中第一层结点数为 x1 x1,第二层结点数为 x2 x2,第三层结点数为 x3 x3,则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。

f(x)=β1eαx1+eαx f(x)=β1−e−αx1+e−αx

4.2. 设置神经网络训练参数

神经网络训练参数的类型存放在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);

4.3. 神经网络的训练

我们先看训练函数的接口,然后按接口去准备数据。

1 int CvANN_MLP::train(const Mat& inputs, const Mat& outputs, const Mat& sampleWeights, const Mat& sampleIdx=Mat(), CvANN_MLP_TrainParams params=CvANN_MLP_TrainParams(), int flags=0 );

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

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分别用于禁止输入与输出矩阵的归一化。

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

4.4. 识别

识别是通过Cv_ANN_MLP类提供的predict来实现的,知道原理的会明白,它实际上就是做了一次向前传播。

1 float CvANN_MLP::predict(const Mat& inputs, Mat& outputs) const

在进行识别的时候,我们对图像进行特征提取,把它保存在inputs里,通过调用predict函数,我们得到一个输出向量,它是一个1*nClass的行向量,其中每一列说明它与该类的相似程度(0-1之间),也可以说是置信度。我们只用对output求一个最大值,就可得到结果。这个函数的返回值是一个无用的float值,可以忽略。

5. 车牌字符识别测试

1,我们需要读取所有的训练样本,将它们的路径在保存在vector<string>中。

这里面我的车牌字符,因为1和I、0和O是一样的,所以数字加字母一共34类,其中每类有200个样本图像,共34*200个训练样本。

image

2,计算特征。我们按顺序读入图像,调用特征计算函数,把得到的结合保存在input对应的行中,同时把图像对应的预期输出保存在output中。

3,创建神经网络,这里我们计算得到的特征维数为48维,所以我们简单的设计一个3层的神经网络,输入层有48个结点,隐藏层也为48个结点,输出层为34个结点。然后神经网络的训练方法选用BACKPROP,迭代次数设置为5000次。

4,调用训练函数进行训练,并保存训练得到的权值矩阵,直接调用save成员函数即可。

nnetwork.save(“mlp.xml”);

5,识别测试,我们可以用单张图像进行测试,也可以选定一个测试集去进行测试,比如可以用一半的图像作为训练集,一半的图像作为测试集。这里我们可以加载已经训练好的权值矩阵,而不用重新训练,只要开始有保存了xml文件。但是记得你还是要创建一个网络后,才能加载进来。

 1 int NNClassifier::classifier(const Mat& image)
 2 {
 3     Mat nearest(1, nclass, CV_32FC1, Scalar(0));
 4     Mat charFeature;
 5     calcFeature(image, charFeature);
 6 
 7     neuralNetwork.predict(charFeature, nearest);
 8     Point maxLoc;
 9     minMaxLoc(nearest, NULL, NULL, NULL, &maxLoc);
10     int result = maxLoc.x;
11     return result;
12 }

这里我简单的做了一下测试,在这两个特征下,网络设置为3层[48,48,34],一半图像为测试集,得到的识别率为98%,我相信通过尝试调整网络的层数以及选用更好的特征,一定会得到更满意的识别率。PS(工作中用的是SVM识别器,正常采集到的车牌,字符识别率在99.8%以上)。但是神经网络识别器有个很大的优点就是,一旦网络训练好,识别需要的数据文件非常小,而且速度很快。

image

 

6. 字符样本的下载

看到文章下的评论多是需求字符样本的,希望拿到字符样本的同学不要将其用于商业用途或者创建分享下载的链接。博文里用的样本是每类200张图像的测试样本,下面给出一份每类50个图像的样本子集,我以为用来做学术测试已经够了,出于公司利益考虑,请勿再向我索要完整样本。

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

分类:  OpenCV

转载自:http://www.cnblogs.com/ronny/p/opencv_road_more_01.html
标签:  opencv神经网络字符识别
20
0
« 上一篇: 图像分析:二值图像连通域标记
» 下一篇: 图像分析:投影曲线的波峰查找
posted @  2014-03-17 09:24  ☆Ronny丶 阅读( 14859) 评论( 93编辑  收藏
< Prev 1 2

  
#51楼   2015-03-30 22:54  King4_Sun   
Ronny哥,对训练样本文件的读入,能否提示下?
  
#52楼 [ 楼主2015-04-01 09:45  ☆Ronny丶   
@ King4_Sun
训练样本的读入按你自己存放样本的方式,从目录里一张张读入就行了~ 我一般是将所有样本的数据写入一个XML文件,这样方便一些,你可以参考一下。
  
#53楼   2015-04-09 16:08  尚武馨苑   
博主您好!能不能发您的源代码和测试用的车牌照片给我,最近刚学会opencv的基础知识,想再深入地学习,正好看到了您的博文。420478155@qq.com
  
#54楼   2015-04-21 22:07  秋冬   
楼主 能将源码发我一份做参考吗 刚接触opencv 希望能参考下 绝对不会用作商业用途的 谢谢
  
#55楼   2015-04-21 22:08  秋冬   
楼主 能将源码发我一份做参考吗 刚接触opencv 希望能参考下 绝对不会用作商业用途的 谢谢 392680995@qq.com
  
#56楼   2015-04-29 14:39  王者之心style   
楼主,请问你有中文字符的模板库吗?能否发我一份?
  
#57楼   2015-05-01 23:55  yehu   
博主,你好!
有一个问题请教,sigmoid函数的输出是-1到1,那么是否应该将输出矩阵中不是该类别的项设置为-1,即楼主文章中“比如我们需要识别0-9这10个数字,则总的类数为10类,那么样本数字“3”的预期输出为[0,0,1,0,0,0,0,0,0,0];”是否可以设置为[-1,-1,1,-1,-1,-1,-1,-1,-1,-1]。
还望得到博主的回复。
  
#58楼   2015-05-07 20:34  karma2014   
楼主你好,最近我们在做论文,希望你能将你的车牌提取和识别源代码给我发一下,谢谢了。1524866830@qq.com
  
#59楼 [ 楼主2015-05-08 09:58  ☆Ronny丶   
@ karma2014
不好意思,车牌方面的代码,不对外公开!ANN识别车牌字符的核心代码 博客里写的很清楚了!
  
#60楼   2015-05-15 11:31  风起的时候   
博主你好,请问一下,train函数是否只能调用一次呢?
我用三个样本进行训练,然后再针对三个样本进行判断,结果发现如果分开训练的话,只有最后一个样本是判断正确的。
  
#61楼 [ 楼主2015-05-15 18:48  ☆Ronny丶   
@ 风起的时候
train只调用一次,生成好的model,可以保存。
  
#62楼   2015-05-21 16:54  practice   
楼主,你好,一般工程上识别字符会用到比较高级的特征(如SIFT之类)吗?还有汉字和其他字符的识别需要分开吗?期待楼主指点。非商业目的。
  
#63楼   2015-05-23 13:38  王者之心style   
楼主哥,请问您有中文字符的模板库吗?就是车牌上各省市的简称,我通过学习你的博文已经完成了车牌识别的毕设,但是还缺中文的识别,求提供啊,仅仅是毕设,绝不做商用。
  
#64楼 [ 楼主2015-05-23 14:05  ☆Ronny丶   
@ 王者之心style
抱歉,手里现在没有中文字符的样本,这个项目做过太久了!
  
#65楼   2015-06-14 08:26  zengwh   
楼主,训练我用的是一个网上的数字数据集,如果测试也是从那个数据集的话(跟训练集没有交叉),这个识别率很好,但我用你的图片做测试的话,识别率非常差,这个是什么原因?
  
#66楼   2015-06-18 10:58  aidediy   
@ ☆Ronny丶
perClass值是多少?
  
#67楼 [ 楼主2015-06-18 13:38  ☆Ronny丶   
@ zengwh
不太清楚你的数据集的图片质量如何,有可能是过拟合了,可以度着减少隐藏层的数量,以及每层Neurals的数量。
  
#68楼 [ 楼主2015-06-18 13:39  ☆Ronny丶   
@ aidediy
perClass是指每一类样本的数量,比如你每个字符有100个样本,那么perClass = 100
  
#69楼   2015-06-18 16:14  aidediy   
楼主,希望你能够帮帮我!
神经网络训练好后,通过调用predict函数,得到一个输出向量,它是一个1*nClass的行向量,其中每一列说明它与该类的相似程度(0-1之间)。
但是我的不是(0-1之间),还有负数。楼主能不能帮我看一下我的代码?
如果你同意,麻烦你留下你的邮箱,我发给你。谢谢楼主,这个问你困扰了我好久,我身边会做图像处理的大牛都没有,希望你能够帮帮我!
  
#70楼   2015-06-18 16:21  aidediy   
Ronny哥,我是按照你的思路弄完这个程序的,你能不能帮我看看到底哪里出问题了?谢谢~我的邮箱是372354020@qq.com
如果你不想让你的邮箱对外公布,可以帮你的邮箱地址发到我的邮箱里.谢谢Ronny哥
  
#71楼   2015-06-19 15:59  zengwh   
@ aidediy
有负数是对的,你看下这几个数,哪个最大,最大的就是结果了
  
#72楼   2015-06-23 10:04  aidediy   
Ronny哥,相似字特征的选取的具体有效的提取方法是哪些呢?能够有较高的识别率来识别O、0、D;4,A;B,8等等,请指教~非常感谢,谢谢~
  
#73楼   2015-06-24 17:11  aidediy   
Ronny,完整的样本能否传一份给我?
  
#74楼   2015-08-25 14:54  幻灭的星星   
赞赞赞,项目里正好用到,样本量也已知足
  
#75楼   2015-09-01 14:49  爱与自由   
大神 我现在在看你的博客做工程 但是不理解为什么特征维数是48,我看一张样图经过你说的特征提取只有16个数字啊 我能理解的是output是34 最后输出有34种情况 望能给我解答 谢谢
  
#76楼   2015-12-07 10:54  o137   
博主好!能不能帮我看下代码?我检查了输入训练的data和label都没错,可是预测结果就是不对,实在不知道哪出问题了,能把您邮箱告诉我吗 感激不尽!
  
#77楼   2015-12-07 17:01  ssssKKK   
博主您好!我现在有个问题就是训练完之后,无论输入什么样的特征向量,输出结果都是一样的?求帮助啊
  
#78楼   2015-12-08 14:13  ssssKKK   
博主您好,能否把测试样本给我也发一份,在此万分感谢!156690308@qq.com
  
#79楼   2016-01-20 00:14  king123456   
您好,可以发个源码参考下吗?最近在写这方面的论文,另外,我根据博主的文章,在opencv 3.0下做测试,总是提示vector 下标越界,所以急切想参考下您的代码,非常感谢!!!
8406798@qq.com
  
#80楼   2016-03-30 11:48  leonfg   
博主您好,
我按照您在文章中的方式构建网络(48\48\34)并将您分享的图像包进行特征提取,每个字符选择45个进行训练,剩下5个做测试,最终正确率只有70%左右,即使我用全部数据进行训练然后再把全部数据输入测试,正确率也只到85%,请问是网络参数需要优化还是特征提取策略需要优化?或者我编码可能有问题?
  
#81楼   2016-04-10 10:20  lcjoz16087   
感谢分享,请问神经网络识别车牌字符的源码有吗? OpenCV源码: http://sourcecode.itdadao.com/forum-opencv-1.html
  
#82楼   2016-05-06 22:14  鸟羽   
全部作为训练集和测试集,最后的正确率达到0.978235,感谢博主
  
#83楼   2016-05-09 22:23  Winter_2013   
楼主你好,我刚学opencv,Mat layerSizes=(Mat_<int>(1,3)<<x1,x2,x3),这句话是怎么初始化的,我查了查手册,没见到这种用法啊,能给解释一下吗?
  
#84楼   2016-05-10 13:23  XDTheSUN   
Ronny哥,麻烦能不能把各省简称样本集发一部分,做毕设用的,字符训练结果还不错,但是省份的训练样本太少,导致识别率很低,拜托拜托!
1403185977@qq.com
  
#85楼   2016-05-29 02:33  辞锦曲   
博主,能不能把34*200个完整测试样本发我一份?最近在做毕设,SVM分类,用的你的样本集,不知道是不是因为训练样本太少了,正确率才85%, 1090457953@qq.com谢谢博主
  
#86楼   2016-06-16 10:08  cnKlaus   
Ronny哥,我想知道字符样本是什么软件画的,打算自己做个字符训练库,请问用什么软件或者调用什么能实现您做的字符样本的效果,谢谢!
  
#87楼   2016-06-23 09:53  kjcx100   
好文,刚好要学习这个,
  
#88楼   2016-08-12 17:08  陌上轻寒   
楼主,您好~您的样本链接失效了,可不可以发我一份,万分感谢,1020744806@qq.com
  
#89楼   2016-08-18 16:50  braverobin   
楼主你好,我最近在研究SVM字符识别算法,我想跟你交流一下。万分感谢,我的QQ号是386663559 对我非常重要后面如果有帮助小弟一定感谢楼主。
  
#90楼   2016-11-21 22:12  itmm   
博主您好!你分享的链接已失效,能不能发您的源代码和车牌样本给我或者新的链接,仅用于学习,非常感谢。403583341@qq.com
  
#91楼   2016-12-10 21:36  geeg   
楼主您好,我刚刚接触opencv,需要您的帮助,保证仅仅用于学习,可不可以把代码发我一份,我的邮箱是1690243425@qq.com,十分感谢
  
#92楼   2017-01-11 13:26  Daevid   
博主您好!能不能发您的源代码和测试用的车牌照片给我,最近要做毕设,万分感激。1101645313@qq.com
  
#93楼   2017-03-15 10:41  xuxiaotu   
博主你好,我是大四的学生,最近在做毕设,您方便把源代码发给我一份么,仅做学习参考2448152521@qq.com,万分感谢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值