adding samples to the android apps directory
authorEthan Rublee <no@email>
Tue, 12 Oct 2010 02:21:30 +0000 (02:21 +0000)
committerEthan Rublee <no@email>
Tue, 12 Oct 2010 02:21:30 +0000 (02:21 +0000)
56 files changed:
android/apps/CVCamera/AndroidManifest.xml [new file with mode: 0644]
android/apps/CVCamera/Makefile [new file with mode: 0644]
android/apps/CVCamera/README.txt [new file with mode: 0644]
android/apps/CVCamera/build.sh [new file with mode: 0644]
android/apps/CVCamera/clean.sh [new file with mode: 0644]
android/apps/CVCamera/default.properties [new file with mode: 0644]
android/apps/CVCamera/jni/Android.mk [new file with mode: 0644]
android/apps/CVCamera/jni/Application.mk [new file with mode: 0644]
android/apps/CVCamera/jni/Processor.cpp [new file with mode: 0644]
android/apps/CVCamera/jni/Processor.h [new file with mode: 0644]
android/apps/CVCamera/jni/Processor.i [new file with mode: 0644]
android/apps/CVCamera/jni/cvcamera.i [new file with mode: 0644]
android/apps/CVCamera/project_create.sh [new file with mode: 0755]
android/apps/CVCamera/res/drawable-hdpi/icon.png [new file with mode: 0644]
android/apps/CVCamera/res/drawable-ldpi/icon.png [new file with mode: 0644]
android/apps/CVCamera/res/drawable-mdpi/icon.png [new file with mode: 0644]
android/apps/CVCamera/res/layout/main.xml [new file with mode: 0644]
android/apps/CVCamera/res/values/strings.xml [new file with mode: 0644]
android/apps/CVCamera/sample.local.env.mk [new file with mode: 0644]
android/apps/CVCamera/src/com/theveganrobot/cvcamera/CVCamera.java [new file with mode: 0644]
android/apps/CVCamera/uninstall.phone.sh [new file with mode: 0755]
android/apps/Calibration/AndroidManifest.xml [new file with mode: 0644]
android/apps/Calibration/artwork/icon.xcf [new file with mode: 0644]
android/apps/Calibration/default.properties [new file with mode: 0644]
android/apps/Calibration/project_create.sh [new file with mode: 0755]
android/apps/Calibration/res/drawable-hdpi/icon.png [new file with mode: 0644]
android/apps/Calibration/res/drawable-ldpi/icon.png [new file with mode: 0644]
android/apps/Calibration/res/drawable-mdpi/cameraback.jpg [new file with mode: 0644]
android/apps/Calibration/res/drawable-mdpi/icon.png [new file with mode: 0644]
android/apps/Calibration/res/drawable-mdpi/patternicon.png [new file with mode: 0644]
android/apps/Calibration/res/layout/camera.xml [new file with mode: 0644]
android/apps/Calibration/res/layout/chesssizer.xml [new file with mode: 0644]
android/apps/Calibration/res/menu/calibrationmenu.xml [new file with mode: 0644]
android/apps/Calibration/res/values/chessnumbers.xml [new file with mode: 0644]
android/apps/Calibration/res/values/color.xml [new file with mode: 0644]
android/apps/Calibration/res/values/strings.xml [new file with mode: 0644]
android/apps/Calibration/src/com/opencv/calibration/Calibration.java [new file with mode: 0644]
android/apps/Calibration/src/com/opencv/calibration/ChessBoardChooser.java [new file with mode: 0644]
android/apps/Calibration/src/com/opencv/calibration/services/CalibrationService.java [new file with mode: 0644]
android/apps/Calibration/src/com/opencv/misc/SDCardChecker.java [new file with mode: 0644]
android/apps/camera_template/AndroidManifest.xml [new file with mode: 0644]
android/apps/camera_template/Makefile [new file with mode: 0644]
android/apps/camera_template/README.txt [new file with mode: 0644]
android/apps/camera_template/build.sh [new file with mode: 0644]
android/apps/camera_template/clean.sh [new file with mode: 0644]
android/apps/camera_template/default.properties [new file with mode: 0644]
android/apps/camera_template/jni/Android.mk [new file with mode: 0644]
android/apps/camera_template/jni/Application.mk [new file with mode: 0644]
android/apps/camera_template/jni/TestBar.cpp [new file with mode: 0644]
android/apps/camera_template/jni/TestBar.h [new file with mode: 0644]
android/apps/camera_template/jni/foobar.i [new file with mode: 0644]
android/apps/camera_template/res/drawable-hdpi/icon.png [new file with mode: 0644]
android/apps/camera_template/res/drawable-ldpi/icon.png [new file with mode: 0644]
android/apps/camera_template/res/drawable-mdpi/icon.png [new file with mode: 0644]
android/apps/camera_template/res/values/strings.xml [new file with mode: 0644]
android/apps/camera_template/src/com/foo/bar/FooBar.java [new file with mode: 0644]

diff --git a/android/apps/CVCamera/AndroidManifest.xml b/android/apps/CVCamera/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..0acd4e9
--- /dev/null
@@ -0,0 +1,30 @@
+<?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
diff --git a/android/apps/CVCamera/Makefile b/android/apps/CVCamera/Makefile
new file mode 100644 (file)
index 0000000..89d847d
--- /dev/null
@@ -0,0 +1,83 @@
+# 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)
+
diff --git a/android/apps/CVCamera/README.txt b/android/apps/CVCamera/README.txt
new file mode 100644 (file)
index 0000000..8bc5b3a
--- /dev/null
@@ -0,0 +1,2 @@
+see http://code.google.com/p/android-opencv/wiki/CVCamera
+
diff --git a/android/apps/CVCamera/build.sh b/android/apps/CVCamera/build.sh
new file mode 100644 (file)
index 0000000..1497a39
--- /dev/null
@@ -0,0 +1 @@
+make V=0
diff --git a/android/apps/CVCamera/clean.sh b/android/apps/CVCamera/clean.sh
new file mode 100644 (file)
index 0000000..121e391
--- /dev/null
@@ -0,0 +1 @@
+make OPENCV_ROOT=../../opencv V=0 clean
diff --git a/android/apps/CVCamera/default.properties b/android/apps/CVCamera/default.properties
new file mode 100644 (file)
index 0000000..66148fe
--- /dev/null
@@ -0,0 +1,12 @@
+# 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
diff --git a/android/apps/CVCamera/jni/Android.mk b/android/apps/CVCamera/jni/Android.mk
new file mode 100644 (file)
index 0000000..f5aa1b1
--- /dev/null
@@ -0,0 +1,21 @@
+# 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)
+
diff --git a/android/apps/CVCamera/jni/Application.mk b/android/apps/CVCamera/jni/Application.mk
new file mode 100644 (file)
index 0000000..a2c96a8
--- /dev/null
@@ -0,0 +1,2 @@
+# The ARMv7 is significanly faster due to the use of the hardware FPU
+APP_ABI := armeabi armeabi-v7a
\ No newline at end of file
diff --git a/android/apps/CVCamera/jni/Processor.cpp b/android/apps/CVCamera/jni/Processor.cpp
new file mode 100644 (file)
index 0000000..3d5a6b1
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * 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();
+}
diff --git a/android/apps/CVCamera/jni/Processor.h b/android/apps/CVCamera/jni/Processor.h
new file mode 100644 (file)
index 0000000..49bee55
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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_ */
diff --git a/android/apps/CVCamera/jni/Processor.i b/android/apps/CVCamera/jni/Processor.i
new file mode 100644 (file)
index 0000000..ff66d53
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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);
+
+};
diff --git a/android/apps/CVCamera/jni/cvcamera.i b/android/apps/CVCamera/jni/cvcamera.i
new file mode 100644 (file)
index 0000000..ccca8d9
--- /dev/null
@@ -0,0 +1,36 @@
+/* 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
diff --git a/android/apps/CVCamera/project_create.sh b/android/apps/CVCamera/project_create.sh
new file mode 100755 (executable)
index 0000000..ec76728
--- /dev/null
@@ -0,0 +1,2 @@
+android update project --name CVCamera \
+--path .
diff --git a/android/apps/CVCamera/res/drawable-hdpi/icon.png b/android/apps/CVCamera/res/drawable-hdpi/icon.png
new file mode 100644 (file)
index 0000000..4e828ba
Binary files /dev/null and b/android/apps/CVCamera/res/drawable-hdpi/icon.png differ
diff --git a/android/apps/CVCamera/res/drawable-ldpi/icon.png b/android/apps/CVCamera/res/drawable-ldpi/icon.png
new file mode 100644 (file)
index 0000000..5e11406
Binary files /dev/null and b/android/apps/CVCamera/res/drawable-ldpi/icon.png differ
diff --git a/android/apps/CVCamera/res/drawable-mdpi/icon.png b/android/apps/CVCamera/res/drawable-mdpi/icon.png
new file mode 100644 (file)
index 0000000..a591eb8
Binary files /dev/null and b/android/apps/CVCamera/res/drawable-mdpi/icon.png differ
diff --git a/android/apps/CVCamera/res/layout/main.xml b/android/apps/CVCamera/res/layout/main.xml
new file mode 100644 (file)
index 0000000..ae6cdd1
--- /dev/null
@@ -0,0 +1,8 @@
+<?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>
diff --git a/android/apps/CVCamera/res/values/strings.xml b/android/apps/CVCamera/res/values/strings.xml
new file mode 100644 (file)
index 0000000..5fe379d
--- /dev/null
@@ -0,0 +1,7 @@
+<?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>
diff --git a/android/apps/CVCamera/sample.local.env.mk b/android/apps/CVCamera/sample.local.env.mk
new file mode 100644 (file)
index 0000000..203c730
--- /dev/null
@@ -0,0 +1,4 @@
+#location of android-opencv port of OpenCV to android
+OPENCV_CONFIG=../../build/android-opencv.mk
+ANDROID_NDK_ROOT=$(HOME)/android-ndk-r4-crystax
+
diff --git a/android/apps/CVCamera/src/com/theveganrobot/cvcamera/CVCamera.java b/android/apps/CVCamera/src/com/theveganrobot/cvcamera/CVCamera.java
new file mode 100644 (file)
index 0000000..2cbcbb3
--- /dev/null
@@ -0,0 +1,498 @@
+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");
+                       }
+
+               }
+
+       }
+
+}
diff --git a/android/apps/CVCamera/uninstall.phone.sh b/android/apps/CVCamera/uninstall.phone.sh
new file mode 100755 (executable)
index 0000000..06b78ca
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/bash
+echo uninstalling CVCamera from phone
+adb uninstall com.theveganrobot.cvcamera
diff --git a/android/apps/Calibration/AndroidManifest.xml b/android/apps/Calibration/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..2933e87
--- /dev/null
@@ -0,0 +1,38 @@
+<?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> 
diff --git a/android/apps/Calibration/artwork/icon.xcf b/android/apps/Calibration/artwork/icon.xcf
new file mode 100644 (file)
index 0000000..aa7bb99
Binary files /dev/null and b/android/apps/Calibration/artwork/icon.xcf differ
diff --git a/android/apps/Calibration/default.properties b/android/apps/Calibration/default.properties
new file mode 100644 (file)
index 0000000..66148fe
--- /dev/null
@@ -0,0 +1,12 @@
+# 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
diff --git a/android/apps/Calibration/project_create.sh b/android/apps/Calibration/project_create.sh
new file mode 100755 (executable)
index 0000000..f8c9c51
--- /dev/null
@@ -0,0 +1,2 @@
+android update project --name Calibration \
+--path .
diff --git a/android/apps/Calibration/res/drawable-hdpi/icon.png b/android/apps/Calibration/res/drawable-hdpi/icon.png
new file mode 100644 (file)
index 0000000..ab9f932
Binary files /dev/null and b/android/apps/Calibration/res/drawable-hdpi/icon.png differ
diff --git a/android/apps/Calibration/res/drawable-ldpi/icon.png b/android/apps/Calibration/res/drawable-ldpi/icon.png
new file mode 100644 (file)
index 0000000..ab9f932
Binary files /dev/null and b/android/apps/Calibration/res/drawable-ldpi/icon.png differ
diff --git a/android/apps/Calibration/res/drawable-mdpi/cameraback.jpg b/android/apps/Calibration/res/drawable-mdpi/cameraback.jpg
new file mode 100644 (file)
index 0000000..b53ffd4
Binary files /dev/null and b/android/apps/Calibration/res/drawable-mdpi/cameraback.jpg differ
diff --git a/android/apps/Calibration/res/drawable-mdpi/icon.png b/android/apps/Calibration/res/drawable-mdpi/icon.png
new file mode 100644 (file)
index 0000000..ab9f932
Binary files /dev/null and b/android/apps/Calibration/res/drawable-mdpi/icon.png differ
diff --git a/android/apps/Calibration/res/drawable-mdpi/patternicon.png b/android/apps/Calibration/res/drawable-mdpi/patternicon.png
new file mode 100644 (file)
index 0000000..879044a
Binary files /dev/null and b/android/apps/Calibration/res/drawable-mdpi/patternicon.png differ
diff --git a/android/apps/Calibration/res/layout/camera.xml b/android/apps/Calibration/res/layout/camera.xml
new file mode 100644 (file)
index 0000000..8e721d8
--- /dev/null
@@ -0,0 +1,59 @@
+<?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>
diff --git a/android/apps/Calibration/res/layout/chesssizer.xml b/android/apps/Calibration/res/layout/chesssizer.xml
new file mode 100644 (file)
index 0000000..b93bc0b
--- /dev/null
@@ -0,0 +1,40 @@
+<?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>
diff --git a/android/apps/Calibration/res/menu/calibrationmenu.xml b/android/apps/Calibration/res/menu/calibrationmenu.xml
new file mode 100644 (file)
index 0000000..8dd3457
--- /dev/null
@@ -0,0 +1,17 @@
+<?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>
diff --git a/android/apps/Calibration/res/values/chessnumbers.xml b/android/apps/Calibration/res/values/chessnumbers.xml
new file mode 100644 (file)
index 0000000..f0db569
--- /dev/null
@@ -0,0 +1,20 @@
+<?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>
diff --git a/android/apps/Calibration/res/values/color.xml b/android/apps/Calibration/res/values/color.xml
new file mode 100644 (file)
index 0000000..e339837
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+<color name="good_color">#00ff00</color>
+<color name="bad_color">#FF0000</color>
+</resources>
diff --git a/android/apps/Calibration/res/values/strings.xml b/android/apps/Calibration/res/values/strings.xml
new file mode 100644 (file)
index 0000000..a33cf0b
--- /dev/null
@@ -0,0 +1,24 @@
+<?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>
diff --git a/android/apps/Calibration/src/com/opencv/calibration/Calibration.java b/android/apps/Calibration/src/com/opencv/calibration/Calibration.java
new file mode 100644 (file)
index 0000000..5c7abf3
--- /dev/null
@@ -0,0 +1,311 @@
+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
diff --git a/android/apps/Calibration/src/com/opencv/calibration/ChessBoardChooser.java b/android/apps/Calibration/src/com/opencv/calibration/ChessBoardChooser.java
new file mode 100644 (file)
index 0000000..10f9360
--- /dev/null
@@ -0,0 +1,74 @@
+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);
+       }
+
+}
diff --git a/android/apps/Calibration/src/com/opencv/calibration/services/CalibrationService.java b/android/apps/Calibration/src/com/opencv/calibration/services/CalibrationService.java
new file mode 100644 (file)
index 0000000..bc9d5cd
--- /dev/null
@@ -0,0 +1,151 @@
+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
+
+       }
+
+}
diff --git a/android/apps/Calibration/src/com/opencv/misc/SDCardChecker.java b/android/apps/Calibration/src/com/opencv/misc/SDCardChecker.java
new file mode 100644 (file)
index 0000000..1a7d2b7
--- /dev/null
@@ -0,0 +1,64 @@
+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;
+       }
+
+}
diff --git a/android/apps/camera_template/AndroidManifest.xml b/android/apps/camera_template/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..6af45ff
--- /dev/null
@@ -0,0 +1,27 @@
+<?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
diff --git a/android/apps/camera_template/Makefile b/android/apps/camera_template/Makefile
new file mode 100644 (file)
index 0000000..3d1e8ee
--- /dev/null
@@ -0,0 +1,98 @@
+#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)
diff --git a/android/apps/camera_template/README.txt b/android/apps/camera_template/README.txt
new file mode 100644 (file)
index 0000000..14d57b5
--- /dev/null
@@ -0,0 +1,2 @@
+see http://code.google.com/p/android-opencv/wiki/camera_template
+
diff --git a/android/apps/camera_template/build.sh b/android/apps/camera_template/build.sh
new file mode 100644 (file)
index 0000000..92772c3
--- /dev/null
@@ -0,0 +1 @@
+make OPENCV_ROOT=../../opencv V=0
diff --git a/android/apps/camera_template/clean.sh b/android/apps/camera_template/clean.sh
new file mode 100644 (file)
index 0000000..121e391
--- /dev/null
@@ -0,0 +1 @@
+make OPENCV_ROOT=../../opencv V=0 clean
diff --git a/android/apps/camera_template/default.properties b/android/apps/camera_template/default.properties
new file mode 100644 (file)
index 0000000..8878724
--- /dev/null
@@ -0,0 +1,12 @@
+# 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
diff --git a/android/apps/camera_template/jni/Android.mk b/android/apps/camera_template/jni/Android.mk
new file mode 100644 (file)
index 0000000..b66bb70
--- /dev/null
@@ -0,0 +1,36 @@
+# 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)
+
diff --git a/android/apps/camera_template/jni/Application.mk b/android/apps/camera_template/jni/Application.mk
new file mode 100644 (file)
index 0000000..a2c96a8
--- /dev/null
@@ -0,0 +1,2 @@
+# The ARMv7 is significanly faster due to the use of the hardware FPU
+APP_ABI := armeabi armeabi-v7a
\ No newline at end of file
diff --git a/android/apps/camera_template/jni/TestBar.cpp b/android/apps/camera_template/jni/TestBar.cpp
new file mode 100644 (file)
index 0000000..869113a
--- /dev/null
@@ -0,0 +1,5 @@
+#include "TestBar.h"
+
+void BarBar::crazy(){
+
+}
diff --git a/android/apps/camera_template/jni/TestBar.h b/android/apps/camera_template/jni/TestBar.h
new file mode 100644 (file)
index 0000000..e919f8f
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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_ */
diff --git a/android/apps/camera_template/jni/foobar.i b/android/apps/camera_template/jni/foobar.i
new file mode 100644 (file)
index 0000000..a66a059
--- /dev/null
@@ -0,0 +1,68 @@
+/* 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();
+};
diff --git a/android/apps/camera_template/res/drawable-hdpi/icon.png b/android/apps/camera_template/res/drawable-hdpi/icon.png
new file mode 100644 (file)
index 0000000..4e828ba
Binary files /dev/null and b/android/apps/camera_template/res/drawable-hdpi/icon.png differ
diff --git a/android/apps/camera_template/res/drawable-ldpi/icon.png b/android/apps/camera_template/res/drawable-ldpi/icon.png
new file mode 100644 (file)
index 0000000..5e11406
Binary files /dev/null and b/android/apps/camera_template/res/drawable-ldpi/icon.png differ
diff --git a/android/apps/camera_template/res/drawable-mdpi/icon.png b/android/apps/camera_template/res/drawable-mdpi/icon.png
new file mode 100644 (file)
index 0000000..a591eb8
Binary files /dev/null and b/android/apps/camera_template/res/drawable-mdpi/icon.png differ
diff --git a/android/apps/camera_template/res/values/strings.xml b/android/apps/camera_template/res/values/strings.xml
new file mode 100644 (file)
index 0000000..5ff41dc
--- /dev/null
@@ -0,0 +1,8 @@
+<?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>
diff --git a/android/apps/camera_template/src/com/foo/bar/FooBar.java b/android/apps/camera_template/src/com/foo/bar/FooBar.java
new file mode 100644 (file)
index 0000000..6bc31be
--- /dev/null
@@ -0,0 +1,224 @@
+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();
+
+               }
+
+       }
+
+}