用OpenCV的SVM实现简单的手势识别(切水果)[附源码]

您所在的位置:网站首页 手势识别怎么识别 用OpenCV的SVM实现简单的手势识别(切水果)[附源码]

用OpenCV的SVM实现简单的手势识别(切水果)[附源码]

2024-07-11 09:19| 来源: 网络整理| 查看: 265

基于HOG特征的SVM分类器实现 在机器学习领域,支持向量机SVM(Support Vector Machine)是一个有监督的学习模型,通常用来进行模式识别、分类、以及回归分析。 方向梯度直方图(Histogram of Oriented Gradient, HOG)特征是一种在计算机视觉和图像处理中用来进行物体检测的特征描述子。HOG特征通过计算和统计图像局部区域的梯度方向直方图来构成特征 一、计算HOG void calculateHog(const Mat& src, vector& descriptors,size windowSize,size blockSize,size cellSize) { //梯度方向数 nbins=9 HOGDescriptor myHog = HOGDescriptor(src.size(), windowSize, blockSize, cellSize,9); myHog.compute(src.clone(), descriptors, Size(1, 1), Size(0, 0)); } 二、SVM

因此容易写得一个基于HOG特征SVM分类器

#ifndef HOGSVM_H #define HOGSVM_H #include "cvHeadspace.h" #include #include using namespace cv; using namespace cv::ml; class HogSVM { public: HogSVM(std::string xmlFilePath,Size sWindow,Size sBlock,Size sCell,int enBins=9) { mySVM = Algorithm::load(xmlFilePath); HogDesSize[0]=sWindow; HogDesSize[1]=sBlock; HogDesSize[2]=sCell; nbins=enBins; } int getLabel(const Mat &src) { std::vector imageDescriptor; calculateHog(src, imageDescriptor,HogDesSize[0],HogDesSize[1],HogDesSize[2]); Mat testDescriptor = Mat::zeros(1, imageDescriptor.size(), CV_32FC1); for (size_t i = 0; i predict(testDescriptor); return (int)label; } private: void calculateHog(const Mat& src, std::vector& descriptors,size windowSize,size blockSize,size cellSize) { //梯度方向数 nbins默认为9 HOGDescriptor myHog = HOGDescriptor(src.size(), windowSize, blockSize, cellSize,nbins); myHog.compute(src.clone(), descriptors, Size(1, 1), Size(0, 0)); } int nbins; Size HogDesSize[3]; Ptr pHogSVM; }; #endif // HOGSVM_H 三、测试

简单尝试了一下训练,然后把训练的xml读入,做了测试(这里表格里的单位应该是ms不是s)

int label = tempSvm.getLabel(rROI);

在这里插入图片描述

四、小demo

运用SVM+Qt+openCV写了小demo测试 在这里插入图片描述

适当调整灵敏度后点击“抢占”就能调用windows.api控制鼠标,开始愉快(智杖)的玩耍了!

在这里插入图片描述

五、因为有人需要,更新了一下

时间比较久,有些东西已经没了,不过代码还在,之前没上传的原因就是感觉代码写得太烂,而且就是个本科作业级别的玩具,不好意思上传,但是有人需要,所以上传修改了一下文章,如下。

该项目主要有三个工程, 一个是vs_test_project用于前期的手势识别的测试。 还有一个是svm_train用于训练svm.xml文件。这两个工程文件全部贴在下面了。 QT的gui工程用于展示,但这个工程我没备份😂主要就是调windows api,同时展示一下中间图片变换的过程。

当时是本科作业,主要参考了这位开源的代码和论文,肤色检测部分的原理可以参考这个老哥的本科毕业论文。我主要在这位老哥的工作上干了两件事情: ①做完肤色分割后,是靠肤色点的数量来区别脸部和手部,效果相当不尽人意,于是我在github上找到了一个现有的去除脸部的xml模型,直接用openCV调用即可 ②模板匹配的效果太差,于是将模板匹配替换为了HOG+SVM,提升明显 当时作业的C++水平约等于C with class,勿喷

vs_test_project FaceDetector.h

#pragma once #include using namespace cv; using namespace std; class FaceDetector { public: FaceDetector(void); void removeFaces(Mat &input, Mat &output); };

vs_test_project FaceDetector.cpp

#include "FaceDetector.h" #include #include #include #include #include #include #include Rect getFaceRect(Mat input); String faceClassifierFileName = "haarcascade_frontalface_alt.xml"; CascadeClassifier faceCascadeClassifier; FaceDetector::FaceDetector(void) { if (!faceCascadeClassifier.load(faceClassifierFileName)) throw runtime_error("can't load file " + faceClassifierFileName); } void FaceDetector::removeFaces(Mat &input, Mat &output) { vector faces; Mat frameGray; cvtColor(input, frameGray, CV_BGR2GRAY); equalizeHist(frameGray, frameGray); faceCascadeClassifier.detectMultiScale(frameGray, faces, 1.1, 2, 0 | CASCADE_SCALE_IMAGE, Size(100, 100)); for (size_t i = 0; i 0) return faceRectangles[0]; else return Rect(0, 0, 1, 1); }

vs_test_project HogSvm.h

#pragma once #include #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace cv; using namespace cv::ml; class HogSvm { public: HogSvm(std::string xmlFilePath) { mySVM = Algorithm::load(xmlFilePath); } int getLabel(const Mat &src) { vector imageDescriptor; coumputeHog(src, imageDescriptor); Mat testDescriptor = Mat::zeros(1, imageDescriptor.size(), CV_32FC1); for (size_t i = 0; i predict(testDescriptor); return (int)label; } private: void coumputeHog(const Mat& src, vector& descriptors) { HOGDescriptor myHog = HOGDescriptor(src.size(), Size(32, 32), Size(8, 8), Size(8, 8), 9); myHog.compute(src.clone(), descriptors, Size(1, 1), Size(0, 0)); } Ptr mySVM; };

vs_test_project SkinSegment.h

#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace cv; using namespace std; //值域 struct ValueRange { int lowerBound; int upperBound; ValueRange() { lowerBound = 0; upperBound= 0; } ValueRange(int pLowerBound, int pUpperBound) :lowerBound(pLowerBound), upperBound(pUpperBound) {} int getDistance() { return upperBound - lowerBound; } void updateValueRange(int capVal) { lowerBound = min(lowerBound, capVal); upperBound = max(upperBound, capVal); } }; //像素搜素类 class SearchPixel { public: //种子填充 static void SeedFillfunc(int grayTrackingValue, const cv::Mat& binaryImg, int& blockNums, ValueRange(*yAxisRealm), ValueRange(*xAxisRealm), vector(*pointSet)); static Mat WaterShedToBin(const cv::Mat& binaryImg); }; //线性变换 class LinearConvert { public: static void MirrorConvert(Mat pSrc,Mat &pDst) { int row = pSrc.rows; int col = pSrc.cols; pDst = pSrc.clone(); for (int i = 0; i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3