--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.theveganrobot.cvcamera" android:versionCode="7" android:versionName="7.0"
+ >
+ <application android:debuggable="false" android:icon="@drawable/icon">
+ <activity android:name=".CVCamera" android:screenOrientation="landscape"
+ android:configChanges="orientation|keyboardHidden|keyboard"
+ android:label="@string/app_name"
+ >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ </application>
+
+
+
+ <uses-feature android:glEsVersion="0x00020000" android:required="true"/>
+ <uses-feature android:name="android.hardware.camera" android:required="true"/>
+
+ <uses-permission android:name="android.permission.CAMERA"></uses-permission>
+
+
+
+ <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="7" />
+
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
+</manifest>
\ No newline at end of file
--- /dev/null
+# The path to the NDK, requires crystax version r-4 for now, due to support
+# for the standard library
+
+# load environment from local make file
+LOCAL_ENV_MK=local.env.mk
+ifneq "$(wildcard $(LOCAL_ENV_MK))" ""
+include $(LOCAL_ENV_MK)
+else
+$(shell cp sample.$(LOCAL_ENV_MK) $(LOCAL_ENV_MK))
+$(info ERROR local environement not setup! try:)
+$(info gedit $(LOCAL_ENV_MK))
+$(error Please setup the $(LOCAL_ENV_MK) - the default was just created')
+endif
+
+ANDROID_NDK_BASE = $(ANDROID_NDK_ROOT)
+
+$(info OPENCV_CONFIG = $(OPENCV_CONFIG))
+
+ifndef PROJECT_PATH
+$(info PROJECT_PATH defaulting to this directory)
+PROJECT_PATH=.
+endif
+
+
+# The name of the native library
+LIBNAME = libcvcamera.so
+
+
+# Find all the C++ sources in the native folder
+SOURCES = $(wildcard jni/*.cpp)
+HEADERS = $(wildcard jni/*.h)
+
+ANDROID_MKS = $(wildcard jni/*.mk)
+
+SWIG_IS = $(wildcard jni/*.i)
+
+SWIG_MAIN = jni/cvcamera.i
+
+SWIG_JAVA_DIR = src/com/theveganrobot/cvcamera/jni
+SWIG_JAVA_OUT = $(wildcard $(SWIG_JAVA_DIR)/*.java)
+
+
+SWIG_C_DIR = jni/gen
+SWIG_C_OUT = $(SWIG_C_DIR)/cvcamera_swig.cpp
+
+BUILD_DEFS=OPENCV_CONFIG=$(OPENCV_CONFIG) \
+ PROJECT_PATH=$(PROJECT_PATH) \
+ V=$(V) \
+ $(NDK_FLAGS)
+
+# The real native library stripped of symbols
+LIB = libs/armeabi-v7a/$(LIBNAME) libs/armeabi/$(LIBNAME)
+
+
+all: $(LIB)
+
+
+#calls the ndk-build script, passing it OPENCV_ROOT and OPENCV_LIBS_DIR
+$(LIB): $(SWIG_C_OUT) $(SOURCES) $(HEADERS) $(ANDROID_MKS)
+ $(ANDROID_NDK_BASE)/ndk-build $(BUILD_DEFS)
+
+
+#this creates the swig wrappers
+$(SWIG_C_OUT): $(SWIG_IS)
+ make clean-swig &&\
+ mkdir -p $(SWIG_C_DIR) &&\
+ mkdir -p $(SWIG_JAVA_DIR) &&\
+ swig -java -c++ -I../../android-jni/jni -package "com.theveganrobot.cvcamera.jni" \
+ -outdir $(SWIG_JAVA_DIR) \
+ -o $(SWIG_C_OUT) $(SWIG_MAIN)
+
+
+#clean targets
+.PHONY: clean clean-swig cleanall
+
+#this deletes the generated swig java and the generated c wrapper
+clean-swig:
+ rm -f $(SWIG_JAVA_OUT) $(SWIG_C_OUT)
+
+#does clean-swig and then uses the ndk-build clean
+clean: clean-swig
+ $(ANDROID_NDK_BASE)/ndk-build clean $(BUILD_DEFS)
+
--- /dev/null
+see http://code.google.com/p/android-opencv/wiki/CVCamera
+
--- /dev/null
+make OPENCV_ROOT=../../opencv V=0 clean
--- /dev/null
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+android.library.reference.1=../../android-jni
+# Project target.
+target=android-7
--- /dev/null
+# date: Summer, 2010
+# author: Ethan Rublee
+# contact: ethan.rublee@gmail.com
+#
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+#define OPENCV_INCLUDES and OPENCV_LIBS
+include $(OPENCV_CONFIG)
+
+LOCAL_LDLIBS += $(OPENCV_LIBS) $(ANDROID_OPENCV_LIBS) -llog -lGLESv2
+
+LOCAL_C_INCLUDES += $(OPENCV_INCLUDES) $(ANDROID_OPENCV_INCLUDES)
+
+LOCAL_MODULE := cvcamera
+
+LOCAL_SRC_FILES := Processor.cpp gen/cvcamera_swig.cpp
+
+include $(BUILD_SHARED_LIBRARY)
+
--- /dev/null
+# The ARMv7 is significanly faster due to the use of the hardware FPU
+APP_ABI := armeabi armeabi-v7a
\ No newline at end of file
--- /dev/null
+/*
+ * Processor.cpp
+ *
+ * Created on: Jun 13, 2010
+ * Author: ethan
+ */
+
+#include "Processor.h"
+
+
+#include <sys/stat.h>
+
+using namespace cv;
+
+Processor::Processor() :
+ stard(20/*max_size*/, 8/*response_threshold*/,
+ 15/*line_threshold_projected*/,
+ 8/*line_threshold_binarized*/, 5/*suppress_nonmax_size*/),
+ fastd(20/*threshold*/, true/*nonmax_suppression*/),
+ surfd(100./*hessian_threshold*/, 1/*octaves*/, 2/*octave_layers*/)
+
+{
+
+}
+
+Processor::~Processor() {
+ // TODO Auto-generated destructor stub
+}
+
+void Processor::detectAndDrawFeatures(int input_idx, image_pool* pool,int feature_type) {
+ FeatureDetector* fd = 0;
+
+ switch (feature_type) {
+ case DETECT_SURF:
+ fd = &surfd;
+ break;
+ case DETECT_FAST:
+ fd = &fastd;
+ break;
+ case DETECT_STAR:
+ fd = &stard;
+ break;
+ }
+
+ Mat greyimage;
+ pool->getGrey(input_idx, greyimage);
+ //Mat* grayimage = pool->getYUV(input_idx);
+
+ Mat* img = pool->getImage(input_idx);
+
+ if (!img || greyimage.empty() || fd == 0)
+ return; //no image at input_idx!
+
+
+ keypoints.clear();
+
+ //if(grayimage->step1() > sizeof(uchar)) return;
+ //cvtColor(*img,*grayimage,CV_RGB2GRAY);
+
+
+ fd->detect(greyimage, keypoints);
+
+ for (vector<KeyPoint>::const_iterator it = keypoints.begin(); it
+ != keypoints.end(); ++it) {
+ circle(*img, it->pt, 3, cvScalar(255, 0, 255, 0));
+ }
+
+ //pool->addImage(output_idx,outimage);
+
+}
+static double computeReprojectionErrors(
+ const vector<vector<Point3f> >& objectPoints, const vector<vector<
+ Point2f> >& imagePoints, const vector<Mat>& rvecs,
+ const vector<Mat>& tvecs, const Mat& cameraMatrix,
+ const Mat& distCoeffs, vector<float>& perViewErrors) {
+ vector<Point2f> imagePoints2;
+ int i, totalPoints = 0;
+ double totalErr = 0, err;
+ perViewErrors.resize(objectPoints.size());
+
+ for (i = 0; i < (int) objectPoints.size(); i++) {
+ projectPoints(Mat(objectPoints[i]), rvecs[i], tvecs[i], cameraMatrix,
+ distCoeffs, imagePoints2);
+ err = norm(Mat(imagePoints[i]), Mat(imagePoints2), CV_L1 );
+ int n = (int) objectPoints[i].size();
+ perViewErrors[i] = err / n;
+ totalErr += err;
+ totalPoints += n;
+ }
+
+ return totalErr / totalPoints;
+}
+
+static void calcChessboardCorners(Size boardSize, float squareSize, vector<
+ Point3f>& corners) {
+ corners.resize(0);
+
+ for (int i = 0; i < boardSize.height; i++)
+ for (int j = 0; j < boardSize.width; j++)
+ corners.push_back(Point3f(float(j * squareSize), float(i
+ * squareSize), 0));
+}
+
+/**from opencv/samples/cpp/calibration.cpp
+ *
+ */
+static bool runCalibration(vector<vector<Point2f> > imagePoints,
+ Size imageSize, Size boardSize, float squareSize, float aspectRatio,
+ int flags, Mat& cameraMatrix, Mat& distCoeffs, vector<Mat>& rvecs,
+ vector<Mat>& tvecs, vector<float>& reprojErrs, double& totalAvgErr) {
+ cameraMatrix = Mat::eye(3, 3, CV_64F);
+ if (flags & CV_CALIB_FIX_ASPECT_RATIO)
+ cameraMatrix.at<double> (0, 0) = aspectRatio;
+
+ distCoeffs = Mat::zeros(5, 1, CV_64F);
+
+ vector<vector<Point3f> > objectPoints(1);
+ calcChessboardCorners(boardSize, squareSize, objectPoints[0]);
+ for (size_t i = 1; i < imagePoints.size(); i++)
+ objectPoints.push_back(objectPoints[0]);
+
+ calibrateCamera(objectPoints, imagePoints, imageSize, cameraMatrix,
+ distCoeffs, rvecs, tvecs, flags);
+
+ bool ok = checkRange(cameraMatrix, CV_CHECK_QUIET ) && checkRange(
+ distCoeffs, CV_CHECK_QUIET );
+
+ totalAvgErr = computeReprojectionErrors(objectPoints, imagePoints, rvecs,
+ tvecs, cameraMatrix, distCoeffs, reprojErrs);
+
+ return ok;
+}
+
+bool Processor::detectAndDrawChessboard(int idx,image_pool* pool) {
+
+ Mat grey;
+ pool->getGrey(idx, grey);
+ if (grey.empty())
+ return false;
+ vector<Point2f> corners;
+
+ IplImage iplgrey = grey;
+ if (!cvCheckChessboard(&iplgrey, Size(6, 8)))
+ return false;
+ bool patternfound = findChessboardCorners(grey, Size(6, 8), corners);
+
+ Mat * img = pool->getImage(idx);
+
+ if (corners.size() < 1)
+ return false;
+
+ cornerSubPix(grey, corners, Size(11, 11), Size(-1, -1), TermCriteria(
+ CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));
+
+ if(patternfound)
+ imagepoints.push_back(corners);
+
+ drawChessboardCorners(*img, Size(6, 8), Mat(corners), patternfound);
+
+ imgsize = grey.size();
+
+ return patternfound;
+
+}
+
+void Processor::drawText(int i, image_pool* pool, const char* ctext){
+ // Use "y" to show that the baseLine is about
+ string text = ctext;
+ int fontFace = FONT_HERSHEY_COMPLEX_SMALL;
+ double fontScale = .8;
+ int thickness = .5;
+
+ Mat img = *pool->getImage(i);
+
+ int baseline=0;
+ Size textSize = getTextSize(text, fontFace,
+ fontScale, thickness, &baseline);
+ baseline += thickness;
+
+ // center the text
+ Point textOrg((img.cols - textSize.width)/2,
+ (img.rows - textSize.height *2));
+
+ // draw the box
+ rectangle(img, textOrg + Point(0, baseline),
+ textOrg + Point(textSize.width, -textSize.height),
+ Scalar(0,0,255),CV_FILLED);
+ // ... and the baseline first
+ line(img, textOrg + Point(0, thickness),
+ textOrg + Point(textSize.width, thickness),
+ Scalar(0, 0, 255));
+
+ // then put the text itself
+ putText(img, text, textOrg, fontFace, fontScale,
+ Scalar::all(255), thickness, 8);
+}
+void saveCameraParams(const string& filename, Size imageSize, Size boardSize,
+ float squareSize, float aspectRatio, int flags,
+ const Mat& cameraMatrix, const Mat& distCoeffs,
+ const vector<Mat>& rvecs, const vector<Mat>& tvecs,
+ const vector<float>& reprojErrs,
+ const vector<vector<Point2f> >& imagePoints, double totalAvgErr) {
+ FileStorage fs(filename, FileStorage::WRITE);
+
+ time_t t;
+ time(&t);
+ struct tm *t2 = localtime(&t);
+ char buf[1024];
+ strftime(buf, sizeof(buf) - 1, "%c", t2);
+
+ fs << "calibration_time" << buf;
+
+ if (!rvecs.empty() || !reprojErrs.empty())
+ fs << "nframes" << (int) std::max(rvecs.size(), reprojErrs.size());
+ fs << "image_width" << imageSize.width;
+ fs << "image_height" << imageSize.height;
+ fs << "board_width" << boardSize.width;
+ fs << "board_height" << boardSize.height;
+ fs << "squareSize" << squareSize;
+
+ if (flags & CV_CALIB_FIX_ASPECT_RATIO)
+ fs << "aspectRatio" << aspectRatio;
+
+ if (flags != 0) {
+ sprintf(buf, "flags: %s%s%s%s",
+ flags & CV_CALIB_USE_INTRINSIC_GUESS ? "+use_intrinsic_guess"
+ : "",
+ flags & CV_CALIB_FIX_ASPECT_RATIO ? "+fix_aspectRatio" : "",
+ flags & CV_CALIB_FIX_PRINCIPAL_POINT ? "+fix_principal_point"
+ : "",
+ flags & CV_CALIB_ZERO_TANGENT_DIST ? "+zero_tangent_dist" : "");
+ cvWriteComment(*fs, buf, 0);
+ }
+
+ fs << "flags" << flags;
+
+ fs << "camera_matrix" << cameraMatrix;
+ fs << "distortion_coefficients" << distCoeffs;
+
+ fs << "avg_reprojection_error" << totalAvgErr;
+ if (!reprojErrs.empty())
+ fs << "per_view_reprojection_errors" << Mat(reprojErrs);
+
+ if (!rvecs.empty() && !tvecs.empty()) {
+ Mat bigmat(rvecs.size(), 6, CV_32F);
+ for (size_t i = 0; i < rvecs.size(); i++) {
+ Mat r = bigmat(Range(i, i + 1), Range(0, 3));
+ Mat t = bigmat(Range(i, i + 1), Range(3, 6));
+ rvecs[i].copyTo(r);
+ tvecs[i].copyTo(t);
+ }
+ cvWriteComment(
+ *fs,
+ "a set of 6-tuples (rotation vector + translation vector) for each view",
+ 0);
+ fs << "extrinsic_parameters" << bigmat;
+ }
+
+ if (!imagePoints.empty()) {
+ Mat imagePtMat(imagePoints.size(), imagePoints[0].size(), CV_32FC2);
+ for (size_t i = 0; i < imagePoints.size(); i++) {
+ Mat r = imagePtMat.row(i).reshape(2, imagePtMat.cols);
+ Mat(imagePoints[i]).copyTo(r);
+ }
+ fs << "image_points" << imagePtMat;
+ }
+}
+void Processor::resetChess() {
+
+ imagepoints.clear();
+}
+
+void Processor::calibrate(const char* filename) {
+
+ vector<Mat> rvecs, tvecs;
+ vector<float> reprojErrs;
+ double totalAvgErr = 0;
+ int flags = 0;
+ bool writeExtrinsics = true;
+ bool writePoints = true;
+
+ bool ok = runCalibration(imagepoints, imgsize, Size(6, 8), 1.f, 1.f,
+ flags, K, distortion, rvecs, tvecs, reprojErrs, totalAvgErr);
+
+
+ if (ok){
+
+ saveCameraParams(filename, imgsize, Size(6, 8), 1.f,
+ 1.f, flags, K, distortion, writeExtrinsics ? rvecs
+ : vector<Mat> (), writeExtrinsics ? tvecs
+ : vector<Mat> (), writeExtrinsics ? reprojErrs
+ : vector<float> (), writePoints ? imagepoints : vector<
+ vector<Point2f> > (), totalAvgErr);
+ }
+
+}
+
+int Processor::getNumberDetectedChessboards() {
+ return imagepoints.size();
+}
--- /dev/null
+/*
+ * Processor.h
+ *
+ * Created on: Jun 13, 2010
+ * Author: ethan
+ */
+
+#ifndef PROCESSOR_H_
+#define PROCESSOR_H_
+
+#include <opencv2/core/core.hpp>
+#include <opencv2/features2d/features2d.hpp>
+#include <opencv2/highgui/highgui.hpp>
+#include <opencv2/imgproc/imgproc.hpp>
+#include <opencv2/calib3d/calib3d.hpp>
+
+
+
+#include <vector>
+
+#include "image_pool.h"
+
+#define DETECT_FAST 0
+#define DETECT_STAR 1
+#define DETECT_SURF 2
+
+class Processor {
+
+ cv::StarFeatureDetector stard;
+ cv::FastFeatureDetector fastd;
+ cv::SurfFeatureDetector surfd;
+ std::vector<cv::KeyPoint> keypoints;
+
+ vector<vector<Point2f> > imagepoints;
+
+ cv::Mat K;
+ cv::Mat distortion;
+ cv::Size imgsize;
+ //image_pool pool;
+public:
+
+ Processor();
+ virtual ~Processor();
+
+ void detectAndDrawFeatures(int idx, image_pool* pool, int feature_type);
+
+ bool detectAndDrawChessboard(int idx,image_pool* pool);
+
+ void resetChess();
+
+ int getNumberDetectedChessboards();
+
+ void calibrate(const char* filename);
+
+ void drawText(int idx, image_pool* pool, const char* text);
+
+
+};
+
+#endif /* PROCESSOR_H_ */
--- /dev/null
+/*
+ * include the headers required by the generated cpp code
+ */
+%{
+#include "Processor.h"
+#include "image_pool.h"
+using namespace cv;
+%}
+
+
+/**
+ * some constants, see Processor.h
+ */
+#define DETECT_FAST 0
+#define DETECT_STAR 1
+#define DETECT_SURF 2
+
+//import the android-cv.i file so that swig is aware of all that has been previous defined
+//notice that it is not an include....
+%import "android-cv.i"
+
+//make sure to import the image_pool as it is
+//referenced by the Processor java generated
+//class
+%typemap(javaimports) Processor "
+import com.opencv.jni.image_pool;// import the image_pool interface for playing nice with
+ // android-opencv
+
+/** Processor - for processing images that are stored in an image pool
+*/"
+
+class Processor {
+public:
+ Processor();
+ virtual ~Processor();
+
+
+
+ void detectAndDrawFeatures(int idx, image_pool* pool, int feature_type);
+
+ bool detectAndDrawChessboard(int idx,image_pool* pool);
+
+ void resetChess();
+
+ int getNumberDetectedChessboards();
+
+ void calibrate(const char* filename);
+
+ void drawText(int idx, image_pool* pool, const char* text);
+
+};
--- /dev/null
+/* File : android-cv.i */
+
+%module cvcamera
+
+
+/*
+ * the java import code muse be included for the opencv jni wrappers
+ * this means that the android project must reference opencv/android as a project
+ * see the default.properties for how this is done
+ */
+%pragma(java) jniclassimports=%{
+import com.opencv.jni.*; //import the android-opencv jni wrappers
+%}
+
+%pragma(java) jniclasscode=%{
+ static {
+ try {
+ //load the cvcamera library, make sure that libcvcamera.so is in your <project>/libs/armeabi directory
+ //so that android sdk automatically installs it along with the app.
+
+ //the android-opencv lib must be loaded first inorder for the cvcamera
+ //lib to be found
+ //check the apk generated, by opening it in an archive manager, to verify that
+ //both these libraries are present
+ System.loadLibrary("android-opencv");
+ System.loadLibrary("cvcamera");
+ } catch (UnsatisfiedLinkError e) {
+ //badness
+ throw e;
+ }
+ }
+
+%}
+
+//include the Processor class swig interface file
+%include "Processor.i"
\ No newline at end of file
--- /dev/null
+android update project --name CVCamera \
+--path .
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ >
+
+</LinearLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <string name="app_name">CVCamera</string>
+<string name="app_description">app to demo using android camera and passing data to opencv layer.</string>
+<string name="Changes">Release 0.0.1 - first demo of using the OpenCV library with camera data</string>
+</resources>
--- /dev/null
+#location of android-opencv port of OpenCV to android
+OPENCV_CONFIG=../../build/android-opencv.mk
+ANDROID_NDK_ROOT=$(HOME)/android-ndk-r4-crystax
+
--- /dev/null
+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");
+ }
+
+ }
+
+ }
+
+}
--- /dev/null
+#!/bin/bash
+echo uninstalling CVCamera from phone
+adb uninstall com.theveganrobot.cvcamera
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.opencv.calibration" android:versionCode="1"
+ android:versionName="1.0">
+
+ <application android:debuggable="true" android:icon="@drawable/icon"
+ android:label="@string/app_name">
+
+ <activity android:name=".Calibration" android:label="@string/app_name"
+ android:screenOrientation="landscape"
+ android:configChanges="orientation|keyboardHidden|keyboard">
+ <intent-filter>
+ <!-- <action android:name="android.intent.action.MAIN" /> -->
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+
+ </activity>
+
+ <activity android:name=".ChessBoardChooser" android:label="@string/app_name"
+ android:screenOrientation="landscape"
+ android:configChanges="orientation|keyboardHidden|keyboard">
+
+ </activity>
+
+ <service android:name=".services.CalibrationService"></service>
+
+ </application>
+
+ <uses-sdk android:minSdkVersion="7" />
+
+ <uses-feature android:glEsVersion="0x00020000" />
+
+ <uses-permission android:name="android.permission.CAMERA"></uses-permission>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
+
+
+</manifest>
--- /dev/null
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+android.library.reference.1=../../android-jni
+# Project target.
+target=android-7
--- /dev/null
+android update project --name Calibration \
+--path .
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:background="@drawable/cameraback">
+ <!--<com.opencv.camera.NativePreviewer-->
+ <!-- <SurfaceView -->
+
+ <com.opencv.camera.NativePreviewer
+
+ android:id="@+id/nativepreviewer"
+
+ android:layout_width="400dip"
+ android:layout_height="300dip"
+ android:layout_alignParentLeft="true"
+ android:layout_margin="20dip"
+ android:gravity="center_horizontal|center_vertical"
+ android:layout_marginRight="20dip"
+ />
+ <LinearLayout
+ android:id="@+id/glview_layout"
+
+ android:layout_width="400dip"
+ android:layout_height="300dip"
+ android:layout_alignParentLeft="true"
+ android:layout_margin="20dip"
+ android:gravity="center_horizontal|center_vertical"
+ android:layout_marginRight="20dip"
+ >
+</LinearLayout>
+ <LinearLayout android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:orientation="vertical"
+ android:layout_margin="20dip"
+ android:gravity="center_horizontal|center_vertical"
+ android:layout_alignParentRight="true">
+
+
+ <ImageButton android:src="@android:drawable/ic_menu_camera"
+ android:id="@+id/capture" android:layout_width="60dip"
+ android:layout_height="60dip"></ImageButton>
+ <ImageButton android:src="@android:drawable/ic_menu_save"
+ android:id="@+id/calibrate" android:layout_width="60dip"
+ android:layout_height="60dip"></ImageButton>
+ <TextView android:id="@+id/numberpatterns"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="10dip"
+ android:background="@android:color/white"
+ android:text="0"/>
+
+
+ </LinearLayout>
+
+
+
+
+</RelativeLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical"
+ android:gravity="center_vertical|center_horizontal">
+ <TextView android:text="@string/patterntext" android:autoLink="web" android:layout_width="wrap_content"
+ android:layout_height="wrap_content" android:padding="20dip"/>
+ <LinearLayout android:id="@+id/LinearLayout01"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical">
+ <TextView android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Corners in width direction:"/>
+ <Spinner android:id="@+id/rows"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:saveEnabled="true"
+ android:prompt="@string/chesspromptx"
+android:entries="@array/chesssizes">
+</Spinner>
+ </LinearLayout>
+
+ <LinearLayout android:id="@+id/LinearLayout01"
+ android:layout_width="wrap_content" android:layout_height="wrap_content"
+ android:gravity="center_vertical">
+ <TextView android:layout_width="wrap_content"
+ android:layout_height="wrap_content" android:text="Corners in height direction:"/>
+ <Spinner android:id="@+id/cols"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:saveEnabled="true"
+ android:prompt="@string/chessprompty"
+android:entries="@array/chesssizes">
+</Spinner>
+</LinearLayout>
+
+</LinearLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<menu
+ xmlns:android="http://schemas.android.com/apk/res/android">
+<item android:id="@+id/patternsize" android:titleCondensed="Size"
+android:title="@string/patternsize"
+android:icon="@drawable/patternicon"
+></item>
+<item android:id="@+id/calibrate"
+android:titleCondensed="Calib"
+android:title="Calibrate"
+></item>
+<item android:id="@+id/help"
+android:titleCondensed="Help"
+android:title="Help"
+android:icon="@android:drawable/ic_menu_help"
+></item>
+</menu>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+<string-array name="chesssizes">
+<item>3</item>
+<item>4</item>
+<item>5</item>
+<item>6</item>
+<item>7</item>
+<item>8</item>
+<item>9</item>
+<item>10</item>
+<item>11</item>
+<item>12</item>
+<item>13</item>
+</string-array>
+<string name="chesspromptx">
+Choose the width:</string>
+<string name="chessprompty">
+Choose the height:</string>
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+<color name="good_color">#00ff00</color>
+<color name="bad_color">#FF0000</color>
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="app_name">Calibration</string>
+ <string name="patternsize">Pattern Size</string>
+ <string name="patterntext">Please choose the width and height (number of inside corners) of the checker
+ board pattern you will be using for calibration. Default is 6 by 8 corners. You may find a checkerboard pattern at
+ http://opencv.willowgarage.com/pattern</string>
+
+ <string name="patternlink">http://opencv.willowgarage.com/pattern</string>
+
+ <string name="calibfile">/opencv/camera.yml</string>
+ <string name="sdcarddir">/opencv</string>
+
+ <string name="calibration_service_started">Calibration calculations have started...</string>
+ <string name="calibration_service_stopped">Calibration calculations has stopped.</string>
+ <string name="calibration_service_finished">Calibration finished, you camera is calibrated.</string>
+
+ <string name="calibration_service_label">Calibration</string>
+ <string name="calibration_not_enough">Please capture atleast 3 - preferably greater than 10 - images of the pattern!</string>
+
+
+ <string name="sdcard_error_msg"> Please make sure that you\'re sdcard is not mounted to you\'re computer, and that you have an sdcard that is writable on your device.</string>
+
+</resources>
--- /dev/null
+package com.opencv.calibration;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.LinkedList;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.ActivityInfo;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.opencv.calibration.Calibrator.CalibrationCallback;
+import com.opencv.calibration.services.CalibrationService;
+import com.opencv.camera.NativePreviewer;
+import com.opencv.camera.NativeProcessor;
+import com.opencv.misc.SDCardChecker;
+import com.opencv.opengl.GL2CameraViewer;
+
+public class Calibration extends Activity implements CalibrationCallback {
+ private NativePreviewer mPreview;
+
+ private GL2CameraViewer glview;
+ private Calibrator calibrator;
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_CAMERA:
+ case KeyEvent.KEYCODE_SPACE:
+ case KeyEvent.KEYCODE_DPAD_CENTER:
+ calibrator.queueChessCapture();
+ return true;
+ default:
+ return super.onKeyUp(keyCode, event);
+ }
+
+ }
+
+ @Override
+ public boolean onTrackballEvent(MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_UP) {
+ calibrator.queueChessCapture();
+ return true;
+ }
+ return super.onTrackballEvent(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) {
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.calibrationmenu, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.patternsize: {
+ Intent sizer = new Intent(getApplicationContext(),
+ ChessBoardChooser.class);
+ startActivity(sizer);
+ }
+ break;
+ case R.id.help:
+ help();
+ break;
+ case R.id.calibrate:
+ calibrate();
+ break;
+ }
+
+ return true;
+
+ }
+
+ private void help() {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void onOptionsMenuClosed(Menu menu) {
+ // TODO Auto-generated method stub
+ super.onOptionsMenuClosed(menu);
+ }
+
+ private ServiceConnection mConnection = new ServiceConnection() {
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+
+ CalibrationService calibservice = ((CalibrationService.CalibrationServiceBinder) service)
+ .getService();
+ if (!SDCardChecker.CheckStorage(Calibration.this))
+ return;
+ SDCardChecker.MakeDataDir(Calibration.this);
+
+ File calibfile = SDCardChecker.getFile(calibservice,
+ R.string.calibfile);
+ try {
+
+ Calibrator tcalib = calibrator;
+ calibrator = new Calibrator(Calibration.this);
+ setCallbackStack();
+ calibservice.startCalibrating(tcalib, calibfile);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ // Tell the user about this for our demo.
+ Toast.makeText(Calibration.this,
+ "Starting calibration in the background.",
+ Toast.LENGTH_SHORT).show();
+ unbindService(this);
+ }
+
+ };
+
+ public static File getCalibrationFile(Context ctx) {
+ return SDCardChecker.getFile(ctx, R.string.calibfile);
+ }
+
+ void doBindCalibService() {
+ // Establish a connection with the service. We use an explicit
+ // class name because we want a specific service implementation that
+ // we know will be running in our own process (and thus won't be
+ // supporting component replacement by other applications).
+ bindService(new Intent(Calibration.this, CalibrationService.class),
+ mConnection, Context.BIND_AUTO_CREATE);
+ }
+
+ void calibrate() {
+ if (calibrator.getNumberPatternsDetected() < 3) {
+ Toast.makeText(this, getText(R.string.calibration_not_enough),
+ Toast.LENGTH_LONG).show();
+ return;
+ }
+ Intent calibservice = new Intent(Calibration.this,
+ CalibrationService.class);
+ startService(calibservice);
+ doBindCalibService();
+
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setFullscreen();
+ disableScreenTurnOff();
+ setContentView(R.layout.camera);
+ mPreview = (NativePreviewer) findViewById(R.id.nativepreviewer);
+ LinearLayout glview_layout = (LinearLayout) findViewById(R.id.glview_layout);
+ glview = new GL2CameraViewer(getApplication(), false, 0, 0);
+ glview_layout.addView(glview);
+ calibrator = new Calibrator(this);
+
+ ImageButton capturebutton = (ImageButton) findViewById(R.id.capture);
+ capturebutton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ calibrator.queueChessCapture();
+
+ }
+ });
+ ImageButton calibbutton = (ImageButton) findViewById(R.id.calibrate);
+ calibbutton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ calibrate();
+ }
+ });
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ mPreview.onPause();
+
+ glview.onPause();
+
+ }
+
+ protected void setCallbackStack() {
+ calibrator.setPatternSize(ChessBoardChooser.getPatternSize(this));
+
+ LinkedList<NativeProcessor.PoolCallback> callbackstack = new LinkedList<NativeProcessor.PoolCallback>();
+ callbackstack.add(calibrator);
+ callbackstack.add(glview.getDrawCallback());
+ mPreview.addCallbackStack(callbackstack);
+ updateNumber(calibrator);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ glview.onResume();
+ mPreview.onResume();
+ setCallbackStack();
+
+ }
+
+ void updateNumber(Calibrator calibrator) {
+ TextView numbertext = (TextView) findViewById(R.id.numberpatterns);
+ int numdetectd = calibrator.getNumberPatternsDetected();
+ if (numdetectd > 2) {
+ numbertext
+ .setTextColor(getResources().getColor(R.color.good_color));
+
+ } else
+ numbertext.setTextColor(getResources().getColor(R.color.bad_color));
+
+ numbertext.setText(String.valueOf(numdetectd));
+
+ }
+
+ @Override
+ public void onFoundChessboard(final Calibrator calibrator) {
+ runOnUiThread(new Runnable() {
+
+ @Override
+ public void run() {
+ Toast.makeText(Calibration.this,
+ "Captured a calibration pattern!", Toast.LENGTH_SHORT)
+ .show();
+ updateNumber(calibrator);
+
+ }
+ });
+
+ }
+
+ @Override
+ public void onDoneCalibration(Calibrator calibration, File calibfile) {
+
+ }
+
+ @Override
+ public void onFailedChessboard(final Calibrator calibrator) {
+ runOnUiThread(new Runnable() {
+
+ @Override
+ public void run() {
+ Toast.makeText(
+ Calibration.this,
+ "No pattern found. Make sure its the right dimensions, and close enough...",
+ Toast.LENGTH_LONG).show();
+ updateNumber(calibrator);
+
+ }
+ });
+
+ }
+
+}
\ No newline at end of file
--- /dev/null
+package com.opencv.calibration;
+
+import com.opencv.jni.Size;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemSelectedListener;
+import android.widget.Spinner;
+
+public class ChessBoardChooser extends Activity {
+ public static final String CHESS_SIZE = "chess_size";
+ public static final int DEFAULT_WIDTH = 6;
+ public static final int DEFAULT_HEIGHT = 8;
+ public static final int LOWEST = 3;
+
+ class DimChooser implements OnItemSelectedListener {
+ private String dim;
+
+ public DimChooser(String dim) {
+ this.dim = dim;
+ }
+
+ @Override
+ public void onItemSelected(AdapterView<?> arg0, View arg1, int pos,
+ long arg3) {
+ SharedPreferences settings = getSharedPreferences(CHESS_SIZE, 0);
+ Editor editor = settings.edit();
+ editor.putInt(dim, pos + LOWEST);
+ editor.commit();
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> arg0) {
+ }
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ // TODO Auto-generated method stub
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.chesssizer);
+ // Restore preferences
+ SharedPreferences settings = getSharedPreferences(CHESS_SIZE, 0);
+ int width = settings.getInt("width", 6);
+
+ int height = settings.getInt("height", 8);
+
+ Spinner wspin, hspin;
+ wspin = (Spinner) findViewById(R.id.rows);
+ hspin = (Spinner) findViewById(R.id.cols);
+
+ wspin.setSelection(width - LOWEST);
+ hspin.setSelection(height - LOWEST);
+
+ wspin.setOnItemSelectedListener(new DimChooser("width"));
+ hspin.setOnItemSelectedListener(new DimChooser("height"));
+
+ }
+
+ public static Size getPatternSize(Context ctx) {
+ SharedPreferences settings = ctx.getSharedPreferences(CHESS_SIZE, 0);
+ int width = settings.getInt("width", 6);
+
+ int height = settings.getInt("height", 8);
+
+ return new Size(width, height);
+ }
+
+}
--- /dev/null
+package com.opencv.calibration.services;
+
+import java.io.File;
+import java.io.IOException;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+import android.util.Log;
+import android.widget.Toast;
+
+import com.opencv.calibration.Calibration;
+import com.opencv.calibration.Calibrator;
+import com.opencv.calibration.Calibrator.CalibrationCallback;
+import com.opencv.calibration.R;
+
+public class CalibrationService extends Service implements CalibrationCallback {
+
+ public void startCalibrating(Calibrator calibrator, File calibration_file)
+ throws IOException {
+ calibrator.setCallback(this);
+ calibrator.calibrate(calibration_file);
+ }
+
+ private NotificationManager mNM;
+
+ /**
+ * Class for clients to access. Because we know this service always runs in
+ * the same process as its clients, we don't need to deal with IPC.
+ */
+ public class CalibrationServiceBinder extends Binder {
+ public CalibrationService getService() {
+ return CalibrationService.this;
+ }
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ Log.i("LocalService", "Received start id " + startId + ": " + intent);
+ // We want this service to continue running until it is explicitly
+ // stopped, so return sticky.
+ return START_NOT_STICKY;
+ }
+
+ @Override
+ public void onCreate() {
+ mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+
+ // Display a notification about us starting. We put an icon in the
+ // status bar.
+ showNotification();
+ }
+
+ @Override
+ public void onDestroy() {
+ // Cancel the persistent notification.
+ // mNM.cancel(R.string.calibration_service_started);
+
+ // Tell the user we stopped.
+ Toast.makeText(this, R.string.calibration_service_finished,
+ Toast.LENGTH_SHORT).show();
+ }
+
+ private final IBinder mBinder = new CalibrationServiceBinder();
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+
+ /**
+ * Show a notification while this service is running.
+ */
+ private void showNotification() {
+ // In this sample, we'll use the same text for the ticker and the
+ // expanded notification
+ CharSequence text = getText(R.string.calibration_service_started);
+
+ // Set the icon, scrolling text and timestamp
+ Notification notification = new Notification(R.drawable.icon, text,
+ System.currentTimeMillis());
+
+ // The PendingIntent to launch our activity if the user selects this
+ // notification
+ PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
+ new Intent(this, Calibration.class), 0);
+
+ // Set the info for the views that show in the notification panel.
+ notification.setLatestEventInfo(this,
+ getText(R.string.calibration_service_label), text,
+ contentIntent);
+
+ notification.defaults |= Notification.DEFAULT_SOUND;
+ // Send the notification.
+ // We use a layout id because it is a unique number. We use it later to
+ // cancel.
+ mNM.notify(R.string.calibration_service_started, notification);
+ }
+
+ /**
+ * Show a notification while this service is running.
+ */
+ private void doneNotification() {
+ // In this sample, we'll use the same text for the ticker and the
+ // expanded notification
+ CharSequence text = getText(R.string.calibration_service_finished);
+
+ // Set the icon, scrolling text and timestamp
+ Notification notification = new Notification(R.drawable.icon, text,
+ System.currentTimeMillis());
+
+ // The PendingIntent to launch our activity if the user selects this
+ // notification
+ PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
+ new Intent(this, Calibration.class), 0);
+
+ // Set the info for the views that show in the notification panel.
+ notification.setLatestEventInfo(this,
+ getText(R.string.calibration_service_label), text,
+ contentIntent);
+
+ notification.defaults |= Notification.DEFAULT_SOUND;
+ // Send the notification.
+ // We use a layout id because it is a unique number. We use it later to
+ // cancel.
+ mNM.notify(R.string.calibration_service_started, notification);
+ }
+
+ @Override
+ public void onFoundChessboard(Calibrator calibrator) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void onDoneCalibration(Calibrator calibration, File calibfile) {
+ doneNotification();
+ stopSelf();
+ }
+
+ @Override
+ public void onFailedChessboard(Calibrator calibrator) {
+ // TODO Auto-generated method stub
+
+ }
+
+}
--- /dev/null
+package com.opencv.misc;
+
+import java.io.File;
+
+import android.content.Context;
+import android.os.Environment;
+import android.widget.Toast;
+
+import com.opencv.calibration.R;
+
+public class SDCardChecker {
+
+ public static File createThumb(Context ctx, File workingDir) {
+ return new File(workingDir, "thumb.jpg");
+ }
+
+ public static File getDir(Context ctx, String relativename) {
+ return new File(Environment.getExternalStorageDirectory()
+ + relativename);
+ }
+
+ public static File getDir(Context ctx, int id) {
+ return new File(Environment.getExternalStorageDirectory()
+ + ctx.getResources().getString(id));
+ }
+
+ public static File getFile(Context ctx, int id) {
+ return new File(Environment.getExternalStorageDirectory()
+ + ctx.getResources().getString(id));
+ }
+
+ public static void MakeDataDir(Context ctx) {
+ File dir = getDir(ctx, R.string.sdcarddir);
+ dir.mkdirs();
+ }
+
+ public static boolean CheckStorage(Context ctx) {
+ boolean mExternalStorageAvailable = false;
+ boolean mExternalStorageWriteable = false;
+ String state = Environment.getExternalStorageState();
+
+ if (Environment.MEDIA_MOUNTED.equals(state)) {
+ // We can read and write the media
+ mExternalStorageAvailable = mExternalStorageWriteable = true;
+ } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
+ // We can only read the media
+ mExternalStorageAvailable = true;
+ mExternalStorageWriteable = false;
+ } else {
+ // Something else is wrong. It may be one of many other states, but
+ // all we need
+ // to know is we can neither read nor write
+ mExternalStorageAvailable = mExternalStorageWriteable = false;
+ }
+ boolean goodmount = mExternalStorageAvailable
+ && mExternalStorageWriteable;
+ if (!goodmount) {
+ Toast.makeText(ctx, ctx.getString(R.string.sdcard_error_msg),
+ Toast.LENGTH_LONG).show();
+ }
+ return goodmount;
+ }
+
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.foo.bar" android:versionCode="1" android:versionName="1.0" >
+
+ <application android:debuggable="true" android:icon="@drawable/icon">
+ <activity android:name=".FooBar" android:screenOrientation="landscape"
+ android:configChanges="orientation|keyboardHidden|keyboard"
+ android:label="@string/app_name"
+ >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ </application>
+
+
+
+ <uses-feature android:glEsVersion="0x00020000" />
+
+ <uses-permission android:name="android.permission.CAMERA"></uses-permission>
+
+ <uses-sdk android:minSdkVersion="7" />
+
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
+</manifest>
\ No newline at end of file
--- /dev/null
+#Re-usable Makefile template for
+#android-ndk + swig projects
+#author: Ethan Rublee
+#date: summer 2010
+
+# The path to the NDK, requires crystax version r-4 for now, due to support
+#for the standard library
+ifndef ANDROID_NDK_BASE
+ANDROID_NDK_BASE = $(HOME)/android-ndk-r4-crystax
+$(info default ndk location set ANDROID_NDK_BASE = $(ANDROID_NDK_BASE))
+endif
+
+#define OPENCV_ROOT when calling this makefile
+#OPENCV_ROOT = $(ANDROID_NDK_BASE)/apps/opencv
+ifndef OPENCV_ROOT
+$(error Please define OPENCV_ROOT with something like the command \
+make OPENCV_ROOT=<opencv>)
+endif
+
+ifndef PROJECT_PATH
+$(info PROJECT_PATH defaulting to this directory)
+PROJECT_PATH=.
+endif
+
+$(info OPENCV_ROOT = $(OPENCV_ROOT))
+
+# The name of the native library
+LIBNAME = libfoobar.so
+
+#define the main jni swig interface file
+#the desired java package name
+#and the desired java directory
+#notice that the package and the java dir
+#are related...
+SWIG_MAIN = jni/foobar.i
+SWIG_JAVA_PACKAGE = com.foo.bar.jni
+SWIG_JAVA_DIR = src/com/foo/bar/jni
+
+SWIG_BASE = foobar
+
+#swig definitions - auto as long as all the
+#swig interface files are in jni/*.i
+SWIG_JAVA_OUT = $(wildcard $(SWIG_JAVA_DIR)/*.java)
+SWIG_IS = $(wildcard jni/*.i)
+
+#the directory where the jni sources are
+C_DIR = jni
+
+#directory where to put generated files
+#relative to the C_DIR
+GEN_DIR = gen
+
+#the c swig is generated and put into the jni/gen folder
+SWIG_C_DIR = $(C_DIR)/$(GEN_DIR)
+
+#this file - jin/gen/foobar_swig.cpp must be included in the Android.mk
+#for it to be built!
+SWIG_C_OUT = $(SWIG_C_DIR)/$(SWIG_BASE)_swig.cpp
+
+# The real native library stripped of symbols
+LIB = libs/armeabi-v7a/$(LIBNAME) libs/armeabi/$(LIBNAME)
+
+# Find all the C++ sources in the native folder
+SOURCES = $(wildcard jni/*.cpp)
+HEADERS = $(wildcard jni/*.h)
+
+ANDROID_MKS = $(wildcard jni/*.mk)
+
+#this gets called by the make command
+all: $(LIB)
+
+#calls the ndk-build script, passing it OPENCV_ROOT and OPENCV_LIBS_DIR
+$(LIB): $(SWIG_C_OUT) $(SOURCES) $(HEADERS) $(ANDROID_MKS)
+ $(ANDROID_NDK_BASE)/ndk-build OPENCV_ROOT=$(OPENCV_ROOT) \
+ OPENCV_LIBS_DIR=$(OPENCV_LIBS_DIR) PROJECT_PATH=$(PROJECT_PATH) SWIG_C_OUT=$(GEN_DIR)/$(SWIG_BASE)_swig.cpp V=$(V) $(NDK_FLAGS)
+
+
+#this creates the swig wrappers
+#-I$(OPENCV_ROOT)/android/jni is an additional swig include path
+$(SWIG_C_OUT): $(SWIG_IS)
+ make clean-swig &&\
+ mkdir -p $(SWIG_C_DIR) &&\
+ mkdir -p $(SWIG_JAVA_DIR) &&\
+ swig -java -c++ -I$(OPENCV_ROOT)/android/jni -package "$(SWIG_JAVA_PACKAGE)" \
+ -outdir $(SWIG_JAVA_DIR) \
+ -o $(SWIG_C_OUT) $(SWIG_MAIN)
+
+
+#clean targets
+.PHONY: clean clean-swig cleanall
+
+#this deletes the generated swig java and the generated c wrapper
+clean-swig:
+ rm -f $(SWIG_JAVA_OUT) $(SWIG_C_OUT)
+
+#does clean-swig and then uses the ndk-build clean
+clean: clean-swig
+ $(ANDROID_NDK_BASE)/ndk-build clean V=$(V) $(NDK_FLAGS)
--- /dev/null
+see http://code.google.com/p/android-opencv/wiki/camera_template
+
--- /dev/null
+make OPENCV_ROOT=../../opencv V=0
--- /dev/null
+make OPENCV_ROOT=../../opencv V=0 clean
--- /dev/null
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+android.library.reference.1=../../opencv/android/
+# Project target.
+target=android-7
--- /dev/null
+# date: Summer, 2010
+# author: Ethan Rublee
+# contact: ethan.rublee@gmail.com
+#
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+#pass in OPENCV_ROOT or define it here
+#OPENCV_ROOT := ~/android-opencv/opencv
+ifndef OPENCV_ROOT
+${error please define OPENCV_ROOT before this point!}
+endif
+
+#define OPENCV_INCLUDES
+include $(OPENCV_ROOT)/includes.mk
+#define OPENCV_LIBS
+include $(OPENCV_ROOT)/libs.mk
+
+LOCAL_LDLIBS += $(OPENCV_LIBS) $(ANDROID_OPENCV_LIBS) -llog -lGLESv2
+
+LOCAL_C_INCLUDES += $(OPENCV_INCLUDES) $(ANDROID_OPENCV_INCLUDES)
+
+LOCAL_MODULE := foobar
+
+
+ifndef SWIG_C_OUT
+${error please define SWIG_C_OUT before this point!}
+endif
+
+#make sure to pass in SWIG_C_OUT=gen/foobar_swig.cpp
+#done in the makefile
+LOCAL_SRC_FILES := ${SWIG_C_OUT} TestBar.cpp
+
+include $(BUILD_SHARED_LIBRARY)
+
--- /dev/null
+# The ARMv7 is significanly faster due to the use of the hardware FPU
+APP_ABI := armeabi armeabi-v7a
\ No newline at end of file
--- /dev/null
+#include "TestBar.h"
+
+void BarBar::crazy(){
+
+}
--- /dev/null
+/*
+ * TestBar.h
+ *
+ * Created on: Jul 17, 2010
+ * Author: ethan
+ */
+
+#ifndef TESTBAR_H_
+#define TESTBAR_H_
+
+#include "image_pool.h"
+
+struct FooBarStruct {
+
+ int pool_image_count(image_pool* pool){
+ return pool->getCount();
+ }
+
+};
+
+class BarBar{
+public:
+ void crazy();
+};
+
+#endif /* TESTBAR_H_ */
--- /dev/null
+/* File : foobar.i */
+%module foobar
+
+/*
+ * the java import code muse be included for the opencv jni wrappers
+ * this means that the android project must reference opencv/android as a project
+ * see the default.properties for how this is done
+ */
+%pragma(java) jniclassimports=%{
+import com.opencv.jni.*; //import the android-opencv jni wrappers
+%}
+
+%pragma(java) jniclasscode=%{
+ static {
+ try {
+ //load the cvcamera library, make sure that libcvcamera.so is in your <project>/libs/armeabi directory
+ //so that android sdk automatically installs it along with the app.
+
+ //the android-opencv lib must be loaded first inorder for the cvcamera
+ //lib to be found
+ //check the apk generated, by opening it in an archive manager, to verify that
+ //both these libraries are present
+ System.loadLibrary("android-opencv");
+ System.loadLibrary("foobar");
+ } catch (UnsatisfiedLinkError e) {
+ //badness
+ throw e;
+ }
+ }
+
+%}
+
+%{
+#include "image_pool.h"
+#include "TestBar.h"
+using namespace cv;
+%}
+
+
+//import the android-cv.i file so that swig is aware of all that has been previous defined
+//notice that it is not an include....
+%import "android-cv.i"
+
+
+//make sure to import the image_pool as it is
+//referenced by the Processor java generated
+//class
+%typemap(javaimports) FooBarStruct "
+import com.opencv.jni.image_pool;// import the image_pool interface for playing nice with
+ // android-opencv
+
+/** FooBar - template
+*/"
+
+//sample inline class that needs to include image_pool
+struct FooBarStruct {
+
+ int pool_image_count(image_pool* pool){
+ return pool->getCount();
+ }
+
+};
+
+//sample jni class
+class BarBar{
+public:
+ void crazy();
+};
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+<string name="app_name">FooBar</string>
+<string name="about_str">FooBar is a template app for the android-opencv project!\nVisit http://code.google.com/p/android-opencv for details.</string>
+<string name="about_title">About FooBar</string>
+<string name="about_menu">About</string>
+<string name="ok">O.K.</string>
+</resources>
--- /dev/null
+package com.foo.bar;
+
+import java.util.LinkedList;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+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.Window;
+import android.view.WindowManager;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+
+//make sure you have the OpenCV project open, so that the
+//android-sdk can find it!
+import com.foo.bar.jni.BarBar;
+import com.foo.bar.jni.FooBarStruct;
+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;
+
+public class FooBar extends Activity {
+
+ private final int FOOBARABOUT = 0;
+
+ @Override
+ protected Dialog onCreateDialog(int id) {
+ Dialog dialog;
+ switch (id) {
+ case FOOBARABOUT:
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(R.string.about_title);
+ builder.setMessage(R.string.about_str);
+ builder.setPositiveButton(R.string.ok,
+ new DialogInterface.OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dismissDialog(FOOBARABOUT);
+
+ }
+ });
+ dialog = builder.create();
+ default:
+ dialog = null;
+ }
+ return dialog;
+ }
+
+ /*
+ * Handle the capture button as follows...
+ */
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_CAMERA:
+ case KeyEvent.KEYCODE_SPACE:
+ case KeyEvent.KEYCODE_DPAD_CENTER:
+ // capture button pressed here
+ return true;
+
+ default:
+ return super.onKeyUp(keyCode, event);
+ }
+
+ }
+
+ /*
+ * Handle the capture button as follows... On some phones there is no
+ * capture button, only trackball
+ */
+ @Override
+ public boolean onTrackballEvent(MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_UP) {
+ // capture button pressed
+ return true;
+ }
+ return super.onTrackballEvent(event);
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ menu.add(R.string.about_menu);
+ return true;
+ }
+
+ private NativePreviewer mPreview;
+ private GL2CameraViewer glview;
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ // example menu
+ if (item.getTitle().equals(
+ getResources().getString(R.string.about_menu))) {
+ showDialog(FOOBARABOUT);
+ }
+ return true;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
+ WindowManager.LayoutParams.FLAG_FULLSCREEN);
+
+ FrameLayout frame = new FrameLayout(this);
+
+ // Create our Preview view and set it as the content of our activity.
+ mPreview = new NativePreviewer(getApplication(), 300, 300);
+
+ 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));
+ frame.addView(glview);
+
+ setContentView(frame);
+
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ // IMPORTANT
+ // must tell the NativePreviewer of a pause
+ // and the glview - so that they can release resources and start back up
+ // properly
+ // failing to do this will cause the application to crash with no
+ // warning
+ // on restart
+ // clears the callback stack
+ mPreview.onPause();
+
+ glview.onPause();
+
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ // resume the opengl viewer first
+ glview.onResume();
+
+ // add an initial callback stack to the preview on resume...
+ // this one will just draw the frames to opengl
+ LinkedList<NativeProcessor.PoolCallback> cbstack = new LinkedList<PoolCallback>();
+
+ // SpamProcessor will be called first
+ cbstack.add(new SpamProcessor());
+
+ // then the same idx and pool will be passed to
+ // the glview callback -
+ // so operate on the image at idx, and modify, and then
+ // it will be drawn in the glview
+ // or remove this, and call glview manually in SpamProcessor
+ // cbstack.add(glview.getDrawCallback());
+
+ mPreview.addCallbackStack(cbstack);
+ mPreview.onResume();
+
+ }
+
+ class SpamProcessor implements NativeProcessor.PoolCallback {
+
+ FooBarStruct foo = new FooBarStruct();
+ BarBar barbar = new BarBar();
+
+ @Override
+ public void process(int idx, image_pool pool, long timestamp,
+ NativeProcessor nativeProcessor) {
+
+ // example of using the jni generated FoobarStruct;
+ int nImages = foo.pool_image_count(pool);
+ Log.i("foobar", "Number of images in pool: " + nImages);
+
+ // call a function - this function does absolutely nothing!
+ barbar.crazy();
+
+ // sample processor
+ // this gets called every frame in the order of the list
+ // first add to the callback stack linked list will be the
+ // first called
+ // the idx and pool may be used to get the cv::Mat
+ // that is the latest frame being passed.
+ // pool.getClass(idx)
+
+ // these are what the glview.getDrawCallback() calls
+ glview.drawMatToGL(idx, pool);
+ glview.requestRender();
+
+ }
+
+ }
+
+}