Updates & Articles

JavaCV on CentOS 6

JavaCV is a “Java interface to OpenCV and more”. OpenCV is the de facto standard of computer vision software enabling facial recognition, motion detection, general object detection to run over images. JavaCV incorporates with other technologies like ffmpeg allowing the same computer vision algorithms to intake videos.

If Java is language of choice, or the JVM, Java Bindings are used to interact with c/c++ libraries like OpenCV and ffmpeg. JavaCV provides all the jars pre-built including a jar that contains .so files, shared object files, for the various platforms, Mac, Linux and Windows. The intention is to not require a system level install of the OpenCV libraries.

CentOS 6.4 was unable to find the shared object files. JavaCV loaded the .so files from the provided jar and dynamically made the jnilib*.so files. Unfortunately the libc version provided with CentOS 6.4 is below the version the provided .so files were built for and the linking operation failed.

To see what version of libc is installed, ldd --version. In this case 2.12 and the stack traces looked like this:

Exception in thread "main" java.lang.UnsatisfiedLinkError: no jniopencv_objdetect in java.library.path
        at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1681)
        at java.lang.Runtime.loadLibrary0(Runtime.java:840)
        at java.lang.System.loadLibrary(System.java:1047)
        at com.googlecode.javacpp.Loader.loadLibrary(Loader.java:701)
        at com.googlecode.javacpp.Loader.load(Loader.java:578)
        at com.googlecode.javacpp.Loader.load(Loader.java:532)
        at com.googlecode.javacv.cpp.opencv_objdetect.<clinit>(opencv_objdetect.java:91)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:266)
        at com.googlecode.javacpp.Loader.load(Loader.java:553)
        at Smoother.main(Smoother.java:6)
Caused by: java.lang.UnsatisfiedLinkError: /tmp/javacpp8883169523366/libjniopencv_objdetect.so: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by /tmp/javacpp8883169523366/libjniopencv_objdetect.so)
        at java.lang.ClassLoader$NativeLibrary.load(Native Method)
        at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1750)
        at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1646)
        at java.lang.Runtime.load0(Runtime.java:787)
        at java.lang.System.load(System.java:1022)
        at com.googlecode.javacpp.Loader.loadLibrary(Loader.java:690)

Try out the provided demo on CentOS 6.4

git clone https://github.com/imintel/javacv-on-centos-6.git && cd javacv-on-centos-6/demo
javac -cp javacv-linux-x86_64.jar:javacpp.jar:javacv.jar Smoother.java
java -cp javacv-linux-x86_64.jar:javacpp.jar:javacv.jar Smoother

This produces a similar stack trace from above.

To fix these errors, compile javacv-linux-x86_64.jar and OpenCV libraries on CentOS 6.4.

###Building OpenCV

Ensure JAVA_HOME defined. Something like /usr/lib/jvm/java

  1. Install system packages

         sudo yum groupinstall "Development Tools"
         sudo yum install cmake
         sudo yum install ant
    
  2. Clone the OpenCV repository

          git clone https://github.com/Itseez/opencv.git && cd opencv
    
  3. Checkout desired release

          git checkout 2.4.6.2
    
  4. Make release directory

          mkdir release && cd release
    
  5. Generate make file, make and install

    This takes some time depending on the machine and what 3rd party libraries are built.

          cmake -DBUILD_SHARED_LIBS=ON -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/ ..
          make
          sudo make install
    
  6. Ensure library files exist

          ls /usr/lib/*opencv*
    

###Building JavaCV

  1. Install maven if needed.

  2. Clone the JavaCV repository

         git clone https://code.google.com/p/javacv/ && cd javacv
    
  3. Checkout the latest release tag, 0.6 at this time.

         git checkout 0.6
    
  4. Build the project

         mvn install
    

    In step 3 c++ compiler commands execute and pick up on the libraries built in the “Building OpenCV” step.

  5. Copy the built jar

         cp target/javacv-linux-x86_64.jar PATH_TO_DEMO_REPOSITORY/
    

###Using the jar built from source

Run the same test commands from above

javac -cp javacv-linux-x86_64.jar:javacpp.jar:javacv.jar Smoother.java
java -cp javacv-linux-x86_64.jar:javacpp.jar:javacv.jar Smoother

The correctly linked libjni file path prints.

/tmp/javacpp14551117426304/libjniopencv_objdetect.so

The provided Smoother.java file attempts to load the shared library and print the path. To get started with JavaCV take a look at their cookbook.

You can see the demo files on our Github repo.


D3: Multiple Brushes

One of the useful features D3 offers is a dynamic brush that allows one to select a portion of a scale. If desired, SVG elements within the “brushed” range of the can then be manipulated. For an in-house project, we wanted to select multiple time ranges using brushes.

This great example from D3’s creator made implementing one brush simple (if you haven’t previously implemented a singular brush, you’ll probably want to give the example a look before continuing). However, when we tried to add another brush to the display the brushes weren’t usable, and there didn’t seem to be any D3 documentation about how to achieve the functionality. There also didn’t seem to be any other examples online with more than one brush. Since it was a feature we needed, we experimented. In the end, by making two simple DOM alterations to the brushes, we were able to create multiple brushes on the same scale.

The brush exposes certain events: ‘brushstart’ when it is started, a series of ‘brush’ events while it is being altered, and a ‘brushend’ event when the alterations end (for more on this see the documentation link above). To provide these events, the brush captures mouse events within its active area (the SVG DOM element in which the brush can be drawn, dragged, and resized), processes the mouse events, and outputs them as one of the three events provided by the brush.

This is sufficient for one brush because every click event is captured by the first brush created. Determining whether a user mouse event should create a new brush or alter an existing brush has to be accomplished manually.

Looking at a brush in the DOM, we realized the brush would respond to mouse events if its pointer-events attribute was set to ‘all’. Setting the same attribute to ‘none’ resulted in the brush no longer honoring (and therefore consuming) click events. By adding a simple jQuery click listener to the DOM element that contains the brush, mouse clicks can be examined if the brush isn’t listening to / consuming click events. To make this happen, each time a brush sends a ‘brushend’ event, the brush’s pointer-events attribute is set to none. That means the brush won’t swallow the next click event, and the event will occur in the jQuery click listener for the active region containing the brush. At this point, logic occurs to determine if the user is holding down the meta-key while clicking. If this is the case, a new brush is created and the old brush remains deactivated. If the user is performing a click without the meta-key, the brush’s pointer-events attribute is set back to ‘all’ and it will continue consuming click events and updating its size/location accordingly.

But that wasn’t the last piece of the puzzle. Simply setting the brush’s ‘pointer-events’ attribute didn’t actually have the desired effect of activating and deactivating the brush. It wasn’t until accidentally stumbling across manually assigning the brush an id attribute that the brushes would activate and deactivate accordingly. Since no mention of id is made in the brush documentation, it’s unclear whether this is an intended or unintended feature in the inner workings of the brush.

While this surely isn’t the most elegant solution to implementing multiple brushes, it seems the best until the brush’s functionality is extended.

D3 Multiple Brushes Example


Reinvent Transit Hackathon

Mission Focus is a sponsor for Reinvent Transit, a gathering and “hackathon” that brings together technologists, makers, and creative problem solvers to better all forms of transportation in Baltimore. The event will run from Friday April 5th through Sunday April 7th at Betamore, the recently-opened urban campus for technology and entrepreneurship located in Federal Hill.

Over the weekend, groups of software developers, designers, and citizens will be taking ideas that have been crowdsourced from the local community and building applications and prototypes that help solve some transportation-related problems and address the needs of Baltimore’s bus riders, cyclists, drivers, and pedestrians. After hearing about transit experiences from a panel of speakers on Friday evening, participants will form teams on Saturday morning and will work collaboratively over the next 24 hours on their solutions. By Sunday evening, they’ll compete to win prizes by presenting a demo of what they’ve built to a distinguished panel ranging from city transit officials to venture capitalists. While technology will be a likely tool used over the weekend, creative non-technical solutions are also of interest.