对每个分离的对象进行分类
训练系统,以便能够学习必需的参数,从而决定将哪个特定标签分配给检测到的对象
机器学习的基本概念,以便对具有不同标签的图像进行分类
机器学习:计算机无须明确编程就能够开展学习的能力
机器学习涉及到人工智能中的模式识别和学习理论,并且与计算统计学有关
应用:OCR、垃圾邮件过滤、搜索引擎以及数以千计的计算机视觉应用程序。
机器学习算法从输入数据中进行学习的方式:
继承自StatModel类的8种算法:
bool train(const Ptr<TrainData>& trainData, int falgs = 0);
bool train(InputArray samples, int layout, INputArray responses);
Ptr<_Tp> train(const Ptr<TrainData>& data, int falgs = 0);
参数:
TrainData:训练数据可以从TrainData类加载或创建,该类可帮助开发人员从机器学习算法中创建和提取训练数据。
samples:一系列的训练阵列样本,例如采用机器学习算法所需格式的训练数据
layout:ROW_SAMPLE(训练样本是矩阵行)或COL_SAMPLE(训练样本是矩阵列)。
responses:与样本数据相关的响应向量。
flags:由每个方法定义的可选标志。
predict
float StatModel::predict(InputArray samples, OutputArray results=noArray(), int flags = 0);
参数:
samples:用于预测模型结果的输入样本可以包含任意数量的数据,无论是单个还
是多个。
results:每个输入行样本的结果(由先前训练的模型的算法计算)。
flags:这些可选标志与模型有关。某些模型(如Boost)由SVM StatModel::RAW
_OUTPUT标志识别,这使得该方法可以返回原始结果(总和),而不是类标签。
StatModel类为其他非常有用的方法提供接口:
具备机器学习的计算机视觉应用具有共同的基本结构,这种结构分为不同的步骤
预处理:去除光和噪声、滤波、模糊。。。
分割:提取图像中的感兴趣区域,并将每个区域隔离为感兴趣的唯一对象
特征提取:特征用于描述对象,可以是对象区域、轮廓、纹理图案、像素等
分类结果:对象的描述符[特征向量或特征集],是用于描述对象的特征,用它们来训练或预测模型。须创建一个大型的特征数据集,其中预先处理了数千个图像,在选择的训练模型函数中使用提取的特征(图像/对象的特征),如面积、大小和纵横比。
步骤
不同对象可能的特征:
vector<vector<float>> ExtractFeatures(Mat img, vector<int>* left = NULL, vector<int>* top = NULL) {
vector<vector<float>> output;
vector<vector<Point>> contours;
Mat input = img.clone();
vector<Vec4i> hierarchy;
findContours(input, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
if(contours.size() == 0)
return output;
RNG rng(0xFFFFFFFF);
for(auto i = 0; i < contours.size(); ++i) {
Mat mask = Mat::zeros(img.rows, img.cols, CV_8UC1);
drawContours(mask, contours, i, Scalar(1), FILLED, LIN8, hierarchy, 1);
Scalar areas_s = sum(mask);
float area = area_s[0];
if(area > 500) {
RotatedRect r = minAreaRect(contours[i]);
float width r.size.width;
float heigh = r.size.height;
float ar = (width < height) ? height / width : width / height;
vector<float> row;
row.push_back(area, ar);
output.push_back(row);
if(left != NULL)
left->push_back((int)(r.center.x));
if(top != NULL)
top->push_back((int)(r.center.y));
miw->addImage("ExtractF Features", mask * 255);
miw->render();
waitKey(10);
}
}
return output;
}
用监督学习,为每个对象及其相应的标签获取一组图像。
创建模型。OpenCV使用Ptr模板类进行指针管理 Ptr svm;
void trainAndTest()
{
vector< float > trainingData;
vector< int > responsesData;
vector< float > testData;
vector< float > testResponsesData;
int num_for_test= 20;
// Get the nut images
readFolderAndExtractFeatures("../data/nut/tuerca_%04d.pgm", 0, num_for_test, trainingData, responsesData, testData, testResponsesData);
// Get and process the ring images
readFolderAndExtractFeatures("../data/ring/arandela_%04d.pgm", 1, num_for_test, trainingData, responsesData, testData, testResponsesData);
// get and process the screw images
readFolderAndExtractFeatures("../data/screw/tornillo_%04d.pgm", 2, num_for_test, trainingData, responsesData, testData, testResponsesData);
cout << "Num of train samples: " << responsesData.size() << endl;
cout << "Num of test samples: " << testResponsesData.size() << endl;
// Merge all data
Mat trainingDataMat(trainingData.size()/2, 2, CV_32FC1, &trainingData[0]);
Mat responses(responsesData.size(), 1, CV_32SC1, &responsesData[0]);
Mat testDataMat(testData.size()/2, 2, CV_32FC1, &testData[0]);
Mat testResponses(testResponsesData.size(), 1, CV_32FC1, &testResponsesData[0]);
Ptr<TrainData> tdata= TrainData::create(trainingDataMat, ROW_SAMPLE, responses);
svm = cv::ml::SVM::create();
svm->setType(cv::ml::SVM::C_SVC);
svm->setNu(0.05);
svm->setKernel(cv::ml::SVM::CHI2);
svm->setDegree(1.0);
svm->setGamma(2.0);
svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6));
svm->train(tdata);
if(testResponsesData.size()>0){
cout << "Evaluation" << endl;
cout << "==========" << endl;
// Test the ML Model
Mat testPredict;
svm->predict(testDataMat, testPredict);
cout << "Prediction Done" << endl;
// Error calculation
Mat errorMat= testPredict!=testResponses;
float error= 100.0f * countNonZero(errorMat) / testResponsesData.size();
cout << "Error: " << error << "\%" << endl;
// Plot training data with error label
plotTrainData(trainingDataMat, responses, &error);
}else{
plotTrainData(trainingDataMat, responses);
}
}
bool readFolderAndExtractFeatures(string folder, int label, int num_for_test,
vector<float> &trainingData, vector<int> &responsesData,
vector<float> &testData, vector<float> &testResponsesData)
{
VideoCapture images;
if(images.open(folder)==false){
cout << "Can not open the folder images" << endl;
return false;
}
Mat frame;
int img_index=0;
while( images.read(frame) ){
Preprocess image
Mat pre= preprocessImage(frame);
// Extract features
vector< vector<float> > features= ExtractFeatures(pre);
for(int i=0; i< features.size(); i++){
if(img_index >= num_for_test){
trainingData.push_back(features[i][0]);
trainingData.push_back(features[i][1]);
responsesData.push_back(label);
}else{
testData.push_back(features[i][0]);
testData.push_back(features[i][1]);
testResponsesData.push_back((float)label);
}
}
img_index++;
}
return true;
}
bool readFolderAndExtractFeatures(string folder, int label, int num_for_test,
vector<float> &trainingData, vector<int> &responsesData,
vector<float> &testData, vector<float> &testResponsesData)
{
VideoCapture images;
if(images.open(folder)==false){
cout << "Can not open the folder images" << endl;
return false;
}
Mat frame;
int img_index=0;
while( images.read(frame) ){
Preprocess image
Mat pre= preprocessImage(frame);
// Extract features
vector< vector<float> > features= ExtractFeatures(pre);
for(int i=0; i< features.size(); i++){
if(img_index >= num_for_test){
trainingData.push_back(features[i][0]);
trainingData.push_back(features[i][1]);
responsesData.push_back(label);
}else{
testData.push_back(features[i][0]);
testData.push_back(features[i][1]);
testResponsesData.push_back((float)label);
}
}
img_index++;
}
return true;
}