Tuesday, April 3, 2012

WebCam Video Capture in Java

I got a lot of requests asking for how to do video capturing in Java as comments on my previous post :

Capture photo / image from Web Cam / USB Camera using Java

In this quick post i will highlight how i did this functionality in Interactive4j

We will use the library LTI-CIVIL which is part of FMJ (Freedom for Media in Java).



PreRequisities:

-Download the library and place it correctly in your classpath and load the native library using JVM parameter exactly as the previous mentioned post above.
Download from here:  https://sourceforge.net/projects/lti-civil/

Steps:

1) Create Interface For Captured Images:
public interface CaptureListener {
/**
* Method called once capturing of the web cam jpg file is done.
* @param filename
*/
public void setCaptureFile(File filename);
}

2) Create A Wrapper Class:
This class wrap the camera functionality..

/**
* JHCaptureUtil class
* Used for capture images through the usb (camera, scanner,...etc)
* Osama Oransa
* Interactive4J
* (c) 2011
**/
package osa.ora.utils;

import com.lti.civil.*;
import com.lti.civil.awt.AWTImageConverter;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import osa.ora.utils.faces.CaptureListener;

/**
*
* @author mabdelmo
*/
public class JHCaptureUtil implements CaptureObserver {

CaptureStream captureStream = null;
CaptureListener captureListener;
String fileName;
/**
* Constructor accept the listener and file to save image into.
* @param captureListener
* @param fileName
*/
public JHCaptureUtil(CaptureListener captureListener, String fileName) {
this.fileName = fileName;
this.captureListener = captureListener;
init();
}
private void init(){
System.out.println("Init....");
/*
* initialize capturing to use the current devices...
*/
CaptureSystemFactory factory = DefaultCaptureSystemFactorySingleton.instance();
CaptureSystem system;
try {
system = factory.createCaptureSystem();
system.init();
List list = system.getCaptureDeviceInfoList();
int i = 0;
if (i < list.size()) {
CaptureDeviceInfo info = (CaptureDeviceInfo) list.get(i);
System.out.println((new StringBuilder()).append("Device ID ").append(i).append(": ").append(info.getDeviceID()).toString());
System.out.println((new StringBuilder()).append("Description ").append(i).append(": ").append(info.getDescription()).toString());
captureStream = system.openCaptureDeviceStream(info.getDeviceID());
captureStream.setObserver(this);
}
} catch (CaptureException ex) {
Logger.getLogger(JHCaptureUtil.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* Start capture method
*/
public void start() {
//System.out.println("Start....");
try {
captureStream.start();
} catch (CaptureException ex) {
Logger.getLogger(JHCaptureUtil.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* Stop capture method
*/
public void stop() {
//System.out.println("Stop....");
try {
captureStream.stop();
} catch (CaptureException ex) {
Logger.getLogger(JHCaptureUtil.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
*
* @param stream
* @param image
*/
public void onNewImage(CaptureStream stream, Image image) {
//System.out.println("get new image....");
byte bytes[] = null;
try {
if (image == null) {
return;
}
try {
ByteArrayOutputStream os = new ByteArrayOutputStream();
JPEGImageEncoder jpeg = JPEGCodec.createJPEGEncoder(os);
jpeg.encode(AWTImageConverter.toBufferedImage(image));
os.close();
bytes = os.toByteArray();
if (bytes == null) {
return;
}
} catch (Throwable t) {
t.printStackTrace();
bytes = null;
return;
}
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
File currentImageFile = new File(fileName);
FileOutputStream fos = new FileOutputStream(currentImageFile);
fos.write(bytes);
fos.close();
captureListener.setCaptureFile(currentImageFile);
} catch (IOException ex) {
Logger.getLogger(JHCaptureUtil.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
*
* @param stream
* @param ce
*/
public void onError(CaptureStream stream, CaptureException ce) {
System.out.println("Error : "+ce.getStackTrace());
}
}




3) Write the code that control your wrapper class:
Here is sample usage code that display a dialog with one image or a video .. You need to add 2 buttons 1 for image capture and 1 for video capture and add the action listeners on these buttons..


int mode=0;
static int ONE_PHOTO=0;
static int MULTI_PHOTO=1;
JHCaptureUtil webCam;

//this method to capture one image

private void captureImageButtonActionPerformed(java.awt.event.ActionEvent evt) {
mode=ONE_PHOTO;
if(webCam==null) webCam=new JHCaptureUtil(this, "/myWebCamPic.jpg");
webCam.start();
}

private void captureVideoActionPerformed(java.awt.event.ActionEvent evt) {
mode=MULTI_PHOTO;
if(webCam==null) webCam=new JHCaptureUtil(this, "/myWebCamPic.jpg");
webCam.start();
}


You class must implements : CaptureListener , this interface has 1 method inside it :
public void setCaptureFile(File filename);

And this is the interface method implementation that display the image without saving the photos (you can change the implementation)


JDialog monitorjDialog;
JLabel monitorLabel;
JScrollPane monitorScroll;

public void setCaptureFile(File filename) {
if(mode==ONE_PHOTO){
System.out.println("No more photos");
JDialog jDialog=new JDialog(this.getFrame(),true);
Image image=ImageUtils.loadJPG(filename.getAbsolutePath());
jDialog.setBounds(this.getFrame().getX()+50,this.getFrame().getY()+50,500, 500);
JLabel label=new JLabel(new ImageIcon(image));
JScrollPane jscroll=new JScrollPane(label);
jDialog.add(jscroll);
jDialog.setVisible(true);
jDialog.validate();
webCam.stop();
}else{
System.out.println("display new photo");
if(monitorjDialog==null) {
monitorjDialog=new JDialog(this.getFrame(),false);
monitorjDialog.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
webCam.stop();
}
});
Image image=ImageUtils.loadJPG(filename.getAbsolutePath());
monitorjDialog.setBounds(this.getFrame().getX()+50,this.getFrame().getY()+50,image.getWidth(null), image.getHeight(null));
monitorLabel=new JLabel(new ImageIcon(image));
monitorScroll=new JScrollPane(monitorLabel);
monitorjDialog.add(monitorScroll);
monitorjDialog.setVisible(true);
monitorjDialog.validate();
}else{
Image image=ImageUtils.loadJPG(filename.getAbsolutePath());
monitorjDialog.remove(monitorScroll);
monitorScroll.remove(monitorLabel);
monitorLabel=new JLabel(new ImageIcon(image));
monitorScroll=new JScrollPane(monitorLabel);
monitorjDialog.add(monitorScroll);
monitorjDialog.validate();
}
}
}

4) Utility method used: ImageUtils.loadJPG ..
public static Image loadJPG(String filename) {
FileInputStream in = null;
try {
in = new FileInputStream(filename);
} catch (java.io.FileNotFoundException io) {
System.out.println("File Not Found");
}
JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(in);
BufferedImage bi = null;
try {
bi = decoder.decodeAsBufferedImage();
in.close();
} catch (java.io.IOException io) {
System.out.println("IOException");
}
return bi;
}

That's all needed !