一、SVM分类器(支持向量机引导)
代码:
//--------------------------------------【程序说明】-------------------------------------------
// 程序说明:支持向量机之SVM引导
// 测试所用操作系统: Windows 10 64bit
// 测试所用IDE版本:Visual Studio 2015(企业版)
// 开发测试所用OpenCV版本: 3.1 beta
// 2017年4月 Revised by 陈梓归
//------------------------------------------------------------------------------------------------
//说明:由于此代码由OpenCV2向OpenCV3升级时改动幅度较大,OpenCV2版本的此代码请参考单独的OpenCV2版本。在此不再列出
//---------------------------------【头文件、命名空间包含部分】----------------------------
// 描述:包含程序所使用的头文件和命名空间
//-------------------------------------------------------------------------------------------------
#include
#include
#include
using namespace cv;
//OpenCV3需额外加入:
#include
#include "opencv2/imgcodecs.hpp"
using namespace cv::ml;
//--------------------------------【help( )函数】----------------------------------------------
// 描述:输出帮助信息
//-------------------------------------------------------------------------------------------------
//-----------------------------------【ShowHelpText( )函数】----------------------------------
// 描述:输出一些帮助信息
//----------------------------------------------------------------------------------------------
void ShowHelpText()
{
//输出欢迎信息和OpenCV版本
printf("\n\n\t\t\t 作者:陈梓归\n");
printf("\n\n\t\t\t 当前使用的OpenCV版本为:" CV_VERSION);
printf("\n\n ----------------------------------------------------------------------------\n");
}
//-----------------------------------【main( )函数】--------------------------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始
//-------------------------------------------------------------------------------------------------
int main()
{
// 视觉表达数据的设置(Data for visual representation)
int width = 512, height = 512;
Mat image = Mat::zeros(height, width, CV_8UC3);
//建立训练数据( Set up training data)
int labels[4] = { 1, -1, -1, -1 };
Mat labelsMat(4, 1, CV_32SC1, labels);
float trainingData[4][2] = { { 501, 10 },{ 255, 10 },{ 501, 255 },{ 10, 501 } };
Mat trainingDataMat(4, 2, CV_32FC1, trainingData);
ShowHelpText();
//设置支持向量机的参数(Set up SVM's parameters)
cv::Ptr
svm = cv::ml::SVM::create(); svm->setType(cv::ml::SVM::Types::C_SVC); svm->setKernel(cv::ml::SVM::KernelTypes::LINEAR); svm->setTermCriteria(cv::TermCriteria(cv::TermCriteria::MAX_ITER, 100, 1e-6)); // 训练支持向量机(Train the SVM) svm->train(trainingDataMat, cv::ml::SampleTypes::ROW_SAMPLE, labelsMat); Vec3b green(0, 255, 0), blue(255, 0, 0); //显示由SVM给出的决定区域 (Show the decision regions given by the SVM) for (int i = 0; i < image.rows; ++i) for (int j = 0; j < image.cols; ++j) { Mat sampleMat = (Mat_
(1, 2) << j, i); float response = svm->predict(sampleMat); if (response == 1) image.at
(i, j) = green; else if (response == -1) image.at
(i, j) = blue; } //显示训练数据 (Show the training data) int thickness = -1; int lineType = 8; circle(image, Point(501, 10), 5, Scalar(0, 0, 0), thickness, lineType); circle(image, Point(255, 10), 5, Scalar(255, 255, 255), thickness, lineType); circle(image, Point(501, 255), 5, Scalar(255, 255, 255), thickness, lineType); circle(image, Point(10, 501), 5, Scalar(255, 255, 255), thickness, lineType); //显示支持向量 (Show support vectors) thickness = 2; lineType = 8; Mat sv = svm->getSupportVectors(); for (int i = 0; i < sv.rows; ++i) { const float* v = sv.ptr
(i); circle(image, Point((int)v[0], (int)v[1]), 6, Scalar(128, 128, 128), thickness, lineType); } imwrite("CZG.png", image); // 保存图像 imshow("SVM Simple Example", image); // 显示图像 waitKey(0); }
效果:
二、SVM分类器(支持向量机之处理线性不可分数据)
注:此例子主要讲解在训练数据线性不可分时,如何定义支持向量机器最优化问题;
代码:
//--------------------------------------【程序说明】-------------------------------------------
// 程序说明:支持向量机之SVM引导
// 测试所用操作系统: Windows 10 64bit
// 测试所用IDE版本:Visual Studio 2015(企业版)
// 开发测试所用OpenCV版本: 3.1 beta
// 2017年4月 Revised by 陈梓归
//------------------------------------------------------------------------------------------------
//说明:由于此代码由OpenCV2向OpenCV3升级时改动幅度较大,OpenCV2版本的此代码请参考单独的OpenCV2版本。在此不再列出
//---------------------------------【头文件、命名空间包含部分】----------------------------
// 描述:包含程序所使用的头文件和命名空间
//------------------------------------------------------------------------------------------------
#include
#include
#include
#include
//OpenCV3需额外加入:
#include
#include "opencv2/imgcodecs.hpp" using namespace cv::ml; #define NTRAINING_SAMPLES 100 // 每类训练样本的数量 #define FRAC_LINEAR_SEP 0.9f // 部分(Fraction)线性可分的样本组成部分 using namespace cv; using namespace std; //-----------------------------------【ShowHelpText( )函数】---------------------------------- // 描述:输出一些帮助信息 //---------------------------------------------------------------------------------------------- void ShowHelpText() { //输出欢迎信息和OpenCV版本 printf("\n\n\t\t\t 作者:陈梓归\n"); printf("\n\n\t\t\t 当前使用的OpenCV版本为:" CV_VERSION); printf("\n\n ----------------------------------------------------------------------------\n"); } //-----------------------------------【main( )函数】-------------------------------------------- // 描述:控制台应用程序的入口函数,我们的程序从这里开始 //------------------------------------------------------------------------------------------------- int main() { //设置视觉表达的参数 const int WIDTH = 512, HEIGHT = 512; Mat I = Mat::zeros(HEIGHT, WIDTH, CV_8UC3); ShowHelpText(); //---------------------【1】随机建立训练数据--------------------------------------- Mat trainData(2 * NTRAINING_SAMPLES, 2, CV_32FC1); Mat labels(2 * NTRAINING_SAMPLES, 1, CV_32SC1); RNG rng(100); // 随机生成值 //建立训练数据的线性可分的组成部分 int nLinearSamples = (int)(FRAC_LINEAR_SEP * NTRAINING_SAMPLES); // 为Class1生成随机点 Mat trainClass = trainData.rowRange(0, nLinearSamples); // 点的x坐标为[0,0.4) Mat c = trainClass.colRange(0, 1); rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(0.4 * WIDTH)); // 点的Y坐标为[0,1) c = trainClass.colRange(1, 2); rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT)); // 为Class2生成随机点 trainClass = trainData.rowRange(2 * NTRAINING_SAMPLES - nLinearSamples, 2 * NTRAINING_SAMPLES); // 点的x坐标为[0.6, 1] c = trainClass.colRange(0, 1); rng.fill(c, RNG::UNIFORM, Scalar(0.6*WIDTH), Scalar(WIDTH)); // 点的Y坐标为[0, 1) c = trainClass.colRange(1, 2); rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT)); //------------------建立训练数据的非线性可分组成部分 --------------- // 随机生成Class1和Class2的点 trainClass = trainData.rowRange(nLinearSamples, 2 * NTRAINING_SAMPLES - nLinearSamples); // 点的x坐标为[0.4, 0.6) c = trainClass.colRange(0, 1); rng.fill(c, RNG::UNIFORM, Scalar(0.4*WIDTH), Scalar(0.6*WIDTH)); // 点的y坐标为[0, 1) c = trainClass.colRange(1, 2); rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT)); //------------------------- 为类设置标签 --------------------------------- labels.rowRange(0, NTRAINING_SAMPLES).setTo(1); // Class 1 labels.rowRange(NTRAINING_SAMPLES, 2 * NTRAINING_SAMPLES).setTo(2); // Class 2 //------------------------ 2. 设置支持向量机的参数 -------------------- cv::Ptr
svm = cv::ml::SVM::create(); svm->setType(cv::ml::SVM::Types::C_SVC); svm->setKernel(cv::ml::SVM::KernelTypes::LINEAR); svm->setTermCriteria(cv::TermCriteria(cv::TermCriteria::MAX_ITER, 100, 1e-6)); //------------------------ 3. 训练支持向量机 ---------------------------------------------------- svm->train(trainData, cv::ml::SampleTypes::ROW_SAMPLE, labels); //------------------------ 4. 标出决策区域(decision regions)---------------------------------------- Vec3b green(0, 100, 0), blue(100, 0, 0); for (int i = 0; i < I.rows; ++i) for (int j = 0; j < I.cols; ++j) { Mat sampleMat = (Mat_
(1, 2) << i, j); float response = svm->predict(sampleMat); if (response == 1) I.at
(j, i) = green; else if (response == 2) I.at
(j, i) = blue; } //----------------------- 5. 显示训练数据(training data)-------------------------------------------- int thick = -1; int lineType = 8; float px, py; // Class 1 for (int i = 0; i < NTRAINING_SAMPLES; ++i) { px = trainData.at
(i, 0); py = trainData.at
(i, 1); circle(I, Point((int)px, (int)py), 3, Scalar(0, 255, 0), thick, lineType); } // Class 2 for (int i = NTRAINING_SAMPLES; i <2 * NTRAINING_SAMPLES; ++i) { px = trainData.at
(i, 0); py = trainData.at
(i, 1); circle(I, Point((int)px, (int)py), 3, Scalar(255, 0, 0), thick, lineType); } //------------------------- 6. 显示支持向量(support vectors)------------------------------------------- thick = 2; lineType = 8; Mat sv = svm->getSupportVectors(); for (int i = 0; i < sv.rows; ++i) { const float* v = sv.ptr
(i); circle(I, Point((int)v[0], (int)v[1]), 6, Scalar(128, 128, 128), thick, lineType); } imwrite("CZG.png", I); //保存图像到文件 imshow("SVM for Non-Linear Training Data", I); // 显示最终窗口 waitKey(0); }
效果:
在这里感谢:http://blog.csdn.net/wfh2015/article/details/51163890
笔者开始运行的时候出现错误(依照大神的代码摸索这解决,感谢~):
1>e:\c++\opencv\opencv\main.cpp(61): error C2039: “Params”: 不是“cv::ml::SVM”的成员
1> d:\vs2015\opencv\opencv\build\include\opencv2\ml.hpp(481): note: 参见“cv::ml::SVM”的声明
1>e:\c++\opencv\opencv\main.cpp(61): error C2065: “Params”: 未声明的标识符
1> d:\vs2015\opencv\opencv\build\include\opencv2\ml.hpp(481): note: 参见“cv::ml::SVM”的声明
1>e:\c++\opencv\opencv\main.cpp(61): error C2065: “Params”: 未声明的标识符
三、人脸识别
注:记得将haarcascade_eye_tree_eyeglasses.xml和haarcascade_frontalface_alt.xml 和源代码放在同一目录(两个.xml文件自己去官网或者opencv\sources\data\haarcascades\)
代码:
//--------------------------------------【程序说明】-------------------------------------------
// 程序说明:支持向量机之SVM引导
// 测试所用操作系统: Windows 10 64bit
// 测试所用IDE版本:Visual Studio 2015(企业版)
// 开发测试所用OpenCV版本: 3.1 beta
// 2017年4月 Revised by 陈梓归
//------------------------------------------------------------------------------------------------
/**
* @file ObjectDetection.cpp
* @author A. Huaman ( based in the classic facedetect.cpp in samples/c )
* @brief A simplified version of facedetect.cpp, show how to load a cascade classifier and how to find objects (Face + eyes) in a video stream
*/
//---------------------------------【头文件、命名空间包含部分】----------------------------
// 描述:包含程序所使用的头文件和命名空间
//-------------------------------------------------------------------------------------------------
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include
#include
using namespace std;
using namespace cv;
void detectAndDisplay(Mat frame);
//--------------------------------【全局变量声明】----------------------------------------------
// 描述:声明全局变量
//-------------------------------------------------------------------------------------------------
//注意,需要把"haarcascade_frontalface_alt.xml"和"haarcascade_eye_tree_eyeglasses.xml"这两个文件复制到工程路径下
String face_cascade_name = "haarcascade_frontalface_alt.xml";
String eyes_cascade_name = "haarcascade_eye_tree_eyeglasses.xml";
CascadeClassifier face_cascade;
CascadeClassifier eyes_cascade;
string window_name = "Capture - Face detection";
RNG rng(12345);
//--------------------------------【help( )函数】----------------------------------------------
// 描述:输出帮助信息
//-------------------------------------------------------------------------------------------------
static void ShowHelpText()
{
//输出欢迎信息和OpenCV版本
cout << "\n\n\t\t\t 作者:陈梓归\n"
<< "\n\n\t\t\t 当前使用的OpenCV版本为:" << CV_VERSION
<< "\n\n ----------------------------------------------------------------------------";
}
//-----------------------------------【main( )函数】--------------------------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始
//-------------------------------------------------------------------------------------------------
int main(void)
{
VideoCapture capture;
Mat frame;
//-- 1. 加载级联(cascades)
if (!face_cascade.load(face_cascade_name)) { printf("--(!)Error loading\n"); return -1; };
if (!eyes_cascade.load(eyes_cascade_name)) { printf("--(!)Error loading\n"); return -1; };
//-- 2. 读取视频
capture.open(0);
ShowHelpText();
if (capture.isOpened())
{
for (;;)
{
capture >> frame;
//-- 3. 对当前帧使用分类器(Apply the classifier to the frame)
if (!frame.empty())
{
detectAndDisplay(frame);
}
else
{
printf(" --(!) No captured frame -- Break!"); break;
}
int c = waitKey(10);
if ((char)c == 'c') { break; }
}
}
return 0;
}
void detectAndDisplay(Mat frame)
{
std::vector
faces;
Mat frame_gray;
cvtColor(frame, frame_gray, COLOR_BGR2GRAY);
equalizeHist(frame_gray, frame_gray);
//-- 人脸检测
//此句代码的OpenCV2版为:
//face_cascade.detectMultiScale( frame_gray, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, Size(30, 30) );
//此句代码的OpenCV3版为:
face_cascade.detectMultiScale(frame_gray, faces, 1.1, 2, 0 | CASCADE_SCALE_IMAGE, Size(30, 30));
for (size_t i = 0; i < faces.size(); i++)
{
Point center(faces[i].x + faces[i].width / 2, faces[i].y + faces[i].height / 2);
ellipse(frame, center, Size(faces[i].width / 2, faces[i].height / 2), 0, 0, 360, Scalar(255, 0, 255), 2, 8, 0);
Mat faceROI = frame_gray(faces[i]);
std::vector
eyes;
//-- 在脸中检测眼睛
//此句代码的OpenCV2版为:
// eyes_cascade.detectMultiScale( faceROI, eyes, 1.1, 2, 0 |CV_HAAR_SCALE_IMAGE, Size(30, 30) );
//此句代码的OpenCV3版为:
eyes_cascade.detectMultiScale(faceROI, eyes, 1.1, 2, 0 | CASCADE_SCALE_IMAGE, Size(30, 30));
for (size_t j = 0; j < eyes.size(); j++)
{
Point eye_center(faces[i].x + eyes[j].x + eyes[j].width / 2, faces[i].y + eyes[j].y + eyes[j].height / 2);
int radius = cvRound((eyes[j].width + eyes[j].height)*0.25);
circle(frame, eye_center, radius, Scalar(255, 0, 0), 3, 8, 0);
}
}
//-- 显示最终效果图
imshow(window_name, frame);
}
效果:
四、点追踪
注:按键盘"r"键来实现自动点追踪。
代码:
//--------------------------------------【程序说明】-------------------------------------------
// 程序说明:支持向量机之SVM引导
// 测试所用操作系统: Windows 10 64bit
// 测试所用IDE版本:Visual Studio 2015(企业版)
// 开发测试所用OpenCV版本: 3.1 beta
// 2017年4月 Revised by 陈梓归
//------------------------------------------------------------------------------------------------
//---------------------------------【头文件、命名空间包含部分】----------------------------
// 描述:包含程序所使用的头文件和命名空间
//-------------------------------------------------------------------------------------------------
#include "opencv2/video/tracking.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include
#include
using namespace cv;
using namespace std;
//--------------------------------【help( )函数】----------------------------------------------
// 描述:输出帮助信息
//-------------------------------------------------------------------------------------------------
static void help()
{
//输出欢迎信息和OpenCV版本
cout << "\n\n\t\t\t 作者:陈梓归\n"
<< "\n\n\t\t\t 当前使用的OpenCV版本为:" << CV_VERSION
<< "\n\n ----------------------------------------------------------------------------";
cout << "\n\n\t该Demo演示了 Lukas-Kanade基于光流的lkdemo\n";
cout << "\n\t程序默认从摄像头读入视频,可以按需改为从视频文件读入图像\n";
cout << "\n\t操作说明: \n"
"\t\t通过点击在图像中添加/删除特征点\n"
"\t\tESC - 退出程序\n"
"\t\tr -自动进行追踪\n"
"\t\tc - 删除所有点\n"
"\t\tn - 开/光-夜晚模式\n" << endl;
}
Point2f point;
bool addRemovePt = false;
//--------------------------------【onMouse( )回调函数】------------------------------------
// 描述:鼠标操作回调
//-------------------------------------------------------------------------------------------------
static void onMouse(int event, int x, int y, int /*flags*/, void* /*param*/)
{
//此句代码的OpenCV2版为:
//if( event == CV_EVENT_LBUTTONDOWN )
//此句代码的OpenCV3版为:
if (event == EVENT_LBUTTONDOWN)
{
point = Point2f((float)x, (float)y);
addRemovePt = true;
}
}
//-----------------------------------【main( )函数】--------------------------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始
//-------------------------------------------------------------------------------------------------
int main(int argc, char** argv)
{
help();
VideoCapture cap;
//此句代码的OpenCV2版为:
//TermCriteria termcrit(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS, 20, 0.03);
//此句代码的OpenCV3版为:
TermCriteria termcrit(TermCriteria::MAX_ITER | TermCriteria::EPS, 20, 0.03);
Size subPixWinSize(10, 10), winSize(31, 31);
const int MAX_COUNT = 500;
bool needToInit = false;
bool nightMode = false;
cap.open(0);
if (!cap.isOpened())
{
cout << "Could not initialize capturing...\n";
return 0;
}
namedWindow("LK Demo", 1);
setMouseCallback("LK Demo", onMouse, 0);
Mat gray, prevGray, image;
vector
points[2];
for (;;)
{
Mat frame;
cap >> frame;
if (frame.empty())
break;
frame.copyTo(image);
cvtColor(image, gray, COLOR_BGR2GRAY);
if (nightMode)
image = Scalar::all(0);
if (needToInit)
{
// 自动初始化
goodFeaturesToTrack(gray, points[1], MAX_COUNT, 0.01, 10, Mat(), 3, 0, 0.04);
cornerSubPix(gray, points[1], subPixWinSize, Size(-1, -1), termcrit);
addRemovePt = false;
}
else if (!points[0].empty())
{
vector
status;
vector
err; if (prevGray.empty()) gray.copyTo(prevGray); calcOpticalFlowPyrLK(prevGray, gray, points[0], points[1], status, err, winSize, 3, termcrit, 0, 0.001); size_t i, k; for (i = k = 0; i < points[1].size(); i++) { if (addRemovePt) { if (norm(point - points[1][i]) <= 5) { addRemovePt = false; continue; } } if (!status[i]) continue; points[1][k++] = points[1][i]; circle(image, points[1][i], 3, Scalar(0, 255, 0), -1, 8); } points[1].resize(k); } if (addRemovePt && points[1].size() < (size_t)MAX_COUNT) { vector
tmp; tmp.push_back(point); //此句代码的OpenCV2版为: //cornerSubPix( gray, tmp, winSize, cvSize(-1,-1), termcrit); //此句代码的OpenCV3版为: cornerSubPix(gray, tmp, winSize, Size(-1, -1), termcrit); points[1].push_back(tmp[0]); addRemovePt = false; } needToInit = false; imshow("LK Demo", image); char c = (char)waitKey(10); if (c == 27) break; switch (c) { case 'r': needToInit = true; break; case 'c': points[0].clear(); points[1].clear(); break; case 'n': nightMode = !nightMode; break; } std::swap(points[1], points[0]); cv::swap(prevGray, gray); } return 0; }
五、光流法检测运动目标
注:光流是目前运动图像分析的重要方法,由Gibso于1950年首先提出。光流用来指定时变图像中模式的运动速度,因为当物体在运动时,在图像上对应点的高度模式也在运动。这种图像高亮模式的表观运动就是光流。光流表达了图像的变化,由于它包含了目标运动的信息,因此可被观察者用来确定目标的运动情况。
代码:
//--------------------------------------【程序说明】-------------------------------------------
// 程序说明:支持向量机之SVM引导
// 测试所用操作系统: Windows 10 64bit
// 测试所用IDE版本:Visual Studio 2015(企业版)
// 开发测试所用OpenCV版本: 3.1 beta
// 2017年4月 Revised by 陈梓归
//------------------------------------------------------------------------------------------------
/************************************************************************
* Copyright(c) 2011 Yang Xian
* All rights reserved.
*
* File: opticalFlow.cpp
* Brief: lk光流法做运动目标检测
* Version: 1.0
* Author: Yang Xian
* Email: xyang2011@sinano.ac.cn
* Date: 2011/11/18
* History:
************************************************************************/
//---------------------------------【头文件、命名空间包含部分】----------------------------
// 描述:包含程序所使用的头文件和命名空间
//-------------------------------------------------------------------------------------------------
#include
#include
#include
#include
#include
#include
using namespace std; using namespace cv; //-----------------------------------【全局函数声明】----------------------------------------- // 描述:声明全局函数 //------------------------------------------------------------------------------------------------- void tracking(Mat &frame, Mat &output); bool addNewPoints(); bool acceptTrackedPoint(int i); //-----------------------------------【全局变量声明】----------------------------------------- // 描述:声明全局变量 //------------------------------------------------------------------------------------------------- string window_name = "optical flow tracking"; Mat gray; // 当前图片 Mat gray_prev; // 预测图片 vector
points[2]; // point0为特征点的原来位置,point1为特征点的新位置 vector
initial; // 初始化跟踪点的位置 vector
features; // 检测的特征 int maxCount = 500; // 检测的最大特征数 double qLevel = 0.01; // 特征检测的等级 double minDist = 10.0; // 两特征点之间的最小距离 vector
status; // 跟踪特征的状态,特征的流发现为1,否则为0 vector
err; //--------------------------------【help( )函数】---------------------------------------------- // 描述:输出帮助信息 //------------------------------------------------------------------------------------------------- static void help() { //输出欢迎信息和OpenCV版本 cout << "\n\n\t\t\t 作者:陈梓归\n" << "\n\n\t\t\t 当前使用的OpenCV版本为:" << CV_VERSION << "\n\n ----------------------------------------------------------------------------"; } //-----------------------------------【main( )函数】-------------------------------------------- // 描述:控制台应用程序的入口函数,我们的程序从这里开始 //------------------------------------------------------------------------------------------------- int main() { Mat frame; Mat result; VideoCapture capture("1.avi"); help(); if (capture.isOpened()) // 摄像头读取文件开关 { while (true) { capture >> frame; if (!frame.empty()) { tracking(frame, result); } else { printf(" --(!) No captured frame -- Break!"); break; } int c = waitKey(50); if ((char)c == 27) { break; } } } return 0; } //------------------------------------------------------------------------------------------------- // function: tracking // brief: 跟踪 // parameter: frame 输入的视频帧 // output 有跟踪结果的视频帧 // return: void //------------------------------------------------------------------------------------------------- void tracking(Mat &frame, Mat &output) { //此句代码的OpenCV3版为: cvtColor(frame, gray, COLOR_BGR2GRAY); //此句代码的OpenCV2版为: //cvtColor(frame, gray, CV_BGR2GRAY); frame.copyTo(output); // 添加特征点 if (addNewPoints()) { goodFeaturesToTrack(gray, features, maxCount, qLevel, minDist); points[0].insert(points[0].end(), features.begin(), features.end()); initial.insert(initial.end(), features.begin(), features.end()); } if (gray_prev.empty()) { gray.copyTo(gray_prev); } // l-k光流法运动估计 calcOpticalFlowPyrLK(gray_prev, gray, points[0], points[1], status, err); // 去掉一些不好的特征点 int k = 0; for (size_t i = 0; i
2); }
效果:
六、彩色目标跟踪
注:根据鼠标框选区域的色度光谱来进行摄像头读入的视屏目标的跟踪。(主要采用Camshift算法)。
代码:
//--------------------------------------【程序说明】-------------------------------------------
// 程序说明:支持向量机之SVM引导
// 测试所用操作系统: Windows 10 64bit
// 测试所用IDE版本:Visual Studio 2015(企业版)
// 开发测试所用OpenCV版本: 3.1 beta
// 2017年4月 Revised by 陈梓归
//------------------------------------------------------------------------------------------------
//---------------------------------【头文件、命名空间包含部分】----------------------------
// 描述:包含程序所使用的头文件和命名空间
//-------------------------------------------------------------------------------------------------
#include "opencv2/video/tracking.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include
#include
using namespace cv;
using namespace std;
//-----------------------------------【全局变量声明】-----------------------------------------
// 描述:声明全局变量
//-------------------------------------------------------------------------------------------------
Mat image;
bool backprojMode = false;
bool selectObject = false;
int trackObject = 0;
bool showHist = true;
Point origin;
Rect selection;
int vmin = 10, vmax = 256, smin = 30;
//--------------------------------【onMouse( )回调函数】------------------------------------
// 描述:鼠标操作回调
//-------------------------------------------------------------------------------------------------
static void onMouse( int event, int x, int y, int, void* )
{
if( selectObject )
{
selection.x = MIN(x, origin.x);
selection.y = MIN(y, origin.y);
selection.width = std::abs(x - origin.x);
selection.height = std::abs(y - origin.y);
selection &= Rect(0, 0, image.cols, image.rows);
}
switch( event )
{
//此句代码的OpenCV2版为:
//case CV_EVENT_LBUTTONDOWN:
//此句代码的OpenCV3版为:
case EVENT_LBUTTONDOWN:
origin = Point(x,y);
selection = Rect(x,y,0,0);
selectObject = true;
break;
//此句代码的OpenCV2版为:
//case CV_EVENT_LBUTTONUP:
//此句代码的OpenCV3版为:
case EVENT_LBUTTONUP:
selectObject = false;
if( selection.width > 0 && selection.height > 0 )
trackObject = -1;
break;
}
}
//--------------------------------【help( )函数】----------------------------------------------
// 描述:输出帮助信息
//-------------------------------------------------------------------------------------------------
static void ShowHelpText()
{
cout <<"\n\n\t\t\t 作者:陈梓归\n"
<< "\n\n\t\t\t 当前使用的OpenCV版本为:" << CV_VERSION
<<"\n\n ----------------------------------------------------------------------------" ;
cout << "\n\n\t此Demo显示了基于均值漂移的追踪(tracking)技术\n"
"\t请用鼠标框选一个有颜色的物体,对它进行追踪操作\n";
cout << "\n\n\t操作说明: \n"
"\t\t用鼠标框选对象来初始化跟踪\n"
"\t\tESC - 退出程序\n"
"\t\tc - 停止追踪\n"
"\t\tb - 开/关-投影视图\n"
"\t\th - 显示/隐藏-对象直方图\n"
"\t\tp - 暂停视频\n";
}
const char* keys =
{
"{1| | 0 | camera number}"
};
//-----------------------------------【main( )函数】--------------------------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始
//-------------------------------------------------------------------------------------------------
int main( int argc, const char** argv )
{
ShowHelpText();
VideoCapture cap;
Rect trackWindow;
int hsize = 16;
float hranges[] = {0,180};
const float* phranges = hranges;
cap.open(0);
if( !cap.isOpened() )
{
cout << "不能初始化摄像头\n";
}
namedWindow( "Histogram", 0 );
namedWindow( "CamShift Demo", 0 );
setMouseCallback( "CamShift Demo", onMouse, 0 );
createTrackbar( "Vmin", "CamShift Demo", &vmin, 256, 0 );
createTrackbar( "Vmax", "CamShift Demo", &vmax, 256, 0 );
createTrackbar( "Smin", "CamShift Demo", &smin, 256, 0 );
Mat frame, hsv, hue, mask, hist, histimg = Mat::zeros(200, 320, CV_8UC3), backproj;
bool paused = false;
for(;;)
{
if( !paused )
{
cap >> frame;
if( frame.empty() )
break;
}
frame.copyTo(image);
if( !paused )
{
cvtColor(image, hsv, COLOR_BGR2HSV);
if( trackObject )
{
int _vmin = vmin, _vmax = vmax;
inRange(hsv, Scalar(0, smin, MIN(_vmin,_vmax)),
Scalar(180, 256, MAX(_vmin, _vmax)), mask);
int ch[] = {0, 0};
hue.create(hsv.size(), hsv.depth());
mixChannels(&hsv, 1, &hue, 1, ch, 1);
if( trackObject < 0 )
{
Mat roi(hue, selection), maskroi(mask, selection);
calcHist(&roi, 1, 0, maskroi, hist, 1, &hsize, &phranges);
//此句代码的OpenCV3版为:
normalize(hist, hist, 0, 255, NORM_MINMAX);
//此句代码的OpenCV2版为:
//normalize(hist, hist, 0, 255, CV_MINMAX);
trackWindow = selection;
trackObject = 1;
histimg = Scalar::all(0);
int binW = histimg.cols / hsize;
Mat buf(1, hsize, CV_8UC3);
for( int i = 0; i < hsize; i++ )
buf.at
(i) = Vec3b(saturate_cast
(i*180./hsize), 255, 255);
//此句代码的OpenCV3版为:
cvtColor(buf, buf, COLOR_HSV2BGR);
//此句代码的OpenCV2版为:
//cvtColor(buf, buf, CV_HSV2BGR);
for( int i = 0; i < hsize; i++ )
{
int val = saturate_cast
(hist.at
(i)*histimg.rows/255); rectangle( histimg, Point(i*binW,histimg.rows), Point((i+1)*binW,histimg.rows - val), Scalar(buf.at
(i)), -1, 8 ); } } calcBackProject(&hue, 1, 0, hist, backproj, &phranges); backproj &= mask; RotatedRect trackBox = CamShift(backproj, trackWindow, //此句代码的OpenCV3版为: TermCriteria( TermCriteria::EPS | TermCriteria::COUNT, 10, 1 )); //此句代码的OpenCV2版为: //TermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 )); if( trackWindow.area() <= 1 ) { int cols = backproj.cols, rows = backproj.rows, r = (MIN(cols, rows) + 5)/6; trackWindow = Rect(trackWindow.x - r, trackWindow.y - r, trackWindow.x + r, trackWindow.y + r) & Rect(0, 0, cols, rows); } if( backprojMode ) cvtColor( backproj, image, COLOR_GRAY2BGR ); //此句代码的OpenCV3版为: ellipse( image, trackBox, Scalar(0,0,255), 3, LINE_AA ); //此句代码的OpenCV2版为: //ellipse( image, trackBox, Scalar(0,0,255), 3, CV_AA ); } } else if( trackObject < 0 ) paused = false; if( selectObject && selection.width > 0 && selection.height > 0 ) { Mat roi(image, selection); bitwise_not(roi, roi); } imshow( "CamShift Demo", image ); imshow( "Histogram", histimg ); char c = (char)waitKey(10); if( c == 27 ) break; switch(c) { case 'b': backprojMode = !backprojMode; break; case 'c': trackObject = 0; histimg = Scalar::all(0); break; case 'h': showHist = !showHist; if( !showHist ) destroyWindow( "Histogram" ); else namedWindow( "Histogram", 1 ); break; case 'p': paused = !paused; break; default: ; } } return 0; }
效果:
大家有没有更加有兴趣呢~