opencv/android/apps/CVCamera/src/com/theveganrobot/cvcamera/CVCamera.java
2010-10-12 02:21:30 +00:00

499 lines
12 KiB
Java

package com.theveganrobot.cvcamera;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.LinkedList;
import java.util.Scanner;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.ViewGroup.LayoutParams;
import android.widget.AnalogClock;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.Toast;
import com.opencv.camera.NativePreviewer;
import com.opencv.camera.NativeProcessor;
import com.opencv.camera.NativeProcessor.PoolCallback;
import com.opencv.jni.image_pool;
import com.opencv.opengl.GL2CameraViewer;
import com.theveganrobot.cvcamera.jni.Processor;
import com.theveganrobot.cvcamera.jni.cvcamera;
public class CVCamera extends Activity {
static final int DIALOG_CALIBRATING = 0;
static final int DIALOG_CALIBRATION_FILE = 1;
private static final int DIALOG_OPENING_TUTORIAL = 2;
private static final int DIALOG_TUTORIAL_FAST = 3;
private static final int DIALOG_TUTORIAL_SURF = 4;
private static final int DIALOG_TUTORIAL_STAR = 5;
private static final int DIALOG_TUTORIAL_CHESS = 6;
private boolean captureChess;
ProgressDialog makeCalibDialog() {
ProgressDialog progressDialog;
progressDialog = new ProgressDialog(this);
progressDialog.setMessage("Callibrating. Please wait...");
progressDialog.setCancelable(false);
return progressDialog;
}
void toasts(int id) {
switch (id) {
case DIALOG_OPENING_TUTORIAL:
Toast.makeText(this, "Try clicking the menu for CV options.",
Toast.LENGTH_LONG).show();
break;
case DIALOG_TUTORIAL_FAST:
Toast.makeText(this, "Detecting and Displaying FAST features",
Toast.LENGTH_LONG).show();
break;
case DIALOG_TUTORIAL_SURF:
Toast.makeText(this, "Detecting and Displaying SURF features",
Toast.LENGTH_LONG).show();
break;
case DIALOG_TUTORIAL_STAR:
Toast.makeText(this, "Detecting and Displaying STAR features",
Toast.LENGTH_LONG).show();
break;
case DIALOG_TUTORIAL_CHESS:
Toast
.makeText(
this,
"Calibration Mode, Point at a chessboard pattern and press the camera button, space,"
+ "or the DPAD to capture.",
Toast.LENGTH_LONG).show();
break;
default:
break;
}
}
@Override
protected Dialog onCreateDialog(int id) {
Dialog dialog;
switch (id) {
case DIALOG_CALIBRATING:
dialog = makeCalibDialog();
break;
case DIALOG_CALIBRATION_FILE:
dialog = makeCalibFileAlert();
break;
default:
dialog = null;
}
return dialog;
}
private Dialog makeCalibFileAlert() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(calib_text).setTitle(
"camera.yml at " + calib_file_loc).setCancelable(false)
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
}
});
AlertDialog alert = builder.create();
return alert;
}
/*
* (non-Javadoc)
*
* @see android.app.Activity#onKeyUp(int, android.view.KeyEvent)
*/
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_CAMERA:
case KeyEvent.KEYCODE_SPACE:
case KeyEvent.KEYCODE_DPAD_CENTER:
captureChess = true;
return true;
default:
return super.onKeyUp(keyCode, event);
}
}
/*
* (non-Javadoc)
*
* @see android.app.Activity#onKeyLongPress(int, android.view.KeyEvent)
*/
@Override
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
return super.onKeyLongPress(keyCode, event);
}
/**
* Avoid that the screen get's turned off by the system.
*/
public void disableScreenTurnOff() {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
/**
* Set's the orientation to landscape, as this is needed by AndAR.
*/
public void setOrientation() {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
/**
* Maximize the application.
*/
public void setFullscreen() {
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
public void setNoTitle() {
requestWindowFeature(Window.FEATURE_NO_TITLE);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add("FAST");
menu.add("STAR");
menu.add("SURF");
menu.add("Chess");
return true;
}
private NativePreviewer mPreview;
private GL2CameraViewer glview;
@Override
public boolean onOptionsItemSelected(MenuItem item) {
LinkedList<PoolCallback> defaultcallbackstack = new LinkedList<PoolCallback>();
defaultcallbackstack.addFirst(glview.getDrawCallback());
if (item.getTitle().equals("FAST")) {
defaultcallbackstack.addFirst(new FastProcessor());
toasts(DIALOG_TUTORIAL_FAST);
}
else if (item.getTitle().equals("Chess")) {
defaultcallbackstack.addFirst(new CalibrationProcessor());
toasts(DIALOG_TUTORIAL_CHESS);
}
else if (item.getTitle().equals("STAR")) {
defaultcallbackstack.addFirst(new STARProcessor());
toasts(DIALOG_TUTORIAL_STAR);
}
else if (item.getTitle().equals("SURF")) {
defaultcallbackstack.addFirst(new SURFProcessor());
toasts(DIALOG_TUTORIAL_SURF);
}
mPreview.addCallbackStack(defaultcallbackstack);
return true;
}
@Override
public void onOptionsMenuClosed(Menu menu) {
// TODO Auto-generated method stub
super.onOptionsMenuClosed(menu);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setFullscreen();
disableScreenTurnOff();
FrameLayout frame = new FrameLayout(this);
// Create our Preview view and set it as the content of our activity.
mPreview = new NativePreviewer(getApplication(), 640, 480);
LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
params.height = getWindowManager().getDefaultDisplay().getHeight();
params.width = (int) (params.height * 4.0 / 2.88);
LinearLayout vidlay = new LinearLayout(getApplication());
vidlay.setGravity(Gravity.CENTER);
vidlay.addView(mPreview, params);
frame.addView(vidlay);
// make the glview overlay ontop of video preview
mPreview.setZOrderMediaOverlay(false);
glview = new GL2CameraViewer(getApplication(), false, 0, 0);
glview.setZOrderMediaOverlay(true);
glview.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT));
ImageButton capture_button = new ImageButton(getApplicationContext());
capture_button.setImageDrawable(getResources().getDrawable(android.R.drawable.ic_menu_camera));
capture_button.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
capture_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
captureChess = true;
}
});
LinearLayout buttons = new LinearLayout(getApplicationContext());
buttons.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
buttons.addView(capture_button);
Button focus_button = new Button(getApplicationContext());
focus_button.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
focus_button.setText("Focus");
focus_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mPreview.postautofocus(100);
}
});
buttons.addView(focus_button);
frame.addView(glview);
frame.addView(buttons);
setContentView(frame);
toasts(DIALOG_OPENING_TUTORIAL);
}
@Override
public boolean onTrackballEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_UP){
captureChess = true;
return true;
}
return super.onTrackballEvent(event);
}
@Override
protected void onPause() {
super.onPause();
//clears the callback stack
mPreview.onPause();
glview.onPause();
}
@Override
protected void onResume() {
super.onResume();
glview.onResume();
//add an initiall callback stack to the preview on resume...
//this one will just draw the frames to opengl
LinkedList<NativeProcessor.PoolCallback> cbstack = new LinkedList<PoolCallback>();
cbstack.add(glview.getDrawCallback());
mPreview.addCallbackStack(cbstack);
mPreview.onResume();
}
// final processor so taht these processor callbacks can access it
final Processor processor = new Processor();
class FastProcessor implements NativeProcessor.PoolCallback {
@Override
public void process(int idx, image_pool pool, long timestamp,
NativeProcessor nativeProcessor) {
processor.detectAndDrawFeatures(idx, pool, cvcamera.DETECT_FAST);
}
}
class STARProcessor implements NativeProcessor.PoolCallback {
@Override
public void process(int idx, image_pool pool, long timestamp,
NativeProcessor nativeProcessor) {
processor.detectAndDrawFeatures(idx, pool, cvcamera.DETECT_STAR);
}
}
class SURFProcessor implements NativeProcessor.PoolCallback {
@Override
public void process(int idx, image_pool pool, long timestamp,
NativeProcessor nativeProcessor) {
processor.detectAndDrawFeatures(idx, pool, cvcamera.DETECT_SURF);
}
}
String calib_text = null;
String calib_file_loc = null;
class CalibrationProcessor implements NativeProcessor.PoolCallback {
boolean calibrated = false;
@Override
public void process(int idx, image_pool pool, long timestamp,
NativeProcessor nativeProcessor) {
if (calibrated) {
processor.drawText(idx, pool, "Calibrated successfully");
return;
}
if (processor.getNumberDetectedChessboards() == 10) {
File opencvdir = new File(Environment
.getExternalStorageDirectory(), "opencv");
if (!opencvdir.exists()) {
opencvdir.mkdir();
}
File calibfile = new File(opencvdir, "camera.yml");
calib_file_loc = calibfile.getAbsolutePath();
processor.calibrate(calibfile.getAbsolutePath());
Log.i("chessboard", "calibrated");
calibrated = true;
processor.resetChess();
runOnUiThread(new Runnable() {
@Override
public void run() {
removeDialog(DIALOG_CALIBRATING);
}
});
try {
StringBuilder text = new StringBuilder();
String NL = System.getProperty("line.separator");
Scanner scanner = new Scanner(calibfile);
try {
while (scanner.hasNextLine()) {
text.append(scanner.nextLine() + NL);
}
} finally {
scanner.close();
}
calib_text = text.toString();
runOnUiThread(new Runnable() {
@Override
public void run() {
showDialog(DIALOG_CALIBRATION_FILE);
}
});
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else if (captureChess
&& processor.detectAndDrawChessboard(idx, pool)) {
runOnUiThread(new Runnable() {
String numchess = String.valueOf(processor
.getNumberDetectedChessboards());
@Override
public void run() {
Toast.makeText(CVCamera.this,
"Detected " + numchess + " of 10 chessboards",
Toast.LENGTH_SHORT).show();
}
});
Log.i("cvcamera",
"detected a chessboard, n chess boards found: "
+ String.valueOf(processor
.getNumberDetectedChessboards()));
}
captureChess = false;
if (processor.getNumberDetectedChessboards() == 10) {
runOnUiThread(new Runnable() {
@Override
public void run() {
showDialog(DIALOG_CALIBRATING);
}
});
processor.drawText(idx, pool, "Calibrating, please wait.");
}
if (processor.getNumberDetectedChessboards() < 10) {
processor.drawText(idx, pool, "found "
+ processor.getNumberDetectedChessboards()
+ "/10 chessboards");
}
}
}
}