Android使用OpenCV 2.4.2时出现UnsatisfiedLinkError错误

14

我试图编写一个简单的OpenCV Android程序。按照这里的说明下载并安装了OpenCV for Android,然后像说明中所述将OpenCV Library 2.4.2作为库项目添加到我的Android项目中。

然而,当我编译标准的“Hello World程序”时,如果包括Mat mat = new Mat();这行代码,则编译失败;否则编译成功。

package com.example;

import org.opencv.core.Mat;

import android.app.Activity;
import android.os.Bundle;

public class HelloAndroidActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Mat mat = new Mat();
    }
}

这是它打印出来的堆栈跟踪:

    07-23 09:59:43.835: E/AndroidRuntime(8222): FATAL EXCEPTION: main
07-23 09:59:43.835: E/AndroidRuntime(8222): java.lang.UnsatisfiedLinkError: n_Mat
07-23 09:59:43.835: E/AndroidRuntime(8222):     at org.opencv.core.Mat.n_Mat(Native Method)
07-23 09:59:43.835: E/AndroidRuntime(8222):     at org.opencv.core.Mat.<init>(Mat.java:181)
07-23 09:59:43.835: E/AndroidRuntime(8222):     at com.example.HelloAndroidActivity.onCreate(HelloAndroidActivity.java:15)
07-23 09:59:43.835: E/AndroidRuntime(8222):     at android.app.Activity.performCreate(Activity.java:4538)
07-23 09:59:43.835: E/AndroidRuntime(8222):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1071)
07-23 09:59:43.835: E/AndroidRuntime(8222):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2161)
07-23 09:59:43.835: E/AndroidRuntime(8222):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2240)
07-23 09:59:43.835: E/AndroidRuntime(8222):     at android.app.ActivityThread.access$600(ActivityThread.java:139)
07-23 09:59:43.835: E/AndroidRuntime(8222):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1262)
07-23 09:59:43.835: E/AndroidRuntime(8222):     at android.os.Handler.dispatchMessage(Handler.java:99)
07-23 09:59:43.835: E/AndroidRuntime(8222):     at android.os.Looper.loop(Looper.java:154)
07-23 09:59:43.835: E/AndroidRuntime(8222):     at android.app.ActivityThread.main(ActivityThread.java:4977)
07-23 09:59:43.835: E/AndroidRuntime(8222):     at java.lang.reflect.Method.invokeNative(Native Method)
07-23 09:59:43.835: E/AndroidRuntime(8222):     at java.lang.reflect.Method.invoke(Method.java:511)
07-23 09:59:43.835: E/AndroidRuntime(8222):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
07-23 09:59:43.835: E/AndroidRuntime(8222):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
07-23 09:59:43.835: E/AndroidRuntime(8222):     at dalvik.system.NativeStart.main(Native Method)

需要注意两件事情:我在这段代码中没有直接使用任何本地的东西(就像其他一些问题所述),而且旧的OpenCV 2.3.x库在使用相同的方法之前工作得很好。这两个Android项目具有相同的目标和支持的API设置。


请确保您已将库“org.opencv.core.Mat”放置在正确的位置。请确保该jar文件位于libs文件夹中。 - Padma Kumar
1
添加这段代码解决了我的问题。 static{ System.loadLibrary("opencv_java3"); } - M Faisal Hameed
3个回答

19

我搞定了。之前没有静态链接库。如果你使用这段代码,它就可以工作了。

package com.example;

import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class HelloAndroidActivity extends Activity
{

    final String TAG = "Hello World";

private BaseLoaderCallback mOpenCVCallBack = new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(int status) {
   switch (status) {
       case LoaderCallbackInterface.SUCCESS:
       {
      Log.i(TAG, "OpenCV loaded successfully");
      // Create and set View
      setContentView(R.layout.main);
       } break;
       default:
       {
      super.onManagerConnected(status);
       } break;
   }
    }
};

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
    Log.i(TAG, "onCreate");
    super.onCreate(savedInstanceState);

    Log.i(TAG, "Trying to load OpenCV library");
    if (!OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_2, this, mOpenCVCallBack))
    {
      Log.e(TAG, "Cannot connect to OpenCV Manager");
    }
}
}

然而,我对这个"OpenCV Manager"的想法并不是太喜欢。这使得用户必须在应用程序能够工作之前手动安装多个软件包。


我的问题也是一样的,仍然在为同样的错误而苦苦挣扎。你能否请帮我提供更多的解决方案? - Rekha
1
不,我还没有尝试过你的代码。但现在我的问题已经解决了。我的错误非常愚蠢,就是在调用库之前定义了Mat m = new Mat(),所以它会报错。但这个错误竟然被忽略了两天。 - Rekha
哈哈,不错。很高兴你解决了它。我肯定我也遇到过类似的问题。 - Jason
1
谢谢@Rekha分享你的“愚蠢”错误!我在不同类之间使用OpenCV类时也犯了同样的错误。你的评论解决了这个问题! :) - Mahm00d
JavaCV的方式(https://code.google.com/p/javacv/#Quick_Start_for_OpenCV_and_FFmpeg)在OpenCV上不起作用。 - Abhishek Choudhary

3
解决方案之一是像@Jason的答案一样使用OpenCV Manager。官方文档在此详细说明
但正如@Jason所说,"这使用户必须在应用程序正常工作之前手动安装多个包"。虽然如此,OpenCV Manager有一些优点,例如:
-如果更新OpenCV,则用户只需要更新管理器/库。使用管理器的应用程序可以保持不变。
-您的应用程序apk大小将更小: -每个应用程序的简单opencv约为~400KB+约为800KB的OpenCV管理器+编译为设备架构的OpenCV库的约12MB。 -对于传统的静态链接,您的设备中每个opencv应用程序至少为~25MB。
当然,这些大小取决于您放置在应用程序内的内容...
即使如此,如果您希望以传统方式部署应用程序,使用静态链接,您可以在此阅读说明

5
如果更新了OpenCV,用户只需要更新管理器/库。这可能是一个不好的事情。你希望控制你正在使用的版本,否则就没有延迟时间来测试你的应用程序是否能够与最新版本一起运行。这是基本的质量保证... - pablisco
没错,我没有关注最近的发展,但应该有一种机制让应用程序控制它们与哪个版本兼容。如果没有这样的机制,那就是一个问题。 - Rui Marques
1
另一种选择是为每个4个目标CPU架构(或仅一个,x86和mips并不那么常见)拥有多个目标APK。这只会增加4MB的开销,应该没问题。 - pablisco
从我最近看到的情况来看,有静态常量可以让您断言管理器正在运行的版本。 - Rui Marques
1
链接静态库真的很有帮助!谢谢 (+1) - Rat-a-tat-a-tat Ratatouille

2
 static{System.loadLibrary("opencv_java3"); } //the name of the .so file, without the 'lib' prefix

您可以在活动中的任何位置静态加载open cv库。 在您的jniLibs文件夹中搜索.so文件,并将其复制/粘贴为“loadLibrary”方法的参数,不包括lib前缀。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接