mirror of https://github.com/opencv/opencv.git
parent
769f61f8c7
commit
a32004f90c
16 changed files with 616 additions and 0 deletions
@ -0,0 +1,8 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<classpath> |
||||||
|
<classpathentry kind="src" path="src"/> |
||||||
|
<classpathentry kind="src" path="gen"/> |
||||||
|
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/> |
||||||
|
<classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/> |
||||||
|
<classpathentry kind="output" path="bin/classes"/> |
||||||
|
</classpath> |
@ -0,0 +1,33 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<projectDescription> |
||||||
|
<name>CameraWriter</name> |
||||||
|
<comment></comment> |
||||||
|
<projects> |
||||||
|
</projects> |
||||||
|
<buildSpec> |
||||||
|
<buildCommand> |
||||||
|
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name> |
||||||
|
<arguments> |
||||||
|
</arguments> |
||||||
|
</buildCommand> |
||||||
|
<buildCommand> |
||||||
|
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name> |
||||||
|
<arguments> |
||||||
|
</arguments> |
||||||
|
</buildCommand> |
||||||
|
<buildCommand> |
||||||
|
<name>org.eclipse.jdt.core.javabuilder</name> |
||||||
|
<arguments> |
||||||
|
</arguments> |
||||||
|
</buildCommand> |
||||||
|
<buildCommand> |
||||||
|
<name>com.android.ide.eclipse.adt.ApkBuilder</name> |
||||||
|
<arguments> |
||||||
|
</arguments> |
||||||
|
</buildCommand> |
||||||
|
</buildSpec> |
||||||
|
<natures> |
||||||
|
<nature>com.android.ide.eclipse.adt.AndroidNature</nature> |
||||||
|
<nature>org.eclipse.jdt.core.javanature</nature> |
||||||
|
</natures> |
||||||
|
</projectDescription> |
@ -0,0 +1,5 @@ |
|||||||
|
#Wed Jun 29 04:36:40 MSD 2011 |
||||||
|
eclipse.preferences.version=1 |
||||||
|
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 |
||||||
|
org.eclipse.jdt.core.compiler.compliance=1.5 |
||||||
|
org.eclipse.jdt.core.compiler.source=1.5 |
@ -0,0 +1,27 @@ |
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
package="org.opencv.test.camerawriter" |
||||||
|
android:versionCode="1" |
||||||
|
android:versionName="1.0" > |
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.CAMERA"/> |
||||||
|
<uses-feature android:name="android.hardware.camera" /> |
||||||
|
<uses-feature android:name="android.hardware.camera.autofocus" /> |
||||||
|
|
||||||
|
<uses-sdk android:minSdkVersion="8" /> |
||||||
|
|
||||||
|
<application |
||||||
|
android:icon="@drawable/ic_launcher" |
||||||
|
android:label="@string/app_name" |
||||||
|
android:theme="@style/AppTheme" > |
||||||
|
<activity |
||||||
|
android:name=".CameraWriterActivity" |
||||||
|
android:label="@string/title_activity_camera_writer" > |
||||||
|
<intent-filter> |
||||||
|
<action android:name="android.intent.action.MAIN" /> |
||||||
|
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" /> |
||||||
|
</intent-filter> |
||||||
|
</activity> |
||||||
|
</application> |
||||||
|
|
||||||
|
</manifest> |
@ -0,0 +1,6 @@ |
|||||||
|
set(sample example-camera-preview) |
||||||
|
|
||||||
|
add_android_project(${sample} "${CMAKE_CURRENT_SOURCE_DIR}" LIBRARY_DEPS ${OpenCV_BINARY_DIR} SDK_TARGET 11 ${ANDROID_SDK_TARGET}) |
||||||
|
if(TARGET ${sample}) |
||||||
|
add_dependencies(opencv_android_examples ${sample}) |
||||||
|
endif() |
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 2.9 KiB |
@ -0,0 +1,13 @@ |
|||||||
|
<RelativeLayout 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" > |
||||||
|
|
||||||
|
<view class="org.opencv.test.camerawriter.OpenCvNativeCameraView" |
||||||
|
android:id="@+id/camera_surface_view" |
||||||
|
android:layout_width = "fill_parent" |
||||||
|
android:layout_height="fill_parent" |
||||||
|
/> |
||||||
|
|
||||||
|
|
||||||
|
</RelativeLayout> |
@ -0,0 +1,6 @@ |
|||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"> |
||||||
|
<item android:id="@+id/menu_settings" |
||||||
|
android:title="@string/menu_settings" |
||||||
|
android:orderInCategory="100" |
||||||
|
android:showAsAction="never" /> |
||||||
|
</menu> |
@ -0,0 +1,5 @@ |
|||||||
|
<resources> |
||||||
|
|
||||||
|
<style name="AppTheme" parent="android:Theme.Holo.Light" /> |
||||||
|
|
||||||
|
</resources> |
@ -0,0 +1,7 @@ |
|||||||
|
<resources> |
||||||
|
|
||||||
|
<string name="app_name">CameraWriter</string> |
||||||
|
<string name="menu_settings">Settings</string> |
||||||
|
<string name="title_activity_camera_writer">CameraWriterActivity</string> |
||||||
|
|
||||||
|
</resources> |
@ -0,0 +1,5 @@ |
|||||||
|
<resources> |
||||||
|
|
||||||
|
<style name="AppTheme" parent="android:Theme.Light" /> |
||||||
|
|
||||||
|
</resources> |
@ -0,0 +1,72 @@ |
|||||||
|
package org.opencv.test.camerawriter; |
||||||
|
|
||||||
|
import org.opencv.android.BaseLoaderCallback; |
||||||
|
import org.opencv.android.LoaderCallbackInterface; |
||||||
|
import org.opencv.android.OpenCVLoader; |
||||||
|
import org.opencv.core.Mat; |
||||||
|
import org.opencv.test.camerawriter.OpenCvCameraBridgeViewBase.CvCameraViewListener; |
||||||
|
|
||||||
|
import android.os.Bundle; |
||||||
|
import android.app.Activity; |
||||||
|
import android.util.Log; |
||||||
|
import android.view.Menu; |
||||||
|
|
||||||
|
public class CameraWriterActivity extends Activity implements CvCameraViewListener { |
||||||
|
|
||||||
|
protected static final String TAG = "CameraWriterActivity"; |
||||||
|
|
||||||
|
|
||||||
|
private OpenCvCameraBridgeViewBase mCameraView; |
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
mCameraView.setMaxFrameSize(640, 480); |
||||||
|
mCameraView.enableView(); |
||||||
|
break; |
||||||
|
default: |
||||||
|
super.onManagerConnected(status); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onCreate(Bundle savedInstanceState) { |
||||||
|
super.onCreate(savedInstanceState); |
||||||
|
setContentView(R.layout.activity_camera_writer); |
||||||
|
|
||||||
|
mCameraView = (OpenCvCameraBridgeViewBase)findViewById(R.id.camera_surface_view); |
||||||
|
mCameraView.setCvCameraViewListener(this); |
||||||
|
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_2, this, mLoaderCallback); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean onCreateOptionsMenu(Menu menu) { |
||||||
|
getMenuInflater().inflate(R.menu.activity_camera_writer, menu); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onCameraViewStarted(int width, int height) { |
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onCameraViewStopped() { |
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Mat onCameraFrame(Mat inputFrame) { |
||||||
|
return inputFrame; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,301 @@ |
|||||||
|
package org.opencv.test.camerawriter; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import org.opencv.android.Utils; |
||||||
|
import org.opencv.core.Mat; |
||||||
|
import org.opencv.core.Size; |
||||||
|
import org.opencv.highgui.Highgui; |
||||||
|
import org.opencv.highgui.VideoCapture; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.graphics.Bitmap; |
||||||
|
import android.graphics.Canvas; |
||||||
|
import android.util.AttributeSet; |
||||||
|
import android.util.Log; |
||||||
|
import android.view.SurfaceHolder; |
||||||
|
import android.view.SurfaceView; |
||||||
|
|
||||||
|
/** |
||||||
|
* This is a basic class, implementing the interaction with Camera and OpenCV library. |
||||||
|
* The main responsibility of it - is to control when camera can be enabled, process the frame, |
||||||
|
* call external listener to make any adjustments to the frame and then draw the resulting |
||||||
|
* frame to the screen. |
||||||
|
* The clients shall implement CvCameraViewListener |
||||||
|
*/ |
||||||
|
public abstract class OpenCvCameraBridgeViewBase extends SurfaceView implements SurfaceHolder.Callback { |
||||||
|
|
||||||
|
private static final int MAX_UNSPECIFIED = -1; |
||||||
|
|
||||||
|
protected int mFrameWidth; |
||||||
|
protected int mFrameHeight; |
||||||
|
|
||||||
|
protected int mMaxHeight; |
||||||
|
protected int mMaxWidth; |
||||||
|
|
||||||
|
private Bitmap mCacheBitmap; |
||||||
|
|
||||||
|
|
||||||
|
public OpenCvCameraBridgeViewBase(Context context, AttributeSet attrs) { |
||||||
|
super(context,attrs); |
||||||
|
getHolder().addCallback(this); |
||||||
|
mMaxWidth = MAX_UNSPECIFIED; |
||||||
|
mMaxHeight = MAX_UNSPECIFIED; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public interface CvCameraViewListener { |
||||||
|
/** |
||||||
|
* This method is invoked when camera preview has started. After this method is invoked |
||||||
|
* the frames will start to be delivered to client via the onCameraFrame() callback. |
||||||
|
* @param width - the width of the frames that will be delivered |
||||||
|
* @param height - the height of the frames that will be delivered |
||||||
|
*/ |
||||||
|
public void onCameraViewStarted(int width, int height); |
||||||
|
|
||||||
|
/** |
||||||
|
* This method is invoked when camera preview has been stopped for some reason. |
||||||
|
* No frames will be delivered via onCameraFrame() callback after this method is called. |
||||||
|
*/ |
||||||
|
public void onCameraViewStopped(); |
||||||
|
|
||||||
|
/** |
||||||
|
* This method is invoked when delivery of the frame needs to be done. |
||||||
|
* The returned values - is a modified frame which needs to be displayed on the screen. |
||||||
|
*/ |
||||||
|
public Mat onCameraFrame(Mat inputFrame); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private static final int STOPPED = 0; |
||||||
|
private static final int STARTED = 1; |
||||||
|
private static final String TAG = "SampleCvBase"; |
||||||
|
|
||||||
|
private CvCameraViewListener mListener; |
||||||
|
private int mState = STOPPED; |
||||||
|
|
||||||
|
private boolean mEnabled; |
||||||
|
private boolean mSurfaceExist; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private Object mSyncObject = new Object(); |
||||||
|
|
||||||
|
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { |
||||||
|
synchronized(mSyncObject) { |
||||||
|
if (!mSurfaceExist) { |
||||||
|
mSurfaceExist = true; |
||||||
|
checkCurrentState(); |
||||||
|
} else { |
||||||
|
/** Surface changed. We need to stop camera and restart with new parameters */ |
||||||
|
/* Pretend that old surface has been destroyed */ |
||||||
|
mSurfaceExist = false; |
||||||
|
checkCurrentState(); |
||||||
|
/* Now use new surface. Say we have it now */ |
||||||
|
mSurfaceExist = true; |
||||||
|
checkCurrentState(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void surfaceCreated(SurfaceHolder holder) { |
||||||
|
/* Do nothing. Wait until surfaceChanged delivered */ |
||||||
|
} |
||||||
|
|
||||||
|
public void surfaceDestroyed(SurfaceHolder holder) { |
||||||
|
synchronized(mSyncObject) { |
||||||
|
mSurfaceExist = false; |
||||||
|
checkCurrentState(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* This method is provided for clients, so they can enable the camera connection. |
||||||
|
* The actuall onCameraViewStarted callback will be delivered only after both this method is called and surface is available |
||||||
|
*/ |
||||||
|
public void enableView() { |
||||||
|
synchronized(mSyncObject) { |
||||||
|
mEnabled = true; |
||||||
|
checkCurrentState(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This method is provided for clients, so they can disable camera connection and stop |
||||||
|
* the delivery of frames eventhough the surfaceview itself is not destroyed and still stays on the scren |
||||||
|
*/ |
||||||
|
public void disableView() { |
||||||
|
synchronized(mSyncObject) { |
||||||
|
mEnabled = false; |
||||||
|
checkCurrentState(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void setCvCameraViewListener(CvCameraViewListener listener) { |
||||||
|
mListener = listener; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This method sets the maximum size that camera frame is allowed to be. When selecting |
||||||
|
* size - the biggest size which less or equal the size set will be selected. |
||||||
|
* As an example - we set setMaxFrameSize(200,200) and we have 176x152 and 320x240 sizes. The |
||||||
|
* preview frame will be selected with 176x152 size. |
||||||
|
* This method is usefull when need to restrict the size of preview frame for some reason (for example for video recording) |
||||||
|
* @param maxWidth - the maximum width allowed for camera frame. |
||||||
|
* @param maxHeight - the maxumum height allowed for camera frame |
||||||
|
*/ |
||||||
|
public void setMaxFrameSize(int maxWidth, int maxHeight) { |
||||||
|
mMaxWidth = maxWidth; |
||||||
|
mMaxHeight = maxHeight; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Called when mSyncObject lock is held |
||||||
|
*/ |
||||||
|
private void checkCurrentState() { |
||||||
|
int targetState; |
||||||
|
|
||||||
|
if (mEnabled && mSurfaceExist) { |
||||||
|
targetState = STARTED; |
||||||
|
} else { |
||||||
|
targetState = STOPPED; |
||||||
|
} |
||||||
|
|
||||||
|
if (targetState != mState) { |
||||||
|
/* The state change detected. Need to exit the current state and enter target state */ |
||||||
|
processExitState(mState); |
||||||
|
mState = targetState; |
||||||
|
processEnterState(mState); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void processEnterState(int state) { |
||||||
|
switch(state) { |
||||||
|
case STARTED: |
||||||
|
onEnterStartedState(); |
||||||
|
if (mListener != null) { |
||||||
|
mListener.onCameraViewStarted(mFrameWidth, mFrameHeight); |
||||||
|
} |
||||||
|
break; |
||||||
|
case STOPPED: |
||||||
|
onEnterStoppedState(); |
||||||
|
if (mListener != null) { |
||||||
|
mListener.onCameraViewStopped(); |
||||||
|
} |
||||||
|
break; |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private void processExitState(int state) { |
||||||
|
switch(state) { |
||||||
|
case STARTED: |
||||||
|
onExitStartedState(); |
||||||
|
break; |
||||||
|
case STOPPED: |
||||||
|
onExitStoppedState(); |
||||||
|
break; |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
private void onEnterStoppedState() { |
||||||
|
/* nothing to do */ |
||||||
|
} |
||||||
|
|
||||||
|
private void onExitStoppedState() { |
||||||
|
/* nothing to do */ |
||||||
|
} |
||||||
|
|
||||||
|
private void onEnterStartedState() { |
||||||
|
|
||||||
|
connectCamera(getWidth(), getHeight()); |
||||||
|
/* Now create cahe Bitmap */ |
||||||
|
mCacheBitmap = Bitmap.createBitmap(mFrameWidth, mFrameHeight, Bitmap.Config.ARGB_8888); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private void onExitStartedState() { |
||||||
|
|
||||||
|
disconnectCamera(); |
||||||
|
if (mCacheBitmap != null) { |
||||||
|
mCacheBitmap.recycle(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* This method shall be called by the subclasses when they have valid |
||||||
|
* object and want it to be delivered to external client (via callback) and |
||||||
|
* then displayed on the screen. |
||||||
|
* @param frame - the current frame to be delivered |
||||||
|
*/ |
||||||
|
protected void deliverAndDrawFrame(Mat frame) { |
||||||
|
Mat modified; |
||||||
|
|
||||||
|
synchronized(mSyncObject) { |
||||||
|
if (mListener != null) { |
||||||
|
modified = mListener.onCameraFrame(frame); |
||||||
|
} else { |
||||||
|
modified = frame; |
||||||
|
} |
||||||
|
|
||||||
|
if (modified != null) { |
||||||
|
Utils.matToBitmap(modified, mCacheBitmap); |
||||||
|
} |
||||||
|
|
||||||
|
if (mCacheBitmap != null) { |
||||||
|
Canvas canvas = getHolder().lockCanvas(); |
||||||
|
if (canvas != null) { |
||||||
|
canvas.drawBitmap(mCacheBitmap, (canvas.getWidth() - mCacheBitmap.getWidth()) / 2, (canvas.getHeight() - mCacheBitmap.getHeight()) / 2, null); |
||||||
|
getHolder().unlockCanvasAndPost(canvas); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This method is invoked shall perform concrete operation to initialize the camera. |
||||||
|
* CONTRACT: as a result of this method variables mFrameWidth and mFrameHeight MUST be |
||||||
|
* initialized with the size of the Camera frames that will be delivered to external processor. |
||||||
|
* @param width - the width of this SurfaceView |
||||||
|
* @param height - the height of this SurfaceView |
||||||
|
*/ |
||||||
|
protected abstract void connectCamera(int width, int height); |
||||||
|
|
||||||
|
/** |
||||||
|
* Disconnects and release the particular camera object beeing connected to this surface view. |
||||||
|
* Called when syncObject lock is held |
||||||
|
*/ |
||||||
|
protected abstract void disconnectCamera(); |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* This helper method can be called by subclasses to select camera preview size. |
||||||
|
* It goes over the list of the supported preview sizes and selects the maximum one which |
||||||
|
* fits both values set via setMaxFrameSize() and surface frame allocated for this view |
||||||
|
* @param supportedSizes |
||||||
|
* @param surfaceWidth |
||||||
|
* @param surfaceHeight |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
protected Size calculateCameraFrameSize(List<Size> supportedSizes, int surfaceWidth, int surfaceHeight) { |
||||||
|
int calcWidth = 0; |
||||||
|
int calcHeight = 0; |
||||||
|
|
||||||
|
int maxAllowedWidth = (mMaxWidth != MAX_UNSPECIFIED && mMaxWidth < surfaceWidth)? mMaxWidth : surfaceWidth; |
||||||
|
int maxAllowedHeight = (mMaxHeight != MAX_UNSPECIFIED && mMaxHeight < surfaceHeight)? mMaxHeight : surfaceHeight; |
||||||
|
|
||||||
|
for (Size size : supportedSizes) { |
||||||
|
if (size.width <= maxAllowedWidth && size.height <= maxAllowedHeight) { |
||||||
|
if (size.width >= calcWidth && size.height >= calcHeight) { |
||||||
|
calcWidth = (int) size.width; |
||||||
|
calcHeight = (int) size.height; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return new Size(calcWidth, calcHeight); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,126 @@ |
|||||||
|
package org.opencv.test.camerawriter; |
||||||
|
|
||||||
|
import org.opencv.android.Utils; |
||||||
|
import org.opencv.core.Mat; |
||||||
|
import org.opencv.core.Size; |
||||||
|
import org.opencv.highgui.Highgui; |
||||||
|
import org.opencv.highgui.VideoCapture; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.graphics.Bitmap; |
||||||
|
import android.graphics.Canvas; |
||||||
|
import android.util.AttributeSet; |
||||||
|
import android.util.Log; |
||||||
|
|
||||||
|
/** |
||||||
|
* This class is an implementation of a bridge between SurfaceView and native OpenCV camera. |
||||||
|
* Due to the big amount of work done, by the base class this child is only responsible |
||||||
|
* for creating camera, destroying camera and delivering frames while camera is enabled |
||||||
|
*/ |
||||||
|
public class OpenCvNativeCameraView extends OpenCvCameraBridgeViewBase { |
||||||
|
|
||||||
|
public static final String TAG = "OpenCvNativeCameraView"; |
||||||
|
private boolean mStopThread; |
||||||
|
private Thread mThread; |
||||||
|
private VideoCapture mCamera; |
||||||
|
|
||||||
|
|
||||||
|
public OpenCvNativeCameraView(Context context, AttributeSet attrs) { |
||||||
|
super(context, attrs); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
protected void connectCamera(int width, int height) { |
||||||
|
|
||||||
|
/* 1. We need to instantiate camera |
||||||
|
* 2. We need to start thread which will be getting frames |
||||||
|
*/ |
||||||
|
/* First step - initialize camera connection */ |
||||||
|
initializeCamera(getWidth(), getHeight()); |
||||||
|
|
||||||
|
/* now we can start update thread */ |
||||||
|
mThread = new Thread(new CameraWorker(getWidth(), getHeight())); |
||||||
|
mThread.start(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void disconnectCamera() { |
||||||
|
/* 1. We need to stop thread which updating the frames |
||||||
|
* 2. Stop camera and release it |
||||||
|
*/ |
||||||
|
try { |
||||||
|
mStopThread = true; |
||||||
|
mThread.join(); |
||||||
|
} catch (InterruptedException e) { |
||||||
|
e.printStackTrace(); |
||||||
|
} finally { |
||||||
|
mThread = null; |
||||||
|
mStopThread = false; |
||||||
|
} |
||||||
|
|
||||||
|
/* Now release camera */ |
||||||
|
releaseCamera(); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private void initializeCamera(int width, int height) { |
||||||
|
mCamera = new VideoCapture(Highgui.CV_CAP_ANDROID); |
||||||
|
//TODO: improve error handling
|
||||||
|
|
||||||
|
java.util.List<Size> sizes = mCamera.getSupportedPreviewSizes(); |
||||||
|
|
||||||
|
/* Select the size that fits surface considering maximum size allowed */ |
||||||
|
Size frameSize = calculateCameraFrameSize(sizes, width, height); |
||||||
|
|
||||||
|
|
||||||
|
double frameWidth = frameSize.width; |
||||||
|
double frameHeight = frameSize.height; |
||||||
|
|
||||||
|
|
||||||
|
mCamera.set(Highgui.CV_CAP_PROP_FRAME_WIDTH, frameWidth); |
||||||
|
mCamera.set(Highgui.CV_CAP_PROP_FRAME_HEIGHT, frameHeight); |
||||||
|
|
||||||
|
mFrameWidth = (int)frameWidth; |
||||||
|
mFrameHeight = (int)frameHeight; |
||||||
|
|
||||||
|
Log.i(TAG, "Selected camera frame size = (" + mFrameWidth + ", " + mFrameHeight + ")"); |
||||||
|
} |
||||||
|
|
||||||
|
private void releaseCamera() { |
||||||
|
if (mCamera != null) { |
||||||
|
mCamera.release(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private class CameraWorker implements Runnable { |
||||||
|
|
||||||
|
private Mat mRgba = new Mat(); |
||||||
|
private int mWidth; |
||||||
|
private int mHeight; |
||||||
|
|
||||||
|
CameraWorker(int w, int h) { |
||||||
|
mWidth = w; |
||||||
|
mHeight = h; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void run() { |
||||||
|
Mat modified; |
||||||
|
|
||||||
|
|
||||||
|
do { |
||||||
|
if (!mCamera.grab()) { |
||||||
|
Log.e(TAG, "Camera frame grab failed"); |
||||||
|
break; |
||||||
|
} |
||||||
|
mCamera.retrieve(mRgba, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA); |
||||||
|
|
||||||
|
deliverAndDrawFrame(mRgba); |
||||||
|
|
||||||
|
} while (!mStopThread); |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
Loading…
Reference in new issue