65.9K
CodeProject 正在变化。 阅读更多。
Home

Lego 平移倾斜摄像头和物体跟踪

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.97/5 (63投票s)

2008年11月20日

GPL3

7分钟阅读

viewsIcon

202187

downloadIcon

6323

将普通USB网络摄像头通过乐高Mindstorms机器人套件变成一个云台摄像头,并使用C#进行简单物体跟踪。

引言

如果您从事计算机视觉领域,那么您肯定知道——一个摄像头很好,但一个云台摄像头更好!但是,如果您没有专门的云台摄像头,只有一个普通的USB网络摄像头怎么办?嗯,如果您喜欢自己动手制作,那也不是什么大问题。在网上快速搜索一下,您可能会找到各种制作云台摄像头的教程。其中一些教程使用了非常简单的电子元件和步进电机,而另一些则使用了不同的特殊云台设备,这些设备可用于将任何摄像头变成云台摄像头。

在本文中,我们将讨论另一种制作自制云台摄像头的方法,该方法利用一个普通的USB网络摄像头和乐高Mindstorms NXT机器人套件。我们已经在另一篇文章中讨论了使用AForge.NET框架与乐高机器人套件进行通信,所以现在,我们将以此为基础,专注于构建我们的云台设备并对其进行操作。

在我们构建好云台摄像头后,我们将加以利用——我们将尝试定位一些物体,并利用上述AForge.NET框架的图像处理例程来跟踪它们。这部分将是相当通用的,可以应用于任何带有云台设备的摄像头。

那么,让我们开始构建吧……

更改乐高Mindstorm的电源供应

当您构建一个在特定区域移动的机器人时,机器人的移动性非常重要,任何电线都可能轻易地中断它。因此,移动机器人应该是无线的,随身携带电池,并在需要时与主机进行无线通信。然而,云台摄像头不需要到处移动,它们只需要固定在一个地方,只将摄像头转动一定的角度。这意味着,与无线移动性相比,我们可能更希望恒定的电源供应,使设备能够尽可能长时间地工作。

因此,我们要做的第一步是去掉Lego Minstorm的电池,并使用普通的电源适配器为其供电。NXT模块需要9伏特电源,最初是通过6节电池实现的——每节电池提供1.5伏特。我们需要做的是找到一个提供类似电压的电源适配器。我没有一个确切的9伏特适配器,但看起来7.5伏特也能正常工作。因此,拿一些电线和焊接工具,我们可以让我们的NXT模块由电源适配器供电……

Lego's power supply - internal viewLego's power supply - assembled view

将电源适配器连接到升级后的NXT,它就能启动了!我们可以使用AForge.NET框架中的一个简单的NXT测试应用程序来检查连接性并查看模块的电源——对于我们的7.5伏特适配器,它显示为7671毫伏。

NXT brick's status

构建一个云台摄像头

嗯,很难提供关于如何用乐高NXT零件构建云台模块的详细分步说明。但实际上,这是不必要的,因为它会扼杀创造力和想象力。云台模块非常简单——最简单的方法是使用套件提供的旋转平台零件。俯仰模块可能需要一些工作。我尝试了几种不同的方案,并决定基于块状并带有螺纹操纵平台的方案对我来说效果最好。

Pan moduleTilt module

将两部分连接在一起并安装一个罗技摄像头,就构成了一个相当有趣的模型,它赋予了摄像头两个自由度。是的,这个设备看起来不小,但它是使用乐高积木的通用零件构建的。实际上,这足以满足我们进一步的实验。

Assembled pan tilt camera

摄像头视图及其操作

在我们开始操作摄像头之前,我们首先需要获取它的视图。这非常简单,VideoSourcePlayer控件将为我们完成所有工作,因为它负责视频显示。我们所需要做的就是将控件放在我们的表单上,创建所需的视频源提供程序,并将其交给控件。在这种情况下,我们将使用VideoCaptureDevice类,该类通过DirectShow接口处理捕获设备。

VideoCaptureDevice videoSouce = new VideoCaptureDevice( deviceMonikerString );

videoSourcePlayer.VideoSource = videoSouce;
videoSourcePlayer.Start( );

现在,当我们有了视图,我们就需要对其进行操作。为此,我们将使用两个特殊的控件来控制摄像头——一个控制云台设备,另一个控制俯仰设备。这些是简单的控件,中央有一个操纵器,将其从中心移开会导致摄像头向一个或另一个方向移动。下面的截图可以说明这个想法……

Initial version of application

我们不打算在这里讨论操纵控件的代码(可以在文章的附件中找到),但需要提到的是,它在操纵器位置改变时会生成一个事件,该事件提供其在[-1, 1]范围内的当前位置(0表示操纵器在中心)。因此,收到事件后,我们只需要将操纵器的位置转换为电机的功率,然后将其打开(我们使用的是AForge.NET框架中的NXTBrick类,该类之前已有讨论)。

// convert power to the |[55, 60]| range
int power = (int) ( 5 * panMotorPower + 55 * Math.Sign( panMotorPower ) );

NXTBrick.MotorState motorsState = new NXTBrick.MotorState( );
// check if we need to stop
if ( power == 0 )
{
    motorsState.Mode      = NXTBrick.MotorMode.None;
    motorsState.RunState  = NXTBrick.MotorRunState.Idle;
}
else
{
    motorsState.Mode       = NXTBrick.MotorMode.On;
    motorsState.RunState   = NXTBrick.MotorRunState.Running;
    motorsState.TachoLimit = 0;
    motorsState.Power      = power;
    motorsState.TurnRatio  = 80;
}

nxt.SetMotorState( NXTBrick.Motor.A, motorsState );

注意:功率转换方程可能看起来不同——这取决于您希望电机移动的速度。

现在,我们已经用乐高Mindstorms NXT机器人套件和罗技摄像头构建了一个云台摄像头,并且可以使用普通的鼠标和两个控件手动操作它。下一步是让它自己动起来……

物体跟踪

云台摄像头比固定摄像头更有趣,因为它们提供了非常有趣的可能性,例如物体跟踪。既然我们刚刚构建了一个云台摄像头,让我们尝试完成跟踪一些简单物体的任务。例如,让我们跟踪一个特定颜色的球。

在我们开始跟踪之前,第一个任务是检测物体并获取其在摄像头图像上的位置。由于我们将跟踪实心颜色的简单物体,因此可以使用AForge.NET框架提供的图像处理例程轻松完成物体检测。第一步是执行颜色过滤,只保留我们感兴趣的颜色物体,并去除所有其他物体,例如可以使用ColorFiltering类来实现。

// create color filter
ColorFiltering colorFilter = new ColorFiltering( );
// configure the filter to keep red object only
colorFilter.Red   = new IntRange( 110, 255 );
colorFilter.Green = new IntRange(   0,  60 );
colorFilter.Blue  = new IntRange(   0,  60 );
// filter image
colorFilter.ApplyInPlace( image );

Source camera viewColor filtering to locate red objects

现在,当我们得到了只包含感兴趣物体的图像后,我们需要获取其坐标。这可以通过使用BlobCounter类来实现,该类能够定位独立的对象。然而,该类仅适用于灰度图像和二值图像,因此我们首先需要使用GrayscaleBT709滤波器,例如。

// create grayscale filter
GrayscaleBT709 grayscaleFilter = new GrayscaleBT709( );
// apply it to color filtered image
Bitmap grayImage = grayscaleFilter.Apply( image );

// create blob counter
BlobCounter blobCounter = new BlobCounter( );
// configure it to filter out small objects
blobCounter.MinWidth  = 25;
blobCounter.MinHeight = 25;
blobCounter.FilterBlobs = true;
// set ordering - bigger objects go first
blobCounter.ObjectsOrder = ObjectsOrder.Size;

// locate blobs
blobCounter.ProcessImage( grayImage );
Rectangle[] rects = blobCounter.GetObjectRectangles( );

// get the biggest object
if ( rects.Length > 0 )
{
    Rectangle objectRect = rects[0];

    ...
}

从上面的代码可以看出,我们只取第一个物体,也就是最大的物体,因为我们不想处理任何具有相似颜色或仅是噪点的较小物体。

现在,最后一步是获取物体中心的坐标并使摄像头朝向它……

int objectX = objectRect.X + objectRect.Width / 2 - image.Width / 2;
int objectY = image.Height / 2 - ( objectRect.Y + objectRect.Height / 2 );

最后,让我们看看实际效果……

结论

好吧,最后,我们已经构建了一个云台摄像头,甚至能够跟踪一些物体。不是一个顶级的摄像头,但它是用通用的乐高积木制作的。

我用我的乐高NXT电机发现了一些水下石头,它们不允许进行精确的移动,这使得实现摄像头的平滑移动变得困难。根据乐高文件,电机的功率范围是[0, 100](负向运动为[-100, 0])。但是,将功率设置为50没有任何效果,只会产生恼人的噪音,而将其设置为60可能会导致移动速度过快,这对于精确操作是不可接受的。

关于我们用来定位感兴趣物体的颜色过滤,有不同的方法可以获得更好的结果。我们应用过的ColorFiltering过滤器是最简单的,它在RGB颜色空间中执行颜色过滤,对于RGB图像具有最快的性能。然而,例如,在HSL颜色空间中进行过滤,在仅定位我们想要的颜色并拒绝其他颜色方面可能获得更好的结果(请参阅HSLFiltering过滤器)。

尽管本文介绍了使用乐高NXT积木手动制作的云台摄像头进行物体跟踪,但跟踪代码可以很容易地应用于任何其他云台摄像头。您需要做的就是检测物体,计算其中心的坐标,然后将摄像头朝向它。

© . All rights reserved.