#include<opencv.hpp>
#include<iostream>
#include<highgui/highgui.hpp>
#include<ml/ml.hpp>
#include<string>
#include<fstream>
#include<vector>
using namespace std;
using namespace cv;
void main()
{
VideoCapture cap("D:\\negtive.mp4");
long totalFrameNumber = cap.get(CAP_PROP_FRAME_COUNT);
cout << totalFrameNumber << endl;
Mat frame;
bool flags = true;
long currentFrame = 0;
while (flags)
{
cap.read(frame);
stringstream str;
str << currentFrame << ".jpg";
imwrite("C:\\Users\\xx\\Desktop\\neg\\neg" + str.str(), frame);
if (currentFrame >= totalFrameNumber)
{
flags = false;
}
currentFrame++;
}
system("pause");
}
利用cmd將圖片名字寫入txt文件中,這個與Linux命令相似,利用cd切換到當前目錄,cd 文件目錄。在輸入 dir /s/b > path.txt。則將圖片路徑寫入txt文件中。
當要進入其他盤時,可以win+R,打開運行窗口,再輸入cmd,進去之後輸入d:,這樣就進入了D盤了,就可以對D盤中的文件進行讀取了。
製作樣本時將樣本複製到word中製作標籤。選中jpg換成jpg^p1,ctrl+h表示替換全局的這個值,加個小三角表示將轉義字符,加p表示換行,在加入1表示後面追加1。這樣就成功的添加了標籤了。
接下來我們通過使用HOG對樣本進行分類,以及模型的訓練。
#include<opencv.hpp>
#include<iostream>
#include<highgui/highgui.hpp>
#include<ml/ml.hpp>
#include<string>
#include<fstream>
#include<vector>
#include<objdetect.hpp>
#include<stdlib.h>
#include<algorithm>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
int ImgWidght = 64;
int ImgHeight = 128;
vector<string> img_path;
vector<int> img_catg;
int nLine = 0;
string buf;
ifstream svm_data("D:\\traindatabase\\path.txt");
unsigned long n;
while (svm_data)
{
if (getline(svm_data, buf))
{
nLine++;
if (nLine%2 ==0)
{
img_catg.push_back(atoi(buf.c_str())); //atoi將字符串轉化爲整型,標誌(0,1)
}
else
{
img_path.push_back(buf); //圖像路徑
}
}
}
svm_data.close();
Mat data_mat, res_mat;
int nImgNum = nLine / 2;
data_mat = Mat::zeros(nImgNum, 3780, CV_32FC1);
res_mat = Mat::zeros(nImgNum, 1, CV_32SC1);
Mat src;
Mat small;
Mat trainImg = Mat(Size(ImgWidght, ImgHeight), 8, 3);
for (string::size_type i = 0; i != img_path.size(); i++)
{
src = imread(img_path[i].c_str());
if (src.empty())
{
cout << "can not load the image" << img_path[i] << endl;
continue;
}
cout << "processing" << img_path[i].c_str() << endl;
resize(src, small, Size(ImgWidght, ImgHeight), (0, 0), (0, 0), 1);
cvtColor(small, small, COLOR_RGB2GRAY);
HOGDescriptor *hog = new HOGDescriptor(Size(ImgWidght, ImgHeight), Size(16,16), Size(8, 8),Size(8,8), 9);
vector<float>descriptors;
hog->compute(small,descriptors, Size(1, 1), Size(0, 0));
//cout << "HOG dimision is" << descriptors.size() << endl;
n = 0;
for (vector<float>::iterator iter=descriptors.begin();iter!=descriptors.end();iter++)
{
data_mat.at<float>(i, n) = *iter;
n++;
}
res_mat.at<float>(i, 0) = img_catg[i];
cout << "end processing " << img_path[i].c_str() << img_catg[i] << endl;
}
//cout << data_mat << endl;
//cout << res_mat << endl;
Ptr<ml::SVM>svm = ml::SVM::create();
cout << "training" << endl;
svm->setType(ml::SVM::C_SVC);
svm->setKernel(ml::SVM::RBF);
svm->setDegree(10.0);
svm->setGamma(8.0);
svm->setCoef0(1.0);
svm->setC(10.0);
svm->setNu(0.5);
svm->setP(0);
svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 1000,0.01));
svm->train(data_mat,ml::ROW_SAMPLE,res_mat);
cout << "End of training" << endl;
svm->save("SVM_HOG.xml");
因爲這個樣本是第一行爲路徑,第二行爲標籤,因此通過這樣的方法可以將路徑轉化爲數組,將對應的每個標籤儲存到數組中,實現對飲料瓶的二分類。接下來就是對SVM的參數的設置,這些參數的說明可以查看官方文檔進行設置,最後將訓練好的xml文件保存到當前文件夾,並通過此模型來判斷物體是不是屬於飲料瓶。
接下來是SVM的預測。
HOGDescriptor hog(Size(64, 128), Size(16, 16), Size(8, 8), Size(8, 8), 9);
int DescriptorDim;
Ptr<ml::SVM>svm = ml::SVM::load("SVM_HOG.xml");
DescriptorDim = svm->getVarCount();
Mat supportVector = svm->getSupportVectors();
int supportVectorNum = supportVector.rows;
cout << "支持向量個數爲" << supportVectorNum << endl;
vector<float>svm_alpha;
vector<float>svm_svidx;
float svm_rho;
svm_rho = svm->getDecisionFunction(0, svm_alpha, svm_svidx);
Mat alphaMat = Mat::zeros(1, supportVectorNum, CV_32FC1);
Mat supportVectorMat = Mat::zeros(supportVectorNum, DescriptorDim, CV_32FC1);
Mat resultMat = Mat::zeros(1, DescriptorDim, CV_32FC1);
supportVectorMat = supportVector;
//將alpha向量的數據複製到alphaMat中,返回SVM決策函數中的alpha向量
for (int i = 0; i < supportVectorNum; i++)
{
alphaMat.at<float>(0, i) = svm_alpha[i];
}
//計算-(alphaMat*supportVectorMat),結果放在resultMat中。
resultMat = -1 * alphaMat * supportVectorMat;
vector<float>myDetector;
//將resultMat中的數據複製到數組myDetector;
for (int i = 0; i < DescriptorDim; i++)
{
myDetector.push_back(resultMat.at<float>(0, i));
}
//最後添加偏移量rho,得到檢測子
myDetector.push_back(svm_rho);
HOGDescriptor myHOG;
myHOG.setSVMDetector(myDetector);
Size s1(128, 128);
Size s2(64, 64);
myHOG.winSize = s1;
myHOG.blockSize = s1;
myHOG.blockStride = s1;
myHOG.cellSize = s2;
myHOG.nbins = 9;
ofstream fout("HOGDetectorForOpenCv.txt");
for (unsigned int i = 0; i < myDetector.size(); i++)
{
fout << myDetector[i] << endl;
}
Mat frame;
Mat src1 = imread("D:\\predict\\3.jpg");
resize(src1, frame, Size(64, 128), (0, 0), (0, 0), 1);
vector<Rect>found,found_filtered;
myHOG.detectMultiScale(frame, found, 0, Size(8, 8), Size(32, 32), 1.05, 2);
cout << "找到的矩形框個數爲" << found.size() << endl;
printf("找到%d個水瓶", found.size());
//找出所有沒有嵌套的矩形框,並放入found_filtered中,如果有嵌套,取最外面的一個
for (unsigned int i = 0; i < found.size(); i++)
{
Rect r = found[i];
unsigned int j = 0;
for (; j < found.size(); j++)
if (j != i && (r & found[j]) == r)
break;
if (j == found.size())
{
found_filtered.push_back(r);
}
}
//畫矩形框
for (unsigned int i = 0; i < found_filtered.size(); i++)
{
Rect r = found_filtered[i];
r.x += cvRound(r.width*0.1);
r.width = cvRound(r.width*0.8);
r.y += cvRound(r.height * 0.07);
r.height = cvRound(r.height*0.8);
rectangle(frame, r.tl(), r.br(), Scalar(255, 0, 0), 5);
}
imshow("frame", frame);
//imshow("src", src);
waitKey(0);
使用訓練好的模型進行判斷,可以預測結果。
接下來是對結果的預測:
HOGDescriptor hog(Size(64, 128), Size(16, 16), Size(8, 8), Size(8, 8), 9);
int DescriptorDim;
Ptr<ml::SVM>svm = ml::SVM::load("SVM_HOG.xml");
DescriptorDim = svm->getVarCount();
Mat supportVector = svm->getSupportVectors();
int supportVectorNum = supportVector.rows;
cout << "支持向量個數爲" << supportVectorNum << endl;
vector<float>svm_alpha;
vector<float>svm_svidx;
float svm_rho;
svm_rho = svm->getDecisionFunction(0, svm_alpha, svm_svidx);
Mat alphaMat = Mat::zeros(1, supportVectorNum, CV_32FC1);
Mat supportVectorMat = Mat::zeros(supportVectorNum, DescriptorDim, CV_32FC1);
Mat resultMat = Mat::zeros(1, DescriptorDim, CV_32FC1);
supportVectorMat = supportVector;
//將alpha向量的數據複製到alphaMat中,返回SVM決策函數中的alpha向量
for (int i = 0; i < supportVectorNum; i++)
{
alphaMat.at<float>(0, i) = svm_alpha[i];
}
//計算-(alphaMat*supportVectorMat),結果放在resultMat中。
resultMat = -1 * alphaMat * supportVectorMat;
vector<float>myDetector;
//將resultMat中的數據複製到數組myDetector;
for (int i = 0; i < DescriptorDim; i++)
{
myDetector.push_back(resultMat.at<float>(0, i));
}
//最後添加偏移量rho,得到檢測子
myDetector.push_back(svm_rho);
HOGDescriptor myHOG;
myHOG.setSVMDetector(myDetector);
Size s1(128, 128);
Size s2(64, 64);
myHOG.winSize = s1;
myHOG.blockSize = s1;
myHOG.blockStride = s1;
myHOG.cellSize = s2;
myHOG.nbins = 9;
ofstream fout("HOGDetectorForOpenCv.txt");
for (unsigned int i = 0; i < myDetector.size(); i++)
{
fout << myDetector[i] << endl;
}
Mat frame;
Mat src = imread("D:\\predict\\2.jpg");
resize(src, frame, Size(64, 128), (0, 0), (0, 0), 1);
vector<Rect>found,found_filtered;
myHOG.detectMultiScale(frame, found, 0, Size(16, 16), Size(16, 16), 1.05, 2);
cout << "找到的矩形框個數爲" << found.size() << endl;
printf("找到%d個水瓶", found.size());
//找出所有沒有嵌套的矩形框,並放入found_filtered中,如果有嵌套,取最外面的一個
for (unsigned int i = 0; i < found.size(); i++)
{
Rect r = found[i];
unsigned int j = 0;
for (; j < found.size(); j++)
if (j != i && (r & found[j]) == r)
break;
if (j == found.size())
{
found_filtered.push_back(r);
}
}
//畫矩形框
for (unsigned int i = 0; i < found_filtered.size(); i++)
{
Rect r = found_filtered[i];
r.x += cvRound(r.width*0.1);
r.width = cvRound(r.width*0.8);
r.y += cvRound(r.height * 0.07);
r.height = cvRound(r.height*0.8);
rectangle(frame, r.tl(), r.br(), Scalar(255, 0, 0), 5);
}
imshow("frame", frame);
//imshow("src", src);
waitKey(0);
這就是SVM的簡單的識別,這段代碼仍然具有很多的錯誤,但是可以實現一些簡單的識別。也存在着精度和速度上的問題,沒有GPU的加速,而且HOG進行檢測時需要算很多,特徵向量有754個,因此帶來的計算問題還需要優化。特徵向量矩陣和分類使用的xml文件如果有需要的可以私信我,因爲文件比較大,在這就不方便發了。