billmccord / OpenCV-Android

A project for porting and optimizing OpenCV for Google's Android OS
http://billmccord.github.com/OpenCV-Android/
444 stars 162 forks source link

Segmentation fault in VideoEmulation #7

Open pflammertsma opened 14 years ago

pflammertsma commented 14 years ago

Firstly, I'd like to commend Bill and Noritsuna on the amazing job they've done in porting OpenCV to Android. Compiling the library was surprisingly simple and all-in-all it's a great achievement.

I have been running the VideoEmulation example (using the Java implementation of SocketCamera) on the emulator, and am encountering a segmentation fault at VideoEmulation.java:226:

data = mOpenCV.getSourceImage();

LogCat first warns me of a mismatch between JNI and Java:

WARN/dalvikvm(29093): JNI WARNING: method declared to return '[B' returned '[Z'
              failed in Lorg/siprop/opencv/OpenCV;.getSourceImage ('[B' not found)

I took a look at the C declaration and JNI declaration, and the former, [Z, is a boolean array while the latter, [B is a byte array.

A stack trace of org.siprop.opencv.OpenCV.getSourceImage(Native Method) is outputted and the VM instantly aborts.

What have I done wrong here? Is my library somehow not compiled correctly?

pflammertsma commented 14 years ago

After some debugging, I've confirmed that the native method getSourceImage() in cvjni.cpp:134 is actually called; the JNI WARNING above is raised immediately after the function returns, and has the following trace:

"Thread-8" prio=5 tid=15 RUNNABLE
  | group="main" sCount=0 dsCount=0 s=N obj=0x43d16548 self=0x119ff8
  | sysTid=16284 nice=0 sched=0/0 cgrp=default handle=1196176
  at org.siprop.opencv.OpenCV.getSourceImage(Native Method)
  at org.siprop.opencv.VideoEmulation$1.run(VideoEmulation.java:226)
pflammertsma commented 14 years ago

If I change the type declaration in OpenCV.java:38 from:

public native byte[] getSourceImage();

To:

public native boolean[] getSourceImage();

The application no longer crashes, but then of course I cannot decode the byte array in VideoEmulation.java:240.

pflammertsma commented 14 years ago

I resolved the problem, but needed to make changes to cvjni.h and cvjni.cpp:

  1. The datatype of Java_org_siprop_opencv_OpenCV_getSourceImage() should be jbyteArray, not jbooleanArray.
  2. With all subsequent modifications within that function (line 152, 154 and 157), the Android application works as expected.

I would also suggest changing the datatype of Java_org_siprop_opencv_OpenCV_findContours() to jbyteArray.

ntbb commented 13 years ago

The solution mentioned above was so useful, and therefore I've completed the porting of face detector from PC to android.

Thanks to pflammertsma and the author of this awesome project!

bruciebruce commented 13 years ago

Hello,

Thanks for all the good pointers (pardon the joke).

I took your advice and made changes to cvjni.h file. Here are the changes:

JNIEXPORT jbyteArray JNICALL Java_org_siprop_opencv_OpenCV_findContours(JNIEnv* env, jobject thiz, jint width, jint height);

and also this:

JNIEXPORT jbyteArray JNICALL Java_org_siprop_opencv_OpenCV_getSourceImage(JNIEnv* env, jobject thiz);

I then made chanes to the implementation file cvjni.cpp as such:

/ Generate and return a boolean array from the source image. // Return 0 if a failure occurs or if the source image is undefined. JNIEXPORT jbyteArray JNICALL Java_org_siprop_opencv_OpenCV_getSourceImage(JNIEnv* env, jobject thiz) {

...

jbyteArray res_array = env->NewByteArray(imageSize);
if (res_array == 0) {
    LOGE("Unable to allocate a new boolean array for the source image.");
    return 0;
}
env->SetByteArrayRegion(res_array, 0, imageSize, (jbyte*)strm->GetByte());

strm->Close();
SAFE_DELETE(strm);

return res_array;

}

and finally the 2nd file:

JNIEXPORT jbyteArray JNICALL Java_org_siprop_opencv_OpenCV_findContours(JNIEnv* env, jobject thiz, jint width, jint height) { ...

jbyteArray res_array = env->NewByteArray(imageSize);
LOGV("Load NewBooleanArray.");
if (res_array == 0) {
    return 0;
}
env->SetByteArrayRegion(res_array, 0, imageSize, (jbyte*)strm->GetByte());
LOGV("Load SetBooleanArrayRegion.");

LOGV("Release sourceImage");
if (m_sourceImage) {
    cvReleaseImage(&m_sourceImage);
    m_sourceImage = 0;
}
LOGV("Release binaryImage");
cvReleaseImage( &binaryImage );
LOGV("Release grayImage");
cvReleaseImage( &grayImage );
LOGV("Release contourImage");
cvReleaseImage( &contourImage );
LOGV("Release storage");
cvReleaseMemStorage( &storage );
LOGV("Delete strm");
strm->Close();
SAFE_DELETE(strm);

return res_array;

}

I still get the same seg fault alluded to by the previous writers on this thread.

I have not run the emulator program. I have an ADP2

Thanks!

-Bruce

billmccord commented 13 years ago

Yes, much thanks to pflammertsma. I have been rather disconnected from this project of late because of other priorities, but I am going to try to integrate this work back into the project.