adding samples to the android apps directory
30
android/apps/CVCamera/AndroidManifest.xml
Normal file
@ -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>
|
83
android/apps/CVCamera/Makefile
Normal file
@ -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)
|
||||
|
2
android/apps/CVCamera/README.txt
Normal file
@ -0,0 +1,2 @@
|
||||
see http://code.google.com/p/android-opencv/wiki/CVCamera
|
||||
|
1
android/apps/CVCamera/build.sh
Normal file
@ -0,0 +1 @@
|
||||
make V=0
|
1
android/apps/CVCamera/clean.sh
Normal file
@ -0,0 +1 @@
|
||||
make OPENCV_ROOT=../../opencv V=0 clean
|
12
android/apps/CVCamera/default.properties
Normal file
@ -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
|
21
android/apps/CVCamera/jni/Android.mk
Normal file
@ -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)
|
||||
|
2
android/apps/CVCamera/jni/Application.mk
Normal file
@ -0,0 +1,2 @@
|
||||
# The ARMv7 is significanly faster due to the use of the hardware FPU
|
||||
APP_ABI := armeabi armeabi-v7a
|
300
android/apps/CVCamera/jni/Processor.cpp
Normal file
@ -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();
|
||||
}
|
60
android/apps/CVCamera/jni/Processor.h
Normal file
@ -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_ */
|
51
android/apps/CVCamera/jni/Processor.i
Normal file
@ -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);
|
||||
|
||||
};
|
36
android/apps/CVCamera/jni/cvcamera.i
Normal file
@ -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"
|
2
android/apps/CVCamera/project_create.sh
Executable file
@ -0,0 +1,2 @@
|
||||
android update project --name CVCamera \
|
||||
--path .
|
BIN
android/apps/CVCamera/res/drawable-hdpi/icon.png
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
android/apps/CVCamera/res/drawable-ldpi/icon.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
android/apps/CVCamera/res/drawable-mdpi/icon.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
8
android/apps/CVCamera/res/layout/main.xml
Normal file
@ -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>
|
7
android/apps/CVCamera/res/values/strings.xml
Normal file
@ -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>
|
4
android/apps/CVCamera/sample.local.env.mk
Normal file
@ -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
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
3
android/apps/CVCamera/uninstall.phone.sh
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
echo uninstalling CVCamera from phone
|
||||
adb uninstall com.theveganrobot.cvcamera
|
38
android/apps/Calibration/AndroidManifest.xml
Normal file
@ -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>
|
BIN
android/apps/Calibration/artwork/icon.xcf
Normal file
12
android/apps/Calibration/default.properties
Normal file
@ -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
|
2
android/apps/Calibration/project_create.sh
Executable file
@ -0,0 +1,2 @@
|
||||
android update project --name Calibration \
|
||||
--path .
|
BIN
android/apps/Calibration/res/drawable-hdpi/icon.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
BIN
android/apps/Calibration/res/drawable-ldpi/icon.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
BIN
android/apps/Calibration/res/drawable-mdpi/cameraback.jpg
Normal file
After Width: | Height: | Size: 161 KiB |
BIN
android/apps/Calibration/res/drawable-mdpi/icon.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
BIN
android/apps/Calibration/res/drawable-mdpi/patternicon.png
Normal file
After Width: | Height: | Size: 409 B |
59
android/apps/Calibration/res/layout/camera.xml
Normal file
@ -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>
|
40
android/apps/Calibration/res/layout/chesssizer.xml
Normal file
@ -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>
|
17
android/apps/Calibration/res/menu/calibrationmenu.xml
Normal file
@ -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>
|
20
android/apps/Calibration/res/values/chessnumbers.xml
Normal file
@ -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>
|
5
android/apps/Calibration/res/values/color.xml
Normal file
@ -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>
|
24
android/apps/Calibration/res/values/strings.xml
Normal file
@ -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>
|
@ -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);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
27
android/apps/camera_template/AndroidManifest.xml
Normal file
@ -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>
|
98
android/apps/camera_template/Makefile
Normal file
@ -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)
|
2
android/apps/camera_template/README.txt
Normal file
@ -0,0 +1,2 @@
|
||||
see http://code.google.com/p/android-opencv/wiki/camera_template
|
||||
|
1
android/apps/camera_template/build.sh
Normal file
@ -0,0 +1 @@
|
||||
make OPENCV_ROOT=../../opencv V=0
|
1
android/apps/camera_template/clean.sh
Normal file
@ -0,0 +1 @@
|
||||
make OPENCV_ROOT=../../opencv V=0 clean
|
12
android/apps/camera_template/default.properties
Normal file
@ -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
|
36
android/apps/camera_template/jni/Android.mk
Normal file
@ -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)
|
||||
|
2
android/apps/camera_template/jni/Application.mk
Normal file
@ -0,0 +1,2 @@
|
||||
# The ARMv7 is significanly faster due to the use of the hardware FPU
|
||||
APP_ABI := armeabi armeabi-v7a
|
5
android/apps/camera_template/jni/TestBar.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
#include "TestBar.h"
|
||||
|
||||
void BarBar::crazy(){
|
||||
|
||||
}
|
26
android/apps/camera_template/jni/TestBar.h
Normal file
@ -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_ */
|
68
android/apps/camera_template/jni/foobar.i
Normal file
@ -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();
|
||||
};
|
BIN
android/apps/camera_template/res/drawable-hdpi/icon.png
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
android/apps/camera_template/res/drawable-ldpi/icon.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
android/apps/camera_template/res/drawable-mdpi/icon.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
8
android/apps/camera_template/res/values/strings.xml
Normal file
@ -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>
|
224
android/apps/camera_template/src/com/foo/bar/FooBar.java
Normal file
@ -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();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|