您的位置:首页 > 其它

C/S构架的USB摄像头视频采集

2009-08-14 20:01 337 查看
最近开始做一个机器人操作界面RescueOperator。主要功能有:

显示安装在机器人上的摄像头采集到得视频

显示机器人传感器状态

控制机器人运动

控制机器人手臂

昨天刚刚实现了摄像头视频显示功能。为了调试方便,先做了一个测试用的AgentTest。AgentTest采集USB摄像头视频,并通过网络传输给RescueOperator。

我用JMF[1]

来采集视频。JMF支持添加视频,声音等媒体信息,并且支持捕捉,回放,译码。我只是用它来采集显示视频。相关的类有:

javax.media.CaptureDeviceManager

javax.media.CaptureDeviceInfo

javax.media.MediaLocator


javax.media.Player

javax.media.Manager

CaptureDeviceManager负责管理系统中所哟可用的采集设备。在使用前需要通过JMFRegister注册USB摄像头,也可用通过CaptureDeviceManager来注册采集设备。

CaptureDeviceInfo用于保存采集设备的信息,包括设备输出格式,设备名,MediaLocater。

MediaLocator负责描述媒体内容的位置。它与URL相似。采用一种vfw协议。USB摄像头的MediaLocator.toString()为“vfw://0”。

Player是一个接口,继承MediaHandler和Controller。它负责显示,控制媒体数据。

Manager可以让程序访问系统非独立资源,比如Player,DataSources,Processor等。这里,我用它根据MediaLocator创建Player实例。实例化Player后,需要调用其Start()方法。为了显示视频,我们需要调用Player的getVisualComponent()方法来获得一个gui组建。将该组件添加到窗口中,就可以显示摄像头四品了。

对于AgentTest,最关键的是将视频截为一帧帧图片,再发送给操作站。截取视频也可以使用JMF来实现。首先,获得FrameGrabbingControl实例:

FrameGrabbingControl fgc = (FrameGrabbingControl) cameraView.player.getControl("javax.media.control.FrameGrabbingControl");


然后直接获得当前帧的buffer

Buffer buffer = fgc.grabFrame();


最后将buffer转为byte[],这个过程比较复杂(应该有更简单的方法吧)

BufferToImage b2i = new BufferToImage((RGBFormat) buffer.getFormat());
Image capturedImage = b2i.createImage(buffer); // show the image
BufferedImage bImage;
try {
bImage = new BufferedImage(capturedImage.getWidth(cameraView), capturedImage.getHeight(cameraView), BufferedImage.TYPE_INT_RGB);
} catch (NullPointerException e) {
e.printStackTrace();
return;
}
Graphics2D bImageG = bImage.createGraphics();
bImageG.drawImage(capturedImage, 0, 0, capturedImage.getWidth(cameraView), capturedImage
.getHeight(cameraView), cameraView);
bImageG.dispose();
ByteArrayOutputStream byteOS = new ByteArrayOutputStream();
try {
ImageIO.write(bImage, "JPEG", byteOS);
byte[] imageData = byteOS.toByteArray();
}catch(){
}


发送信息中还要添加图片的字节长度,方便操作站接受。这样就大功告成了,直接发送...

接下来就是完成操作站的接受和显示工作。

接受时先读取图片字节长度,然后读取图片数据。然后用java.awt.Toolkit将图片数据生成图片。

然后就只剩把一帧一帧图片画到Canvas上了。调用drawImage()方法时,需要传一个ImageObserver[2]

。调用drawImage()时,image可能还没有完全加载,甚至还没有开始加载。如果drawImage()方法等待图片加载,可能会降低程序响应速度。所以java会在开启一加载图片的线程来监视图片加载。ImageObserver就是用来监视图片加载状态的。java提供三种监视图片加载方法:

ImageObserver 重写imageUpdate
()方法,手动监视加载图片

MediaTracker 加载多个图片

ImageIcon 加载单个图片

显然,我需要MediaTracker。想MediaTracker中添加图片时需要给一个ID。ID决定加载图片的优先级,ID越小,优先级越高。

最后比较一下ImageObserver和MediaTracker的性能。加载连续图片时,MediaTracker用时<20ms,而ImageObserver需要100ms左右,相差一个数量级。

需要改进:

CPU使用率高

向MediaTracker添加图片时,用了ArrayList和HashMap,虽然不会太大,但可能没有必要

AgentTest中,用Buffer生成图片的方法太繁琐,效率低

进一步工作:

完成视频接收显示测试,主要测试延时;

确定电机控制协议;

实现按键响应->控制信息发送;

设计GUI界面;

接收图片与接收其他传感器信息分别用两个Socket。因为图片数据是基于字节的,而其他传感器信息是基于数字或字符串的;

将图片解析从AgentSenseThread中移出,并添加其他传感器信息的解析模块;

引用:

[1] http://java.sun.com/javase/technologies/desktop/media/jmf/index.jsp
[2] http://www.particle.kth.se/~lindsey/JavaCourse/Book/Part1/Java/Chapter11/loadingImages.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: