OpenCV:利用OpenCV2.4.9進行SVM圖片分類測試

一、對不同紅色圖片進行分類,圖片名稱爲預設顏色,有三種:深紅色、粉紅色、橘紅色,分別對應標籤名稱"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 謝謝

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章