opencv-java: OpenCV 2.4 bindings for Java and Processing

Me and my friend Julián Hernández Muñoz were playing around with image processing from our favorite programming language Java but were sad to find that there wasn’t  (at least at the […]

Me and my friend Julián Hernández Muñoz were playing around with image processing from our favorite programming language Java but were sad to find that there wasn’t  (at least at the time) any good OpenCV bindings into the language (at least not for OpenCV 2.1). So we began to develop our own bindings, including all functions that we needed for our work and thought might be useful for others.

Main Features

  • Runs on OSX 1.5 and up (64-bit) and can easily be made to run on Linux
  • All image buffers in Java are shared with the native libraries. This means no intense copying of data between Java and the native libraries
  • OpenCV binaries are included so no OpenCV installation is required
  • Memory management is done by Java and when the application exits, native resources are released
  • Includes a processing library and .pde examples
  • … more to come

This project now hosted on Google code

https://code.google.com/p/opencv-java/

How to install

Java (Eclipse or similar IDE)

  1. Download the opencv-java.zip below and unzip into your workspace folder (or wherever you store code)
  2. In Eclipse create new Java project and tell it to not use the default new folder but point it to the recently unzipped folder
  3. The New Project wizard should be able to figure the layout of the project out automagically but if not then:
    1. Tell it to use the “src” folder as the source folder
    2. Tell it to output its class files into a folder named “bin” or “build”
    3. Tell it about “opencv-java.jar”, “core.jar” and “controlP5.jar” in the “lib” folder
  4. … and you’re all set

Processing

  1. Download the opencv-java-processing.zip below and unzip into your Processing folder (usually /Users/[username]/Documents/Processing)
  2. In that folder you should now see two new libraries under the “libraries” subfolder and a new subfolder named “examples”
  3. Set up your Processing app to execute your sketch in 64-bit mode (if on OSX)
    1. Open you Processing application and select the menu item Processing -> Preferences
    2. Click on the link to the “preferences.txt” file at the bottom of the dialog and open that file in a textviewer
    3. CLOSE YOUR PROCESSING APPLICATION (very important, otherwise your changes will be overwritten)
    4. Search for a line that says “run.options=” and add the string “-d64” at the end of it so that it looks like this: “run.options=-d64” or “run.options=something_that_was_here_already -d64”
    5. Now re-open the Processing application and run any of the example sketches

How to use

There are examples for most of the functionality we included and these should be fairly self-explanatory. These examples use the Processing and the P5 GUI library to visualize the results but the underlying functionality of our bindings do not rely on those libraries in any other way.

JavaDocs are included in the download and can also be accessed here:
http://siggiorn.com/wp-content/uploads/libraries/opencv-java/docs

A list of the OpenCV functions we implemented can be found here:
http://siggiorn.com/wp-content/uploads/libraries/opencv-java/docs/sj/opencv/OpenCV.html

 

Processing Example

import controlP5.*;
import sj.opencv.*;
import sj.opencv.Constants.*;
import controlP5.*;
 
int w = 320;
int h = 240;
 
IplImage im;
IplImage im_gray;
IplImage im_dst;
Capture capture;
 
CompareMode type = CompareMode.values()[0];
int toggle_cnt = 0;
 
void setup(){
	size(3*w, h);
 
	// Camera initiated to capture from device
	capture = OpenCV.captureFromCAM(0);
 
	im = OpenCV.allocateIplImage(w, h, PixelDepth.IPL_DEPTH_8U, ColorModel.BGR);
	im_gray = OpenCV.allocateIplImage(w, h, PixelDepth.IPL_DEPTH_8U, ColorModel.GRAY);
	im_dst = OpenCV.allocateIplImage(w, h, PixelDepth.IPL_DEPTH_8U, ColorModel.GRAY);
 
	System.out.println("Move mouse across width to change compare value");
	System.out.println("Press 't' to toggle compare mode");
}
 
void draw(){
	// When a frame becomes available
	if( OpenCV.queryFrame(capture, im) ){
		// Draw it
		image(PUtils.getPImage(im), 0, 0);
 
		// Change to 1 channel
		OpenCV.cvtColor(im, im_gray);
		image(PUtils.getPImage(im_gray), w, 0);
 
		OpenCV.cmpS(im_gray, 255*mouseX/width, im_dst, type);
		image(PUtils.getPImage(im_dst), 2*w, 0);
	}
}
 
void keyPressed(){
	if( key == 't' ){
		type = CompareMode.values()[(toggle_cnt++)%CompareMode.values().length];
		System.out.println("Switched to: "+type);
	}
}

Java Example

import controlP5.*;
import sj.opencv.*;
import sj.opencv.Constants.ColorModel;
import sj.opencv.Constants.PixelDepth;
import processing.core.*;
 
/**
 * @author siggi
 * @date Jul 29, 2010
 */
public class SubtractionExample extends PApplet{
 
	int w = 320;
	int h = 240;
 
	IplImage im;
	IplImage im_sub;
	IplImage im_background = null;
	Capture capture;
 
	Slider sub_slider;
 
	@Override
	public void setup(){
		size(4*w, 2*h+150);
 
		// Camera initiated to capture from device
		capture = OpenCV.captureFromCAM(0);
 
		im = OpenCV.allocateIplImage(w, h, PixelDepth.IPL_DEPTH_8U, ColorModel.BGR);
		im_sub = OpenCV.allocateIplImage(w, h, PixelDepth.IPL_DEPTH_8U, ColorModel.BGR);
 
		// Init GUI
		ControlP5 controlP5 = new ControlP5(this);
		sub_slider = controlP5.addSlider("sub_val", 0, 255, 100, 20, 2*h+20, 10, 100);
 
		System.err.println("Press b to capture the background");
	}
 
	@Override
	public void draw(){
		// When a frame becomes available
		if( OpenCV.queryFrame(capture, im) ){
			background(70);
 
			// Draw it
			image(Utils.getPImage(im), 0, 0);
 
			// Grab a scalar value from a gui object
			Scalar scalar = new Scalar(sub_slider.value());
 
			// Calculate an absolute difference between cam image and the scalar value
			OpenCV.absDiffS(im, im_sub, scalar);
			image(Utils.getPImage(im_sub), w, 0);
 
			// Calculate an difference between cam image and the scalar value
			OpenCV.subS(im, scalar, im_sub, null);
			image(Utils.getPImage(im_sub), 2*w, 0);
 
			// Calculate the opposite difference between cam image and the scalar value
			OpenCV.subRS(im, scalar, im_sub, null);
			image(Utils.getPImage(im_sub), 3*w, 0);
 
			// Subtract background image from the cam image if it has been captured
			if( im_background != null ){
				image(Utils.getPImage(im_background), 0, h);
 
				OpenCV.absDiff(im, im_background, im_sub);
				image(Utils.getPImage(im_sub), 1*w, h);
 
				OpenCV.sub(im, im_background, im_sub, null);
				image(Utils.getPImage(im_sub), 2*w, h);
 
				OpenCV.sub(im_background, im, im_sub, null);
				image(Utils.getPImage(im_sub), 3*w, h);
			}
			else{
				text("Press b to capture background", 100, h+50);
			}
		}
	}
 
	@Override
	public void keyPressed(){
		if( key == 'b' ){
			// Capture background image when button is pressed
			im_background = OpenCV.cloneImage(im);
		}
	}
}

About Siggi