科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件VC DirectShow对视频进行图片处理之四

VC DirectShow对视频进行图片处理之四

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

在我的程序中图像处理函数是作为 DirectShow 封装类一部分的,我认为这样便于移动和使用.

作者:longway 来源:天极开发 2007年10月16日

关键字:

  • 评论
  • 分享微博
  • 分享邮件
7. 来点高级的,用摄像头控制鼠标!

  看着这个有点神奇吧,其实比什么都要简单。先做好"硬件准备":把摄像头如图摆放,镜头下方放张白纸以使图像中物体界限分明。


  软件方面,把图片作阀值处理-- B 值大于 128 的设为黑色,其它的设为白色。因为白纸的作用,您的手或其他物体会在阀值图中显示为白色,如图,再找出图中红点,即第一点白点的在图中位置(x,y),再把图的坐标影射到屏幕坐标就行了。

 

  下面要讨论具体做法。先解决图像坐标问题。我获取第一点白点的程序如下:

void CDSControl::GetMousePos(BYTE* pb,int *xPos,int* yPos)
{
 int x,y;
 BOOL mouseFound = FALSE;
 for(y = 0; y < m_bmpHei; y ++){
  for(x = 0; x < m_bmpWid; x ++){
   if(pb[0] == 255){
    // 因为白色为(255,255,255),判断一个255 即可
    pb[2] = 255; // 设为红色,别忘了 BGRA 的内存排列方式
    pb[1] = pb[0] = 0; //
    // 计算坐标
    *xPos = ScreenWid - x * ScreenWid / m_bmpWid;
    *yPos = y * ScreenHei / m_bmpHei;
    mouseFound = TRUE;
    break;
   }
   pb += 4;
  }
  if(mouseFound){
   break;
  }
 }
}

  可以看出我是从所得的图像缓冲区的第一点开始检索的,这也是摄像头扫描 CCD 的顺序,看上面右边的图,那是右手的图像,可以推想出摄像头的扫描顺序如下图所示:

 
(摄像头扫描坐标) (与屏幕坐标(蓝)相对的摄像头坐标(红))

  而相对于屏幕坐标很容易得到上面右图,说明屏幕坐标以左上角为原点,x的正方向为右,而摄像头坐标以右上角为原点,x的正方向为左,也就是说我按顺序寻找所得到的坐标值是这样的:y 与屏幕坐标 y 相符,x 则与屏幕坐标 x 刚好相反。因此推算出鼠标位置应该是:

*xPos = ScreenWid - x * ScreenWid / m_bmpWid;
*yPos = y * ScreenHei / m_bmpHei;

  其中 ScreenWid 、ScreenHei 分别是屏幕的宽和高,用 ScreenWid = GetSystemMetrics(SM_CXSCREEN) 和 ScreenHei = GetSystemMetrics(SM_CYSCREEN) 得到,而m_bmpWid、m_bmpHei 当然是图片的宽和高了。得到鼠标坐标后再用 SetCursorPos 设置即可,只不过鼠标晃动会比较厉害,这与图像噪音有关,可能先做个柔化处理会好一点,但鉴于摄像头的摄像质量,我不想作无谓的挣扎,您不会真的想用摄像头代替鼠标吧?!

  在使用前应该调整二值图的阀值,使整个图都变成黑色,保证能正确滤除干扰,不然在按下"鼠标控制"按钮后您的鼠标就不会听话,您会无法控制好它。请问没有鼠标的帮忙您将如何关闭程序?对了,"Alt + F4",别忘了,否则您得硬着动手把摄像头拔掉!!

  可以说控制鼠标真的很容易实现,不过效果出奇的不错,这种好像无影无踪的控制方式相当令人惊奇,记得我的大哥看程序时对我前面的图像处理没有一丝反应,看到这个却大大的惊奇!呵呵。如果您有兴趣的话可以在此方面做更多的试验,例如可以把手裁剪出来,让它参加拨动一个小球等游戏,只要您的几何过关、有毅力就可以实现。

  8. 更实用的数字减影技术

  请看上面两幅图,左边的是先存储一幅背景图然后把手放到摄像头前摄像,用摄到的图片减去背景图得到的图;中图是根据左图把手的颜色设为原来颜色得到的;右图是不断用新图片减去上一幅图得到的手移动痕迹图。这充分显示了数字减影的功用:能够从背景分解物体和侦测到物体的运动。


  如此说来此技术在安保方面的应用会很突出,像上面右图那样不断减去上一幅图片,当减影后得到的图片差别大于某一程度的点多到一定数值时就说明有情况发生,这时候就提醒保安工作,弥补保安的人为失误,也可以在此时启动录像录取有价值的情况。请看程序:

void CDSControl::DNS(BYTE* pIn,BYTE* pReduce,BYTE* pOut)
{
 // pIn 新图的数据区指针,pReduce 背景指针,pOut 存储区指针
 if(!pReduce) return; // 没有背景图就不处理
 int differentPoint = 0;
 for(int i = 0; i < m_bmpBufferLen; i ++){
  // m_bmpBufferLen 为数据区长度
  pOut[i] = abs(pIn[i] - pReduce[i]); // 相减,取差值的绝对值
  if(pOut[i] > 32){
   // 相差大于 32 就认为是不同的点,此值因摄像头而异,与噪音有关,请自行试验
   differentPoint ++; // 不同点增加
   pOut[i] = pIn[i]; // 把不同点赋回它的颜色
  }
  if(differentPoint > 200){
   // 不同点大于 200 就认为有情况,应适当改变
   // 调用警报等……
  }
 }
}

  当然了,我可舍不得整天整夜开着电脑守着我睡觉,只是试验这项技术获取了却罢了。
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章