opencv神经网络,预测不正确

时间:2016-04-07 21:07:52

标签: c++ opencv neural-network

我试图用OpenCV在C ++中创建一个神经网络。目的是识别道路标志。我以这种方式创建了网络,但它预测得很糟糕,因为它会返回奇怪的结果:

enter image description here

来自训练选择的样本图像如下所示:examples

有人可以帮忙吗?

  trainNN() {
    char* templates_directory[] = {
        "speed50ver1\\", 
        "speed60ver1\\", 
        "speed70ver1\\",
        "speed80ver1\\"
    };

    int const numFilesChars[]={ 213, 100, 385, 163};

    char const strCharacters[] = { '5', '6', '7', '8' };

    Mat trainingData; 
    Mat trainingLabels(0, 0, CV_32S);

    int const numCharacters = 4;  

    // load images from directory
    for (int i = 0; i != numCharacters; ++i) {
        int numFiles = numFilesChars[i];

        DIR *dir;
        struct dirent *ent;

        char* s1 = templates_directory[i];

        if ((dir = opendir (s1)) != NULL) {
            Size size(80, 80);

            while ((ent = readdir (dir)) != NULL) {
                string s = s1;
                s.append(ent->d_name);

                if(s.substr(s.find_last_of(".") + 1) == "jpg") {
                    Mat img = imread(s,0);
                    Mat img_mat;
                    resize(img, img_mat, size);
                    Mat new_img = img_mat.reshape(1, 1);
                    trainingData.push_back(new_img);
                    trainingLabels.push_back(i);

                }

            }
            int b = 0;
            closedir (dir);
        } else {
            /* could not open directory */
            perror ("");
        }
    }

    trainingData.convertTo(trainingData, CV_32FC1);

    Mat trainClasses(trainingData.rows, numCharacters, CV_32FC1);
    for( int i = 0; i !=  trainClasses.rows; ++i){
        int const labels = *trainingLabels.ptr<int>(i);
        auto train_ptr = trainClasses.ptr<float>(i);
        for(int k = 0; k != trainClasses.cols; ++k){
            *train_ptr = k != labels ? 0 : 1;
            ++train_ptr;
        }
    }

    int layers_d[] = { trainingData.cols, 10,  numCharacters};
    Mat layers(1, 3, CV_32SC1, layers_d);
    ann.create(layers, CvANN_MLP::SIGMOID_SYM, 1, 1);

    CvANN_MLP_TrainParams params = CvANN_MLP_TrainParams(
        // terminate the training after either 1000
        // iterations or a very small change in the
        // network wieghts below the specified value
        cvTermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, 1000, 0.000001),

        // use backpropogation for training
        CvANN_MLP_TrainParams::BACKPROP,

        // co-efficents for backpropogation training
        // (refer to manual)
        0.1,
        0.1);

    int iterations = ann.train(trainingData, trainClasses, cv::Mat(), cv::Mat(), params);

    CvFileStorage* storage = cvOpenFileStorage( "neural_network_2.xml", 0, CV_STORAGE_WRITE );
    ann.write(storage,"digit_recognition");
    cvReleaseFileStorage(&storage);

}  


void analysis(char* file, bool a) {
    //trainNN(a);
    read_nn();


    // load image
    Mat img = imread(file,  0);

    Size my_size(80,80);
    resize(img, img, my_size);

    Mat r_img = img.reshape(1,1);

    r_img.convertTo(r_img, CV_32FC1);   

    Mat classOut(1,4,CV_32FC1); 

    ann.predict(r_img, classOut);

    double min1, max1;
    cv::Point min_loc, max_loc;
    minMaxLoc(classOut, &min1, &max1, &min_loc, &max_loc);
    int x = max_loc.x;


    //create windows
    namedWindow("Original Image", CV_WINDOW_AUTOSIZE);
    imshow("Original Image", img);

    waitKey(0); //wait for key press

    img.release();
    rr.release();

    destroyAllWindows(); //destroy all open windows
}

奇怪的结果:对于这个输入speed80答案是3(因为我只有4个类 - 速度限制50,60,70,80)。它对速度限制80标志是正确的。results

但其余输入结果不正确。它们对于标志50,60,70是相同的.max1 = min1 = 1.02631 ......(如第一张图片所示)它很奇怪。

2 个答案:

答案 0 :(得分:3)

我已经调整了你的代码来训练4手位置的分类器(因为那是我的图像数据)。我保持你的逻辑尽可能相似,只改变了使我的Windows机器上的图像运行绝对必要的东西。简而言之,您的代码没有任何根本性的错误 - 我没有看到您描述的失败模式。

你遗漏的一件事是read_nn()的代码。我假设只是执行以下操作: ann.load("neural_network_2.xml");

无论如何,我的怀疑是你的神经网络根本没有融合,或者它过度拟合。也许训练数据没有足够的变化。您是否在ANN没有接受过培训的单独测试数据上运行analysis()?如果是这样,ANN是否能够至少正确地预测训练数据?

编辑:好的,我刚刚下载了您的图像数据并尝试了它并看到了相同的行为。经过一些分析,看起来你的ANN没有收敛。即使您仅为cvTermCriteria指定CV_TERMCRIT_ITER,训练操作也仅在大约250次迭代后退出。在将隐藏的图层大小从10增加到20之后,我看到了显着的改进,成功将212,72,94和143个图像的训练数据分类到了类(50,60,70和80) 。这不是很好,但它表明你走在正确的轨道上。

基本上,网络体系结构的表达力不足以充分模拟您尝试解决的问题,因此网络权重永远不会收敛,并且它会尽早放弃反向提升。对于一门课程,您可能会看到一些成功,但我认为这很大程度上取决于缺乏训练数据的改组。如果它在刚刚训练了几百个非常相似的图像后停止,它可能能够设法正确地对它们进行分类。

简而言之,我建议您执行以下操作:

  1. 构建测试结果的方法 - 例如:创建一个函数来对所有训练数据进行预测,并理想地将一些图像作为验证集放在一边,以便确认模型不会过度拟合训练数据。 / LI>
  2. 在训练前随机播放训练数据。否则,backprop将不会轻易收敛。
  3. 尝试使用不同的体系结构,例如多个不同大小的隐藏层。
  4. 实际上,这是一个可以从使用卷积神经网络中获益的问题,但OpenCV的机器学习设施非常有限。最后,如果你真的想要创建人工神经网络,你可能想要研究一些更强大的工具。我个人使用Tensorflow,但我也听说过Theano的好消息。

答案 1 :(得分:0)

我只使用OpenCV实现NN进行布尔分类,但我认为对于需要对两个以上不同类进行分类的任务,这也可能适用:

“如果您使用默认的cvANN_MLP :: SIGMOID_SYM激活函数,那么输出应该在[-1,1]范围内,而不是[0,1],以获得最佳结果。”

所以,你在哪里:

*train_ptr = k != labels ? 0 : 1;

您可能想尝试:

*train_ptr = k != labels ? -1 : 1;

如果我在这里偏离轨道,请不要理会。