Skip to content

Commit

Permalink
Use OpenCV for Android libraries for image processing
Browse files Browse the repository at this point in the history
  • Loading branch information
efokschaner committed Jan 1, 2016
1 parent 6276d46 commit 0970689
Show file tree
Hide file tree
Showing 114 changed files with 26,557 additions and 100 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@ Automatically plays the android game named "∞ Loop" (com.balysv.loop)

adb install ∞\ Loop_v3_0.apk

### Install OpenCV Manager application:
If you have the Play Store on the device you can skip this step
as the application should (in theory) prompt you to install it.

Either get it from the Play Store or install it from the SDK
http://sourceforge.net/projects/opencvlibrary/files/opencv-android/
eg.

adb install OpenCV-android-sdk/apk/OpenCV_3.1.0_Manager_3.10_x86.apk

Make sure to pick the right architecture apk for the target device

### Install the application (debug works fine):

./gradlew installDebug
Expand Down
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,5 @@ dependencies {
compile 'com.android.support:appcompat-v7:23.1.1'
compile 'com.android.support:support-v4:23.1.1'
compile 'com.android.support:design:23.1.1'
compile project(':openCVLibrary310')
}
76 changes: 76 additions & 0 deletions app/src/main/java/efokschaner/infinityloopsolver/Debug.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package efokschaner.infinityloopsolver;


import android.app.UiAutomation;
import android.graphics.Bitmap;

import org.opencv.android.Utils;
import org.opencv.core.Mat;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Debug {
public static void sendBitmap(Bitmap bitmap) {
try {
String timestamp = new SimpleDateFormat("HH_mm_ss").format(new Date());
URL url = new URL("http://10.0.2.2:8888/" + timestamp + ".png");
try {
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
try {
conn.setDoOutput(true);
conn.setChunkedStreamingMode(0);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/octet-stream");
try (OutputStream ostream = conn.getOutputStream()) {
bitmap.compress(Bitmap.CompressFormat.PNG, 100, ostream);
} catch (IOException e) {
e.printStackTrace();
}
final int responseCode = conn.getResponseCode();
if (!(responseCode >= 200 && responseCode < 300)) {
throw new AssertionError(String.format("Http response was: %d", responseCode));
}
conn.getResponseMessage();
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
while (in.readLine() != null){
// ignore contents
}
in.close();
} catch (ProtocolException e) {
e.printStackTrace();
} finally {
conn.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (MalformedURLException e) {
e.printStackTrace();
}
}

public static void sendMatrix(Mat m) {
Bitmap b2 = Bitmap.createBitmap(m.width(), m.height(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(m, b2);
sendBitmap(b2);
b2.recycle();
}

public static void sendScreenshot(UiAutomation uiAutomation) {
Bitmap b = uiAutomation.takeScreenshot();
try{
sendBitmap(b);
} finally {
b.recycle();
}
}
}
92 changes: 92 additions & 0 deletions app/src/main/java/efokschaner/infinityloopsolver/GameState.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package efokschaner.infinityloopsolver;


public class GameState {
public static class Direction {
public static final int NONE = 0;
public static final int UP = 1;
public static final int RIGHT = 1 << 1;
public static final int DOWN = 1 << 2;
public static final int LEFT = 1 << 3;

public static final int[] ALL = {UP, RIGHT, DOWN, LEFT};
}

// Represents offset from the canonical orientations
public static class TileOrientation {
public static final TileOrientation ZERO = new TileOrientation(0);
public static final TileOrientation QUARTER = new TileOrientation(1);
public static final TileOrientation HALF = new TileOrientation(2);
public static final TileOrientation THREE_QUARTERS = new TileOrientation(3);

private int mValue;

TileOrientation(int value) {
mValue = value;
}

public TileOrientation rotate(int num) {
return new TileOrientation((mValue + num) % 3);
}

public TileOrientation rotate() {
return new TileOrientation(0);
}
}

public enum TileType {
EMPTY(Direction.NONE, new TileOrientation[]{
TileOrientation.ZERO
}),
END(Direction.UP, new TileOrientation[]{
TileOrientation.ZERO,
TileOrientation.QUARTER,
TileOrientation.HALF,
TileOrientation.THREE_QUARTERS
}),
LINE(Direction.UP| Direction.DOWN, new TileOrientation[]{
TileOrientation.ZERO,
TileOrientation.QUARTER
}),
CORNER(Direction.UP| Direction.RIGHT, new TileOrientation[]{
TileOrientation.ZERO,
TileOrientation.QUARTER,
TileOrientation.HALF,
TileOrientation.THREE_QUARTERS
}),
TEE(Direction.UP| Direction.RIGHT| Direction.DOWN, new TileOrientation[]{
TileOrientation.ZERO,
TileOrientation.QUARTER,
TileOrientation.HALF,
TileOrientation.THREE_QUARTERS
}),
CROSS(Direction.UP| Direction.RIGHT| Direction.DOWN| Direction.LEFT, new TileOrientation[]{
TileOrientation.ZERO
});


private final int mConnectionDirections;
private final TileOrientation[] mPossibleOrientations;

// connectionDirections are which directions the tile connects to in its default orientation
// possibleOrientations allows us to cull orientations that are the same for the purposes of the game
TileType(int connectionDirections, TileOrientation[] possibleOrientations) {
mConnectionDirections = connectionDirections;
mPossibleOrientations = possibleOrientations;
}
}

public static class TileState {
TileType type;
TileOrientation orientation;
boolean isOrientationSolved = false;
}

private TileState[][] mGrid;

public GameState(TileState[][] grid) {
mGrid = grid;
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package efokschaner.infinityloopsolver;

import android.graphics.Bitmap;

import org.opencv.android.Utils;
import org.opencv.core.Mat;


public class ImageProcessor {
public static GameState getGameStateFromImage(Bitmap b) {
Mat m = new Mat();
Utils.bitmapToMat(b, m);
Debug.sendMatrix(m);
return new GameState(new GameState.TileState[2][2]);
}
}
50 changes: 47 additions & 3 deletions app/src/main/java/efokschaner/infinityloopsolver/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,65 @@

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.CompoundButton;
import android.widget.Switch;

import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;

public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();

Switch mEnabledSwitch;

private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(int status) {
switch(status) {
case LoaderCallbackInterface.SUCCESS:
Log.i(TAG, "OpenCV Manager Connected");
mEnabledSwitch.setEnabled(true);
break;
case LoaderCallbackInterface.INIT_FAILED:
Log.i(TAG,"Init Failed");
break;
case LoaderCallbackInterface.INSTALL_CANCELED:
Log.i(TAG,"Install Cancelled");
break;
case LoaderCallbackInterface.INCOMPATIBLE_MANAGER_VERSION:
Log.i(TAG,"Incompatible Version");
break;
case LoaderCallbackInterface.MARKET_ERROR:
Log.i(TAG,"Market Error");
break;
default:
Log.i(TAG,"OpenCV Manager Install");
super.onManagerConnected(status);
break;
}
}
};

@Override
protected void onResume() {
super.onResume();
//initialize OpenCV manager
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_1_0, this, mLoaderCallback);
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final SolverApplication app = (SolverApplication) getApplication();
setContentView(R.layout.activity_main);
final Switch enabledSwitch = (Switch) findViewById(R.id.switch_solver_enabled);
enabledSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
mEnabledSwitch = (Switch) findViewById(R.id.switch_solver_enabled);
mEnabledSwitch.setEnabled(false);
mEnabledSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked) {
if (isChecked) {
app.enableSolver();
} else {
app.disableSolver();
Expand Down
Loading

0 comments on commit 0970689

Please sign in to comment.