使用OpenCV的ANN_MLP神经网络实现数字识别
前言
1.OpenCV中的ML模塊實(shí)現(xiàn)了前饋人工神經(jīng)網(wǎng)絡(luò),具體地說(shuō)是多層感知器(MLP),是最常用的神經(jīng)網(wǎng)絡(luò)類(lèi)型。 MLP由輸入層,輸出層和一個(gè)或多個(gè)隱藏層組成。 MLP的每一層包括一個(gè)或多個(gè)與來(lái)自上一層和下一層的神經(jīng)元定向連接的神經(jīng)元。關(guān)于ANN_MLP的具體說(shuō)明可以看opencv的官方文檔。
2.我這里要是使用ANN_MLP神經(jīng)網(wǎng)絡(luò)來(lái)實(shí)現(xiàn)0到9的印刷數(shù)字識(shí)別,使用的OpenCV版本是3.30,IDE是VS2015,實(shí)現(xiàn)語(yǔ)言是C++,還使用了boost來(lái)進(jìn)行文件讀取的相關(guān)操作。
樣本準(zhǔn)備
1.先準(zhǔn)備0到9的樣本,分別放在相應(yīng)的文件目錄下,這是我保存的格式:
2.每個(gè)目錄下放著對(duì)的樣本,我這里每個(gè)字母都有50個(gè)樣本,對(duì)應(yīng)的文件沒(méi)有特殊要求。
代碼
1.訓(xùn)練代碼
//訓(xùn)練函數(shù) //root_path樣本地址 //model_path保存模型路徑加文件名,后續(xù)為xml void trainChar(string &root_path, string &model_path) {vector<string> dir_path;int dir_number;getFileNameFromDir(root_path, dir_path, dir_number);//圖像的行const int image_rows = 8;//圖像的列const int image_cols = 16;//要訓(xùn)練的類(lèi)別const int class_sum = 10;//每個(gè)類(lèi)別的樣本個(gè)數(shù)const int images_sum = 50;if (dir_number != class_sum){cout << "要訓(xùn)練的種類(lèi)與當(dāng)前目錄下的種類(lèi)和差異!" << endl;return;}//每一行一個(gè)訓(xùn)練樣本float trainingData[class_sum*images_sum][image_rows*image_cols] = { { 0 } };//訓(xùn)練樣本標(biāo)簽float labels[class_sum*images_sum][class_sum] = { { 0 } };Mat src, resize_img, train_img;//這里讀文件的方式不是很好,用boost會(huì)好一些for (int i = 0; i < dir_path.size(); i++){//cout << dir_path.at(i) << endl;int k = 0;fs::directory_iterator begin_iter(dir_path.at(i));fs::directory_iterator end_iter;//獲取該目錄下的所有文件名for (; begin_iter != end_iter; ++begin_iter){string image_path = begin_iter->path().string();src = imread(image_path, 0);if (src.empty()){cerr << "can not load image \n" << std::endl;exit(0);}//更改尺寸resize(src, resize_img, Size(image_rows, image_cols), (0, 0), (0, 0), INTER_AREA);//二值化threshold(resize_img, train_img, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);for (int j = 0; j < image_rows*image_cols; j++){trainingData[i*images_sum + k][j] = (float)resize_img.data[j];}// 設(shè)置標(biāo)簽數(shù)據(jù)for (int j = 0; j < class_sum; j++){if (j == i){labels[i*images_sum + k][j] = 1;}else{labels[i*images_sum + k][j] = 0;}}k++;}Mat labelsMat(class_sum*images_sum, class_sum, CV_32FC1, labels);}//訓(xùn)練數(shù)據(jù)及標(biāo)簽Mat trainingDataMat(class_sum*images_sum, image_rows*image_cols, CV_32FC1, trainingData);Mat labelsMat(class_sum*images_sum, class_sum, CV_32FC1, labels);//設(shè)置參數(shù)Ptr<ANN_MLP>model = ANN_MLP::create();Mat layerSizes = (Mat_<int>(1, 5) << image_rows*image_cols, 128, 128, 128, class_sum);model->setLayerSizes(layerSizes);//訓(xùn)練方法為反向傳播(這個(gè)跟深度學(xué)習(xí)的反向轉(zhuǎn)播是一個(gè)道理)model->setTrainMethod(ANN_MLP::BACKPROP, 0.001, 0.1);// 激活函數(shù)設(shè)置為 sigmoidmodel->setActivationFunction(ANN_MLP::SIGMOID_SYM, 1.0, 1.0);model->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER | TermCriteria::EPS, 10000, 0.0001));cout << "開(kāi)始訓(xùn)練!" << endl;Ptr<TrainData> trainData = TrainData::create(trainingDataMat, ROW_SAMPLE, labelsMat);model->train(trainData);//保存模型model->save(model_path);cout << "訓(xùn)練完成" << endl; }//得到路徑下第一層的文件夾的絕對(duì)路徑 void getFileNameFromDir(string &root_path,vector<string> &dir_path, int &class_sum) {class_sum = 0;vector<string> dir_name;fs::path dir(root_path);// 判斷路徑是否存在if (fs::exists(dir)){fs::directory_iterator itEnd;fs::directory_iterator itDir(dir);string file_name;// 遍歷路徑下所有文件for (; itDir != itEnd; itDir++){file_name = itDir->path().string();// 判斷文件是否是文件夾if (boost::filesystem::is_directory(file_name.c_str())){dir_path.push_back(file_name);class_sum++; }}} }訓(xùn)練代碼調(diào)用方式:
//保存字符集的主目錄 string char_path = "C:/code/DigitalRecognition/DigitalRecognition/numberChar/"; //訓(xùn)練好的模型保存的路徑和文件名 string model_path = "C:/code/DigitalRecognition/DigitalRecognition/numberCharModel.xml"; trainChar(char_path,model_path);2.測(cè)試代碼
//測(cè)試模型 //src是要識(shí)別的圖像 //model_path模型的路徑 void useModel(Mat &src, string &model_path) {if (src.empty()){cout << "當(dāng)前傳入的圖像為空!" << endl;return;}if (src.channels() > 1){cvtColor(src, src, CV_BGR2GRAY);}Mat dst;//圖像的行const int image_rows = 8;//圖像的列const int image_cols = 16;Ptr<ANN_MLP>model = ANN_MLP::create();model = cv::Algorithm::load<cv::ml::ANN_MLP>(model_path);//將測(cè)試圖像轉(zhuǎn)化為1*128的向量resize(src, src, Size(image_rows, image_cols), (0, 0), (0, 0), INTER_AREA);threshold(src, src, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);Mat_<float> testMat(1, image_rows*image_cols);for (int i = 0; i < image_rows*image_cols; i++){testMat.at<float>(0, i) = (float)src.at<uchar>(i / 8, i % 8);}//使用訓(xùn)練好的MLP model預(yù)測(cè)測(cè)試圖像,把預(yù)測(cè)到的值放到dst里面model->predict(testMat, dst);cout << "dst:" << dst << endl;//選出最大值double maxVal = 0;Point maxLoc;minMaxLoc(dst, NULL, &maxVal, NULL, &maxLoc);cout << "測(cè)試結(jié)果:" << maxLoc.x << "置信度:" << maxVal * 100 << "%" << endl; }測(cè)試代碼調(diào)用方式:
//訓(xùn)練好的模型保存的路徑和文件名 string model_path = "C:/code/DigitalRecognition/DigitalRecognition/numberCharModel.xml"; //讀取圖像 Mat src = imread("src.png"); useModel(src,model_path);運(yùn)行結(jié)果:
結(jié)語(yǔ)
1.上面的所用到的樣本,可以從我的資源上傳那里得到。
2.如果在運(yùn)行中有什么bug,可以找我之前的博客,下面有推薦的群,互相討論學(xué)習(xí)。
總結(jié)
以上是生活随笔為你收集整理的使用OpenCV的ANN_MLP神经网络实现数字识别的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: OpenCV图像增强(三)——自适应对数
- 下一篇: 使用OpenCV进行身份证号码字符进行分