0

Java から JNI (OpenCV4Android) を介して渡された cv::Mat (opencv) オブジェクトに作用するネイティブ C++ 関数があります。

これは私の関数宣言です:

extern "C" jboolean Java_com_test_JNIActivity_track(JNIEnv *env, jobject obj, jlong inMatGr, jlong inMatRgba, jint currFrame);

これは、渡された引数にアクセスして出力するコードです。

extern "C" jboolean Java_com_test_JNIActivity_track(JNIEnv *env, jobject obj, jlong inMatGr, jlong inMatRgba, jint currFrame)
{
   ALOG("Native: Rgba@%.8x, Gray@%.8x", inMatRgba, inMatGr);

   cv::Mat& captured_image = *(cv::Mat *)inMatRgba;
   cv::Mat_<uchar>& grayscale_image = *(cv::Mat_<uchar> *)inMatGr;
   ...
}

Java 宣言部分は次のように設定されます。

private native boolean track(long grayAddr, long rgbaAddr, int currFrameNum);

これは OnCameraFrame() メソッドの実装です。

public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
    mRgba = inputFrame.rgba();
    mGray = inputFrame.gray();
    Log.d(TAG_LOG, "Java: Rgba@0x" + Long.toString(mRgba.getNativeObjAddr(),16) +
            ", Gray@0x" + Long.toString(mGray.getNativeObjAddr(),16));
    track(mGray.getNativeObjAddr(), mRgba.getNativeObjAddr(), currFrameNum++);
    //Log.d(TAG_LOG, "Java: Frame(" + currFrameNum + ')');
    return inputFrame.rgba();
}

ただし、Java 部分 (Mat.getNatvieObjAddr()) で設定したものから 2 つの引数に対して (ネイティブ関数内の場合) 異なる値を取得します。

これらは、JNI インターフェイスの両側の値です。

In Java: 1st argument = 0x405ab288, 2nd argument = 0x557ab9d8
In Native: 1st argument = 0x00000000, 2nd argument = 0x405ab288

最後の引数は jint であり、正しい値を与えます。この問題は、さまざまなアーキテクチャでさまざまなサイズの jlong​​ に関係している可能性があります (コードは armv7a プロセッサで実行されます)。

助けていただければ幸いです。ありがとう。

4

1 に答える 1

1

私は自分でそれを理解し、私の状況にいる人に共有しています。

private native boolean track(long grayAddr, long rgbaAddr, int currFrameNum);

Java の long 型のサイズは 8 バイトで、jlong​​ も同様です (typedef は c++ では _int64_t、C では long long です。jni.h を確認してください)。

cv::Mat& captured_image = *(cv::Mat *)inMatRgba;

inMatRgbacv::Matオブジェクトへのポインターです。64 ビット マシンでは、ポインターは 8 バイト (jlong​​ と同じ) であるため、うまく機能するはずです。ただし、32 ビット マシンでは、ポインターは 4 バイトであり、inMatRgba の下位 4 バイトのみが cv::Mat オブジェクトへのアドレスと見なされます。これは、32 ビット マシンがビッグ エンディアンの場合に問題になります (この場合、下位 4 バイトは値 0 を保持します)。

解決:

ケースごとに異なる割り当てを定義する必要がありました。

int *ptrRgba = NULL;   
int *ptrGr = NULL;

if (4 == sizeof(int *) && is_big_endian()) {
   ptrRgba = (int *)&inMatRgba;
   ptrGr = (int *)&inMatGr;
}

cv::Mat& captured_image = ptrRgba ? *(cv::Mat *)(*(ptrRgba+1)) : *(cv::Mat *)inMatRgba;
cv::Mat_<uchar>& grayscale_image = ptrGr ? *(cv::Mat_<uchar> *)(*(ptrGr+1)) : *(cv::Mat_<uchar> *)inMatGr;
于 2016-07-05T17:27:15.863 に答える