使用OpenCv with Android Camera Surfaceview時OpenCVLoader失敗問題
阿新 • • 發佈:2019-02-16
今天在使用OpenCV Library 2.4.10建立了我的第一個基於opencv的Android程式,先貼出我的程式碼:
package com.example.facedetector; import org.opencv.android.BaseLoaderCallback; import org.opencv.android.CameraBridgeViewBase; import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame; import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2; import org.opencv.android.LoaderCallbackInterface; import org.opencv.android.OpenCVLoader; import org.opencv.core.Core; import org.opencv.core.CvType; import org.opencv.core.Mat; import org.opencv.core.MatOfRect; import org.opencv.core.Point; import org.opencv.core.Rect; import org.opencv.core.Scalar; import org.opencv.highgui.Highgui; import org.opencv.imgproc.Imgproc; import org.opencv.objdetect.CascadeClassifier; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.SurfaceView; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity implements CvCameraViewListener2, OnClickListener { private Button btnStart; private CameraBridgeViewBase cameraPreview = null; private Mat mRgba; private boolean startProcess = false; protected BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) { @Override public void onManagerConnected(int status) { switch (status) { case LoaderCallbackInterface.SUCCESS: { cameraPreview.enableView(); } break; default: { super.onManagerConnected(status); } break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); cameraPreview = (CameraBridgeViewBase) findViewById(R.id.cameraView); cameraPreview.setVisibility(SurfaceView.VISIBLE); cameraPreview.setCvCameraViewListener(this); btnStart = (Button) findViewById(R.id.btnStart); btnStart.setOnClickListener(this); } @Override protected void onResume() { super.onResume(); <strong> OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_10, getApplicationContext(), mLoaderCallback );</strong> } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } private void startFaceDetetion(Mat image){ String xmlfilePath=getClass().getResource("lbpcascade_frontalface.xml").getPath().substring(1); CascadeClassifier faceDetector = new CascadeClassifier(xmlfilePath); // Detect faces in the image. // MatOfRect is a special container class for Rect. MatOfRect faceDetections = new MatOfRect(); faceDetector.detectMultiScale(image, faceDetections); System.out.println(String.format("Detected %s faces", faceDetections.toArray().length)); // Draw a bounding box around each face. for (Rect rect : faceDetections.toArray()) { Scalar color = new Scalar(0, 255, 0); Core.rectangle(image, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height), color); } } @Override protected void onDestroy() { super.onDestroy(); if (cameraPreview != null) { cameraPreview.disableView(); startProcess = false; } } @Override protected void onPause() { super.onPause(); if(cameraPreview != null){ cameraPreview.disableView(); startProcess = false; } } @Override public void onCameraViewStarted(int width, int height) { mRgba = new Mat(height, width, CvType.CV_8UC4); } @Override public void onCameraViewStopped() { mRgba.release(); } @Override public Mat onCameraFrame(CvCameraViewFrame inputFrame) { if(startProcess == true) { mRgba = inputFrame.rgba();
return mRgba
}
return null;
}
@Override
public void onClick(View v) {
startProcess = !startProcess;
}
}
這段程式碼,按照Internet上各位前輩們的經驗總結,是沒有問題的,但是當我在真正run它的時候,還是出現了問題,logcat上出現了以下提示:
也就是說OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_10, getApplicationContext(), mLoaderCallback );無法執行成功。08-18 20:57:03.549: E/AndroidRuntime(3444): java.lang.RuntimeException: Unable to resume activity {com.example.facedetector/com.example.facedetector.MainActivity}: java.lang.IllegalArgumentException: Service Intent must be explicit: Intent { act=org.opencv.engine.BIND }
網路上也有人遇到了同樣的問題,給出的解決方案是:
Try using getApplicationContext()
instead
of this
in OpenCVLoader.initAsync(..)
但是我在修改後,程式依然無法執行。
出現上述問題的原因主要是因為使用了Android 5.0作為targetsdk,專業的解釋 in here。這裡我就不多說,大家可以自行研究。簡單解釋是:
Android 5.0 service intents must be explicit intents and the OpenCV library uses implicit intents in the
AsyncServiceHelper.java ( new Intent("org.opencv.engine.BIND") ), so it doesn't work.
既然是因為SDK version 的問題,那麼只需要改變version就可以了,因此這裡我將我的targetsdk由API 21改為了API 19:
android:targetSdkVersion="21" ---------> android:targetSdkVersion="19"
問題解決了,這時候就可以正常執行APP了。