Android:
authorAndrey Kamaev <no@email>
Sat, 16 Jul 2011 22:31:47 +0000 (22:31 +0000)
committerAndrey Kamaev <no@email>
Sat, 16 Jul 2011 22:31:47 +0000 (22:31 +0000)
* Added manual port for getTextSize;
* Fixed bugs in "native camera" sample;
* Added 15-puzzle sample.

13 files changed:
modules/imgproc/doc/filtering.rst
modules/java/gen_java.py
samples/android/15-puzzle/.classpath [new file with mode: 0644]
samples/android/15-puzzle/.project [new file with mode: 0644]
samples/android/15-puzzle/.settings/org.eclipse.jdt.core.prefs [new file with mode: 0644]
samples/android/15-puzzle/AndroidManifest.xml [new file with mode: 0644]
samples/android/15-puzzle/default.properties [new file with mode: 0644]
samples/android/15-puzzle/res/drawable/icon.png [new file with mode: 0644]
samples/android/15-puzzle/res/values/strings.xml [new file with mode: 0644]
samples/android/15-puzzle/src/org/opencv/samples/puzzle15/SampleViewBase.java [new file with mode: 0644]
samples/android/15-puzzle/src/org/opencv/samples/puzzle15/puzzle15Activity.java [new file with mode: 0644]
samples/android/15-puzzle/src/org/opencv/samples/puzzle15/puzzle15View.java [new file with mode: 0644]
samples/android/tutorial-2-opencvcamera/src/org/opencv/samples/tutorial2/SampleViewBase.java

index 845e35b..819514b 100644 (file)
@@ -1332,7 +1332,7 @@ pyrMeanShiftFiltering
 ---------------------
 Performs initial step of meanshift segmentation of an image.
 
-.. ocv:function: void pyrMeanShiftFiltering( InputArray src, OutputArray dst, double sp, double sr, int maxLevel=1, TermCriteria termcrit=TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS,5,1) )
+.. ocv:function:: void pyrMeanShiftFiltering( InputArray src, OutputArray dst, double sp, double sr, int maxLevel=1, TermCriteria termcrit=TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS,5,1) )
 
 .. ocv:pyfunction:: cv2.pyrMeanShiftFiltering(src, sp, sr[, dst[, maxLevel[, termcrit]]]) -> dst
 
index ad73314..3d3cd00 100644 (file)
@@ -176,7 +176,7 @@ type_dict = {
 \r
 }\r
 \r
-setManualFunctions=set(['minMaxLoc'])\r
+setManualFunctions=set(['minMaxLoc', 'getTextSize'])\r
 \r
 class ConstInfo(object):\r
     def __init__(self, cname, name, val):\r
@@ -420,7 +420,14 @@ class JavaWrapperGenerator(object):
         return minMaxLoc(src, null);\r
     }\r
     private static native double[] n_minMaxLocManual(long src_nativeObj, long mask_nativeObj);\r
-\r
+    \r
+    //javadoc:getTextSize(text, fontFace, fontScale, thickness, baseLine)\r
+    public static Size getTextSize(String text, int fontFace, double fontScale, int thickness, int[] baseLine) {\r
+        assert(baseLine == null || baseLine.length == 1);\r
+        Size retVal = new Size(n_getTextSize(text, fontFace, fontScale, thickness, baseLine));\r
+        return retVal;\r
+    }\r
+    private static native double[] n_getTextSize(String text, int fontFace, double fontScale, int thickness, int[] baseLine);\r
 \r
 """ )\r
 \r
@@ -558,7 +565,62 @@ JNIEXPORT jdoubleArray JNICALL Java_org_opencv_core_n_1minMaxLocManual
         LOGD("core::n_1minMaxLoc() catched unknown exception (...)");\r
 #endif // DEBUG\r
         jclass je = env->FindClass("java/lang/Exception");\r
-        env->ThrowNew(je, "Unknown exception in JNI code {$module::$fname()}");\r
+        env->ThrowNew(je, "Unknown exception in JNI code {core::minMaxLoc()}");\r
+        return NULL;\r
+    }\r
+}\r
+\r
+JNIEXPORT jdoubleArray JNICALL Java_org_opencv_core_n_1getTextSize\r
+  (JNIEnv* env, jclass cls, jstring text, jint fontFace, jdouble fontScale, jint thickness, jintArray baseLine)\r
+{\r
+    try {\r
+#ifdef DEBUG\r
+        LOGD("core::n_1getTextSize()");\r
+#endif // DEBUG\r
+\r
+        jdoubleArray result;\r
+        result = env->NewDoubleArray(2);\r
+        if (result == NULL) {\r
+            return NULL; /* out of memory error thrown */\r
+        }\r
+        \r
+        const char* utf_text = env->GetStringUTFChars(text, 0);\r
+        std::string n_text( utf_text ? utf_text : "" );\r
+        env->ReleaseStringUTFChars(text, utf_text);\r
+        \r
+        int _baseLine;\r
+        int* pbaseLine = 0;\r
+        \r
+        if (baseLine != NULL)\r
+            pbaseLine = &_baseLine;\r
+            \r
+        cv::Size rsize = cv::getTextSize(n_text, (int)fontFace, (double)fontScale, (int)thickness, pbaseLine);\r
+\r
+        jdouble fill[2];\r
+        fill[0]=rsize.width;\r
+        fill[1]=rsize.height;\r
+\r
+        env->SetDoubleArrayRegion(result, 0, 2, fill);\r
+        \r
+        if (baseLine != NULL)\r
+            env->SetIntArrayRegion(baseLine, 0, 1, pbaseLine);\r
+\r
+        return result;\r
+\r
+    } catch(cv::Exception e) {\r
+#ifdef DEBUG\r
+        LOGD("core::n_1getTextSize() catched cv::Exception: %s", e.what());\r
+#endif // DEBUG\r
+        jclass je = env->FindClass("org/opencv/CvException");\r
+        if(!je) je = env->FindClass("java/lang/Exception");\r
+        env->ThrowNew(je, e.what());\r
+        return NULL;\r
+    } catch (...) {\r
+#ifdef DEBUG\r
+        LOGD("core::n_1getTextSize() catched unknown exception (...)");\r
+#endif // DEBUG\r
+        jclass je = env->FindClass("java/lang/Exception");\r
+        env->ThrowNew(je, "Unknown exception in JNI code {core::getTextSize()}");\r
         return NULL;\r
     }\r
 }\r
diff --git a/samples/android/15-puzzle/.classpath b/samples/android/15-puzzle/.classpath
new file mode 100644 (file)
index 0000000..87ce3fa
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<classpath>\r
+       <classpathentry kind="src" path="src"/>\r
+       <classpathentry kind="src" path="gen"/>\r
+       <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>\r
+       <classpathentry kind="src" path="OpenCV-2.3.1_src"/>\r
+       <classpathentry kind="output" path="bin"/>\r
+</classpath>\r
diff --git a/samples/android/15-puzzle/.project b/samples/android/15-puzzle/.project
new file mode 100644 (file)
index 0000000..415bed2
--- /dev/null
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+       <name>15-puzzle</name>\r
+       <comment></comment>\r
+       <projects>\r
+       </projects>\r
+       <buildSpec>\r
+               <buildCommand>\r
+                       <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.jdt.core.javabuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>com.android.ide.eclipse.adt.ApkBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+       </buildSpec>\r
+       <natures>\r
+               <nature>com.android.ide.eclipse.adt.AndroidNature</nature>\r
+               <nature>org.eclipse.jdt.core.javanature</nature>\r
+       </natures>\r
+       <linkedResources>\r
+               <link>\r
+                       <name>OpenCV-2.3.1_src</name>\r
+                       <type>2</type>\r
+                       <locationURI>_android_OpenCV_2_3_1_df28900a/src</locationURI>\r
+               </link>\r
+       </linkedResources>\r
+</projectDescription>\r
diff --git a/samples/android/15-puzzle/.settings/org.eclipse.jdt.core.prefs b/samples/android/15-puzzle/.settings/org.eclipse.jdt.core.prefs
new file mode 100644 (file)
index 0000000..d995784
--- /dev/null
@@ -0,0 +1,5 @@
+#Wed Jun 29 04:36:40 MSD 2011\r
+eclipse.preferences.version=1\r
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5\r
+org.eclipse.jdt.core.compiler.compliance=1.5\r
+org.eclipse.jdt.core.compiler.source=1.5\r
diff --git a/samples/android/15-puzzle/AndroidManifest.xml b/samples/android/15-puzzle/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..30003c1
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      package="org.opencv.samples.puzzle15"
+      android:versionCode="1"
+      android:versionName="1.0">
+
+    <application android:icon="@drawable/icon" android:label="@string/app_name">
+        <activity android:name=".puzzle15Activity"
+                  android:label="@string/app_name"
+                  android:screenOrientation="landscape"
+                  android:configChanges="keyboardHidden|orientation">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+    
+    <uses-sdk android:minSdkVersion="8" />
+
+    <uses-permission android:name="android.permission.CAMERA"/>
+    <uses-feature android:name="android.hardware.camera" />
+    <uses-feature android:name="android.hardware.camera.autofocus" />
+</manifest>
\ No newline at end of file
diff --git a/samples/android/15-puzzle/default.properties b/samples/android/15-puzzle/default.properties
new file mode 100644 (file)
index 0000000..fb3ea1f
--- /dev/null
@@ -0,0 +1,3 @@
+android.library.reference.1=../../../android/build
+# Project target.
+target=android-8
diff --git a/samples/android/15-puzzle/res/drawable/icon.png b/samples/android/15-puzzle/res/drawable/icon.png
new file mode 100644 (file)
index 0000000..4e828ba
Binary files /dev/null and b/samples/android/15-puzzle/res/drawable/icon.png differ
diff --git a/samples/android/15-puzzle/res/values/strings.xml b/samples/android/15-puzzle/res/values/strings.xml
new file mode 100644 (file)
index 0000000..99e7315
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="app_name">15-puzzle</string>
+</resources>
diff --git a/samples/android/15-puzzle/src/org/opencv/samples/puzzle15/SampleViewBase.java b/samples/android/15-puzzle/src/org/opencv/samples/puzzle15/SampleViewBase.java
new file mode 100644 (file)
index 0000000..b85325e
--- /dev/null
@@ -0,0 +1,108 @@
+package org.opencv.samples.puzzle15;
+
+import java.util.List;
+
+import org.opencv.*;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.util.Log;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+public abstract class SampleViewBase extends SurfaceView implements SurfaceHolder.Callback, Runnable {
+    private static final String TAG = "Sample::SurfaceView";
+
+    private SurfaceHolder       mHolder;
+    private VideoCapture        mCamera;
+
+    public SampleViewBase(Context context) {
+        super(context);
+        mHolder = getHolder();
+        mHolder.addCallback(this);
+        Log.i(TAG, "Instantiated new " + this.getClass());
+    }
+
+    public void surfaceChanged(SurfaceHolder _holder, int format, int width, int height) {
+        Log.i(TAG, "surfaceCreated");
+        synchronized (this) {
+            if (mCamera != null && mCamera.isOpened()) {
+                Log.i(TAG, "before mCamera.getSupportedPreviewSizes()");
+                List<Size> sizes = mCamera.getSupportedPreviewSizes();
+                Log.i(TAG, "after mCamera.getSupportedPreviewSizes()");
+                int mFrameWidth = width;
+                int mFrameHeight = height;
+
+                // selecting optimal camera preview size
+                {
+                    double minDiff = Double.MAX_VALUE;
+                    for (Size size : sizes) {
+                        if (Math.abs(size.height - height) < minDiff) {
+                            mFrameWidth = (int) size.width;
+                            mFrameHeight = (int) size.height;
+                            minDiff = Math.abs(size.height - height);
+                        }
+                    }
+                }
+
+                mCamera.set(highgui.CV_CAP_PROP_FRAME_WIDTH, mFrameWidth);
+                mCamera.set(highgui.CV_CAP_PROP_FRAME_HEIGHT, mFrameHeight);
+            }
+        }
+    }
+
+    public void surfaceCreated(SurfaceHolder holder) {
+        Log.i(TAG, "surfaceCreated");
+        mCamera = new VideoCapture(highgui.CV_CAP_ANDROID);
+        if (mCamera.isOpened()) {
+            (new Thread(this)).start();
+        } else {
+            mCamera.release();
+            mCamera = null;
+            Log.e(TAG, "Failed to open native camera");
+        }
+    }
+
+    public void surfaceDestroyed(SurfaceHolder holder) {
+        Log.i(TAG, "surfaceDestroyed");
+        if (mCamera != null) {
+            synchronized (this) {
+                mCamera.release();
+                mCamera = null;
+            }
+        }
+    }
+
+    protected abstract Bitmap processFrame(VideoCapture capture);
+
+    public void run() {
+        Log.i(TAG, "Starting processing thread");
+        while (true) {
+            Bitmap bmp = null;
+
+            synchronized (this) {
+                if (mCamera == null)
+                    break;
+
+                if (!mCamera.grab()) {
+                    Log.e(TAG, "mCamera.grab() failed");
+                    break;
+                }
+
+                bmp = processFrame(mCamera);
+            }
+
+            if (bmp != null) {
+                Canvas canvas = mHolder.lockCanvas();
+                if (canvas != null) {
+                    canvas.drawBitmap(bmp, (canvas.getWidth() - bmp.getWidth()) / 2, (canvas.getHeight() - bmp.getHeight()) / 2, null);
+                    mHolder.unlockCanvasAndPost(canvas);
+                }
+                bmp.recycle();
+            }
+        }
+
+        Log.i(TAG, "Finishing processing thread");
+    }
+}
\ No newline at end of file
diff --git a/samples/android/15-puzzle/src/org/opencv/samples/puzzle15/puzzle15Activity.java b/samples/android/15-puzzle/src/org/opencv/samples/puzzle15/puzzle15Activity.java
new file mode 100644 (file)
index 0000000..2444f57
--- /dev/null
@@ -0,0 +1,50 @@
+package org.opencv.samples.puzzle15;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.Window;
+
+public class puzzle15Activity extends Activity {
+    private static final String TAG = "Sample::Activity";
+
+    private MenuItem            mItemNewGame;
+    private MenuItem            mItemToggleNumbers;
+    private puzzle15View        mView;
+
+    public puzzle15Activity() {
+        Log.i(TAG, "Instantiated new " + this.getClass());
+    }
+
+    /** Called when the activity is first created. */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        Log.i(TAG, "onCreate");
+        super.onCreate(savedInstanceState);
+        requestWindowFeature(Window.FEATURE_NO_TITLE);
+        mView = new puzzle15View(this);
+        setContentView(mView);
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        Log.i(TAG, "onCreateOptionsMenu");
+        mItemNewGame = menu.add("Start new game");
+        mItemToggleNumbers = menu.add("Show/hide tile numbers");
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        Log.i(TAG, "Menu Item selected " + item);
+        if (item == mItemNewGame) {
+            synchronized (mView) {
+                mView.startNewGame();
+            }
+        } else if (item == mItemToggleNumbers)
+            mView.tolggleTileNumbers();
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/samples/android/15-puzzle/src/org/opencv/samples/puzzle15/puzzle15View.java b/samples/android/15-puzzle/src/org/opencv/samples/puzzle15/puzzle15View.java
new file mode 100644 (file)
index 0000000..1f6abbc
--- /dev/null
@@ -0,0 +1,221 @@
+package org.opencv.samples.puzzle15;\r
+\r
+import org.opencv.*;\r
+\r
+import android.content.Context;\r
+import android.graphics.Bitmap;\r
+import android.view.MotionEvent;\r
+import android.view.SurfaceHolder;\r
+import android.view.View;\r
+import android.view.View.OnTouchListener;\r
+\r
+public class puzzle15View extends SampleViewBase implements OnTouchListener {\r
+    private Mat     mRgba;\r
+    private Mat     mRgba15;\r
+    private Mat[]   mCells;\r
+    private Mat[]   mCells15;\r
+    private int[]   mIndexses;\r
+    private int[]   mTextWidths;\r
+    private int[]   mTextHeights;\r
+    private boolean mShowTileNumbers = true;\r
+\r
+    int             gridSize         = 4;\r
+    int             gridArea         = gridSize * gridSize;\r
+    int             gridEmptyIdx     = gridArea - 1;\r
+\r
+    public puzzle15View(Context context) {\r
+        super(context);\r
+        setOnTouchListener(this);\r
+\r
+        mTextWidths = new int[gridArea];\r
+        mTextHeights = new int[gridArea];\r
+        for (int i = 0; i < gridArea; i++) {\r
+            Size s = core.getTextSize(Integer.toString(i + 1), 3/* CV_FONT_HERSHEY_COMPLEX */, 1, 2, null);\r
+            mTextHeights[i] = (int) s.height;\r
+            mTextWidths[i] = (int) s.width;\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public void surfaceChanged(SurfaceHolder _holder, int format, int width, int height) {\r
+        super.surfaceChanged(_holder, format, width, height);\r
+        synchronized (this) {\r
+            // initialize Mat before usage\r
+            mRgba = new Mat();\r
+        }\r
+    }\r
+\r
+    public static void shuffle(int[] array) {\r
+        for (int i = array.length; i > 1; i--) {\r
+            int temp = array[i - 1];\r
+            int randIx = (int) (Math.random() * i);\r
+            array[i - 1] = array[randIx];\r
+            array[randIx] = temp;\r
+        }\r
+    }\r
+\r
+    public boolean isPuzzleSolvable() {\r
+        if (gridSize != 4)\r
+            return true;\r
+\r
+        int sum = 0;\r
+        for (int i = 0; i < gridArea; i++) {\r
+            if (mIndexses[i] == gridEmptyIdx)\r
+                sum += (i / gridSize) + 1;\r
+            else {\r
+                int smaller = 0;\r
+                for (int j = i + 1; j < gridArea; j++) {\r
+                    if (mIndexses[j] < mIndexses[i])\r
+                        smaller++;\r
+                }\r
+                sum += smaller;\r
+            }\r
+        }\r
+\r
+        return sum % 2 == 0;\r
+    }\r
+\r
+    private void createPuzzle(int cols, int rows) {\r
+        mCells = new Mat[gridArea];\r
+        mCells15 = new Mat[gridArea];\r
+\r
+        mRgba15 = new Mat(rows, cols, mRgba.type());\r
+        mIndexses = new int[gridArea];\r
+\r
+        for (int i = 0; i < gridSize; i++) {\r
+            for (int j = 0; j < gridSize; j++) {\r
+                int k = i * gridSize + j;\r
+                mIndexses[k] = k;\r
+                mCells[k] = mRgba.submat(i * rows / gridSize, (i + 1) * rows / gridSize, j * cols / gridSize, (j + 1) * cols / gridSize);\r
+                mCells15[k] = mRgba15.submat(i * rows / gridSize, (i + 1) * rows / gridSize, j * cols / gridSize, (j + 1) * cols / gridSize);\r
+            }\r
+        }\r
+\r
+        startNewGame();\r
+    }\r
+\r
+    public void startNewGame() {\r
+        do {\r
+            shuffle(mIndexses);\r
+        } while (!isPuzzleSolvable());\r
+    }\r
+\r
+    public void tolggleTileNumbers() {\r
+        mShowTileNumbers = !mShowTileNumbers;\r
+    }\r
+\r
+    @Override\r
+    protected Bitmap processFrame(VideoCapture capture) {\r
+        capture.retrieve(mRgba, highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA);\r
+        int cols = mRgba.cols();\r
+        int rows = mRgba.rows();\r
+\r
+        if (mCells == null)\r
+            createPuzzle(cols, rows);\r
+\r
+        // copy shuffled tiles\r
+        for (int i = 0; i < gridArea; i++) {\r
+            int idx = mIndexses[i];\r
+            if (idx == gridEmptyIdx)\r
+                mCells15[i].setTo(new Scalar(0x33, 0x33, 0x33, 0xFF));\r
+            else {\r
+                mCells[idx].copyTo(mCells15[i]);\r
+                if (mShowTileNumbers) {\r
+                    core.putText(mCells15[i], Integer.toString(1 + idx), new Point((cols / gridSize - mTextWidths[idx]) / 2,\r
+                            (rows / gridSize + mTextHeights[idx]) / 2), 3/* CV_FONT_HERSHEY_COMPLEX */, 1, new Scalar(255, 0, 0, 255), 2);\r
+                }\r
+            }\r
+        }\r
+\r
+        drawGrid(cols, rows);\r
+\r
+        Bitmap bmp = Bitmap.createBitmap(cols, rows, Bitmap.Config.ARGB_8888);\r
+        if (android.MatToBitmap(mRgba15, bmp))\r
+            return bmp;\r
+\r
+        bmp.recycle();\r
+        return null;\r
+    }\r
+\r
+    private void drawGrid(int cols, int rows) {\r
+        for (int i = 1; i < gridSize; i++) {\r
+            core.line(mRgba15, new Point(0, i * rows / gridSize), new Point(cols, i * rows / gridSize), new Scalar(0, 255, 0, 255), 3);\r
+            core.line(mRgba15, new Point(i * cols / gridSize, 0), new Point(i * cols / gridSize, rows), new Scalar(0, 255, 0, 255), 3);\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public void run() {\r
+        super.run();\r
+\r
+        synchronized (this) {\r
+            // Explicitly deallocate Mats\r
+            if (mCells != null) {\r
+                for (Mat m : mCells)\r
+                    m.dispose();\r
+            }\r
+            if (mCells15 != null) {\r
+                for (Mat m : mCells15)\r
+                    m.dispose();\r
+            }\r
+            if (mRgba != null)\r
+                mRgba.dispose();\r
+            if (mRgba15 != null)\r
+                mRgba15.dispose();\r
+\r
+            mRgba = null;\r
+            mRgba15 = null;\r
+            mCells = null;\r
+            mCells15 = null;\r
+            mIndexses = null;\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public boolean onTouch(View v, MotionEvent event) {\r
+        int cols = mRgba.cols();\r
+        int rows = mRgba.rows();\r
+        float xoffset = (getWidth() - cols) / 2;\r
+        float yoffset = (getHeight() - rows) / 2;\r
+\r
+        float x = event.getX() - xoffset;\r
+        float y = event.getY() - yoffset;\r
+\r
+        int row = (int) Math.floor(y * gridSize / rows);\r
+        int col = (int) Math.floor(x * gridSize / cols);\r
+\r
+        if (row < 0 || row >= gridSize || col < 0 || col >= gridSize)\r
+            return false;\r
+\r
+        int idx = row * gridSize + col;\r
+        int idxtoswap = -1;\r
+\r
+        // left\r
+        if (idxtoswap < 0 && col > 0)\r
+            if (mIndexses[idx - 1] == gridEmptyIdx)\r
+                idxtoswap = idx - 1;\r
+        // right\r
+        if (idxtoswap < 0 && col < gridSize - 1)\r
+            if (mIndexses[idx + 1] == gridEmptyIdx)\r
+                idxtoswap = idx + 1;\r
+        // top\r
+        if (idxtoswap < 0 && row > 0)\r
+            if (mIndexses[idx - gridSize] == gridEmptyIdx)\r
+                idxtoswap = idx - gridSize;\r
+        // bottom\r
+        if (idxtoswap < 0 && row < gridSize - 1)\r
+            if (mIndexses[idx + gridSize] == gridEmptyIdx)\r
+                idxtoswap = idx + gridSize;\r
+\r
+        // swap\r
+        if (idxtoswap >= 0) {\r
+            synchronized (this) {\r
+                int touched = mIndexses[idx];\r
+                mIndexses[idx] = mIndexses[idxtoswap];\r
+                mIndexses[idxtoswap] = touched;\r
+            }\r
+        }\r
+\r
+        return false;// don't need subsequent touch events\r
+    }\r
+}\r
index 2f5c03a..4725844 100644 (file)
@@ -16,7 +16,6 @@ public abstract class SampleViewBase extends SurfaceView implements SurfaceHolde
 
     private SurfaceHolder       mHolder;
     private VideoCapture        mCamera;
-    private boolean             mThreadRun;
 
     public SampleViewBase(Context context) {
         super(context);
@@ -27,27 +26,29 @@ public abstract class SampleViewBase extends SurfaceView implements SurfaceHolde
 
     public void surfaceChanged(SurfaceHolder _holder, int format, int width, int height) {
         Log.i(TAG, "surfaceCreated");
-        if (mCamera != null && mCamera.isOpened()) {
-            Log.i(TAG, "before mCamera.getSupportedPreviewSizes()");
-            List<Size> sizes = mCamera.getSupportedPreviewSizes();
-            Log.i(TAG, "after mCamera.getSupportedPreviewSizes()");
-            int mFrameWidth = width;
-            int mFrameHeight = height;
-
-            // selecting optimal camera preview size
-            {
-                double minDiff = Double.MAX_VALUE;
-                for (Size size : sizes) {
-                    if (Math.abs(size.height - height) < minDiff) {
-                        mFrameWidth = (int) size.width;
-                        mFrameHeight = (int) size.height;
-                        minDiff = Math.abs(size.height - height);
+        synchronized (this) {
+            if (mCamera != null && mCamera.isOpened()) {
+                Log.i(TAG, "before mCamera.getSupportedPreviewSizes()");
+                List<Size> sizes = mCamera.getSupportedPreviewSizes();
+                Log.i(TAG, "after mCamera.getSupportedPreviewSizes()");
+                int mFrameWidth = width;
+                int mFrameHeight = height;
+
+                // selecting optimal camera preview size
+                {
+                    double minDiff = Double.MAX_VALUE;
+                    for (Size size : sizes) {
+                        if (Math.abs(size.height - height) < minDiff) {
+                            mFrameWidth = (int) size.width;
+                            mFrameHeight = (int) size.height;
+                            minDiff = Math.abs(size.height - height);
+                        }
                     }
                 }
-            }
 
-            mCamera.set(highgui.CV_CAP_PROP_FRAME_WIDTH, mFrameWidth);
-            mCamera.set(highgui.CV_CAP_PROP_FRAME_HEIGHT, mFrameHeight);
+                mCamera.set(highgui.CV_CAP_PROP_FRAME_WIDTH, mFrameWidth);
+                mCamera.set(highgui.CV_CAP_PROP_FRAME_HEIGHT, mFrameHeight);
+            }
         }
     }
 
@@ -65,7 +66,6 @@ public abstract class SampleViewBase extends SurfaceView implements SurfaceHolde
 
     public void surfaceDestroyed(SurfaceHolder holder) {
         Log.i(TAG, "surfaceDestroyed");
-        mThreadRun = false;
         if (mCamera != null) {
             synchronized (this) {
                 mCamera.release();
@@ -77,17 +77,19 @@ public abstract class SampleViewBase extends SurfaceView implements SurfaceHolde
     protected abstract Bitmap processFrame(VideoCapture capture);
 
     public void run() {
-        mThreadRun = true;
         Log.i(TAG, "Starting processing thread");
-        while (mThreadRun) {
+        while (true) {
             Bitmap bmp = null;
 
-            if (!mCamera.grab()) {
-                Log.e(TAG, "mCamera.grab() failed");
-                break;
-            }
-
             synchronized (this) {
+                if (mCamera == null)
+                    break;
+
+                if (!mCamera.grab()) {
+                    Log.e(TAG, "mCamera.grab() failed");
+                    break;
+                }
+
                 bmp = processFrame(mCamera);
             }
 
@@ -100,5 +102,7 @@ public abstract class SampleViewBase extends SurfaceView implements SurfaceHolde
                 bmp.recycle();
             }
         }
+
+        Log.i(TAG, "Finishing processing thread");
     }
 }
\ No newline at end of file