Merge pull request #24692 from savuor:doc_android_tutorial_camera

Android camera tutorial update #24692

This PR extends the OpenCV 4 Android tutorial by a simple camera app based on existing code.
This part was accidentally removed during the #24653 preparation, this PR restores it and aligns it to the latest Android Studio.

### Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

- [x] I agree to contribute to the project under Apache 2 License.
- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [x] The PR is proposed to the proper branch
- [x] There is a reference to the original bug report and related work
- [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
      Patch to opencv_extra has the same branch name.
- [x] The feature is well documented and sample code can be built with the project CMake
pull/24696/head
Rostislav Vasilikhin 12 months ago committed by GitHub
parent 850be1e087
commit 42ab298f01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      doc/tutorials/introduction/android_binary_package/android_dev_intro.markdown
  2. 92
      doc/tutorials/introduction/android_binary_package/dev_with_OCV_on_Android.markdown
  3. BIN
      doc/tutorials/introduction/android_binary_package/images/camera_permissions.png
  4. BIN
      doc/tutorials/introduction/android_binary_package/images/delete_text.png
  5. BIN
      doc/tutorials/introduction/android_binary_package/images/usb_device_connect_13.png
  6. 2
      samples/android/tutorial-1-camerapreview/gradle/AndroidManifest.xml
  7. 2
      samples/android/tutorial-1-camerapreview/res/layout/tutorial1_surface_view.xml
  8. 9
      samples/android/tutorial-1-camerapreview/src/org/opencv/samples/tutorial1/Tutorial1Activity.java

@ -55,7 +55,7 @@ Here's how to get a ready to work environment:
2. Extract the tar.gz archive
3. Follow the instructions in `Install-Linux-tar.txt`: open `android-studio/bin` folder in terminal and run `./studio.sh`
4. Perform standard installation through GUI
5. Optionally you can add a shortcut on a desktop for a quick access by clicking menu Tools -> Create desktop entry. The menu appears after any project is created or opened.
5. Optionally you can add a shortcut on a desktop for a quick access by clicking menu ***Tools -> Create desktop entry***. The menu appears after any project is created or opened.
2. Install fresh Android SDK and NDK:
1. Open SDK manager in Android Studio (***Customize -> All Settings -> Languages & Frameworks -> Android SDK***)

@ -29,6 +29,8 @@ If you encounter any error after thoroughly following these steps, feel free to
Hello OpenCV sample
-------------------
In this section we're gonna create a simple app that does nothing but OpenCV loading. In next section we'll extend it to support camera.
In addition to this instruction you can use some video guide, for example [this one](https://www.youtube.com/watch?v=bR7lL886-uc&ab_channel=ProgrammingHut)
1. Open Android Studio and create empty project by choosing ***Empty Views Activity***
@ -75,7 +77,6 @@ In addition to this instruction you can use some video guide, for example [this
6. OpenCV project uses `aidl` and `buildConfig` features. Please enable them in
`MyApplication/OpenCV/build.gradle` file to `android` block:
@code{.gradle}
buildFeatures{
aidl true
@ -93,17 +94,19 @@ In addition to this instruction you can use some video guide, for example [this
7. Add the module to the project:
- Click ***File -> Project structure... -> Dependencies -> All modules -> + (Add Dependency button) -> Module dependency***
- Choose `app`
- Select `OpenCV`
![](images/add_module_1.png)
- Choose `app`
![](images/add_module_2.png)
- Select `OpenCV`
![](images/add_module_3.png)
8. Before using any OpenCV function you have to load the library first. If you application includes other OpenCV-dependent native libraries you should load them ***after*** OpenCV initialization.
Library is loaded at app start:
Add the folowing code to load the library at app start:
@snippet samples/android/tutorial-1-camerapreview/src/org/opencv/samples/tutorial1/Tutorial1Activity.java ocv_loader_init
Like this:
![](images/sample_code.png)
@ -111,3 +114,84 @@ In addition to this instruction you can use some video guide, for example [this
9. Choose a device to check the sample on and run the code by pressing `run` button
![](images/run_app.png)
Camera view sample
------------------
In this section we'll extend our empty OpenCV app created in the previous section to support camera. We'll take camera frames and display them on the screen.
1. Tell a system that we need camera permissions.
Add the following code to the file `MyApplication/app/src/main/AndroidManifest.xml`:
@snippet samples/android/tutorial-1-camerapreview/gradle/AndroidManifest.xml camera_permissions
Like this:
![](images/camera_permissions.png)
2. Go to `activity_main.xml` layout and delete TextView with text "Hello World!"
![](images/delete_text.png)
This can also be done in Code or Split mode by removing the `TextView` block from XML file.
3. Add camera view to the layout:
1. Add a scheme into layout description:
@code{.xml}
xmlns:opencv="http://schemas.android.com/apk/res-auto"
@endcode
2. Replace `TextView` with `org.opencv.android.JavaCameraView` widget:
@snippet /samples/android/tutorial-1-camerapreview/res/layout/tutorial1_surface_view.xml camera_view
3. If you get a layout warning replace `fill_parent` values by `match_parent` for `android:layout_width` and `android:layout_height` properties
You'll get a code like this:
@include /samples/android/tutorial-1-camerapreview/res/layout/tutorial1_surface_view.xml
4. Inherit the main class from `org.opencv.android.CameraActivity`. CameraActivity implements
camera perimission requiest and some other utilities needed for CV application. Methods we're
interested in to override are `onCreate`, `onDestroy`, `onPause`, `onResume` and `getCameraViewList`
5. Implement the interface `org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2`
`onCameraFrame` method should return the `Mat` object with content for render.
The sample just returns camera frame for preview: `return inputFrame.rgba();`
6. Allocate `org.opencv.android.CameraBridgeViewBase` object:
- It should be created at app start (`onCreate` method) and this class should be set as a listener
- At pause/resume (`onPause`, `onResume` methods) it should be disabled/enabled
- Should be disabled at app finish (`onDestroy` method)
- Should be returned in `getCameraViewList`
7. Optionally you can forbid the phone to dim screen or lock:
@snippet samples/android/tutorial-1-camerapreview/src/org/opencv/samples/tutorial1/Tutorial1Activity.java keep_screen
Finally you'll get source code similar to this:
@include samples/android/tutorial-1-camerapreview/src/org/opencv/samples/tutorial1/Tutorial1Activity.java
This is it! Now you can run the code on your device to check it.
Let's 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 perform OpenCV
initialization, create a view to show preview from camera and implement `CvCameraViewListener2` interface
to get frames from camera and process them.
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 OpenCV class is inherited from
`CameraBridgeViewBase` that extends `SurfaceView` and under the hood uses standard Android camera API.
The `CvCameraViewListener2` interface lets you add some processing steps after the frame is grabbed from
the camera and before it's rendered on the screen. The most important method is `onCameraFrame`. This is
a callback function and it's called on retrieving frame from camera. It expects that `onCameraFrame`
function returns RGBA frame that will be drawn on the screen.
The callback passes a frame from camera to our class as an object of `CvCameraViewFrame` class.
This object has `rgba()` and `gray()` methods that let a user get colored or one-channel grayscale
frame as a `Mat` class object.
@note Do not save or use `CvCameraViewFrame` object out of `onCameraFrame` callback. This object does
not have its own state and its behavior outside the callback is unpredictable!

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

@ -27,11 +27,13 @@
android:largeScreens="true"
android:anyDensity="true" />
//! [camera_permissions]
<uses-permission android:name="android.permission.CAMERA"/>
<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"/>
//! [camera_permissions]
</manifest>

@ -4,6 +4,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- [camera_view] -->
<org.opencv.android.JavaCameraView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
@ -11,5 +12,6 @@
android:id="@+id/tutorial1_activity_java_surface_view"
opencv:show_fps="true"
opencv:camera_id="any" />
<!-- [camera_view] -->
</FrameLayout>

@ -9,7 +9,6 @@ import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;
import android.os.Bundle;
import android.util.Log;
import android.view.MenuItem;
import android.view.SurfaceView;
import android.view.WindowManager;
import android.widget.Toast;
@ -21,8 +20,6 @@ public class Tutorial1Activity extends CameraActivity implements CvCameraViewLis
private static final String TAG = "OCVSample::Activity";
private CameraBridgeViewBase mOpenCvCameraView;
private boolean mIsJavaCamera = true;
private MenuItem mItemSwitchCamera = null;
public Tutorial1Activity() {
Log.i(TAG, "Instantiated new " + this.getClass());
@ -44,7 +41,9 @@ public class Tutorial1Activity extends CameraActivity implements CvCameraViewLis
}
//! [ocv_loader_init]
//! [keep_screen]
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
//! [keep_screen]
setContentView(R.layout.tutorial1_surface_view);
@ -76,18 +75,22 @@ public class Tutorial1Activity extends CameraActivity implements CvCameraViewLis
return Collections.singletonList(mOpenCvCameraView);
}
@Override
public void onDestroy() {
super.onDestroy();
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
}
@Override
public void onCameraViewStarted(int width, int height) {
}
@Override
public void onCameraViewStopped() {
}
@Override
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
return inputFrame.rgba();
}

Loading…
Cancel
Save