My solution: Create a proxy class.
That is, create a C++ class, which accesses the C/C++ functions in the main code which uses the OpenCV data types/objects and/or functions. So it looks like this: C++ class --> main C/C++ code --> OpenCV data types/objects and/or functions. Only the class will be wrapped, so SWIG does not have to deal with the OpenCV data types/objects and functions.
So in the class, I include the main C/C++ code using: #include "...", and for the class' methods, just access the main C/C++ code's functions statically (i.e. directly call the functions). For example:
My main C/C++ code:
/*
* File name: main_capture.cpp
* This program will do a live feed from a webcam and display it, until the ESC key is pressed
*/
#include "cv.h"
#include "highgui.h"
int initate_capture() {
IplImage* frame; // OpenCV data type for images
CvCapture* capture; // OpenCV object for camera capture
// Initialize capture from camera
capture = cvCreateCameraCapture( -1 ); // "-1" -> capture from any detected camera
// If there is no camera connected/detected...
if ( !capture ) {
fprintf( stderr, "ERROR, capture is NULL\n "); // ... show error ...
cvWaitKey(0); // ... wait for any key to be pressed ...
return -1; // ... and quit the program.
}
// If capture is successful, create a window named "Capture" to display the captured image
cvNamedWindow( "Capture", CV_WINDOW_AUTOSIZE );
// Create loop...
while (1) {
frame = cvQueryFrame( capture ); // Capture from camera...
cvShowImage( "Captue", frame ); // Show captured image in the window "Capture"
if ( (cvWaitKey(10) & 255 ) == 27 ) break; // Exit loop when ESC is pressed
}
// Clear some used memory before quitting the program
cvReleaseCapture( &capture );
cvDestroyWindow( "Capture" );
return 0;
}
// End of main_capture.cpp
My C++ proxy class:
/*
* File name: main_capture_class.cc
*/
#ifndef main_capture_class
#define main_capture_class
#include "main_capture.cpp" // Include the main C/C++ program
using std namespace;
class Capture {
// Declare the class methods
public:
void do_capture(); // This one is public
};
void Capture::do_capture() {
initiate_capture(); // Calls the function "initiate_capture()" in main_capture.cpp
}
#endif
// End of main_capture_class.cc
If you want to test if the class works, add this at the end of the class code (before the #endif):
int main() {
Capture c; // Instantiate the class Capture
c.do_capture(); // Call the "do_capture()" method of class Capture
}
Notice a couple of things here:
- I don't have a "main()" function in the main program. I don't need to, since the program will be run by some other program, unless I want to test the main program by itself, then I would need the "main()" function. However, I have to have a function that I can easily call from the class (depends on what you define as "easily" - my definition is where I don't have to worry about passing around variables and return types. Eventually, we will need/want to have something returned from the main program, e.g. name, or some other values).
- There are no OpenCV stuffs in the class - LEAVE THOSE IN THE MAIN PROGRAM!
- I try to keep the functions as simple as possible, i.e. not a lot of variable passing - this will make the functions easier to call from Java. Notice that the class' code has no variable passing, all the return types are void, and is very short (and sweet),
- The class' extension is .cc, for some reason SWIG doesn't like it when the extension is .cpp for C++
The next step is to create all the interface file (.i) for the class for SWIG, but first (as it is called in the SWIG tutorial website), I like to use a header file (.h) of the class, and include it in the interface file. So the header file for the class:
// File name: main_capture_class.h
class Capture {
public:
void do_capture();
}
// End of main_capture_class.h
Now the interface file:
// File name: main_capture_class.i
%module capture
%{
#include "main_capture_class.h"
%}
// List of all the methods of the class
%Capture::do_capture();
%include "main_capture_class.h"
// End of main_capture_class.i
So to recap, you need four files:
- The main C/C++ code where you use the OpenCV data types/objects and/or functions (main_capture.cpp)
- The proxy class that calls the functions in main_capture.cpp (main_capture_class.cc)
- The header file for the class (main_capture_class.h)
- The interface file for the class (main_capture_class.i)
So now start wrapping up! Using the interface file ... etc. etc. After the whole thing is done, you should have several files such as:
- Capture.java --> this is your usable Java class
- captureJNI.java
- captureJNI.class
- main_capture_class.o
- main_capture_class_wrap.cxx
- main_capture_class_wrap.o
- libcapture.so
Note that 'libcapture.so' is the shared object (hence, the '.so' extension) library, and the name 'libcapture' depends on what you define as the output name when you finally create the shared object after all the compilation steps are done.
If you want to test it, make a test Java file, for example:
// File name: CaptureTest.java
public class CaptureTest {
// CaptureTest constructor
CaptureTest() {
System.out.println("Running CaptureTest...\n");
System.loadLibrary("capture"); // Load the library, i.e. shared object "libcapture.so"
// Notice that the "lib-" and the ".so" extension are omitted
}
// CaptureTest method: doCapture()
public void doCapture() {
Capture c = new Capture(); // Instantiate the Capture object (class)
c.do_capture(); // Call the Capture method "do_capture()"
}
// Main routine
public static void main( String [] args ) {
CaptureTest ct = new CaptureTest(); // Instantiate the CaptureTest class
ct.doCapture(); // Start capturing...
}
}
// End of CaptureTest.java
Now I'm not claiming that this is THE way to do it, or the most elegant way, but it's certainly a sure-fire one. Give it a shot!
For more information, consult:
http://www.swig.org/tutorial.html --> for basic SWIG wrapping tutorial (for other languages as well)
http://www.swig.org/Doc1.3/Java.html --> for details on SWIG wrapping C++ for Java
4 comments:
Hi. I ran across this blog post while searching around for a solution to a problem I've recently encountered. I am writing an application using OpenCV. This is for a school project (masters program). The issue is that we had to change the project's focus after just a few weeks into the semester. Oddly enough, that didn't move the prototype's deadline back any.
The initial program was more complex from a science perspective (my kind of fun), and simple from an interface/software engineering standpoint. The new project is the reverse. Much simpler scientifically, but now there is all this gui and Oop stuff. Sitting down to build the skeleton I just realized that, though my C skills have certainly improved in the last couple years, I have nearly forgotten everything about C++. Also, windows development is horrendous.
My Java skills are much fresher than my C++ experience. Its been roughly ten years since I've done anything with C++, and I am much more comfortable with Java swing than with C++\CL or MFC (who isn't?). Obviously, Java wrappers to my C code is a good quick solution. But, i have never done that.
So here is my question, I am not asking for help per se, but if I run into a couple of snags would you mind me contacting you for suggestions or pointers? (not C style pointers, I'm ok with those:p)
Nice, I will try to test your code as soon as I have some time, for the moment I was able to make it work with the library that I got here. I also wrote something about how to achive it in my blog.
Excellent. Wrappers, of course.
How do you access the C++ method in java?
Post a Comment