(49)Air Band生成自己的级联分类器并进行手势识别(学习版)

我们使用OpenCV2.4.13自带的样本生成工具和支持向量机来生成自己的手势级联分类器。

大致的过程参见 Opencv目标检测之级联分类器训练与测试

按照这个过程执行也有一些问题,在这里记录一下。


1.准备正样本

这里我用Kinect拍摄了三十多张手部图片,将他们在PS里截取手部并统一改为30*28的大小(这个办法并不好,训练集可能很大,效率太低,应在拍摄时就注意手的位置,然后使用一些工具批量修改大小),刚开始使用的就是原图640*480,也不是全图只有手部,处理起来电脑“僵劲不能动”,于是修改大小。

这里还涉及到统一命名的问题,Kinect拍摄截图后名称不统一(问题不大)可能中间还有空格(问题很大),于是将图片放到一个文件夹pos中,全选+F2,修改第一个图片的名字,后面的会自动改成相同的名字加上序号,但是仍然有空格。这里用到控制台在pos文件加下进行dir /b>pos.dat这样就能将所有文件名一行行放到pos/pos.dat文件中,我们将所有图片文件名(需要将pos.dat这一行删除)拷贝到excel中,第一列全部写上ren,第二列为文件名(注意在两边加上双引号,使用"替换工具"),第三列为没有空格的文件名(使用“替换”工具)。然后将三列拷贝到一个文本文件中,再用notepad替换将制表符换为空格,将该文件命名为a.bat,双击执行,所有文件名就替换好了,这时再生成(或用之前替换过的)pos.dat文件,让然可以用notepad或记事本自带的替换在每行后写上" 1 0 0 30 28",1表示每个文件中只有一个目标,0,0是目标位置,30,28是目标大小(也有文章说是左上角和右下角的坐标)。这样我们就生成了可使用的pos.dat文件。



(刚刚说我只有30多张图片,是的,我只是复制成了4倍,所以才有那么多名字要替换,否则名称中全是空格;不一定要很多张,手势等可能需要的稍微多一点因为有变化,固定的物体一张也可以,而且我用复制的方式得到这么多张其实并不一定有用)

用opencv_createsamples.exe生成.vec格式的正样本文件:

第一个写opencv_createsamples.exe的带路径文件名,-info后写pos.dat的带路径文件名,-vec后写生成文件名,-num后写正样本数量,-w为正样本宽度,-h为正样本高度。
"D:\OpenCV\opencv\build\x64\vc12\bin\opencv_createsamples.exe" -info pos/pos.dat -vec pos.vec -num 156 -w 30 -h 28
pause


  
于是在和pos文件夹同一级的位置出现了pos.vec文件,注意文件名中如果有空格很可能出错,会报告生成了0个样本。



2.准备负样本

任意不带有检测目标的图片(我这里出现了手,其实不太好),任意的名字均可,同样生成一个neg.dat文件,这个文件中只有文件名就可以了



注意:正样本和pos.dat可以放在一个单独的文件夹pos中,负样本刚开始放在单独的文件夹neg中来产生neg.dat,但是此时请将他们与net.dat放到和pos.vec同一级的位置。

3.使用opencv_traincascade.exe训练级联分类器

第一个为opencv_traincascade.exe的带路径文件名,-data后写当前文件夹(即现在neg图片的路径),-vec后写pos.vec文件名,-bg后写neg.dat文件名(注意这里不能带路径否则不成功),-numPos为每一级训练的样本数量,据说应该在总样本的90%左右,-numNeg为负样本数量,据说可以比真实负样本数量大,-numStage后写训练的级数,-mem后写分配的内存,越大处理地越快,-featureType后写类型,这里用LBP,-w后写目标宽度,-h后写目标高度。(Pause可以让你看到打印信息,而不是一脸懵比不知道发生了什么,对了type命令相当于Linux中的cat可以读取文本文件内容,不记得在哪里用过了)

"D:\OpenCV\opencv\build\x64\vc12\bin\opencv_traincascade.exe" -data "F:\AirBand\training" -vec pos.vec -bg neg.dat -numPos 150 -numNeg 46 -numStage 10 -mem 1024 -featureType LBP -w 30 -h 28
Pause

成功的样子是这样的,请注意负样本不能放在二级目录中:http://bbs.youkuaiyun.com/topics/391005340



4.实战:用Kinect传递视频信息给OpenCV检测,类似于我们之前检测人脸和眼睛的程序:

这里代码使用了opencv学习笔记—opencv+openni2 深度图像与彩色图像的读取与显示中Opencv读取Kinect数据的方法和之前的检测人脸、眼睛的Opencv示例

#include "iostream"
#include "OpenNI.h"
#include "opencv\cv.h"
#include "opencv\highgui.h"

using namespace std;
using namespace openni;
using namespace cv;

/** Function Headers */
void detectAndDisplay(Mat frame);

/** Global variables */
String hand_cascade_name = "cascade.xml";
CascadeClassifier hand_cascade;
string window_name = "Capture - Face detection";

RNG rng(12345);

int main(int argc, char** argv)
{
	//-- 1. 加载分类器
	if (!hand_cascade.load(hand_cascade_name)){ printf("--(!)Error loading\n"); return -1; };
	//opencv
	//Mat imgDepth(640, 480, IPL_DEPTH_16U, 1);
	char key = 0;

	//1.initialize OpenNI
	Status rc = OpenNI::initialize();
	if (rc != STATUS_OK)
	{
		cout << "Initialize failed" << OpenNI::getExtendedError();
		cin.get();
		cin.get();
		return -1;
	}

	//2.open a device
	Device device;
	rc = device.open(ANY_DEVICE);

	VideoStream depth, image;

	if (device.getSensorInfo(SENSOR_DEPTH) != NULL)
	{

		rc = depth.create(device, SENSOR_DEPTH);

		if (rc == STATUS_OK)
		{
			rc = depth.start();
			if (rc != STATUS_OK)
			{
				cout << "couldn't create depth stream" << OpenNI::getExtendedError();
				cin.get();
				cin.get();
				return -1;
			}
		}
	}
	if (device.getSensorInfo(SENSOR_COLOR) != NULL)
	{
		rc = image.create(device, SENSOR_COLOR);

		if (rc == STATUS_OK)
		{
			rc = image.start();
		}
	}


	VideoStream* streams[] = { &depth, &image };

	//videoStream.setVideoMode(videoMode);
	VideoFrameRef frame;
	if (device.hasSensor(SENSOR_COLOR) && device.hasSensor(SENSOR_DEPTH))
		cout << "the color is OK";

	while (key != 27)
	{
		int readyStream = -1;
		//for the readFrame, you should waitForAnyStream to get the new frame;
		rc = OpenNI::waitForAnyStream(streams, 2, &readyStream);
		switch (readyStream)
		{
		case 0:
			//depth
			depth.readFrame(&frame);
			break;
		case 1:
			//color
			image.readFrame(&frame);
			break;
		default:
			cout << "unexpected stream" << endl;
		}

		switch (frame.getVideoMode().getPixelFormat())
		{
		case PIXEL_FORMAT_DEPTH_1_MM:
		case PIXEL_FORMAT_DEPTH_100_UM:
		{
			DepthPixel  *pDepth = (DepthPixel*)frame.getData();
			Mat imgDEP(frame.getHeight(), frame.getWidth(), CV_16UC1, (void*)frame.getData());
			//	cout << depth.getMaxPixelValue() << endl;
			imgDEP.convertTo(imgDEP, CV_8U, 255.0 / 4096.0);
			namedWindow("depth", 1);
			imshow("depth", imgDEP);
			break;
		}
		case PIXEL_FORMAT_RGB888:
		{
			Mat imgRGB(frame.getHeight(), frame.getWidth(), CV_8UC3, (void*)frame.getData());  //const 使用
			cvtColor(imgRGB, imgRGB, CV_BGR2RGB);

			//-- 3. 逐帧执行分类器
			
			std::vector<Rect> faces;
			Mat frame_gray;

			cvtColor(imgRGB, frame_gray, COLOR_BGR2GRAY);
			equalizeHist(frame_gray, frame_gray);

			//-- 检测手部
			hand_cascade.detectMultiScale(frame_gray, faces, 1.1, 2, 0, Size(80, 80));

			for (size_t i = 0; i < faces.size(); i++)
			{
				Mat faceROI = frame_gray(faces[i]);
				//-- 画出手部
				Point center(faces[i].x + faces[i].width / 2, faces[i].y + faces[i].height / 2);
				ellipse(imgRGB, center, Size(faces[i].width / 2, faces[i].height / 2), 0, 0, 360, Scalar(255, 0, 0), 2, 8, 0);
			}

			namedWindow("test", 1);
			imshow("test", imgRGB);
			//-- 显示结果
			//imshow(window_name, imgRGB);
			break;
		}
		default:
			cout << "unknown format" << endl;
		}
		key = cvWaitKey(20);
	}

	image.stop();
	image.destroy();
	depth.stop();
	depth.destroy();
	device.close();
	OpenNI::shutdown();

	cin.get();
	cin.get();
	return 0;
}
结果:





结果很粗糙,从我上述的训练过程就可以看出,这里只是一个示例。


这个过程中还涉及了VS2013对部分opencv的lib中文件找不到,在设置中将VC++ C/C++ Link中include和lib路径都配一下大概就可以,这里一个人总结的很好:http://bbs.youkuaiyun.com/topics/390789326

VC6:
工程、设置、C/C++、分类:Preprocessor、附加包含路径:填写附加头文件所在目录 逗号间隔多项
工程、设置、Link、分类:Input、附加库路径:填写附加依赖库所在目录 分号间隔多项
工程、设置、Link、分类:Input、对象/库模块:填写附加依赖库的名字.lib 空格间隔多项
VS20xx:
项目、属性、C/C++、附加包含目录:填写附加头文件所在目录 分号间隔多项
项目、属性、链接器、常规、附加库目录:填写附加依赖库所在目录 分号间隔多项
项目、属性、链接器、输入、附加依赖项:填写附加依赖库的名字.lib 空格或分号间隔多项


Window7打开笔记本的网络摄像头可能出现问题,见https://stackoverflow.com/questions/4749498/cant-access-webcam-with-opencv

还有可能在调试时出现找不到pdb文件,使用Ctrl+F5它就不会来烦你了,毕竟我们不求甚解,具体为什么就不深究了。





评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值