It’s Oh So Quiet…

Five months and no blog posts? Aiya!

I’ve been extremely busy through the first half of 2011, mostly because my wife and I are expecting our first baby (only a few weeks to go), and most of my free time has been spent getting our house in order, doing baby shopping and doing my part to support as best I can.

Work has also been very hectic with a lot going on. What little time I’ve had to work on personal projects, was spent implementing the new search features at onmydoorstep.com.au, doing the initial Wicket 1.5 branch for visural-wicket and learning a bit about Android development.

I do have some blog posts sorted out though for the coming months. Mostly they’re not going to be long form in-depth posts, but there are a few things I’ve learned or been working on lately that I’d like to post about, but haven’t had a chance to write up before now.

Of course, once our son arrives in a few weeks, who knows what could happen! :)

Posted in General | Leave a comment

Use Hudson (now Jenkins) to restart a Windows service…

Here’s a quick tip – you can easily make Hudson restart a windows service, by using its “Windows Batch Command” build step in combination with the command line windows “net” command.

Here’s an example of how we can get Hudson to restart Apache running on the same host -

  1. Create a new Job, say “Restart Apache” as a standard Hudson job.
  2. Add a new “Windows batch command” step, and in the box enter -
    net stop Apache2
  3. Add another new “Windows batch command” step, and in the box enter -
    net start Apache2
  4. Run the job, and behold!

This is handy if you’re automating deployments usnig Hudson on Windows hosts. Particularly if you’re trying to avoid PermGen issues with hot-redeployments on say, Apache Tomcat.

Posted in Java, Software Engineering | Tagged automation, ci, Java, releases, windows | Leave a comment

Face Detection in Java – Haar Cascade with JJIL (how-to)

A requirement came up on a recent project to automatically crop displayed profile images of people to just the “face” area for a thumbnail.

This seems like a job for a face detection algorithm. Searching for appropriate open-source Java implementations didn’t yield too many results, however I was successful with JJILJon’s Java Imaging Library, which is open sourced under the LGPL licence.

JJIL is targeted at Java ME / Android platforms and doesn’t have much documentation or a particularly intuitive API (not complaining, as clearly some stellar work has gone into it, kudos to Jon Webb, it’s creator).

In the end I muddled through, detecting faces in an image in a standard Java project, but given it took me a while to get everything working, I thought I’d write a quick guide to help out others that are trying to achieve similar results.

Getting the Right JARs

First things first, I had trouble getting the published JAR files to work happily together. There seems to be some sort of version mismatch issue between the core and J2SE versions.

So I built my own copy – you can download it here – JJIL-visural-build-20110112.zip

This is a build of the current trunk JJIL code, and the Java SE additions (jjil-j2se).

This build is guaranteed to work with the code examples below.

Basic Process

I’m going to try to explain the basic process of detecting the faces in terms of input and output data.

The key file provided by JJIL for easy face (and other body part) detection is Gray8DetectHaarMultiScale.java

This operation is applied to an 8-bit greyscale input image, in combination with a pre-defined Haar Cascade profile. The profile determines which areas of the image are “detected”. So you would want (for example) a profile to detect the frontal face features. JJIL provides several profiles out of the box.

The output image is a mask of the area of image where faces are detected (white) and the areas where no face was detected (black). This isn’t tremendously useful, as we’d usually rather just have the rectangular areas in coordinate form – I’ll address this later, after walking through the process.

1. Read an image from disk (.JPG, etc.)

2. Convert it into a jjil.core.Image

3. Generally we’ll have an RGB image (colored image) and so need to convert it to 8-bit greyscale, which is what the Gray8DetectHaarMultiScale class requires.

4. Create a new instance of Gray8DetectHaarMultiScale with the Haar profile for detecting faces (or other body part if that’s what you’re looking for).

5. Apply Gray8DetectHaarMultiScale to our 8-bit grey image.

6. Retrieve result from Gray8DetectHaarMultiScale.

Resulting Haar mask for test image for face detection

The figure below shows, the source image, overlayed with the resulting mask, from step #6

So as you can see, the masks correctly identify the faces the two people in the image.

The Code

Here’s a small Java class that demonstrates how to read an image and apply the process described above.

Note: all the code in the article can be downloaded as a full project at the end of the article.

package jjilexample;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.InputStream;
import javax.imageio.ImageIO;
import jjil.algorithm.Gray8Rgb;
import jjil.algorithm.RgbAvgGray;
import jjil.core.Image;
import jjil.core.RgbImage;
import jjil.j2se.RgbImageJ2se;
import jjil.algorithm.Gray8DetectHaarMultiScale;

public class Main {
    public static void findFaces(BufferedImage bi, int minScale, int maxScale, File output) {
        try {
            // step #2 - convert BufferedImage to JJIL Image
            RgbImage im = RgbImageJ2se.toRgbImage(bi);
            // step #3 - convert image to greyscale 8-bits
            RgbAvgGray toGray = new RgbAvgGray();
            toGray.push(im);
            // step #4 - initialise face detector with correct Haar profile
            InputStream is  = Main.class.getResourceAsStream("/jjilexample/haar/HCSB.txt");
            Gray8DetectHaarMultiScale detectHaar = new Gray8DetectHaarMultiScale(is, minScale, maxScale);
            // step #5 - apply face detector to grayscale image
            detectHaar.push(toGray.getFront());
            // step #6 - retrieve resulting face detection mask
            Image i = detectHaar.getFront();
            // finally convert back to RGB image to write out to .jpg file
            Gray8Rgb g2rgb = new Gray8Rgb();
            g2rgb.push(i);
            RgbImageJ2se conv = new RgbImageJ2se();
            conv.toFile((RgbImage)g2rgb.getFront(), output.getCanonicalPath());
        } catch (Throwable e) {
            throw new IllegalStateException(e);
        }
    }

    public static void main(String[] args) throws Exception {
        // step #1 - read source image
        BufferedImage bi = ImageIO.read(Main.class.getResourceAsStream("test.jpg"));
        // onto following steps...
        findFaces(bi, 1, 40, new File("c:/Temp/result.jpg")); // change as needed
    }
}

Getting Face Rectangles Instead

It would be more useful in many cases, to get a collection of Rectangles, in coordinate form, instead of an image mask.

There is a version of DetectHaarMultiScale in the JJIL project SVN, which implements a “getRectangles” method to retrieve this data. Unfortunately the source in incompatible with the rest of the library in SVN, so it may be WIP or an abandoned version of the code.

To get around this, I created my own version of Gray8DetectHaarMultiScale, which you can download here – Gray8DetectHaarMultiScale

Here are the important changes below -

    public void push(Image image)  throws jjil.core.Error {
        pushAndReturn(image);
    }

    public List pushAndReturn(Image image) throws jjil.core.Error
    {
        List result = new ArrayList();
....
                    if (hcc.eval(imSub)) {
                        // Found something.
                        nxLastFound = imSub.getXOffset();
                        nyLastFound = imSub.getYOffset();
                        // assign Byte.MAX_VALUE to the feature area so we don't
                        // search it again
                        result.add(new Rect(nxLastFound*nScale, nyLastFound*nScale,
                                this.hcc.getWidth()*nScale,
                                this.hcc.getHeight()*nScale));

                        Gray8Rect gr = new Gray8Rect(nxLastFound,
                                nyLastFound,
                                this.hcc.getWidth(),
                                this.hcc.getHeight(),
                                Byte.MAX_VALUE);
                        gr.push(imMask);
                        imMask = (Gray8Image) gr.getFront();
                     }
....
        return result;
    }

So now we can call “pushAndReturn(…)” instead of just push() to apply the process to our image, and get a List back of the detected faces. Perfect!

Using this here is a version of the example code above which prints out the rectangles where faces were detected -

package jjilexample;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.InputStream;
import java.util.List;
import javax.imageio.ImageIO;
import jjil.algorithm.Gray8Rgb;
import jjil.algorithm.RgbAvgGray;
import jjil.core.Image;
import jjil.core.Rect;
import jjil.core.RgbImage;
import jjil.j2se.RgbImageJ2se;

public class Main {

    public static void findFaces(BufferedImage bi, int minScale, int maxScale, File output) {
        try {
            InputStream is  = Main.class.getResourceAsStream("/jjilexample/haar/HCSB.txt");
            Gray8DetectHaarMultiScale detectHaar = new Gray8DetectHaarMultiScale(is, minScale, maxScale);
            RgbImage im = RgbImageJ2se.toRgbImage(bi);
            RgbAvgGray toGray = new RgbAvgGray();
            toGray.push(im);
            List results = detectHaar.pushAndReturn(toGray.getFront());
            System.out.println("Found "+results.size()+" faces");
            Image i = detectHaar.getFront();
            Gray8Rgb g2rgb = new Gray8Rgb();
            g2rgb.push(i);
            RgbImageJ2se conv = new RgbImageJ2se();
            conv.toFile((RgbImage)g2rgb.getFront(), output.getCanonicalPath());
        } catch (Throwable e) {
            throw new IllegalStateException(e);
        }
    }

    public static void main(String[] args) throws Exception {
        BufferedImage bi = ImageIO.read(Main.class.getResourceAsStream("test.jpg"));
        findFaces(bi, 1, 40, new File("c:/Temp/result.jpg")); // change as needed
    }

}

If you run this, you will note that it actually detects 3 faces in the image. This is common, as the way the Haar algorithm works, is by resizing the image to different scales and running a fixed size matrix over the image. It is possible for the same face to be detected at different scales and so you end up with rectangles within rectangles. It is a pretty trivial matter to remove these “extra” rectangles though by just checking if they are fully contained by another and ignoring them accordingly.

Download the Project

To save you some time, here’s the full example as a Netbeans project that you can download and run, play with, etc. Have fun!

JJILExample

Photo used in this article courtesy of Gill Penny.

Posted in Java, Software Engineering | Tagged guides, images, Java, open-source, ui | 26 Comments

Looking back on 2010…

Each year I try to look back over my year and take stock of what I’ve spent my time on, what I’d like to improve on, things I’d like to do more, or do less.

This year was a very busy year for me. February saw the initial release of my open source projects, visural-common and visural-wicket, with two subsequent releases during the year. The visural-wicket library was much more successful that I had guessed and has been downloaded by hundreds of developers of the course of the year.

The rest of the first half of the year were a combination of juggling work, personal life and building onmydoorstep.com.au. Ultimately I was not successful in the AppMyState competition that I entered in to, but I continued to work on the site throughout the year with many of the features that I had planned initially finally making their way into the site over the following months.

Depsite not fulfilling its intended purpose, building On My Doorstep was a fantastic experience for me, and expanded my skills greatly, particularly in the areas of CSS, SEO, UI design and server administration. Having work mainly on internally hosted apps in the past, this site was a crash course in startup-dom which has been invaluable.

I dabbled in a little Python this year, having felt like I’ve “run my course” with Java recently. I like Python, but I don’t think I’m ready to switch over as yet. I think I’d like to dabble with a little Scala and Ruby first, before undertaking any “proper” project with a new language.

One thing that I felt consistently over the past year, is that I’ve been spreading myself too thin. I need to spend less time writing code, and try some new things in life.

This is reflected in my goals for 2011 below -

  • Get “On My Doorstep” to a “parkable” state.
    By parkable, I don’t mean to abandon the project, but simply finish off the work in progress stuff and put it into “maintenance” for the time being.
  • Write a novel.
    This will be a new and much needed creative experience. I went from working on animated films in 2006 to working two jobs and cutting code 7 days a week. It’s time I put my creative energies in a less work-oriented direction.
  • Dropping 10kgs.
    Over the past 4 years I’ve slowly gained around 10 kgs in weight. This is since I dropped roughly 25 kgs between 2005/2006, dropping from 105kgs to 80kgs. This time it’s been mainly caused by too much good food, as opposed to bad food, and also excessive hours working with not enough exercise. My plan is to decrease the amount of food I eat (particularly carbs), but also try to schedule in some sustainable exercise.

I’ve kept it to three, as I feel it’s not realistic to have more than that at a time.

That’s not to say everything else falls by the way-side, I expect to make another few releases of visural-wicket during the year, and other random projects. I will keep making new blog posts, but maybe not quite as frequently as I have this year (at one stage I was managing 1-2 posts per week).

Some things I’m looking forward to -

  • spending more time with my family
  • getting through my bluray home-theatre backlog
  • Dragon Age 2 (hope they don’t screw it up, I’m being optimistic!)
  • Mass Effect 3 (hope it makes it for 2011)
  • Diablo 3 (I might be disappointed – 2012?)

Anyway, here’s to a new year! I hope everyone has a good one, and finds it to be bigger, better and more enjoyable than the last.

Posted in General, Software Engineering | Tagged off-topic, soap-box, visural-common, visural-wicket | Leave a comment