一、對不同紅色圖檔進行分類,圖檔名稱為預設顔色,有三種:深紅色、粉紅色、橘紅色,分别對應标簽名稱"crimson", "pink","tangerine"。
二、利用圖檔的RGB所占比例作為三個特征,對紅色圖檔進行SVM訓練,并進行預測分類。訓練所用圖檔和要預測的圖檔分布放在兩個檔案夾中。

三、代碼【用到了Qt】分享給有需要的人,代碼品質勿噴。
void xjImage::xjSVMtest2()//紅色分類
{
#pragma region 資料情況
const string xjSampleFolder = "E:/SVM/ImgColor/train";//樣本資料檔案夾
vector<string> xjSampleFiles;//用來存儲檔案名
SVMfunction * xjSvmFun = new SVMfunction();
xjSvmFun->xjGetFilesNames(xjSampleFolder, xjSampleFiles);
const int xjSampleSum = xjSampleFiles.size();//訓練樣本數量
string xjLabelName[3] = { "crimson", "pink","tangerine" };//類别名稱
const int xjClassSum = 3;//樣本類别數量
const int xjFeatureSum = 3;//樣本特征數量:RGB的均值
//訓練資料及标簽
Mat xjMatSampleTrain = Mat::zeros(xjSampleSum, xjFeatureSum, CV_32FC1);//據說好像必須是CV_32FC1
Mat xjMatSampleLabel = Mat::zeros(xjSampleSum, 1, CV_32SC1);
#pragma endregion
#pragma region 建立訓練資料:3個特征和标簽
for (int i = 0; i < xjSampleSum; i++)
{
string xjTrainName = xjSampleFiles[i];
Mat xjMatTrainData = imread(xjTrainName);
float Pred = 0, Pgreen = 0, Pblue = 0;
int red, green, blue;
float rgbSum = 0;
for (int r = 1; r < xjMatTrainData.rows; r++)
{
for (int c = 1; c < xjMatTrainData.cols; c++)
{
red = xjMatTrainData.at<Vec3b>(r, c)[2];
green = xjMatTrainData.at<Vec3b>(r, c)[1];
blue = xjMatTrainData.at<Vec3b>(r, c)[0];
rgbSum = red + green + blue;
Pred += red / rgbSum;
Pgreen += green / rgbSum;
Pblue += blue / rgbSum;
}
}
Pred /= (xjMatTrainData.rows*xjMatTrainData.cols);
Pgreen /= (xjMatTrainData.rows*xjMatTrainData.cols);
Pblue /= (xjMatTrainData.rows*xjMatTrainData.cols);
xjMatSampleTrain.at<float>(i, 0) = Pred;//特征1
xjMatSampleTrain.at<float>(i, 1) = Pgreen;//特征2
xjMatSampleTrain.at<float>(i, 2) = Pblue;//特征3
int xjLabel = xjSvmFun->xjGetLabelByFileName(xjTrainName, xjLabelName);
xjMatSampleLabel.at<int>(i, 0) = xjLabel;//标簽(類别)
}
#pragma endregion
#pragma region SVM參數和訓練模型
CvSVMParams SVMparameter;//參數
SVMparameter.svm_type = CvSVM::C_SVC;
SVMparameter.kernel_type = CvSVM::LINEAR;
SVMparameter.degree = 1.0;
SVMparameter.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6);
CvSVM SVM;//訓練模型
SVM.train(xjMatSampleTrain, xjMatSampleLabel, Mat(), Mat(), SVMparameter);
#pragma endregion
#pragma region 預測分類
string xjResult = "";
const string xjForecastFolder = "E:/SVM/ImgColor/forecast";
vector<string> xjForecastFiles;
xjSvmFun->xjGetFilesNames(xjForecastFolder, xjForecastFiles);
const int xjForecastSum = xjForecastFiles.size();//預測資料數量
for (int i = 0; i < xjForecastSum; i++)
{
//預測資料特征和标簽
Mat xjForecastData = Mat::zeros(1, xjFeatureSum, CV_32FC1);
Mat xjForecastLabel;
string xjForecastName = xjForecastFiles[i];
Mat xjMatForecast = imread(xjForecastName);
float Pred = 0, Pgreen = 0, Pblue = 0;
int red, green, blue;
float rgbSum = 0;
for (int r = 1; r < xjMatForecast.rows; r++)
{
for (int c = 1; c < xjMatForecast.cols; c++)
{
red = xjMatForecast.at<Vec3b>(r, c)[2];
green = xjMatForecast.at<Vec3b>(r, c)[1];
blue = xjMatForecast.at<Vec3b>(r, c)[0];
rgbSum = red + green + blue;
Pred += red / rgbSum;
Pgreen += green / rgbSum;
Pblue += blue / rgbSum;
}
}
Pred /= (xjMatForecast.rows*xjMatForecast.cols);
Pgreen /= (xjMatForecast.rows*xjMatForecast.cols);
Pblue /= (xjMatForecast.rows*xjMatForecast.cols);
//三個特征
xjForecastData.at<float>(0, 0) = Pred;
xjForecastData.at<float>(0, 1) = Pgreen;
xjForecastData.at<float>(0, 2) = Pblue;
//預測
SVM.predict(xjForecastData, xjForecastLabel);
//預測結果
int xjClassLabel = xjForecastLabel.at<float>(0, 0);
string xjForecastResult = xjLabelName[xjClassLabel];//結果
QString qFileFullPath = QString::fromStdString(xjForecastName);
QFileInfo xjFileInfo(qFileFullPath);
QString qFileName = xjFileInfo.completeBaseName();
string xjFileName = qFileName.toStdString();
putText(xjMatForecast, xjFileName + "" + xjForecastResult, Point(30, 30),
FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 0, 0), 1, 1);
imshow("結果對比", xjMatForecast);
waitKey(200);
xjResult += xjFileName + "--" + xjForecastResult + "\r\n";
}
#pragma endregion
QString xjQResult = QString::fromStdString(xjResult);
QMessageBox::information(NULL, "提示", xjQResult);
}
//擷取檔案夾下的所有檔案名稱
void SVMfunction::xjGetFilesNames(const string & xjFolder, vector<string> & xjFiles)
{
//檔案句柄
long hFile = 0;
struct _finddata_t fileinfo;
std::string p;
if((hFile = _findfirst(p.assign(xjFolder).append("\\*").c_str(),&fileinfo)) != -1)
{
do
{
//如果是目錄,疊代之
//如果不是,加入清單
if((fileinfo.attrib & _A_SUBDIR))
{
if(strcmp(fileinfo.name,".") != 0 && strcmp(fileinfo.name,"..") != 0)
xjGetFilesNames(p.assign(xjFolder).append("\\").append(fileinfo.name), xjFiles);
}
else
{
xjFiles.push_back(p.assign(xjFolder).append("\\").append(fileinfo.name));
}
} while (_findnext(hFile, &fileinfo) == 0);
//_findclose(hFile);
}
}
//根據檔案名稱擷取分類标簽
int SVMfunction::xjGetLabelByFileName(string FileFullPath, string xjLabelName[])
{
int xjLabel = 0;
//檔案名稱
QString qFileFullPath = QString::fromStdString(FileFullPath);
QFileInfo xjFileInfo(qFileFullPath);
QString qFileName = xjFileInfo.completeBaseName();
string xjFileName = qFileName.toStdString();
string labelName;
string::size_type idx;
for (int i = 0; i < 3; i++)
{
labelName = xjLabelName[i];
//字元串是否包含子字元串
if (xjFileName.find(labelName) < xjFileName.length())
{
xjLabel = i;
break;
}
}
return xjLabel;
}
四、結果
最後三個分類是錯誤的。
五、分析
SVM是監督分類,在訓練樣本數量不足或者特征不明顯的情況下,分類錯誤的機率會大大提高。
圖檔見:連結:https://pan.baidu.com/s/1WlnlEfkgmnx8Wvpp4c6Lag
提取碼:j2ds
百度網盤系統維護,一定要有提取碼
【注】本文參考 https://blog.csdn.net/akadiao/article/details/79278072 謝謝