使用手势与计算机交互OpenCV和Java
在我们的日常生活中,我们用许多其他的方式与我们周围的人和环境互动。然而,当我们仅仅使用鼠标和键盘与计算机交互时,我们在速度和便利性方面是相当有限的。因此,为什么不使用计算机视觉和语音呢?
在本文中,我将介绍使用OpenCV与计算机交互的简单手势和移动跟踪。
捕捉摄像头流
你不需要任何华丽的硬件来实现这一点,只要笔记本的内置摄像头或任何外部摄像头就足够了。我们首先捕获摄像头的视频流,然后在每个帧上应用图像处理过滤器来识别手势和跟踪动作。为了方便,我使用了红色、绿色和蓝色的道具,它们的动作就是我们的输入。
CvCapture capture = cvCreateCameraCapture(0);
IplImage image = cvRetrieveFrame(capture);
cvFlip(image, image, 1);
分离颜色通道
每个图像都是一个n x m维的4D矩阵,其中n和m分别是图像的宽度和高度。每个矩阵表示图像中每个像素的rgba值,我们将把每个这些值提取到单独的1D矩阵中。
IplImage red = IplImage.create(image.cvSize(), image.depth(), 1);
cvSplit(image, red, green, blue, null);
提取颜色
我们需要一个灰度图像从颜色通道图像中取出来获取包含每种颜色强度的图像。灰度图像仅携带强度信息。
IplImage gray = IplImage.create(image.cvSize(), image.depth(), 1);
cvCvtColor(image,gray,CV_RGB2GRAY);
CvMat diff_red_mat = IplImage.create(image.cvSize(), image.depth(), 1).asCvMat();
cvSub(gray ,red , diff_red_mat, null);
我们现在所拥有的图像只有红色,高强度为白色,低强度为黑色。然后,我们应用高斯模糊和Medium filter来去除低强度红色值的不想要的失真和小片区域。然后,我们使用二进制阈值过滤器来填充图像,0表示无红色,1表示红色。
cvSmooth(diff_red_mat, diff_red_mat, CV_MEDIAN, 75);
cvSmooth(bin_red, bin_red, CV_GAUSSIAN, 5);
IplImage bin_red = cvCreateImage(image.cvSize(), image.depth(), 1);
cvThreshold(diff_red_mat, bin_red, 20, 200, CV_THRESH_BINARY);
寻找轮廓和界限
轮廓是轮廓边框。现在,我们绘制包含我们的轮廓的矩形,该轮廓包围所识别的对象并使用矩形的中心来跟踪道具的移动。
CvMemStorage mem = CvMemStorage.create();
CvSeq contours = new CvSeq();
CvSeq ptr = new CvSeq();
cvFindContours(binary, mem, contours, Loader.sizeof(CvContour.class) , CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0));
CvRect boundbox = null;
CvRect big=null;
if(!contours.isNull())
{
big = cvRect(0,0,1,1);
for (ptr = contours; ptr != null; ptr = ptr.h_next())
{
boundbox = cvBoundingRect(ptr, 0);
if(boundbox.height()*boundbox.width()>big.height()*big.width())
{
big=boundbox;
}
}
cvRectangle( image, cvPoint( big.x()-offset, big.y()-offset ), cvPoint( big.x() + big.width()+offset, big.y() + big.height()+offset),CvScalar.BLUE, 0, 0, 0 );
}
Robot 类
Java AWT库有一个Robot 类,它提供了生成输入以移动鼠标光标、单击和滚动的方法。我们将使用单色属性的矩形边界来移动我们的光标和两个颜色属性的任意两个矩形边界的碰撞以执行点击。我们也可以使用此手势进行拖放操作。
//Instantiate robot
Robot robot = new Robot();
//Scale points on image to screen resolution
double scalex = SCREEN_WIDTH / IMG_WIDTH;
double scaley = SCREEN_HEIGHT / IMG_HEIGHT;
double factorx = scalex * (double)cursor.x();
double factory = scaley * (double)cursor.y();
int x = (int)factorx * SPEED;
int y = (int)factory * SPEED;
//Mouse move
robot.mouseMove(x, y);
//Scroll
if(y < OFFSET)
robot.mouseWheel(-SCROLL_SPEED);
if(y > SCREEN_HEIGHT - OFFSET)
robot.mouseWheel(SCROLL_SPEED);
//Click
if(cursor.intersects(thumb))
{
robot.mousePress(InputEvent.BUTTON1_MASK);
} else {
robot.mouseRelease(InputEvent.BUTTON1_MASK);
}
这里cursor和thumb两个不同颜色的道具绑定在一起。
无限可能
借助OpenCV和Robot类,我们可以创建无限用例,以便使用手势与我们的计算机进行交互。我们可以创建一个手势识别器,基于记录的手势组合来启动应用程序,而不仅仅是跟踪道具的移动。这只是一个简单的例子,但我们也可以使用OpenCV的机器学习库来使我们的系统更加准确。而且,通过增加NLP,我们可以在I / O领域取得突破,摆脱传统的交互方式。