Solved

JTwain, BufferedImage and a lot of mess.

Posted on 2004-09-21
28
814 Views
Last Modified: 2008-01-09
Hey everyone again. I come to you w/ a problem that's been eating at me all day. I have acquired an image from my webcam using JTwain, but I can't seem to change it to BufferedImage so I can modify it and the like w/ the Graphics2D class. Can anyone help me here?

I'm not posting any code since, well, it'd be rather dumb to post useless code.


Thanks.
0
Comment
Question by:holobyted
  • 16
  • 12
28 Comments
 
LVL 92

Expert Comment

by:objects
ID: 12119424
If its not one already then you'll need to create a blank image and paint the image onto your new BufferedImage.
0
 

Author Comment

by:holobyted
ID: 12119443
Thing is, how?
0
 
LVL 92

Expert Comment

by:objects
ID: 12119507
try something like:

BufferedImage bi = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RBG);
bi.getGraphics().drawImage(image,0,0,NULL);
0
 

Author Comment

by:holobyted
ID: 12119549
getWidth() and getHeight() seem to require an ImageObserver object... which in turn doesn't let me use ImageIO so I can write it to a file (and actually make sure it's being made the way I want).

Any chance you can give me some barebone code, so I can look at something that's actually usable? Thanks.
0
 
LVL 92

Expert Comment

by:objects
ID: 12119585
Sorry ,try:

BufferedImage bi = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_RBG);
bi.getGraphics().drawImage(image,0,0,null);
0
 

Author Comment

by:holobyted
ID: 12119661
Okay, incoming code! You've been warned. This is what I have at the moment, but the RGB printing part doesn't go through. Also, how would I go on about writing it to a file?

---- snip/duck!

public class Final
{
      public static void main(String args[])
      {
            try {
                  Source source = SourceManager.instance().getDefaultSource();
                  
                  source.setIndicators(false);
                  source.setUIEnabled(false);
                  source.open();
                  
                  Image image = source.acquireImage();
                  int width = image.getWidth(null);
                  int height = image.getHeight(null);
                  
                  source.close();
                  
                  BufferedImage bi = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_RGB);
                  bi.getGraphics().drawImage(image,0,0,null);



                  for(int x = 0; x<width; x++)
                  {
                        for(int y = 0; y<height; y++)
                        {
                              Color c = new Color(bi.getRGB( x, y ));
                              int red = c.getRed(); int blue = c.getBlue(); int green = c.getGreen();
                              
                              System.out.println("RGB: " + red + "|" + green + "|" + blue + " [" + x + ", " + y + "]");
                        }
                  }

                  } catch(Exception e) {
                  JOptionPane.showMessageDialog(null, e);
                  System.exit(0);
            } finally{
                  SourceManager.closeSourceManager();
            }
      }
}

---- snip/you can now stand up.
0
 

Author Comment

by:holobyted
ID: 12128541
I decided to go into a somewhat simpler (or at least, more well known) method. I'm going to end up using Java Media Framework... however, I'm still clueless. Anyone ever coded a real-time webcam viewer? Is it possible to alter the frame(s) using Graphics2D?
0
 
LVL 92

Expert Comment

by:objects
ID: 12128772
> I'm going to end up using Java Media Framework

what is it exactly you are trying to achieve?

> Anyone ever coded a real-time webcam viewer?
>  Is it possible to alter the frame(s) using Graphics2D?

Depends how you code it :) Certainly possible.

0
 

Author Comment

by:holobyted
ID: 12128786
Well, my project itself is motion detection. Very basic, as I'll be using a white box and a red ball to test. JMF seems to be faster than JTwain, so it seems to be better. My idea is to have it be live, and analyze each of the frames one by one. Since there will be a huge difference between white and red, it'll be easy. After I analyze it I plan to draw a circle on top of the ball - that is, using Graphics2D.

I guess that sums it up.
0
 
LVL 92

Expert Comment

by:objects
ID: 12128834
0
 

Author Comment

by:holobyted
ID: 12128841
The example code on that site is incomplete...

   /*  Loop through the results and print them out for the user  */

   for (int i = 0; i

That goes for all the examples, too.
0
 

Author Comment

by:holobyted
ID: 12128848
Heh, I'm stupid. Or they are. Either way, just went into source code mode and they didn't escape the <. No wonder it wasn't displaying... let me check it.
0
 

Author Comment

by:holobyted
ID: 12129068
As pathetic as this may sound, would you be able to (*gulp*) copy/paste all of the example code into 1 .java for me? As you can probably guess, I'm not very good at this. FrameGrabber.zip isn't working for me either.

Once I can get the example code up and running, I think I'll be on my way off to start the analyzing process. (Granted you can also tell me how to access it as a BufferedImage :p)

Thanks, hope I'm not being too much of a hassle.
0
 
LVL 92

Accepted Solution

by:
objects earned 500 total points
ID: 12129101
/**
 *  JMF/Webcam Frame Grabber Demo
 *
 * @author S.Ritter  24.01.2002
 * @version 1.0
 *
 *  ALL EXAMPLES OF CODE AND/OR COMMAND-LINE INSTRUCTIONS ARE BEING
 *  PROVIDED BY SUN AS A COURTESY, "AS IS," AND SUN DISCLAIMS ANY AND
 *  ALL WARRANTIES PERTAINING THERETO, INCLUDING ANY WARRANTIES OF
 *  MERCHANTABILTY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
 *  SUN IS NOT LICENSING THIS EXAMPLE FOR ANY USE OTHER THAN FOR THE
 *  EDUCATIONAL PURPOSE OF SHOWING THE FUNCTIONALITY CONTAINED
 *  THEREIN, BY WAY OF EXAMPLE.
 **/
package jmfdemo;

import java.io.*;
import java.awt.*;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Vector;
import javax.media.*;
import javax.media.control.*;
import javax.media.protocol.*;
import javax.media.util.*;
import javax.media.format.RGBFormat;
import javax.media.format.VideoFormat;

/**
 *  Frame grabber class
 **/
public class FrameGrabber implements ControllerListener {
  /*  Default device name and format parameters to use if no properties file
   *  is provided
   */
  private final static String DEFAULT_DEV_NAME =
    "vfw:Logitech USB Video Camera:0";
  private final static String DEFAULT_X_RES = "160";
  private final static String DEFAULT_Y_RES = "120";
  private final static String DEFAULT_DEPTH = "24";

  private Properties videoProperties;

  private Object stateLock = new Object();

  private PushBufferStream camStream;
  private BufferToImage converter;

  /**
   *  Constructor
   *
   * @throws FrameGrabberException If we can't start up the camera
   **/
  public FrameGrabber() throws FrameGrabberException {
    /*  We use a properties file to allow the user to define what kind of
     *  camera and resolution they want to use for the vision input
     */
    String videoPropFile =
      System.getProperty("video.properties", "video.properties");

    try {
      FileInputStream fis = new FileInputStream(new File(videoPropFile));
      videoProperties = new Properties();
      videoProperties.load(fis);
    } catch (IOException ioe) {
      throw new FrameGrabberException(ioe.getMessage());
    }

    Dimension viewSize = null;
    int viewDepth = 0;

    String cameraDevice =
      videoProperties.getProperty("device-name", DEFAULT_DEV_NAME);

    /*  Get the parameters for the video capture device from the properties
     *  file.  If not defined use default values
     */
    try {
      String pValue =
        videoProperties.getProperty("resolution-x", DEFAULT_X_RES);
      int xRes = Integer.parseInt(pValue);
      pValue = videoProperties.getProperty("resolution-y", DEFAULT_Y_RES);
      int yRes = Integer.parseInt(pValue);
      viewSize = new Dimension(xRes, yRes);
      pValue = videoProperties.getProperty("colour-depth", DEFAULT_DEPTH);
      viewDepth = Integer.parseInt(pValue);
    } catch (NumberFormatException nfe) {
      System.out.println("Bad numeric value in video properties file");
      System.exit(1);
    }

    System.out.println("Searching for [" + cameraDevice + "]");

    /*  Try to get the CaptureDevice that matches the name supplied by the
     *  user
     */
    CaptureDeviceInfo device = CaptureDeviceManager.getDevice(cameraDevice);

    if (device == null)
      throw new FrameGrabberException("No device found [ " +
        cameraDevice + "]");

    RGBFormat userFormat = null;
    Format[] cfmt = device.getFormats();

    /*  Find the format that the user has requested (if available)  */
    for (int i = 0; i < cfmt.length; i++) {
      if (cfmt[i] instanceof RGBFormat) {
        userFormat = (RGBFormat)cfmt[i];
        Dimension d = userFormat.getSize();
        int bitsPerPixel = userFormat.getBitsPerPixel();
   
        if (viewSize.equals(d) && bitsPerPixel == viewDepth)
          break;

        userFormat = null;
      }
    }

    /*  Throw an exception if we can't find a format that matches the
     *  user's criteria
     */
    if (userFormat == null)
      throw new FrameGrabberException("Requested format not supported");

    /*  To use this device we need a MediaLocator  */
    MediaLocator loc = device.getLocator();

    if (loc == null)
      throw new FrameGrabberException("Unable to get MediaLocator for device");

    DataSource formattedSource = null;

    /*  Now create a dataSource for this device and set the format to
     *  the one chosen by the user.
     */
    try {
      formattedSource = Manager.createDataSource(loc);
    } catch (IOException ioe) {
      throw new FrameGrabberException("IO Error creating dataSource");
    } catch (NoDataSourceException ndse) {
      throw new FrameGrabberException("Unable to create dataSource");
    }

    /*  Setting the format is rather complicated.  Firstly we need to get
     *  the format controls from the dataSource we just created.  In order
     *  to do this we need a reference to an object implementing the
     *  CaptureDevice interface (which DataSource objects can).
     */
    if (!(formattedSource instanceof CaptureDevice))
      throw new FrameGrabberException("DataSource not a CaptureDevice");

    FormatControl[] fmtControls =
      ((CaptureDevice)formattedSource).getFormatControls();

    if (fmtControls == null || fmtControls.length == 0)
      throw new FrameGrabberException("No FormatControl available");

    Format setFormat = null;

    /*  Now we need to loop through the available FormatControls and try
     *  to set the format to the one we want.  According to the documentation
     *  even though this may appear to work, it may fail later on.  Since
     *  we know that the format is supported we hope that this won't happen
     */
    for (int i = 0; i < fmtControls.length; i++) {
      if (fmtControls[i] == null)
        continue;

      if ((setFormat = fmtControls[i].setFormat(userFormat)) != null)
        break;
    }

    /*  Throw an exception if we couldn't set the format  */
    if (setFormat == null)
      throw new FrameGrabberException("Failed to set camera format");

    /*  Connect to the DataSource  */
    try {
      formattedSource.connect();
    } catch (IOException ioe) {
      throw new FrameGrabberException("Unable to connect to DataSource");
    }

    System.out.println("Data source created and format set");

    /*  Since we don't want to display the output to the user at this stage
     *  we use a processor rather than a player to get frame access
     */
    Processor deviceProc = null;

    try {
      deviceProc = Manager.createProcessor(formattedSource);
    } catch (IOException ioe) {
      throw new FrameGrabberException("Unable to get Processor for device: " +
        ioe.getMessage());
    } catch (NoProcessorException npe) {
      throw new FrameGrabberException("Unable to get Processor for device: " +
        npe.getMessage());
    }

    /*  In order to use the controller we have to put it in the realized
     *  state.  We do this by calling the realize method, but this will
     *  return immediately so we must register a listener (this class) to
     *  be notified when the controller is ready.
     */
    deviceProc.addControllerListener(this);
    deviceProc.realize();
    System.out.println("Realizing capture device");

    /*  Wait for the device to send an event telling us that it has
     *  reached the realized state
     */
    while (deviceProc.getState() != Controller.Realized) {
      synchronized (stateLock) {
        try {
          stateLock.wait();
        } catch (InterruptedException ie) {
          throw new FrameGrabberException("Failed to get to realized state");
        }
      }
    }

    deviceProc.start();

    /*  Get access to the PushBufferDataSource which will provide us with
     *  a means to get at the frame grabber
     */
    PushBufferDataSource source = null;

    try {
      source = (PushBufferDataSource)deviceProc.getDataOutput();
    } catch (NotRealizedError nre) {
      /*  Should never happen  */
      throw new FrameGrabberException("Processor not realized");
    }
   
    /*  Now we can retrieve the PushBufferStreams that will enable us to
     *  access the data from the camera
     */
    PushBufferStream[] streams = source.getStreams();
    camStream = null;

    for (int i = 0; i < streams.length; i++) {
      /*  Use the first Stream that is RGBFormat (there should be only one  */
      if (streams[i].getFormat() instanceof RGBFormat) {
        camStream = streams[i];
        RGBFormat rgbf = (RGBFormat)streams[i].getFormat();
        converter = new BufferToImage(rgbf);
        break;
      }
    }

    System.out.println("Capture device ready");
  }

  /**
   *  Get an image from the camera
   *
   * @returns The current image from the camera
   * @throws FrameGrabberException If there is a problem
   **/
  public Image getImage() throws FrameGrabberException {
    Buffer b = new Buffer();

    try {
      camStream.read(b);
    } catch (IOException ioe) {
      throw new FrameGrabberException("Unable to capture frame from camera");
    }

    Image i = converter.createImage(b);
    return i;
  }

  /**
   *  Method called when a controller event is received (implements
   *  ControllerListener interface)
   *
   * @param ce The controller event
   **/
  public void controllerUpdate(ControllerEvent ce) {
    if (ce instanceof RealizeCompleteEvent) {
      System.out.println("Realize transition completed");

      synchronized (stateLock) {
        stateLock.notifyAll();
      }
    }
  }
}
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 

Author Comment

by:holobyted
ID: 12129453
FrameGrabber.java:54: cannot resolve symbol
symbol  : class FrameGrabberException
location: class jmfdemo.FrameGrabber
  public FrameGrabber() throws FrameGrabberException {

Weird...
0
 
LVL 92

Expert Comment

by:objects
ID: 12129475
yes that was also in the zip, but it's just a simple exception subclass.
You should be able to replace FrameGrabberException with Exception or create your own subclass.
0
 

Author Comment

by:holobyted
ID: 12129485
Where am I supposed to get all the jmfdemo/ files?
0
 

Author Comment

by:holobyted
ID: 12129936
I'm testing my last resort here.. but, I was wondering if you could tell me. I'm using this code atm, for learning purposes:

http://forum.java.sun.com/thread.jsp?forum=28&thread=452747

Where can I modify the video frames? Ie, not snapshots.. the live video frames.

If you can help me w/ that, I swear I'll give you your points and I'll leave you alone. :p
0
 
LVL 92

Expert Comment

by:objects
ID: 12129954
what do you consider the difference between a videa frame and a snapshot?
0
 

Author Comment

by:holobyted
ID: 12130068
Well, a snapshot won't change... download that code, test it. You'll see what I mean.
I want to be able to modify the video frames (instead of the still image) on the fly, before they get sent to the GUI.
0
 
LVL 92

Expert Comment

by:objects
ID: 12130083
aren't you going to need to take a snapshot to achieve that?
0
 

Author Comment

by:holobyted
ID: 12130103
You're the guru, you tell me. :p

If so, how would I go on about taking a snapshot every second and adding it to GUI?
0
 
LVL 92

Expert Comment

by:objects
ID: 12130126
0
 

Author Comment

by:holobyted
ID: 12130149
That's a servlet though...
0
 
LVL 92

Expert Comment

by:objects
ID: 12130158
same principle apply regardless of how it's used.
0
 

Author Comment

by:holobyted
ID: 12130194
Okay... I guess I'm gonna close this thread now, before we slashdot EE.C. Any chance we talk through e-mails?
0
 
LVL 92

Expert Comment

by:objects
ID: 12130213
feel free, but if i'm busy I may not always answer.
0
 

Author Comment

by:holobyted
ID: 12130232
Send me an e-mail so I can know what it is... holobytedSILLYBOTS<at>cuernaonline<dot>com. Remove the obvious bit
0

Featured Post

Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

Join & Write a Comment

Suggested Solutions

For customizing the look of your lightweight component and making it look lucid like it was made of glass. Or: how to make your component more Apple-ish ;) This tip assumes your component to be of rectangular shape and completely opaque. (COD…
An old method to applying the Singleton pattern in your Java code is to check if a static instance, defined in the same class that needs to be instantiated once and only once, is null and then create a new instance; otherwise, the pre-existing insta…
The viewer will learn how to implement Singleton Design Pattern in Java.
This tutorial covers a practical example of lazy loading technique and early loading technique in a Singleton Design Pattern.

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now