web-dev-qa-db-ja.com

YUV_420_888の画像をAndroidからOpenCVMatのJNIに送信する最も効率的な方法

Android Camera2APIからのライブ画像に対してOpenCV画像処理を実行したいAndroidアプリケーションがあります。現在、処理を行わない場合、通常の1280x720フレームでOnImageAvailble関数の画像を30fpsで受信できます。

ダーティハックとして、JPEG形式のImageReaderから画像をリクエストし、ビットマップをjniに渡すと、パフォーマンスが大幅に低下します。

YUVフレームをcv Matオブジェクトのjniに渡す最も効率的な方法は何ですか。また、さらに処理するために、このフレームをRGBに変換したいと思います。 Java側でフォーマットを変更する必要がありますか、それともMatオブジェクトをjniに渡して、そこでのみ色空間を変換する必要があります。

18
HimalayanCoder

C++で行うことはすべて、YUVからRGBへの変換を含む明らかな理由でJava同等のものよりもはるかに高速です(Java実装がコンパイル済みライブラリに依存している場合でも)) 。

Javaの既存のマットからJNIを介してC++に直接ポインターを渡すことができます。C++とJNIを使​​用してCanny()を実行したいとし、JNI関数を次のように定義します。

// In Java
public static native boolean nativeCanny(long iAddr);

long iAddrパラメーターに注意してください。これは、Javaのマットへの直接ポインターです。次のように呼び出します。

// In Java
nativeCanny(myImage.getNativeObjAddr());

C++でのこの関数の実装は、これと同様の方法でこのポインターを受け取ります(これが機能しない場合は、longをjlong​​に置き換えます)。

// In C++
JNIEXPORT jboolean JNICALL
VeryLongName_nativeCanny(JNIEnv *env, jobject instance, long iAddr) {
    cv::Mat* img = (cv::Mat*) iAddr;
    cv::Canny(*img, *img, 80, 100, 3);
    return true;
}

そして、imgマットに対して行ったことは、JavamyImageで発生しますマットも、結局のところそれはポインタなので、コピーを作成することはありませんでした。

私の知る限り、それはそれが得るのと同じくらい速いです。

2
DanyAlejandro

たぶんあなたに役立つかもしれません:私たちは多くの画像処理を行っているので、私たちはその目的のために私たちの会社でライブラリを書きました。 Cで書かれていませんが、非常にパフォーマンスが優れています。変換後、JNIを介してMatポインターをCコードに渡すだけです。

YUV(標準AndroidカメラフォーマットYUV_420_888))をRGBマットに変換します。さらに、変換前にYUVを効率的にクリッピングすることもできます(非常に大きな画像の場合は重要です。変換する必要があります)。画像全体、および後でクリップするのは高価です)。使用法は非常に簡単です。

Mat mat = Yuv.toMat(image)

https://github.com/quickbirdstudios/yuvToMat

3
Malte