I use:
cvFindContours(gray, mem, contours, Loader.sizeof(CvContour.class) , CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0));
and as the result I have CvSeq contours
to iterate (as far as I understand it).
So I use it like that:
if(contours!=null) {
for (ptr = contours; ptr != null; ptr = ptr.h_next()) {
//..do sth with ptr
}
}
It works, but from time to time (quite often) I get:
Exception in thread "Thread-3" java.lang.NullPointerException: This pointer address is NULL.
at com.googlecode.javacv.cpp.opencv_core$CvSeq.h_next(Native Method)
at pl..filter(FullFilter.java:69)
at pl..Window$1.run(Window.java:41)
at java.lang.Thread.run(Unknown Source)
The line in which the exception is thrown is the line with ptr.h_next().
I tried to check for nulls but it doesn't work:
System.out.println("PTR="+ptr); // it's not null here!
if(ptr.h_next()==null) //exception in this line!
System.out.println("NULL");
System.out.println(ptr.h_next());
The first line shows:
PTR=com.googlecode.javacv.cpp.opencv_core$CvSeq[address=0x0,position=0,limit=1,capacity=1,deallocator=com.googlecode.javacpp.Pointer$NativeDeallocator@66d53ea4]
I tried also invoking contours.total()
but it always throws the same exception.
So, what is a proper way to use in Java such C-like sequences?
EDIT: my full method:
public IplImage filter(IplImage image) {
IplConvKernel kernel = cvCreateStructuringElementEx(2,2,1,1,CV_SHAPE_RECT, null);
cvDilate(image, image, kernel, 1);
kernel = cvCreateStructuringElementEx(5,5,2,2,CV_SHAPE_RECT, null);
cvErode(image, image, kernel, 1);
IplImage resultImage = cvCloneImage(image);
IplImage gray = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);
cvCvtColor(image, gray, CV_BGR2GRAY);
CvMemStorage mem = CvMemStorage.create();
CvSeq contours = new CvSeq();
CvSeq ptr = new CvSeq();
cvThreshold(gray, gray, 20, 255, opencv_imgproc.CV_THRESH_BINARY);
double thresh = 20;
Canny( gray, gray, thresh, thresh*2, 3 ,true);
cvFindContours(gray, mem, contours, Loader.sizeof(CvContour.class) , CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0));
int i=0;
CvRect boundbox;
if(contours!=null) {
for (ptr = contours; ptr != null; ptr = ptr.h_next()) { //EXCEPTION HERE!
System.out.println((i++)+"\t"+ptr);
cvDrawContours( resultImage, ptr, CvScalar.BLUE, CvScalar.RED, -1, 3, 8, cvPoint(0,0) );
System.out.println("PTR="+ptr);
}
}
return resultImage;
}
It works fine for some time and suddenly (probably when no contours found?) it ends with the following exception:
Exception in thread "Thread-3" java.lang.NullPointerException: This pointer address is NULL.
at com.googlecode.javacv.cpp.opencv_core$CvSeq.h_next(Native Method)
at pl.kasprowski.eyetracker.FullFilter2.filter(FullFilter2.java:39)
at pl.kasprowski.eyetracker.Window$1.run(Window.java:42)
at java.lang.Thread.run(Unknown Source)
Im feeding the method directly with images taken from camera (once a second).
EDIT:
After some experiments it occurs that from time to time when I invoke cvFindContours
as above I get a contour
object which IS NOT NULL but invoking any method like contour.h_next()
or contour.total()
results in exception like above. What can be wrong? Or - how to check if the contour
object is OK?! Of course I could catch NullPointerException
but I don't think it's a correct way to solve the problem...
Problem solved.
I added additional condition. Instead of:
if(contours!=null) {
I wrote
if(contours!=null && !contours.isNull()) {
and it works. I don't see exactly why it is necessary but I think it's connected with Java <-> C semantic gap.