mirror of
https://gitcode.com/gh_mirrors/es/esp32-opencv.git
synced 2025-08-14 01:57:43 +08:00
initial commit
This commit is contained in:
@ -0,0 +1,391 @@
|
||||
package org.opencv.android;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.opencv.core.Core;
|
||||
import org.opencv.engine.OpenCVEngineInterface;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.net.Uri;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
class AsyncServiceHelper
|
||||
{
|
||||
public static boolean initOpenCV(String Version, final Context AppContext,
|
||||
final LoaderCallbackInterface Callback)
|
||||
{
|
||||
AsyncServiceHelper helper = new AsyncServiceHelper(Version, AppContext, Callback);
|
||||
Intent intent = new Intent("org.opencv.engine.BIND");
|
||||
intent.setPackage("org.opencv.engine");
|
||||
if (AppContext.bindService(intent, helper.mServiceConnection, Context.BIND_AUTO_CREATE))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
AppContext.unbindService(helper.mServiceConnection);
|
||||
InstallService(AppContext, Callback);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected AsyncServiceHelper(String Version, Context AppContext, LoaderCallbackInterface Callback)
|
||||
{
|
||||
mOpenCVersion = Version;
|
||||
mUserAppCallback = Callback;
|
||||
mAppContext = AppContext;
|
||||
}
|
||||
|
||||
protected static final String TAG = "OpenCVManager/Helper";
|
||||
protected static final int MINIMUM_ENGINE_VERSION = 2;
|
||||
protected OpenCVEngineInterface mEngineService;
|
||||
protected LoaderCallbackInterface mUserAppCallback;
|
||||
protected String mOpenCVersion;
|
||||
protected Context mAppContext;
|
||||
protected static boolean mServiceInstallationProgress = false;
|
||||
protected static boolean mLibraryInstallationProgress = false;
|
||||
|
||||
protected static boolean InstallServiceQuiet(Context context)
|
||||
{
|
||||
boolean result = true;
|
||||
try
|
||||
{
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(OPEN_CV_SERVICE_URL));
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected static void InstallService(final Context AppContext, final LoaderCallbackInterface Callback)
|
||||
{
|
||||
if (!mServiceInstallationProgress)
|
||||
{
|
||||
Log.d(TAG, "Request new service installation");
|
||||
InstallCallbackInterface InstallQuery = new InstallCallbackInterface() {
|
||||
private LoaderCallbackInterface mUserAppCallback = Callback;
|
||||
public String getPackageName()
|
||||
{
|
||||
return "OpenCV Manager";
|
||||
}
|
||||
public void install() {
|
||||
Log.d(TAG, "Trying to install OpenCV Manager via Google Play");
|
||||
|
||||
boolean result = InstallServiceQuiet(AppContext);
|
||||
if (result)
|
||||
{
|
||||
mServiceInstallationProgress = true;
|
||||
Log.d(TAG, "Package installation started");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.d(TAG, "OpenCV package was not installed!");
|
||||
int Status = LoaderCallbackInterface.MARKET_ERROR;
|
||||
Log.d(TAG, "Init finished with status " + Status);
|
||||
Log.d(TAG, "Unbind from service");
|
||||
Log.d(TAG, "Calling using callback");
|
||||
mUserAppCallback.onManagerConnected(Status);
|
||||
}
|
||||
}
|
||||
|
||||
public void cancel()
|
||||
{
|
||||
Log.d(TAG, "OpenCV library installation was canceled");
|
||||
int Status = LoaderCallbackInterface.INSTALL_CANCELED;
|
||||
Log.d(TAG, "Init finished with status " + Status);
|
||||
Log.d(TAG, "Calling using callback");
|
||||
mUserAppCallback.onManagerConnected(Status);
|
||||
}
|
||||
|
||||
public void wait_install()
|
||||
{
|
||||
Log.e(TAG, "Installation was not started! Nothing to wait!");
|
||||
}
|
||||
};
|
||||
|
||||
Callback.onPackageInstall(InstallCallbackInterface.NEW_INSTALLATION, InstallQuery);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.d(TAG, "Waiting current installation process");
|
||||
InstallCallbackInterface WaitQuery = new InstallCallbackInterface() {
|
||||
private LoaderCallbackInterface mUserAppCallback = Callback;
|
||||
public String getPackageName()
|
||||
{
|
||||
return "OpenCV Manager";
|
||||
}
|
||||
public void install()
|
||||
{
|
||||
Log.e(TAG, "Nothing to install we just wait current installation");
|
||||
}
|
||||
public void cancel()
|
||||
{
|
||||
Log.d(TAG, "Waiting for OpenCV canceled by user");
|
||||
mServiceInstallationProgress = false;
|
||||
int Status = LoaderCallbackInterface.INSTALL_CANCELED;
|
||||
Log.d(TAG, "Init finished with status " + Status);
|
||||
Log.d(TAG, "Calling using callback");
|
||||
mUserAppCallback.onManagerConnected(Status);
|
||||
}
|
||||
public void wait_install()
|
||||
{
|
||||
InstallServiceQuiet(AppContext);
|
||||
}
|
||||
};
|
||||
|
||||
Callback.onPackageInstall(InstallCallbackInterface.INSTALLATION_PROGRESS, WaitQuery);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* URL of OpenCV Manager page on Google Play Market.
|
||||
*/
|
||||
protected static final String OPEN_CV_SERVICE_URL = "market://details?id=org.opencv.engine";
|
||||
|
||||
protected ServiceConnection mServiceConnection = new ServiceConnection()
|
||||
{
|
||||
public void onServiceConnected(ComponentName className, IBinder service)
|
||||
{
|
||||
Log.d(TAG, "Service connection created");
|
||||
mEngineService = OpenCVEngineInterface.Stub.asInterface(service);
|
||||
if (null == mEngineService)
|
||||
{
|
||||
Log.d(TAG, "OpenCV Manager Service connection fails. May be service was not installed?");
|
||||
InstallService(mAppContext, mUserAppCallback);
|
||||
}
|
||||
else
|
||||
{
|
||||
mServiceInstallationProgress = false;
|
||||
try
|
||||
{
|
||||
if (mEngineService.getEngineVersion() < MINIMUM_ENGINE_VERSION)
|
||||
{
|
||||
Log.d(TAG, "Init finished with status " + LoaderCallbackInterface.INCOMPATIBLE_MANAGER_VERSION);
|
||||
Log.d(TAG, "Unbind from service");
|
||||
mAppContext.unbindService(mServiceConnection);
|
||||
Log.d(TAG, "Calling using callback");
|
||||
mUserAppCallback.onManagerConnected(LoaderCallbackInterface.INCOMPATIBLE_MANAGER_VERSION);
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Trying to get library path");
|
||||
String path = mEngineService.getLibPathByVersion(mOpenCVersion);
|
||||
if ((null == path) || (path.length() == 0))
|
||||
{
|
||||
if (!mLibraryInstallationProgress)
|
||||
{
|
||||
InstallCallbackInterface InstallQuery = new InstallCallbackInterface() {
|
||||
public String getPackageName()
|
||||
{
|
||||
return "OpenCV library";
|
||||
}
|
||||
public void install() {
|
||||
Log.d(TAG, "Trying to install OpenCV lib via Google Play");
|
||||
try
|
||||
{
|
||||
if (mEngineService.installVersion(mOpenCVersion))
|
||||
{
|
||||
mLibraryInstallationProgress = true;
|
||||
Log.d(TAG, "Package installation started");
|
||||
Log.d(TAG, "Unbind from service");
|
||||
mAppContext.unbindService(mServiceConnection);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.d(TAG, "OpenCV package was not installed!");
|
||||
Log.d(TAG, "Init finished with status " + LoaderCallbackInterface.MARKET_ERROR);
|
||||
Log.d(TAG, "Unbind from service");
|
||||
mAppContext.unbindService(mServiceConnection);
|
||||
Log.d(TAG, "Calling using callback");
|
||||
mUserAppCallback.onManagerConnected(LoaderCallbackInterface.MARKET_ERROR);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();;
|
||||
Log.d(TAG, "Init finished with status " + LoaderCallbackInterface.INIT_FAILED);
|
||||
Log.d(TAG, "Unbind from service");
|
||||
mAppContext.unbindService(mServiceConnection);
|
||||
Log.d(TAG, "Calling using callback");
|
||||
mUserAppCallback.onManagerConnected(LoaderCallbackInterface.INIT_FAILED);
|
||||
}
|
||||
}
|
||||
public void cancel() {
|
||||
Log.d(TAG, "OpenCV library installation was canceled");
|
||||
Log.d(TAG, "Init finished with status " + LoaderCallbackInterface.INSTALL_CANCELED);
|
||||
Log.d(TAG, "Unbind from service");
|
||||
mAppContext.unbindService(mServiceConnection);
|
||||
Log.d(TAG, "Calling using callback");
|
||||
mUserAppCallback.onManagerConnected(LoaderCallbackInterface.INSTALL_CANCELED);
|
||||
}
|
||||
public void wait_install() {
|
||||
Log.e(TAG, "Installation was not started! Nothing to wait!");
|
||||
}
|
||||
};
|
||||
|
||||
mUserAppCallback.onPackageInstall(InstallCallbackInterface.NEW_INSTALLATION, InstallQuery);
|
||||
}
|
||||
else
|
||||
{
|
||||
InstallCallbackInterface WaitQuery = new InstallCallbackInterface() {
|
||||
public String getPackageName()
|
||||
{
|
||||
return "OpenCV library";
|
||||
}
|
||||
|
||||
public void install() {
|
||||
Log.e(TAG, "Nothing to install we just wait current installation");
|
||||
}
|
||||
public void cancel()
|
||||
{
|
||||
Log.d(TAG, "OpenCV library installation was canceled");
|
||||
mLibraryInstallationProgress = false;
|
||||
Log.d(TAG, "Init finished with status " + LoaderCallbackInterface.INSTALL_CANCELED);
|
||||
Log.d(TAG, "Unbind from service");
|
||||
mAppContext.unbindService(mServiceConnection);
|
||||
Log.d(TAG, "Calling using callback");
|
||||
mUserAppCallback.onManagerConnected(LoaderCallbackInterface.INSTALL_CANCELED);
|
||||
}
|
||||
public void wait_install() {
|
||||
Log.d(TAG, "Waiting for current installation");
|
||||
try
|
||||
{
|
||||
if (!mEngineService.installVersion(mOpenCVersion))
|
||||
{
|
||||
Log.d(TAG, "OpenCV package was not installed!");
|
||||
Log.d(TAG, "Init finished with status " + LoaderCallbackInterface.MARKET_ERROR);
|
||||
Log.d(TAG, "Calling using callback");
|
||||
mUserAppCallback.onManagerConnected(LoaderCallbackInterface.MARKET_ERROR);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.d(TAG, "Waiting for package installation");
|
||||
}
|
||||
|
||||
Log.d(TAG, "Unbind from service");
|
||||
mAppContext.unbindService(mServiceConnection);
|
||||
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
Log.d(TAG, "Init finished with status " + LoaderCallbackInterface.INIT_FAILED);
|
||||
Log.d(TAG, "Unbind from service");
|
||||
mAppContext.unbindService(mServiceConnection);
|
||||
Log.d(TAG, "Calling using callback");
|
||||
mUserAppCallback.onManagerConnected(LoaderCallbackInterface.INIT_FAILED);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
mUserAppCallback.onPackageInstall(InstallCallbackInterface.INSTALLATION_PROGRESS, WaitQuery);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.d(TAG, "Trying to get library list");
|
||||
mLibraryInstallationProgress = false;
|
||||
String libs = mEngineService.getLibraryList(mOpenCVersion);
|
||||
Log.d(TAG, "Library list: \"" + libs + "\"");
|
||||
Log.d(TAG, "First attempt to load libs");
|
||||
int status;
|
||||
if (initOpenCVLibs(path, libs))
|
||||
{
|
||||
Log.d(TAG, "First attempt to load libs is OK");
|
||||
String eol = System.getProperty("line.separator");
|
||||
for (String str : Core.getBuildInformation().split(eol))
|
||||
Log.i(TAG, str);
|
||||
|
||||
status = LoaderCallbackInterface.SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.d(TAG, "First attempt to load libs fails");
|
||||
status = LoaderCallbackInterface.INIT_FAILED;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Init finished with status " + status);
|
||||
Log.d(TAG, "Unbind from service");
|
||||
mAppContext.unbindService(mServiceConnection);
|
||||
Log.d(TAG, "Calling using callback");
|
||||
mUserAppCallback.onManagerConnected(status);
|
||||
}
|
||||
}
|
||||
catch (RemoteException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
Log.d(TAG, "Init finished with status " + LoaderCallbackInterface.INIT_FAILED);
|
||||
Log.d(TAG, "Unbind from service");
|
||||
mAppContext.unbindService(mServiceConnection);
|
||||
Log.d(TAG, "Calling using callback");
|
||||
mUserAppCallback.onManagerConnected(LoaderCallbackInterface.INIT_FAILED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onServiceDisconnected(ComponentName className)
|
||||
{
|
||||
mEngineService = null;
|
||||
}
|
||||
};
|
||||
|
||||
private boolean loadLibrary(String AbsPath)
|
||||
{
|
||||
boolean result = true;
|
||||
|
||||
Log.d(TAG, "Trying to load library " + AbsPath);
|
||||
try
|
||||
{
|
||||
System.load(AbsPath);
|
||||
Log.d(TAG, "OpenCV libs init was ok!");
|
||||
}
|
||||
catch(UnsatisfiedLinkError e)
|
||||
{
|
||||
Log.d(TAG, "Cannot load library \"" + AbsPath + "\"");
|
||||
e.printStackTrace();
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean initOpenCVLibs(String Path, String Libs)
|
||||
{
|
||||
Log.d(TAG, "Trying to init OpenCV libs");
|
||||
if ((null != Path) && (Path.length() != 0))
|
||||
{
|
||||
boolean result = true;
|
||||
if ((null != Libs) && (Libs.length() != 0))
|
||||
{
|
||||
Log.d(TAG, "Trying to load libs by dependency list");
|
||||
StringTokenizer splitter = new StringTokenizer(Libs, ";");
|
||||
while(splitter.hasMoreTokens())
|
||||
{
|
||||
String AbsLibraryPath = Path + File.separator + splitter.nextToken();
|
||||
result &= loadLibrary(AbsLibraryPath);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the dependencies list is not defined or empty.
|
||||
String AbsLibraryPath = Path + File.separator + "libopencv_java4.so";
|
||||
result = loadLibrary(AbsLibraryPath);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.d(TAG, "Library path \"" + Path + "\" is empty");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,141 @@
|
||||
package org.opencv.android;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Basic implementation of LoaderCallbackInterface.
|
||||
*/
|
||||
public abstract class BaseLoaderCallback implements LoaderCallbackInterface {
|
||||
|
||||
public BaseLoaderCallback(Context AppContext) {
|
||||
mAppContext = AppContext;
|
||||
}
|
||||
|
||||
public void onManagerConnected(int status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
/** OpenCV initialization was successful. **/
|
||||
case LoaderCallbackInterface.SUCCESS:
|
||||
{
|
||||
/** Application must override this method to handle successful library initialization. **/
|
||||
} break;
|
||||
/** OpenCV loader can not start Google Play Market. **/
|
||||
case LoaderCallbackInterface.MARKET_ERROR:
|
||||
{
|
||||
Log.e(TAG, "Package installation failed!");
|
||||
AlertDialog MarketErrorMessage = new AlertDialog.Builder(mAppContext).create();
|
||||
MarketErrorMessage.setTitle("OpenCV Manager");
|
||||
MarketErrorMessage.setMessage("Package installation failed!");
|
||||
MarketErrorMessage.setCancelable(false); // This blocks the 'BACK' button
|
||||
MarketErrorMessage.setButton(AlertDialog.BUTTON_POSITIVE, "OK", new OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
MarketErrorMessage.show();
|
||||
} break;
|
||||
/** Package installation has been canceled. **/
|
||||
case LoaderCallbackInterface.INSTALL_CANCELED:
|
||||
{
|
||||
Log.d(TAG, "OpenCV library installation was canceled by user");
|
||||
finish();
|
||||
} break;
|
||||
/** Application is incompatible with this version of OpenCV Manager. Possibly, a service update is required. **/
|
||||
case LoaderCallbackInterface.INCOMPATIBLE_MANAGER_VERSION:
|
||||
{
|
||||
Log.d(TAG, "OpenCV Manager Service is uncompatible with this app!");
|
||||
AlertDialog IncomatibilityMessage = new AlertDialog.Builder(mAppContext).create();
|
||||
IncomatibilityMessage.setTitle("OpenCV Manager");
|
||||
IncomatibilityMessage.setMessage("OpenCV Manager service is incompatible with this app. Try to update it via Google Play.");
|
||||
IncomatibilityMessage.setCancelable(false); // This blocks the 'BACK' button
|
||||
IncomatibilityMessage.setButton(AlertDialog.BUTTON_POSITIVE, "OK", new OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
IncomatibilityMessage.show();
|
||||
} break;
|
||||
/** Other status, i.e. INIT_FAILED. **/
|
||||
default:
|
||||
{
|
||||
Log.e(TAG, "OpenCV loading failed!");
|
||||
AlertDialog InitFailedDialog = new AlertDialog.Builder(mAppContext).create();
|
||||
InitFailedDialog.setTitle("OpenCV error");
|
||||
InitFailedDialog.setMessage("OpenCV was not initialised correctly. Application will be shut down");
|
||||
InitFailedDialog.setCancelable(false); // This blocks the 'BACK' button
|
||||
InitFailedDialog.setButton(AlertDialog.BUTTON_POSITIVE, "OK", new OnClickListener() {
|
||||
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
InitFailedDialog.show();
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
public void onPackageInstall(final int operation, final InstallCallbackInterface callback)
|
||||
{
|
||||
switch (operation)
|
||||
{
|
||||
case InstallCallbackInterface.NEW_INSTALLATION:
|
||||
{
|
||||
AlertDialog InstallMessage = new AlertDialog.Builder(mAppContext).create();
|
||||
InstallMessage.setTitle("Package not found");
|
||||
InstallMessage.setMessage(callback.getPackageName() + " package was not found! Try to install it?");
|
||||
InstallMessage.setCancelable(false); // This blocks the 'BACK' button
|
||||
InstallMessage.setButton(AlertDialog.BUTTON_POSITIVE, "Yes", new OnClickListener()
|
||||
{
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
callback.install();
|
||||
}
|
||||
});
|
||||
|
||||
InstallMessage.setButton(AlertDialog.BUTTON_NEGATIVE, "No", new OnClickListener() {
|
||||
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
callback.cancel();
|
||||
}
|
||||
});
|
||||
|
||||
InstallMessage.show();
|
||||
} break;
|
||||
case InstallCallbackInterface.INSTALLATION_PROGRESS:
|
||||
{
|
||||
AlertDialog WaitMessage = new AlertDialog.Builder(mAppContext).create();
|
||||
WaitMessage.setTitle("OpenCV is not ready");
|
||||
WaitMessage.setMessage("Installation is in progress. Wait or exit?");
|
||||
WaitMessage.setCancelable(false); // This blocks the 'BACK' button
|
||||
WaitMessage.setButton(AlertDialog.BUTTON_POSITIVE, "Wait", new OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
callback.wait_install();
|
||||
}
|
||||
});
|
||||
WaitMessage.setButton(AlertDialog.BUTTON_NEGATIVE, "Exit", new OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
callback.cancel();
|
||||
}
|
||||
});
|
||||
|
||||
WaitMessage.show();
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void finish()
|
||||
{
|
||||
((Activity) mAppContext).finish();
|
||||
}
|
||||
|
||||
protected Context mAppContext;
|
||||
private final static String TAG = "OCV/BaseLoaderCallback";
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package org.opencv.android;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static android.Manifest.permission.CAMERA;
|
||||
|
||||
public class CameraActivity extends Activity {
|
||||
|
||||
private static final int CAMERA_PERMISSION_REQUEST_CODE = 200;
|
||||
|
||||
protected List<? extends CameraBridgeViewBase> getCameraViewList() {
|
||||
return new ArrayList<CameraBridgeViewBase>();
|
||||
}
|
||||
|
||||
protected void onCameraPermissionGranted() {
|
||||
List<? extends CameraBridgeViewBase> cameraViews = getCameraViewList();
|
||||
if (cameraViews == null) {
|
||||
return;
|
||||
}
|
||||
for (CameraBridgeViewBase cameraBridgeViewBase: cameraViews) {
|
||||
if (cameraBridgeViewBase != null) {
|
||||
cameraBridgeViewBase.setCameraPermissionGranted();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
boolean havePermission = true;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (checkSelfPermission(CAMERA) != PackageManager.PERMISSION_GRANTED) {
|
||||
requestPermissions(new String[]{CAMERA}, CAMERA_PERMISSION_REQUEST_CODE);
|
||||
havePermission = false;
|
||||
}
|
||||
}
|
||||
if (havePermission) {
|
||||
onCameraPermissionGranted();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||
if (requestCode == CAMERA_PERMISSION_REQUEST_CODE && grantResults.length > 0
|
||||
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
onCameraPermissionGranted();
|
||||
}
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
}
|
||||
}
|
@ -0,0 +1,519 @@
|
||||
package org.opencv.android;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.opencv.BuildConfig;
|
||||
import org.opencv.R;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.Size;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
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 CameraBridgeViewBase extends SurfaceView implements SurfaceHolder.Callback {
|
||||
|
||||
private static final String TAG = "CameraBridge";
|
||||
protected static final int MAX_UNSPECIFIED = -1;
|
||||
private static final int STOPPED = 0;
|
||||
private static final int STARTED = 1;
|
||||
|
||||
private int mState = STOPPED;
|
||||
private Bitmap mCacheBitmap;
|
||||
private CvCameraViewListener2 mListener;
|
||||
private boolean mSurfaceExist;
|
||||
private final Object mSyncObject = new Object();
|
||||
|
||||
protected int mFrameWidth;
|
||||
protected int mFrameHeight;
|
||||
protected int mMaxHeight;
|
||||
protected int mMaxWidth;
|
||||
protected float mScale = 0;
|
||||
protected int mPreviewFormat = RGBA;
|
||||
protected int mCameraIndex = CAMERA_ID_ANY;
|
||||
protected boolean mEnabled;
|
||||
protected boolean mCameraPermissionGranted = false;
|
||||
protected FpsMeter mFpsMeter = null;
|
||||
|
||||
public static final int CAMERA_ID_ANY = -1;
|
||||
public static final int CAMERA_ID_BACK = 99;
|
||||
public static final int CAMERA_ID_FRONT = 98;
|
||||
public static final int RGBA = 1;
|
||||
public static final int GRAY = 2;
|
||||
|
||||
public CameraBridgeViewBase(Context context, int cameraId) {
|
||||
super(context);
|
||||
mCameraIndex = cameraId;
|
||||
getHolder().addCallback(this);
|
||||
mMaxWidth = MAX_UNSPECIFIED;
|
||||
mMaxHeight = MAX_UNSPECIFIED;
|
||||
}
|
||||
|
||||
public CameraBridgeViewBase(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
int count = attrs.getAttributeCount();
|
||||
Log.d(TAG, "Attr count: " + Integer.valueOf(count));
|
||||
|
||||
TypedArray styledAttrs = getContext().obtainStyledAttributes(attrs, R.styleable.CameraBridgeViewBase);
|
||||
if (styledAttrs.getBoolean(R.styleable.CameraBridgeViewBase_show_fps, false))
|
||||
enableFpsMeter();
|
||||
|
||||
mCameraIndex = styledAttrs.getInt(R.styleable.CameraBridgeViewBase_camera_id, -1);
|
||||
|
||||
getHolder().addCallback(this);
|
||||
mMaxWidth = MAX_UNSPECIFIED;
|
||||
mMaxHeight = MAX_UNSPECIFIED;
|
||||
styledAttrs.recycle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the camera index
|
||||
* @param cameraIndex new camera index
|
||||
*/
|
||||
public void setCameraIndex(int cameraIndex) {
|
||||
this.mCameraIndex = cameraIndex;
|
||||
}
|
||||
|
||||
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.
|
||||
* TODO: pass the parameters specifying the format of the frame (BPP, YUV or RGB and etc)
|
||||
*/
|
||||
public Mat onCameraFrame(Mat inputFrame);
|
||||
}
|
||||
|
||||
public interface CvCameraViewListener2 {
|
||||
/**
|
||||
* 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.
|
||||
* TODO: pass the parameters specifying the format of the frame (BPP, YUV or RGB and etc)
|
||||
*/
|
||||
public Mat onCameraFrame(CvCameraViewFrame inputFrame);
|
||||
};
|
||||
|
||||
protected class CvCameraViewListenerAdapter implements CvCameraViewListener2 {
|
||||
public CvCameraViewListenerAdapter(CvCameraViewListener oldStypeListener) {
|
||||
mOldStyleListener = oldStypeListener;
|
||||
}
|
||||
|
||||
public void onCameraViewStarted(int width, int height) {
|
||||
mOldStyleListener.onCameraViewStarted(width, height);
|
||||
}
|
||||
|
||||
public void onCameraViewStopped() {
|
||||
mOldStyleListener.onCameraViewStopped();
|
||||
}
|
||||
|
||||
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
|
||||
Mat result = null;
|
||||
switch (mPreviewFormat) {
|
||||
case RGBA:
|
||||
result = mOldStyleListener.onCameraFrame(inputFrame.rgba());
|
||||
break;
|
||||
case GRAY:
|
||||
result = mOldStyleListener.onCameraFrame(inputFrame.gray());
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "Invalid frame format! Only RGBA and Gray Scale are supported!");
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setFrameFormat(int format) {
|
||||
mPreviewFormat = format;
|
||||
}
|
||||
|
||||
private int mPreviewFormat = RGBA;
|
||||
private CvCameraViewListener mOldStyleListener;
|
||||
};
|
||||
|
||||
/**
|
||||
* This class interface is abstract representation of single frame from camera for onCameraFrame callback
|
||||
* Attention: Do not use objects, that represents this interface out of onCameraFrame callback!
|
||||
*/
|
||||
public interface CvCameraViewFrame {
|
||||
|
||||
/**
|
||||
* This method returns RGBA Mat with frame
|
||||
*/
|
||||
public Mat rgba();
|
||||
|
||||
/**
|
||||
* This method returns single channel gray scale Mat with frame
|
||||
*/
|
||||
public Mat gray();
|
||||
};
|
||||
|
||||
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
|
||||
Log.d(TAG, "call surfaceChanged event");
|
||||
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 signal camera permission has been granted.
|
||||
* The actual onCameraViewStarted callback will be delivered only after setCameraPermissionGranted
|
||||
* and enableView have been called and surface is available
|
||||
*/
|
||||
public void setCameraPermissionGranted() {
|
||||
synchronized(mSyncObject) {
|
||||
mCameraPermissionGranted = true;
|
||||
checkCurrentState();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method is provided for clients, so they can enable the camera connection.
|
||||
* The actual onCameraViewStarted callback will be delivered only after setCameraPermissionGranted
|
||||
* and enableView have been 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 even though the surface view itself is not destroyed and still stays on the screen
|
||||
*/
|
||||
public void disableView() {
|
||||
synchronized(mSyncObject) {
|
||||
mEnabled = false;
|
||||
checkCurrentState();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method enables label with fps value on the screen
|
||||
*/
|
||||
public void enableFpsMeter() {
|
||||
if (mFpsMeter == null) {
|
||||
mFpsMeter = new FpsMeter();
|
||||
mFpsMeter.setResolution(mFrameWidth, mFrameHeight);
|
||||
}
|
||||
}
|
||||
|
||||
public void disableFpsMeter() {
|
||||
mFpsMeter = null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param listener
|
||||
*/
|
||||
|
||||
public void setCvCameraViewListener(CvCameraViewListener2 listener) {
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
public void setCvCameraViewListener(CvCameraViewListener listener) {
|
||||
CvCameraViewListenerAdapter adapter = new CvCameraViewListenerAdapter(listener);
|
||||
adapter.setFrameFormat(mPreviewFormat);
|
||||
mListener = adapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 useful 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 maximum height allowed for camera frame
|
||||
*/
|
||||
public void setMaxFrameSize(int maxWidth, int maxHeight) {
|
||||
mMaxWidth = maxWidth;
|
||||
mMaxHeight = maxHeight;
|
||||
}
|
||||
|
||||
public void SetCaptureFormat(int format)
|
||||
{
|
||||
mPreviewFormat = format;
|
||||
if (mListener instanceof CvCameraViewListenerAdapter) {
|
||||
CvCameraViewListenerAdapter adapter = (CvCameraViewListenerAdapter) mListener;
|
||||
adapter.setFrameFormat(mPreviewFormat);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when mSyncObject lock is held
|
||||
*/
|
||||
private void checkCurrentState() {
|
||||
Log.d(TAG, "call checkCurrentState");
|
||||
int targetState;
|
||||
|
||||
if (mEnabled && mCameraPermissionGranted && mSurfaceExist && getVisibility() == VISIBLE) {
|
||||
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) {
|
||||
Log.d(TAG, "call processEnterState: " + 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) {
|
||||
Log.d(TAG, "call processExitState: " + state);
|
||||
switch(state) {
|
||||
case STARTED:
|
||||
onExitStartedState();
|
||||
break;
|
||||
case STOPPED:
|
||||
onExitStoppedState();
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
private void onEnterStoppedState() {
|
||||
/* nothing to do */
|
||||
}
|
||||
|
||||
private void onExitStoppedState() {
|
||||
/* nothing to do */
|
||||
}
|
||||
|
||||
// NOTE: The order of bitmap constructor and camera connection is important for android 4.1.x
|
||||
// Bitmap must be constructed before surface
|
||||
private void onEnterStartedState() {
|
||||
Log.d(TAG, "call onEnterStartedState");
|
||||
/* Connect camera */
|
||||
if (!connectCamera(getWidth(), getHeight())) {
|
||||
AlertDialog ad = new AlertDialog.Builder(getContext()).create();
|
||||
ad.setCancelable(false); // This blocks the 'BACK' button
|
||||
ad.setMessage("It seems that you device does not support camera (or it is locked). Application will be closed.");
|
||||
ad.setButton(DialogInterface.BUTTON_NEUTRAL, "OK", new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
((Activity) getContext()).finish();
|
||||
}
|
||||
});
|
||||
ad.show();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
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(CvCameraViewFrame frame) {
|
||||
Mat modified;
|
||||
|
||||
if (mListener != null) {
|
||||
modified = mListener.onCameraFrame(frame);
|
||||
} else {
|
||||
modified = frame.rgba();
|
||||
}
|
||||
|
||||
boolean bmpValid = true;
|
||||
if (modified != null) {
|
||||
try {
|
||||
Utils.matToBitmap(modified, mCacheBitmap);
|
||||
} catch(Exception e) {
|
||||
Log.e(TAG, "Mat type: " + modified);
|
||||
Log.e(TAG, "Bitmap type: " + mCacheBitmap.getWidth() + "*" + mCacheBitmap.getHeight());
|
||||
Log.e(TAG, "Utils.matToBitmap() throws an exception: " + e.getMessage());
|
||||
bmpValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (bmpValid && mCacheBitmap != null) {
|
||||
Canvas canvas = getHolder().lockCanvas();
|
||||
if (canvas != null) {
|
||||
canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR);
|
||||
if (BuildConfig.DEBUG)
|
||||
Log.d(TAG, "mStretch value: " + mScale);
|
||||
|
||||
if (mScale != 0) {
|
||||
canvas.drawBitmap(mCacheBitmap, new Rect(0,0,mCacheBitmap.getWidth(), mCacheBitmap.getHeight()),
|
||||
new Rect((int)((canvas.getWidth() - mScale*mCacheBitmap.getWidth()) / 2),
|
||||
(int)((canvas.getHeight() - mScale*mCacheBitmap.getHeight()) / 2),
|
||||
(int)((canvas.getWidth() - mScale*mCacheBitmap.getWidth()) / 2 + mScale*mCacheBitmap.getWidth()),
|
||||
(int)((canvas.getHeight() - mScale*mCacheBitmap.getHeight()) / 2 + mScale*mCacheBitmap.getHeight())), null);
|
||||
} else {
|
||||
canvas.drawBitmap(mCacheBitmap, new Rect(0,0,mCacheBitmap.getWidth(), mCacheBitmap.getHeight()),
|
||||
new Rect((canvas.getWidth() - mCacheBitmap.getWidth()) / 2,
|
||||
(canvas.getHeight() - mCacheBitmap.getHeight()) / 2,
|
||||
(canvas.getWidth() - mCacheBitmap.getWidth()) / 2 + mCacheBitmap.getWidth(),
|
||||
(canvas.getHeight() - mCacheBitmap.getHeight()) / 2 + mCacheBitmap.getHeight()), null);
|
||||
}
|
||||
|
||||
if (mFpsMeter != null) {
|
||||
mFpsMeter.measure();
|
||||
mFpsMeter.draw(canvas, 20, 30);
|
||||
}
|
||||
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 boolean connectCamera(int width, int height);
|
||||
|
||||
/**
|
||||
* Disconnects and release the particular camera object being connected to this surface view.
|
||||
* Called when syncObject lock is held
|
||||
*/
|
||||
protected abstract void disconnectCamera();
|
||||
|
||||
// NOTE: On Android 4.1.x the function must be called before SurfaceTexture constructor!
|
||||
protected void AllocateCache()
|
||||
{
|
||||
mCacheBitmap = Bitmap.createBitmap(mFrameWidth, mFrameHeight, Bitmap.Config.ARGB_8888);
|
||||
}
|
||||
|
||||
public interface ListItemAccessor {
|
||||
public int getWidth(Object obj);
|
||||
public int getHeight(Object obj);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 optimal frame size
|
||||
*/
|
||||
protected Size calculateCameraFrameSize(List<?> supportedSizes, ListItemAccessor accessor, 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 (Object size : supportedSizes) {
|
||||
int width = accessor.getWidth(size);
|
||||
int height = accessor.getHeight(size);
|
||||
Log.d(TAG, "trying size: " + width + "x" + height);
|
||||
|
||||
if (width <= maxAllowedWidth && height <= maxAllowedHeight) {
|
||||
if (width >= calcWidth && height >= calcHeight) {
|
||||
calcWidth = (int) width;
|
||||
calcHeight = (int) height;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((calcWidth == 0 || calcHeight == 0) && supportedSizes.size() > 0)
|
||||
{
|
||||
Log.i(TAG, "fallback to the first frame size");
|
||||
Object size = supportedSizes.get(0);
|
||||
calcWidth = accessor.getWidth(size);
|
||||
calcHeight = accessor.getHeight(size);
|
||||
}
|
||||
|
||||
return new Size(calcWidth, calcHeight);
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package org.opencv.android;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import org.opencv.core.Core;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.util.Log;
|
||||
|
||||
public class FpsMeter {
|
||||
private static final String TAG = "FpsMeter";
|
||||
private static final int STEP = 20;
|
||||
private static final DecimalFormat FPS_FORMAT = new DecimalFormat("0.00");
|
||||
|
||||
private int mFramesCounter;
|
||||
private double mFrequency;
|
||||
private long mprevFrameTime;
|
||||
private String mStrfps;
|
||||
Paint mPaint;
|
||||
boolean mIsInitialized = false;
|
||||
int mWidth = 0;
|
||||
int mHeight = 0;
|
||||
|
||||
public void init() {
|
||||
mFramesCounter = 0;
|
||||
mFrequency = Core.getTickFrequency();
|
||||
mprevFrameTime = Core.getTickCount();
|
||||
mStrfps = "";
|
||||
|
||||
mPaint = new Paint();
|
||||
mPaint.setColor(Color.BLUE);
|
||||
mPaint.setTextSize(20);
|
||||
}
|
||||
|
||||
public void measure() {
|
||||
if (!mIsInitialized) {
|
||||
init();
|
||||
mIsInitialized = true;
|
||||
} else {
|
||||
mFramesCounter++;
|
||||
if (mFramesCounter % STEP == 0) {
|
||||
long time = Core.getTickCount();
|
||||
double fps = STEP * mFrequency / (time - mprevFrameTime);
|
||||
mprevFrameTime = time;
|
||||
if (mWidth != 0 && mHeight != 0)
|
||||
mStrfps = FPS_FORMAT.format(fps) + " FPS@" + Integer.valueOf(mWidth) + "x" + Integer.valueOf(mHeight);
|
||||
else
|
||||
mStrfps = FPS_FORMAT.format(fps) + " FPS";
|
||||
Log.i(TAG, mStrfps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setResolution(int width, int height) {
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
}
|
||||
|
||||
public void draw(Canvas canvas, float offsetx, float offsety) {
|
||||
Log.d(TAG, mStrfps);
|
||||
canvas.drawText(mStrfps, offsetx, offsety, mPaint);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package org.opencv.android;
|
||||
|
||||
/**
|
||||
* Installation callback interface.
|
||||
*/
|
||||
public interface InstallCallbackInterface
|
||||
{
|
||||
/**
|
||||
* New package installation is required.
|
||||
*/
|
||||
static final int NEW_INSTALLATION = 0;
|
||||
/**
|
||||
* Current package installation is in progress.
|
||||
*/
|
||||
static final int INSTALLATION_PROGRESS = 1;
|
||||
|
||||
/**
|
||||
* Target package name.
|
||||
* @return Return target package name.
|
||||
*/
|
||||
public String getPackageName();
|
||||
/**
|
||||
* Installation is approved.
|
||||
*/
|
||||
public void install();
|
||||
/**
|
||||
* Installation is canceled.
|
||||
*/
|
||||
public void cancel();
|
||||
/**
|
||||
* Wait for package installation.
|
||||
*/
|
||||
public void wait_install();
|
||||
};
|
@ -0,0 +1,379 @@
|
||||
package org.opencv.android;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.ImageFormat;
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.hardware.Camera;
|
||||
import android.hardware.Camera.PreviewCallback;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
|
||||
import org.opencv.BuildConfig;
|
||||
import org.opencv.core.CvType;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.Size;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
|
||||
/**
|
||||
* This class is an implementation of the Bridge View between OpenCV and Java Camera.
|
||||
* This class relays on the functionality available in base class and only implements
|
||||
* required functions:
|
||||
* connectCamera - opens Java camera and sets the PreviewCallback to be delivered.
|
||||
* disconnectCamera - closes the camera and stops preview.
|
||||
* When frame is delivered via callback from Camera - it processed via OpenCV to be
|
||||
* converted to RGBA32 and then passed to the external callback for modifications if required.
|
||||
*/
|
||||
public class JavaCameraView extends CameraBridgeViewBase implements PreviewCallback {
|
||||
|
||||
private static final int MAGIC_TEXTURE_ID = 10;
|
||||
private static final String TAG = "JavaCameraView";
|
||||
|
||||
private byte mBuffer[];
|
||||
private Mat[] mFrameChain;
|
||||
private int mChainIdx = 0;
|
||||
private Thread mThread;
|
||||
private boolean mStopThread;
|
||||
|
||||
protected Camera mCamera;
|
||||
protected JavaCameraFrame[] mCameraFrame;
|
||||
private SurfaceTexture mSurfaceTexture;
|
||||
private int mPreviewFormat = ImageFormat.NV21;
|
||||
|
||||
public static class JavaCameraSizeAccessor implements ListItemAccessor {
|
||||
|
||||
@Override
|
||||
public int getWidth(Object obj) {
|
||||
Camera.Size size = (Camera.Size) obj;
|
||||
return size.width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight(Object obj) {
|
||||
Camera.Size size = (Camera.Size) obj;
|
||||
return size.height;
|
||||
}
|
||||
}
|
||||
|
||||
public JavaCameraView(Context context, int cameraId) {
|
||||
super(context, cameraId);
|
||||
}
|
||||
|
||||
public JavaCameraView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
protected boolean initializeCamera(int width, int height) {
|
||||
Log.d(TAG, "Initialize java camera");
|
||||
boolean result = true;
|
||||
synchronized (this) {
|
||||
mCamera = null;
|
||||
|
||||
if (mCameraIndex == CAMERA_ID_ANY) {
|
||||
Log.d(TAG, "Trying to open camera with old open()");
|
||||
try {
|
||||
mCamera = Camera.open();
|
||||
}
|
||||
catch (Exception e){
|
||||
Log.e(TAG, "Camera is not available (in use or does not exist): " + e.getLocalizedMessage());
|
||||
}
|
||||
|
||||
if(mCamera == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
|
||||
boolean connected = false;
|
||||
for (int camIdx = 0; camIdx < Camera.getNumberOfCameras(); ++camIdx) {
|
||||
Log.d(TAG, "Trying to open camera with new open(" + Integer.valueOf(camIdx) + ")");
|
||||
try {
|
||||
mCamera = Camera.open(camIdx);
|
||||
connected = true;
|
||||
} catch (RuntimeException e) {
|
||||
Log.e(TAG, "Camera #" + camIdx + "failed to open: " + e.getLocalizedMessage());
|
||||
}
|
||||
if (connected) break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
|
||||
int localCameraIndex = mCameraIndex;
|
||||
if (mCameraIndex == CAMERA_ID_BACK) {
|
||||
Log.i(TAG, "Trying to open back camera");
|
||||
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
|
||||
for (int camIdx = 0; camIdx < Camera.getNumberOfCameras(); ++camIdx) {
|
||||
Camera.getCameraInfo( camIdx, cameraInfo );
|
||||
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
|
||||
localCameraIndex = camIdx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (mCameraIndex == CAMERA_ID_FRONT) {
|
||||
Log.i(TAG, "Trying to open front camera");
|
||||
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
|
||||
for (int camIdx = 0; camIdx < Camera.getNumberOfCameras(); ++camIdx) {
|
||||
Camera.getCameraInfo( camIdx, cameraInfo );
|
||||
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
|
||||
localCameraIndex = camIdx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (localCameraIndex == CAMERA_ID_BACK) {
|
||||
Log.e(TAG, "Back camera not found!");
|
||||
} else if (localCameraIndex == CAMERA_ID_FRONT) {
|
||||
Log.e(TAG, "Front camera not found!");
|
||||
} else {
|
||||
Log.d(TAG, "Trying to open camera with new open(" + Integer.valueOf(localCameraIndex) + ")");
|
||||
try {
|
||||
mCamera = Camera.open(localCameraIndex);
|
||||
} catch (RuntimeException e) {
|
||||
Log.e(TAG, "Camera #" + localCameraIndex + "failed to open: " + e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mCamera == null)
|
||||
return false;
|
||||
|
||||
/* Now set camera parameters */
|
||||
try {
|
||||
Camera.Parameters params = mCamera.getParameters();
|
||||
Log.d(TAG, "getSupportedPreviewSizes()");
|
||||
List<android.hardware.Camera.Size> sizes = params.getSupportedPreviewSizes();
|
||||
|
||||
if (sizes != null) {
|
||||
/* Select the size that fits surface considering maximum size allowed */
|
||||
Size frameSize = calculateCameraFrameSize(sizes, new JavaCameraSizeAccessor(), width, height);
|
||||
|
||||
/* Image format NV21 causes issues in the Android emulators */
|
||||
if (Build.FINGERPRINT.startsWith("generic")
|
||||
|| Build.FINGERPRINT.startsWith("unknown")
|
||||
|| Build.MODEL.contains("google_sdk")
|
||||
|| Build.MODEL.contains("Emulator")
|
||||
|| Build.MODEL.contains("Android SDK built for x86")
|
||||
|| Build.MANUFACTURER.contains("Genymotion")
|
||||
|| (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic"))
|
||||
|| "google_sdk".equals(Build.PRODUCT))
|
||||
params.setPreviewFormat(ImageFormat.YV12); // "generic" or "android" = android emulator
|
||||
else
|
||||
params.setPreviewFormat(ImageFormat.NV21);
|
||||
|
||||
mPreviewFormat = params.getPreviewFormat();
|
||||
|
||||
Log.d(TAG, "Set preview size to " + Integer.valueOf((int)frameSize.width) + "x" + Integer.valueOf((int)frameSize.height));
|
||||
params.setPreviewSize((int)frameSize.width, (int)frameSize.height);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH && !android.os.Build.MODEL.equals("GT-I9100"))
|
||||
params.setRecordingHint(true);
|
||||
|
||||
List<String> FocusModes = params.getSupportedFocusModes();
|
||||
if (FocusModes != null && FocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO))
|
||||
{
|
||||
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
|
||||
}
|
||||
|
||||
mCamera.setParameters(params);
|
||||
params = mCamera.getParameters();
|
||||
|
||||
mFrameWidth = params.getPreviewSize().width;
|
||||
mFrameHeight = params.getPreviewSize().height;
|
||||
|
||||
if ((getLayoutParams().width == LayoutParams.MATCH_PARENT) && (getLayoutParams().height == LayoutParams.MATCH_PARENT))
|
||||
mScale = Math.min(((float)height)/mFrameHeight, ((float)width)/mFrameWidth);
|
||||
else
|
||||
mScale = 0;
|
||||
|
||||
if (mFpsMeter != null) {
|
||||
mFpsMeter.setResolution(mFrameWidth, mFrameHeight);
|
||||
}
|
||||
|
||||
int size = mFrameWidth * mFrameHeight;
|
||||
size = size * ImageFormat.getBitsPerPixel(params.getPreviewFormat()) / 8;
|
||||
mBuffer = new byte[size];
|
||||
|
||||
mCamera.addCallbackBuffer(mBuffer);
|
||||
mCamera.setPreviewCallbackWithBuffer(this);
|
||||
|
||||
mFrameChain = new Mat[2];
|
||||
mFrameChain[0] = new Mat(mFrameHeight + (mFrameHeight/2), mFrameWidth, CvType.CV_8UC1);
|
||||
mFrameChain[1] = new Mat(mFrameHeight + (mFrameHeight/2), mFrameWidth, CvType.CV_8UC1);
|
||||
|
||||
AllocateCache();
|
||||
|
||||
mCameraFrame = new JavaCameraFrame[2];
|
||||
mCameraFrame[0] = new JavaCameraFrame(mFrameChain[0], mFrameWidth, mFrameHeight);
|
||||
mCameraFrame[1] = new JavaCameraFrame(mFrameChain[1], mFrameWidth, mFrameHeight);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
mSurfaceTexture = new SurfaceTexture(MAGIC_TEXTURE_ID);
|
||||
mCamera.setPreviewTexture(mSurfaceTexture);
|
||||
} else
|
||||
mCamera.setPreviewDisplay(null);
|
||||
|
||||
/* Finally we are ready to start the preview */
|
||||
Log.d(TAG, "startPreview");
|
||||
mCamera.startPreview();
|
||||
}
|
||||
else
|
||||
result = false;
|
||||
} catch (Exception e) {
|
||||
result = false;
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void releaseCamera() {
|
||||
synchronized (this) {
|
||||
if (mCamera != null) {
|
||||
mCamera.stopPreview();
|
||||
mCamera.setPreviewCallback(null);
|
||||
|
||||
mCamera.release();
|
||||
}
|
||||
mCamera = null;
|
||||
if (mFrameChain != null) {
|
||||
mFrameChain[0].release();
|
||||
mFrameChain[1].release();
|
||||
}
|
||||
if (mCameraFrame != null) {
|
||||
mCameraFrame[0].release();
|
||||
mCameraFrame[1].release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean mCameraFrameReady = false;
|
||||
|
||||
@Override
|
||||
protected boolean 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 */
|
||||
Log.d(TAG, "Connecting to camera");
|
||||
if (!initializeCamera(width, height))
|
||||
return false;
|
||||
|
||||
mCameraFrameReady = false;
|
||||
|
||||
/* now we can start update thread */
|
||||
Log.d(TAG, "Starting processing thread");
|
||||
mStopThread = false;
|
||||
mThread = new Thread(new CameraWorker());
|
||||
mThread.start();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void disconnectCamera() {
|
||||
/* 1. We need to stop thread which updating the frames
|
||||
* 2. Stop camera and release it
|
||||
*/
|
||||
Log.d(TAG, "Disconnecting from camera");
|
||||
try {
|
||||
mStopThread = true;
|
||||
Log.d(TAG, "Notify thread");
|
||||
synchronized (this) {
|
||||
this.notify();
|
||||
}
|
||||
Log.d(TAG, "Waiting for thread");
|
||||
if (mThread != null)
|
||||
mThread.join();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
mThread = null;
|
||||
}
|
||||
|
||||
/* Now release camera */
|
||||
releaseCamera();
|
||||
|
||||
mCameraFrameReady = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPreviewFrame(byte[] frame, Camera arg1) {
|
||||
if (BuildConfig.DEBUG)
|
||||
Log.d(TAG, "Preview Frame received. Frame size: " + frame.length);
|
||||
synchronized (this) {
|
||||
mFrameChain[mChainIdx].put(0, 0, frame);
|
||||
mCameraFrameReady = true;
|
||||
this.notify();
|
||||
}
|
||||
if (mCamera != null)
|
||||
mCamera.addCallbackBuffer(mBuffer);
|
||||
}
|
||||
|
||||
private class JavaCameraFrame implements CvCameraViewFrame {
|
||||
@Override
|
||||
public Mat gray() {
|
||||
return mYuvFrameData.submat(0, mHeight, 0, mWidth);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mat rgba() {
|
||||
if (mPreviewFormat == ImageFormat.NV21)
|
||||
Imgproc.cvtColor(mYuvFrameData, mRgba, Imgproc.COLOR_YUV2RGBA_NV21, 4);
|
||||
else if (mPreviewFormat == ImageFormat.YV12)
|
||||
Imgproc.cvtColor(mYuvFrameData, mRgba, Imgproc.COLOR_YUV2RGB_I420, 4); // COLOR_YUV2RGBA_YV12 produces inverted colors
|
||||
else
|
||||
throw new IllegalArgumentException("Preview Format can be NV21 or YV12");
|
||||
|
||||
return mRgba;
|
||||
}
|
||||
|
||||
public JavaCameraFrame(Mat Yuv420sp, int width, int height) {
|
||||
super();
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
mYuvFrameData = Yuv420sp;
|
||||
mRgba = new Mat();
|
||||
}
|
||||
|
||||
public void release() {
|
||||
mRgba.release();
|
||||
}
|
||||
|
||||
private Mat mYuvFrameData;
|
||||
private Mat mRgba;
|
||||
private int mWidth;
|
||||
private int mHeight;
|
||||
};
|
||||
|
||||
private class CameraWorker implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
do {
|
||||
boolean hasFrame = false;
|
||||
synchronized (JavaCameraView.this) {
|
||||
try {
|
||||
while (!mCameraFrameReady && !mStopThread) {
|
||||
JavaCameraView.this.wait();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (mCameraFrameReady)
|
||||
{
|
||||
mChainIdx = 1 - mChainIdx;
|
||||
mCameraFrameReady = false;
|
||||
hasFrame = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mStopThread && hasFrame) {
|
||||
if (!mFrameChain[1 - mChainIdx].empty())
|
||||
deliverAndDrawFrame(mCameraFrame[1 - mChainIdx]);
|
||||
}
|
||||
} while (!mStopThread);
|
||||
Log.d(TAG, "Finish processing thread");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package org.opencv.android;
|
||||
|
||||
/**
|
||||
* Interface for callback object in case of asynchronous initialization of OpenCV.
|
||||
*/
|
||||
public interface LoaderCallbackInterface
|
||||
{
|
||||
/**
|
||||
* OpenCV initialization finished successfully.
|
||||
*/
|
||||
static final int SUCCESS = 0;
|
||||
/**
|
||||
* Google Play Market cannot be invoked.
|
||||
*/
|
||||
static final int MARKET_ERROR = 2;
|
||||
/**
|
||||
* OpenCV library installation has been canceled by the user.
|
||||
*/
|
||||
static final int INSTALL_CANCELED = 3;
|
||||
/**
|
||||
* This version of OpenCV Manager Service is incompatible with the app. Possibly, a service update is required.
|
||||
*/
|
||||
static final int INCOMPATIBLE_MANAGER_VERSION = 4;
|
||||
/**
|
||||
* OpenCV library initialization has failed.
|
||||
*/
|
||||
static final int INIT_FAILED = 0xff;
|
||||
|
||||
/**
|
||||
* Callback method, called after OpenCV library initialization.
|
||||
* @param status status of initialization (see initialization status constants).
|
||||
*/
|
||||
public void onManagerConnected(int status);
|
||||
|
||||
/**
|
||||
* Callback method, called in case the package installation is needed.
|
||||
* @param callback answer object with approve and cancel methods and the package description.
|
||||
*/
|
||||
public void onPackageInstall(final int operation, InstallCallbackInterface callback);
|
||||
};
|
@ -0,0 +1,132 @@
|
||||
package org.opencv.android;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* Helper class provides common initialization methods for OpenCV library.
|
||||
*/
|
||||
public class OpenCVLoader
|
||||
{
|
||||
/**
|
||||
* OpenCV Library version 2.4.2.
|
||||
*/
|
||||
public static final String OPENCV_VERSION_2_4_2 = "2.4.2";
|
||||
|
||||
/**
|
||||
* OpenCV Library version 2.4.3.
|
||||
*/
|
||||
public static final String OPENCV_VERSION_2_4_3 = "2.4.3";
|
||||
|
||||
/**
|
||||
* OpenCV Library version 2.4.4.
|
||||
*/
|
||||
public static final String OPENCV_VERSION_2_4_4 = "2.4.4";
|
||||
|
||||
/**
|
||||
* OpenCV Library version 2.4.5.
|
||||
*/
|
||||
public static final String OPENCV_VERSION_2_4_5 = "2.4.5";
|
||||
|
||||
/**
|
||||
* OpenCV Library version 2.4.6.
|
||||
*/
|
||||
public static final String OPENCV_VERSION_2_4_6 = "2.4.6";
|
||||
|
||||
/**
|
||||
* OpenCV Library version 2.4.7.
|
||||
*/
|
||||
public static final String OPENCV_VERSION_2_4_7 = "2.4.7";
|
||||
|
||||
/**
|
||||
* OpenCV Library version 2.4.8.
|
||||
*/
|
||||
public static final String OPENCV_VERSION_2_4_8 = "2.4.8";
|
||||
|
||||
/**
|
||||
* OpenCV Library version 2.4.9.
|
||||
*/
|
||||
public static final String OPENCV_VERSION_2_4_9 = "2.4.9";
|
||||
|
||||
/**
|
||||
* OpenCV Library version 2.4.10.
|
||||
*/
|
||||
public static final String OPENCV_VERSION_2_4_10 = "2.4.10";
|
||||
|
||||
/**
|
||||
* OpenCV Library version 2.4.11.
|
||||
*/
|
||||
public static final String OPENCV_VERSION_2_4_11 = "2.4.11";
|
||||
|
||||
/**
|
||||
* OpenCV Library version 2.4.12.
|
||||
*/
|
||||
public static final String OPENCV_VERSION_2_4_12 = "2.4.12";
|
||||
|
||||
/**
|
||||
* OpenCV Library version 2.4.13.
|
||||
*/
|
||||
public static final String OPENCV_VERSION_2_4_13 = "2.4.13";
|
||||
|
||||
/**
|
||||
* OpenCV Library version 3.0.0.
|
||||
*/
|
||||
public static final String OPENCV_VERSION_3_0_0 = "3.0.0";
|
||||
|
||||
/**
|
||||
* OpenCV Library version 3.1.0.
|
||||
*/
|
||||
public static final String OPENCV_VERSION_3_1_0 = "3.1.0";
|
||||
|
||||
/**
|
||||
* OpenCV Library version 3.2.0.
|
||||
*/
|
||||
public static final String OPENCV_VERSION_3_2_0 = "3.2.0";
|
||||
|
||||
/**
|
||||
* OpenCV Library version 3.3.0.
|
||||
*/
|
||||
public static final String OPENCV_VERSION_3_3_0 = "3.3.0";
|
||||
|
||||
/**
|
||||
* OpenCV Library version 3.4.0.
|
||||
*/
|
||||
public static final String OPENCV_VERSION_3_4_0 = "3.4.0";
|
||||
|
||||
/**
|
||||
* Current OpenCV Library version
|
||||
*/
|
||||
public static final String OPENCV_VERSION = "@OPENCV_VERSION_MAJOR@.@OPENCV_VERSION_MINOR@.@OPENCV_VERSION_PATCH@";
|
||||
|
||||
|
||||
/**
|
||||
* Loads and initializes OpenCV library from current application package. Roughly, it's an analog of system.loadLibrary("opencv_java").
|
||||
* @return Returns true is initialization of OpenCV was successful.
|
||||
*/
|
||||
public static boolean initDebug()
|
||||
{
|
||||
return StaticHelper.initOpenCV(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads and initializes OpenCV library from current application package. Roughly, it's an analog of system.loadLibrary("opencv_java").
|
||||
* @param InitCuda load and initialize CUDA runtime libraries.
|
||||
* @return Returns true is initialization of OpenCV was successful.
|
||||
*/
|
||||
public static boolean initDebug(boolean InitCuda)
|
||||
{
|
||||
return StaticHelper.initOpenCV(InitCuda);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads and initializes OpenCV library using OpenCV Engine service.
|
||||
* @param Version OpenCV library version.
|
||||
* @param AppContext application context for connecting to the service.
|
||||
* @param Callback object, that implements LoaderCallbackInterface for handling the connection status.
|
||||
* @return Returns true if initialization of OpenCV is successful.
|
||||
*/
|
||||
public static boolean initAsync(String Version, Context AppContext,
|
||||
LoaderCallbackInterface Callback)
|
||||
{
|
||||
return AsyncServiceHelper.initOpenCV(Version, AppContext, Callback);
|
||||
}
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
package org.opencv.android;
|
||||
|
||||
import org.opencv.core.Core;
|
||||
|
||||
import java.util.StringTokenizer;
|
||||
import android.util.Log;
|
||||
|
||||
class StaticHelper {
|
||||
|
||||
public static boolean initOpenCV(boolean InitCuda)
|
||||
{
|
||||
boolean result;
|
||||
String libs = "";
|
||||
|
||||
if(InitCuda)
|
||||
{
|
||||
loadLibrary("cudart");
|
||||
loadLibrary("nppc");
|
||||
loadLibrary("nppi");
|
||||
loadLibrary("npps");
|
||||
loadLibrary("cufft");
|
||||
loadLibrary("cublas");
|
||||
}
|
||||
|
||||
Log.d(TAG, "Trying to get library list");
|
||||
|
||||
try
|
||||
{
|
||||
System.loadLibrary("opencv_info");
|
||||
libs = getLibraryList();
|
||||
}
|
||||
catch(UnsatisfiedLinkError e)
|
||||
{
|
||||
Log.e(TAG, "OpenCV error: Cannot load info library for OpenCV");
|
||||
}
|
||||
|
||||
Log.d(TAG, "Library list: \"" + libs + "\"");
|
||||
Log.d(TAG, "First attempt to load libs");
|
||||
if (initOpenCVLibs(libs))
|
||||
{
|
||||
Log.d(TAG, "First attempt to load libs is OK");
|
||||
String eol = System.getProperty("line.separator");
|
||||
for (String str : Core.getBuildInformation().split(eol))
|
||||
Log.i(TAG, str);
|
||||
|
||||
result = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.d(TAG, "First attempt to load libs fails");
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean loadLibrary(String Name)
|
||||
{
|
||||
boolean result = true;
|
||||
|
||||
Log.d(TAG, "Trying to load library " + Name);
|
||||
try
|
||||
{
|
||||
System.loadLibrary(Name);
|
||||
Log.d(TAG, "Library " + Name + " loaded");
|
||||
}
|
||||
catch(UnsatisfiedLinkError e)
|
||||
{
|
||||
Log.d(TAG, "Cannot load library \"" + Name + "\"");
|
||||
e.printStackTrace();
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean initOpenCVLibs(String Libs)
|
||||
{
|
||||
Log.d(TAG, "Trying to init OpenCV libs");
|
||||
|
||||
boolean result = true;
|
||||
|
||||
if ((null != Libs) && (Libs.length() != 0))
|
||||
{
|
||||
Log.d(TAG, "Trying to load libs by dependency list");
|
||||
StringTokenizer splitter = new StringTokenizer(Libs, ";");
|
||||
while(splitter.hasMoreTokens())
|
||||
{
|
||||
result &= loadLibrary(splitter.nextToken());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If dependencies list is not defined or empty.
|
||||
result = loadLibrary("opencv_java4");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static final String TAG = "OpenCV/StaticHelper";
|
||||
|
||||
private static native String getLibraryList();
|
||||
}
|
@ -0,0 +1,139 @@
|
||||
package org.opencv.android;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
import org.opencv.core.CvException;
|
||||
import org.opencv.core.CvType;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.imgcodecs.Imgcodecs;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class Utils {
|
||||
|
||||
public static String exportResource(Context context, int resourceId) {
|
||||
return exportResource(context, resourceId, "OpenCV_data");
|
||||
}
|
||||
|
||||
public static String exportResource(Context context, int resourceId, String dirname) {
|
||||
String fullname = context.getResources().getString(resourceId);
|
||||
String resName = fullname.substring(fullname.lastIndexOf("/") + 1);
|
||||
try {
|
||||
InputStream is = context.getResources().openRawResource(resourceId);
|
||||
File resDir = context.getDir(dirname, Context.MODE_PRIVATE);
|
||||
File resFile = new File(resDir, resName);
|
||||
|
||||
FileOutputStream os = new FileOutputStream(resFile);
|
||||
|
||||
byte[] buffer = new byte[4096];
|
||||
int bytesRead;
|
||||
while ((bytesRead = is.read(buffer)) != -1) {
|
||||
os.write(buffer, 0, bytesRead);
|
||||
}
|
||||
is.close();
|
||||
os.close();
|
||||
|
||||
return resFile.getAbsolutePath();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new CvException("Failed to export resource " + resName
|
||||
+ ". Exception thrown: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Mat loadResource(Context context, int resourceId) throws IOException
|
||||
{
|
||||
return loadResource(context, resourceId, -1);
|
||||
}
|
||||
|
||||
public static Mat loadResource(Context context, int resourceId, int flags) throws IOException
|
||||
{
|
||||
InputStream is = context.getResources().openRawResource(resourceId);
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream(is.available());
|
||||
|
||||
byte[] buffer = new byte[4096];
|
||||
int bytesRead;
|
||||
while ((bytesRead = is.read(buffer)) != -1) {
|
||||
os.write(buffer, 0, bytesRead);
|
||||
}
|
||||
is.close();
|
||||
|
||||
Mat encoded = new Mat(1, os.size(), CvType.CV_8U);
|
||||
encoded.put(0, 0, os.toByteArray());
|
||||
os.close();
|
||||
|
||||
Mat decoded = Imgcodecs.imdecode(encoded, flags);
|
||||
encoded.release();
|
||||
|
||||
return decoded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts Android Bitmap to OpenCV Mat.
|
||||
* <p>
|
||||
* This function converts an Android Bitmap image to the OpenCV Mat.
|
||||
* <br>'ARGB_8888' and 'RGB_565' input Bitmap formats are supported.
|
||||
* <br>The output Mat is always created of the same size as the input Bitmap and of the 'CV_8UC4' type,
|
||||
* it keeps the image in RGBA format.
|
||||
* <br>This function throws an exception if the conversion fails.
|
||||
* @param bmp is a valid input Bitmap object of the type 'ARGB_8888' or 'RGB_565'.
|
||||
* @param mat is a valid output Mat object, it will be reallocated if needed, so it may be empty.
|
||||
* @param unPremultiplyAlpha is a flag, that determines, whether the bitmap needs to be converted from alpha premultiplied format (like Android keeps 'ARGB_8888' ones) to regular one; this flag is ignored for 'RGB_565' bitmaps.
|
||||
*/
|
||||
public static void bitmapToMat(Bitmap bmp, Mat mat, boolean unPremultiplyAlpha) {
|
||||
if (bmp == null)
|
||||
throw new IllegalArgumentException("bmp == null");
|
||||
if (mat == null)
|
||||
throw new IllegalArgumentException("mat == null");
|
||||
nBitmapToMat2(bmp, mat.nativeObj, unPremultiplyAlpha);
|
||||
}
|
||||
|
||||
/**
|
||||
* Short form of the bitmapToMat(bmp, mat, unPremultiplyAlpha=false).
|
||||
* @param bmp is a valid input Bitmap object of the type 'ARGB_8888' or 'RGB_565'.
|
||||
* @param mat is a valid output Mat object, it will be reallocated if needed, so Mat may be empty.
|
||||
*/
|
||||
public static void bitmapToMat(Bitmap bmp, Mat mat) {
|
||||
bitmapToMat(bmp, mat, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts OpenCV Mat to Android Bitmap.
|
||||
* <p>
|
||||
* <br>This function converts an image in the OpenCV Mat representation to the Android Bitmap.
|
||||
* <br>The input Mat object has to be of the types 'CV_8UC1' (gray-scale), 'CV_8UC3' (RGB) or 'CV_8UC4' (RGBA).
|
||||
* <br>The output Bitmap object has to be of the same size as the input Mat and of the types 'ARGB_8888' or 'RGB_565'.
|
||||
* <br>This function throws an exception if the conversion fails.
|
||||
*
|
||||
* @param mat is a valid input Mat object of types 'CV_8UC1', 'CV_8UC3' or 'CV_8UC4'.
|
||||
* @param bmp is a valid Bitmap object of the same size as the Mat and of type 'ARGB_8888' or 'RGB_565'.
|
||||
* @param premultiplyAlpha is a flag, that determines, whether the Mat needs to be converted to alpha premultiplied format (like Android keeps 'ARGB_8888' bitmaps); the flag is ignored for 'RGB_565' bitmaps.
|
||||
*/
|
||||
public static void matToBitmap(Mat mat, Bitmap bmp, boolean premultiplyAlpha) {
|
||||
if (mat == null)
|
||||
throw new IllegalArgumentException("mat == null");
|
||||
if (bmp == null)
|
||||
throw new IllegalArgumentException("bmp == null");
|
||||
nMatToBitmap2(mat.nativeObj, bmp, premultiplyAlpha);
|
||||
}
|
||||
|
||||
/**
|
||||
* Short form of the <b>matToBitmap(mat, bmp, premultiplyAlpha=false)</b>
|
||||
* @param mat is a valid input Mat object of the types 'CV_8UC1', 'CV_8UC3' or 'CV_8UC4'.
|
||||
* @param bmp is a valid Bitmap object of the same size as the Mat and of type 'ARGB_8888' or 'RGB_565'.
|
||||
*/
|
||||
public static void matToBitmap(Mat mat, Bitmap bmp) {
|
||||
matToBitmap(mat, bmp, false);
|
||||
}
|
||||
|
||||
|
||||
private static native void nBitmapToMat2(Bitmap b, long m_addr, boolean unPremultiplyAlpha);
|
||||
|
||||
private static native void nMatToBitmap2(long m_addr, Bitmap b, boolean premultiplyAlpha);
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package org.opencv.engine;
|
||||
|
||||
/**
|
||||
* Class provides a Java interface for OpenCV Engine Service. It's synchronous with native OpenCVEngine class.
|
||||
*/
|
||||
interface OpenCVEngineInterface
|
||||
{
|
||||
/**
|
||||
* @return Returns service version.
|
||||
*/
|
||||
int getEngineVersion();
|
||||
|
||||
/**
|
||||
* Finds an installed OpenCV library.
|
||||
* @param OpenCV version.
|
||||
* @return Returns path to OpenCV native libs or an empty string if OpenCV can not be found.
|
||||
*/
|
||||
String getLibPathByVersion(String version);
|
||||
|
||||
/**
|
||||
* Tries to install defined version of OpenCV from Google Play Market.
|
||||
* @param OpenCV version.
|
||||
* @return Returns true if installation was successful or OpenCV package has been already installed.
|
||||
*/
|
||||
boolean installVersion(String version);
|
||||
|
||||
/**
|
||||
* Returns list of libraries in loading order, separated by semicolon.
|
||||
* @param OpenCV version.
|
||||
* @return Returns names of OpenCV libraries, separated by semicolon.
|
||||
*/
|
||||
String getLibraryList(String version);
|
||||
}
|
Reference in New Issue
Block a user