@ -270,214 +270,107 @@ It will be capable of accessing camera output, processing it and displaying the
#. Set name, target, package and minSDKVersion accordingly.
#. Create a new class (*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.
* It also should implement * SurfaceHolder.Callback*, * Runnable*.
#. Edit *HelloOpenCVView* class.
* Add an * import* line for * android.content.context*.
* Modify autogenerated stubs: * HelloOpenCVView*, * surfaceCreated*, * surfaceDestroyed* and * surfaceChanged*.
#. Add the following permissions to the AndroidManifest.xml file:
.. code-block :: java
.. code-block :: xml
:linenos:
package com.hello.opencv.test;
</application>
import android.content.Context;
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
public class HelloOpenCVView extends SurfaceView implements Callback, Runnable {
#. Reference OpenCV library within your project properties.
public HelloOpenCVView(Context context) {
super(context);
getHolder().addCallback(this);
}
.. image :: images/dev_OCV_reference.png
:alt: Reference OpenCV library.
:align: center
public void surfaceCreated(SurfaceHolder holder) {
(new Thread(this)).start();
}
#. Create new view layout for your application, lets name it hello_opencv.xml, and add the following to it:
public void surfaceDestroyed(SurfaceHolder holder) {
cameraRelease();
}
.. code-block :: xml
:linenos:
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
cameraSetup(width, height);
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
//...
<org.opencv.android.JavaCameraView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:visibility="gone"
android:id="@+id/java_surface_view" />
* Add * cameraOpen*, * cameraRelease* and * cameraSetup* voids as shown below.
</LinearLayout>
* Also, don't forget to add the public void * run()* as follows:
#. Remove default auto generated layout, if exists.
#. Create a new *Activity* (*New -> Other -> Android -> Android Activity* ) and name it, for example: *HelloOpenCVActivity* . Add *CvCameraViewListener* interface to *implementes* section of *HelloOpenCVActivity* class. Add the following code to activity implementation:
.. code-block :: java
:linenos:
public void run() {
// TODO: loop { getFrame(), processFrame(), drawFrame() }
}
public class Sample1Java extends Activity implements CvCameraViewListener {
public boolean cameraOpen() {
return false; //TODO: open camera
}
private CameraBridgeViewBase mOpenCvCameraView;
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);
}
private void cameraSetup(int width, int height) {
// TODO setup camera
}
};
#. Create a new *Activity* (*New -> Other -> Android -> Android Activity* ) and name it, for example: *HelloOpenCVActivity* . For this activity define *onCreate* , *onResume* and *onPause* voids.
.. code-block :: java
:linenos:
/** Called when the activity is first created. * /
@Override
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "called onCreate");
super.onCreate(savedInstanceState);
mView = new HelloOpenCVView(this);
setContentView (mView);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.hello_opencv);
mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.java_surface_view);
mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);
mOpenCvCameraView.setCvCameraViewListener(this);
}
protected void onPause() {
@Override
public void onPause()
{
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
super.onPause();
mView.cameraRelease();
}
protected void onResume() {
@Override
public 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();
}
}
#. Add the following permissions to the 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;
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_3, this, mLoaderCallback);
}
public void cameraRelease() {
synchronized(this) {
if (mCamera != null) {
mCamera.release();
mCamera = null;
}
}
}
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 void onDestroy() {
super.onDestroy();
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
}
#. The last step would be to update the *run()* void in *HelloOpenCVView* class as follows:
.. code-block :: java
:linenos:
public void run() {
while (true) {
Bitmap bmp = null;
synchronized (this) {
if (mCamera == null)
break;
if (!mCamera.grab())
break;
bmp = processFrame(mCamera);
public void onCameraViewStarted(int width, int height) {
}
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();
}
}
public void onCameraViewStopped() {
}
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;
public Mat onCameraFrame(Mat inputFrame) {
return inputFrame;
}
return bmp;
}