本页主题: (原创)简单讲解用JMF技术在网页中用Applet直接抓取摄像头的影像(附源代码) 打印 | 加为IE收藏 | 收藏主题 | 上一主题 | 下一主题

oscar

头衔:口琴王子 口琴王子
状态: 离线
级别: CEC高级程序员
精华: 2
发帖: 71
威望: 3 点
财富: 250 元
在线时间:0(小时)
注册时间:2006-05-17
最后登录:2008-11-12

(原创)简单讲解用JMF技术在网页中用Applet直接抓取摄像头的影像(附源代码)

Oscar Xie
Software Engineer
eMail:Xie.Oscar@gmail.com
MSN:oscar.xie@eBaoTech.com

需求描述:

我自己的R&D系统学生注册模块中,学生领到ID号码后,在电脑前用摄像头采集照片,采集的工作人员在WEB页面上控制系统采集拍照,工作人员可以实时看到学生头像的效果,在等到满意的画面时按拍照取像,系统将原来页面上指定的区域内照片采集下来,同时生成ID号码的条形码图像存入数据库(暂不讨论,过后发新帖)。

之前在这里发过类似的贴子,在这个需求中,需要实现用Applet在页面直接拍照,当然拍照的同时要实时预览拍摄的取像效果,所以有一个监视窗口,同时在监视窗口中画一个红色的矩形拍照边框,拍照结束后,直接将照片插入图像数据库,最早我想用SWT做GUI然后内部用JMF技术来拍照,将数据流用SWT容器来显示(就是监视窗口),这个如果用AWT的窗口是不费吹灰之力的,但是界面不好看,用SWT是一个技术难点,主要是数据流和播放容器的问题,所以值得一试,但是这里的问题一直没有解决,期待有人能提供一个解决方案。现在我是用Applet在页面上直接拍照的,可以看到WebCam的实时影像,其它的就是如何将Applet取到的单桢图像保存下来,这个问题不大,不过这里可能会遇到的问题就是安全问题,JMF有一个注册表专门来管理这些JMF相关的配置信息。

这里我没有摄像头,用了一个虚拟摄像头软件,驱动都一样的。

代码解析如下(论坛页面上对中括号的处理有bug,我将中括号临时改了一下):

import java.awt.BorderLayout;
import java.awt.Choice;
import java.awt.Component;
import java.util.Vector;
// JMF相关的类
import javax.media.CaptureDeviceInfo;
import javax.media.CaptureDeviceManager;
import javax.media.Format;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.Player;
import javax.media.format.VideoFormat;

import javax.swing.JPanel;

import javax.swing.JApplet;

public class VApplet extends JApplet {

private JPanel jContentPane = null;
 
private Choice choice = null;
 
public VApplet() {
super();
}
 
public void init() {
this.setSize(320, 240);
this.setContentPane(getJContentPane());
this.setName("VApplet");
}
 // 取系统所有可采集的硬件设备列表
private CaptureDeviceInfo[] getDevices() {
Vector devices = CaptureDeviceManager.getDeviceList(null);
CaptureDeviceInfo[] info = new CaptureDeviceInfo[devices.size()];
for (int i = 0; i < devices.size(); i++) {
info〔i〕 = (CaptureDeviceInfo) devices.get(i);
}
return info;
}
// 从已知设备中取所有视频设备的列表
private CaptureDeviceInfo[] getVideoDevices() {
CaptureDeviceInfo[] info = getDevices();
CaptureDeviceInfo[] videoDevInfo;
Vector vc = new Vector();
for (int i = 0; i < info.length; i++) {
// 取设备支持的格式,如果有一个是视频格式,则认为此设备为视频设备
Format[] fmt = info〔i〕.getFormats();

for (int j = 0; j < fmt.length; j++) {
if (fmt[j] instanceof VideoFormat) {
vc.add(info〔i〕);
}
break;
}
}
videoDevInfo = new CaptureDeviceInfo[vc.size()];
for (int i = 0; i < vc.size(); i++) {
videoDevInfo〔i〕 = (CaptureDeviceInfo) vc.get(i);
}
return videoDevInfo;
}

private JPanel getJContentPane() {
if (jContentPane == null) {
BorderLayout borderLayout = new BorderLayout();
jContentPane = new JPanel();
jContentPane.setLayout(borderLayout);
 
MediaLocator ml = null;
Player player = null;
try {
// 这里我只有一个视频设备,直接取第一个
      // 取得当前设备的MediaLocator

ml = getVideoDevices()[0].getLocator();
// 用已经取得的MediaLocator得到一个Player
player = Manager.createRealizedPlayer(ml);

player.start();
// 取得Player的AWT Component

Component comp = player.getVisualComponent();
// 如果是音频设备这个方法将返回null,这里要再判断一次
if (comp != null) {
// 将Component加到窗体

jContentPane.add(comp, BorderLayout.EAST);
}
} catch (Exception e) {
e.printStackTrace();
}
}
return jContentPane;
}
}

这个例子需要的环境信息如下:

Java Media Framework 运行库下载地址

http://java.sun.com/products/java-media/jmf/2.1.1/download.html

Additional link
http://java.sun.com/products/java-media/jmf/2.1.1/documentation.html
[ 此贴被oscar在2007年02月12日 20:52重新编辑 ]
描述:Eclipse中直接运行的效果
图片:
描述:Firefox浏览器中运行的效果
图片:
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
我自己的照片&口琴音乐:   http://kouqin.zj.com
顶端 时间: 2007年02月12日 17:27 | [楼 主]
seanla

头衔:今天你Eclipse了没 今天你Eclipse了没
状态: 离线
级别: CEC高级程序员
精华: 0
发帖: 91
威望: 0 点
财富: 299 元
在线时间:3(小时)
注册时间:2006-02-23
最后登录:2008-11-18

谢谢楼主,学到东西了
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
AndroidWorld中文社区欢迎各位访问!
www.androidworld.org.cn
顶端 时间: 2007年02月12日 20:23 | 1 楼
romkk

状态: 离线
级别: CEC高级程序员
精华: 0
发帖: 9
威望: 11 点
财富: 211 元
在线时间:2(小时)
注册时间:2005-12-16
最后登录:2007-11-07

      不错呀,我现在也遇到你这样的需求,不知你是怎么实现预览-截图-保存到数据库的。上面的代码还只是从摄像头获取图像,后面的步骤还没有,不知道楼主实现了没有。希望楼主能共享一下,感激不尽。
   
顶端 时间: 2007年03月12日 17:35 | 2 楼
romkk

状态: 离线
级别: CEC高级程序员
精华: 0
发帖: 9
威望: 11 点
财富: 211 元
在线时间:2(小时)
注册时间:2005-12-16
最后登录:2007-11-07

不知道在web中截取摄像头的图片还有什么方法!!!!
顶端 时间: 2007年03月12日 17:36 | 3 楼
oscar

头衔:口琴王子 口琴王子
状态: 离线
级别: CEC高级程序员
精华: 2
发帖: 71
威望: 3 点
财富: 250 元
在线时间:0(小时)
注册时间:2006-05-17
最后登录:2008-11-12

给你写代码看一下,关注一下蓝色的代码,得到Image以后你再用JPEGImageEncoder或其它方式写到文件或数据库

try {
            player = Manager.createRealizedPlayer(ml);
            player.start();
            Component comp;
            if ((comp = player.getVisualComponent()) != null) {              
                FrameGrabbingControl fbc = (FrameGrabbingControl) player
                        .getControl("javax.media.control.FrameGrabbingControl");
                Buffer buf = fbc.grabFrame();
                BufferToImage bti = new BufferToImage((VideoFormat) buf
                        .getFormat());
                Image img = bti.createImage(buf);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
我自己的照片&口琴音乐:   http://kouqin.zj.com
顶端 时间: 2007年03月13日 13:25 | 4 楼
cncangle

状态: 离线
级别: CEC程序员
精华: 0
发帖: 2
威望: 1 点
财富: 2 元
在线时间:0(小时)
注册时间:2007-01-25
最后登录:2007-04-13

如何写入数据库?
我用插件调试的时候用的是先把image对象存入文件“D:\\tem.jpg”,然后在访问文件存入数据库成功。但用到网页中无法输出成文件,也无法访问到文件所以无法存入数据库。
顶端 时间: 2007年03月17日 09:35 | 5 楼
cncangle

状态: 离线
级别: CEC程序员
精华: 0
发帖: 2
威望: 1 点
财富: 2 元
在线时间:0(小时)
注册时间:2007-01-25
最后登录:2007-04-13

急!!盼尽快答复
顶端 时间: 2007年03月17日 09:36 | 6 楼
oscar

头衔:口琴王子 口琴王子
状态: 离线
级别: CEC高级程序员
精华: 2
发帖: 71
威望: 3 点
财富: 250 元
在线时间:0(小时)
注册时间:2006-05-17
最后登录:2008-11-12

<以下为邮件原文>

XXX
   
你好,用在WEB环境中,你最好不要直接用“D:\\tem.jpg”这样来向本地写文件的
如果你的应用的访问时是在
http://127.0.0.1:8080/webapp/xxx.jsp
这里request.getContextPath()可以取到/webapp这个目录

我给你写两段写分别生成文件和写数据库的代码:
这里只要看一下蓝色代码可以了,这里我是生成的条形码图片,和你的差不多
生成文件>

[size=-0]import com.mask.util.barcode.BarCode;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGEncodeParam;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
[size=-0]XXXXX.......

 
PrintBarForm form = (PrintBarForm) arg1;
    String appRoot = "D:/program files/Apache Software Foundation/Tomcat 5.0/webapps/rd_sys";
    String filename = appRoot+"/temp/temp.jpeg";   
    File file = new File(filename); 
         FileOutputStream output = new FileOutputStream(file);
         BarCode barcode = new BarCode();
         barcode.code = form.getBarCode();
         //barcode.barType = BarCode.CODE128;
         barcode.barType = BarCode.CODE39;
         barcode.setSize(barcode.width * 2, barcode.height * 2);
         //则采用自动适应条码的尺寸
         BufferedImage bufferedimage_temp = new BufferedImage(barcode.getSize().width, barcode.getSize().height,  BufferedImage.TYPE_BYTE_INDEXED);
         Graphics2D graphics2d_temp = bufferedimage_temp.createGraphics();
         barcode.paint(graphics2d_temp);
         barcode.invalidate();
         graphics2d_temp.dispose();
         //格式化图片格式为jpeg
         BufferedImage bufferedimage = new BufferedImage(barcode.getSize().width, barcode.getSize().height, BufferedImage.TYPE_INT_RGB);
         Graphics2D graphics2d = bufferedimage.createGraphics();
         barcode.paint(graphics2d);
         JPEGImageEncoder jpegimageencoder = JPEGCodec.createJPEGEncoder(output);
         JPEGEncodeParam jpegencodeparam = jpegimageencoder.getDefaultJPEGEncodeParam(bufferedimage);
         jpegencodeparam.setQuality(1.0F, true);
         jpegimageencoder.setJPEGEncodeParam(jpegencodeparam);
         jpegimageencoder.encode(bufferedimage, jpegencodeparam);
         output.close();
 
   System.out.println("Image created");
  }catch(Exception e){
   e.printStackTrace();
  }

如果要写入数据库,可以将文件流直接写入数据库:

public ByteArrayOutputStream getOps() {
  ByteArrayOutputStream bops = null;
  BitmapCanvasProvider canvas = null;
  String msg = "620101198508271513";
  Code128Bean bean = new Code128Bean();
  int dpi = 120;
  try {   
   bean.setModuleWidth(UnitConv.in2mm(1.0f / dpi));
   bops = new ByteArrayOutputStream(1024 * 10);
   canvas = new BitmapCanvasProvider(bops,
     MimeTypes.MIME_PNG, dpi, BufferedImage.TYPE_BYTE_BINARY,
     false);
   bean.generateBarcode(canvas, msg);
   canvas.finish();   
  } catch (Exception e) {
   e.printStackTrace();
  }
  System.out.println(bops==null);
  return bops;
 }
 
 public void setImage(ByteArrayOutputStream bops){
  try{
   String url = "jdbc:mysql://localhost/dev_db";
   String user = "dev_user";
   String pwd = "Li7129";
   String sql = "update t_image set image = ? where image_id = 1 ";
   Connection conn = null;
   PreparedStatement psmt = null;
   ResultSet rslt = null;
   Class.forName("com.mysql.jdbc.Driver");
   conn = DriverManager.getConnection(url,user,pwd);
   System.out.println("Connected.");
   psmt = conn.prepareStatement(sql);
   System.out.println(bops.toByteArray().length);
   psmt.setBytes(1,bops.toByteArray());
   psmt.executeUpdate();
   /*while(rslt.next()){
    Blob blob = rslt.getBlob("image");
    int lens = blob.setBytes(0,bops.toByteArray());
    System.out.println("Lens:"+lens);   
   }*/
   
  }catch(Exception e){
   e.printStackTrace();
  }
 }

public static void main(String[] arg) {
  DB db = new DB();
  ByteArrayOutputStream ops = db.getOps();
  db.setImage(ops);
 }

以上都是我自己的想法,不一定是最好的解决方案仅供参考,希望对你有用
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
我自己的照片&口琴音乐:   http://kouqin.zj.com
顶端 时间: 2007年03月17日 12:21 | 7 楼
lxm2010

状态: 离线
级别: CEC程序员
精华: 0
发帖: 1
威望: 1 点
财富: 1 元
在线时间:0(小时)
注册时间:2007-06-16
最后登录:2007-06-16

你好啊
那个原创)简单讲解用JMF技术在网页中用Applet直接抓取摄像头的影像 ...的帖子上的源代码
我在运行的时候老提示
run-applet:
java.lang.ArrayIndexOutOfBoundsException: 0
        at VApplet.getJContentPane(VApplet.java:74)
        at VApplet.init(VApplet.java:29)
        at sun.applet.AppletPanel.run(AppletPanel.java:373)
        at java.lang.Thread.run(Thread.java:595)

请问是什么原因呢?
顶端 时间: 2007年06月16日 17:00 | 8 楼
yangxt

状态: 离线
级别: CEC程序员
精华: 0
发帖: 2
威望: 1 点
财富: 2 元
在线时间:0(小时)
注册时间:2007-02-08
最后登录:2008-04-02

非常感谢lz,小弟学习中。。。。
顶端 时间: 2007年08月14日 17:16 | 9 楼
itjoy

状态: 离线
级别: CEC高级程序员
精华: 0
发帖: 39
威望: 1 点
财富: 139 元
在线时间:0(小时)
注册时间:2006-12-04
最后登录:2008-07-02

正在做一个照片现场采集的模块,楼主的东东很有参考价值,谢谢了
顶端 时间: 2007年09月10日 10:13 | 10 楼
kangsoft

状态: 离线
级别: CEC程序员
精华: 0
发帖: 1
威望: 1 点
财富: 1 元
在线时间:0(小时)
注册时间:2008-05-22
最后登录:2008-05-22

你好:
刚刚学jmf 吧你的代码copy走了  但是出错了
run-applet:
java.lang.ArrayIndexOutOfBoundsException: 0
        at VApplet.getJContentPane(VApplet.java:74)
        at VApplet.init(VApplet.java:29)
        at sun.applet.AppletPanel.run(AppletPanel.java:373)
        at java.lang.Thread.run(Thread.java:595)

而且 我也不懂是如何用虚拟设想头弄啊!!!!
能不能说的跟详细点
顶端 时间: 2008年05月22日 15:05 | 11 楼
zilanshe

状态: 离线
级别: CEC程序员
精华: 0
发帖: 1
威望: 1 点
财富: 1 元
在线时间:0(小时)
注册时间:2008-06-16
最后登录:2008-06-19

为什么 我把代码放到 JBuilder2005里面运行 显示不了呢 而且不抱错
顶端 时间: 2008年06月18日 00:05 | 12 楼
wcplyy

状态: 离线
级别: CEC程序员
精华: 0
发帖: 2
威望: 1 点
财富: 2 元
在线时间:0(小时)
注册时间:2008-06-27
最后登录:2008-10-08

楼主,请教下SWT中视频采集,我买的一个视频监控卡是天敏的VC4000,能时时显示4路视频,但是用SWT+JMF开发的话,怎么把得到的视频放到SWT容器中呢。我看网上的资料大部分是放在AWT或SWING里。请问楼主是否知道SWT容器怎么存放JMF获得的视频
顶端 时间: 2008年08月13日 16:55 | 13 楼
oscar

头衔:口琴王子 口琴王子
状态: 离线
级别: CEC高级程序员
精华: 2
发帖: 71
威望: 3 点
财富: 250 元
在线时间:0(小时)
注册时间:2006-05-17
最后登录:2008-11-12

我看到这个帖子说可以放到SWT窗口里去播,好久没有去碰过桌面JAVA的东西了
http://www.softhouse.com.cn/news/show/1369.html
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
我自己的照片&口琴音乐:   http://kouqin.zj.com
顶端 时间: 2008年08月14日 10:19 | 14 楼
snowteng17

状态: 离线
级别: CEC程序员
精华: 0
发帖: 20
威望: 1 点
财富: 20 元
在线时间:2(小时)
注册时间:2008-08-04
最后登录:2008-10-03

Re:(原创)简单讲解用JMF技术在网页中用Applet直接抓取摄像头的影像(附源代 ..

JMF第一次听说,长见识了
顶端 时间: 2008年10月01日 13:37 | 15 楼
ecl_0

状态: 离线
级别: CEC程序员
精华: 0
发帖: 18
威望: 10 点
财富: 18 元
在线时间:4(小时)
注册时间:2008-09-09
最后登录:2008-11-16

Re:(原创)简单讲解用JMF技术在网页中用Applet直接抓取摄像头的影像(附源代 ..

顶端 时间: 2008年10月13日 17:14 | 16 楼
中国Eclipse社区 » 项目交流


辽ICP备05021625号