OpenCVのオプティカルフローを使ったAndroidアプリの開発をしています。

OpenCV for
Androidにオプティカルフローのサンプルがないため、先日下記のサイトを参考にしてオプティカルフローを動かそうとしましたが「問題が発生したため終了します」というメッセージと共に強制終了してしまいます。

<http://pukulab.blog.fc2.com/blog-category-7.html>

様々なサイトを見たのですが解決できません。どうぞよろしくお願いします。

エラーは以下の通りです。

```

    11-27 17:03:44.492 768-801/? E/WindowManager: Starting window AppWindowToken{4449a3f8 token=Token{429fff58 ActivityRecord{426bb2b8 u0 jp.wings.nikkeibp.eyegraphic/.CameraActivity t28}}} timed out
    11-27 17:05:41.702 7090-7090/? E/AndroidRuntime: FATAL EXCEPTION: main
                                                 Process: jp.wings.nikkeibp.eyegraphic, PID: 7090
                                                 java.lang.UnsatisfiedLinkError: Native method not found: org.opencv.core.Mat.n_Mat:()J
                                                     at org.opencv.core.Mat.n_Mat(Native Method)
                                                     at org.opencv.core.Mat.<init>(Mat.java:447)
                                                     at org.opencv.core.MatOfPoint2f.<init>(MatOfPoint2f.java:12)
                                                     at jp.wings.nikkeibp.eyegraphic.CameraActivity.<init>(CameraActivity.java:85)
                                                     at java.lang.Class.newInstanceImpl(Native Method)
                                                     at java.lang.Class.newInstance(Class.java:1208)
                                                     at android.app.Instrumentation.newActivity(Instrumentation.java:1061)
                                                     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2101)
                                                     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2233)
                                                     at android.app.ActivityThread.access$800(ActivityThread.java:135)
                                                     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
                                                     at android.os.Handler.dispatchMessage(Handler.java:102)
                                                     at android.os.Looper.loop(Looper.java:136)
                                                     at android.app.ActivityThread.main(ActivityThread.java:5001)
                                                     at java.lang.reflect.Method.invokeNative(Native Method)
                                                     at java.lang.reflect.Method.invoke(Method.java:515)
                                                     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
                                                     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
                                                     at dalvik.system.NativeStart.main(Native Method)
    
```

ソースコードはこのようになります。  
CameraActivity.java

```

    // Java
    import java.util.List;
    import java.util.Vector;
    
    // OpenCV
    import org.opencv.android.BaseLoaderCallback;
    import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;
    import org.opencv.android.LoaderCallbackInterface;
    import org.opencv.android.OpenCVLoader;
    import org.opencv.core.Core;
    import org.opencv.core.CvType;
    import org.opencv.core.Size;
    import org.opencv.core.Mat;
    import org.opencv.core.MatOfByte;
    import org.opencv.core.MatOfFloat;
    import org.opencv.core.MatOfInt;
    import org.opencv.core.MatOfPoint;
    import org.opencv.core.MatOfPoint2f;
    import org.opencv.core.MatOfPoint3f;
    import org.opencv.core.Point;
    import org.opencv.core.Point3;
    import org.opencv.core.Rect;
    import org.opencv.core.Scalar;
    import org.opencv.core.TermCriteria;
    import org.opencv.features2d.Features2d;
    import org.opencv.imgproc.Imgproc;
    import org.opencv.objdetect.CascadeClassifier;
    import org.opencv.video.Video;
    import org.opencv.android.CameraBridgeViewBase;
    import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;
    
    // UI
    import android.app.Activity;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.view.SurfaceView;
    import android.view.WindowManager;
    import android.widget.Toast;
    
    public class CameraActivity extends Activity implements     CvCameraViewListener2 {
    private static final String TAG = "OCVSample::Activity";
    
    // カメラビューのインスタンス
    // CameraBridgeViewBase は JavaCameraView/NativeCameraView のスーパークラス
    private CameraBridgeViewBase mOpenCvCameraView;
    
    // カメラ画像保存用
    private Mat image, image_small;
    
    // オプティカルフロー用
    private Mat image_prev, image_next;//画像比較
    private MatOfPoint2f pts_prev,pts_next;//Point2f（座標　）計算結果の格納？
    
    // OpenCVライブラリのロード
    private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
        @Override
        public void onManagerConnected(int status) {
            switch (status) {
                // 読み込みが成功したらカメラプレビューを開始
                case LoaderCallbackInterface.SUCCESS: {
                    Log.i(TAG, "OpenCV loaded successfully");
                    mOpenCvCameraView.enableView();
                    break;
                }
                default: {
                    super.onManagerConnected(status);
                    break;
                }
            }
        }
    };
    
    // コンストラクタ
    public CameraActivity() {
        Log.i(TAG, "Instantiated new " + this.getClass());
        pts_prev = new MatOfPoint2f();　//エラーで指摘される行
        pts_next = new MatOfPoint2f();
    }
    
    // 起動時
    @Override
    public void onCreate(Bundle savedInstanceState) {
        Log.i(TAG, "called onCreate");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.eyeglance);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    
        //camera_viewはeyeglanceのレイアウトに定義したプレビュー用の画面
        // カメラビューのインスタンス(mOpenCvCameraView)を変数にバインド
        mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.camera_view);
        mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);
        // リスナーの登録＊
        mOpenCvCameraView.setCvCameraViewListener(this);
    
    }
    
    
    
    // 再開時,activity前
    @Override
    public void onResume() {
        super.onResume();
        OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_9, this, mLoaderCallback);
    
    }
    
    // 停止時,activity後
    @Override
    public void onPause() {
        super.onPause();
        if (mOpenCvCameraView != null) mOpenCvCameraView.disableView();
    }
    
    // 破棄時,一番最後
    public void onDestroy() {
        super.onDestroy();
        if (mOpenCvCameraView != null) mOpenCvCameraView.disableView();
    }
    
    // カメラ開始時
    public void onCameraViewStarted(int width, int height) {
        image = new Mat(height, width, CvType.CV_8UC3);
        image_small = new Mat(height/8, width/8, CvType.CV_8UC3);
        image_prev = new Mat(image_small.rows(), image_small.cols(), image_small.type());
        image_next = new Mat(image_small.rows(), image_small.cols(), image_small.type());
    }
    
    // カメラ停止時
    public void onCameraViewStopped() {
    }
    
    
    
    // 画像取得時
    public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
        // 縮小
        image = inputFrame.rgba();
        Imgproc.resize(image, image_small, image_small.size(), 0, 0, Imgproc.INTER_NEAREST);
    
        // グレースケール
    
        Mat gray = new Mat(image_small.rows(), image_small.cols(), CvType.CV_8UC1);
        Imgproc.cvtColor(image_small, gray, Imgproc.COLOR_RGB2GRAY);
    
        // 特徴点抽出
        MatOfPoint features = new MatOfPoint();
        Imgproc.goodFeaturesToTrack(gray, features, 50, 0.01, 10);
    
        // 特徴点が見つかった
        if (features.total() > 0) {
            // 過去のデータが存在する
            if (pts_prev.total() > 0) {
                // 現在のデータ
                gray.copyTo(image_next);
                pts_next = new MatOfPoint2f(features.toArray());
    
                // オプティカルフロー算出
                MatOfByte status = new MatOfByte();
                MatOfFloat err = new MatOfFloat();
                Video.calcOpticalFlowPyrLK(image_prev, image_next, pts_prev, pts_next, status, err);
    
                // 表示
                long flow_num = status.total();
                if (flow_num > 0) {
                    List<Byte>  list_status = status.toList();
                    List<Point> list_features_prev = pts_prev.toList();
                    List<Point> list_features_next = pts_next.toList();
                    double scale_x = image.cols() / image_small.cols();
                    double scale_y = image.rows() / image_small.rows();
                    for (int i = 0; i < flow_num; i++) {
                        if (list_status.get(i) == 1) {
                            Point p1 = new Point();
                            p1.x = list_features_prev.get(i).x * scale_x;
                            p1.y = list_features_prev.get(i).y * scale_y;
                            //Core.circle(image, p1, 3, new Scalar(255,0,0), -1, 8, 0 );
                            Point p2 = new Point();
                            p2.x = list_features_next.get(i).x * scale_x;
                            p2.y = list_features_next.get(i).y * scale_y;
                            //Core.circle(image, p2, 3, new Scalar(255,255,0), -1, 8, 0 );
    
                            // フロー描画
                            int thickness = 5;
                            Core.line(image, p1, p2, new Scalar(0,255,0), thickness);
                        }
                    }
                }
            }
    
            // 過去のデータ
            gray.copyTo(image_prev);
            pts_prev = new MatOfPoint2f(features.toArray());
        }
    
        return image;
     }
    }
    
```

MatOfPoint2f.java

```

    package org.opencv.core;
    
    import java.util.Arrays;
    import java.util.List;
    
    public class MatOfPoint2f extends Mat {
    // 32FC2
    private static final int _depth = CvType.CV_32F;
    private static final int _channels = 2;
    
    public MatOfPoint2f() {
        super(); //エラーで指摘される行
    }
    
    protected MatOfPoint2f(long addr) {
        super(addr);
        if( !empty() && checkVector(_channels, _depth) < 0 )
            throw new IllegalArgumentException("Incompatible Mat");
        //FIXME: do we need release() here?
    }
    
    public static MatOfPoint2f fromNativeAddr(long addr) {
        return new MatOfPoint2f(addr);
    }
    
    public MatOfPoint2f(Mat m) {
        super(m, Range.all());
        if( !empty() && checkVector(_channels, _depth) < 0 )
            throw new IllegalArgumentException("Incompatible Mat");
        //FIXME: do we need release() here?
    }
    
    public MatOfPoint2f(Point...a) {
        super();
        fromArray(a);
    }
    
    public void alloc(int elemNumber) {
        if(elemNumber>0)
            super.create(elemNumber, 1, CvType.makeType(_depth, _channels));
    }
    
    public void fromArray(Point...a) {
        if(a==null || a.length==0)
            return;
        int num = a.length;
        alloc(num);
        float buff[] = new float[num * _channels];
        for(int i=0; i<num; i++) {
            Point p = a[i];
            buff[_channels*i+0] = (float) p.x;
            buff[_channels*i+1] = (float) p.y;
        }
        put(0, 0, buff); //TODO: check ret val!
    }
    
    public Point[] toArray() {
        int num = (int) total();
        Point[] ap = new Point[num];
        if(num == 0)
            return ap;
        float buff[] = new float[num * _channels];
        get(0, 0, buff); //TODO: check ret val!
        for(int i=0; i<num; i++)
            ap[i] = new Point(buff[i*_channels], buff[i*_channels+1]);
        return ap;
    }
    
    public void fromList(List<Point> lp) {
        Point ap[] = lp.toArray(new Point[0]);
        fromArray(ap);
    }
    
    public List<Point> toList() {
        Point[] ap = toArray();
        return Arrays.asList(ap);
     }
    }
    
```

Mat.java

```

    public Mat()
    {
    
        nativeObj = n_Mat();　//エラーで指摘される行
    
        return;
    }
    
```
CC BY-SA 4.0
2015-11-27T08:48:57.033
19374
2021-03-07T05:17:12.570
2021-03-07T05:17:12.570
3060
13431
question
java android opencv
Android アプリが強制終了してしまい、オプティカルフローが使えない
Mat クラス用のnativeメソッドの実体がロードできていないようです。

原因はいろいろ考えられますが、

  * nativeライブラリ(拡張子が.soのファイル)が適切にapkに含まれているか
  * ビルドで生成された.soファイルのABIが適切なもの(ARMで実行できるもの)になっているかるか
  * nativeライブラリを適切に`System.loadLibrary()`しているか

等を確認してみてください。
CC BY-SA 3.0
2015-11-28T06:21:08.687
19399
2015-11-28T06:21:08.687
319
19374
answer