Monday, May 18, 2015

Using the leJOS-0.9 video library

The following program illustrates how one might use the LeJOS-0.9 webcam library in conjunction with the lambda feature from Java 8:

package edu.hendrix.demo;

import java.io.IOException;
import java.util.function.Consumer;

import lejos.hardware.BrickFinder;
import lejos.hardware.Button;
import lejos.hardware.lcd.GraphicsLCD;
import lejos.hardware.video.Video;
import lejos.hardware.video.YUYVImage;

public class FilteredCameraDemo {
  private Consumer<YUYVimage> imgConsumer;
 
  public FilteredCameraDemo(Consumer<YUYVimage> filterer) {
    imgConsumer = filterer;
  }

  public void run() {
    try {
      Video wc = BrickFinder.getDefault().getVideo();
      wc.open(160,120);
      byte[] frame = wc.createFrame();
      YUYVImage img = 
        new YUYVImage(frame, wc.getWidth(), wc.getHeight());
      while (!Button.ESCAPE.isDown()) {
        wc.grabFrame(frame);
        imgConsumer.accept(img);
      }
      wc.close();
    } catch (IOException ioe) {
      ioe.printStackTrace();
      System.out.println("Driver exception: " + ioe.getMessage());
    }
  }
 
  public static void main(String[] args) {
    GraphicsLCD g = BrickFinder.getDefault().getGraphicsLCD();
    new FilteredCameraDemo
      (img -> img.display(g, 0, 0, img.getMeanY())).run();
  }
}

To allow flexibility of implementation, the YUYVImage class is essentially a wrapper around a byte array.  So every time we grab a frame from the webcam, we dump the bytes into a byte array that, in turn, we access via a YUYVImage that maintains a reference to it.  This YUYVImage class has methods that decode the byte layout according to the YUYV standard.

We have a private data member belonging to the Consumer interface. Consumer objects have an accept() method that takes a parameter (corresponding to the parameterized type) and does not return anything.  We make use of this within the run() method's while loop.  In this case, the type parameter is a YUYVImage object.

Now, when we invoke the constructor, we can write a lambda expression to describe the desired computation.  For this example, we just display the image.  Note that the LCD screen is referenced from outside the scope of the lambda.  This still works after it has gone out of scope, as Java 8's lambda expressions are closures.  You can write code to do arbitrary things when seeing an image, just by calling the FilteredCameraDemo constructor with a different lambda parameter.

I plan to write a more elaborate example in a future blog post, but this should suffice to demonstrate the concept.  Happy coding!

No comments:

Post a Comment