现在的位置: 首页 > 综合 > 正文

[Leap Motion开发系列]理解C++应用例子

2013年06月25日 ⁄ 综合 ⁄ 共 5743字 ⁄ 字号 评论关闭

持续维护地址:http://52coding.com/understanding-the-cpp-sample-application

今天晚上悦读了下Leap Motion提供的官方C++例子,感觉很棒很给力!相对于微软Kinect的程序,他们的例子编码风格少许不同,十分的高效简单!对于才学编程的菜鸟来说,你要好好看下他编程的基本功。对于有一定基础的人来说,你阅读后一定会惊讶于Leap Motion API如此的简洁给力。对于从事开发Kinect的孩子们,你们遇到Leap,一定会立即投入她的怀抱。

例子在LeapSDK下的samples文件夹下面,如果不知道哪里下载SDK,可以去这个地址,也可以去官方地址(如果此文时间超过一个月了,请去官方地址下载为佳)。

同时本人准备做一个弹钢琴的应用。在Leap Motion上也有一个弹钢琴应用(还是一个从事商业音乐软件开发的公司),虽然他的界面效果很好,但是被喷的不成人样(主要是用户体验不好,不能准确识别弹钢琴手势)。嗯,我从零开始做~关注的自然是感情背后手指弹动如何准确的识别,如果做得好,我会请会弹钢琴的人辅助调试软件。如果不出意外,所有代码是开源的,大家可以互相学习和借鉴。同时,如果有人想与我合作,十分欢迎,上海的优先哦~

/******************************************************************************\
* Copyright (C) 2012-2013 Leap Motion, Inc. All rights reserved.               *
* Leap Motion proprietary and confidential. Not for distribution.              *
* Use subject to the terms of the Leap Motion SDK Agreement available at       *
* https://developer.leapmotion.com/sdk_agreement, or another agreement         *
* between Leap Motion and you, your company or other organization.             *
\******************************************************************************/
//#include <windows.h>//如果嫌刷屏太快打开这个定义1(一共2处)
#include <iostream>
#include "Leap.h"
using namespace Leap;

class SampleListener : public Listener {
public:
	virtual void onInit(const Controller&);
	virtual void onConnect(const Controller&);
	virtual void onDisconnect(const Controller&);
	virtual void onExit(const Controller&);
	virtual void onFrame(const Controller&);
	virtual void onFocusGained(const Controller&);
	virtual void onFocusLost(const Controller&);
};

void SampleListener::onInit(const Controller& controller) {
	std::cout << "Initialized" << std::endl;
}

//打开对所有手势的识别
void SampleListener::onConnect(const Controller& controller) {
	std::cout << "Connected" << std::endl;
	controller.enableGesture(Gesture::TYPE_CIRCLE);
	controller.enableGesture(Gesture::TYPE_KEY_TAP);
	controller.enableGesture(Gesture::TYPE_SCREEN_TAP);
	controller.enableGesture(Gesture::TYPE_SWIPE);
}

void SampleListener::onDisconnect(const Controller& controller) {
	//Note: not dispatched when running in a debugger.
	std::cout << "Disconnected" << std::endl;
}

void SampleListener::onExit(const Controller& controller) {
	std::cout << "Exited" << std::endl;
}

//核心函数,当获取一帧数据时要做点什么事
void SampleListener::onFrame(const Controller& controller) {
	// 获取最新的一帧,并且返回一些基本信息
	const Frame frame = controller.frame();
	std::cout << "Frame id: " << frame.id()
		<< ", timestamp: " << frame.timestamp()
		<< ", hands: " << frame.hands().count()
		<< ", fingers: " << frame.fingers().count()
		<< ", tools: " << frame.tools().count()
		<< ", gestures: " << frame.gestures().count() << std::endl;

	//非空,检测到手
	if (!frame.hands().empty()) {
		// 得到第一只手[hands()返回HandList结构,可以向操作容器一样操作]
		const Hand hand = frame.hands()[0];

		// 检查下手是否有手指[握拳的话,是找不到手指的]
		const FingerList fingers = hand.fingers();
		if (!fingers.empty()) {
			// 计算指尖尖端平均位置坐标
			Vector avgPos;
			for (int i = 0; i < fingers.count(); ++i) {
				avgPos += fingers[i].tipPosition();
			}
			avgPos /= (float)fingers.count();
			std::cout << "Hand has " << fingers.count()
				<< " fingers, average finger tip position" << avgPos << std::endl;
		}

		// 获取手的球心半径和手掌的坐标
		std::cout << "Hand sphere radius: " << hand.sphereRadius()
			<< " mm, palm position: " << hand.palmPosition() << std::endl;

		// 获取手的垂直向量(垂直手心向里)和方向(以手心开始,沿着手指指尖方向)
		const Vector normal = hand.palmNormal();
		const Vector direction = hand.direction();

		// 计算手的俯仰Pitch角度、平面Roll旋转角度和左右Yaw旋转角度
		std::cout << "Hand pitch: " << direction.pitch() * RAD_TO_DEG << " degrees, "
			<< "roll: " << normal.roll() * RAD_TO_DEG << " degrees, "
			<< "yaw: " << direction.yaw() * RAD_TO_DEG << " degrees" << std::endl;
	}
	/*他并没有使用一些函数rightmost和leftmost之类*/


	// 获取手势
	const GestureList gestures = frame.gestures();
	for (int g = 0; g < gestures.count(); ++g) {
		Gesture gesture = gestures[g];//这里最好去看下Gesture的定义,里面详细描述各种手势触发的阈值
		//编程技术比较厉害啊,都看不到Gesture的成员变量在哪里,完全被封装起来了,不是com就是dll封装的吧
		//我也很想学习这种完全把变量封装到看不见的方法,这样程序员会很省心(眼不见心为净)

		//注意下来使用了switch语句先判断它是否是这种类型手势,再进行类的重新构造
		switch (gesture.type()) {
		case Gesture::TYPE_CIRCLE:
			{
				CircleGesture circle = gesture;
				std::string clockwiseness;

				if (circle.pointable().direction().angleTo(circle.normal()) <= PI/4) {
					clockwiseness = "clockwise";//顺时针旋转的话,circle.normal()指向外侧[右手坐标系,学过物理磁力线神马的一下子就会明白]
				} else {
					clockwiseness = "counterclockwise";//逆时针,同上理解
				}

				// 计算和上一帧经过的角度
				float sweptAngle = 0;
				if (circle.state() != Gesture::STATE_START) {
					//如果不是第一帧[第一帧肯定不能作为判断,只能作为初始化]
					//frame(0)表示当前最新一帧,而frame(1)表示前一帧,以此类推
					//对于id的使用十分简单明了,但很重要。这样表示只针对这个人的这个手指。
					CircleGesture previousUpdate = CircleGesture(controller.frame(1).gesture(circle.id()));
					//progress()表示手指旋转了几圈,如果是0.5表示旋转了半圈,如果是3表示已经旋转了3圈[计数功能很赞啊]
					sweptAngle = (circle.progress() - previousUpdate.progress()) * 2 * PI;//一共旋转多少弧度[显示时他再次转换成角度]
				}
				std::cout << "Circle id: " << gesture.id()
					<< ", state: " << gesture.state()
					<< ", progress: " << circle.progress()
					<< ", radius: " << circle.radius()
					<< ", angle " << sweptAngle * RAD_TO_DEG
					<<  ", " << clockwiseness << std::endl;
				break;
			}
		case Gesture::TYPE_SWIPE:
			{//相对旋转手势来说,这个以及下面几个简单很多
				SwipeGesture swipe = gesture;
				std::cout << "Swipe id: " << gesture.id()
					<< ", state: " << gesture.state()
					<< ", direction: " << swipe.direction()//这个可是能判断所有方向的,强大!我玩Kinect时只能识别几个特定的方向。
					<< ", speed: " << swipe.speed() << std::endl;
				break;
			}
		case Gesture::TYPE_KEY_TAP:
			{
				KeyTapGesture tap = gesture;
				std::cout << "Key Tap id: " << gesture.id()
					<< ", state: " << gesture.state()
					<< ", position: " << tap.position()
					<< ", direction: " << tap.direction()<< std::endl;
				break;
			}
		case Gesture::TYPE_SCREEN_TAP:
			{
				ScreenTapGesture screentap = gesture;
				std::cout << "Screen Tap id: " << gesture.id()
					<< ", state: " << gesture.state()
					<< ", position: " << screentap.position()
					<< ", direction: " << screentap.direction()<< std::endl;
				break;
			}
		default:
			std::cout << "Unknown gesture type." << std::endl;
			break;
		}
	}

	if (!frame.hands().empty() || !gestures.empty()) {
		std::cout << std::endl;
	}
	//  Sleep(1000);//如果嫌刷屏太快打开这个定义2(一共2处)
}

void SampleListener::onFocusGained(const Controller& controller) {
	std::cout << "Focus Gained" << std::endl;
}

void SampleListener::onFocusLost(const Controller& controller) {
	std::cout << "Focus Lost" << std::endl;
}

int main() {
	// 创建例子监听者和控制器
	SampleListener listener;
	Controller controller;

	// 让监听者获取控制器的数据并进行分析
	controller.addListener(listener);

	// 让程序一直运行,直到输入回车键才结束
	std::cout << "Press Enter to quit..." << std::endl;
	std::cin.get();

	// 移除监听者
	controller.removeListener(listener);

	return 0;
}

下面是运行效果:

抱歉!评论已关闭.