我遇到了一个奇怪的问题。长话短说:我写了一个Android应用程序,利用OpenCV与两个活动:
Activity1预览前置摄像头,用户点击启动Activity2,通过Intent发送当前帧的地址
Activity2将给定地址下的帧的Mat克隆类型分配给它的本地字段,并允许用户对其进行简单的操作(即在HSV色彩空间中执行inRange方法)。Mat被转换为位图并在ImageView中显示:这发生在Activity2启动时(对于原始捕获的帧)和每个用户操作SeekBar之后。
Activity1是Activity2的父级,因此单击后退按钮将重新启动Activity1。现在是奇怪的部分:
1)一段时间后(不到1分钟)Activity1崩溃,与libc: Fatal signal 11 (SIGSEGV)
-正如你可以想象的,它不会发生当Activity2从未启动
2)如果我通过简单地返回到Activity1并再次单击重新启动Activity2, OnCreate()和其他方法从常规生命周期被调用,应用程序崩溃时,从Mat转换到位图执行相同的致命信号错误:
Utils.matToBitmap(mCapturedFrame, bm);
所以,这是第一次OpenCV的函数被重新启动一个活动后被调用。最好的部分是,mcaptureframe存在,并且前面提到的方法在加载OpenCV库后被称为。更重要的是,我释放()本地创建的Mats,以及包含捕获帧Mat的字段(当我从Activity2返回时)。在Activity1的情况下,错误看起来像内存泄漏,但是在哪里?!
我真的看不出我在这里做错了什么,如果有任何建议,我将很高兴。请随意从这里下载我的java代码文件:http://speedy.sh/RMPKH/thesis.zip如果我理解正确,您正在将Mat的本机对象地址从活动1发送到活动2。然后,在活动2中,你要做这样的事情:
Mat receivingMat = new Mat(nativeAddrFromActivity1);
在这种情况下,问题是您遇到了一个双重自由错误。这样做的原因很重要,但我会告诉你。首先,让我们看看OpenCV的Mat实现的构造函数:
public Mat(long addr)
{
if (addr == 0)
throw new java.lang.UnsupportedOperationException("Native object address is NULL");
nativeObj = addr;
}
当然,receivingMat将在将来的某个时候超出作用域,然后由GarbageCollector收集。在这种情况下,finalize方法将被调用。这将导致调用OpenCV的Mat实现的本地删除函数,因为finalize方法是这样实现的:
@Override
protected void finalize() throws Throwable {
n_delete(nativeObj);
super.finalize();
}
n_delete函数定义如下(见这里):
//
// native support for java finalize()
// static void Mat::n_delete( __int64 self )
//
JNIEXPORT void JNICALL Java_org_opencv_core_Mat_n_1delete
(JNIEnv*, jclass, jlong self);
JNIEXPORT void JNICALL Java_org_opencv_core_Mat_n_1delete
(JNIEnv*, jclass, jlong self)
{
delete (Mat*) self;
}
在我看来,这是Android的OpenCV的一个bug。用本机地址构造函数创建的Mat不应该调用n_delete函数,因为它没有本机Mat头的所有权,也不负责清理它。我想不出任何情况下你会喜欢这种行为……
要解决您的问题,您应该将Mat转换为位图,将其保存到临时文件中,并通过intent extras将该文件的路径从Activity 1发送到Activity 2。