技术宅男逆袭 牛人自制激光虚拟投影键盘

#include <iostream>
  #include <iomanip>
  #include "opencv/cv.h"
  #include "opencv/highgui.h"
  #include "cvblob.h"
  using namespace cvb;
  typedef struct key
  {
  char c;
  int x0;
  int y0;
  int x1;
  int y1;
  };
key g_keymap[] =
  {
  {'4',525,350,588,419},
  {'5',442,345,504,414},
  {'6',360,339,422,408},
  {'7',277,332,342,404},
  {'8',198,327,259,399},
  {'9',121,320,174,389},
  {'0',41, 318,94, 383},
  {'E',528,274,590,337},
  {'R',443,267,507,332},
  {'T',359,263,428,327},
  {'Y',280,259,344,321},
  {'U',199,251,261,315},
  {'I',119,246,179,307},
  {'O',41, 240,96, 301},
  {'D',504,203,567,259},
  {'F',424,199,489,257},
  {'G',348,194,410,251},
  {'H',266,187,329,245},
  {'J',192,183,251,241},
  {'K',117,178,171,236},
  {'L',42 ,174,92, 229},
  {'X',543,144,605,197},
  {'C',467,139,530,191},
  {'V',392,135,457,190},
  {'B',316,128,377,181},
  {'N',242,124,299,176},
  {'M',171,118,225,172},
  {'<',98, 114,149,166},
  {'>',26, 108,73, 159},
  {'_',182,62, 531,127},
  };
  int g_key_num = sizeof(g_keymap)/sizeof(key);
  int main()
  {
  CvTracks tracks;
  cvNamedWindow("red_object_tracking", CV_WINDOW_AUTOSIZE);
  CvCapture *capture = cvCaptureFromCAM(0);
  cvGrabFrame(capture);
  IplImage *img = cvRetrieveFrame(capture);
  CvSize imgSize = cvGetSize(img);
  IplImage *frame = cvCreateImage(imgSize, img->depth, img->nChannels);
  IplConvKernel* morphKernel = cvCreateStructuringElementEx(5, 5, 1, 1, CV_SHAPE_RECT, NULL);
//unsigned int frameNumber = 0;
  unsigned int blobNumber = 0;
  bool quit = false;
  while (!quit&&cvGrabFrame(capture))
  {
  IplImage *img = cvRetrieveFrame(capture);
  cvConvertScale(img, frame, 1, 0);
  IplImage *segmentated = cvCreateImage(imgSize, 8, 1);
  // Detecting red pixels:
  // (This is very slow, use direct access better...)
  for (unsigned int j=0; j<imgSize.height; j++)
  for (unsigned int i=0; i<imgSize.width; i++)
  {
  CvScalar c = cvGet2D(frame, j, i);
  double b = ((double)c.val[0])/255.;
  double g = ((double)c.val[1])/255.;
  double r = ((double)c.val[2])/255.;
  // unsigned char f = 255*((r>0.2+g)&&(r>0.2+b));
  // cvSet2D(segmentated, j, i, CV_RGB(f, f, f));
  if(b>0.4 || g>0.4 || r>0.4)
  cvSet2D(segmentated, j, i, CV_RGB(255, 255, 255));
  else
  cvSet2D(segmentated, j, i, CV_RGB(0, 0, 0));
  }
  cvMorphologyEx(segmentated, segmentated, NULL, morphKernel, CV_MOP_OPEN, 1);
  cvShowImage("segmentated", segmentated);
  IplImage *labelImg = cvCreateImage(cvGetSize(frame), IPL_DEPTH_LABEL, 1);
  CvBlobs blobs;
  unsigned int result = cvLabel(segmentated, labelImg, blobs);
  cvFilterByArea(blobs, 500, 1000000);
  cvRenderBlobs(labelImg, blobs, frame, frame, CV_BLOB_RENDER_BOUNDING_BOX);
  cvUpdateTracks(blobs, tracks, 200., 5);
  cvRenderTracks(tracks, frame, frame, CV_TRACK_RENDER_ID|CV_TRACK_RENDER_BOUNDING_BOX);
  cvShowImage("red_object_tracking", frame);
  // print key
  for (CvTracks::const_iterator it=tracks.begin(); it!=tracks.end(); ++it)
  {
  int xx = (int)it->second->centroid.x;
  int yy = (int)it->second->centroid.y;
  //std::cout << xx << ',' << yy << std::endl;
for(int i=0; i<g_key_num; i++)
  {
  if(xx > g_keymap.x0 &&
  xx < g_keymap[i].x1 &&
  yy > g_keymap[i].y0 &&
  yy < g_keymap[i].y1)
  {
  std::cout << g_keymap[i].c << std::endl;
  break;
  }
  }
  }
  cvReleaseImage(&labelImg);
  cvReleaseImage(&segmentated);
  char k = cvWaitKey(10)&0xff;
  switch (k)
  {
  case 27:
  case 'q':
  case 'Q':
  quit = true;
  break;
  case 's':
  case 'S':
  for (CvBlobs::const_iterator it=blobs.begin(); it!=blobs.end(); ++it)
  {
  std::stringstream filename;
  filename << "redobject_blob_" << std::setw(5) << std::setfill('0') << blobNumber << ".png";
  cvSaveImageBlob(filename.str().c_str(), img, it->second);
  blobNumber++;
  std::cout << filename.str() << " saved!" << std::endl;
  }
  break;
  }
  cvReleaseBlobs(blobs);
  //frameNumber++;
  }
  cvReleaseStructuringElement(&morphKernel);
  cvReleaseImage(&frame);
  cvDestroyWindow("red_object_tracking");
  return 0;
  }


虚拟 激光投射键盘在1992年就由IBM发明了。

  我第一次看到这玩意儿就觉得特别新奇,后来看到淘宝上棒子的产品,要900多米,实在是宰人啊。于是就一直有想法做一个。

  不久前在淘宝看到了投射键盘图案的激光模组,果断买了一个,开始筹划制作一个。

  taobao上买的650nm虚拟键盘激光组件

虚拟键盘激光组件

虚拟键盘激光组件

  而且现在有了强大的opencv图像处理库,实现这样的虚拟激光投射键盘变得易如反掌。

  先说说投影键盘的基本原理。键盘由三个主要部件组成:摄像头、键盘图案投射器、一字线性感应激光头。

  见下图:

投影键盘的基本原理

投影键盘的基本原理

  图上从上到下分别是键盘图案投射器、摄像头、一字线性感应激光头。

  当然,摄像头放在键盘图案投射器上面也是可以的,比如我就是这么做的。

1. 键盘图案投射器在平坦的桌面投出清晰键盘图案

  2. 最底下的一字线性激光(一般采用红外线的,这样眼睛不可见)发出一字型激光,平行于桌面射出,这样如果手指有按键活动,会在手指上形成激光光斑

  3. 摄像头捕获激光光斑,对应于键盘图案映射的位置,就可以知道哪些键被按下

  OK,原理很简单,是不是。有了这些模块,剩下的关键就是摄像头的图像处理算法了,而且现在有了opencv,实现也不是难事。

  这里说一下我的实现方法。

可见光谱

可见光谱

  由于人眼对激光的反应不一样,780nm-808nm的激光人眼不敏感,可看到微弱的一丝红光。850nm至1064nm波长人眼不可见,通过红外感光仪器等专业设备可以看到,其中808-850nm通过摄像头可以看到。980-1064nm通过倍频片可以看到。

  所以我在网上买了一个808nm-810nm 红外一字线激光器。这样配上滤光片,可以滤去绝大多数其他波长的杂光,只剩下红外激光的光斑。

  这样做的好处是减少干扰,增加键盘的可靠性,而且使算法处理更加简单有效。

  加上前面的650nm虚拟键盘激光组件,总共也就花了100块钱左右。

  25mw 808nm-810nm 红外一字线激光器 激光头

红外一字线激光器

红外一字线激光器

顺便说一句,本文中的摄像头放的位置只能捕捉到部分键盘图像,所以demo只是演示了部分键盘的按键。

  不过丝毫不影响原理介绍。如果要获得全部键盘图像,或者去买一个广角的摄像头,或者把这个摄像头位置提高,不是什么难事。

  时间有限,不想折腾了。

激光投影键盘

激光投影键盘

  代码:




  • 15
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
前言: 自1999年发布第一只浏览传感器以来,其光学鼠标传感器的出货量已经突破6亿只。Avago开创了应用于鼠标的光学传感技术,并向全球各大LED和激光鼠标制造商提供从入门级到下一代的光学和激光鼠标传感器,继续引领市场潮流。Avago Technologies(安华高科技)是为先进的通信、工业和商业等应用领域提供创新的半导体解决方案的领导厂商,成为激光技术应用中的佼佼者。 虚拟激光键盘设计介绍: 激光投射键盘相信大家之前也有所听说,他通过光学手段,将计算机键盘的画面通过激光投影到任意的平面上(如桌面)上,并且允许操作者像使用真实键盘那样进行输入操作。 虚拟激光键盘设计方案概述: 我们的设计基于了PC机上进行的计算机视觉来处理按键事件。采用了一个由摄像头和激光器组成的测距系统工作。 本设计所需要的硬件非常简单,只需要3个核心部件即可实现:一个摄像头、一个激光器以及投射键盘图案的投射激光。这也是正是低成本的奥秘所在了。 当用户在桌上“按下”一个虚拟的按键后,手指上反射的激光信号会被摄像头捕捉。随后安装在PC/Mac上的信号处理软件就会进行最核心的工作:通过反射的激光光斑定位用户的指尖位置,并求出对应的按键: 虚拟激光键盘效果图如下: 视频演示: 虚拟激光键盘原理分析: 在具体介绍实现过程前,我们首先需要分析这类激光投影键盘的工作原理以及给出解决问题的思路,这样也可方便大家举一反三。首先需要解决的核心问题有这么两个: 如何产生键盘的画面? 如何检测键盘输入事件? 产生键盘画面 对于产生键盘画面,可能很多人认为这种画面是通过激光+高速光学振镜来得到的。这种方式虽然在技术上是完全可行的,但由于需要采用精密的机械部件,成本非常高,并且也难以做成轻便的产品。 通过光学振镜扫描产生的激光投影画面截图 实际上在激光投影键盘产品中,这类画面往往是通过全息投影技术得到的。激光器通过照射先前保存有键盘画面的全息镜片的方式在目标平面上产生相应的画面。这种方式的成本非常低廉,市面销售的激光笔常配备的投影图案的镜头也是用这种原理产生的。 不过这类全息投影方式对于DIY来说仍旧不现实,幸好得益于目前网络的便利——通过网购可以直接买到用于产生激光键盘画面的全息投影设备了,且成本在¥50以内。 更多详细介绍详见附件内容。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值