matlab 软键盘,(转载)DIY激光虚拟键盘低成本自制【全面讲解二】

本帖最后由 gazelle 于 2013-8-15 10:58 编辑

转载请注明出处:CLK.blog实现过程

器件选择

有前面的原理分析可知,本激光键盘至少需要摄像头、投射键盘画面的激光器以及一字线激光。如下是我选用的器件和参数

元件核心参数

摄像头广角镜头,视角>120度

投射键盘画面的激光器无特殊要求

一字线激光红外激光器,>50mW

红外带通滤光片800nm左右光谱带通

对于摄像头,这里一个比较关键的特性是需要采用广角镜头。目前的USB摄像头一般视角在90度左右,这样的摄像头需要在很高处俯视才能拍摄到完整的激光键盘图案,如果想把本投影键盘制作的小巧,则需要采用广角镜头,视角最好在120度以上。

46440003_1.jpg

图:窄视角的摄像头需要安装在较高的位置

除了镜头外,摄像头本身没有特殊要求,一般市面VGA画质的普通USB摄像头即可满足要求。下图为我采用的镜头和摄像头照片:

46440003_2.jpg

图:两种不同视角的摄像头镜头,左边为窄视角镜头,右边为广角镜头

46440003_3.jpg

图:USB摄像头模组

对投射键盘图案的激光发射器模组前文已经提到,且没有特殊要求。

46440003_4.jpg

图:选用的激光键盘图案投射模组

对用于测距的激光发射器,只需要使用红外波段的一字线激光器,功率在50mW左右即可。为了安全考虑,不要使用过大功率的激光器。采用红外波段主要为了过滤可见光干扰,简化视觉处理中的兴趣点提取,同时也不会因为手指反射对投射的键盘图案产生干扰。

46440003_5.jpg

图:选用的红外线型激光器

摄像头改装

在我之前的3D测距仪文章[2]中提到过使用红外激光器配合红外滤光片进行测距可有效避免可见光干扰的技巧,在这里也仍旧适用。对此我们需要对摄像头镜头做一些改造,首先拆除镜头上的红外光截至滤光片,并在镜头头部安装红外带通滤光片:

46440003_6.jpg

图:拆除镜头内的红外截止滤光片

46440003_7.jpg

图:在镜头表面安装红外带通滤光片

电子系统

本制作的电子系统比较简单,仅仅涉及给两个激光发射器供电以及通过USB电缆连接摄像头至主机。并没有采用任何单片机,这样也意味着之前原理部分介绍的算法将完全在PC上实现。这样的优点是大幅降低了制作成本以及制作的难度。如果使用的是免驱动USB摄像头,在PC上使用本激光投影键盘只需要额外运行处理程序即可。不过缺点就是这样的设计无法给手机等不支持USB的设备使用。

由于摄像头已经使用了一条USB电缆,因此这里我们直接通过usb的5V供电来驱动另外2个激光器。电路很简单,如下图所示:

46440003_8.jpg

可以看到电路的核心就是一个3.3V的LDO芯片而已,可以裁剪一个洞洞板制作:

46440003_9.jpg

图:使用小块洞洞板制作简易的驱动电路

总体安装

由前面的分析可以得到如下的安装结构:

其中线型激光器需要安装在设备的最底下并紧靠底部,这样可以保证产生的激光平面能够尽可能的靠近桌面平面。在激光器上方安装投射键盘图案的激光模组,他的高度以能够投射出与常规键盘尺寸大小类似的图案来决定。在最顶端安装摄像头,其高度取决于摄像头能够完整拍摄整个键盘图案画面为宜。

我使用一块轻质木材作为安装这3个部件的整体支架:

46440003_10.jpg

图:将激光器安装在木板最底部,使用热熔胶固定

46440003_11.jpg

图:安装图案投射模块和摄像头并点亮

46440003_12.jpg

图:在木板背面安装稳压电路板和所有供电连线

46440003_13.jpg

图:将木板装入一个牢固的纸盒

46440003_14.jpg

图:完成并通电

46440003_15.jpg

图:顶部加装一个“保护罩”

最终本制作的实体部分组装完毕,接下来将介绍本制作的重点:视觉算法部分。

3.5.前期视觉处理

由于本制作的视觉处理部分都在PC上进行,因此我使用了OpenCV[6]库来加速视觉运算代码的开发。在进行原理部分提到的手指尖提取和坐标求解前,需要对摄像头捕获的原始画面做一些前期的处理,方便后续的计算。

3.5.1.镜头扭曲矫正

由于我们使用了广角镜头,因此摄像头拍摄到的画面会存在比较明显的扭曲,就如下图所示:

46440003_16.jpg

这样扭曲的画面难以直接进行处理计算出后续需要的坐标信息,因为这种扭曲变换是非线性的。因此这里首先需要对摄像头镜头进行校正。在之前的文章[2]中有对摄像头矫正技术的介绍,这里我仍旧使用matlab的摄像头校正工具[7]进行校正。在OpenCV中也提供了相关函数和工具可以对摄像头校正,不过很多人反映相比matlab的算法,OpenCV函数校正得到的结果略差。

在使用Chessboard图案完整校正后,可使用OpenCV的cvInitUndistortRectifyMap/ cvRemap函数通过校正数据将扭曲的画面重新修正。

46440003_17.jpg

图:将左侧广角镜头的原始画面进行扭曲修正,得到右侧画面

这里有一点需要注意,在先前的安装阶段我们提到摄像头需要安装红外带通滤光片。但在安装滤光片后,由于可见光都被过滤,因此之后无法再进行上述的镜头校正。因此这部分的校正工作需要先于红外滤光片的安装进行。

3.5.2.滤波

由于摄像头镜头加装了红外带通滤光片,可见光可以有效地被阻挡,因此在摄像头捕获的画面上基本只含有手指对红外激光的反射。

46440003_18.jpg

图:红外带通滤光片有效地过滤了可见光干扰

对于这样的画面基本上是可以直接进行后续的视觉处理的,不过一般我们还需要额外进行几个步骤:灰度化、高斯滤波、阈值化、形态学滤波

灰度化即将原先RGB色彩的彩色图像转化成灰度图,因为后续的视觉算法并不关心色彩信息,但需要反射光亮度,使用灰度表示后可以大幅加速处理速度。高斯滤波(Gauss Filter)、阈值化(Threshold)、形态学滤波(Morphology Filter)用于过滤画面中的噪点并且使得反射光斑变得平滑和连贯。如果不熟悉这部分概念,可以参考Digital Image Processing一书[8]。这几步操作在OpenCV中均有对应函数可以实现。

46440003_19.jpg

图:对图像进行各类滤波处理后的效果

上图展现了经过上述滤波算法后,手指尖激光反光光斑处理后的效果。可以看到,原先光斑外围的反射光干扰以及两个比较靠近的指尖之间“黏连”的光斑已经有效地过滤掉了。通过一系列的滤波过程,使得我们可以很精确的求出指尖的坐标。

3.6.兴趣点提取

可以使用OpenCV提供的cvFindContours对先前与处理得到的光斑画面进行轮廓提取,进而求解出每个光斑区域在图像中的位置。进一步的,我们通过质心法并以光斑亮度作为权重,可以大致求解出每个指尖中心的大致坐标。虽然这个中心坐标未必真的在指尖中心,但相比简单的以光斑区域中心作为指尖中心的方法要精确很多。

46440003_20.jpg

图:使用轮廓提取手段提取出来的手指区域坐标

3.7.手指坐标计算和校正

在得到了手指光斑中心点相对于画面坐标之后,可以通过三角测距的方法,把手指在桌面平面内的坐标P(x,y)求出来。

该过程可以类比在激光3D测距中的算法,如下图所示:

46440003_21.jpg

图:将指尖坐标求解问题转化成3D激光测距问题

我们可以把兴趣点画面顺时针旋转90度,即将图像的X/Y轴相互交换,并在兴趣点之间连接起直线,如上图(b)所示。就会发现这样的画面就和[2]中进行3D激光测距出现的激光扫描线类似,如上图(c)。因此,我们可以按照[2]中推导的公式,求出画面中每个兴趣点的真实坐标(即以激光器为原点,桌面所在平面的坐标系坐标)

这部分的具体原理和公式推导请参考文章[2]。为了能够进行精确的激光测距,我们也需要和[2]中描述的那样对本制作进行校正。校正方法与[2]一样,可以在投影键盘前方用直尺做测量并进行曲线拟合。

46440003_22.jpg

图:对激光测距部分进行校正

经过本轮的运算,我们可以得到先前监测到的兴趣点在桌面平面坐标下的表示,测试坐标值具有了物理意义,均以毫米为单位表示。

46440003_23.jpg

3.8.按键映射和校正

在得到了以桌面坐标平面表示的指尖坐标P(x,y)后,我们需要再进行校正得到前文提到的映射函数

P' (x,y)=fprojection (P(x,y))

该部分的校正比较容易,可以将手指放置在键盘图案的某几个“按键”上,然后将当前的坐标P(x,y)与所“按”“按键”在键盘图案的坐标P_key (x,y)做一下对比。

理想状态下,每个P(x,y)与对应的P_key (x,y)都偏差了一个固定的位移量D。不过由于校正中会带来误差,每次测量时的偏差量D’与理想的位移量都存在一个误差偏移Derror。即

Pkey (x,y)=P(x,y)+D+ Derror

这里我们就可以采用多次测量,并进行最小二乘拟合的方式,把Derror给消除掉,得到近似于D的一个校正值。因此,这里的映射函数就是:

P' (x,y)=P(x,y)+D

另外这里也需要把键盘图案的坐标事先保存下来。我直接对投影在桌面上的键盘图案进行了测量,并按照如下格式保存在程序当中:

46440003_24.jpg

图:使用一维数组,保存每个按键中心点的坐标(x,y),按键的尺寸,以及按键的键值

在有了上述数据后,一方面我们可以使用Kd-tree来快速查找到所按下的按键ID。及前文所说的函数

Key[n]=fmapping (P' (x,y))

这里的f_mapping在我的实现中,就是一个Kd-tree。相比循环查找的O(n)复杂度,Kd-tree可以在O(log(n))的时间复杂度下,找到距离点P’(x,y)最接近的元素,因此非常高效率。

目前OpenCV中提供了Kd-tree的实现,不过我在使用过程中遇到了诸多问题,尤其它可能会导致程序crash,因此我使用了由Martin F. Krafft开发的基于C++模板的Kd-tree实现libkdtree++[9]。

得到键盘图案坐标后的另一个好处是可以在PC上重新绘制出一个软键盘,用于提示当前“按下”的按键,提高使用体验:

46440003_25.jpg

图:将坐标映射到对应“按下”的按键,并提供视觉反馈

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值