2

I'm working on an OpenCV project, using NDK. There are also some Java calls to OpenCV's library. The java calls are currently working fine, and the project compiles and runs fine. Once a native call is introduced however, the app crashes and then errors appear in the .cpp file referenced stating the could not be resolved error (for eg. Symbol 'cv' could not be resolved). Before opening the cpp file, there seem to be no errors, which is how the app is run initially. With every Eclipse restart, the errors don't appear until triggered as mentioned.

I've tested the cpp file beforehand on one of the OpenCV's provided samples (namely; sample 3 - native), and was working fine, so it must be somewhere in the linking process.

Project properties details& problem research

After scanning through and comparing the project settings of the current project in question and the successfully running OpenCV's sample; the differences I noticed were:

  • The project's Current ToolChain (under C/C++ Build > Tool Chain Editor,in the project's properties) is Cygwin GCC, while OpenCV's sample is No ToolChain. I recall reading somewhere that this is a recommended setting, unsure why, but early when converting my Android project to a C/C++ project, I don't recall finding the tool chain option as adjustable.

  • The Configuration in the project in question is Debug [Active] while that in the OpenCV sample is Default [Active]. I couldn't find the latter as an option in the Configuration drop-down menu in my project. The indexer build configuration (Under C/C++ General > Indexer) in turn is also different where my project has Debug, and OpenCV's sample has Default.

Below illustrates my project's aforementioned settings (not OpenCV's sample):

Tool Chain Editor settings

Tool Chain Editor settings

Indexer Build Configuration settings

Indexer Build Configuration settings

The project is prepared with the recommended suggestions that can be found in most tutorials and in questions regarding the matter; as adding necessary project paths and adding the NDKROOT path (also mentioned here). Also the ndk-build command has run successfully.

Also, the method names in the cpp file are named as the naming convention that I've observed in the OpenCV sample, namely it follows this pattern; Java_packageName_callingJavaClass_functionName.

Code and detailed results

Below is the Android.mk outline:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

OPENCV_INSTALL_MODULES:=on
OPENCV_CAMERA_MODULES:=on

include <Full Path To OpenCV>\OpenCV\sdk\native\jni\OpenCV.mk

LOCAL_MODULE    := proc #The name referred to in System.loadLibrary() in the calling Android  activity
LOCAL_SRC_FILES := proc.cpp
LOCAL_LDLIBS +=  -llog -ldl

include $(BUILD_SHARED_LIBRARY)

Application.mk is as follows:

APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := armeabi

EDIT Below is the logcat output for the first run (afterwards, compile errors, namely in the form of could not be resolved errors, in the cpp are realised and thus no run is possible unless Eclipse is restarted). median is the native method called upon which the crash occurs.

01-29 19:14:23.786: W/dalvikvm(8750): No implementation found for native Lcom/ocv/MainActivity;.median (JJ)V
01-29 19:14:23.786: W/dalvikvm(8750): threadid=1: thread exiting with uncaught exception (group=0x400207d8)
01-29 19:14:23.786: E/AndroidRuntime(8750): FATAL EXCEPTION: main
01-29 19:14:23.786: E/AndroidRuntime(8750): java.lang.UnsatisfiedLinkError: median
01-29 19:14:23.786: E/AndroidRuntime(8750):     at com.ocv.MainActivity.median(Native Method)
01-29 19:14:23.786: E/AndroidRuntime(8750):     at com.ocv.MainActivity.onActivityResult(MainActivity.java:155)
01-29 19:14:23.786: E/AndroidRuntime(8750):     at android.app.Activity.dispatchActivityResult(Activity.java:3890)
01-29 19:14:23.786: E/AndroidRuntime(8750):     at android.app.ActivityThread.deliverResults(ActivityThread.java:3517)
01-29 19:14:23.786: E/AndroidRuntime(8750):     at android.app.ActivityThread.handleSendResult(ActivityThread.java:3563)
01-29 19:14:23.786: E/AndroidRuntime(8750):     at android.app.ActivityThread.access$2800(ActivityThread.java:126)
01-29 19:14:23.786: E/AndroidRuntime(8750):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2068)
01-29 19:14:23.786: E/AndroidRuntime(8750):     at android.os.Handler.dispatchMessage(Handler.java:99)
01-29 19:14:23.786: E/AndroidRuntime(8750):     at android.os.Looper.loop(Looper.java:123)
01-29 19:14:23.786: E/AndroidRuntime(8750):     at android.app.ActivityThread.main(ActivityThread.java:4633)
01-29 19:14:23.786: E/AndroidRuntime(8750):     at java.lang.reflect.Method.invokeNative(Native Method)
01-29 19:14:23.786: E/AndroidRuntime(8750):     at java.lang.reflect.Method.invoke(Method.java:521)
01-29 19:14:23.786: E/AndroidRuntime(8750):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
01-29 19:14:23.786: E/AndroidRuntime(8750):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
01-29 19:14:23.786: E/AndroidRuntime(8750):     at dalvik.system.NativeStart.main(Native Method)

EDIT Regarding the code used; for the .java activity code, namely MainActivity.java, below are excerpts relevant to the native functionality.

    // package name
    package com.ocv;

    // Class header
    public class MainActivity extends Activity implements View.OnClickListener{

       // native method declaration    
       public native void median(long matAddrGr, long matAddrRgba);  

       protected void onActivityResult(int requestCode, int resultCode, Intent data) {

           if (OpenCVLoader.initDebug()){

               /* This is line 155 referenced from logcat */
               median(gray_img.getNativeObjAddr(), rgb_img.getNativeObjAddr());
              }
            }
          }

Regarding the native code, proc.cpp (following a similar pattern to that understood from OpenCV's samples):

#include <jni.h>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <vector>

using namespace std;
using namespace cv;

extern "C" {
JNIEXPORT void JNICALL Java_com_ocv_MainActivity_median(JNIEnv*, jobject, jlong addrGray, jlong addrRgba)
{
    Mat* pMatGr=(Mat*)addrGray;
    Mat* pMatRgb=(Mat*)addrRgba;
    vector<KeyPoint> v;

    medianBlur(*pMatGr,*pMatRgb,3);
}
}

Regarding the library loading; OpenCV has successfully loaded (in the first run before the native cpp file's errors appear) as seen below (I even called Imgproc.cvtColor successfully in Java (in the activity MainActivity.java) before the native method median was called):

successful OpenCV loading as shown in logcat

The semantic errors resulting from proc.cpp:

cpp semantic errors


Question

Are the above project properties' observations possibly relevant to the problem? How can they be amended if so? If not, any idea what might be causing the error?

I'm using Eclipse Indigo Service Release 2 (and thus this solution to Eclipse Juno users is not applicable).

I've found many similar questions online (some of which are linked earlier); but none of the suggested answers thus far seem to resolve the issue.

Thank you in advance.

Community
  • 1
  • 1
Noha Kareem
  • 1,748
  • 1
  • 22
  • 32
  • 2
    Sounds like you might be using the cygwin compiler instead of the ndk build system. Also sounds like you might have made a mistake with the native function naming - it should be the java PACKAGE name, not the PROJECT name. So unless you changed the package hierarchy of the openCV java code, the names of the functions in the openCV native code should be unchanged. Posting the exact logcat error message would be a big help, too. – Chris Stratton Jan 29 '13 at 17:51
  • Thank you for the suggestions; I altered the naming convention accordingly (yes, it would make no difference in my case) and added the logcat results. – Noha Kareem Jan 29 '13 at 18:26
  • This does look like a naming problem, please post the native function declaration and the java native method declaration with an indication of its java package and class (they have to match, and I strongly suspect from your log that they don't - when using existing code, you would not put the java declaration of your native method in your Activity class, but rather keep it in the original java wrapper class that came with the library port). Also look earlier in logcat and make sure that it reports having loaded the library. – Chris Stratton Jan 29 '13 at 18:39
  • Thank you for the feedback; I have updated the question accordingly adding java excerpts, the native code as well as the sematic errors resulted. Yes, the library is successfully loaded (mentioned in the question edit as well). I'm not sure I understand this suggestion however `"but rather keep it in the original java wrapper class that came with the library port"`; mainly I don't understand what is meant by the `wrapper class` and `library port` - I am not quite experienced with Android, nor OpenCV, development. – Noha Kareem Jan 29 '13 at 20:01
  • 2
    You have not verified from the logcat log that the **native** library (.so file) has been loaded. That's important, because that it verifies that is was successfully built, packaged, installed, and loaded, and your java-level logging indicates it may have failed to load libraries or may have loaded the original one rather than the one you modified. You are looking for a line of the form "D/dalvikvm( xxxx): Trying to load lib /data/data/com.xxxx.xxxx/lib/libxxx.so" and then one like "D/dalvikvm( xxxx): Added shared lib..." – Chris Stratton Jan 29 '13 at 20:13
  • No I couldn't find them. The only dalvikvm-tagged logcat outputs are posted in the logcat results above (logcat is set to `verbose` display). – Noha Kareem Jan 29 '13 at 20:24
  • If it's not in the log and you cold-started the application recently such that it hasn't simply been flushed out by newer messages, perhaps you don't have a System.loadLibrary([name]); in your java code that is getting called before you try to use the function. As a suggestion you might want to go build hello-jni from the samples directory of the ndk installation to get some experience with how the whole thing works and the log messages that it will generate. – Chris Stratton Jan 29 '13 at 20:38
  • Thanks for the suggestion. I'm currently using OpenCV's java API to save time and hopefully would retry the NDK at some point if possible. Thanks for your time. – Noha Kareem Feb 12 '13 at 13:37

3 Answers3

1
  1. Try to build it in command line with ndk-build when you cd to jni directory.
  2. If it builds, close all cpp editor windows, restart Eclipse but DON'T open any cpp file. Run your app as Android application.
  3. If it runs ok, open cpp file - you will see an error this time.
  4. Erase and retype all "using namespace" strings. I know it sounds weird but when you restart Eclipse another time the errors should disappear. Given that you have all your Paths correct, of course.
  5. Warnings about includes still can be there. I don't know why but the Installation on the phone works.
Vlad
  • 4,425
  • 1
  • 30
  • 39
0

When I had a similar problem I had to change this directory

${ProjDirPath}/../../sdk/native/jni/include

with this one

${ProjDirPath}/../OpenCV-2.4.3.2-android-sdk/sdk/native/jni/include

w3u37905
  • 37
  • 5
  • Thank you for the reply; I have tried it but it still doesn't work. Perhaps it's something else, but thanks for the suggestion. – Noha Kareem Feb 12 '13 at 13:38
0

This may be useful.

However, someone said, it's a bug of eclipse that eclipse has difficult when include headers.

Community
  • 1
  • 1
ccs
  • 1
  • 1