«

»

May 31

Porting Rob Hess's SIFT impl. to Java

beavers_siftThis is a Java port of Rob Hess' implementation of SIFT that I did for a project @ work.

However, I couldn't port the actual extraction of SIFT descriptors from images as it relies very heavily on OpenCV. So actually all that I ported to native Java is the KD-Tree features matching part, and the rest is in JNI calls to Rob's code.

I wrote this more as a tutorial to Rob's work, with an easy JNI interface to Java.

You can find the sources here: http://www.morethantechnical.com/extupload/code/JavaSIFT.zip

Here's how to use it:

First, you need to compile Rob Hess' code with the JNI extension provided in the ZIP archive (sift_SIFTTester.c & h). This is actually very easy, as Rob provided a MS Studio sln & vcproj files, so you can just open the project, add the files and compile right away. Just make sure you set the output type to DLL, and save the file to a known location.

After that you just need to see that you point Java in the direction of the DLL in SIFTTester.java. I set to load the DLLs in a static section.


static {
try {
//OpenCV DLLs
Runtime.getRuntime().load("D:/PROGRA~1/OpenCV/bin/cv100.dll");
Runtime.getRuntime().load("D:/Program Files/OpenCV/bin/cvaux100.dll");
Runtime.getRuntime().load("D:/Program Files/OpenCV/bin/cxcore100.dll");
Runtime.getRuntime().load("D:/Program Files/OpenCV/bin/highgui100.dll");

//DLL you compiled yourself with the JNI extension
Runtime.getRuntime().load("C:/downloads/sift-1.1.1_20090108_win/match/Debug/match.dll");
} catch (UnsatisfiedLinkError e) {
e.printStackTrace();
}
}

The SIFTTester will save two files containing the SIFT features, that look something like this:


237 128
177.991610 197.747542 100.355503 2.912007
0 0 0 0 3 1 0 0 23 6 0 0 30 16 0 1 45 16 0 0
1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 53 7 0 0
138 32 0 6 173 173 10 26 173 91 0 0 29 27 8 74 1 0 0 0
0 0 0 0 0 0 0 0 8 3 0 0 36 1 0 2 145 173 74 59
173 4 0 0 10 55 50 173 3 0 0 0 0 0 0 2 0 0 0 0
0 0 0 0 0 0 0 0 0 8 1 0 0 0 0 0 0 1 0 0

0 0 0 0 0 0 0 0

...

Though you don't have to worry about them, the program loads and parses them. This is another portion ported right from Rob's code (import features).

The output should state how many matches were found between the 2 feature sets.

Note:

  • Performance wise - this is kind of an ass-backwards way to work, since I'm exporting the features to a text file and then loading them back. BUT - it is far more complicated to work with OpenCVs sequence data structures, or porting it to Java. You are welcome to extend the code and do a more tight integration of Rob's code to Java.

Next I will try to share some thoughts about image registration (finding transform from one image to another), with OpenCV.

A few words about portingĀ  from C to Java

I could not find any decent porters from C to Java, so I did the process manually. I came to realize that static code porting (by "static" I mean porting the code line-for-line from the .c file), is really very simple. Especially for syntactically similar languages like Java and C. There are simply just a few find-replace operations like: malloc -> new, printf -> System.out.println, !object -> object == null, etc. And the clean-up work is fairly simple.

The problems begin when C programmers start abusing pointers. That's where your skills as a programmer kick-in, and you need to be a sharp C programmer to understand where all the "*(objectPtr + 12)" actually point... But all in all, it's no big deal.

Enjoy!

Roy.

Share
  • sameera manuranga

    I,m really glad of your implementation.It's really helpful.

  • danni31

    hello;
    I fail to execute your implementation java if you can explain to me in detail how.
    thank you

  • varun

    Hey Roy,

    I keep getting an UnsatisfiedLinkError when I try to run your program.
    Can you let me know what could be the reason?

    Thanks a lot.

    Exception in thread "main" java.lang.UnsatisfiedLinkError: sift.SIFTTester.saveSIFT(Ljava/lang/String;[BIIII)I
    at sift.SIFTTester.saveSIFT(Native Method)
    at sift.SIFTTester.main(SIFTTester.java:75)