基于opencv的bp神经网络判别

来源:互联网 发布:a星寻路算法介绍 编辑:程序博客网 时间:2024/05/01 14:38

事先说明,本人纯粹是小白。写这篇博客也是相信小白惜小白,顺带锻炼一下写作能力(毕设需求),因此,有问题还是靠度娘吧! 作为刚接触程序的新人,看网上大佬们分享的程序,在对他们顶膜礼拜的同时,却不经怀有抱怨的心情。因为大部分大佬们,不知是想锻炼我们,还是单纯的嫌麻烦,亦或者对于他们来说,这根本就不是什么难懂的地方,我只想说,你们为什么就不写注释呢(血泪聚下)。这篇博客是在网上查找的程序基础上,标注自己的理解,或许有不当的地方,请大家指正,好了,我就不啰嗦了(应该也没人看)以下是干货。 我是利用bp神经网络进行对图片分类判别,神经网络的原理在网上有现成的,不想去搜的朋友可以看这一篇http://blog.csdn.net/garfielder007/article/details/51004919,原理稍稍理解后,我们就可以进行程序的实现了。 首先在VS中建立工程,名字随意,我这里起名为bpnet;在建好的工程文件夹中放入训练的文件,我这里分成两类,一类是清晰图片,另一类是模糊图片,都放在charSamples,如图,0文件夹为清晰,1文件夹为模糊

如图

添加源程序:

#include <windows.h>#include <iostream>#include <opencv2/opencv.hpp>using namespace cv;using namespace std;char* WcharToChar(const wchar_t* wp)  {      char *m_char;    int len= WideCharToMultiByte(CP_ACP,0,wp,wcslen(wp),NULL,0,NULL,NULL);      m_char=new char[len+1];      WideCharToMultiByte(CP_ACP,0,wp,wcslen(wp),m_char,len,NULL,NULL);      m_char[len]='\0';      return m_char;  }  wchar_t* CharToWchar(const char* c)  {       wchar_t *m_wchar;    int len = MultiByteToWideChar(CP_ACP,0,c,strlen(c),NULL,0);      m_wchar=new wchar_t[len+1];      MultiByteToWideChar(CP_ACP,0,c,strlen(c),m_wchar,len);      m_wchar[len]='\0';      return m_wchar;  }  wchar_t* StringToWchar(const string& s)  {      const char* p=s.c_str();      return CharToWchar(p);  }  int main(){const string fileform = "*.jpg";//文件格式const string perfileReadPath = "charSamples"; //文件前置路径   const int sample_mun_perclass = 40;//训练字符每类数量const int class_mun = 2;//训练字符类数    const int image_cols = 8;//图片分为列,可自行调整,这里只是随意写的const int image_rows = 16;//图片分为行    string fileReadName,fileReadPath;            char temp[256];float trainingData[class_mun*sample_mun_perclass] [image_cols*image_rows] = {{0}};//每一行一个训练样本float labels[class_mun*sample_mun_perclass][class_mun] = {{0}};//训练样本标签   for(int i=0;i<=class_mun-1;++i)//不同类{//读取每个类文件夹下所有图像int  j = 0;//每一类下读取图像计数个数sprintf(temp,"%d",i);//按顺序读图fileReadPath = perfileReadPath + "/" + temp + "/" + fileform;//文件读取路径cout<<"文件夹"<<i<<endl;HANDLE hFile;        LPCTSTR lpFileName = StringToWchar(fileReadPath);//指定搜索目录和文件类型WIN32_FIND_DATA pNextInfo;//搜索得到的文件信息将储存在pNextInfo中;hFile = FindFirstFile(lpFileName,&pNextInfo);if(hFile == INVALID_HANDLE_VALUE)//搜索失败{exit(-1);}//循环读取do{if(pNextInfo.cFileName[0] == '.')//过滤.和..                continue;                 j++;//读取一张图 printf("%s\n",WcharToChar(pNextInfo.cFileName));            //对读入的图片进行处理    Mat srcImage = imread( perfileReadPath + "/" + temp + "/" + WcharToChar(pNextInfo.cFileName),CV_LOAD_IMAGE_GRAYSCALE);//读入图像            Mat resizeImage;            Mat trainImage;   resize(srcImage,resizeImage,Size(image_cols,image_rows),(0,0),(0,0),CV_INTER_AREA);//使用象素关系重采样。当图像缩小时候,该方法可以避免波纹出现            threshold(resizeImage,trainImage,0,255,CV_THRESH_BINARY|CV_THRESH_OTSU);//对灰度图像进行阈值操作得到二值图像    for(int k = 0; k<image_rows*image_cols; ++k)//每个图片            {                trainingData[i*sample_mun_perclass+(j-1)][k] = (float)trainImage.data[k];//将二值化数据拷贝到trainingData中            }}while (FindNextFile(hFile,&pNextInfo) && j<sample_mun_perclass);//如果设置读入的图片数量,则以设置的为准,如果图片不够,则读取文件夹下所有图片}    // 设置训练数据Mat输入    Mat trainingDataMat(class_mun*sample_mun_perclass, image_rows*image_cols, CV_32FC1, trainingData);// 设置训练数据Mat//cout<<trainingDataMat<<endl;    cout<<"trainingDataMat——OK!"<<endl;    // 设置标签数据Mat输出    for(int i=0;i<=class_mun-1;++i)    {        for(int j=0;j<=sample_mun_perclass-1;++j)        {            for(int k = 0;k<class_mun;++k)            {                if(k==i)                    labels[i*sample_mun_perclass + j][k] = 1;                else labels[i*sample_mun_perclass + j][k] = 0;            }        }    }    Mat labelsMat(class_mun*sample_mun_perclass, class_mun, CV_32FC1,labels);//设置标签数据Mat    cout<<"labelsMat:"<<endl;    cout<<labelsMat<<endl;    cout<<"labelsMat——OK!"<<endl;    //训练代码    cout<<"training start...."<<endl;    CvANN_MLP bp;//bp神经网络    //设置bp神经网络的参数    CvANN_MLP_TrainParams params;//类,参数    params.train_method=CvANN_MLP_TrainParams::BACKPROP;//训练方法    params.bp_dw_scale=0.001;//权值更新率    params.bp_moment_scale=0.1;//权值更新冲量    params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,10000,0.0001);  //设置结束条件term_crit:终止条件, //它包括了两项,迭代次数(CV_TERMCRIT_ITER)和误差最小值(CV_TERMCRIT_EPS),一旦有一个达到条件就终止训练。    //设置bp神经网络    Mat layerSizes=(Mat_<int>(1,5) << image_rows*image_cols,128,128,128,class_mun);//1个输入,1个输出,3个隐藏层,隐藏层数也根据内容自己调整    bp.create(layerSizes,CvANN_MLP::SIGMOID_SYM,1.0,1.0);//CvANN_MLP::SIGMOID_SYM节点使用的函数                                                   cout<<"training...."<<endl;    bp.train(trainingDataMat, labelsMat, Mat(),Mat(), params);//trainingDataMat:输入矩阵,存储了所有训练样本的特征                                                       //labelsMat:输出矩阵,每个样本所属的种类每一行表示一个样本的预期输出结果,    bp.save("bpnet.xml"); //保存训练    cout<<"training finish...bpnet.xml saved "<<endl;   /*CvANN_MLP bp;//bp神经网络bp.load("bpnet.xml")*/;//这是网络训练好后直接调用    //测试神经网络    cout<<"测试:"<<endl;    Mat test_image = imread("test.jpg",CV_LOAD_IMAGE_GRAYSCALE);//读入测试图    Mat test_temp;    resize(test_image,test_temp,Size(image_cols,image_rows),(0,0),(0,0),CV_INTER_AREA);//使用象素关系重采样。当图像缩小时候,该方法可以避免波纹出现    threshold(test_temp,test_temp,0,255,CV_THRESH_BINARY|CV_THRESH_OTSU);//二值化    Mat_<float>sampleMat(1,image_rows*image_cols);     for(int i = 0; i<image_rows*image_cols; ++i)      {          sampleMat.at<float>(0,i) = (float)test_temp.at<uchar>(i/8,i%8);  //将test数据(unchar)copy到sampleMat(float)中图像特征    }      Mat responseMat;      bp.predict(sampleMat,responseMat); //过调用predict函数,我们得到一个输出向量,它是一个1*nClass的行向量,                                   //其中每一列说明它与该类的相似程度(0-1之间),也可以说是置信度    Point maxLoc;    double maxVal = 0;    minMaxLoc(responseMat,NULL,&maxVal,NULL,&maxLoc);//最小最大值    string judge = "";if(maxLoc.x == 0)judge = "清晰";     if(maxLoc.x == 1)judge = "模糊";    cout<<"识别结果:"<<judge<<endl;    imshow("test_image",test_image);      waitKey(0);    return 0;}


测试图:


运行结果:


以上,我的第一篇博客就写完了,建议配合大神们给出的原理理解会更好!



2 0