Merge pull request #452 from asmorkalov:android_tutorial_update

pull/455/merge
Andrey Kamaev 12 years ago committed by OpenCV Buildbot
commit bb25111d23
  1. 365
      doc/tutorials/introduction/android_binary_package/dev_with_OCV_on_Android.rst
  2. 2
      doc/tutorials/introduction/table_of_content_introduction/table_of_content_introduction.rst

@ -78,39 +78,33 @@ See the "15-puzzle" OpenCV sample for details.
.. code-block:: java .. code-block:: java
:linenos: :linenos:
public class MyActivity extends Activity implements HelperCallbackInterface public class Sample1Java extends Activity implements CvCameraViewListener {
{
private BaseLoaderCallback mOpenCVCallBack = new BaseLoaderCallback(this) { private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
@Override @Override
public void onManagerConnected(int status) { public void onManagerConnected(int status) {
switch (status) { switch (status) {
case LoaderCallbackInterface.SUCCESS: case LoaderCallbackInterface.SUCCESS:
{ {
Log.i(TAG, "OpenCV loaded successfully"); Log.i(TAG, "OpenCV loaded successfully");
// Create and set View mOpenCvCameraView.enableView();
mView = new puzzle15View(mAppContext); } break;
setContentView(mView); default:
} break; {
default: super.onManagerConnected(status);
{ } break;
super.onManagerConnected(status); }
} break; }
} };
}
}; @Override
public void onResume()
/** Call on every application resume **/
@Override
protected void onResume()
{
Log.i(TAG, "called onResume");
super.onResume();
Log.i(TAG, "Trying to load OpenCV library");
if (!OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_2, this, mOpenCVCallBack))
{ {
Log.e(TAG, "Cannot connect to OpenCV Manager"); super.onResume();
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_3, this, mLoaderCallback);
} }
...
} }
It this case application works with OpenCV Manager in asynchronous fashion. ``OnManagerConnected`` It this case application works with OpenCV Manager in asynchronous fashion. ``OnManagerConnected``
@ -297,220 +291,165 @@ application. It will be capable of accessing camera output, processing it and di
result. result.
#. Open Eclipse IDE, create a new clean workspace, create a new Android project #. Open Eclipse IDE, create a new clean workspace, create a new Android project
:menuselection:`File --> New --> Android Project`. :menuselection:`File --> New --> Android Project`
#. Set name, target, package and ``minSDKVersion`` accordingly.
#. Create a new class :menuselection:`File -> New -> Class`. Name it for example:
*HelloOpenCVView*.
.. image:: images/dev_OCV_new_class.png
:alt: Add a new class.
:align: center
* It should extend ``SurfaceView`` class. #. Set name, target, package and ``minSDKVersion`` accordingly. The minimal SDK version for build
* It also should implement ``SurfaceHolder.Callback``, ``Runnable``. with OpenCV4Android SDK is 11. Minimal device API Level (for application manifest) is 8.
#. Edit ``HelloOpenCVView`` class. #. Allow Eclipse to create default activity. Lets name the activity ``HelloOpenCvActivity``.
* Add an ``import`` line for ``android.content.context``. #. Choose Blank Activity with full screen layout. Lets name the layout ``HelloOpenCvLayout``.
* Modify autogenerated stubs: ``HelloOpenCVView``, ``surfaceCreated``, ``surfaceDestroyed`` and #. Import OpenCV library project to your workspace.
``surfaceChanged``.
.. code-block:: java
:linenos:
package com.hello.opencv.test;
import android.content.Context;
public class HelloOpenCVView extends SurfaceView implements Callback, Runnable {
public HelloOpenCVView(Context context) {
super(context);
getHolder().addCallback(this);
}
public void surfaceCreated(SurfaceHolder holder) {
(new Thread(this)).start();
}
public void surfaceDestroyed(SurfaceHolder holder) { #. Reference OpenCV library within your project properties.
cameraRelease();
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
cameraSetup(width, height);
}
* Add ``cameraOpen``, ``cameraRelease`` and ``cameraSetup`` voids as shown below. .. image:: images/dev_OCV_reference.png
:alt: Reference OpenCV library.
:align: center
* Also, don't forget to add the public void ``run()`` as follows: #. Edit your layout file as xml file and pass the following layout there:
.. code-block:: java .. code-block:: xml
:linenos: :linenos:
public void run() { <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
// TODO: loop { getFrame(), processFrame(), drawFrame() } xmlns:tools="http://schemas.android.com/tools"
} xmlns:opencv="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent" >
public boolean cameraOpen() { <org.opencv.android.JavaCameraView
return false; //TODO: open camera android:layout_width="fill_parent"
} android:layout_height="fill_parent"
android:visibility="gone"
android:id="@+id/HelloOpenCvView"
opencv:show_fps="true"
opencv:camera_id="any" />
private void cameraRelease() { </LinearLayout>
// TODO release camera
}
private void cameraSetup(int width, int height) {
// TODO setup camera
}
#. Create a new ``Activity`` :menuselection:`New -> Other -> Android -> Android Activity` and name #. Add the following permissions to the :file:`AndroidManifest.xml` file:
it, for example: *HelloOpenCVActivity*. For this activity define ``onCreate``, ``onResume`` and
``onPause`` voids.
.. code-block:: java .. code-block:: xml
:linenos: :linenos:
public void onCreate (Bundle savedInstanceState) { </application>
super.onCreate(savedInstanceState);
mView = new HelloOpenCVView(this);
setContentView (mView);
}
protected void onPause() { <uses-permission android:name="android.permission.CAMERA"/>
super.onPause();
mView.cameraRelease();
}
protected void onResume() { <uses-feature android:name="android.hardware.camera" android:required="false"/>
super.onResume(); <uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
if( !mView.cameraOpen() ) { <uses-feature android:name="android.hardware.camera.front" android:required="false"/>
// MessageBox and exit app <uses-feature android:name="android.hardware.camera.front.autofocus" android:required="false"/>
AlertDialog ad = new AlertDialog.Builder(this).create();
ad.setCancelable(false); // This blocks the "BACK" button
ad.setMessage("Fatal error: can't open camera!");
ad.setButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
finish();
}
});
ad.show();
}
}
#. Add the following permissions to the :file:`AndroidManifest.xml` file: #. Set application theme in AndroidManifest.xml to hide title and system buttons.
.. code-block:: xml .. code-block:: xml
:linenos: :linenos:
</application> <application
android:icon="@drawable/icon"
android:label="@string/app_name"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
#. Add OpenCV library initialization to your activity. Fix errors by adding requited imports.
.. code-block:: java
:linenos:
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;
}
}
};
<uses-permission android:name="android.permission.CAMERA" /> @Override
<uses-feature android:name="android.hardware.camera" /> public void onResume()
<uses-feature android:name="android.hardware.camera.autofocus" /> {
super.onResume();
#. Reference OpenCV library within your project properties. OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_3, this, mLoaderCallback);
}
.. image:: images/dev_OCV_reference.png
:alt: Reference OpenCV library.
:align: center
#. We now need some code to handle the camera. Update the ``HelloOpenCVView`` class as follows: #. Defines that your activity implements CvViewFrameListener interface and fix activity related
errors by defining missed methods. For this activity define ``onCreate``, ``onDestroy`` and
``onPause`` and implement them according code snippet bellow. Fix errors by adding requited
imports.
.. code-block:: java .. code-block:: java
:linenos: :linenos:
private VideoCapture mCamera; private CameraBridgeViewBase mOpenCvCameraView;
public boolean cameraOpen() {
synchronized (this) {
cameraRelease();
mCamera = new VideoCapture(Highgui.CV_CAP_ANDROID);
if (!mCamera.isOpened()) {
mCamera.release();
mCamera = null;
Log.e("HelloOpenCVView", "Failed to open native camera");
return false;
}
}
return true;
}
public void cameraRelease() { @Override
synchronized(this) { public void onCreate(Bundle savedInstanceState) {
if (mCamera != null) { Log.i(TAG, "called onCreate");
mCamera.release(); super.onCreate(savedInstanceState);
mCamera = null; getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
} setContentView(R.layout.HelloOpenCvLayout);
} mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.HelloOpenCvView);
} mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);
mOpenCvCameraView.setCvCameraViewListener(this);
}
private void cameraSetup(int width, int height) { @Override
synchronized (this) { public void onPause()
if (mCamera != null && mCamera.isOpened()) { {
List<Size> sizes = mCamera.getSupportedPreviewSizes(); super.onPause();
int mFrameWidth = width; if (mOpenCvCameraView != null)
int mFrameHeight = height; mOpenCvCameraView.disableView();
{ // selecting optimal camera preview size }
double minDiff = Double.MAX_VALUE;
for (Size size : sizes) {
if (Math.abs(size.height - height) < minDiff) {
mFrameWidth = (int) size.width;
mFrameHeight = (int) size.height;
minDiff = Math.abs(size.height - height);
}
}
}
mCamera.set(Highgui.CV_CAP_PROP_FRAME_WIDTH, mFrameWidth);
mCamera.set(Highgui.CV_CAP_PROP_FRAME_HEIGHT, mFrameHeight);
}
}
}
#. The last step would be to update the ``run()`` void in ``HelloOpenCVView`` class as follows: public void onDestroy() {
super.onDestroy();
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
}
.. code-block:: java public void onCameraViewStarted(int width, int height) {
:linenos: }
public void run() { public void onCameraViewStopped() {
while (true) { }
Bitmap bmp = null;
synchronized (this) {
if (mCamera == null)
break;
if (!mCamera.grab())
break;
bmp = processFrame(mCamera);
}
if (bmp != null) {
Canvas canvas = getHolder().lockCanvas();
if (canvas != null) {
canvas.drawBitmap(bmp, (canvas.getWidth() - bmp.getWidth()) / 2,
(canvas.getHeight() - bmp.getHeight()) / 2, null);
getHolder().unlockCanvasAndPost(canvas);
}
bmp.recycle();
}
}
}
protected Bitmap processFrame(VideoCapture capture) { public Mat onCameraFrame(Mat inputFrame) {
Mat mRgba = new Mat(); return inputFrame;
capture.retrieve(mRgba, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA); }
//process mRgba
Bitmap bmp = Bitmap.createBitmap(mRgba.cols(), mRgba.rows(), Bitmap.Config.ARGB_8888); #. Run your application on device or emulator.
try {
Utils.matToBitmap(mRgba, bmp); Lets discuss some most important steps. Every Android application with UI must implement Activity
} catch(Exception e) { and View. By the first steps we create blank activity and default view layout. The simplest
Log.e("processFrame", "Utils.matToBitmap() throws an exception: " + e.getMessage()); OpenCV-centric application must implement OpenCV initialization, create its own view to show
bmp.recycle(); preview from camera and implements ``CvViewFrameListener`` interface to get frames from camera and
bmp = null; process it.
}
return bmp; First of all we create our application view using xml layout. Our layout consists of the only
} one full screen component of class ``org.opencv.android.JavaCameraView``. This class is
implemented inside OpenCV library. It is inherited from ``CameraBridgeViewBase``, that extends
``SurfaceView`` and uses standard Android camera API. Alternatively you can use
``org.opencv.android.NativeCameraView`` class, that implements the same interface, but uses
``VideoCapture`` class as camera access back-end. ``opencv:show_fps="true"`` and
``opencv:camera_id="any"`` options enable FPS message and allow to use any camera on device.
Application tries to use back camera first.
After creating layout we need to implement ``Activity`` class. OpenCV initialization process has
been already discussed above. In this sample we use asynchronous initialization. Implementation of
``CvCameraViewListener`` interface allows you to add processing steps after frame grabbing from
camera and before its rendering on screen. The most important function is ``onCameraFrame``. It is
callback function and it is called on retrieving frame from camera. The callback input is frame
from camera. RGBA format is used by default. You can change this behavior by ``SetCaptureFormat``
method of ``View`` class. ``Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA`` and
``Highgui.CV_CAP_ANDROID_GREY_FRAME`` are supported. It expects that function returns RGBA frame
that will be drawn on the screen.

@ -137,7 +137,7 @@ Here you can read tutorials about how to set up your computer to work with the O
================ ================================================= ================ =================================================
|AndroidLogo| **Title:** :ref:`dev_with_OCV_on_Android` |AndroidLogo| **Title:** :ref:`dev_with_OCV_on_Android`
*Compatibility:* > OpenCV 2.4.2 *Compatibility:* > OpenCV 2.4.3
*Author:* |Author_VsevolodG| *Author:* |Author_VsevolodG|

Loading…
Cancel
Save