Skip to content

Commit 014d576

Browse files
committed
brought in opencv, drawing contours in red, and roundish/squarish objects in green
drawing lines in cyan
1 parent 1b95c89 commit 014d576

File tree

11 files changed

+470
-19
lines changed

11 files changed

+470
-19
lines changed

android/AndroidManifest.xml

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,34 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:installLocation="preferExternal"
34
package="com.androidmontreal.opencv"
45
android:versionCode="1"
56
android:versionName="1.0" >
67

7-
<uses-sdk android:minSdkVersion="8" />
8+
<uses-sdk android:minSdkVersion="8"
9+
android:targetSdkVersion="15" />
810

11+
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
12+
<uses-permission android:name="android.permission.CAMERA" />
13+
14+
<uses-feature android:name="android.hardware.camera" />
15+
<uses-feature android:name="android.hardware.camera.autofocus" />
16+
17+
<supports-screens
18+
android:anyDensity="true"
19+
android:largeScreens="true"
20+
android:normalScreens="true"
21+
android:smallScreens="true" />
22+
23+
924
<application
1025
android:icon="@drawable/ic_launcher"
1126
android:label="@string/app_name" >
1227
<activity
1328
android:name="AndroidOpenCVforHackathonsActivity"
14-
android:label="@string/app_name" >
29+
android:label="@string/app_name"
30+
android:configChanges="keyboardHidden|orientation"
31+
android:screenOrientation="landscape">
1532
<intent-filter>
1633
<action android:name="android.intent.action.MAIN" />
1734

android/jni/Android.mk

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@ LOCAL_PATH := $(call my-dir)
1616

1717
include $(CLEAR_VARS)
1818

19+
OPENCV_MK_PATH:=$(OPENCV_PACKAGE_DIR)/OpenCV-2.3.1/share/OpenCV/OpenCV.mk
20+
include $(OPENCV_MK_PATH)
21+
1922
LOCAL_MODULE := opencv_sample
20-
LOCAL_SRC_FILES := main.cpp
21-
LOCAL_LDLIBS := -llog
23+
LOCAL_SRC_FILES := main.cpp image_processing.cpp
24+
LOCAL_LDLIBS += -llog -ldl
2225

2326
include $(BUILD_SHARED_LIBRARY)

android/jni/Application.mk

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
APP_STL := gnustl_static
2+
APP_CPPFLAGS := -frtti -fexceptions
3+
APP_ABI := armeabi

android/jni/image_processing.cpp

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
#include "image_processing.h"
2+
#include <android/log.h>
3+
4+
#define LOG_TAG "Image Processing"
5+
# define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
6+
# define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
7+
8+
9+
using namespace cv;
10+
using namespace std;
11+
12+
/* Calculate the circularity of a contour */
13+
double calcCircularity(vector<Point> contour) {
14+
// Check circularity
15+
double perimeter = arcLength(contour, true);
16+
double area = contourArea(contour);
17+
double circularity = 4 * 3.14159265 * area / (perimeter * perimeter);
18+
return circularity;
19+
}
20+
21+
22+
/*
23+
* Finds all the shapes (contours) in a region
24+
* 1. gets a thesholded matrix to find outlines
25+
* 2. gets all the contours around those outlines, contours are stored as a vector of points
26+
*
27+
*/
28+
string colorSomeStuff(Mat& mbgra) {
29+
LOGI("Using thresholds to find contrast and then contours around those highcontrast items...");
30+
31+
int width = mbgra.size[1];
32+
int height = mbgra.size[0];
33+
34+
// Separate the image in 3 places ( B, G and R )
35+
vector<Mat> rgbPlanes;
36+
split(mbgra, rgbPlanes);
37+
38+
/*
39+
Get the yellow plane since most people wont write in yellow on a white board,
40+
then apply an adaptive threshold with a 31pixel window to look for contrast,
41+
save the contrast into the thresh matrix
42+
*/
43+
Mat yellow = rgbPlanes[1]/2+rgbPlanes[2]/2;
44+
Mat thresh;
45+
adaptiveThreshold(yellow, thresh, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, 31, 11);
46+
//Blackboard dont do an inverse, it will already be dark on light : adaptiveThreshold(yellow, thresh, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 31, 10);
47+
48+
49+
50+
/*
51+
Take the thresh matrix, and look for contours in it
52+
*/
53+
vector<vector<Point> > contours;
54+
findContours(thresh, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);//###
55+
LOGI("Contours: %d", contours.size());
56+
57+
/*
58+
For each contour, find out how rectangle it is (between .8 and 1 is a pretty good rectangle candidate)
59+
*/
60+
vector<vector<Point> > checkboxes;
61+
for (int i = 0; i < contours.size(); i++) {
62+
Rect rect = boundingRect(contours[i]);
63+
64+
// Make contour convex, not sure why but probably to get the outermost line of the contour
65+
vector<Point> convex;
66+
convexHull(contours[i], convex);
67+
68+
// Check roundness
69+
double roundness = calcCircularity(convex);
70+
71+
if (roundness < 0.8)
72+
continue;
73+
checkboxes.push_back (convex);
74+
}
75+
LOGI("Potential Checkboxes: %d", checkboxes.size());
76+
77+
78+
79+
/*
80+
* Draw the checkbox-like contours which were found in green Scalar(0, 255, 0, 255) so you can see what the function is doing...
81+
*/
82+
drawContours(mbgra, checkboxes, -1, Scalar(0, 255, 0, 255), 2);
83+
84+
/*
85+
* Draw a line below the "roundish" objects if you wish
86+
*/
87+
for (int i = 0; i < checkboxes.size(); i++) {
88+
/*
89+
* Get the rectangle around the contour, use this if you need to know the x,y of the contour,
90+
* or if you want to know the width or height of the contour.
91+
*
92+
* WATCHOUT: if you hold the andriod in portrait, x will be y, and you y will be x.
93+
*/
94+
Rect rect = boundingRect(checkboxes[i]);
95+
96+
/*
97+
* Draw a line across the screen, under the "checkbox"
98+
* you will see if your x is truely the x or if it is the y...
99+
*/
100+
if(rect.width >10){
101+
int margin = 5;
102+
int width = mbgra.size[0];
103+
int height = mbgra.size[1];
104+
line(mbgra
105+
, Point(rect.x + rect.width+margin, 0)
106+
, Point(rect.x + rect.width, height+margin)
107+
, Scalar(200, 200, 0, 255)
108+
, 2);
109+
}
110+
}
111+
112+
/*
113+
* Draw the threshold matrix in red Scalar(0, 0, 255, 255)as a mask on top of the image
114+
*/
115+
mbgra.setTo(Scalar(0, 0, 255, 255), thresh);
116+
117+
/*
118+
* Concatinate a string and return it to the Java,
119+
* if you have something that you want to return
120+
*/
121+
stringstream ss;
122+
ss << "This is the result for this frame " << contours.size();
123+
string resultString = ss.str();
124+
125+
return resultString;
126+
}

android/jni/image_processing.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#include <opencv/cv.h>
2+
#include <opencv2/core/core.hpp>
3+
#include <opencv2/imgproc/imgproc.hpp>
4+
#include <opencv2/features2d/features2d.hpp>
5+
#include <opencv2/highgui/highgui.hpp>
6+
7+
double calcCircularity(std::vector<cv::Point> contour);
8+
9+
std::string colorSomeStuff(cv::Mat& mbgra);

android/jni/main.cpp

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,21 @@
1414
* limitations under the License.
1515
*
1616
*/
17-
#include <string.h>
17+
#include <stdarg.h>
1818
#include <jni.h>
19+
#include <opencv2/core/core.hpp>
20+
#include <opencv2/imgproc/imgproc.hpp>
21+
#include <opencv2/features2d/features2d.hpp>
22+
#include <opencv2/highgui/highgui.hpp>
23+
#include <vector>
24+
1925

20-
#include <stdio.h>
21-
#include <stdlib.h>
2226
#include <android/log.h>
27+
#include "image_processing.h"
28+
2329

24-
#define LOG_TAG "IntheCPP"
25-
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
26-
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
30+
using namespace cv;
31+
using namespace std;
2732

2833
/* This is a trivial JNI example where we use a native method
2934
* to return a new VM String. See the corresponding Java source
@@ -37,6 +42,35 @@ extern "C" {
3742

3843
JNIEXPORT jstring JNICALL Java_com_androidmontreal_opencv_AndroidOpenCVforHackathonsActivity_stringFromJNI(JNIEnv * env, jobject thiz)
3944
{
40-
LOGI("In the function call for stringFromJNI which is in the AndroidOpenCVforHackathonsActivity class in the com.androidmontreal.opencv package ");
41-
return env->NewStringUTF("Hello From CPP");
45+
return env->NewStringUTF("Hello From CPP");
4246
}
47+
extern "C" {
48+
JNIEXPORT jstring JNICALL Java_com_androidmontreal_opencv_OpenCVPreview_processimage(JNIEnv* env, jobject thiz, jint width, jint height, jbyteArray yuv, jintArray bgra);
49+
};
50+
JNIEXPORT jstring JNICALL Java_com_androidmontreal_opencv_OpenCVPreview_processimage(JNIEnv* env, jobject thiz, jint width, jint height, jbyteArray yuv, jintArray bgra)
51+
{
52+
53+
// Get input and output arrays
54+
jbyte* _yuv = env->GetByteArrayElements(yuv, 0);
55+
jint* _bgra = env->GetIntArrayElements(bgra, 0);
56+
57+
Mat myuv(height + height / 2, width, CV_8UC1, (unsigned char *) _yuv);
58+
Mat mbgra(height, width, CV_8UC4, (unsigned char *) _bgra);
59+
60+
// Please pay attention to BGRA byte order
61+
// ARGB stored in java as int array becomes BGRA at native level
62+
cvtColor(myuv, mbgra, CV_YUV420sp2BGR, 4);
63+
64+
65+
int imageYwidth = mbgra.size[1];
66+
int imageXheight = mbgra.size[0];
67+
68+
vector<vector<Point> > items;
69+
string resultsIfAny = colorSomeStuff(mbgra);
70+
71+
env->ReleaseIntArrayElements(bgra, _bgra, 0);
72+
env->ReleaseByteArrayElements(yuv, _yuv, 0);
73+
74+
const char* resultCstring = resultsIfAny.c_str();
75+
return env->NewStringUTF(resultCstring);
76+
}

android/res/layout/main.xml

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,36 @@
44
android:layout_height="fill_parent"
55
android:orientation="vertical" >
66

7-
<TextView
8-
android:id="@+id/textview1"
9-
android:layout_width="fill_parent"
10-
android:layout_height="wrap_content"
11-
android:text="@string/hello" />
7+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
8+
android:layout_width="fill_parent"
9+
android:layout_height="wrap_content"
10+
android:orientation="vertical" >
11+
<TextView
12+
android:id="@+id/textview1"
13+
android:layout_width="fill_parent"
14+
android:layout_height="wrap_content"
15+
android:text="@string/hello" />
16+
<Button
17+
android:id="@+id/capture"
18+
android:layout_width="wrap_content"
19+
android:layout_height="wrap_content"
20+
android:layout_alignParentLeft="true"
21+
android:layout_alignParentTop="true"
22+
android:text="Capture"
23+
android:onClick="onCaptureClick" />
24+
</LinearLayout>
25+
26+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
27+
android:layout_width="fill_parent"
28+
android:layout_height="fill_parent"
29+
android:orientation="vertical" >
30+
<view
31+
class="com.androidmontreal.opencv.OpenCVPreview"
32+
android:id="@+id/preview"
33+
android:layout_width="fill_parent"
34+
android:layout_height="fill_parent"
35+
android:layout_alignParentLeft="true"
36+
android:layout_alignParentTop="true"/>
1237

38+
</LinearLayout>
1339
</LinearLayout>

android/src/com/androidmontreal/opencv/AndroidOpenCVforHackathonsActivity.java

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,29 @@
1515
*/
1616
package com.androidmontreal.opencv;
1717

18+
1819
import android.app.Activity;
20+
import android.hardware.Camera;
21+
import android.hardware.Camera.PictureCallback;
22+
import android.util.Log;
23+
import android.view.View;
24+
import android.widget.Button;
1925
import android.widget.TextView;
2026
import android.os.Bundle;
2127

2228

23-
public class AndroidOpenCVforHackathonsActivity extends Activity
29+
public class AndroidOpenCVforHackathonsActivity extends Activity implements PictureCallback
2430
{
31+
private static final String TAG = "OpenCVforHackathons";
32+
33+
2534
/** Called when the activity is first created. */
2635
@Override
2736
public void onCreate(Bundle savedInstanceState)
2837
{
2938
super.onCreate(savedInstanceState);
30-
39+
Log.d(TAG, "=onCreate=");
40+
3141
/* Create a TextView and set its content.
3242
* the text is retrieved by calling a native
3343
* function.
@@ -38,6 +48,52 @@ public void onCreate(Bundle savedInstanceState)
3848

3949
}
4050

51+
@Override
52+
protected void onDestroy() {
53+
Log.d(TAG, "=onDestroy=");
54+
super.onDestroy();
55+
}
56+
57+
@Override
58+
public void onLowMemory() {
59+
Log.d(TAG, "===onLowMemory===");
60+
super.onLowMemory();
61+
}
62+
63+
@Override
64+
protected void onPause() {
65+
Log.d(TAG, "====onPause====");
66+
super.onPause();
67+
}
68+
69+
@Override
70+
protected void onResume() {
71+
Log.d(TAG, "==onResume==");
72+
super.onResume();
73+
}
74+
75+
@Override
76+
protected void onStop() {
77+
Log.d(TAG, "==onStop==");
78+
super.onStop();
79+
}
80+
81+
public void onCaptureClick(View v) {
82+
Button capture = (Button) findViewById(R.id.capture);
83+
capture.setEnabled(false);
84+
85+
// Take picture
86+
OpenCVPreview previewView = (OpenCVPreview) findViewById(R.id.preview);
87+
Camera camera = previewView.getCamera();
88+
camera.takePicture(null, null, this);
89+
90+
}
91+
public void onPictureTaken(byte[] data, Camera camera) {
92+
/*
93+
* Do some thing
94+
*/
95+
finish();
96+
}
4197
/* A native method that is implemented by the
4298
* 'hello-jni' native library, which is packaged
4399
* with this application.
@@ -56,6 +112,7 @@ public void onCreate(Bundle savedInstanceState)
56112
*/
57113
public native String unimplementedStringFromJNI();
58114

115+
59116
/* this is used to load the 'hello-jni' library on application
60117
* startup. The library has already been unpacked into
61118
* /data/data/com.example.HelloJni/lib/libhello-jni.so at

0 commit comments

Comments
 (0)