OPENCV ANN(類神經網路) 手寫數字辨識 (opencv249_ann_digital_number) ~ opencv249_ann_digital_number01-彩色轉灰階imread、改變圖像解析度resize、灰階轉二值化threshold、二維數據轉一維數據reshape、影像數據轉ML運算數據convertTo、類神經CvANN_MLP、取出ML運算結果minMaxLoc
OPENCV ANN(類神經網路) 手寫數字辨識 (opencv249_ann_digital_number) ~ opencv249_ann_digital_number01-彩色轉灰階imread、改變圖像解析度resize、灰階轉二值化threshold、二維數據轉一維數據reshape、影像數據轉ML運算數據convertTo、類神經CvANN_MLP、取出ML運算結果minMaxLoc
資料來源:https://blog.csdn.net/cherrywish/article/details/78761411
https://blog.csdn.net/qq_15947787/article/details/51385861
GITHUB: https://github.com/jash-git/opencv249_ann_digital_number
opencv249_ann_digital_number01-彩色轉灰階imread、改變圖像解析度resize、灰階轉二值化threshold、二維數據轉一維數據reshape、影像數據轉ML運算數據convertTo、類神經CvANN_MLP、取出ML運算結果minMaxLoc
目前訓練結果-128,128*2,10
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/ml/ml.hpp>
#include <iostream>
#include <cstdio>
#include <cstdlib> //srand() ,rand() ,system()
#include <ctime> //time()
#include <sys/timeb.h>
#if defined(WIN32)
#define TIMEB _timeb
#define ftime _ftime
typedef __int64 TIME_T;
#else
#define TIMEB timeb
typedef long long TIME_T;
#endif
using namespace cv;
using namespace std;
void Pause()
{
printf("Press Enter key to continue...");
fgetc(stdin);
}
int Rand_M2N(int intstart,int intrange)
{
srand(time(NULL));
return intstart+(rand()%intrange);
}
int main()
{
const int image_cols = 8;
const int image_rows = 16;
char ad[128]={0};
Mat traindata ,trainlabel;
//读取训练数据 4000张
for (int i = 0; i < 10; i++)
{
for (int j =0;j<500;j++)
{
sprintf(ad, "data\\%d\\%d.jpg",i,j);
Mat srcImage = imread(ad,0);
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);
/*
Mat::reshape( )
只是在逻辑上改变矩阵的行列数或者通道数,没有任何的数据的复制,也不会增减任何数据,因此这是一个O(1)的操作,它要求矩阵是连续的。
C++: Mat Mat::reshape(int cn, int rows=0 const)
cn:目标通道数,如果是0则保持和原通道数一致;
rows:目标行数,同上是0则保持不变;
改变后的矩阵要满足 rows*cols*channels 跟原数组相等,所以如果原来矩阵是单通道3*3的,调用Reshape(0,2)是会报错的,因为3*3*1不能被2*1整除。
*/
trainImage = trainImage.reshape(1,1);
traindata.push_back(trainImage);//将元素添加到矩阵的底部。(在为mat增加一行的时候,用到push_back)
float responses[10]={0,0,0,0,0,0,0,0,0,0};
responses[i]=1;
Mat responsesMat(1, 10, CV_32FC1, responses);
trainlabel.push_back(responsesMat);//将元素添加到矩阵的底部。(在为mat增加一行的时候,用到push_back)
}
}
traindata.convertTo(traindata,CV_32F);
trainlabel.convertTo(trainlabel,CV_32F);
CvANN_MLP_TrainParams params(
cvTermCriteria(CV_TERMCRIT_ITER + CV_TERMCRIT_EPS, 1000, 0.00001), //终止条件
CvANN_MLP_TrainParams::BACKPROP, // BACKPROP算法
0.1, 0.1); //激活函数的两个参数
//4层MLP,输入层有400个神经元,隐藏层01有400个神经元,隐藏层02有400个神经元,输出层有10个神经元
Mat layerSizes = (Mat_<int>(1,3) << 128, 128*2, 10);
CvANN_MLP bp; //实例化MLP
//创建MLP模型,选用的激励函数为对称SIGMOID函数
bool bnload=true;
if(!bnload)
{
bp.create(layerSizes,CvANN_MLP::SIGMOID_SYM);
bool check=bp.train(traindata, trainlabel, Mat(),Mat(), params); //训练MLP模型
if(check==true)
{
bp.save("ann_param");
cout << "train ok\n";
}
}
else
{
bp.load("ann_param");
}
/*
RNG rng;
int digital=rng.uniform(0, 9);
int index=rng.uniform(400, 499);
*/
int digital=Rand_M2N(0,(9-0));
int index=Rand_M2N(0,(499-0));
sprintf(ad, "data\\%d\\%d.jpg",digital,index);
cout << "test image path : " << ad << endl;
Mat testdata = imread(ad,0);
Mat showdata=testdata.clone();
resize(testdata, testdata, Size(image_cols, image_rows), (0, 0), (0, 0), CV_INTER_AREA);
threshold(testdata, testdata, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
testdata = testdata.reshape(1,1);
testdata.convertTo(testdata,CV_32F);
Mat p_output_01;
bp.predict(testdata, p_output_01);
cout << "output:" << endl << p_output_01 << endl << endl;
Point maxLoc;
double maxVal = 0;
minMaxLoc(p_output_01, NULL, &maxVal, NULL, &maxLoc);
cout << "ANS:" << maxLoc.x << "\t" << maxVal * 100 << "%" << endl;
namedWindow(ad, CV_WINDOW_NORMAL);
imshow(ad,showdata);
waitKey(0);
Pause();
return 0;
}