アンドロイドアプリの強制終了。オプティカルフローが使えない。
失礼します.
大学で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;
}