Tutorial for Android synchronized with actual application framework.

pull/452/head
Alexander Smorkalov 12 years ago
parent 03f7d2f1ca
commit c7e7b77093
  1. 303
      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,18 +78,16 @@ See the "15-puzzle" OpenCV sample for details.
.. code-block:: java
:linenos:
public class MyActivity extends Activity implements HelperCallbackInterface
{
private BaseLoaderCallback mOpenCVCallBack = new BaseLoaderCallback(this) {
public class Sample1Java extends Activity implements CvCameraViewListener {
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS:
{
Log.i(TAG, "OpenCV loaded successfully");
// Create and set View
mView = new puzzle15View(mAppContext);
setContentView(mView);
mOpenCvCameraView.enableView();
} break;
default:
{
@ -99,18 +97,14 @@ See the "15-puzzle" OpenCV sample for details.
}
};
/** Call on every application resume **/
@Override
protected void onResume()
public 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");
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_3, this, mLoaderCallback);
}
...
}
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.
#. 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.
#. Set name, target, package and ``minSDKVersion`` accordingly. The minimal SDK version for build
with OpenCV4Android SDK is 11. Minimal device API Level (for application manifest) is 8.
#. Create a new class :menuselection:`File -> New -> Class`. Name it for example:
*HelloOpenCVView*.
#. Allow Eclipse to create default activity. Lets name the activity ``HelloOpenCvActivity``.
.. image:: images/dev_OCV_new_class.png
:alt: Add a new class.
:align: center
#. Choose Blank Activity with full screen layout. Lets name the layout ``HelloOpenCvLayout``.
* It should extend ``SurfaceView`` class.
* It also should implement ``SurfaceHolder.Callback``, ``Runnable``.
#. Import OpenCV library project to your workspace.
#. Edit ``HelloOpenCVView`` class.
#. Reference OpenCV library within your project properties.
* Add an ``import`` line for ``android.content.context``.
.. image:: images/dev_OCV_reference.png
:alt: Reference OpenCV library.
:align: center
* Modify autogenerated stubs: ``HelloOpenCVView``, ``surfaceCreated``, ``surfaceDestroyed`` and
``surfaceChanged``.
#. Edit your layout file as xml file and pass the following layout there:
.. code-block:: java
.. code-block:: xml
:linenos:
package com.hello.opencv.test;
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
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" >
import android.content.Context;
<org.opencv.android.JavaCameraView
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" />
public class HelloOpenCVView extends SurfaceView implements Callback, Runnable {
</LinearLayout>
public HelloOpenCVView(Context context) {
super(context);
getHolder().addCallback(this);
}
#. Add the following permissions to the :file:`AndroidManifest.xml` file:
public void surfaceCreated(SurfaceHolder holder) {
(new Thread(this)).start();
}
.. code-block:: xml
:linenos:
public void surfaceDestroyed(SurfaceHolder holder) {
cameraRelease();
}
</application>
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
cameraSetup(width, height);
}
<uses-permission android:name="android.permission.CAMERA"/>
* Add ``cameraOpen``, ``cameraRelease`` and ``cameraSetup`` voids as shown below.
<uses-feature android:name="android.hardware.camera" android:required="false"/>
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
<uses-feature android:name="android.hardware.camera.front" android:required="false"/>
<uses-feature android:name="android.hardware.camera.front.autofocus" android:required="false"/>
* Also, don't forget to add the public void ``run()`` as follows:
#. Set application theme in AndroidManifest.xml to hide title and system buttons.
.. code-block:: java
.. code-block:: xml
:linenos:
public void run() {
// TODO: loop { getFrame(), processFrame(), drawFrame() }
}
<application
android:icon="@drawable/icon"
android:label="@string/app_name"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
public boolean cameraOpen() {
return false; //TODO: open camera
}
#. Add OpenCV library initialization to your activity. Fix errors by adding requited imports.
.. code-block:: java
:linenos:
private void cameraRelease() {
// TODO release camera
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;
}
}
};
private void cameraSetup(int width, int height) {
// TODO setup camera
@Override
public void onResume()
{
super.onResume();
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_3, this, mLoaderCallback);
}
#. Create a new ``Activity`` :menuselection:`New -> Other -> Android -> Android Activity` and name
it, for example: *HelloOpenCVActivity*. For this activity define ``onCreate``, ``onResume`` and
``onPause`` voids.
#. 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
:linenos:
private CameraBridgeViewBase mOpenCvCameraView;
@Override
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "called onCreate");
super.onCreate(savedInstanceState);
mView = new HelloOpenCVView(this);
setContentView (mView);
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);
}
protected void onPause() {
@Override
public void onPause()
{
super.onPause();
mView.cameraRelease();
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
}
protected void onResume() {
super.onResume();
if( !mView.cameraOpen() ) {
// MessageBox and exit app
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();
}
public void onDestroy() {
super.onDestroy();
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
}
#. Add the following permissions to the :file:`AndroidManifest.xml` file:
.. code-block:: xml
:linenos:
</application>
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
#. Reference OpenCV library within your project properties.
.. 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:
.. code-block:: java
:linenos:
private VideoCapture mCamera;
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 onCameraViewStarted(int width, int height) {
}
public void cameraRelease() {
synchronized(this) {
if (mCamera != null) {
mCamera.release();
mCamera = null;
}
}
public void onCameraViewStopped() {
}
private void cameraSetup(int width, int height) {
synchronized (this) {
if (mCamera != null && mCamera.isOpened()) {
List<Size> sizes = mCamera.getSupportedPreviewSizes();
int mFrameWidth = width;
int mFrameHeight = height;
{ // 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);
}
}
public Mat onCameraFrame(Mat inputFrame) {
return inputFrame;
}
#. The last step would be to update the ``run()`` void in ``HelloOpenCVView`` class as follows:
#. Run your application on device or emulator.
.. code-block:: java
:linenos:
public void run() {
while (true) {
Bitmap bmp = null;
synchronized (this) {
if (mCamera == null)
break;
if (!mCamera.grab())
break;
Lets discuss some most important steps. Every Android application with UI must implement Activity
and View. By the first steps we create blank activity and default view layout. The simplest
OpenCV-centric application must implement OpenCV initialization, create its own view to show
preview from camera and implements ``CvViewFrameListener`` interface to get frames from camera and
process it.
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);
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.
}
bmp.recycle();
}
}
}
protected Bitmap processFrame(VideoCapture capture) {
Mat mRgba = new Mat();
capture.retrieve(mRgba, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA);
//process mRgba
Bitmap bmp = Bitmap.createBitmap(mRgba.cols(), mRgba.rows(), Bitmap.Config.ARGB_8888);
try {
Utils.matToBitmap(mRgba, bmp);
} catch(Exception e) {
Log.e("processFrame", "Utils.matToBitmap() throws an exception: " + e.getMessage());
bmp.recycle();
bmp = null;
}
return bmp;
}
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`
*Compatibility:* > OpenCV 2.4.2
*Compatibility:* > OpenCV 2.4.3
*Author:* |Author_VsevolodG|

Loading…
Cancel
Save