利用Kinect将投影变得可直接用手操控

Finally

总算是到了这一天了!假期里算法想不出来,或者被BUG折磨得死去活来的时候,总是YY着什么时候能心情愉快地坐在电脑前写一篇项目总结,今天总算是抽出时间来总结一下这神奇的几个月。

现在回过头来看,上学期退出ACM集训队果然是对的,这次开发学到的东西太多太多,以前在ACM的时候,感觉不会的东西好多啊,真正来自己试着开发个东西,发现不会的东西果然好多。不过要是几个老师知道我上午给新生做完ACM宣讲报告下午就跟教练说退出,他们会是什么心情啊哈哈。

这些是第一次尝试开发,如果ACM是练内功的话,那么练了三年也总该让我拿出来用用了,不然学了三年还是只在个控制台里玩甚是寂寞,自己亲手从无到有创造出一个东西来的感觉, 实在太爽了!

先说一下这次项目印象最深的几个教训:

  1. 功能一旦变得复杂,就一定要在纸上先画一画!
    • 流程图也好,大体思路图也行,甚至随手演算的过程都可以,总之一定要把思路理清楚了,思路不清的后果就是代码越写越乱,最后只能全部推倒重来,事先不画图省下的时间远远比不上最后重写所浪费的时间。
  2. 命名一定要规范
    • 以前刷题的时候,也知道命名规范的重要性,只是没想到会如此重要。之前我的代码风格还算不错,不过一开始写的时候还偷下懒,省掉一两个单词之类,有时心急了还直接用原来的命名方法,用下划线分割单词(Kinect的API里都是用大小写分割单词的),这样写的弊端就是代码也是越来越乱,而且一旦有事中断了几天,回来再看代码就发现看不懂了,于是又简单粗暴推倒重来。所以一定要有一套自己的命名风格,而且不要为了省事少些那一两个单词,敲个长变量名所带来的是代码的高可读性,多耗费的时间远远小于以后推倒重来所浪费的时间!
  3. 不写不必要的注释
    • 到处都是注释,反而大大降低了可读性,一眼看去全是绿的,头都晕了,开发中期我就被自己那么多的注释弄得看见绿代码就想吐,后期只注释主要功能,提高抽象程度,代码反而变得清晰有逻辑。所以那种基本每行都有注释的风格,我并不认同,当然,我说的是代码基本仅供自己一个人看的情况。
  4. 最好进行版本控制
    • 有一次就是,我做了个比较微小的改动,结果怎么调都不对,也已经忘了改动之前是什么状态,简直是有种欲哭无泪的感觉。还有就是进行一个大的改动之后,突然发现之前的那个版本才是对的(哭)。有个版本控制机制的话,这种情况应该能避免很多。
  5. 迭代开发似乎是个不错的办法
    • 之前在知乎上看到一个贴,讲的是新手应该怎样进行开发,提到的一种思路就是进行迭代开发。一开始可能什么都不懂,然后着手做了一部分之后,就对项目有了个大概的轮廓,然后推翻进行新的一轮开发,这时又对未来该怎么做有更清晰的了解,这样不断迭代把项目逐步推向成熟。我是迭代了4次之后出了目前这个基本完成的版本,不过在写的时候没刻意考虑过用这种方法,之所以迭代了4次是因为上面提到的种种原因导致推翻重来(捂脸),不过现在看来这种方法好像真的很合理。

项目介绍

好了,现在正式开始介绍一下项目本身。

背景

这个项目原本是用来参加2016年的微软创新杯,但是在上一周,也就是3月20号的四川省区域赛中未获奖,只能直接参战中国区半决赛。这次区域赛失败的原因有很多,虽然作品已经完成得差不多了,但是没能优秀地将其展示出来,在现成演示的时候还遇到了一个巨大失误,中途才发现,所以没等通知结果就知道多半是悲剧了。第一次参加这类开发类的比赛,就当交学费好了,不过这次区域赛给我的感觉是,微软还是想找几个最有商业前途的作品,这个项目炫是很炫酷,但是实际意义不大的样子,所以感觉中国区半决赛希望也不大。不过无所谓啦,我自己玩得嗨就行了,微软欣不欣赏那是另外一回事,说不定哪天我就搭建出个钢铁侠那样的实验室不是?啊哈哈,最近也顺便把这个项目报成了大学生创新创业训练计划,成功申请到国家级,算是可以安慰一下。

目标

简单来说,此项目就是要把投影仪投出的投影变得可以直接用裸手操控,就好像投影变成了一块大型的平板电脑,投影可以是在投影幕上、墙上甚至桌子上,任何光滑且不是反射材质的平面都行,至于为什么不能是反射材质,等下会有介绍。刚开始是计划达到能用手指直接在投影上写字的精度,后来发现很难做到,瓶颈在于指尖的识别算法不够精确,这是我自己构思的一个简单算法,未来应该会用更高级更精确的算法来替代。

开发环境

Kinect for Windows V2 + Kinect SDK 2.0 + OpenCV 3.0 + Visual Studio Community 2015

Kinect

项目里利用到的一个非常重要的东西就是Kinect for Windows V2,一款微软的动作感应器,可以算成是一类现实增强设备,发布时主要是搭配XBox来玩体感游戏,但是这么厉害的一个东西只能用来玩游戏实在太可惜,所以微软在前几天发布了它的Windows版本,让它能够在PC上进行开发。就是下面这么个东西:

原理

原理其实并不算难,主要可以参考下面这张图。

  1. 从Kinect获取的整个画面中识别出投影
    • 因为操作要在投影上进行,所以需要先识别出投影是画面中的哪一块,这里用的算法比较简单,先投一副纯色图像出来,然后利用投影区RGB值近似的原理,找出投影的左下角和右上角之后就确定了投影的区域,这样做的缺点是投影区只能是矩形而且不能太歪。其实有时间的话,可以试一下利用9*9的矩阵来找出所有属于边缘的点,然后渲染所有边缘点,也就找出了整个边缘,这样可以适应任意形状。
  2. 从Kinect获取的整个画面中识别出指尖
    • 因为用手指来调用鼠标进行操作,而接触屏幕的地方又是手指的指尖,所以需要识别出指尖。

    一开始我是基于KinectBodyIndex这个数据源来寻找指尖,首先定位出腕关节在哪,然后根据腕关节的位置向上寻找复合指尖特征的点,可以说效果很好,识别非常精确和稳定,而且能同时识别出5个指尖,这部分是我在假期里完成的,本来以为来到学校后将程序根据投影仪调整下就差不多可以用了,然而到校测试后才发现一个致命的问题,就是当手臂贴近墙壁时,整个手臂的BodyIndex数据都丢失了。因为微软似乎认为,如果某个点要是属于人体的话,那么它和背景的深度差至少要有二三十厘米左右(正好是人体的厚度)。这个问题让我失眠了几晚上...不过也是在失眠的时候想出了现在用的解决方法。ds

    现在用的方法是基于`Depth`数据来找指尖的,简单来说就是根据指尖的特点找出所有吻合的点,然后取 位置最高的那个(因为操作的时候用的基本都是一根手指),这样做可以减少很多工作量,因为很多非法点都直接被略去了。
  3. 将手指的位置映射成鼠标的位置
    • 因为想达到手指指哪,鼠标就点击哪的效果,所以必须把手指在投影上的位置,映射成鼠标在电脑里相应的位置,这个其实简单推导一下就可以得出。

      黑色框为投影屏幕,大写的X和Y代表的是屏幕的宽和高,红色框为电脑屏幕,假设人的手指在的位置,如果想将鼠标也映射到同样的位置,那么就有  的等比关系成立。这里投影屏幕的宽和高在上面第一步中获取,而电脑屏幕的宽和高,实际上是不需要考虑分辨率的,因为在鼠标的坐标系下,电脑的宽和高都被分成了65535个单位,所以宽和高可以视为65535。根据这些,就可以算出的值来。

  4. 根据手指到屏幕的距离,判断点击和非点击两种状态
    • Kinect是带有深度摄像头的,也就是说它能够知道画面中的每一点到它的距离。似乎是利用三组红外发射器来实现,所以也就要求物体不能是反射材质,不然会获取不到距离。因为能够知道屏幕的距离,也能知道手指的距离,所以如果手指距离屏幕足够近,那么就可以判断为点击。但是,屏幕有可能不是绝对垂直的,Kinect也有摆歪的可能性,同时深度数据也不是100%精确,所以在计算屏幕距离时,需要考虑一个容错值,在这个范围内都被视为屏幕,在这里我设置的值是10cm,虽然看上去很多,但是实际效果还不错。但是,这也带来一个很严重的问题,就是手指在离屏幕的位置小于10cm的时候,也被视为了屏幕,这时候指尖就丢失了,手指变成了手指中部(因为手指不是完全平行于墙面的,而是有一定角度,所以指根的地方距离屏幕更远),这就会产生很不稳定的现象,至今没有解决。

上面就是核心的功能,除此之外,还要加入一些鼠标的抖动消除、误差消除的处理,同时我还调用了Kinect的手势识别功能,直接用手势来完成撤销的操作。这段时间忙着找实习,以后有时间的话,应该会优化指尖识别的算法,同时加入更多的手势来调用操作。

效果展示

(博客园的MarkDown居然不可以插视频,差评)

演示视频在这里

直接在墙上玩割绳子:

用手在墙上书写(外加用手势来调用撤销):

直接裸手操控PPT:

END

这个项目差不多就这么多啦,剩下的只是优化下各个功能,或者加点新东西进去。从假期里就构思了一个比较有意思的小程序,等这段时间忙结束,应该就会把它敲出来。真是越来越好玩了!

转载于:https://www.cnblogs.com/czaoth/p/6027449.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/394751.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

my-medium.cnf_您的手机如何打开medium.com-我将让门卫和图书管理员解释。

my-medium.cnfby Andrea Zanin由Andrea Zanin 您的手机如何打开medium.com-我将让门卫和图书管理员解释。 (How your phone opens medium.com — I’ll let a doorman and a librarian explain.) Hey did you notice what just happened? You clicked a link, and now here y…

springboot自动配置的原理_SpringBoot自动配置原理

SpringBoot的启动入口就是一个非常简单的run方法,这个run方法会加载一个应用所需要的所有资源和配置,最后启动应用。通过查看run方法的源码,我们发现,run方法首先启动了一个监听器,然后创建了一个应用上下文Configurab…

Django first lesson 环境搭建

pycharm ide集成开发环境 (提高开发效率) 解释器/编译器编辑器调试环境虚拟机连接 设置VirtualBox端口 操作1 操作2 点击号添加,名称为SSH,其中主机端口为物理机的端口,这里设置为1234,子系统端口为虚拟机的…

《Drupal实战》——3.3 使用Views创建列表

3.3 使用Views创建列表 我们接着讲解Views的设置,首先做一个简单的实例。 3.3.1 添加内容类型“站内公告” 添加一个内容类型“站内公告”,属性配置如表3-1所示。 为该内容类型设置Pathauto的模式news/[node:nid],并且我们在这里将节点类型…

c语言函数编正切余切运算,浅谈正切函数与余切函数的应用

九年义务教育三年制初级中学“数学”课本中,对正切函数和余切函数的定义是这样下的:在RtABC中,∠C=90,a&#…

wget命令下载文件

wget -r -N -l -k http://192.168.99.81:8000/solrhome/ 命令格式: wget [参数列表] [目标软件、网页的网址] -V,–version 显示软件版本号然后退出; -h,–help显示软件帮助信息; -e,–executeCOMMAND 执行一个 “.wgetrc”命令 -o,–output…

idea mybatis generator插件_SpringBoot+MyBatis+Druid整合demo

最近自己写了一个SpringBootMybatis(generator)druid的demo1. mybatisgenerator逆向工程生成代码1. pom文件pom文件添加如下内容,引入generator插件org.mybatis.generator mybatis-generator-maven-plugin 1.3.5 mysql …

vr格式视频价格_如何以100美元的价格打造自己的VR耳机

vr格式视频价格by Maxime Coutte马克西姆库特(Maxime Coutte) 如何以100美元的价格打造自己的VR耳机 (How you can build your own VR headset for $100) My name is Maxime Peroumal. I’m 16 and I built my own VR headset with my best friends, Jonas Ceccon and Gabriel…

python_装饰器

# 装饰器形成的过程 : 最简单的装饰器 有返回值得 有一个参数 万能参数# 装饰器的作用# 原则 :开放封闭原则# 语法糖:装饰函数名# 装饰器的固定模式 import time # time.time() # 获取当前时间 # time.sleep() # 等待 # 装饰带参数的装饰器 def timer…

欧洲的数据中心与美国的数据中心如何区分?

人会想到这意味着,在欧洲和北美的数据中心的设计基本上不会有大的差异。不过,一些小的差异是确实存在的。您可能想知道为什么你需要了解欧洲和北美的数据中心之间的差异,这对你的公司有帮助吗?一个设计团队往往能从另一个设计团队那里学到东…

老农过河

java老农过河问题解决 http://www.52pojie.cn/thread-550328-1-1.html http://bbs.itheima.com/thread-141470-1-1.html http://touch-2011.iteye.com/blog/1104628 转载于:https://www.cnblogs.com/wangjunwei/p/6032602.html

python isalnum函数_探究Python中isalnum()方法的使用

探究Python中isalnum()方法的使用 isalnum()方法检查判断字符串是否包含字母数字字符。 语法 以下是isalnum()方法的语法: str.isa1num() 参数 NA 返回值 如果字符串中的所有字符字母数字和至少有一个字符此方法返回 true,否则返回false。 例子 下面的例…

docker快速入门_Docker标签快速入门

docker快速入门by Shubheksha通过Shubheksha Docker标签快速入门 (A quick introduction to Docker tags) If you’ve worked with Docker even for a little while, I bet you’ve come across tags. They often look like “my_image_name:1” where the part after the col…

动态规划算法——最长上升子序列

今天我们要讲的是最长上升子序列(LIS)。【题目描述】给定N个数,求这N个数的最长上升子序列的长度。【样例输入】      【样例输出】7        42 5 3 4 1 7 6那么什么是最长上升子序列呢? 就是给你一个序列…

如何快速掌握一门新技术/语言/框架

IT行业中的企业特点是都属于知识密集型企业。这种企业的核心竞争力与员工的知识和技能密切相关。而如果你在企业中扮演的是工程师的角色的话,那么 你的核心竞争力就是IT相关的知识与技能的储备情况。而众所周知,IT行业是一个大量产生新知识的地方&#x…

c语言今天星期几问题,C语言输入今天星期几

满意答案迷茫03222015.07.24采纳率&#xff1a;55% 等级&#xff1a;9已帮助&#xff1a;665人123456789101112131415161718192021#include<stdio.h>int main(void){ enum weekday{ sun, mon, tue, wed, thu, fri, sat }; int n; printf("输入星期数(0-…

备忘录模式 详解

定义 在不破坏封装性的前提下&#xff0c;捕获一个对象的内部状态&#xff0c;并在该对象之外保存这个状态&#xff1b; 行为型模式 角色 发起人角色&#xff08;Originator&#xff09;&#xff1a;记录当前时刻的内部状态&#xff0c;负责定义哪些属于备份范围的状态&#xf…

dll oem证书导入工具_技术干货 | 恶意代码分析之反射型DLL注入

欢迎各位添加微信号&#xff1a;qinchang_198231 加入安全 交流群 和大佬们一起交流安全技术01技术概要这是一种允许攻击者从内存而非磁盘向指定进程注入DLL的技术&#xff0c;该技术比常规的DLL注入更为隐蔽&#xff0c;因为除了不需要磁盘上的实际DLL文件之外&#xff0c;它…

像程序员一样思考_如何像程序员一样思考-解决问题的经验教训

像程序员一样思考by Richard Reis理查德里斯(Richard Reis) 如何像程序员一样思考-解决问题的经验教训 (How to think like a programmer — lessons in problem solving) If you’re interested in programming, you may well have seen this quote before:如果您对编程感兴趣…

CF908G New Year and Original Order 数位DP

传送门 看到数据范围到\(10^{700}\)毫无疑问数位DP。那么我们最重要的问题是如何有效地维护所有数位排序之后的数的值。 对于某一个数\(x\)&#xff0c;设\(f_{x,i} (i \in [1,9])\)表示\(x\)中的所有数位的值\(\geq i\)的数位数量&#xff0c;比如说\(f_{6345982 , 7} 2 , f_…