查看: 1754|回复: 3

OpenCv使用BP神经网络将图片分为三类

[复制链接]

665

主题

1234

帖子

6568

积分

xdtech

Rank: 5Rank: 5

积分
6568
发表于 2018-12-23 17:44:35 | 显示全部楼层 |阅读模式
代码的实现:

首先你需要在工程下新建一个存放图片的文件夹,然后在此文件夹下再新建三个名为“0”,“1”,“2”的文件夹,为什么是0,1,2呢,因为代码是这样写的,具体的还是要你去看,去理解。如图:



上代码了(注:此代码是在别人的基础上进行修改的):

#include "stdafx.h"
#include <windows.h>  
#include <iostream>  
#include <opencv2/opencv.hpp>  
#include "opencv2/core/core.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 = "*.png";//文件格式  
    const string perfileReadPath = "charSamples"; //文件前置路径  

    const int sample_mun_perclass = 637;//训练字符每类数量  
    const int class_mun = 3;//训练字符类数  

    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)//不同类  class_mun-1
    {  
        //读取每个类文件夹下所有图像  
        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——OK!"<<endl;  

    // 设置标签数据Mat输出  
    for(int i=0;i<=class_mun-1;++i)  //class_mun-1
    {  
        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; //类,参数  1
    params.train_method=CvANN_MLP_TrainParams::BACKPROP; //训练方法:误差反向传播法  
    params.bp_dw_scale=0.001; //权值更新率  0.001
    params.bp_moment_scale=0.1; //权值更新冲量  
    params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS,10000,0.0001);   //设置结束条件term_crit:终止条件,10000,0.0001
//它包括了两项,迭代次数(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("1.png",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 = "right";  
else if(maxLoc.x == 1)  
        judge = "letf";  
else
judge = "front";
cout<<"识别结果:"<<judge<<endl;  
    imshow("test_image",test_image);   
    waitKey(0);  

    return 0;  
}  

提示:我代码中训练的图片为637张,具体需要多少张你们进行衡量,如果训练图片太多的话会提示指针泄漏的,所以训练图片的数量从少开始依次叠加。
---------------------


回复

使用道具 举报

665

主题

1234

帖子

6568

积分

xdtech

Rank: 5Rank: 5

积分
6568
 楼主| 发表于 2019-2-24 20:30:59 | 显示全部楼层
现在来看
模型太简单了
回复

使用道具 举报

665

主题

1234

帖子

6568

积分

xdtech

Rank: 5Rank: 5

积分
6568
 楼主| 发表于 2019-2-24 20:31:05 | 显示全部楼层
分成三类
也就是个toy
回复

使用道具 举报

665

主题

1234

帖子

6568

积分

xdtech

Rank: 5Rank: 5

积分
6568
 楼主| 发表于 2019-2-24 20:31:17 | 显示全部楼层
所以,
还是要去学真正的ai
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表