Skip to content

Example: SimpleModule

rstauffe edited this page Jun 13, 2013 · 6 revisions

This example demonstrates the following aspects of the Interface SDK:

  • The ability to create Processing modules.
  • Communication with the HardwareManager to provide hand tracking functionality
  • Receiving events through the abstract layer of receivers.

This example may also be found in the /examples/modules/ folder in the git repository. (Not done)

package edu.mines.examples.modules.SimpleModule;

import java.awt.image.BufferedImage;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import processing.core.PApplet;
import processing.core.PConstants;
import processing.core.PImage;
import edu.mines.acmX.exhibit.stdlib.input_processing.receivers.HandReceiver;
import edu.mines.acmX.exhibit.input_services.hardware.BadFunctionalityRequestException;
import edu.mines.acmX.exhibit.input_services.hardware.UnknownDriverRequest;
import edu.mines.acmX.exhibit.input_services.hardware.HardwareManager;
import edu.mines.acmX.exhibit.input_services.hardware.HardwareManagerManifestException;
import edu.mines.acmX.exhibit.input_services.hardware.devicedata.HandTrackerInterface;
import edu.mines.acmX.exhibit.input_services.hardware.devicedata.RGBImageInterface;
import edu.mines.acmX.exhibit.module_management.modules.ProcessingModule;
import edu.mines.acmX.exhibit.stdlib.graphics.Coordinate3D;
import edu.mines.acmX.exhibit.stdlib.graphics.HandPosition;
import edu.mines.acmX.exhibit.stdlib.input_processing.imaging.RGBImageUtilities;

/**
 * A simple module example to demonstrate communicating with the
 * HardwareManager all managing received events within a ProcessingModule
 *   
 * @author Aakash Shah
 * 
 * @see {@link HardwareManager} {@link ProcessingModule}
 */
public class SimpleModule extends ProcessingModule {
	
	public static HardwareManager hm;
	
	private RGBImageInterface imageDriver;
	private HandTrackerInterface handDriver;
	private MyHandReceiver receiver;
	
	/*
	 * A processing module inherits the paradigms of a Processing applet. Here,
	 * we implement the setup method that acts as an entry point for our module.
	 * As such, we initialize a lot of our member variables and register for
	 * events here.
	 */
	public void setup() {
		/*
		 * The hardware manager is a singleton that forms a bridge to
		 * retrieve and communicate with drivers supported (as specified in the
		 * HardwareManager manifest file). 
		 * 
		 * The actual creation of the manager
		 * involves loading and verifying the integrity of the manifest file,
		 * as well as ensuring that a device is connected so that we may
		 * actually obtain information from it.
		 */
		try {
			hm = HardwareManager.getInstance();
		} catch (HardwareManagerManifestException e) {
			System.out.println("Error in the HardwareManager manifest file.");
			e.printStackTrace();
		} 
		
		/*
		 * To actually retrieve the driver, such that we can receive
		 * information, requires requesting it from our instance of the
		 * HardwareManager.
		 * 
		 * In this case, we want to set the size to be the same as the rgbimage
		 * we are going to receive from the driver.
		 */
		try {
			imageDriver = (RGBImageInterface) hm.getInitialDriver("rgbimage");
			size(imageDriver.getRGBImageWidth(), imageDriver.getRGBImageHeight());
			handDriver = (HandTrackerInterface) hm.getInitialDriver("handtracking");
		} catch (BadFunctionalityRequestException | InvalidConfigurationFileException e) {
			System.out.println("Functionality unknown (may not be supported)");
			e.printStackTrace();
		} catch (UnknownDriverRequest e) {
			System.out.println("Attempted to load unknown driver");
			e.printStackTrace();
		}
		
		/*
		 * This creates a "MyHandReceiver" instance that acts a layer of
		 * abstraction towards dealing with data received by the event manager.
		 */
		receiver = new MyHandReceiver();
		/*
		 * Since hand tracking takes an event-based approach towards delivering
		 * information, we should register our receiver with the EventManager.
		 * In this case, this is done through the driver. However, we can also
		 * do it alternatively with:
		 * 
		 * EventManager.getInstance().registerReceiver(EventType.HAND_CREATED, receiver);
		 */
		handDriver.registerHandCreated(receiver);
		handDriver.registerHandUpdated(receiver);
		handDriver.registerHandDestroyed(receiver);		
		
	}
	
	public void draw() {
		/*
		 * For some hand tracking drivers, it may be necessary to allow it to 
		 * refresh information before re-polling for new data. 
		 */
		handDriver.updateDriver();
		
		/*
		 * The RGBImageInterface provides getVisualData() as a method to
		 * retrieve the raw data from a driver that supports the "rgbimage"
		 * functionality.
		 * 
		 * Here we grab this ByteBuffer, convert it into a BufferedImage, and
		 * then finally into a PImage (Processing's form of an image) so that
		 * we may display it on the screeen.
		 */
		ByteBuffer rawRGBImageData = imageDriver.getVisualData();
		BufferedImage bImg = RGBImageUtilities.byteBufferToImage(
				rawRGBImageData,
				imageDriver.getRGBImageWidth(),
				imageDriver.getRGBImageHeight());
		PImage pImg = buffImageToPImage(bImg);
		image(pImg, 0, 0);
		
		noFill();
		stroke(255, 0, 0);
		/*
		 * To actually display a circle indicated the latest position for a
		 * hand, we must first ask our receiver (which in our example is
		 * keeping track of each hand's latest position) for the hand IDs that
		 * it is tracking.
		 * 
		 * Scroll down to read more about this example's receiver object.
		 */
		for (int id : receiver.getHandIDs()) {
			/*
			 * We grab the latest position and draw a red circle which will
			 * follow the hand. Keep in the mind that we are retrieving a
			 * Coordinate3D, so that should we want to incorporate the depth of
			 * the hand into our module, we may do so.
			 */
			Coordinate3D handPosition = receiver.getHandPosition(id);
			ellipse(handPosition.getX(), handPosition.getY(), 20, 20);
		}
	}
	
	/**
	 * A utility function to convert a BufferedImage into a PImage.
	 * @param bimg BufferedImage to convert
	 * @return a PImage
	 */
	public PImage buffImageToPImage(BufferedImage bimg) {
		PImage img = new PImage(bimg.getWidth(), bimg.getHeight(), PConstants.ARGB);
		bimg.getRGB(0, 0, img.width, img.height, img.pixels, 0, img.width);
		return img;
	}
	
	
	/**
	 * This class acts as an extension of the HandReceiver adapter. In this
	 * class, we may override the methods handCreated, handUpdated, and 
	 * handDestroyed to handle the lifecycle of a hand being tracked.
	 * 
	 * In this example, we also include functionality to keep track of a hand's
	 * most recent position.
	 * 
	 * The hand tracking API provides the end-programmer an integer id, and
	 * a Coordinate3D to manage the position of the hand. These two attributes
	 * are wrapped into the class HandPosition which will allow you to grab
	 * this information through getters.
	 * 
	 * @author Aakash Shah
	 */
	class MyHandReceiver extends HandReceiver {
		
		private Map<Integer, Coordinate3D> handPositions;
		
		public MyHandReceiver() {
			handPositions = new HashMap<Integer, Coordinate3D>();
		}
		
		public void handCreated(HandPosition handPos) {
			handPositions.put(handPos.getId(), handPos.getPosition());
		}
		
		public void handUpdated(HandPosition handPos) {
			handPositions.put(handPos.getId(), handPos.getPosition());
		}
		
		public void handDestroyed(int id) {
			handPositions.remove(id);
		}
		
		public Set<Integer> getHandIDs() {
			return handPositions.keySet();
		}
		
		public Coordinate3D getHandPosition(int id) {
			return handPositions.get(id);
		}
	}
}

TODO:

  • Update the package name at the top of the file be changed to match this /examples/ directory structure.
Clone this wiki locally