还是基于老鼠
#include <iostream>
#include <fstream>
#include <ctime>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/ml/ml.hpp>
#include <opencv2/tracking.hpp>
using namespace std;
using namespace cv;
using namespace cv::ml;
vector<float> train(HOGDescriptor& hog)
{
Ptr<SVM> svm = Algorithm::load<SVM>("mouse.xml");
Mat svmat = svm->getSupportVectors();//获取每个支持向量,
int cols = svm->getVarCount();//支持向量的维数,也就是svmat.cols
int rows = svmat.rows;//支持向量的个数
Mat alphamat = Mat::zeros(rows, cols, CV_32F);//初始化拉格朗日乘子,也就是α_i,α_j,其中alpmat不为0的也就是支持向量
Mat svindex = Mat::zeros(1, rows, CV_64F);//初始化一个记录支持向量编号的索引,也就是i,j
Mat Result;//ω
double rho;//b
rho = svm->getDecisionFunction(0, alphamat, svindex);//获得决策函数,解出α,b,注意因为y=wx+b,-b=wx-y,-wx=b-y,这里解出来的α和b是反的。 0代表1-2分类 n分类可自己设n
alphamat.convertTo(alphamat, CV_32F);//因为getDecisionFunction会改变类型 将alphamat元素的数据类型重新转成CV_32F 不然会报错
Result = -alphamat * svmat;//推导的过程中我们知道是α_i * α_j*x_i*x_j,也就是列向量ω,因为上文我们知道α和b是反的,所以*-1变正
vector<float> vec;//分类器
for (int i = 0; i < cols; i++)
{
vec.push_back(Result.at<float>(0, i));
}
vec.push_back(rho);//+b
cout << "检测子维数:" << vec.size() << endl;
ofstream fopen1("svm_vec.txt");//保存vec写入文件
for (int i = 0; i < vec.size(); i++)
{
fopen1 << vec[i] << " ";
}
fopen1.close();
return vec;
}
void track()
{
Mat frame;
Rect2d roi;
HOGDescriptor hog(Size(64, 128), Size(16, 16), Size(8, 8), Size(8, 8), 9);
vector<float> vec;
vec = train(hog);//HOG特征 + SVM训练
hog.setSVMDetector(vec);//设置SVM检测器
//VideoCapture cap("mouse.mp4",0);//跟踪视频
VideoCapture cap(0);//跟踪摄像头
cap >> frame;
int p = 4;
resize(frame, frame, Size(frame.cols /p,frame.rows /p));
if (frame.empty())
{
cout << "视频不存在" << endl;
}
vector<Rect> found, found_filtered;
clock_t startTime, finishTime;
cout << "开始检测" << endl;
startTime = clock();
hog.detectMultiScale(frame, found, 0, Size(2, 2), Size(4, 4), 1.05, 2);//多尺度检测目标,返回的矩形从大到小排列
finishTime = clock();
cout << "检测所用时间为" << (finishTime - startTime)*1.0 / CLOCKS_PER_SEC << " 秒 " << endl;
cout << endl << "矩形框的尺寸为 : " << found.size() << endl;
for (size_t i = 0; i < found.size(); i++)
{
Rect r = found[i];
size_t j;
for (j = 0; j < found.size(); j++)// 如果有嵌套的话,则取外面最大的那个矩形框放入found_filtered中
if (j != i && (r & found[j]) == r)
break;
if (j == found.size())
found_filtered.push_back(r);
}
cout << "嵌套矩形框尺寸= " << found_filtered.size() << " Rects" << endl;
for (size_t i = 0; i < found_filtered.size(); i++)//因为检测到的roi总是大于实际的,所以我们做下调整
{
roi = found_filtered[i];
// hog检测结果返回的矩形比实际的要大一些
roi.x += cvRound(roi.width * 0.1);
roi.width = cvRound(roi.width * 0.8);
roi.y += cvRound(roi.height * 0.07);
roi.height = cvRound(roi.height * 0.8);
}//多个嵌套矩阵
Ptr<TrackerKCF> tracker = TrackerKCF::create();
//下面这三条语句很重要,把多目标框筛出来的框作为感兴趣的区域传递给跟踪器,实现自动跟踪
tracker->init(frame, roi);//追踪第一帧
while(1)
{
cap >> frame;
resize(frame, frame, Size(frame.cols /p, frame.rows /p));
tracker->update(frame,roi);//刷新ROI的位置
rectangle(frame, roi, Scalar(255, 0, 0), 2, 1);
imshow("捕捉老鼠", frame);
//quit on ESC button
if (char(waitKey(1)) == 'q')//按键退出视频
{
cv::destroyWindow("捕捉老鼠");
break;
}
}
}
int main()
{
track();
return 0;
}