1. 文檔簡單介紹
ANN原理及響應函數設置如上所述;
ANN與其他分類算法有一個不同點是,構建和訓練分開進行;
2.OpenCV實現代碼
2.1//從XML文件載入訓練數據和類別標籤,並進行訓練;
OCR::OCR(string trainFile){
DEBUG=false;
trained=false;
saveSegments=false;
//字符塊的寬高
charSize=20;
//Read file storage.
FileStorage fs;
fs.open("OCR.xml", FileStorage::READ);
//新建兩個矩陣,用於存儲訓練數據和類別標籤;
Mat TrainingData;
Mat Classes;
fs["TrainingDataF15"] >> TrainingData;
fs["classes"] >> Classes;
//10層ANN,訓練
train(TrainingData, Classes, 10);
}
2.2訓練
void OCR::train(Mat TrainData, Mat classes, int nlayers){
//矩陣,用於創建ANN;1行3列;訓練數據的列數(特徵屬性),ANN的層數,字符數(類別標籤);
Mat layers(1,3,CV_32SC1);
layers.at<int>(0)= TrainData.cols;
layers.at<int>(1)= nlayers;
layers.at<int>(2)= numCharacters;
//使用sigmoid創建ANN
ann.create(layers, CvANN_MLP::SIGMOID_SYM, 1, 1);
//Prepare trainClases
//Create a mat with n trained data by m classes
Mat trainClasses;
//TrainData.rows表示訓練數據的數量;
trainClasses.create( TrainData.rows, numCharacters, CV_32FC1 );
for( int i = 0; i < trainClasses.rows; i++ )
{
for( int k = 0; k < trainClasses.cols; k++ )
{
//If class of data i is same than a k class
//trainClasses的第i個row存儲第i個樣本的標籤類別,而此標籤存儲在class的第i個元素下;
//class(numCharacters)-->trainClasses(TrainData.rows, numCharacters)矩陣轉換;
//(i,j),遍歷j;在樣本i對應標籤位置置爲1;
//比如第5個樣本對應第3個類別,則設置trainClasses(5,3)=1;
if( k == classes.at<int>(i) )
trainClasses.at<float>(i,k) = 1;
else
trainClasses.at<float>(i,k) = 0;
}
}
//所有的訓練樣本權重都爲1;
Mat weights( 1, TrainData.rows, CV_32FC1, Scalar::all(1) );
if (DEBUG)
{
//存儲訓練前的類別標籤;
FileStorage classBefore;
classBefore.open("classBefore.xml", FileStorage::WRITE);
classBefore << "before" << trainClasses;
classBefore.release();
}
//Learn classifier,訓練數據,類別標籤(大矩陣形式),權重;
//類別標籤並不會變化,此API僅訓練ANN;
ann.train( TrainData, trainClasses, weights );
if (DEBUG)
{
//存儲訓練後的類別標籤;
FileStorage classAfter;
classAfter.open("classAfter.xml", FileStorage::WRITE);
classAfter << "after" << trainClasses;
classAfter.release();
}
trained=true;
}
2.3 分類測試
ann.predict(f, output);
2.4 錯誤備註
2.4.1 訓練類別需要使用整型 int
//set the class of train feature;
vector<int> numberLabel;
for (int colsIdx = 0; colsIdx<10; ++colsIdx)
<span style="white-space:pre"> </span>numberLabel.push_back(colsIdx);
Mat(numberLabel).copyTo(ftrClass);
按上述方式新建類別矩陣;for (int rowsIdx = 0, toFtrIdx = 0; rowsIdx < tempFtr.rows; ++rowsIdx)
for (int colsIdx = 0; colsIdx < tempFtr.cols; ++colsIdx, ++toFtrIdx)
ftrNumberTa.at<float>(nuIdex, toFtrIdx) = tempFtr.at<float>(rowsIdx, colsIdx);
矩陣copy取值時,一般將rows作爲第一層,cols作爲第二層;
MatName.at<dataType>(rowsIdx,colsIdx);
另外Mat新建//cols即image的寬;rows即image的高
Mat ftrNumberTa(cv::Size(ftrNumber_cols, ftrNumber_rows), CV_32F);
此文僅簡單記載ANN識別在opencv中的使用流程;